commit adba4ece22c252ca47696191f8cbaf4108861480
parent 9000fc2c439a9208e0b8cee8296f8772cdcea521
Author: William Casarin <jb55@jb55.com>
Date: Mon, 20 Oct 2025 11:07:04 -0700
Merge sidebar fixes by kernel #1163
kernelkind (9):
update egui-nav
fix: nav drawer shadow extends all the way vertically
drawer: only use drag on mobile
new `egui`
update egui_nav
refactor: move `galley_centered_pos` to notedeck_ui
refactor: rename assets
assets: add accounts image
chrome: ui polish
Diffstat:
9 files changed, 452 insertions(+), 307 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1420,17 +1420,17 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "ecolor"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"bytemuck",
- "emath 0.31.1 (git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72)",
+ "emath 0.31.1 (git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b)",
"serde",
]
[[package]]
name = "eframe"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"ahash",
"bytemuck",
@@ -1466,13 +1466,13 @@ dependencies = [
[[package]]
name = "egui"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"accesskit",
"ahash",
"backtrace",
"bitflags 2.9.1",
- "emath 0.31.1 (git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72)",
+ "emath 0.31.1 (git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b)",
"epaint",
"log",
"nohash-hasher",
@@ -1484,7 +1484,7 @@ dependencies = [
[[package]]
name = "egui-wgpu"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"ahash",
"bytemuck",
@@ -1503,7 +1503,7 @@ dependencies = [
[[package]]
name = "egui-winit"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"ahash",
"arboard",
@@ -1521,7 +1521,7 @@ dependencies = [
[[package]]
name = "egui_extras"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"ahash",
"egui",
@@ -1538,7 +1538,7 @@ dependencies = [
[[package]]
name = "egui_glow"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"ahash",
"bytemuck",
@@ -1555,11 +1555,12 @@ dependencies = [
[[package]]
name = "egui_nav"
version = "0.2.0"
-source = "git+https://github.com/damus-io/egui-nav?rev=8767df4bc8d12a90fbcee7493d9c9604fe30f1a2#8767df4bc8d12a90fbcee7493d9c9604fe30f1a2"
+source = "git+https://github.com/damus-io/egui-nav?rev=6b4b96bae35270434abd69b24fa9943edc3f5b0b#6b4b96bae35270434abd69b24fa9943edc3f5b0b"
dependencies = [
"bitflags 2.9.1",
"egui",
"egui_extras",
+ "tracing",
]
[[package]]
@@ -1618,7 +1619,7 @@ checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b"
[[package]]
name = "emath"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"bytemuck",
"serde",
@@ -1716,13 +1717,13 @@ dependencies = [
[[package]]
name = "epaint"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
dependencies = [
"ab_glyph",
"ahash",
"bytemuck",
"ecolor",
- "emath 0.31.1 (git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72)",
+ "emath 0.31.1 (git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b)",
"epaint_default_fonts",
"log",
"nohash-hasher",
@@ -1734,7 +1735,7 @@ dependencies = [
[[package]]
name = "epaint_default_fonts"
version = "0.31.1"
-source = "git+https://github.com/damus-io/egui?rev=c9073832236dadec21f263ef1f1ffa4d7a159f72#c9073832236dadec21f263ef1f1ffa4d7a159f72"
+source = "git+https://github.com/kernelkind/egui?rev=e05638c40ef734312b3b3e36397d389d0a78b10b#e05638c40ef734312b3b3e36397d389d0a78b10b"
[[package]]
name = "equator"
diff --git a/Cargo.toml b/Cargo.toml
@@ -28,7 +28,7 @@ egui = { version = "0.31.1", features = ["serde"] }
egui-wgpu = "0.31.1"
egui_extras = { version = "0.31.1", features = ["all_loaders"] }
egui-winit = { version = "0.31.1", features = ["android-game-activity", "clipboard"] }
-egui_nav = { git = "https://github.com/damus-io/egui-nav", rev = "8767df4bc8d12a90fbcee7493d9c9604fe30f1a2" }
+egui_nav = { git = "https://github.com/damus-io/egui-nav", rev = "6b4b96bae35270434abd69b24fa9943edc3f5b0b" }
egui_tabs = { git = "https://github.com/damus-io/egui-tabs", rev = "6eb91740577b374a8a6658c09c9a4181299734d0" }
#egui_virtual_list = "0.6.0"
egui_virtual_list = { git = "https://github.com/jb55/hello_egui", rev = "a66b6794f5e707a2f4109633770e02b02fb722e1" }
@@ -107,12 +107,12 @@ strip = true # Strip symbols from binary*
#egui_extras = { path = "/home/jb55/dev/github/emilk/egui/crates/egui_extras" }
#epaint = { path = "/home/jb55/dev/github/emilk/egui/crates/epaint" }
-egui = { git = "https://github.com/damus-io/egui", rev = "c9073832236dadec21f263ef1f1ffa4d7a159f72" }
-eframe = { git = "https://github.com/damus-io/egui", rev = "c9073832236dadec21f263ef1f1ffa4d7a159f72" }
-egui-winit = { git = "https://github.com/damus-io/egui", rev = "c9073832236dadec21f263ef1f1ffa4d7a159f72" }
-egui-wgpu = { git = "https://github.com/damus-io/egui", rev = "c9073832236dadec21f263ef1f1ffa4d7a159f72" }
-egui_extras = { git = "https://github.com/damus-io/egui", rev = "c9073832236dadec21f263ef1f1ffa4d7a159f72" }
-epaint = { git = "https://github.com/damus-io/egui", rev = "c9073832236dadec21f263ef1f1ffa4d7a159f72" }
+egui = { git = "https://github.com/kernelkind/egui", rev = "e05638c40ef734312b3b3e36397d389d0a78b10b" }
+eframe = { git = "https://github.com/kernelkind/egui", rev = "e05638c40ef734312b3b3e36397d389d0a78b10b" }
+egui-winit = { git = "https://github.com/kernelkind/egui", rev = "e05638c40ef734312b3b3e36397d389d0a78b10b" }
+egui-wgpu = { git = "https://github.com/kernelkind/egui", rev = "e05638c40ef734312b3b3e36397d389d0a78b10b" }
+egui_extras = { git = "https://github.com/kernelkind/egui", rev = "e05638c40ef734312b3b3e36397d389d0a78b10b" }
+epaint = { git = "https://github.com/kernelkind/egui", rev = "e05638c40ef734312b3b3e36397d389d0a78b10b" }
puffin = { git = "https://github.com/jb55/puffin", package = "puffin", rev = "c6a6242adaf90b6292c0f462d2acd34d96d224d2" }
puffin_egui = { git = "https://github.com/jb55/puffin", package = "puffin_egui", rev = "c6a6242adaf90b6292c0f462d2acd34d96d224d2" }
#winit = { git = "https://github.com/damus-io/winit", rev = "701a43d3c6479b0a3869acd2cebbfd410d399a59" }
diff --git a/assets/icons/accounts_4x.png b/assets/icons/accounts_4x.png
Binary files differ.
diff --git a/assets/icons/accounts.png b/assets/icons/profile.png
Binary files differ.
diff --git a/crates/notedeck_chrome/src/chrome.rs b/crates/notedeck_chrome/src/chrome.rs
@@ -6,12 +6,16 @@ use crate::ChromeOptions;
use bitflags::bitflags;
use eframe::CreationContext;
use egui::{
- vec2, Button, Color32, CornerRadius, Label, Layout, Rect, RichText, ThemePreference, Widget,
+ vec2, Color32, CornerRadius, Label, Layout, Margin, Rect, RichText, Sense, ThemePreference, Ui,
+ Widget,
};
use egui_extras::{Size, StripBuilder};
use egui_nav::RouteResponse;
use egui_nav::{NavAction, NavDrawer};
use nostrdb::{ProfileRecord, Transaction};
+use notedeck::fonts::get_font_size;
+use notedeck::name::get_display_name;
+use notedeck::ui::is_compiled_as_mobile;
use notedeck::AppResponse;
use notedeck::DrawerRouter;
use notedeck::Error;
@@ -22,9 +26,7 @@ use notedeck::{
};
use notedeck_columns::{timeline::TimelineKind, Damus};
use notedeck_dave::{Dave, DaveAvatar};
-use notedeck_ui::{
- app_images, expanding_button, AnimationHelper, ProfilePic, ICON_EXPANSION_MULTIPLE, ICON_WIDTH,
-};
+use notedeck_ui::{app_images, expanding_button, galley_centered_pos, ProfilePic};
use std::collections::HashMap;
#[derive(Default)]
@@ -211,33 +213,45 @@ impl Chrome {
.navigating(self.nav.navigating)
.returning(self.nav.returning)
.drawer_focused(self.nav.drawer_focused)
- .opened_offset(100.0);
+ .drag(is_compiled_as_mobile())
+ .opened_offset(240.0);
let resp = drawer.show_mut(ui, |ui, route| match route {
ChromeRoute::Chrome => {
ui.painter().rect_filled(
ui.available_rect_before_wrap(),
CornerRadius::ZERO,
- ui.visuals().panel_fill,
- );
- _ = ui.vertical_centered(|ui| {
- self.topdown_sidebar(ui, app_ctx.i18n);
- });
-
- ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
- let options = if amt_keyboard_open > 0.0 {
- SidebarOptions::Compact
+ if ui.visuals().dark_mode {
+ egui::Color32::BLACK
} else {
- SidebarOptions::default()
- };
- let response = bottomup_sidebar(self, app_ctx, ui, options);
+ egui::Color32::WHITE
+ },
+ );
+ egui::Frame::new()
+ .inner_margin(Margin::same(16))
+ .show(ui, |ui| {
+ let options = if amt_keyboard_open > 0.0 {
+ SidebarOptions::Compact
+ } else {
+ SidebarOptions::default()
+ };
+
+ let response = ui
+ .with_layout(Layout::top_down(egui::Align::Min), |ui| {
+ topdown_sidebar(self, app_ctx, ui, options)
+ })
+ .inner;
+
+ ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
+ ui.add(milestone_name(app_ctx.i18n));
+ });
- RouteResponse {
- response,
- can_take_drag_from: Vec::new(),
- }
- })
- .inner
+ RouteResponse {
+ response,
+ can_take_drag_from: Vec::new(),
+ }
+ })
+ .inner
}
ChromeRoute::App => {
let resp = self.apps[self.active as usize].update(app_ctx, ui);
@@ -287,24 +301,29 @@ impl Chrome {
// if the soft keyboard is open, shrink the chrome contents
let mut action: Option<ChromePanelAction> = None;
- // build a strip to carve out the soft keyboard inset
- StripBuilder::new(ui)
- .size(Size::remainder())
- .size(Size::exact(keyboard_height))
- .vertical(|mut strip| {
- // the actual content, shifted up because of the soft keyboard
- strip.cell(|ui| {
- action = self.panel(ctx, ui, keyboard_height);
- });
- // the filler space taken up by the soft keyboard
- strip.cell(|ui| {
- // keyboard-visibility virtual keyboard
- if virtual_keyboard && keyboard_height > 0.0 {
- virtual_keyboard_ui(ui, ui.available_rect_before_wrap())
- }
+ if keyboard_height == 0.0 {
+ action = self.panel(ctx, ui, keyboard_height);
+ } else {
+ // build a strip to carve out the soft keyboard inset
+ StripBuilder::new(ui)
+ .size(Size::remainder())
+ .size(Size::exact(keyboard_height))
+ .vertical(|mut strip| {
+ // the actual content, shifted up because of the soft keyboard
+ strip.cell(|ui| {
+ action = self.panel(ctx, ui, keyboard_height);
+ });
+
+ // the filler space taken up by the soft keyboard
+ strip.cell(|ui| {
+ // keyboard-visibility virtual keyboard
+ if virtual_keyboard && keyboard_height > 0.0 {
+ virtual_keyboard_ui(ui, ui.available_rect_before_wrap())
+ }
+ });
});
- });
+ }
// hovering virtual keyboard
if virtual_keyboard {
@@ -322,53 +341,6 @@ impl Chrome {
action
}
-
- fn topdown_sidebar(&mut self, ui: &mut egui::Ui, i18n: &mut Localization) {
- // macos needs a bit of space to make room for window
- // minimize/close buttons
- if cfg!(target_os = "macos") {
- ui.add_space(30.0);
- } else {
- // we still want *some* padding so that it aligns with the + button regardless
- ui.add_space(notedeck_ui::constants::FRAME_MARGIN.into());
- }
-
- if ui.add(expand_side_panel_button()).clicked() {
- self.nav.close();
- }
-
- ui.add_space(4.0);
- ui.add(milestone_name(i18n));
- //let dark_mode = ui.ctx().style().visuals.dark_mode;
-
- for (i, app) in self.apps.iter_mut().enumerate() {
- let r = match app {
- NotedeckApp::Columns(_columns_app) => columns_button(ui),
-
- NotedeckApp::Dave(dave) => {
- ui.add_space(24.0);
- let rect = dave_sidebar_rect(ui);
- dave_button(dave.avatar_mut(), ui, rect)
- }
-
- NotedeckApp::ClnDash(_clndash) => clndash_button(ui),
-
- NotedeckApp::Notebook(_notebook) => notebook_button(ui),
-
- NotedeckApp::Other(_other) => {
- // app provides its own button rendering ui?
- panic!("TODO: implement other apps")
- }
- };
-
- ui.add_space(4.0);
-
- if r.on_hover_cursor(egui::CursorIcon::PointingHand).clicked() {
- self.active = i as i32;
- self.nav.close();
- }
- }
- }
}
impl notedeck::App for Chrome {
@@ -383,86 +355,42 @@ impl notedeck::App for Chrome {
}
fn milestone_name<'a>(i18n: &'a mut Localization) -> impl Widget + 'a {
- |ui: &mut egui::Ui| -> egui::Response {
- ui.vertical_centered(|ui| {
- let font = egui::FontId::new(
- notedeck::fonts::get_font_size(ui.ctx(), &NotedeckTextStyle::Tiny),
- egui::FontFamily::Name(notedeck::fonts::NamedFontFamily::Bold.as_str().into()),
- );
- ui.add(
- Label::new(
- RichText::new(tr!(i18n, "BETA", "Beta version label"))
- .color(ui.style().visuals.noninteractive().fg_stroke.color)
- .font(font),
- )
- .selectable(false),
- )
- .on_hover_text(tr!(
- i18n,
- "Notedeck is a beta product. Expect bugs and contact us when you run into issues.",
- "Beta product warning message"
- ))
- .on_hover_cursor(egui::CursorIcon::Help)
- })
- .inner
- }
-}
+ let text = if notedeck::ui::is_compiled_as_mobile() {
+ tr!(
+ i18n,
+ "Damus Android BETA",
+ "Damus android beta version label"
+ )
+ } else {
+ tr!(
+ i18n,
+ "Damus Notedeck BETA",
+ "Damus notedeck beta version label"
+ )
+ };
-fn expand_side_panel_button() -> impl Widget {
|ui: &mut egui::Ui| -> egui::Response {
- let img_size = 40.0;
- let img = app_images::damus_image()
- .max_width(img_size)
- .sense(egui::Sense::click());
-
- ui.add(img)
+ let font = egui::FontId::new(
+ notedeck::fonts::get_font_size(ui.ctx(), &NotedeckTextStyle::Tiny),
+ egui::FontFamily::Name(notedeck::fonts::NamedFontFamily::Bold.as_str().into()),
+ );
+ ui.add(
+ Label::new(
+ RichText::new(text)
+ .color(ui.style().visuals.noninteractive().fg_stroke.color)
+ .font(font),
+ )
+ .selectable(false),
+ )
+ .on_hover_text(tr!(
+ i18n,
+ "Notedeck is a beta product. Expect bugs and contact us when you run into issues.",
+ "Beta product warning message"
+ ))
+ .on_hover_cursor(egui::CursorIcon::Help)
}
}
-fn support_button(ui: &mut egui::Ui) -> egui::Response {
- expanding_button(
- "help-button",
- 16.0,
- app_images::help_light_image(),
- app_images::help_dark_image(),
- ui,
- false,
- )
-}
-
-fn settings_button(ui: &mut egui::Ui) -> egui::Response {
- expanding_button(
- "settings-button",
- 32.0,
- app_images::settings_light_image(),
- app_images::settings_dark_image(),
- ui,
- false,
- )
-}
-
-fn columns_button(ui: &mut egui::Ui) -> egui::Response {
- expanding_button(
- "columns-button",
- 40.0,
- app_images::columns_image(),
- app_images::columns_image(),
- ui,
- false,
- )
-}
-
-fn accounts_button(ui: &mut egui::Ui) -> egui::Response {
- expanding_button(
- "accounts-button",
- 24.0,
- app_images::accounts_image().tint(ui.visuals().text_color()),
- app_images::accounts_image(),
- ui,
- false,
- )
-}
-
fn clndash_button(ui: &mut egui::Ui) -> egui::Response {
expanding_button(
"clndash-button",
@@ -485,14 +413,6 @@ fn notebook_button(ui: &mut egui::Ui) -> egui::Response {
)
}
-fn dave_sidebar_rect(ui: &mut egui::Ui) -> Rect {
- let size = vec2(60.0, 60.0);
- let available = ui.available_rect_before_wrap();
- let center_x = available.center().x;
- let center_y = available.top();
- egui::Rect::from_center_size(egui::pos2(center_x, center_y), size)
-}
-
fn dave_button(avatar: Option<&mut DaveAvatar>, ui: &mut egui::Ui, rect: Rect) -> egui::Response {
if let Some(avatar) = avatar {
avatar.render(rect, ui)
@@ -522,33 +442,6 @@ pub fn get_account_url<'a>(
}
}
-fn wallet_button() -> impl Widget {
- |ui: &mut egui::Ui| -> egui::Response {
- let img_size = 24.0;
-
- let max_size = img_size * ICON_EXPANSION_MULTIPLE;
-
- let img = if !ui.visuals().dark_mode {
- app_images::wallet_light_image()
- } else {
- app_images::wallet_dark_image()
- }
- .max_width(img_size);
-
- let helper = AnimationHelper::new(ui, "wallet-icon", vec2(max_size, max_size));
-
- let cur_img_size = helper.scale_1d_pos(img_size);
- img.paint_at(
- ui,
- helper
- .get_animation_rect()
- .shrink((max_size - cur_img_size) / 2.0),
- );
-
- helper.take_animation_response()
- }
-}
-
fn chrome_handle_app_action(
chrome: &mut Chrome,
ctx: &mut AppContext,
@@ -654,34 +547,60 @@ fn columns_route_to_profile(
}
}
-fn pfp_button(ctx: &mut AppContext, ui: &mut egui::Ui) -> egui::Response {
- let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget
- let helper = AnimationHelper::new(ui, "pfp-button", egui::vec2(max_size, max_size));
-
- let min_pfp_size = ICON_WIDTH;
- let cur_pfp_size = helper.scale_1d_pos(min_pfp_size);
-
- let txn = Transaction::new(ctx.ndb).expect("should be able to create txn");
- let profile_url = get_account_url(&txn, ctx.ndb, ctx.accounts.get_selected_account());
-
- let mut widget = ProfilePic::new(ctx.img_cache, profile_url).size(cur_pfp_size);
-
- ui.put(helper.get_animation_rect(), &mut widget);
-
- helper.take_animation_response()
-}
-
/// The section of the chrome sidebar that starts at the
/// bottom and goes up
-fn bottomup_sidebar(
+fn topdown_sidebar(
chrome: &mut Chrome,
ctx: &mut AppContext,
ui: &mut egui::Ui,
options: SidebarOptions,
) -> Option<ChromePanelAction> {
- ui.add_space(8.0);
+ let previous_spacing = ui.spacing().item_spacing;
+ ui.spacing_mut().item_spacing.y = 12.0;
- let pfp_resp = pfp_button(ctx, ui).on_hover_cursor(egui::CursorIcon::PointingHand);
+ let loc = &mut ctx.i18n;
+
+ // macos needs a bit of space to make room for window
+ // minimize/close buttons
+ if cfg!(target_os = "macos") {
+ ui.add_space(8.0);
+ }
+
+ let txn = Transaction::new(ctx.ndb).expect("should be able to create txn");
+ let profile = ctx
+ .ndb
+ .get_profile_by_pubkey(&txn, ctx.accounts.get_selected_account().key.pubkey.bytes());
+
+ let disp_name = get_display_name(profile.as_ref().ok());
+ let name = if let Some(username) = disp_name.username {
+ format!("@{username}")
+ } else {
+ disp_name.username_or_displayname().to_owned()
+ };
+
+ let selected_acc = ctx.accounts.get_selected_account();
+ let profile_url = get_account_url(&txn, ctx.ndb, selected_acc);
+ if let Ok(profile) = profile {
+ get_profile_url_owned(Some(profile))
+ } else {
+ get_profile_url_owned(None)
+ };
+
+ let pfp_resp = ui.add(&mut ProfilePic::new(ctx.img_cache, profile_url).size(64.0));
+
+ ui.horizontal_wrapped(|ui| {
+ ui.add(egui::Label::new(
+ RichText::new(name)
+ .color(ui.visuals().weak_text_color())
+ .size(16.0),
+ ));
+ });
+
+ if let Some(npub) = selected_acc.key.pubkey.npub() {
+ if ui.add(copy_npub(&npub, 200.0)).clicked() {
+ ui.ctx().copy_text(npub);
+ }
+ }
// we skip this whole function in compact mode
if options.contains(SidebarOptions::Compact) {
@@ -694,47 +613,214 @@ fn bottomup_sidebar(
};
}
- let accounts_resp = accounts_button(ui).on_hover_cursor(egui::CursorIcon::PointingHand);
- let settings_resp = settings_button(ui).on_hover_cursor(egui::CursorIcon::PointingHand);
-
- let theme_action = match ui.ctx().theme() {
- egui::Theme::Dark => {
- let resp = ui
- .add(Button::new("☀").frame(false))
- .on_hover_cursor(egui::CursorIcon::PointingHand)
- .on_hover_text(tr!(
- ctx.i18n,
- "Switch to light mode",
- "Hover text for light mode toggle button"
- ));
- if resp.clicked() {
- Some(ChromePanelAction::SaveTheme(ThemePreference::Light))
- } else {
- None
- }
+ let mut action = None;
+
+ let theme = ui.ctx().theme();
+
+ StripBuilder::new(ui)
+ .sizes(Size::exact(40.0), 6)
+ .clip(true)
+ .vertical(|mut strip| {
+ strip.strip(|b| {
+ if drawer_item(
+ b,
+ |ui| {
+ let profile_img = if ui.visuals().dark_mode {
+ app_images::profile_image()
+ } else {
+ app_images::profile_image().tint(ui.visuals().text_color())
+ }
+ .max_size(ui.available_size());
+ ui.add(profile_img);
+ },
+ tr!(loc, "Profile", "Button to go to the user's profile"),
+ )
+ .clicked()
+ {
+ action = Some(ChromePanelAction::Profile(
+ ctx.accounts.get_selected_account().key.pubkey,
+ ));
+ }
+ });
+
+ strip.strip(|b| {
+ if drawer_item(
+ b,
+ |ui| {
+ let account_img = if ui.visuals().dark_mode {
+ app_images::accounts_image()
+ } else {
+ app_images::accounts_image().tint(ui.visuals().text_color())
+ }
+ .max_size(ui.available_size());
+ ui.add(account_img);
+ },
+ tr!(loc, "Accounts", "Button to go to the accounts view"),
+ )
+ .clicked()
+ {
+ action = Some(ChromePanelAction::Account);
+ }
+ });
+
+ strip.strip(|b| {
+ if drawer_item(
+ b,
+ |ui| {
+ let img = if ui.visuals().dark_mode {
+ app_images::wallet_dark_image()
+ } else {
+ app_images::wallet_light_image()
+ };
+
+ ui.add(img);
+ },
+ tr!(loc, "Wallet", "Button to go to the wallet view"),
+ )
+ .clicked()
+ {
+ action = Some(ChromePanelAction::Wallet);
+ }
+ });
+
+ strip.strip(|b| {
+ if drawer_item(
+ b,
+ |ui| {
+ ui.add(if ui.visuals().dark_mode {
+ app_images::settings_dark_image()
+ } else {
+ app_images::settings_light_image()
+ });
+ },
+ tr!(loc, "Settings", "Button to go to the settings view"),
+ )
+ .clicked()
+ {
+ action = Some(ChromePanelAction::Settings);
+ }
+ });
+
+ strip.strip(|b| {
+ if drawer_item(
+ b,
+ |ui| {
+ let c = match theme {
+ egui::Theme::Dark => "🔆",
+ egui::Theme::Light => "🌒",
+ };
+
+ let painter = ui.painter();
+ let galley = painter.layout_no_wrap(
+ c.to_owned(),
+ NotedeckTextStyle::Heading3.get_font_id(ui.ctx()),
+ ui.visuals().text_color(),
+ );
+
+ painter.galley(
+ galley_centered_pos(&galley, ui.available_rect_before_wrap().center()),
+ galley,
+ ui.visuals().text_color(),
+ );
+ },
+ tr!(loc, "Theme", "Button to change the theme (light or dark)"),
+ )
+ .clicked()
+ {
+ match theme {
+ egui::Theme::Dark => {
+ action = Some(ChromePanelAction::SaveTheme(ThemePreference::Light));
+ }
+ egui::Theme::Light => {
+ action = Some(ChromePanelAction::SaveTheme(ThemePreference::Dark));
+ }
+ }
+ }
+ });
+
+ strip.strip(|b| {
+ if drawer_item(
+ b,
+ |ui| {
+ ui.add(if ui.visuals().dark_mode {
+ app_images::help_dark_image()
+ } else {
+ app_images::help_light_image()
+ });
+ },
+ tr!(loc, "Support", "Button to go to the support view"),
+ )
+ .clicked()
+ {
+ action = Some(ChromePanelAction::Support);
+ }
+ });
+ });
+
+ for (i, app) in chrome.apps.iter_mut().enumerate() {
+ if chrome.active == i as i32 {
+ continue;
}
- egui::Theme::Light => {
- let resp = ui
- .add(Button::new("🌙").frame(false))
- .on_hover_cursor(egui::CursorIcon::PointingHand)
- .on_hover_text(tr!(
- ctx.i18n,
- "Switch to dark mode",
- "Hover text for dark mode toggle button"
- ));
- if resp.clicked() {
- Some(ChromePanelAction::SaveTheme(ThemePreference::Dark))
- } else {
- None
+
+ let text = match &app {
+ NotedeckApp::Dave(_) => tr!(loc, "Dave", "Button to go to the Dave app"),
+ NotedeckApp::Columns(_) => tr!(loc, "Columns", "Button to go to the Columns app"),
+ NotedeckApp::Notebook(_) => {
+ tr!(loc, "Notebook", "Button to go to the Notebook app")
}
- }
- };
+ NotedeckApp::ClnDash(_) => tr!(loc, "ClnDash", "Button to go to the ClnDash app"),
+ NotedeckApp::Other(_) => tr!(loc, "Other", "Button to go to the Other app"),
+ };
- let support_resp = support_button(ui).on_hover_cursor(egui::CursorIcon::PointingHand);
+ StripBuilder::new(ui)
+ .size(Size::exact(40.0))
+ .clip(true)
+ .vertical(|mut strip| {
+ strip.strip(|b| {
+ let resp = drawer_item(
+ b,
+ |ui| {
+ match app {
+ NotedeckApp::Columns(_columns_app) => {
+ ui.add(app_images::columns_image());
+ }
+
+ NotedeckApp::Dave(dave) => {
+ dave_button(
+ dave.avatar_mut(),
+ ui,
+ Rect::from_center_size(
+ ui.available_rect_before_wrap().center(),
+ vec2(30.0, 30.0),
+ ),
+ );
+ }
+
+ NotedeckApp::ClnDash(_clndash) => {
+ clndash_button(ui);
+ }
+
+ NotedeckApp::Notebook(_notebook) => {
+ notebook_button(ui);
+ }
+
+ NotedeckApp::Other(_other) => {
+ // app provides its own button rendering ui?
+ panic!("TODO: implement other apps")
+ }
+ }
+ },
+ text,
+ )
+ .on_hover_cursor(egui::CursorIcon::PointingHand);
- let wallet_resp = ui
- .add(wallet_button())
- .on_hover_cursor(egui::CursorIcon::PointingHand);
+ if resp.clicked() {
+ chrome.active = i as i32;
+ chrome.nav.close();
+ }
+ })
+ });
+ }
if ctx.args.options.contains(NotedeckOptions::Debug) {
let r = ui
@@ -784,21 +870,74 @@ fn bottomup_sidebar(
}
}
- if pfp_resp.clicked() {
- let pk = ctx.accounts.get_selected_account().key.pubkey;
- Some(ChromePanelAction::Profile(pk))
- } else if accounts_resp.clicked() {
- Some(ChromePanelAction::Account)
- } else if settings_resp.clicked() {
- Some(ChromePanelAction::Settings)
- } else if theme_action.is_some() {
- theme_action
- } else if support_resp.clicked() {
- Some(ChromePanelAction::Support)
- } else if wallet_resp.clicked() {
- Some(ChromePanelAction::Wallet)
- } else {
- None
+ ui.spacing_mut().item_spacing = previous_spacing;
+
+ action
+}
+
+fn drawer_item(builder: StripBuilder, icon: impl FnOnce(&mut Ui), text: String) -> egui::Response {
+ builder
+ .cell_layout(Layout::left_to_right(egui::Align::Center))
+ .sense(Sense::click())
+ .size(Size::exact(24.0))
+ .size(Size::exact(8.0)) // free space
+ .size(Size::remainder())
+ .horizontal(|mut strip| {
+ strip.cell(icon);
+
+ strip.empty();
+
+ strip.cell(|ui| {
+ ui.add(drawer_label(ui.ctx(), &text));
+ });
+ })
+ .on_hover_cursor(egui::CursorIcon::PointingHand)
+}
+
+fn drawer_label(ctx: &egui::Context, text: &str) -> egui::Label {
+ egui::Label::new(RichText::new(text).size(get_font_size(ctx, &NotedeckTextStyle::Heading2)))
+ .selectable(false)
+}
+
+fn copy_npub<'a>(npub: &'a String, width: f32) -> impl Widget + use<'a> {
+ move |ui: &mut egui::Ui| -> egui::Response {
+ let size = vec2(width, 24.0);
+ let (rect, mut resp) = ui.allocate_exact_size(size, egui::Sense::click());
+ resp = resp.on_hover_cursor(egui::CursorIcon::Copy);
+
+ let painter = ui.painter_at(rect);
+
+ painter.rect_filled(
+ rect,
+ CornerRadius::same(32),
+ if resp.hovered() {
+ ui.visuals().widgets.active.bg_fill
+ } else {
+ // ui.visuals().panel_fill
+ ui.visuals().widgets.inactive.bg_fill
+ },
+ );
+
+ let text =
+ Label::new(RichText::new(npub).size(get_font_size(ui.ctx(), &NotedeckTextStyle::Tiny)))
+ .truncate()
+ .selectable(false);
+
+ let (label_rect, copy_rect) = {
+ let rect = rect.shrink(4.0);
+ let (l, r) = rect.split_left_right_at_x(rect.right() - 24.0);
+ (l, r.shrink2(vec2(4.0, 0.0)))
+ };
+
+ app_images::copy_to_clipboard_image()
+ .tint(ui.visuals().text_color())
+ .maintain_aspect_ratio(true)
+ // .max_size(vec2(24.0, 24.0))
+ .paint_at(ui, copy_rect);
+
+ ui.put(label_rect, text);
+
+ resp
}
}
diff --git a/crates/notedeck_columns/src/ui/add_column.rs b/crates/notedeck_columns/src/ui/add_column.rs
@@ -522,7 +522,7 @@ impl<'a> AddColumnView<'a> {
"Stay up to date with someone's notes & replies",
"Description for individual user column"
),
- icon: app_images::profile_image(),
+ icon: app_images::add_column_individual_image(),
option: AddColumnOption::UndecidedIndividual,
});
vec.push(ColumnOptionData {
@@ -597,7 +597,7 @@ impl<'a> AddColumnView<'a> {
"Keep track of your notes & replies",
"Description for your notes column"
),
- icon: app_images::profile_image(),
+ icon: app_images::add_column_individual_image(),
option: AddColumnOption::Individual(source),
});
@@ -612,7 +612,7 @@ impl<'a> AddColumnView<'a> {
"Stay up to date with someone else's notes & replies",
"Description for someone else's notes column"
),
- icon: app_images::profile_image(),
+ icon: app_images::add_column_individual_image(),
option: AddColumnOption::ExternalIndividual,
});
diff --git a/crates/notedeck_columns/src/ui/repost.rs b/crates/notedeck_columns/src/ui/repost.rs
@@ -1,13 +1,12 @@
use std::f32::consts::PI;
use egui::{
- epaint::PathShape, pos2, vec2, CornerRadius, Layout, Margin, Pos2, RichText, Sense, Shape,
- Stroke,
+ epaint::PathShape, pos2, vec2, CornerRadius, Layout, Margin, RichText, Sense, Shape, Stroke,
};
use egui_extras::StripBuilder;
use enostr::NoteId;
use notedeck::{fonts::get_font_size, NotedeckTextStyle};
-use notedeck_ui::app_images;
+use notedeck_ui::{app_images, galley_centered_pos};
use crate::repost::RepostAction;
@@ -91,7 +90,7 @@ impl<'a> RepostDecisionView<'a> {
);
painter.galley(
- galley_top_left_from_center(&galley, resp.rect.center()),
+ galley_centered_pos(&galley, resp.rect.center()),
galley,
ui.visuals().text_color(),
);
@@ -107,14 +106,6 @@ impl<'a> RepostDecisionView<'a> {
}
}
-fn galley_top_left_from_center(galley: &std::sync::Arc<egui::Galley>, center: Pos2) -> Pos2 {
- let mut top_left = center;
- top_left.x -= galley.rect.width() / 2.0;
- top_left.y -= galley.rect.height() / 2.0;
-
- top_left
-}
-
fn repost_item_text(text: &str) -> impl egui::Widget + use<'_> {
move |ui: &mut egui::Ui| -> egui::Response {
ui.add(egui::Label::new(
diff --git a/crates/notedeck_ui/src/app_images.rs b/crates/notedeck_ui/src/app_images.rs
@@ -11,8 +11,12 @@ pub fn add_account_image() -> Image<'static> {
))
}
+pub fn profile_image() -> Image<'static> {
+ Image::new(include_image!("../../../assets/icons/profile.png"))
+}
+
pub fn accounts_image() -> Image<'static> {
- Image::new(include_image!("../../../assets/icons/accounts.png"))
+ Image::new(include_image!("../../../assets/icons/accounts_4x.png"))
}
pub fn cln_image() -> Image<'static> {
@@ -199,7 +203,7 @@ pub fn reply_light_image() -> Image<'static> {
Image::new(include_image!("../../../assets/icons/reply-dark.png"))
}
-pub fn profile_image() -> Image<'static> {
+pub fn add_column_individual_image() -> Image<'static> {
Image::new(include_image!("../../../assets/icons/profile_icon_4x.png"))
}
diff --git a/crates/notedeck_ui/src/lib.rs b/crates/notedeck_ui/src/lib.rs
@@ -20,7 +20,7 @@ pub use note::{NoteContents, NoteOptions, NoteView};
pub use profile::{ProfilePic, ProfilePreview};
pub use username::Username;
-use egui::{Label, Margin, RichText};
+use egui::{Label, Margin, Pos2, RichText};
/// This is kind of like the Widget trait but is meant for larger top-level
/// views that are typically stateful.
@@ -93,3 +93,13 @@ pub fn input_rect(ui: &mut egui::Ui) -> Option<egui::Rect> {
pub fn clear_input_rect(ui: &mut egui::Ui) {
ui.data_mut(|d| d.remove::<egui::Rect>(egui::Id::new(INPUT_RECT_KEY)))
}
+
+/// Center the galley on the center pos, returning the position of the top left position of the galley,
+/// for the `painter.galley(..)`
+pub fn galley_centered_pos(galley: &std::sync::Arc<egui::Galley>, center: Pos2) -> Pos2 {
+ let mut top_left = center;
+ top_left.x -= galley.rect.width() / 2.0;
+ top_left.y -= galley.rect.height() / 2.0;
+
+ top_left
+}