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::{
|
use iced::{
|
||||||
Color, Length, Subscription, Task, application, event,
|
Alignment, Color, Length, Subscription, Task, application, event,
|
||||||
keyboard::{self, Key, key},
|
keyboard::{self, Key, key},
|
||||||
theme, widget,
|
theme, widget,
|
||||||
};
|
};
|
||||||
|
|
@ -20,12 +20,10 @@ enum Message {
|
||||||
ChangePassword(String),
|
ChangePassword(String),
|
||||||
ChangeSecurity(bool),
|
ChangeSecurity(bool),
|
||||||
OpenDb,
|
OpenDb,
|
||||||
|
DbOpened(Result<keepass::Database, String>),
|
||||||
|
|
||||||
FocusNext,
|
FocusNext,
|
||||||
FocusPrevious,
|
FocusPrevious,
|
||||||
|
|
||||||
Enter,
|
|
||||||
Pick,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -38,6 +36,9 @@ struct State {
|
||||||
password: String,
|
password: String,
|
||||||
|
|
||||||
is_secure: bool,
|
is_secure: bool,
|
||||||
|
|
||||||
|
status: Cow<'static, str>,
|
||||||
|
error: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
|
@ -81,36 +82,27 @@ impl State {
|
||||||
|
|
||||||
Message::ChangePassword(password) => self.password = password,
|
Message::ChangePassword(password) => self.password = password,
|
||||||
Message::ChangeSecurity(bool) => self.is_secure = bool,
|
Message::ChangeSecurity(bool) => self.is_secure = bool,
|
||||||
Message::OpenDb => {
|
Message::OpenDb => return self.open_db(),
|
||||||
match self.open_db() {
|
|
||||||
Err(e) => eprintln!("failed to open db '{}': {e}", self.db_path),
|
Message::DbOpened(result) => {
|
||||||
Ok(()) => {
|
match result {
|
||||||
#[allow(unused_must_use)]
|
Ok(db) => {
|
||||||
db::set_last_opened(&self.db_path)
|
self.error = "".into();
|
||||||
.inspect_err(|e| eprintln!("failed to set last-opened db: {e}"));
|
self.db = Some(db)
|
||||||
}
|
}
|
||||||
};
|
Err(e) => self.error = e.into(),
|
||||||
|
}
|
||||||
|
self.status = "".into();
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::FocusNext => return widget::operation::focus_next(),
|
Message::FocusNext => return widget::operation::focus_next(),
|
||||||
Message::FocusPrevious => return widget::operation::focus_previous(),
|
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()
|
Task::none()
|
||||||
}
|
}
|
||||||
fn view(&self) -> Element<'_> {
|
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::scrollable(widget::row([
|
||||||
widget::column(db.iter_all_entries().map(|entry| {
|
widget::column(db.iter_all_entries().map(|entry| {
|
||||||
widget::text(entry.get_title().unwrap_or_default().to_string()).into()
|
widget::text(entry.get_title().unwrap_or_default().to_string()).into()
|
||||||
|
|
@ -163,11 +155,33 @@ impl State {
|
||||||
)
|
)
|
||||||
.center(Length::Fill)
|
.center(Length::Fill)
|
||||||
.into()
|
.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> {
|
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, .. }) => {
|
iced::Event::Keyboard(keyboard::Event::KeyPressed { key, modifiers, .. }) => {
|
||||||
match key.as_ref() {
|
match key.as_ref() {
|
||||||
Key::Named(key::Named::Tab) => Some(if modifiers.shift() {
|
Key::Named(key::Named::Tab) => Some(if modifiers.shift() {
|
||||||
|
|
@ -176,8 +190,10 @@ impl State {
|
||||||
Message::FocusNext
|
Message::FocusNext
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Key::Named(key::Named::Enter) => Some(Message::Enter),
|
Key::Named(key::Named::Enter) if !db_loaded && db_path_exists => {
|
||||||
Key::Character("p" | "f" | "i") => Some(Message::Pick),
|
Some(Message::OpenDb)
|
||||||
|
}
|
||||||
|
Key::Character("p" | "f" | "i") if !db_loaded => Some(Message::PickDb),
|
||||||
|
|
||||||
// ignore unused keys
|
// ignore unused keys
|
||||||
_ => None,
|
_ => 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);
|
debug_assert!(self.db_path_exists);
|
||||||
|
|
||||||
self.db = Some(
|
self.status = "loading...".into();
|
||||||
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())?,
|
|
||||||
);
|
|
||||||
|
|
||||||
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