notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 400050f3fba63f7a673720ff9e55cc50fa1257b7
parent 5010d3662dec4fcbf16d84387dead6ce8f752faa
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 25 Jun 2025 10:29:49 -0700

Merge remote-tracking branches 'github/pr/877' and 'github/pr/885'

Fernando López Guevara (2):
      fix(content): handle case where notes are not loaded
      feat(app_images): add module to manage static app image assets

Diffstat:
MCargo.lock | 1+
Mcrates/notedeck/src/note/mod.rs | 2++
Mcrates/notedeck/src/unknowns.rs | 14++++++++++----
Mcrates/notedeck_chrome/src/chrome.rs | 40+++++++++++++++++++++-------------------
Mcrates/notedeck_chrome/src/setup.rs | 16+++++-----------
Mcrates/notedeck_columns/src/nav.rs | 3+--
Mcrates/notedeck_columns/src/timeline/route.rs | 8+-------
Mcrates/notedeck_columns/src/ui/account_login_view.rs | 21++++++++++++---------
Mcrates/notedeck_columns/src/ui/accounts.rs | 7+++----
Mcrates/notedeck_columns/src/ui/add_column.rs | 36+++++++++++++++++-------------------
Mcrates/notedeck_columns/src/ui/column/header.rs | 22+++++++++-------------
Mcrates/notedeck_columns/src/ui/note/custom_zap.rs | 5++---
Mcrates/notedeck_columns/src/ui/note/post.rs | 16+++++++++++-----
Mcrates/notedeck_columns/src/ui/profile/mod.rs | 40+++++++++++++++++++++-------------------
Mcrates/notedeck_columns/src/ui/relay.rs | 41+++++++++++++----------------------------
Mcrates/notedeck_columns/src/ui/side_panel.rs | 17+++++++----------
Mcrates/notedeck_columns/src/ui/thread.rs | 7++-----
Mcrates/notedeck_dave/src/ui/dave.rs | 6+++---
Mcrates/notedeck_ui/Cargo.toml | 1+
Acrates/notedeck_ui/src/app_images.rs | 207+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/notedeck_ui/src/lib.rs | 1+
Mcrates/notedeck_ui/src/note/contents.rs | 4++++
Mcrates/notedeck_ui/src/note/media.rs | 13++++++++-----
Mcrates/notedeck_ui/src/note/mod.rs | 30++++++++++++++++--------------
Mcrates/notedeck_ui/src/profile/mod.rs | 7++++---
25 files changed, 382 insertions(+), 183 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -3368,6 +3368,7 @@ version = "0.4.0" dependencies = [ "bitflags 2.9.1", "blurhash", + "eframe", "egui", "egui-winit", "egui_extras", diff --git a/crates/notedeck/src/note/mod.rs b/crates/notedeck/src/note/mod.rs @@ -5,6 +5,7 @@ pub use action::{MediaAction, NoteAction, ZapAction, ZapTargetAmount}; pub use context::{BroadcastContext, ContextSelection, NoteContextSelection}; use crate::JobPool; +use crate::UnknownIds; use crate::{notecache::NoteCache, zaps::Zaps, Images}; use enostr::{NoteId, RelayPool}; use nostrdb::{Ndb, Note, NoteKey, QueryResult, Transaction}; @@ -21,6 +22,7 @@ pub struct NoteContext<'d> { pub zaps: &'d mut Zaps, pub pool: &'d mut RelayPool, pub job_pool: &'d mut JobPool, + pub unknown_ids: &'d mut UnknownIds, pub current_account_has_wallet: bool, } diff --git a/crates/notedeck/src/unknowns.rs b/crates/notedeck/src/unknowns.rs @@ -201,7 +201,11 @@ impl UnknownIds { return; } - self.ids.entry(UnknownId::Pubkey(*pubkey)).or_default(); + let unknown_id = UnknownId::Pubkey(*pubkey); + if self.ids.contains_key(&unknown_id) { + return; + } + self.ids.entry(unknown_id).or_default(); self.mark_updated(); } @@ -211,9 +215,11 @@ impl UnknownIds { return; } - self.ids - .entry(UnknownId::Id(NoteId::new(*note_id))) - .or_default(); + let unknown_id = UnknownId::Id(NoteId::new(*note_id)); + if self.ids.contains_key(&unknown_id) { + return; + } + self.ids.entry(unknown_id).or_default(); self.mark_updated(); } } diff --git a/crates/notedeck_chrome/src/chrome.rs b/crates/notedeck_chrome/src/chrome.rs @@ -12,7 +12,7 @@ use notedeck::{ use notedeck_columns::{timeline::kind::ListKind, timeline::TimelineKind, Damus}; use notedeck_dave::{Dave, DaveAvatar}; -use notedeck_ui::{AnimationHelper, ProfilePic}; +use notedeck_ui::{app_images, AnimationHelper, ProfilePic}; static ICON_WIDTH: f32 = 40.0; pub static ICON_EXPANSION_MULTIPLE: f32 = 1.2; @@ -438,8 +438,7 @@ fn milestone_name() -> impl Widget { fn expand_side_panel_button() -> impl Widget { |ui: &mut egui::Ui| -> egui::Response { let img_size = 40.0; - let img_data = egui::include_image!("../../../assets/damus_rounded_80.png"); - let img = egui::Image::new(img_data) + let img = app_images::damus_image() .max_width(img_size) .sense(egui::Sense::click()); @@ -450,17 +449,16 @@ fn expand_side_panel_button() -> impl Widget { fn expanding_button( name: &'static str, img_size: f32, - light_img: &egui::ImageSource, - dark_img: &egui::ImageSource, + light_img: egui::Image, + dark_img: egui::Image, ui: &mut egui::Ui, ) -> egui::Response { let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget - let img_data = if ui.visuals().dark_mode { + let img = if ui.visuals().dark_mode { dark_img } else { light_img }; - let img = egui::Image::new(img_data.clone()).max_width(img_size); let helper = AnimationHelper::new(ui, name, egui::vec2(max_size, max_size)); @@ -479,8 +477,8 @@ fn support_button(ui: &mut egui::Ui) -> egui::Response { expanding_button( "help-button", 16.0, - &egui::include_image!("../../../assets/icons/help_icon_inverted_4x.png"), - &egui::include_image!("../../../assets/icons/help_icon_dark_4x.png"), + app_images::help_light_image(), + app_images::help_dark_image(), ui, ) } @@ -489,8 +487,8 @@ fn settings_button(ui: &mut egui::Ui) -> egui::Response { expanding_button( "settings-button", 32.0, - &egui::include_image!("../../../assets/icons/settings_light_4x.png"), - &egui::include_image!("../../../assets/icons/settings_dark_4x.png"), + app_images::settings_light_image(), + app_images::settings_dark_image(), ui, ) } @@ -499,8 +497,8 @@ fn notifications_button(ui: &mut egui::Ui) -> egui::Response { expanding_button( "notifications-button", 24.0, - &egui::include_image!("../../../assets/icons/notifications_dark_4x.png"), - &egui::include_image!("../../../assets/icons/notifications_dark_4x.png"), + app_images::notifications_button_image(), + app_images::notifications_button_image(), ui, ) } @@ -509,15 +507,20 @@ fn home_button(ui: &mut egui::Ui) -> egui::Response { expanding_button( "home-button", 24.0, - &egui::include_image!("../../../assets/icons/home-toolbar.png"), - &egui::include_image!("../../../assets/icons/home-toolbar.png"), + app_images::home_button_image(), + app_images::home_button_image(), ui, ) } fn columns_button(ui: &mut egui::Ui) -> egui::Response { - let btn = egui::include_image!("../../../assets/icons/columns_80.png"); - expanding_button("columns-button", 40.0, &btn, &btn, ui) + expanding_button( + "columns-button", + 40.0, + app_images::columns_image(), + app_images::columns_image(), + ui, + ) } fn dave_sidebar_rect(ui: &mut egui::Ui) -> Rect { @@ -574,9 +577,8 @@ fn wallet_button() -> impl Widget { let img_size = 24.0; let max_size = img_size * ICON_EXPANSION_MULTIPLE; - let img_data = egui::include_image!("../../../assets/icons/wallet-icon.svg"); - let mut img = egui::Image::new(img_data).max_width(img_size); + let mut img = app_images::wallet_image().max_width(img_size); if !ui.visuals().dark_mode { img = img.tint(egui::Color32::BLACK); diff --git a/crates/notedeck_chrome/src/setup.rs b/crates/notedeck_chrome/src/setup.rs @@ -3,6 +3,7 @@ use crate::{fonts, theme}; use eframe::NativeOptions; use egui::ThemePreference; use notedeck::{AppSizeHandler, DataPath}; +use notedeck_ui::app_images; use tracing::info; pub fn setup_chrome(ctx: &egui::Context, args: &notedeck::Args, theme: ThemePreference) { @@ -53,9 +54,7 @@ pub fn generate_native_options(paths: DataPath) -> NativeOptions { .with_fullsize_content_view(true) .with_titlebar_shown(false) .with_title_shown(false) - .with_icon(std::sync::Arc::new( - eframe::icon_data::from_png_bytes(app_icon()).expect("icon"), - )); + .with_icon(std::sync::Arc::new(app_images::app_icon())); if let Some(window_size) = AppSizeHandler::new(&paths).get_app_size() { builder.with_inner_size(window_size) @@ -68,9 +67,8 @@ pub fn generate_native_options(paths: DataPath) -> NativeOptions { // for 3d widgets depth_buffer: 24, window_builder: Some(window_builder), - viewport: egui::ViewportBuilder::default().with_icon(std::sync::Arc::new( - eframe::icon_data::from_png_bytes(app_icon()).expect("icon"), - )), + viewport: egui::ViewportBuilder::default() + .with_icon(std::sync::Arc::new(app_images::app_icon())), ..Default::default() } } @@ -89,10 +87,6 @@ fn generate_native_options_with_builder_modifiers( } } -pub fn app_icon() -> &'static [u8; 271986] { - std::include_bytes!("../../../assets/damus-app-icon.png") -} - pub fn generate_mobile_emulator_native_options() -> eframe::NativeOptions { generate_native_options_with_builder_modifiers(|builder| { builder @@ -100,6 +94,6 @@ pub fn generate_mobile_emulator_native_options() -> eframe::NativeOptions { .with_titlebar_shown(false) .with_title_shown(false) .with_inner_size([405.0, 915.0]) - .with_icon(eframe::icon_data::from_png_bytes(app_icon()).expect("icon")) + .with_icon(app_images::app_icon()) }) } diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -420,11 +420,11 @@ fn render_nav_body( zaps: ctx.zaps, pool: ctx.pool, job_pool: ctx.job_pool, + unknown_ids: ctx.unknown_ids, current_account_has_wallet: get_current_wallet(ctx.accounts, ctx.global_wallet).is_some(), }; match top { Route::Timeline(kind) => render_timeline_route( - ctx.unknown_ids, &mut app.timeline_cache, ctx.accounts, kind, @@ -436,7 +436,6 @@ fn render_nav_body( &mut app.jobs, ), Route::Thread(selection) => render_thread_route( - ctx.unknown_ids, &mut app.threads, ctx.accounts, selection, diff --git a/crates/notedeck_columns/src/timeline/route.rs b/crates/notedeck_columns/src/timeline/route.rs @@ -6,12 +6,11 @@ use crate::{ }; use enostr::Pubkey; -use notedeck::{Accounts, MuteFun, NoteContext, UnknownIds}; +use notedeck::{Accounts, MuteFun, NoteContext}; use notedeck_ui::{jobs::JobsCache, NoteOptions}; #[allow(clippy::too_many_arguments)] pub fn render_timeline_route( - unknown_ids: &mut UnknownIds, timeline_cache: &mut TimelineCache, accounts: &mut Accounts, kind: &TimelineKind, @@ -50,7 +49,6 @@ pub fn render_timeline_route( pubkey, accounts, timeline_cache, - unknown_ids, col, ui, &accounts.mutefun(), @@ -79,7 +77,6 @@ pub fn render_timeline_route( #[allow(clippy::too_many_arguments)] pub fn render_thread_route( - unknown_ids: &mut UnknownIds, threads: &mut Threads, accounts: &mut Accounts, selection: &ThreadSelection, @@ -95,7 +92,6 @@ pub fn render_thread_route( ui::ThreadView::new( threads, - unknown_ids, selection.selected_or_root(), note_options, &accounts.mutefun(), @@ -113,7 +109,6 @@ pub fn render_profile_route( pubkey: &Pubkey, accounts: &Accounts, timeline_cache: &mut TimelineCache, - unknown_ids: &mut UnknownIds, col: usize, ui: &mut egui::Ui, is_muted: &MuteFun, @@ -127,7 +122,6 @@ pub fn render_profile_route( col, timeline_cache, note_options, - unknown_ids, is_muted, note_context, jobs, diff --git a/crates/notedeck_columns/src/ui/account_login_view.rs b/crates/notedeck_columns/src/ui/account_login_view.rs @@ -1,13 +1,16 @@ use crate::login_manager::AcquireKeyState; use crate::ui::{Preview, PreviewConfig}; use egui::{ - Align, Button, Color32, Frame, Image, InnerResponse, Margin, RichText, TextBuffer, Vec2, + Align, Button, Color32, Frame, InnerResponse, Layout, Margin, RichText, TextBuffer, TextEdit, + Vec2, }; -use egui::{Layout, TextEdit}; use egui_winit::clipboard::Clipboard; use enostr::Keypair; use notedeck::{fonts::get_font_size, AppAction, NotedeckTextStyle}; -use notedeck_ui::context_menu::{input_context, PasteBehavior}; +use notedeck_ui::{ + app_images, + context_menu::{input_context, PasteBehavior}, +}; pub struct AccountLoginView<'a> { manager: &'a mut AcquireKeyState, @@ -138,15 +141,15 @@ fn login_textedit(manager: &mut AcquireKeyState) -> TextEdit { fn eye_button(ui: &mut egui::Ui, is_visible: bool) -> egui::Response { let is_dark_mode = ui.visuals().dark_mode; - let icon = Image::new(if is_visible && is_dark_mode { - egui::include_image!("../../../../assets/icons/eye-dark.png") + let icon = if is_visible && is_dark_mode { + app_images::eye_dark_image() } else if is_visible { - egui::include_image!("../../../../assets/icons/eye-light.png") + app_images::eye_light_image() } else if is_dark_mode { - egui::include_image!("../../../../assets/icons/eye-slash-dark.png") + app_images::eye_slash_dark_image() } else { - egui::include_image!("../../../../assets/icons/eye-slash-light.png") - }); + app_images::eye_slash_light_image() + }; ui.add(Button::image(icon).frame(false)) } diff --git a/crates/notedeck_columns/src/ui/accounts.rs b/crates/notedeck_columns/src/ui/accounts.rs @@ -1,10 +1,11 @@ use egui::{ - Align, Button, Frame, Image, InnerResponse, Layout, RichText, ScrollArea, Ui, UiBuilder, Vec2, + Align, Button, Frame, InnerResponse, Layout, RichText, ScrollArea, Ui, UiBuilder, Vec2, }; use nostrdb::{Ndb, Transaction}; use notedeck::{Accounts, Images}; use notedeck_ui::colors::PINK; +use notedeck_ui::app_images; use notedeck_ui::profile::preview::SimpleProfilePreview; pub struct AccountsView<'a> { @@ -175,10 +176,8 @@ fn scroll_area() -> ScrollArea { } fn add_account_button() -> Button<'static> { - let img_data = egui::include_image!("../../../../assets/icons/add_account_icon_4x.png"); - let img = Image::new(img_data).fit_to_exact_size(Vec2::new(48.0, 48.0)); Button::image_and_text( - img, + app_images::add_account_image().fit_to_exact_size(Vec2::new(48.0, 48.0)), RichText::new(" Add account") .size(16.0) // TODO: this color should not be hard coded. Find some way to add it to the visuals diff --git a/crates/notedeck_columns/src/ui/add_column.rs b/crates/notedeck_columns/src/ui/add_column.rs @@ -2,8 +2,8 @@ use core::f32; use std::collections::HashMap; use egui::{ - pos2, vec2, Align, Color32, FontId, Id, ImageSource, Margin, Pos2, Rect, RichText, Separator, - Ui, Vec2, Widget, + pos2, vec2, Align, Color32, FontId, Id, Image, Margin, Pos2, Rect, RichText, Separator, Ui, + Vec2, Widget, }; use enostr::Pubkey; use nostrdb::{Ndb, Transaction}; @@ -17,7 +17,7 @@ use crate::{ }; use notedeck::{AppContext, Images, NotedeckTextStyle, UserAccount}; -use notedeck_ui::anim::ICON_EXPANSION_MULTIPLE; +use notedeck_ui::{anim::ICON_EXPANSION_MULTIPLE, app_images}; use tokenator::{ParseError, TokenParser, TokenSerializable, TokenWriter}; use crate::ui::widgets::styled_button; @@ -226,7 +226,7 @@ impl<'a> AddColumnView<'a> { let algo_option = ColumnOptionData { title: "Contact List", description: "Source the last note for each user in your contact list", - icon: egui::include_image!("../../../../assets/icons/home_icon_dark_4x.png"), + icon: app_images::home_image(), option: AddColumnOption::Algo(AlgoOption::LastPerPubkey(Decision::Decided( ListKind::contact_list(deck_author), ))), @@ -244,7 +244,7 @@ impl<'a> AddColumnView<'a> { let algo_option = ColumnOptionData { title: "Last Note per User", description: "Show the last note for each user from a list", - icon: egui::include_image!("../../../../assets/icons/algo.png"), + icon: app_images::algo_image(), option: AddColumnOption::Algo(AlgoOption::LastPerPubkey(Decision::Undecided)), }; @@ -434,7 +434,7 @@ impl<'a> AddColumnView<'a> { ); let icon_cur_y = animation_rect.top() + cur_height_padding + (total_content_height / 2.0); - let icon_img = egui::Image::new(data.icon).fit_to_exact_size(cur_icon_size); + let icon_img = data.icon.fit_to_exact_size(cur_icon_size); let icon_rect = Rect::from_center_size(pos2(cur_icon_x_pos, icon_cur_y), cur_icon_size); icon_img.paint_at(ui, icon_rect); @@ -449,7 +449,7 @@ impl<'a> AddColumnView<'a> { vec.push(ColumnOptionData { title: "Universe", description: "See the whole nostr universe", - icon: egui::include_image!("../../../../assets/icons/universe_icon_dark_4x.png"), + icon: app_images::universe_image(), option: AddColumnOption::Universe, }); @@ -463,32 +463,32 @@ impl<'a> AddColumnView<'a> { vec.push(ColumnOptionData { title: "Contacts", description: "See notes from your contacts", - icon: egui::include_image!("../../../../assets/icons/home_icon_dark_4x.png"), + icon: app_images::home_image(), option: AddColumnOption::Contacts(source), }); } vec.push(ColumnOptionData { title: "Notifications", description: "Stay up to date with notifications and mentions", - icon: egui::include_image!("../../../../assets/icons/notifications_icon_dark_4x.png"), + icon: app_images::notifications_image(), option: AddColumnOption::UndecidedNotification, }); vec.push(ColumnOptionData { title: "Hashtags", description: "Stay up to date with a certain hashtag", - icon: egui::include_image!("../../../../assets/icons/hashtag_icon_4x.png"), + icon: app_images::hashtag_image(), option: AddColumnOption::UndecidedHashtag, }); vec.push(ColumnOptionData { title: "Individual", description: "Stay up to date with someone's notes & replies", - icon: egui::include_image!("../../../../assets/icons/profile_icon_4x.png"), + icon: app_images::profile_image(), option: AddColumnOption::UndecidedIndividual, }); vec.push(ColumnOptionData { title: "Algo", description: "Algorithmic feeds to aid in note discovery", - icon: egui::include_image!("../../../../assets/icons/algo.png"), + icon: app_images::algo_image(), option: AddColumnOption::Algo(AlgoOption::LastPerPubkey(Decision::Undecided)), }); @@ -508,9 +508,7 @@ impl<'a> AddColumnView<'a> { vec.push(ColumnOptionData { title: "Your Notifications", description: "Stay up to date with your notifications and mentions", - icon: egui::include_image!( - "../../../../assets/icons/notifications_icon_dark_4x.png" - ), + icon: app_images::notifications_image(), option: AddColumnOption::Notification(source), }); } @@ -518,7 +516,7 @@ impl<'a> AddColumnView<'a> { vec.push(ColumnOptionData { title: "Someone else's Notifications", description: "Stay up to date with someone else's notifications and mentions", - icon: egui::include_image!("../../../../assets/icons/notifications_icon_dark_4x.png"), + icon: app_images::notifications_image(), option: AddColumnOption::ExternalNotification, }); @@ -538,7 +536,7 @@ impl<'a> AddColumnView<'a> { vec.push(ColumnOptionData { title: "Your Notes", description: "Keep track of your notes & replies", - icon: egui::include_image!("../../../../assets/icons/profile_icon_4x.png"), + icon: app_images::profile_image(), option: AddColumnOption::Individual(source), }); } @@ -546,7 +544,7 @@ impl<'a> AddColumnView<'a> { vec.push(ColumnOptionData { title: "Someone else's Notes", description: "Stay up to date with someone else's notes & replies", - icon: egui::include_image!("../../../../assets/icons/profile_icon_4x.png"), + icon: app_images::profile_image(), option: AddColumnOption::ExternalIndividual, }); @@ -586,7 +584,7 @@ pub(crate) fn sized_button(text: &str) -> impl Widget + '_ { struct ColumnOptionData { title: &'static str, description: &'static str, - icon: ImageSource<'static>, + icon: Image<'static>, option: AddColumnOption, } diff --git a/crates/notedeck_columns/src/ui/column/header.rs b/crates/notedeck_columns/src/ui/column/header.rs @@ -13,6 +13,7 @@ use egui::{Margin, Response, RichText, Sense, Stroke, UiBuilder}; use enostr::Pubkey; use nostrdb::{Ndb, Transaction}; use notedeck::{Images, NotedeckTextStyle}; +use notedeck_ui::app_images; use notedeck_ui::{ anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE}, ProfilePic, @@ -152,12 +153,12 @@ impl<'a> NavTitle<'a> { let img_size = 16.0; let max_size = icon_width * ICON_EXPANSION_MULTIPLE; - let img_data = if ui.visuals().dark_mode { - egui::include_image!("../../../../../assets/icons/column_delete_icon_4x.png") + let img = (if ui.visuals().dark_mode { + app_images::delete_dark_image() } else { - egui::include_image!("../../../../../assets/icons/column_delete_icon_light_4x.png") - }; - let img = egui::Image::new(img_data).max_width(img_size); + app_images::delete_light_image() + }) + .max_width(img_size); let helper = AnimationHelper::new(ui, "delete-column-button", egui::vec2(max_size, max_size)); @@ -427,14 +428,9 @@ impl<'a> NavTitle<'a> { fn title_pfp(&mut self, ui: &mut egui::Ui, top: &Route, pfp_size: f32) -> Option<Response> { match top { Route::Timeline(kind) => match kind { - TimelineKind::Hashtag(_ht) => Some( - ui.add( - egui::Image::new(egui::include_image!( - "../../../../../assets/icons/hashtag_icon_4x.png" - )) - .fit_to_exact_size(egui::vec2(pfp_size, pfp_size)), - ), - ), + TimelineKind::Hashtag(_ht) => Some(ui.add( + app_images::hashtag_image().fit_to_exact_size(egui::vec2(pfp_size, pfp_size)), + )), TimelineKind::Profile(pubkey) => Some(self.show_profile(ui, pubkey, pfp_size)), diff --git a/crates/notedeck_columns/src/ui/note/custom_zap.rs b/crates/notedeck_columns/src/ui/note/custom_zap.rs @@ -9,7 +9,7 @@ use nostrdb::{Ndb, ProfileRecord, Transaction}; use notedeck::{ fonts::get_font_size, get_profile_url, name::get_display_name, Images, NotedeckTextStyle, }; -use notedeck_ui::{colors, profile::display_name_widget, AnimationHelper, ProfilePic}; +use notedeck_ui::{app_images, colors, profile::display_name_widget, AnimationHelper, ProfilePic}; use crate::ui::widgets::styled_button_toggleable; @@ -143,10 +143,9 @@ fn show_title(ui: &mut egui::Ui) { ); painter.circle_filled(rect.center(), max_size / 2.0, circle_color); - let img_data = egui::include_image!("../../../../../assets/icons/filled_zap_icon.svg"); let zap_max_width = 25.16; let zap_max_height = 29.34; - let img = egui::Image::new(img_data) + let img = app_images::filled_zap_image() .max_width(zap_max_width) .max_height(zap_max_height); diff --git a/crates/notedeck_columns/src/ui/note/post.rs b/crates/notedeck_columns/src/ui/note/post.rs @@ -14,6 +14,7 @@ use egui::{ }; use enostr::{FilledKeypair, FullKeypair, KeypairUnowned, NoteId, Pubkey, RelayPool}; use nostrdb::{Ndb, Transaction}; +use notedeck_ui::app_images; use notedeck_ui::blur::PixelDimensions; use notedeck_ui::images::{get_render_state, RenderState}; use notedeck_ui::jobs::JobsCache; @@ -640,11 +641,15 @@ fn media_upload_button() -> impl egui::Widget { painter.rect_filled(resp.rect, 8.0, fill_color); painter.rect_stroke(resp.rect, 8.0, stroke, egui::StrokeKind::Middle); - egui::Image::new(egui::include_image!( - "../../../../../assets/icons/media_upload_dark_4x.png" - )) - .max_size(egui::vec2(16.0, 16.0)) - .paint_at(ui, resp.rect.shrink(8.0)); + let mut upload_img = app_images::media_upload_dark_image(); + + if !ui.visuals().dark_mode { + upload_img = upload_img.tint(egui::Color32::BLACK); + }; + + upload_img + .max_size(egui::vec2(16.0, 16.0)) + .paint_at(ui, resp.rect.shrink(8.0)); resp } } @@ -785,6 +790,7 @@ mod preview { zaps: app.zaps, pool: app.pool, job_pool: app.job_pool, + unknown_ids: app.unknown_ids, current_account_has_wallet: false, }; diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs @@ -12,9 +12,10 @@ use crate::{ }; use notedeck::{ name::get_display_name, profile::get_profile_url, Accounts, MuteFun, NoteAction, NoteContext, - NotedeckTextStyle, UnknownIds, + NotedeckTextStyle, }; use notedeck_ui::{ + app_images, jobs::JobsCache, profile::{about_section_widget, banner, display_name_widget}, NoteOptions, ProfilePic, @@ -26,7 +27,6 @@ pub struct ProfileView<'a, 'd> { col_id: usize, timeline_cache: &'a mut TimelineCache, note_options: NoteOptions, - unknown_ids: &'a mut UnknownIds, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, @@ -45,7 +45,6 @@ impl<'a, 'd> ProfileView<'a, 'd> { col_id: usize, timeline_cache: &'a mut TimelineCache, note_options: NoteOptions, - unknown_ids: &'a mut UnknownIds, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, @@ -56,7 +55,6 @@ impl<'a, 'd> ProfileView<'a, 'd> { col_id, timeline_cache, note_options, - unknown_ids, is_muted, note_context, jobs, @@ -103,7 +101,7 @@ impl<'a, 'd> ProfileView<'a, 'd> { if let Err(e) = profile_timeline.poll_notes_into_view( self.note_context.ndb, &txn, - self.unknown_ids, + self.note_context.unknown_ids, self.note_context.note_cache, reversed, ) { @@ -221,9 +219,13 @@ impl<'a, 'd> ProfileView<'a, 'd> { } fn handle_link(ui: &mut egui::Ui, website_url: &str) { - ui.image(egui::include_image!( - "../../../../../assets/icons/links_4x.png" - )); + let img = if ui.visuals().dark_mode { + app_images::link_image() + } else { + app_images::link_image().tint(egui::Color32::BLACK) + }; + + ui.add(img); if ui .label(RichText::new(website_url).color(notedeck_ui::colors::PINK)) .on_hover_cursor(egui::CursorIcon::PointingHand) @@ -237,9 +239,12 @@ fn handle_link(ui: &mut egui::Ui, website_url: &str) { } fn handle_lud16(ui: &mut egui::Ui, lud16: &str) { - ui.image(egui::include_image!( - "../../../../../assets/icons/zap_4x.png" - )); + let img = if ui.visuals().dark_mode { + app_images::zap_image() + } else { + app_images::zap_image().tint(egui::Color32::BLACK) + }; + ui.add(img); let _ = ui.label(RichText::new(lud16).color(notedeck_ui::colors::PINK)); } @@ -273,10 +278,8 @@ fn copy_key_widget(pfp_rect: &egui::Rect) -> impl egui::Widget + '_ { Stroke::new(1.0, stroke_color), egui::StrokeKind::Outside, ); - egui::Image::new(egui::include_image!( - "../../../../../assets/icons/key_4x.png" - )) - .paint_at( + + app_images::key_image().paint_at( ui, #[allow(deprecated)] painter.round_rect_to_pixels(egui::Rect::from_center_size( @@ -343,10 +346,9 @@ fn edit_profile_button() -> impl egui::Widget + 'static { painter.galley(galley_rect.left_top(), galley, Color32::WHITE); - egui::Image::new(egui::include_image!( - "../../../../../assets/icons/edit_icon_4x_dark.png" - )) - .paint_at(ui, edit_icon_rect); + app_images::edit_dark_image() + .tint(ui.visuals().text_color()) + .paint_at(ui, edit_icon_rect); resp } diff --git a/crates/notedeck_columns/src/ui/relay.rs b/crates/notedeck_columns/src/ui/relay.rs @@ -2,11 +2,10 @@ use std::collections::HashMap; use crate::relay_pool_manager::{RelayPoolManager, RelayStatus}; use crate::ui::{Preview, PreviewConfig}; -use egui::{ - Align, Button, CornerRadius, Frame, Id, Image, Layout, Margin, Rgba, RichText, Ui, Vec2, -}; +use egui::{Align, Button, CornerRadius, Frame, Id, Layout, Margin, Rgba, RichText, Ui, Vec2}; use enostr::RelayPool; use notedeck::{Accounts, NotedeckTextStyle}; +use notedeck_ui::app_images; use notedeck_ui::{colors::PINK, padding, View}; use tracing::debug; @@ -180,10 +179,8 @@ impl<'a> RelayView<'a> { } fn add_relay_button() -> Button<'static> { - let img_data = egui::include_image!("../../../../assets/icons/add_relay_icon_4x.png"); - let img = Image::new(img_data).fit_to_exact_size(Vec2::new(48.0, 48.0)); Button::image_and_text( - img, + app_images::add_relay_image().fit_to_exact_size(Vec2::new(48.0, 48.0)), RichText::new(" Add relay") .size(16.0) // TODO: this color should not be hard coded. Find some way to add it to the visuals @@ -207,18 +204,14 @@ fn get_right_side_width(status: RelayStatus) -> f32 { } } -fn delete_button(_dark_mode: bool) -> egui::Button<'static> { - /* - let img_data = if dark_mode { - egui::include_image!("../../assets/icons/delete_icon_4x.png") +fn delete_button(dark_mode: bool) -> egui::Button<'static> { + let img = if dark_mode { + app_images::delete_dark_image() } else { - // TODO: use light delete icon - egui::include_image!("../../assets/icons/delete_icon_4x.png") + app_images::delete_light_image() }; - */ - let img_data = egui::include_image!("../../../../assets/icons/delete_icon_4x.png"); - egui::Button::image(egui::Image::new(img_data).max_width(10.0)).frame(false) + egui::Button::image(img.max_width(10.0)).frame(false) } fn relay_frame(ui: &mut Ui) -> Frame { @@ -254,19 +247,11 @@ fn show_connection_status(ui: &mut Ui, status: RelayStatus) { } fn get_connection_icon(status: RelayStatus) -> egui::Image<'static> { - let img_data = match status { - RelayStatus::Connected => { - egui::include_image!("../../../../assets/icons/connected_icon_4x.png") - } - RelayStatus::Connecting => { - egui::include_image!("../../../../assets/icons/connecting_icon_4x.png") - } - RelayStatus::Disconnected => { - egui::include_image!("../../../../assets/icons/disconnected_icon_4x.png") - } - }; - - egui::Image::new(img_data) + match status { + RelayStatus::Connected => app_images::connected_image(), + RelayStatus::Connecting => app_images::connecting_image(), + RelayStatus::Disconnected => app_images::disconnected_image(), + } } // PREVIEWS diff --git a/crates/notedeck_columns/src/ui/side_panel.rs b/crates/notedeck_columns/src/ui/side_panel.rs @@ -12,7 +12,7 @@ use crate::{ use notedeck::{Accounts, UserAccount}; use notedeck_ui::{ anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE}, - colors, View, + app_images, colors, View, }; use super::configure_deck::deck_icon; @@ -105,7 +105,7 @@ impl<'a> DesktopSidePanel<'a> { compose_resp.on_hover_cursor(egui::CursorIcon::NotAllowed) }; let search_resp = ui.add(search_button()); - let column_resp = ui.add(add_column_button(dark_mode)); + let column_resp = ui.add(add_column_button()); ui.add(Separator::default().horizontal().spacing(8.0).shrink(4.0)); @@ -295,19 +295,17 @@ impl<'a> DesktopSidePanel<'a> { } } -fn add_column_button(dark_mode: bool) -> impl Widget { +fn add_column_button() -> impl Widget { move |ui: &mut egui::Ui| { let img_size = 24.0; let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget - let img_data = if dark_mode { - egui::include_image!("../../../../assets/icons/add_column_dark_4x.png") + let img = if ui.visuals().dark_mode { + app_images::add_column_dark_image() } else { - egui::include_image!("../../../../assets/icons/add_column_light_4x.png") + app_images::add_column_light_image() }; - let img = egui::Image::new(img_data).max_width(img_size); - let helper = AnimationHelper::new(ui, "add-column-button", vec2(max_size, max_size)); let cur_img_size = helper.scale_1d_pos(img_size); @@ -371,8 +369,7 @@ fn add_deck_button() -> impl Widget { let img_size = 40.0; let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget - let img_data = egui::include_image!("../../../../assets/icons/new_deck_icon_4x_dark.png"); - let img = egui::Image::new(img_data).max_width(img_size); + let img = app_images::new_deck_image().max_width(img_size); let helper = AnimationHelper::new(ui, "new-deck-icon", vec2(max_size, max_size)); diff --git a/crates/notedeck_columns/src/ui/thread.rs b/crates/notedeck_columns/src/ui/thread.rs @@ -3,7 +3,7 @@ use egui_virtual_list::VirtualList; use enostr::KeypairUnowned; use nostrdb::{Note, Transaction}; use notedeck::note::root_note_id_from_selected_id; -use notedeck::{MuteFun, NoteAction, NoteContext, UnknownIds}; +use notedeck::{MuteFun, NoteAction, NoteContext}; use notedeck_ui::jobs::JobsCache; use notedeck_ui::note::NoteResponse; use notedeck_ui::{NoteOptions, NoteView}; @@ -12,7 +12,6 @@ use crate::timeline::thread::{NoteSeenFlags, ParentState, Threads}; pub struct ThreadView<'a, 'd> { threads: &'a mut Threads, - unknown_ids: &'a mut UnknownIds, selected_note_id: &'a [u8; 32], note_options: NoteOptions, col: usize, @@ -27,7 +26,6 @@ impl<'a, 'd> ThreadView<'a, 'd> { #[allow(clippy::too_many_arguments)] pub fn new( threads: &'a mut Threads, - unknown_ids: &'a mut UnknownIds, selected_note_id: &'a [u8; 32], note_options: NoteOptions, is_muted: &'a MuteFun, @@ -38,7 +36,6 @@ impl<'a, 'd> ThreadView<'a, 'd> { let id_source = egui::Id::new("threadscroll_threadview"); ThreadView { threads, - unknown_ids, selected_note_id, note_options, id_source, @@ -96,7 +93,7 @@ impl<'a, 'd> ThreadView<'a, 'd> { self.note_context.note_cache, self.note_context.ndb, txn, - self.unknown_ids, + self.note_context.unknown_ids, self.col, ); diff --git a/crates/notedeck_dave/src/ui/dave.rs b/crates/notedeck_dave/src/ui/dave.rs @@ -5,7 +5,7 @@ use crate::{ use egui::{Align, Key, KeyboardShortcut, Layout, Modifiers}; use nostrdb::{Ndb, Transaction}; use notedeck::{Accounts, AppContext, Images, NoteAction, NoteContext}; -use notedeck_ui::{icons::search_icon, jobs::JobsCache, NoteOptions, ProfilePic}; +use notedeck_ui::{app_images, icons::search_icon, jobs::JobsCache, NoteOptions, ProfilePic}; /// DaveUi holds all of the data it needs to render itself pub struct DaveUi<'a> { @@ -216,6 +216,7 @@ impl<'a> DaveUi<'a> { zaps: ctx.zaps, pool: ctx.pool, job_pool: ctx.job_pool, + unknown_ids: ctx.unknown_ids, current_account_has_wallet: false, }; @@ -359,8 +360,7 @@ fn new_chat_button() -> impl egui::Widget { let img_size = 24.0; let max_size = 32.0; - let img_data = egui::include_image!("../../../../assets/icons/newmessage_64.png"); - let img = egui::Image::new(img_data).max_width(img_size); + let img = app_images::new_message_image().max_width(img_size); let helper = notedeck_ui::anim::AnimationHelper::new( ui, diff --git a/crates/notedeck_ui/Cargo.toml b/crates/notedeck_ui/Cargo.toml @@ -4,6 +4,7 @@ edition = "2021" version.workspace = true [dependencies] +eframe = { workspace = true } egui = { workspace = true } egui_extras = { workspace = true } egui-winit = { workspace = true } diff --git a/crates/notedeck_ui/src/app_images.rs b/crates/notedeck_ui/src/app_images.rs @@ -0,0 +1,207 @@ +use eframe::icon_data::from_png_bytes; +use egui::{include_image, IconData, Image}; + +pub fn app_icon() -> IconData { + from_png_bytes(include_bytes!("../../../assets/damus-app-icon.png")).expect("icon") +} + +pub fn add_account_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/add_account_icon_4x.png" + )) +} + +pub fn add_column_dark_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/add_column_dark_4x.png" + )) +} + +pub fn add_column_light_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/add_column_light_4x.png" + )) +} + +pub fn add_relay_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/add_relay_icon_4x.png" + )) +} + +pub fn algo_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/algo.png")) +} + +pub fn columns_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/columns_80.png")) +} + +pub fn connected_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/connected_icon_4x.png" + )) +} + +pub fn connecting_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/connecting_icon_4x.png" + )) +} + +pub fn damus_image() -> Image<'static> { + Image::new(include_image!("../../../assets/damus_rounded_80.png")) +} + +pub fn delete_dark_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/column_delete_icon_4x.png" + )) +} + +pub fn delete_light_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/column_delete_icon_light_4x.png" + )) +} + +pub fn disconnected_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/disconnected_icon_4x.png" + )) +} + +pub fn edit_dark_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/edit_icon_4x_dark.png" + )) +} + +pub fn eye_dark_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/eye-dark.png")) +} + +pub fn eye_light_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/eye-light.png")) +} + +pub fn eye_slash_dark_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/eye-slash-dark.png")) +} + +pub fn eye_slash_light_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/eye-slash-light.png")) +} + +pub fn filled_zap_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/filled_zap_icon.svg")) +} + +pub fn hashtag_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/hashtag_icon_4x.png")) +} + +pub fn help_dark_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/help_icon_dark_4x.png" + )) +} + +pub fn help_light_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/help_icon_inverted_4x.png" + )) +} + +pub fn home_button_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/home-toolbar.png")) +} + +pub fn home_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/home_icon_dark_4x.png" + )) +} + +pub fn key_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/key_4x.png")) +} + +pub fn link_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/links_4x.png")) +} + +pub fn new_message_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/newmessage_64.png")) +} + +pub fn new_deck_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/new_deck_icon_4x_dark.png" + )) +} + +pub fn notifications_button_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/notifications_dark_4x.png" + )) +} + +pub fn notifications_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/notifications_icon_dark_4x.png" + )) +} +pub fn repost_dark_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/repost_icon_4x.png")) +} + +pub fn repost_light_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/repost_light_4x.png")) +} + +pub fn reply_dark_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/reply.png")) +} + +pub fn reply_light_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/reply-dark.png")) +} + +pub fn profile_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/profile_icon_4x.png")) +} + +pub fn settings_dark_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/settings_dark_4x.png")) +} + +pub fn settings_light_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/settings_light_4x.png" + )) +} + +pub fn universe_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/universe_icon_dark_4x.png" + )) +} + +pub fn verified_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/verified_4x.png")) +} + +pub fn media_upload_dark_image() -> Image<'static> { + Image::new(include_image!( + "../../../assets/icons/media_upload_dark_4x.png" + )) +} + +pub fn wallet_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/wallet-icon.svg")) +} + +pub fn zap_image() -> Image<'static> { + Image::new(include_image!("../../../assets/icons/zap_4x.png")) +} diff --git a/crates/notedeck_ui/src/lib.rs b/crates/notedeck_ui/src/lib.rs @@ -1,4 +1,5 @@ pub mod anim; +pub mod app_images; pub mod blur; pub mod colors; pub mod constants; diff --git a/crates/notedeck_ui/src/note/contents.rs b/crates/notedeck_ui/src/note/contents.rs @@ -89,6 +89,10 @@ pub fn render_note_preview( )); } } else { + note_context + .unknown_ids + .add_note_id_if_missing(note_context.ndb, txn, id); + return NoteResponse::new(ui.colored_label(Color32::RED, "TODO: COULD NOT LOAD")); /* return ui diff --git a/crates/notedeck_ui/src/note/media.rs b/crates/notedeck_ui/src/note/media.rs @@ -10,6 +10,7 @@ use notedeck::{ }; use crate::{ + app_images, blur::{compute_blurhash, Blur, ObfuscationType, PointDimensions}, gif::{handle_repaint, retrieve_latest_texture}, images::{fetch_no_pfp_promise, get_render_state, ImageType}, @@ -537,8 +538,6 @@ fn render_blur_text(ui: &mut egui::Ui, url: &str, render_rect: egui::Rect) -> eg let text_style = NotedeckTextStyle::Button; - let icon_data = egui::include_image!("../../../../assets/icons/eye-slash-dark.png"); - let icon_size = helper.scale_1d_pos(30.0); let animation_fontid = FontId::new( helper.scale_1d_pos(get_font_size(ui.ctx(), &text_style)), @@ -568,9 +567,13 @@ fn render_blur_text(ui: &mut egui::Ui, url: &str, render_rect: egui::Rect) -> eg egui::Rect::from_center_size(center, egui::vec2(icon_size, icon_size)) }; - egui::Image::new(icon_data) - .max_width(icon_size) - .paint_at(ui, icon_rect); + (if ui.visuals().dark_mode { + app_images::eye_slash_dark_image() + } else { + app_images::eye_slash_light_image() + }) + .max_width(icon_size) + .paint_at(ui, icon_rect); let info_galley_pos = { let mut pos = icon_rect.center(); diff --git a/crates/notedeck_ui/src/note/mod.rs b/crates/notedeck_ui/src/note/mod.rs @@ -4,6 +4,7 @@ pub mod media; pub mod options; pub mod reply_description; +use crate::app_images; use crate::jobs::JobsCache; use crate::{ profile::name::one_line_display_name_widget, widgets::x_button, ProfilePic, ProfilePreview, @@ -877,10 +878,10 @@ fn render_reltime( } fn reply_button(ui: &mut egui::Ui, note_key: NoteKey) -> egui::Response { - let img_data = if ui.style().visuals.dark_mode { - egui::include_image!("../../../../assets/icons/reply.png") + let img = if ui.style().visuals.dark_mode { + app_images::reply_dark_image() } else { - egui::include_image!("../../../../assets/icons/reply-dark.png") + app_images::reply_light_image() }; let (rect, size, resp) = @@ -890,18 +891,19 @@ fn reply_button(ui: &mut egui::Ui, note_key: NoteKey) -> egui::Response { let expand_size = 5.0; // from hover_expand_small let rect = rect.translate(egui::vec2(-(expand_size / 2.0), 0.0)); - let put_resp = ui.put(rect, egui::Image::new(img_data).max_width(size)); + let put_resp = ui + .put(rect, img.max_width(size)) + .on_hover_text("Reply to this note"); resp.union(put_resp) } fn repost_icon(dark_mode: bool) -> egui::Image<'static> { - let img_data = if dark_mode { - egui::include_image!("../../../../assets/icons/repost_icon_4x.png") + if dark_mode { + app_images::repost_dark_image() } else { - egui::include_image!("../../../../assets/icons/repost_light_4x.png") - }; - egui::Image::new(img_data) + app_images::repost_light_image() + } } fn quote_repost_button(ui: &mut egui::Ui, note_key: NoteKey) -> egui::Response { @@ -914,18 +916,18 @@ fn quote_repost_button(ui: &mut egui::Ui, note_key: NoteKey) -> egui::Response { let rect = rect.translate(egui::vec2(-(expand_size / 2.0), -1.0)); - let put_resp = ui.put(rect, repost_icon(ui.visuals().dark_mode).max_width(size)); + let put_resp = ui + .put(rect, repost_icon(ui.visuals().dark_mode).max_width(size)) + .on_hover_text("Repost this note"); resp.union(put_resp) } fn zap_button(state: AnyZapState, noteid: &[u8; 32]) -> impl egui::Widget + use<'_> { move |ui: &mut egui::Ui| -> egui::Response { - let img_data = egui::include_image!("../../../../assets/icons/zap_4x.png"); - let (rect, size, resp) = crate::anim::hover_expand_small(ui, ui.id().with("zap")); - let mut img = egui::Image::new(img_data).max_width(size); + let mut img = app_images::zap_image().max_width(size); let id = ui.id().with(("pulse", noteid)); let ctx = ui.ctx().clone(); @@ -954,7 +956,7 @@ fn zap_button(state: AnyZapState, noteid: &[u8; 32]) -> impl egui::Widget + use< let expand_size = 5.0; // from hover_expand_small let rect = rect.translate(egui::vec2(-(expand_size / 2.0), 0.0)); - let put_resp = ui.put(rect, img); + let put_resp = ui.put(rect, img).on_hover_text("Zap this note"); resp.union(put_resp) } diff --git a/crates/notedeck_ui/src/profile/mod.rs b/crates/notedeck_ui/src/profile/mod.rs @@ -10,6 +10,8 @@ pub use preview::ProfilePreview; use egui::{load::TexturePoll, Label, RichText}; use notedeck::{NostrName, NotedeckTextStyle}; +use crate::app_images; + pub fn display_name_widget<'a>( name: &'a NostrName<'a>, add_placeholder_space: bool, @@ -38,9 +40,8 @@ pub fn display_name_widget<'a>( }); let nip05_resp = name.nip05.map(|nip05| { - ui.image(egui::include_image!( - "../../../../assets/icons/verified_4x.png" - )); + ui.add(app_images::verified_image()); + ui.add(Label::new( RichText::new(nip05).size(16.0).color(crate::colors::TEAL), ))