[PATCH notedeck 0/4] Create side panel UI & global popup window

3 views
Skip to first unread message

kernelkind

unread,
May 17, 2024, 11:47:51 AMMay 17
to pat...@damus.io, kernelkind
This patch series features a side panel, DesktopSidePanel, on the left
side of the screen and a DesktopGlobalPopup window which appears when
the user interacts with the side panel. When the user presses the account
management button, the global popup window will appear and the user will
be able to interact with the AccountManagementView.

The first patch in this series adds accounts: Vec<UserAccount> as a
field in the Damus struct. There's an alternative if this isn't the
best solution: to save the user accounts in egui persisted memory.
It's not clear to me yet which solution is better.

The DesktopGlobalPopup can only construct the AccountManagementView, but
we don't know exactly what we will want to present in the future,
so it requires access to the Damus struct to be able to construct any
view. In the future maybe we can restrict this access.

It also adds a mock method to the Damus struct since the global popup
requires access to it. The implementation was just copied from the
existing Damus constructor, it uses the same ndb file as production.
I think all tests & previews should use a seperate ndb file specifically
for testing so tests & previews can be deterministic across all
machines.

The account_management.rs file was refactored as requested, let me know
if it's still too messy.


kernelkind (4):
app: add accounts to Damus & mock
Create side panel & global popup
move test account creation & apply to global popup
account_management: refactor

assets/icons/add_column_dark_4x.png | Bin 0 -> 1150 bytes
assets/icons/settings_dark_4x.png | Bin 0 -> 3886 bytes
src/app.rs | 27 +++
src/test_data.rs | 34 +++-
src/ui/account_management.rs | 255 ++++++++++++----------------
src/ui/global_popup.rs | 128 ++++++++++++++
src/ui/mod.rs | 5 +
src/ui/persist_state.rs | 43 +++++
src/ui/side_panel.rs | 93 ++++++++++
src/ui_preview/main.rs | 6 +-
10 files changed, 444 insertions(+), 147 deletions(-)
create mode 100644 assets/icons/add_column_dark_4x.png
create mode 100644 assets/icons/settings_dark_4x.png
create mode 100644 src/ui/global_popup.rs
create mode 100644 src/ui/persist_state.rs
create mode 100644 src/ui/side_panel.rs


base-commit: 4fc6e225caacce70042b42fc926429ae96b45736
--
2.39.3 (Apple Git-146)

kernelkind

unread,
May 17, 2024, 11:48:06 AMMay 17
to pat...@damus.io, kernelkind
Signed-off-by: kernelkind <kerne...@gmail.com>
---
src/app.rs | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)

diff --git a/src/app.rs b/src/app.rs
index 42db08863768..eeb0c9059702 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,3 +1,4 @@
+use crate::account_manager::UserAccount;
use crate::app_creation::setup_cc;
use crate::app_style::user_requested_visuals_change;
use crate::error::Error;
@@ -41,6 +42,7 @@ pub struct Damus {

pub img_cache: ImageCache,
pub ndb: Ndb,
+ pub accounts: Vec<UserAccount>,

frame_history: crate::frame_history::FrameHistory,
}
@@ -482,6 +484,7 @@ impl Damus {
timelines,
textmode: false,
ndb: Ndb::new(data_path.as_ref().to_str().expect("db path ok"), &config).expect("ndb"),
+ accounts: Vec::new(),
//compose: "".to_string(),
frame_history: FrameHistory::default(),
}
@@ -492,6 +495,30 @@ impl Damus {
.entry(note_key)
.or_insert_with(|| NoteCache::new(note))
}
+
+ pub fn mock<P: AsRef<Path>>(data_path: P) -> Self {
+ let mut timelines: Vec<Timeline> = vec![];
+ let _initial_limit = 100;
+ let filter = serde_json::from_str(include_str!("../queries/global.json")).unwrap();
+ timelines.push(Timeline::new(filter));
+
+ let imgcache_dir = data_path.as_ref().join(ImageCache::rel_datadir());
+ let _ = std::fs::create_dir_all(imgcache_dir.clone());
+
+ let mut config = Config::new();
+ config.set_ingester_threads(2);
+ Self {
+ state: DamusState::Initializing,
+ pool: RelayPool::new(),
+ img_cache: ImageCache::new(imgcache_dir),
+ note_cache: HashMap::new(),
+ timelines,
+ textmode: false,
+ ndb: Ndb::new(data_path.as_ref().to_str().expect("db path ok"), &config).expect("ndb"),
+ accounts: Vec::new(),
+ frame_history: FrameHistory::default(),
+ }
+ }
}

/*
--
2.39.3 (Apple Git-146)

kernelkind

unread,
May 17, 2024, 11:48:08 AMMay 17
to pat...@damus.io, kernelkind
Create a side panel UI element for desktop with three buttons for:
adding a column, settings, and account management. The account
management button is temporary pending a better design. It is the only
one that is interactable at the moment. When the user clicks it, the
global popup window will be shown and the AccountManagementView will be
presented on the window. The user can click on the X on the top right of
the window to close it.

Signed-off-by: kernelkind <kerne...@gmail.com>
---
assets/icons/add_column_dark_4x.png | Bin 0 -> 1150 bytes
assets/icons/settings_dark_4x.png | Bin 0 -> 3886 bytes
src/ui/account_management.rs | 63 ++++++--------
src/ui/global_popup.rs | 127 ++++++++++++++++++++++++++++
src/ui/mod.rs | 5 ++
src/ui/persist_state.rs | 43 ++++++++++
src/ui/side_panel.rs | 93 ++++++++++++++++++++
src/ui_preview/main.rs | 6 +-
8 files changed, 299 insertions(+), 38 deletions(-)
create mode 100644 assets/icons/add_column_dark_4x.png
create mode 100644 assets/icons/settings_dark_4x.png
create mode 100644 src/ui/global_popup.rs
create mode 100644 src/ui/persist_state.rs
create mode 100644 src/ui/side_panel.rs

diff --git a/assets/icons/add_column_dark_4x.png b/assets/icons/add_column_dark_4x.png
new file mode 100644
index 0000000000000000000000000000000000000000..5d8c370b2bd514e372b8c6e5c283528df81da3c0
GIT binary patch
literal 1150
zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9EO-XP4l)OOlRpde#$
zkh>GZx^prwfgF}}M_)$<hK>E)e-c@NTwzZa$B+ufw{!0Y-gXc;7VgA)f$<f?rAFfe
z%>J5;!HfZnJD3(Qd2m*;C0j9QIlMez^ZEEqRU_pSb2l&FyhrR;o$<UA>g=As@7`T^
z?wXz;1H+7o0vt&uQnGvZ?US35uWx2<&acVDA;2L0e@W6GO=hu&GqNTL1sp#1-g?$|
zki@Z7n|yg$4A__?CSR0ERKNPTvZ&eo`ec=f_4nJJrx=~g{MeJp7wC1_h5LY;xbl1N
zk^}3%|D4e4ckIMY8J_mT$7g6P&0Mrh!EB$zzsC6EA}@QSRJ6P@XWddhAS|q}yxNBA
z+Oqr#lRwK;7foZx`BUug!^6Zmuj$mh`|1YbO>PYQPyhX2Cfiq+cZ2c&qwtSkzLcov
zT3cJY{`^08-pu8#ONx3-SNS_OhFmMl`fYH(wDyqX)Rn9cgwOtT=})U!^5Adv?c2A_
zuLy~~IX)*a@`T8i)9deSZLa<uJ8RkfTPZaMGqnB+05!}g+;sHRsZ-@?J_-_38H(Dy
z=iNJRyZ`Jl`^Bt>Hy=I!s(LEJo!`~#$_jVn{Ar5nI&(BfKrm5IHseg0OipfY?FY*!
z^*!&hrew57`DF@BRlep@xNwCV!}pT(j$>W-1UsBm8}dz!Pa9d>^GMpy-@q_2gY`sg
zZ*JLv(@gsWje$YS%-GY&aLl2>;MgfMQvrpZ`fGi5>)*C8F*5zwQuZX~HfQR({oJpZ
z6tmr>44A-58Ilzm3<VBIa3t`6Bj@r|>5WOd4#uwuKFne((IjY4zs%mz=30#elS%ul
zg902EWLCvTJA-w_b~b%_=_Y)>LsR}jL6acV0H_nt%_Stfg-K+cn`f%0Y<e3nS5SkX
zfd6Mv6Sc{mp9}v?pFW+J$&Yc8il#@SSA&V~dt3ICD<4l`)sA`Fzr?|sY0k-?5e@QJ
z3Tw<Bl!ZDu=iUo=E}xuO1=MEyO5;((QMPrpIh&<}76>gk!}<0LvyJWC>8U<etue;Z
zl}~QQW_-?QcX8Zjvi}mdTda`dx~a?phIQ|5oj<f9_{Iv>2lMK@<^>*L%K6}!zq=ql
zAgpVb?rN8v8k=->E2zGD&aC42y}&}|!?Vuk%0clD9{&3EYi$EFw_4p}-SvLam!re1
zrj%@mky)qTU)Jh);w#&8n|-@>Sv?hwe09nt%)@B;1s1=pll(Swi0d5EYb;kOm6YD^
z-*_deYXbAsmAe`Ce*a^4b-}l&0Lv@iR=7Q!qu=tR*ShDVw0P`=NSUjjKNruRyKeij
zGvY2h^~Wxr%gp&YVQ1KtX}goe7P;4VSDvbM)O+i8)MoKYofW;OpU$X`6wQd<s01t<
az(DjLga3vNEt9;ig1MfqelF{r5}E+3#p1#M

literal 0
HcmV?d00001

diff --git a/assets/icons/settings_dark_4x.png b/assets/icons/settings_dark_4x.png
new file mode 100644
index 0000000000000000000000000000000000000000..05b9d43b416ea9546ea45cea3d5c951549dcf711
GIT binary patch
literal 3886
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

literal 0
HcmV?d00001

diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs
index 26db2ac1a0af..419768852166 100644
--- a/src/ui/account_management.rs
+++ b/src/ui/account_management.rs
@@ -1,17 +1,16 @@
-use egui::{
- Align, Align2, Button, Frame, Id, Layout, Margin, RichText, ScrollArea, Sense, Vec2, Window,
-};
-
+use crate::ui::global_popup::FromApp;
use crate::{
account_manager::{AccountManager, SimpleProfilePreviewController, UserAccount},
app_style::NotedeckTextStyle,
ui::{self, Preview, View},
};
+use egui::{Align, Button, Frame, Id, Layout, Margin, RichText, ScrollArea, Sense, Vec2};
+
+use super::persist_state::PERSISTED_ACCOUNT_MANAGEMENT;

pub struct AccountManagementView<'a> {
account_manager: AccountManager<'a>,
simple_preview_controller: SimpleProfilePreviewController<'a>,
- edit_mode: &'a mut bool,
}

impl<'a> View for AccountManagementView<'a> {
@@ -28,37 +27,17 @@ impl<'a> AccountManagementView<'a> {
pub fn new(
account_manager: AccountManager<'a>,
simple_preview_controller: SimpleProfilePreviewController<'a>,
- edit_mode: &'a mut bool,
) -> Self {
AccountManagementView {
account_manager,
simple_preview_controller,
- edit_mode,
}
}

fn show(&mut self, ui: &mut egui::Ui) {
- ui.add_space(24.0);
- let screen_size = ui.ctx().screen_rect();
- let margin_amt = 128.0;
- let window_size = Vec2::new(
- screen_size.width() - margin_amt,
- screen_size.height() - margin_amt,
- );
-
- Window::new("Account Management")
- .frame(Frame::window(ui.style()))
- .collapsible(false)
- .anchor(Align2::CENTER_CENTER, [0.0, 0.0])
- .resizable(false)
- .title_bar(false)
- .default_size(window_size)
- .show(ui.ctx(), |ui| {
- ui.add(title());
- ui.add(self.buttons_widget());
- ui.add_space(8.0);
- self.show_accounts(ui);
- });
+ ui.add(self.buttons_widget());
+ ui.add_space(8.0);
+ self.show_accounts(ui);
}

fn show_accounts(&mut self, ui: &mut egui::Ui) {
@@ -67,7 +46,7 @@ impl<'a> AccountManagementView<'a> {
let maybe_remove = self.simple_preview_controller.set_profile_previews(
&self.account_manager,
ui,
- *self.edit_mode,
+ PERSISTED_ACCOUNT_MANAGEMENT.get_state(ui.ctx()),
|ui, preview, edit_mode| {
let mut should_remove = false;

@@ -103,7 +82,7 @@ impl<'a> AccountManagementView<'a> {
let maybe_remove = self.simple_preview_controller.set_profile_previews(
&self.account_manager,
ui,
- *self.edit_mode,
+ PERSISTED_ACCOUNT_MANAGEMENT.get_state(ui.ctx()),
|ui, preview, edit_mode| {
let mut should_remove = false;

@@ -168,12 +147,12 @@ impl<'a> AccountManagementView<'a> {
Vec2::new(ui.available_size_before_wrap().x, 32.0),
Layout::left_to_right(egui::Align::Center),
|ui| {
- if *self.edit_mode {
+ if PERSISTED_ACCOUNT_MANAGEMENT.get_state(ui.ctx()) {
if ui.add(done_account_button()).clicked() {
- *self.edit_mode = false;
+ PERSISTED_ACCOUNT_MANAGEMENT.set_state(ui.ctx(), false);
}
} else if ui.add(edit_account_button()).clicked() {
- *self.edit_mode = true;
+ PERSISTED_ACCOUNT_MANAGEMENT.set_state(ui.ctx(), true);
}
},
);
@@ -193,6 +172,20 @@ impl<'a> AccountManagementView<'a> {
}
}

+impl<'a> FromApp<'a> for AccountManagementView<'a> {
+ fn from_app(app: &'a mut crate::Damus) -> Self {
+ // TODO: don't hard-code key store & relay generator
+ AccountManagementView::new(
+ AccountManager::new(
+ &mut app.accounts,
+ crate::key_storage::KeyStorage::None,
+ crate::relay_generation::RelayGenerator::Constant,
+ ),
+ SimpleProfilePreviewController::new(&app.ndb, &mut app.img_cache),
+ )
+ }
+}
+
fn simple_preview_frame(ui: &mut egui::Ui) -> Frame {
Frame::none()
.rounding(ui.visuals().window_rounding)
@@ -318,7 +311,6 @@ mod preview {
accounts: Vec<UserAccount>,
ndb: Ndb,
img_cache: ImageCache,
- edit_mode: bool,
}

fn get_accounts() -> Vec<UserAccount> {
@@ -359,7 +351,6 @@ mod preview {
accounts,
ndb,
img_cache,
- edit_mode: false,
}
}
}
@@ -372,10 +363,10 @@ mod preview {
RelayGenerator::Constant,
);

+ ui.add_space(24.0);
AccountManagementView::new(
account_manager,
SimpleProfilePreviewController::new(&self.ndb, &mut self.img_cache),
- &mut self.edit_mode,
)
.ui(ui);
}
diff --git a/src/ui/global_popup.rs b/src/ui/global_popup.rs
new file mode 100644
index 000000000000..e7753b1fccc6
--- /dev/null
+++ b/src/ui/global_popup.rs
@@ -0,0 +1,127 @@
+use egui::{Align2, CentralPanel, RichText, Vec2, Window};
+
+use crate::Damus;
+
+use super::{
+ persist_state::{PERSISTED_GLOBAL_POPUP, PERSISTED_SIDE_PANEL},
+ AccountManagementView, View,
+};
+
+#[derive(Clone, Copy, Debug)]
+pub enum GlobalPopupType {
+ AccountManagement,
+}
+
+static ACCOUNT_MANAGEMENT_TITLE: &str = "Account Management";
+
+impl GlobalPopupType {
+ pub fn title(&self) -> &'static str {
+ match self {
+ Self::AccountManagement => ACCOUNT_MANAGEMENT_TITLE,
+ }
+ }
+}
+
+pub trait FromApp<'a> {
+ fn from_app(app: &'a mut crate::Damus) -> Self
+ where
+ Self: Sized;
+}
+
+fn title(title_str: &'static str) -> RichText {
+ RichText::new(title_str).size(24.0)
+}
+
+fn overlay_window<'a>(
+ open: &'a mut bool,
+ window_size: Vec2,
+ title_str: &'static str,
+) -> Window<'a> {
+ egui::Window::new(title(title_str))
+ .anchor(Align2::CENTER_CENTER, [0.0, 0.0])
+ .collapsible(false)
+ .auto_sized()
+ .movable(false)
+ .open(open)
+ .default_size(window_size)
+}
+
+static MARGIN: Vec2 = Vec2 { x: 100.0, y: 100.0 };
+
+pub struct DesktopGlobalPopup<'a> {
+ app: &'a mut Damus,
+}
+
+impl<'a> View for DesktopGlobalPopup<'a> {
+ fn ui(&mut self, ui: &mut egui::Ui) {
+ DesktopGlobalPopup::global_popup(self.app, ui.ctx())
+ }
+}
+
+impl<'a> DesktopGlobalPopup<'a> {
+ pub fn new(app: &'a mut Damus) -> Self {
+ DesktopGlobalPopup { app }
+ }
+ pub fn global_popup(app: &mut Damus, ctx: &egui::Context) {
+ CentralPanel::default().show(ctx, |ui| {
+ let available_size = ui.available_size();
+ let window_size = available_size - MARGIN;
+
+ if let Some(popup) = PERSISTED_SIDE_PANEL.get_state(ctx) {
+ let mut show_global_popup = PERSISTED_GLOBAL_POPUP.get_state(ctx);
+ if show_global_popup {
+ overlay_window(&mut show_global_popup, window_size, popup.title()).show(
+ ctx,
+ |ui| {
+ match popup {
+ GlobalPopupType::AccountManagement => {
+ AccountManagementView::from_app(app).ui(ui)
+ }
+ };
+ },
+ );
+
+ // user could have closed the window, set the new state in egui memory
+ PERSISTED_GLOBAL_POPUP.set_state(ctx, show_global_popup);
+ }
+ }
+ });
+ }
+}
+
+mod preview {
+ use crate::{
+ ui::{DesktopSidePanel, Preview, View},
+ Damus,
+ };
+
+ use super::DesktopGlobalPopup;
+
+ pub struct GlobalPopupPreview {
+ app: Damus,
+ }
+
+ impl<'a> Preview for DesktopGlobalPopup<'a> {
+ type Prev = GlobalPopupPreview;
+
+ fn preview() -> Self::Prev {
+ GlobalPopupPreview::new()
+ }
+ }
+
+ impl GlobalPopupPreview {
+ fn new() -> Self {
+ GlobalPopupPreview {
+ app: Damus::mock("."),
+ }
+ }
+ }
+
+ impl View for GlobalPopupPreview {
+ fn ui(&mut self, ui: &mut egui::Ui) {
+ let mut panel = DesktopSidePanel::new(ui.ctx());
+ DesktopSidePanel::panel().show(ui.ctx(), |ui| panel.ui(ui));
+ DesktopGlobalPopup::new(&mut self.app).ui(ui);
+ }
+ }
+}
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
index 2a04501212d3..ce4caf50e2ea 100644
--- a/src/ui/mod.rs
+++ b/src/ui/mod.rs
@@ -1,19 +1,24 @@
pub mod account_login_view;
pub mod account_management;
pub mod anim;
+pub mod global_popup;
pub mod mention;
pub mod note;
+pub mod persist_state;
pub mod preview;
pub mod profile;
pub mod relay;
+pub mod side_panel;
pub mod username;

pub use account_management::{AccountManagementView, AccountSelectionWidget};
+pub use global_popup::DesktopGlobalPopup;
pub use mention::Mention;
pub use note::Note;
pub use preview::{Preview, PreviewApp};
pub use profile::{ProfilePic, ProfilePreview};
pub use relay::RelayView;
+pub use side_panel::DesktopSidePanel;
pub use username::Username;

use egui::Margin;
diff --git a/src/ui/persist_state.rs b/src/ui/persist_state.rs
new file mode 100644
index 000000000000..8a63ac39aba9
--- /dev/null
+++ b/src/ui/persist_state.rs
@@ -0,0 +1,43 @@
+use egui::util::id_type_map::SerializableAny;
+
+use super::global_popup::GlobalPopupType;
+
+/// PersistState is a helper struct for interacting with egui memory persisted data
+#[derive(Clone)]
+pub struct PersistState<T: SerializableAny> {
+ id: &'static str,
+ default_state: T,
+}
+
+impl<T: SerializableAny> PersistState<T> {
+ pub fn get_state(&self, ctx: &egui::Context) -> T {
+ ctx.data_mut(|d| {
+ d.get_persisted(egui::Id::new(self.id))
+ .unwrap_or(self.default_state.clone())
+ })
+ }
+
+ pub fn set_state(&self, ctx: &egui::Context, new_val: T) {
+ ctx.data_mut(|d| d.insert_persisted(egui::Id::new(self.id), new_val));
+ }
+}
+
+pub static PERSISTED_ACCOUNT_MANAGEMENT: PersistState<bool> = PersistState::<bool> {
+ id: ACCOUNT_MANAGEMENT_VIEW_STATE_ID,
+ default_state: false,
+};
+
+pub static PERSISTED_SIDE_PANEL: PersistState<Option<GlobalPopupType>> =
+ PersistState::<Option<GlobalPopupType>> {
+ id: SIDE_PANEL_VIEW_STATE_ID,
+ default_state: None,
+ };
+
+pub static PERSISTED_GLOBAL_POPUP: PersistState<bool> = PersistState::<bool> {
+ id: GLOBAL_POPUP_VIEW_STATE_ID,
+ default_state: false,
+};
+
+static ACCOUNT_MANAGEMENT_VIEW_STATE_ID: &str = "account management view state";
+static SIDE_PANEL_VIEW_STATE_ID: &str = "side panel view state";
+static GLOBAL_POPUP_VIEW_STATE_ID: &str = "global popup view state";
diff --git a/src/ui/side_panel.rs b/src/ui/side_panel.rs
new file mode 100644
index 000000000000..0a70f99f1667
--- /dev/null
+++ b/src/ui/side_panel.rs
@@ -0,0 +1,93 @@
+use egui::{Button, Layout, SidePanel, Vec2};
+
+use crate::ui::global_popup::GlobalPopupType;
+
+use super::{
+ persist_state::{PERSISTED_GLOBAL_POPUP, PERSISTED_SIDE_PANEL},
+ View,
+};
+
+pub struct DesktopSidePanel<'a> {
+ ctx: &'a egui::Context,
+}
+
+static ID: &str = "left panel";
+
+impl<'a> View for DesktopSidePanel<'a> {
+ fn ui(&mut self, ui: &mut egui::Ui) {
+ DesktopSidePanel::inner(self.ctx, ui);
+ }
+}
+
+impl<'a> DesktopSidePanel<'a> {
+ pub fn new(ctx: &'a egui::Context) -> Self {
+ DesktopSidePanel { ctx }
+ }
+
+ pub fn inner(ctx: &egui::Context, ui: &mut egui::Ui) {
+ let dark_mode = ui.ctx().style().visuals.dark_mode;
+ let spacing_amt = 16.0;
+ ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
+ ui.add_space(spacing_amt);
+ if ui
+ .add_sized(Vec2::new(32.0, 32.0), Button::new("A"))
+ .clicked()
+ {
+ PERSISTED_SIDE_PANEL.set_state(ctx, Some(GlobalPopupType::AccountManagement));
+ PERSISTED_GLOBAL_POPUP.set_state(ctx, true);
+ }
+ ui.add_space(spacing_amt);
+ ui.add(settings_button(dark_mode));
+ ui.add_space(spacing_amt);
+ ui.add(add_column_button(dark_mode));
+ ui.add_space(spacing_amt);
+ });
+ }
+
+ pub fn panel() -> SidePanel {
+ egui::SidePanel::left(ID).resizable(false).exact_width(40.0)
+ }
+}
+
+fn settings_button(dark_mode: bool) -> egui::Button<'static> {
+ let _ = dark_mode;
+ let img_data = egui::include_image!("../../assets/icons/settings_dark_4x.png");
+
+ egui::Button::image(egui::Image::new(img_data).max_width(32.0)).frame(false)
+}
+
+fn add_column_button(dark_mode: bool) -> egui::Button<'static> {
+ let _ = dark_mode;
+ let img_data = egui::include_image!("../../assets/icons/add_column_dark_4x.png");
+
+ egui::Button::image(egui::Image::new(img_data).max_width(32.0)).frame(false)
+}
+
+mod preview {
+ use crate::ui::Preview;
+
+ use super::*;
+
+ pub struct DesktopSidePanelPreview {}
+
+ impl DesktopSidePanelPreview {
+ fn new() -> Self {
+ DesktopSidePanelPreview {}
+ }
+ }
+
+ impl View for DesktopSidePanelPreview {
+ fn ui(&mut self, ui: &mut egui::Ui) {
+ let mut panel = DesktopSidePanel::new(ui.ctx());
+ DesktopSidePanel::panel().show(ui.ctx(), |ui| panel.ui(ui));
+ }
+ }
+
+ impl Preview for DesktopSidePanel<'_> {
+ type Prev = DesktopSidePanelPreview;
+
+ fn preview() -> Self::Prev {
+ DesktopSidePanelPreview::new()
+ }
+ }
+}
diff --git a/src/ui_preview/main.rs b/src/ui_preview/main.rs
index d2bf9a0bbfcf..f7c8d06a03c4 100644
--- a/src/ui_preview/main.rs
+++ b/src/ui_preview/main.rs
@@ -3,8 +3,8 @@ use notedeck::app_creation::{
};
use notedeck::ui::account_login_view::AccountLoginView;
use notedeck::ui::{
- AccountManagementView, AccountSelectionWidget, Preview, PreviewApp, ProfilePic, ProfilePreview,
- RelayView,
+ AccountManagementView, AccountSelectionWidget, DesktopGlobalPopup, DesktopSidePanel, Preview,
+ PreviewApp, ProfilePic, ProfilePreview, RelayView,
};
use std::env;

@@ -88,5 +88,7 @@ async fn main() {
ProfilePic,
AccountManagementView,
AccountSelectionWidget,
+ DesktopSidePanel,
+ DesktopGlobalPopup,
);
}
--
2.39.3 (Apple Git-146)

kernelkind

unread,
May 17, 2024, 11:48:11 AMMay 17
to pat...@damus.io, kernelkind
Signed-off-by: kernelkind <kerne...@gmail.com>
---
src/test_data.rs | 34 +++++++++++++++++++++++++++++++-
src/ui/account_management.rs | 38 ++++--------------------------------
src/ui/global_popup.rs | 7 ++++---
3 files changed, 41 insertions(+), 38 deletions(-)

diff --git a/src/test_data.rs b/src/test_data.rs
index b7d629284921..5797e7ec3bfe 100644
--- a/src/test_data.rs
+++ b/src/test_data.rs
@@ -1,6 +1,8 @@
-use enostr::RelayPool;
+use enostr::{FullKeypair, Pubkey, RelayPool};
use nostrdb::ProfileRecord;

+use crate::account_manager::UserAccount;
+
#[allow(unused_must_use)]
pub fn sample_pool() -> RelayPool {
let mut pool = RelayPool::new();
@@ -54,3 +56,33 @@ const TEST_PROFILE_DATA: [u8; 448] = [
pub fn test_profile_record() -> ProfileRecord<'static> {
ProfileRecord::new_owned(&TEST_PROFILE_DATA).unwrap()
}
+
+const TEN_ACCOUNT_HEXES: [&str; 10] = [
+ "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681",
+ "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
+ "bd1e19980e2c91e6dc657e92c25762ca882eb9272d2579e221f037f93788de91",
+ "5c10ed0678805156d39ef1ef6d46110fe1e7e590ae04986ccf48ba1299cb53e2",
+ "4c96d763eb2fe01910f7e7220b7c7ecdbe1a70057f344b9f79c28af080c3ee30",
+ "edf16b1dd61eab353a83af470cc13557029bff6827b4cb9b7fc9bdb632a2b8e6",
+ "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681",
+ "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
+ "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
+ "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
+];
+
+pub fn get_test_accounts() -> Vec<UserAccount> {
+ TEN_ACCOUNT_HEXES
+ .iter()
+ .map(|account_hex| {
+ let key = FullKeypair::new(
+ Pubkey::from_hex(account_hex).unwrap(),
+ FullKeypair::generate().secret_key,
+ );
+
+ UserAccount {
+ key,
+ relays: sample_pool(),
+ }
+ })
+ .collect()
+}
diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs
index 419768852166..f5ef146ece85 100644
--- a/src/ui/account_management.rs
+++ b/src/ui/account_management.rs
@@ -285,51 +285,21 @@ impl<'a> AccountSelectionWidget<'a> {
// PREVIEWS

mod preview {
- use enostr::{FullKeypair, Pubkey};
use nostrdb::{Config, Ndb};

use super::*;
+ use crate::imgcache::ImageCache;
use crate::key_storage::KeyStorage;
use crate::relay_generation::RelayGenerator;
- use crate::{imgcache::ImageCache, test_data};
+ use crate::test_data;
use std::path::Path;

- const ACCOUNT_HEXES: [&str; 10] = [
- "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681",
- "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
- "bd1e19980e2c91e6dc657e92c25762ca882eb9272d2579e221f037f93788de91",
- "5c10ed0678805156d39ef1ef6d46110fe1e7e590ae04986ccf48ba1299cb53e2",
- "4c96d763eb2fe01910f7e7220b7c7ecdbe1a70057f344b9f79c28af080c3ee30",
- "edf16b1dd61eab353a83af470cc13557029bff6827b4cb9b7fc9bdb632a2b8e6",
- "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681",
- "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
- "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
- "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
- ];
-
pub struct AccountManagementPreview {
accounts: Vec<UserAccount>,
ndb: Ndb,
img_cache: ImageCache,
}

- fn get_accounts() -> Vec<UserAccount> {
- ACCOUNT_HEXES
- .iter()
- .map(|account_hex| {
- let key = FullKeypair::new(
- Pubkey::from_hex(account_hex).unwrap(),
- FullKeypair::generate().secret_key,
- );
-
- UserAccount {
- key,
- relays: test_data::sample_pool(),
- }
- })
- .collect()
- }
-
fn get_ndb_and_img_cache() -> (Ndb, ImageCache) {
let mut config = Config::new();
config.set_ingester_threads(2);
@@ -344,7 +314,7 @@ mod preview {

impl AccountManagementPreview {
fn new() -> Self {
- let accounts = get_accounts();
+ let accounts = test_data::get_test_accounts();
let (ndb, img_cache) = get_ndb_and_img_cache();

AccountManagementPreview {
@@ -388,7 +358,7 @@ mod preview {

impl AccountSelectionPreview {
fn new() -> Self {
- let accounts = get_accounts();
+ let accounts = test_data::get_test_accounts();
let (ndb, img_cache) = get_ndb_and_img_cache();
AccountSelectionPreview {
accounts,
diff --git a/src/ui/global_popup.rs b/src/ui/global_popup.rs
index e7753b1fccc6..994fb6d1bf42 100644
--- a/src/ui/global_popup.rs
+++ b/src/ui/global_popup.rs
@@ -91,6 +91,7 @@ impl<'a> DesktopGlobalPopup<'a> {

mod preview {
use crate::{
+ test_data::get_test_accounts,
ui::{DesktopSidePanel, Preview, View},
Damus,
};
@@ -111,9 +112,9 @@ mod preview {

impl GlobalPopupPreview {
fn new() -> Self {
- GlobalPopupPreview {
- app: Damus::mock("."),
- }
+ let mut app = Damus::mock(".");
+ app.accounts = get_test_accounts();
+ GlobalPopupPreview { app }
}
}

--
2.39.3 (Apple Git-146)

kernelkind

unread,
May 17, 2024, 11:48:14 AMMay 17
to pat...@damus.io, kernelkind
Signed-off-by: kernelkind <kerne...@gmail.com>
---
src/ui/account_management.rs | 158 ++++++++++++++++++-----------------
1 file changed, 82 insertions(+), 76 deletions(-)

diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs
index f5ef146ece85..96a06cf47cd3 100644
--- a/src/ui/account_management.rs
+++ b/src/ui/account_management.rs
@@ -6,7 +6,9 @@ use crate::{
};
use egui::{Align, Button, Frame, Id, Layout, Margin, RichText, ScrollArea, Sense, Vec2};

+use super::global_popup::GlobalPopupType;
use super::persist_state::PERSISTED_ACCOUNT_MANAGEMENT;
+use super::profile::preview::SimpleProfilePreview;

pub struct AccountManagementView<'a> {
account_manager: AccountManager<'a>,
@@ -37,88 +39,41 @@ impl<'a> AccountManagementView<'a> {
fn show(&mut self, ui: &mut egui::Ui) {
ui.add(self.buttons_widget());
ui.add_space(8.0);
- self.show_accounts(ui);
+ scroll_area().show(ui, |ui| {
+ self.show_accounts(ui);
+ });
}

fn show_accounts(&mut self, ui: &mut egui::Ui) {
- scroll_area().show(ui, |ui| {
- ui.horizontal_wrapped(|ui| {
+ ui.horizontal_wrapped(|ui| {
+ let maybe_remove = self.simple_preview_controller.set_profile_previews(
+ &self.account_manager,
+ ui,
+ PERSISTED_ACCOUNT_MANAGEMENT.get_state(ui.ctx()),
+ desktop_account_card_ui(),
+ );
+
+ self.maybe_remove_accounts(maybe_remove);
+ });
+ }
+
+ fn show_accounts_mobile(&mut self, ui: &mut egui::Ui) {
+ ui.allocate_ui_with_layout(
+ Vec2::new(ui.available_size_before_wrap().x, 32.0),
+ Layout::top_down(egui::Align::Min),
+ |ui| {
+ // create all account 'cards' and get the indicies the user requested to remove
let maybe_remove = self.simple_preview_controller.set_profile_previews(
&self.account_manager,
ui,
PERSISTED_ACCOUNT_MANAGEMENT.get_state(ui.ctx()),
- |ui, preview, edit_mode| {
- let mut should_remove = false;
-
- ui.add_sized(preview.dimensions(), |ui: &mut egui::Ui| {
- simple_preview_frame(ui)
- .show(ui, |ui| {
- ui.vertical_centered(|ui| {
- ui.add(preview);
- if edit_mode {
- should_remove = ui
- .add(delete_button(ui.visuals().dark_mode))
- .clicked();
- }
- });
- })
- .response
- });
- should_remove
- },
+ mobile_account_card_ui(), // closure for creating an account 'card'
);

+ // remove all account indicies user requested
self.maybe_remove_accounts(maybe_remove);
- });
- });
- }
-
- fn show_accounts_mobile(&mut self, ui: &mut egui::Ui) {
- scroll_area().show(ui, |ui| {
- ui.allocate_ui_with_layout(
- Vec2::new(ui.available_size_before_wrap().x, 32.0),
- Layout::top_down(egui::Align::Min),
- |ui| {
- let maybe_remove = self.simple_preview_controller.set_profile_previews(
- &self.account_manager,
- ui,
- PERSISTED_ACCOUNT_MANAGEMENT.get_state(ui.ctx()),
- |ui, preview, edit_mode| {
- let mut should_remove = false;
-
- ui.add_sized(
- Vec2::new(ui.available_width(), 50.0),
- |ui: &mut egui::Ui| {
- Frame::none()
- .show(ui, |ui| {
- ui.horizontal(|ui| {
- ui.add(preview);
- if edit_mode {
- ui.with_layout(
- Layout::right_to_left(Align::Center),
- |ui| {
- should_remove = ui
- .add(delete_button(
- ui.visuals().dark_mode,
- ))
- .clicked();
- },
- );
- }
- });
- })
- .response
- },
- );
- ui.add_space(16.0);
- should_remove
- },
- );
-
- self.maybe_remove_accounts(maybe_remove);
- },
- );
- });
+ },
+ );
}

fn maybe_remove_accounts(&mut self, account_indices: Option<Vec<usize>>) {
@@ -132,10 +87,12 @@ impl<'a> AccountManagementView<'a> {
fn show_mobile(&mut self, ui: &mut egui::Ui) -> egui::Response {
egui::CentralPanel::default()
.show(ui.ctx(), |ui| {
- ui.add(title());
+ ui.add(mobile_title());
ui.add(self.buttons_widget());
ui.add_space(8.0);
- self.show_accounts_mobile(ui);
+ scroll_area().show(ui, |ui| {
+ self.show_accounts_mobile(ui);
+ });
})
.response
}
@@ -172,6 +129,55 @@ impl<'a> AccountManagementView<'a> {
}
}

+fn mobile_account_card_ui(
+) -> fn(ui: &mut egui::Ui, preview: SimpleProfilePreview, edit_mode: bool) -> bool {
+ |ui, preview, edit_mode| {
+ let mut should_remove = false;
+
+ ui.add_sized(
+ Vec2::new(ui.available_width(), 50.0),
+ |ui: &mut egui::Ui| {
+ Frame::none()
+ .show(ui, |ui| {
+ ui.horizontal(|ui| {
+ ui.add(preview);
+ if edit_mode {
+ ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
+ should_remove =
+ ui.add(delete_button(ui.visuals().dark_mode)).clicked();
+ });
+ }
+ });
+ })
+ .response
+ },
+ );
+ ui.add_space(16.0);
+ should_remove
+ }
+}
+
+fn desktop_account_card_ui(
+) -> fn(ui: &mut egui::Ui, preview: SimpleProfilePreview, edit_mode: bool) -> bool {
+ |ui: &mut egui::Ui, preview, edit_mode| {
+ let mut should_remove = false;
+
+ ui.add_sized(preview.dimensions(), |ui: &mut egui::Ui| {
+ simple_preview_frame(ui)
+ .show(ui, |ui| {
+ ui.vertical_centered(|ui| {
+ ui.add(preview);
+ if edit_mode {
+ should_remove = ui.add(delete_button(ui.visuals().dark_mode)).clicked();
+ }
+ });
+ })
+ .response
+ });
+ should_remove
+ }
+}
+
impl<'a> FromApp<'a> for AccountManagementView<'a> {
fn from_app(app: &'a mut crate::Damus) -> Self {
// TODO: don't hard-code key store & relay generator
@@ -195,11 +201,11 @@ fn simple_preview_frame(ui: &mut egui::Ui) -> Frame {
.inner_margin(12.0)
}

-fn title() -> impl egui::Widget {
+fn mobile_title() -> impl egui::Widget {
|ui: &mut egui::Ui| {
ui.vertical_centered(|ui| {
ui.label(
- RichText::new("Accounts")
+ RichText::new(GlobalPopupType::AccountManagement.title())
.text_style(NotedeckTextStyle::Heading2.text_style())
.strong(),

William Casarin

unread,
May 17, 2024, 8:02:04 PMMay 17
to kernelkind, pat...@damus.io
On Fri, May 17, 2024 at 11:47:42AM GMT, kernelkind wrote:
>Create a side panel UI element for desktop with three buttons for:
>adding a column, settings, and account management. The account
>management button is temporary pending a better design. It is the only
>one that is interactable at the moment. When the user clicks it, the
>global popup window will be shown and the AccountManagementView will be
>presented on the window. The user can click on the X on the top right of
>the window to close it.
>
>Signed-off-by: kernelkind <kerne...@gmail.com>
>---

>diff --git a/src/ui/side_panel.rs b/src/ui/side_panel.rs
>+++ b/src/ui/side_panel.rs
>+
>+pub struct DesktopSidePanel<'a> {
>+ ctx: &'a egui::Context,
>+}

you should never need to hold the context like this, you can always get
it from the Ui:

pub struct DesktopSidePanel { }

pub fn inner(ui: &mut egui::Ui) {
let dark_mode = ui.ctx().style().visuals.dark_mode;
let spacing_amt = 16.0;
ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
ui.add_space(spacing_amt);
if ui
.add_sized(Vec2::new(32.0, 32.0), Button::new("A"))
.clicked()
{
PERSISTED_SIDE_PANEL.set_state(ui.ctx(), Some(GlobalPopupType::AccountManagement));
PERSISTED_GLOBAL_POPUP.set_state(ui.ctx(), true);
}
ui.add_space(spacing_amt);
ui.add(settings_button(dark_mode));
ui.add_space(spacing_amt);
ui.add(add_column_button(dark_mode));
ui.add_space(spacing_amt);
});
}

Reply all
Reply to author
Forward
0 new messages