commit 0ac131ef06ce4d06113d81868deb24af8aa7614d
parent 409e8c2e3a890b5b4d7553c023ad0144e842733a
Author: kernelkind <kernelkind@gmail.com>
Date: Tue, 26 Nov 2024 23:40:33 -0500
ui: update account management to design
Closes: https://github.com/damus-io/notedeck/issues/486
Fixes: https://github.com/damus-io/notedeck/issues/444
Signed-off-by: kernelkind <kernelkind@gmail.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
5 files changed, 106 insertions(+), 79 deletions(-)
diff --git a/src/accounts/mod.rs b/src/accounts/mod.rs
@@ -131,7 +131,16 @@ impl Accounts {
self.select_account(selected_index - 1);
}
Ordering::Equal => {
- self.clear_selected_account();
+ if self.accounts.is_empty() {
+ // If no accounts remain, clear the selection
+ self.clear_selected_account();
+ } else if index >= self.accounts.len() {
+ // If the removed account was the last one, select the new last account
+ self.select_account(self.accounts.len() - 1);
+ } else {
+ // Otherwise, select the account at the same position
+ self.select_account(index);
+ }
}
Ordering::Less => {}
}
diff --git a/src/app_style.rs b/src/app_style.rs
@@ -81,6 +81,7 @@ pub fn desktop_font_size(text_style: &NotedeckTextStyle) -> f32 {
NotedeckTextStyle::Monospace => 13.0,
NotedeckTextStyle::Button => 13.0,
NotedeckTextStyle::Small => 12.0,
+ NotedeckTextStyle::Tiny => 11.0,
}
}
@@ -94,6 +95,7 @@ pub fn mobile_font_size(text_style: &NotedeckTextStyle) -> f32 {
NotedeckTextStyle::Monospace => 13.0,
NotedeckTextStyle::Button => 13.0,
NotedeckTextStyle::Small => 12.0,
+ NotedeckTextStyle::Tiny => 11.0,
}
}
@@ -114,6 +116,7 @@ pub enum NotedeckTextStyle {
Monospace,
Button,
Small,
+ Tiny,
}
impl NotedeckTextStyle {
@@ -126,6 +129,7 @@ impl NotedeckTextStyle {
Self::Monospace => TextStyle::Monospace,
Self::Button => TextStyle::Button,
Self::Small => TextStyle::Small,
+ Self::Tiny => TextStyle::Name("Tiny".into()),
}
}
@@ -138,6 +142,7 @@ impl NotedeckTextStyle {
Self::Monospace => FontFamily::Monospace,
Self::Button => FontFamily::Proportional,
Self::Small => FontFamily::Proportional,
+ Self::Tiny => FontFamily::Proportional,
}
}
}
@@ -154,6 +159,7 @@ pub fn create_themed_visuals(theme: ColorTheme, default: Visuals) -> Visuals {
color: theme.selection_color,
},
},
+ warn_fg_color: theme.warn_fg_color,
widgets: Widgets {
noninteractive: WidgetVisuals {
bg_fill: theme.noninteractive_bg_fill,
diff --git a/src/colors.rs b/src/colors.rs
@@ -8,7 +8,7 @@ pub const PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9);
pub const GRAY_SECONDARY: Color32 = Color32::from_rgb(0x8A, 0x8A, 0x8A);
const BLACK: Color32 = Color32::from_rgb(0x00, 0x00, 0x00);
const RED_700: Color32 = Color32::from_rgb(0xC7, 0x37, 0x5A);
-//const ORANGE_700: Color32 = Color32::from_rgb(0xF6, 0xB1, 0x4A);
+const ORANGE_700: Color32 = Color32::from_rgb(0xF6, 0xB1, 0x4A);
// BACKGROUNDS
const SEMI_DARKER_BG: Color32 = Color32::from_rgb(0x39, 0x39, 0x39);
@@ -30,7 +30,7 @@ pub struct ColorTheme {
pub extreme_bg_color: Color32,
pub text_color: Color32,
pub err_fg_color: Color32,
- //pub warn_fg_color: Color32,
+ pub warn_fg_color: Color32,
pub hyperlink_color: Color32,
pub selection_color: Color32,
@@ -57,7 +57,7 @@ pub fn desktop_dark_color_theme() -> ColorTheme {
extreme_bg_color: DARK_ISH_BG,
text_color: Color32::WHITE,
err_fg_color: RED_700,
- //warn_fg_color: ORANGE_700,
+ warn_fg_color: ORANGE_700,
hyperlink_color: PURPLE,
selection_color: PURPLE_ALT,
@@ -93,7 +93,7 @@ pub fn light_color_theme() -> ColorTheme {
extreme_bg_color: LIGHTER_GRAY,
text_color: BLACK,
err_fg_color: RED_700,
- //warn_fg_color: ORANGE_700,
+ warn_fg_color: ORANGE_700,
hyperlink_color: PURPLE,
selection_color: PURPLE_ALT,
diff --git a/src/ui/accounts.rs b/src/ui/accounts.rs
@@ -1,4 +1,4 @@
-use crate::colors::PINK;
+use crate::colors::{self, PINK};
use crate::imgcache::ImageCache;
use crate::{
accounts::Accounts,
@@ -6,7 +6,9 @@ use crate::{
ui::{Preview, PreviewConfig, View},
Damus,
};
-use egui::{Align, Button, Frame, Image, InnerResponse, Layout, RichText, ScrollArea, Ui, Vec2};
+use egui::{
+ Align, Button, Frame, Image, InnerResponse, Layout, RichText, ScrollArea, Stroke, Ui, Vec2,
+};
use nostrdb::{Ndb, Transaction};
use super::profile::preview::SimpleProfilePreview;
@@ -25,7 +27,7 @@ pub enum AccountsViewResponse {
}
#[derive(Debug)]
-enum ProfilePreviewOp {
+enum ProfilePreviewAction {
RemoveAccount,
SwitchTo,
}
@@ -72,14 +74,9 @@ impl<'a> AccountsView<'a> {
};
for i in 0..accounts.num_accounts() {
- let account_pubkey = accounts
- .get_account(i)
- .map(|account| account.pubkey.bytes());
-
- let account_pubkey = if let Some(pubkey) = account_pubkey {
- pubkey
- } else {
- continue;
+ let (account_pubkey, has_nsec) = match accounts.get_account(i) {
+ Some(acc) => (acc.pubkey.bytes(), acc.secret_key.is_some()),
+ None => continue,
};
let profile = ndb.get_profile_by_pubkey(&txn, account_pubkey).ok();
@@ -91,15 +88,22 @@ impl<'a> AccountsView<'a> {
};
let profile_peview_view = {
- let width = ui.available_width();
- let preview = SimpleProfilePreview::new(profile.as_ref(), img_cache);
- show_profile_card(ui, preview, width, is_selected)
+ let max_size = egui::vec2(ui.available_width(), 77.0);
+ let resp = ui.allocate_response(max_size, egui::Sense::click());
+ ui.allocate_ui_at_rect(resp.rect, |ui| {
+ let preview =
+ SimpleProfilePreview::new(profile.as_ref(), img_cache, has_nsec);
+ show_profile_card(ui, preview, max_size, is_selected, resp)
+ })
+ .inner
};
if let Some(op) = profile_peview_view {
return_op = Some(match op {
- ProfilePreviewOp::SwitchTo => AccountsViewResponse::SelectAccount(i),
- ProfilePreviewOp::RemoveAccount => {
+ ProfilePreviewAction::SwitchTo => {
+ AccountsViewResponse::SelectAccount(i)
+ }
+ ProfilePreviewAction::RemoveAccount => {
AccountsViewResponse::RemoveAccount(i)
}
});
@@ -130,30 +134,36 @@ impl<'a> AccountsView<'a> {
fn show_profile_card(
ui: &mut egui::Ui,
preview: SimpleProfilePreview,
- width: f32,
+ max_size: egui::Vec2,
is_selected: bool,
-) -> Option<ProfilePreviewOp> {
- let mut op: Option<ProfilePreviewOp> = None;
-
- ui.add_sized(Vec2::new(width, 50.0), |ui: &mut egui::Ui| {
- Frame::none()
+ card_resp: egui::Response,
+) -> Option<ProfilePreviewAction> {
+ let mut op: Option<ProfilePreviewAction> = None;
+
+ ui.add_sized(max_size, |ui: &mut egui::Ui| {
+ let mut frame = Frame::none();
+ if is_selected || card_resp.hovered() {
+ frame = frame.fill(ui.visuals().noninteractive().weak_bg_fill)
+ }
+ if is_selected {
+ frame = frame.stroke(Stroke::new(2.0, colors::PINK))
+ }
+ frame
+ .rounding(8.0)
+ .inner_margin(8.0)
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.add(preview);
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
- if is_selected {
- ui.add(selected_widget());
- } else {
- if ui
- .add(switch_button(ui.style().visuals.dark_mode))
- .clicked()
- {
- op = Some(ProfilePreviewOp::SwitchTo);
- }
- if ui.add(sign_out_button(ui)).clicked() {
- op = Some(ProfilePreviewOp::RemoveAccount)
- }
+ if card_resp.clicked() {
+ op = Some(ProfilePreviewAction::SwitchTo);
+ }
+ if ui
+ .add_sized(egui::Vec2::new(84.0, 32.0), sign_out_button())
+ .clicked()
+ {
+ op = Some(ProfilePreviewAction::RemoveAccount)
}
});
});
@@ -183,34 +193,8 @@ fn add_account_button() -> Button<'static> {
.frame(false)
}
-fn sign_out_button(ui: &egui::Ui) -> egui::Button<'static> {
- let img_data = egui::include_image!("../../assets/icons/signout_icon_4x.png");
- let img = Image::new(img_data).fit_to_exact_size(Vec2::new(16.0, 16.0));
-
- egui::Button::image_and_text(
- img,
- RichText::new("Sign out").color(ui.visuals().noninteractive().fg_stroke.color),
- )
- .frame(false)
-}
-
-fn switch_button(dark_mode: bool) -> egui::Button<'static> {
- let _ = dark_mode;
-
- egui::Button::new("Switch").min_size(Vec2::new(76.0, 32.0))
-}
-
-fn selected_widget() -> impl egui::Widget {
- |ui: &mut egui::Ui| {
- Frame::none()
- .show(ui, |ui| {
- ui.label(RichText::new("Selected").size(13.0).color(PINK));
- let img_data = egui::include_image!("../../assets/icons/select_icon_3x.png");
- let img = Image::new(img_data).max_size(Vec2::new(16.0, 16.0));
- ui.add(img);
- })
- .response
- }
+fn sign_out_button() -> egui::Button<'static> {
+ egui::Button::new(RichText::new("Sign out"))
}
// PREVIEWS
diff --git a/src/ui/profile/preview.rs b/src/ui/profile/preview.rs
@@ -1,11 +1,11 @@
-use crate::app_style::NotedeckTextStyle;
+use crate::app_style::{get_font_size, NotedeckTextStyle};
use crate::imgcache::ImageCache;
use crate::storage::{DataPath, DataPathType};
use crate::ui::ProfilePic;
use crate::user_account::UserAccount;
use crate::{colors, images, DisplayName};
use egui::load::TexturePoll;
-use egui::{Frame, RichText, Sense, Widget};
+use egui::{Frame, Label, RichText, Sense, Widget};
use egui_extras::Size;
use enostr::NoteId;
use nostrdb::ProfileRecord;
@@ -93,11 +93,20 @@ impl egui::Widget for ProfilePreview<'_, '_> {
pub struct SimpleProfilePreview<'a, 'cache> {
profile: Option<&'a ProfileRecord<'a>>,
cache: &'cache mut ImageCache,
+ is_nsec: bool,
}
impl<'a, 'cache> SimpleProfilePreview<'a, 'cache> {
- pub fn new(profile: Option<&'a ProfileRecord<'a>>, cache: &'cache mut ImageCache) -> Self {
- SimpleProfilePreview { profile, cache }
+ pub fn new(
+ profile: Option<&'a ProfileRecord<'a>>,
+ cache: &'cache mut ImageCache,
+ is_nsec: bool,
+ ) -> Self {
+ SimpleProfilePreview {
+ profile,
+ cache,
+ is_nsec,
+ }
}
}
@@ -108,6 +117,16 @@ impl egui::Widget for SimpleProfilePreview<'_, '_> {
ui.add(ProfilePic::new(self.cache, get_profile_url(self.profile)).size(48.0));
ui.vertical(|ui| {
ui.add(display_name_widget(get_display_name(self.profile), true));
+ if !self.is_nsec {
+ ui.add(
+ Label::new(
+ RichText::new("View only mode")
+ .size(get_font_size(ui.ctx(), &NotedeckTextStyle::Tiny))
+ .color(ui.visuals().warn_fg_color),
+ )
+ .selectable(false),
+ );
+ }
});
})
.response
@@ -203,8 +222,10 @@ fn display_name_widget(
) -> impl egui::Widget + '_ {
move |ui: &mut egui::Ui| match display_name {
DisplayName::One(n) => {
- let name_response =
- ui.label(RichText::new(n).text_style(NotedeckTextStyle::Heading3.text_style()));
+ let name_response = ui.add(
+ Label::new(RichText::new(n).text_style(NotedeckTextStyle::Heading3.text_style()))
+ .selectable(false),
+ );
if add_placeholder_space {
ui.add_space(16.0);
}
@@ -215,14 +236,21 @@ fn display_name_widget(
display_name,
username,
} => {
- ui.label(
- RichText::new(display_name).text_style(NotedeckTextStyle::Heading3.text_style()),
+ ui.add(
+ Label::new(
+ RichText::new(display_name)
+ .text_style(NotedeckTextStyle::Heading3.text_style()),
+ )
+ .selectable(false),
);
- ui.label(
- RichText::new(format!("@{}", username))
- .size(12.0)
- .color(colors::MID_GRAY),
+ ui.add(
+ Label::new(
+ RichText::new(format!("@{}", username))
+ .size(12.0)
+ .color(colors::MID_GRAY),
+ )
+ .selectable(false),
)
}
}