mirror of
https://github.com/aljazceru/notedeck.git
synced 2026-01-19 08:14:20 +01:00
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>
This commit is contained in:
committed by
William Casarin
parent
409e8c2e3a
commit
0ac131ef06
@@ -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 => {}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
@@ -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;
|
||||
card_resp: egui::Response,
|
||||
) -> Option<ProfilePreviewAction> {
|
||||
let mut op: Option<ProfilePreviewAction> = None;
|
||||
|
||||
ui.add_sized(Vec2::new(width, 50.0), |ui: &mut egui::Ui| {
|
||||
Frame::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
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user