commit b8229fb9a9951bb75d53acef7a027d942bb4e081
parent 5396085d961940cd5e7154d42ff511b89e304869
Author: kernelkind <kernelkind@gmail.com>
Date: Sat, 27 Apr 2024 12:12:35 -0400
Move login business logic to LoginManager
Signed-off-by: kernelkind <kernelkind@gmail.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
2 files changed, 117 insertions(+), 28 deletions(-)
diff --git a/src/account_login_view.rs b/src/account_login_view.rs
@@ -1,5 +1,5 @@
use crate::app_style::NotedeckTextStyle;
-use crate::key_parsing::{perform_key_retrieval, LoginError};
+use crate::key_parsing::LoginError;
use crate::login_manager::LoginManager;
use crate::ui;
use crate::ui::{Preview, View};
@@ -7,7 +7,7 @@ use egui::{
Align, Align2, Button, Color32, Frame, Id, LayerId, Margin, Pos2, Rect, RichText, Rounding, Ui,
Vec2, Window,
};
-use egui::{Image, TextBuffer, TextEdit};
+use egui::{Image, TextEdit};
pub struct AccountLoginView<'a> {
manager: &'a mut LoginManager,
@@ -92,10 +92,10 @@ impl<'a> AccountLoginView<'a> {
});
ui.vertical_centered_justified(|ui| {
- ui.add(login_textedit(&mut self.manager.login_key));
+ ui.add(login_textedit(self.manager));
if ui.add(login_button()).clicked() {
- self.manager.promise = Some(perform_key_retrieval(&self.manager.login_key));
+ self.manager.apply_login();
}
});
@@ -217,23 +217,17 @@ impl<'a> AccountLoginView<'a> {
ui.add_space(8f32);
- ui.add(login_textedit(&mut self.manager.login_key).min_size(Vec2::new(440.0, 40.0)));
+ ui.add(login_textedit(self.manager).min_size(Vec2::new(440.0, 40.0)));
ui.add_space(8.0);
ui.vertical_centered(|ui| {
- if self.manager.promise.is_some() {
+ if self.manager.is_awaiting_network() {
ui.add(egui::Spinner::new());
}
});
- if let Some(error_key) = &self.manager.key_on_error {
- if self.manager.login_key != *error_key {
- self.manager.error = None;
- self.manager.key_on_error = None;
- }
- }
- if let Some(err) = &self.manager.error {
+ if let Some(err) = self.manager.check_for_error() {
ui.horizontal(|ui| {
let error_label = match err {
LoginError::InvalidKey => egui::Label::new(
@@ -252,7 +246,7 @@ impl<'a> AccountLoginView<'a> {
let login_button = login_button().min_size(Vec2::new(442.0, 40.0));
if ui.add(login_button).clicked() {
- self.manager.promise = Some(perform_key_retrieval(&self.manager.login_key));
+ self.manager.apply_login()
}
});
}
@@ -332,14 +326,16 @@ fn login_button() -> Button<'static> {
.min_size(Vec2::new(0.0, 40.0))
}
-fn login_textedit(text: &mut dyn TextBuffer) -> TextEdit {
- egui::TextEdit::singleline(text)
- .hint_text(
- RichText::new("Your key here...").text_style(NotedeckTextStyle::Body.text_style()),
- )
- .vertical_align(Align::Center)
- .min_size(Vec2::new(0.0, 40.0))
- .margin(Margin::same(12.0))
+fn login_textedit(manager: &mut LoginManager) -> TextEdit {
+ manager.get_login_textedit(|text| {
+ egui::TextEdit::singleline(text)
+ .hint_text(
+ RichText::new("Your key here...").text_style(NotedeckTextStyle::Body.text_style()),
+ )
+ .vertical_align(Align::Center)
+ .min_size(Vec2::new(0.0, 40.0))
+ .margin(Margin::same(12.0))
+ })
}
pub struct AccountLoginPreview {
diff --git a/src/login_manager.rs b/src/login_manager.rs
@@ -1,4 +1,6 @@
+use crate::key_parsing::perform_key_retrieval;
use crate::key_parsing::LoginError;
+use egui::{TextBuffer, TextEdit};
use nostr_sdk::Keys;
use poll_promise::Promise;
@@ -6,14 +8,105 @@ use poll_promise::Promise;
/// nostr-sdk Keys object if possible.
#[derive(Default)]
pub struct LoginManager {
- pub login_key: String,
- pub promise: Option<Promise<Result<Keys, LoginError>>>,
- pub error: Option<LoginError>,
- pub key_on_error: Option<String>,
+ login_key: String,
+ promise: Option<Promise<Result<Keys, LoginError>>>,
+ error: Option<LoginError>,
+ key_on_error: Option<String>,
}
-impl LoginManager {
+impl<'a> LoginManager {
pub fn new() -> Self {
- LoginManager::default()
+ LoginManager {
+ login_key: String::new(),
+ promise: None,
+ error: None,
+ key_on_error: None,
+ }
+ }
+
+ pub fn get_login_textedit(
+ &'a mut self,
+ textedit_closure: fn(&'a mut dyn TextBuffer) -> TextEdit<'a>,
+ ) -> TextEdit<'a> {
+ textedit_closure(&mut self.login_key)
+ }
+
+ pub fn apply_login(&'a mut self) {
+ self.promise = Some(perform_key_retrieval(&self.login_key));
+ }
+
+ pub fn is_awaiting_network(&self) -> bool {
+ self.promise.is_some()
+ }
+
+ pub fn check_for_error(&'a mut self) -> Option<&'a LoginError> {
+ if let Some(error_key) = &self.key_on_error {
+ if self.login_key != *error_key {
+ self.error = None;
+ self.key_on_error = None;
+ }
+ }
+
+ self.error.as_ref()
+ }
+
+ pub fn check_for_successful_login(&mut self) -> Option<Keys> {
+ if let Some(promise) = &mut self.promise {
+ if promise.ready().is_some() {
+ if let Some(promise) = self.promise.take() {
+ match promise.block_and_take() {
+ Ok(key) => {
+ return Some(key);
+ }
+ Err(e) => {
+ self.error = Some(e);
+ self.key_on_error = Some(self.login_key.clone());
+ }
+ };
+ }
+ }
+ }
+ None
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use nostr_sdk::PublicKey;
+ use std::time::{Duration, Instant};
+
+ #[test]
+ fn test_retrieve_key() {
+ let mut manager = LoginManager::new();
+ let manager_ref = &mut manager;
+ let expected_str = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681";
+ let expected_key = Keys::from_public_key(PublicKey::from_hex(expected_str).unwrap());
+
+ let start_time = Instant::now();
+
+ while start_time.elapsed() < Duration::from_millis(50u64) {
+ let cur_time = start_time.elapsed();
+
+ if cur_time < Duration::from_millis(10u64) {
+ let key = "test";
+ manager_ref.login_key = String::from(key);
+ manager_ref.promise = Some(perform_key_retrieval(key));
+ } else if cur_time < Duration::from_millis(30u64) {
+ let key = "test2";
+ manager_ref.login_key = String::from(key);
+ manager_ref.promise = Some(perform_key_retrieval(key));
+ } else {
+ manager_ref.login_key = String::from(expected_str);
+ manager_ref.promise = Some(perform_key_retrieval(expected_str));
+ }
+
+ if let Some(key) = manager_ref.check_for_successful_login() {
+ assert_eq!(expected_key, key);
+ return;
+ }
+ }
+
+ panic!();
}
}