use crate::app::command::Command;
use crate::app::keys::{KeyBinding, KEY_BINDINGS};
use crate::app::mode::Mode;
use crate::app::prompt::{OutputType, Prompt, COMMAND_PREFIX, SEARCH_PREFIX};
use crate::app::selection::Selection;
use crate::app::splash::SplashScreen;
use crate::app::state::State;
use crate::app::tab::Tab;
use crate::args::Args;
use crate::gpg::context::GpgContext;
use crate::gpg::key::{GpgKey, KeyDetail, KeyType};
use crate::widget::list::StatefulList;
use crate::widget::row::ScrollDirection;
use crate::widget::style::Color as WidgetColor;
use crate::widget::table::{StatefulTable, TableSize, TableState};
use anyhow::{anyhow, Error as AnyhowError, Result};
use colorsys::Rgb;
use copypasta_ext::prelude::ClipboardProvider;
use copypasta_ext::x11_fork::ClipboardContext;
use std::collections::HashMap;
use std::path::Path;
use std::process::Command as OsCommand;
use std::str;
use std::str::FromStr;
use tui::style::Color;
/// Max duration of prompt messages.
const MESSAGE_DURATION: u128 = 1750;
/// Main application.
///
/// It is responsible for running the commands
/// for changing the state of the interface.
pub struct App<'a> {
/// Application state.
pub state: State,
/// Application mode.
pub mode: Mode,
/// Prompt manager.
pub prompt: Prompt,
/// Current tab.
pub tab: Tab,
/// Content of the options menu.
pub options: StatefulList<Command>,
/// Splash screen of the application.
pub splash_screen: SplashScreen,
/// Content of the key bindings list.
pub key_bindings: StatefulList<KeyBinding<'a>>,
/// Public/secret keys.
pub keys: HashMap<KeyType, Vec<GpgKey>>,
/// Table of public/secret keys.
pub keys_table: StatefulTable<GpgKey>,
/// States of the keys table.
pub keys_table_states: HashMap<KeyType, TableState>,
/// Level of detail to show for keys table.
pub keys_table_detail: KeyDetail,
/// Bottom margin value of the keys table.
pub keys_table_margin: u16,
/// Clipboard context.
pub clipboard: Option<ClipboardContext>,
/// GPGME context.
pub gpgme: &'a mut GpgContext,
}
impl<'a> App<'a> {
/// Constructs a new instance of `App`.
pub fn new(gpgme: &'a mut GpgContext, args: &'a Args) -> Result<Self> {
let keys = gpgme.get_all_keys()?;
let keys_table = StatefulTable::with_items(
keys.get(&KeyType::Public)
.expect("failed to get public keys")
.to_vec(),
);
Ok(Self {
state: State::from(args),
mode: Mode::Normal,
prompt: Prompt::default(),
tab: Tab::Keys(KeyType::Public),
options: StatefulList::with_items(Vec::new()),
splash_screen: SplashScreen::new("splash.jpg", 12)?,
key_bindings: StatefulList::with_items(KEY_BINDINGS.to_vec()),
keys,
keys_table,
keys_table_states: HashMap::new(),
keys_table_detail: KeyDetail::Minimum,
keys_table_margin: 1,
clipboard: match ClipboardContext::new() {
Ok(clipboard) => Some(clipboard),
Err(e) => {
eprintln!("failed to initialize clipboard: {:?}", e);
None
}
},
gpgme,
})
}
/// Resets the application state.
pub fn refresh(&mut self) -> Result<()> {
self.state.refresh();
self.mode = Mode::Normal;
self.prompt.clear();
self.options.state.select(Some(0));
self.keys = self.gpgme.get_all_keys()?;
self.keys_table_states.clear();
self.keys_table_detail = KeyDetail::Minimum;
self.keys_table_margin = 1;
match self.tab {
Tab::Keys(key_type) => {
self.keys_table = StatefulTable::with_items(
self.keys
.get(&key_type)
.unwrap_or_else(|| {
panic!("failed to get {} keys", key_type)
})
.to_vec(),
)
}
Tab::Help => {}
};
Ok(())
}
/// Handles the tick event of the application.
///
/// It is currently used to flush the prompt messages.
pub fn tick(&mut self) {
if let Some(clock) = self.prompt.clock {
if clock.elapsed().as_millis() > MESSAGE_D