commit 6afb618089635c01ee35df204b0c273724c8ed39
parent ac0821db7955947b421a8aaf6b21202410415091
Author: kernelkind <kernelkind@gmail.com>
Date:   Sun, 23 Jun 2024 19:46:58 -0400
reintroduce account management
Signed-off-by: kernelkind <kernelkind@gmail.com>
Diffstat:
9 files changed, 181 insertions(+), 21 deletions(-)
diff --git a/src/app.rs b/src/app.rs
@@ -10,7 +10,7 @@ use crate::relay_pool_manager::RelayPoolManager;
 use crate::route::Route;
 use crate::timeline;
 use crate::timeline::{MergeKind, NoteRef, Timeline, ViewFilter};
-use crate::ui::{self, AccountSelectionWidget};
+use crate::ui::{self, AccountSelectionWidget, DesktopGlobalPopup};
 use crate::ui::{DesktopSidePanel, RelayView, View};
 use crate::Result;
 use egui_nav::{Nav, NavAction};
@@ -46,7 +46,7 @@ pub struct Damus {
     is_mobile: bool,
 
     /// global navigation for account management popups, etc.
-    //nav: Vec<Route>,
+    pub global_nav: Vec<Route>,
     pub textmode: bool,
     pub drafts: HashMap<enostr::NoteId, Draft>,
 
@@ -59,6 +59,7 @@ pub struct Damus {
 
     frame_history: crate::frame_history::FrameHistory,
     pub show_account_switcher: bool,
+    pub show_global_popup: bool,
 }
 
 fn relay_setup(pool: &mut RelayPool, ctx: &egui::Context) {
@@ -728,6 +729,8 @@ impl Damus {
             //compose: "".to_string(),
             frame_history: FrameHistory::default(),
             show_account_switcher: false,
+            show_global_popup: false,
+            global_nav: Vec::new(),
         }
     }
 
@@ -755,6 +758,8 @@ impl Damus {
             account_manager: AccountManager::new(None, crate::key_storage::KeyStorage::None),
             frame_history: FrameHistory::default(),
             show_account_switcher: false,
+            show_global_popup: true,
+            global_nav: Vec::new(),
         }
     }
 
@@ -990,9 +995,8 @@ fn render_damus_desktop(ctx: &egui::Context, app: &mut Damus) {
 
     main_panel(&ctx.style(), app.is_mobile()).show(ctx, |ui| {
         ui.spacing_mut().item_spacing.x = 0.0;
-        if app.show_account_switcher {
-            AccountSelectionWidget::ui(app, ui);
-        }
+        AccountSelectionWidget::ui(app, ui);
+        DesktopGlobalPopup::show(app.global_nav.clone(), app, ui);
         if need_scroll {
             egui::ScrollArea::horizontal().show(ui, |ui| {
                 timelines_view(ui, panel_sizes, app, app.timelines.len());
diff --git a/src/fixed_window.rs b/src/fixed_window.rs
@@ -0,0 +1,62 @@
+use egui::{Rect, Response, RichText, Sense, Window};
+
+pub struct FixedWindow {
+    title: Option<RichText>,
+}
+
+#[derive(PartialEq)]
+pub enum FixedWindowResponse {
+    Opened,
+    Closed,
+}
+
+impl FixedWindow {
+    #[allow(dead_code)]
+    pub fn new() -> Self {
+        Self { title: None }
+    }
+
+    pub fn maybe_with_title(maybe_title: Option<RichText>) -> Self {
+        Self { title: maybe_title }
+    }
+
+    #[allow(dead_code)]
+    pub fn with_title(mut self, title: RichText) -> Self {
+        self.title = Some(title);
+        self
+    }
+
+    pub fn show(
+        self,
+        ui: &mut egui::Ui,
+        rect: Rect,
+        add_contents: impl FnOnce(&mut egui::Ui) -> Response,
+    ) -> FixedWindowResponse {
+        let mut is_open = true;
+
+        let use_title_bar = self.title.is_some();
+        let title = if let Some(title) = self.title {
+            title
+        } else {
+            RichText::new("")
+        };
+
+        Window::new(title)
+            .open(&mut is_open)
+            .fixed_rect(rect)
+            .collapsible(false)
+            .movable(false)
+            .resizable(false)
+            .title_bar(use_title_bar)
+            .show(ui.ctx(), |ui| {
+                let resp = add_contents(ui);
+                ui.allocate_rect(resp.rect, Sense::hover())
+            });
+
+        if !is_open {
+            FixedWindowResponse::Closed
+        } else {
+            FixedWindowResponse::Opened
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
@@ -10,6 +10,7 @@ mod app_style;
 mod colors;
 mod draft;
 mod filter;
+mod fixed_window;
 mod fonts;
 mod frame_history;
 mod images;
diff --git a/src/route.rs b/src/route.rs
@@ -1,5 +1,8 @@
+use egui::{Response, RichText};
 use enostr::NoteId;
-use std::fmt;
+use std::fmt::{self};
+
+use crate::{ui::AccountManagementView, Damus};
 
 /// App routing. These describe different places you can go inside Notedeck.
 #[derive(Clone, Debug)]
@@ -22,3 +25,22 @@ impl fmt::Display for Route {
         }
     }
 }
+
+impl Route {
+    pub fn show_global_popup(&self, app: &mut Damus, ui: &mut egui::Ui) -> Option<Response> {
+        match self {
+            Route::ManageAccount => AccountManagementView::ui(app, ui),
+            _ => None,
+        }
+    }
+
+    pub fn title(&self) -> RichText {
+        match self {
+            Route::ManageAccount => RichText::new("Manage Account").size(24.0),
+            Route::Thread(_) => RichText::new("Thread"),
+            Route::Reply(_) => RichText::new("Reply"),
+            Route::Relays => RichText::new("Relays"),
+            Route::Timeline(_) => RichText::new("Timeline"),
+        }
+    }
+}
diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs
@@ -5,7 +5,7 @@ use crate::{
     ui::{profile_preview_controller, Preview, PreviewConfig, View},
     Damus,
 };
-use egui::{Align, Button, Frame, Image, Layout, RichText, ScrollArea, Vec2};
+use egui::{Align, Button, Frame, Image, Layout, Response, RichText, ScrollArea, Vec2};
 
 use super::profile::preview::SimpleProfilePreview;
 use super::profile::ProfilePreviewOp;
@@ -13,14 +13,26 @@ use super::profile::ProfilePreviewOp;
 pub struct AccountManagementView {}
 
 impl AccountManagementView {
-    fn show(app: &mut Damus, ui: &mut egui::Ui) {
-        Frame::none().outer_margin(24.0).show(ui, |ui| {
-            Self::top_section_buttons_widget(ui);
-            ui.add_space(8.0);
-            scroll_area().show(ui, |ui| {
-                Self::show_accounts(app, ui);
-            });
-        });
+    pub fn ui(app: &mut Damus, ui: &mut egui::Ui) -> Option<Response> {
+        if app.is_mobile() {
+            AccountManagementView::show_mobile(app, ui);
+            None
+        } else {
+            Some(AccountManagementView::show(app, ui))
+        }
+    }
+
+    fn show(app: &mut Damus, ui: &mut egui::Ui) -> Response {
+        Frame::none()
+            .outer_margin(24.0)
+            .show(ui, |ui| {
+                Self::top_section_buttons_widget(ui);
+                ui.add_space(8.0);
+                scroll_area().show(ui, |ui| {
+                    Self::show_accounts(app, ui);
+                });
+            })
+            .response
     }
 
     fn show_accounts(app: &mut Damus, ui: &mut egui::Ui) {
diff --git a/src/ui/account_switcher.rs b/src/ui/account_switcher.rs
@@ -1,5 +1,5 @@
 use crate::{
-    account_manager::UserAccount, colors::PINK, profile::DisplayName,
+    account_manager::UserAccount, colors::PINK, profile::DisplayName, route::Route,
     ui::profile_preview_controller, Damus, Result,
 };
 
@@ -27,6 +27,10 @@ struct AccountSelectResponse {
 
 impl AccountSelectionWidget {
     pub fn ui(app: &mut Damus, ui: &mut egui::Ui) {
+        if !app.show_account_switcher {
+            return;
+        }
+
         if app.is_mobile() {
             Self::show_mobile(ui);
         } else {
@@ -54,7 +58,8 @@ impl AccountSelectionWidget {
             }
             AccountSelectAction::OpenAccountManagement => {
                 app.show_account_switcher = false;
-                // TODO: push account management to global popup router
+                app.global_nav.push(Route::ManageAccount);
+                app.show_global_popup = true;
             }
         }
     }
diff --git a/src/ui/global_popup.rs b/src/ui/global_popup.rs
@@ -0,0 +1,53 @@
+use std::{cell::RefCell, rc::Rc};
+
+use egui::Sense;
+use egui_nav::{Nav, NavAction};
+
+use crate::{
+    fixed_window::{FixedWindow, FixedWindowResponse},
+    route::Route,
+    Damus,
+};
+
+static MARGIN: f32 = 100.0;
+
+pub struct DesktopGlobalPopup {}
+
+impl DesktopGlobalPopup {
+    pub fn show(routes: Vec<Route>, app: &mut Damus, ui: &mut egui::Ui) {
+        if routes.is_empty() || !app.show_global_popup {
+            return;
+        }
+
+        let rect = ui.ctx().screen_rect().shrink(MARGIN);
+        let title = if let Some(first) = routes.first() {
+            // TODO(kernelkind): not a great way of getting the title of the routes 'grouping'
+            Some(first.title())
+        } else {
+            None
+        };
+
+        let app_ctx = Rc::new(RefCell::new(app));
+
+        let resp = FixedWindow::maybe_with_title(title).show(ui, rect, |ui| {
+            let nav_response = Nav::new(routes).navigating(false).show(ui, |ui, nav| {
+                if let Some(resp) = nav.top().show_global_popup(&mut app_ctx.borrow_mut(), ui) {
+                    ui.allocate_rect(resp.rect, Sense::hover())
+                } else {
+                    ui.label("") // TODO(kernelkind): not a great practice
+                }
+            });
+
+            if let Some(NavAction::Returned) = nav_response.action {
+                app_ctx.borrow_mut().global_nav.pop();
+            }
+
+            nav_response.inner
+        });
+
+        if resp == FixedWindowResponse::Closed {
+            app_ctx.borrow_mut().global_nav.pop();
+            app_ctx.borrow_mut().show_global_popup = false;
+        }
+    }
+}
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
@@ -2,6 +2,7 @@ pub mod account_login_view;
 pub mod account_management;
 pub mod account_switcher;
 pub mod anim;
+pub mod global_popup;
 pub mod mention;
 pub mod note;
 pub mod preview;
@@ -12,6 +13,7 @@ pub mod username;
 
 pub use account_management::AccountManagementView;
 pub use account_switcher::AccountSelectionWidget;
+pub use global_popup::DesktopGlobalPopup;
 pub use mention::Mention;
 pub use note::{BarAction, Note, NoteResponse, PostView};
 pub use preview::{Preview, PreviewApp, PreviewConfig};
diff --git a/src/ui/side_panel.rs b/src/ui/side_panel.rs
@@ -127,7 +127,7 @@ mod preview {
 
     use crate::{
         test_data,
-        ui::{AccountSelectionWidget, Preview, PreviewConfig},
+        ui::{AccountSelectionWidget, DesktopGlobalPopup, Preview, PreviewConfig},
     };
 
     use super::*;
@@ -157,9 +157,8 @@ mod preview {
                     });
                 });
 
-            if self.app.show_account_switcher {
-                AccountSelectionWidget::ui(&mut self.app, ui);
-            }
+            AccountSelectionWidget::ui(&mut self.app, ui);
+            DesktopGlobalPopup::show(self.app.global_nav.clone(), &mut self.app, ui);
         }
     }