feat: display status and errors
This commit is contained in:
parent
86075c213e
commit
43d382c988
1 changed files with 72 additions and 52 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use std::fs;
|
||||
use std::{borrow::Cow, fs};
|
||||
|
||||
use iced::{
|
||||
Color, Length, Subscription, Task, application, event,
|
||||
Alignment, Color, Length, Subscription, Task, application, event,
|
||||
keyboard::{self, Key, key},
|
||||
theme, widget,
|
||||
};
|
||||
|
|
@ -20,12 +20,10 @@ enum Message {
|
|||
ChangePassword(String),
|
||||
ChangeSecurity(bool),
|
||||
OpenDb,
|
||||
DbOpened(Result<keepass::Database, String>),
|
||||
|
||||
FocusNext,
|
||||
FocusPrevious,
|
||||
|
||||
Enter,
|
||||
Pick,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -38,6 +36,9 @@ struct State {
|
|||
password: String,
|
||||
|
||||
is_secure: bool,
|
||||
|
||||
status: Cow<'static, str>,
|
||||
error: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
|
@ -81,36 +82,27 @@ impl State {
|
|||
|
||||
Message::ChangePassword(password) => self.password = password,
|
||||
Message::ChangeSecurity(bool) => self.is_secure = bool,
|
||||
Message::OpenDb => {
|
||||
match self.open_db() {
|
||||
Err(e) => eprintln!("failed to open db '{}': {e}", self.db_path),
|
||||
Ok(()) => {
|
||||
#[allow(unused_must_use)]
|
||||
db::set_last_opened(&self.db_path)
|
||||
.inspect_err(|e| eprintln!("failed to set last-opened db: {e}"));
|
||||
Message::OpenDb => return self.open_db(),
|
||||
|
||||
Message::DbOpened(result) => {
|
||||
match result {
|
||||
Ok(db) => {
|
||||
self.error = "".into();
|
||||
self.db = Some(db)
|
||||
}
|
||||
};
|
||||
Err(e) => self.error = e.into(),
|
||||
}
|
||||
self.status = "".into();
|
||||
}
|
||||
|
||||
Message::FocusNext => return widget::operation::focus_next(),
|
||||
Message::FocusPrevious => return widget::operation::focus_previous(),
|
||||
|
||||
Message::Enter => {
|
||||
if self.db.is_none() && self.db_path_exists {
|
||||
return Task::done(Message::OpenDb);
|
||||
}
|
||||
}
|
||||
Message::Pick => {
|
||||
if self.db.is_none() {
|
||||
return Task::done(Message::PickDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Task::none()
|
||||
}
|
||||
fn view(&self) -> Element<'_> {
|
||||
if let Some(db) = self.db.as_ref() {
|
||||
let main = if let Some(db) = self.db.as_ref() {
|
||||
widget::scrollable(widget::row([
|
||||
widget::column(db.iter_all_entries().map(|entry| {
|
||||
widget::text(entry.get_title().unwrap_or_default().to_string()).into()
|
||||
|
|
@ -163,11 +155,33 @@ impl State {
|
|||
)
|
||||
.center(Length::Fill)
|
||||
.into()
|
||||
};
|
||||
|
||||
let mut bar = Vec::new();
|
||||
if !self.error.is_empty() {
|
||||
bar.push(
|
||||
widget::container(widget::text(&self.error).style(widget::text::danger))
|
||||
.align_x(Alignment::Start)
|
||||
.width(Length::Fill)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
if !self.status.is_empty() {
|
||||
bar.push(
|
||||
widget::container(widget::text(&self.status))
|
||||
.align_x(Alignment::End)
|
||||
.width(Length::Fill)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
widget::column([main, widget::row(bar).into()]).into()
|
||||
}
|
||||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
event::listen().filter_map(|event| match event {
|
||||
event::listen()
|
||||
.with((self.db.is_some(), self.db_path_exists))
|
||||
.filter_map(move |((db_loaded, db_path_exists), event)| match event {
|
||||
iced::Event::Keyboard(keyboard::Event::KeyPressed { key, modifiers, .. }) => {
|
||||
match key.as_ref() {
|
||||
Key::Named(key::Named::Tab) => Some(if modifiers.shift() {
|
||||
|
|
@ -176,8 +190,10 @@ impl State {
|
|||
Message::FocusNext
|
||||
}),
|
||||
|
||||
Key::Named(key::Named::Enter) => Some(Message::Enter),
|
||||
Key::Character("p" | "f" | "i") => Some(Message::Pick),
|
||||
Key::Named(key::Named::Enter) if !db_loaded && db_path_exists => {
|
||||
Some(Message::OpenDb)
|
||||
}
|
||||
Key::Character("p" | "f" | "i") if !db_loaded => Some(Message::PickDb),
|
||||
|
||||
// ignore unused keys
|
||||
_ => None,
|
||||
|
|
@ -189,18 +205,22 @@ impl State {
|
|||
})
|
||||
}
|
||||
|
||||
fn open_db(&mut self) -> Result<(), String> {
|
||||
fn open_db(&mut self) -> Task<Message> {
|
||||
debug_assert!(self.db_path_exists);
|
||||
|
||||
self.db = Some(
|
||||
keepass::Database::open(
|
||||
&mut fs::File::open(&self.db_path).map_err(|e| e.to_string())?,
|
||||
keepass::DatabaseKey::new().with_password(&self.password),
|
||||
)
|
||||
.map_err(|e| e.to_string())?,
|
||||
);
|
||||
self.status = "loading...".into();
|
||||
|
||||
Ok(())
|
||||
let (db_path, password) = (self.db_path.clone(), self.password.clone());
|
||||
Task::perform(
|
||||
async move {
|
||||
Ok(keepass::Database::open(
|
||||
&mut fs::File::open(&db_path).map_err(|e| e.to_string())?,
|
||||
keepass::DatabaseKey::new().with_password(&password),
|
||||
)
|
||||
.map_err(|e| e.to_string())?)
|
||||
},
|
||||
Message::DbOpened,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue