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
This commit is contained in:
William Casarin
2025-10-20 11:07:04 -07:00
9 changed files with 451 additions and 306 deletions

29
Cargo.lock generated
View File

@@ -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"

View File

@@ -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" }

Binary file not shown.

After

Width:  |  Height:  |  Size: 984 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -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()
};
RouteResponse {
response,
can_take_drag_from: Vec::new(),
}
})
.inner
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
}
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 {
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"
)
};
|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),
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),
)
.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
.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 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)
}
}
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 mut action = None;
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 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());
}
let wallet_resp = ui
.add(wallet_button())
.on_hover_cursor(egui::CursorIcon::PointingHand);
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);
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
}
}

View File

@@ -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,
});

View File

@@ -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(

View File

@@ -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"))
}

View File

@@ -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
}