notedeck

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

commit dac786e60fe48887c3ca543c36ac245316b42aeb
parent 09eeb57bd918e34e9539d6b823e318f8be43892c
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 31 Jul 2025 17:07:25 -0700

chrome: remove duplication in app setup

Also move debug warning to chrome so that headless
notedeck apps don't hit that.

Diffstat:
Mcrates/notedeck/src/app.rs | 38+++++++++++++++++++++++++++++++++++---
Mcrates/notedeck/src/fonts.rs | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/notedeck/src/lib.rs | 1+
Acrates/notedeck/src/setup.rs | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/notedeck/src/theme.rs | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mcrates/notedeck_chrome/src/android.rs | 41+++--------------------------------------
Mcrates/notedeck_chrome/src/chrome.rs | 50++++++++++++++++++++++++++++++++++++++++++++++----
Dcrates/notedeck_chrome/src/fonts.rs | 151------------------------------------------------------------------------------
Mcrates/notedeck_chrome/src/lib.rs | 2--
Mcrates/notedeck_chrome/src/notedeck.rs | 52++++++----------------------------------------------
Mcrates/notedeck_chrome/src/setup.rs | 71+----------------------------------------------------------------------
Dcrates/notedeck_chrome/src/theme.rs | 149-------------------------------------------------------------------------------
12 files changed, 449 insertions(+), 467 deletions(-)

diff --git a/crates/notedeck/src/app.rs b/crates/notedeck/src/app.rs @@ -3,6 +3,7 @@ use crate::i18n::Localization; use crate::persist::{AppSizeHandler, SettingsHandler}; use crate::wallet::GlobalWallet; use crate::zaps::Zaps; +use crate::Error; use crate::JobPool; use crate::NotedeckOptions; use crate::{ @@ -252,9 +253,6 @@ impl Notedeck { } } - // Initialize global i18n context - //crate::i18n::init_global_i18n(i18n.clone()); - Self { ndb, img_cache, @@ -277,10 +275,44 @@ impl Notedeck { } } + /// Setup egui context + pub fn setup(&self, ctx: &egui::Context) { + // Initialize global i18n context + //crate::i18n::init_global_i18n(i18n.clone()); + crate::setup::setup_egui_context( + ctx, + self.args.options, + self.theme(), + self.note_body_font_size(), + self.zoom_factor(), + ); + } + + /// ensure we recognized all the arguments + pub fn check_args(&self, other_app_args: &BTreeSet<String>) -> Result<(), Error> { + let completely_unrecognized: Vec<String> = self + .unrecognized_args() + .intersection(other_app_args) + .cloned() + .collect(); + if !completely_unrecognized.is_empty() { + let err = format!("Unrecognized arguments: {:?}", completely_unrecognized); + tracing::error!("{}", &err); + return Err(Error::Generic(err)); + } + + Ok(()) + } + + #[inline] pub fn options(&self) -> NotedeckOptions { self.args.options } + pub fn has_option(&self, option: NotedeckOptions) -> bool { + self.options().contains(option) + } + pub fn app<A: App + 'static>(mut self, app: A) -> Self { self.set_app(app); self diff --git a/crates/notedeck/src/fonts.rs b/crates/notedeck/src/fonts.rs @@ -1,4 +1,9 @@ use crate::{ui, NotedeckTextStyle}; +use egui::FontData; +use egui::FontDefinitions; +use egui::FontTweak; +use std::collections::BTreeMap; +use std::sync::Arc; pub enum NamedFontFamily { Medium, @@ -58,3 +63,148 @@ pub fn get_font_size(ctx: &egui::Context, text_style: &NotedeckTextStyle) -> f32 desktop_font_size(text_style) } } + +// Use gossip's approach to font loading. This includes japanese fonts +// for rending stuff from japanese users. +pub fn setup_fonts(ctx: &egui::Context) { + let mut font_data: BTreeMap<String, Arc<FontData>> = BTreeMap::new(); + let mut families = BTreeMap::new(); + + font_data.insert( + "Onest".to_owned(), + Arc::new(FontData::from_static(include_bytes!( + "../../../assets/fonts/onest/OnestRegular1602-hint.ttf" + ))), + ); + + font_data.insert( + "OnestMedium".to_owned(), + Arc::new(FontData::from_static(include_bytes!( + "../../../assets/fonts/onest/OnestMedium1602-hint.ttf" + ))), + ); + + font_data.insert( + "DejaVuSans".to_owned(), + Arc::new(FontData::from_static(include_bytes!( + "../../../assets/fonts/DejaVuSansSansEmoji.ttf" + ))), + ); + + font_data.insert( + "OnestBold".to_owned(), + Arc::new(FontData::from_static(include_bytes!( + "../../../assets/fonts/onest/OnestBold1602-hint.ttf" + ))), + ); + + /* + font_data.insert( + "DejaVuSansBold".to_owned(), + FontData::from_static(include_bytes!( + "../assets/fonts/DejaVuSans-Bold-SansEmoji.ttf" + )), + ); + + font_data.insert( + "DejaVuSans".to_owned(), + FontData::from_static(include_bytes!("../assets/fonts/DejaVuSansSansEmoji.ttf")), + ); + font_data.insert( + "DejaVuSansBold".to_owned(), + FontData::from_static(include_bytes!( + "../assets/fonts/DejaVuSans-Bold-SansEmoji.ttf" + )), + ); + */ + + font_data.insert( + "Inconsolata".to_owned(), + Arc::new( + FontData::from_static(include_bytes!( + "../../../assets/fonts/Inconsolata-Regular.ttf" + )) + .tweak(FontTweak { + scale: 1.22, // This font is smaller than DejaVuSans + y_offset_factor: -0.18, // and too low + y_offset: 0.0, + baseline_offset_factor: 0.0, + }), + ), + ); + + font_data.insert( + "NotoSansCJK".to_owned(), + Arc::new(FontData::from_static(include_bytes!( + "../../../assets/fonts/NotoSansCJK-Regular.ttc" + ))), + ); + + font_data.insert( + "NotoSansThai".to_owned(), + Arc::new(FontData::from_static(include_bytes!( + "../../../assets/fonts/NotoSansThai-Regular.ttf" + ))), + ); + + // Some good looking emojis. Use as first priority: + font_data.insert( + "NotoEmoji".to_owned(), + Arc::new( + FontData::from_static(include_bytes!( + "../../../assets/fonts/NotoEmoji-Regular.ttf" + )) + .tweak(FontTweak { + scale: 1.1, // make them a touch larger + y_offset_factor: 0.0, + y_offset: 0.0, + baseline_offset_factor: 0.0, + }), + ), + ); + + let base_fonts = vec![ + "DejaVuSans".to_owned(), + "NotoEmoji".to_owned(), + "NotoSansCJK".to_owned(), + "NotoSansThai".to_owned(), + ]; + + let mut proportional = vec!["Onest".to_owned()]; + proportional.extend(base_fonts.clone()); + + let mut medium = vec!["OnestMedium".to_owned()]; + medium.extend(base_fonts.clone()); + + let mut mono = vec!["Inconsolata".to_owned()]; + mono.extend(base_fonts.clone()); + + let mut bold = vec!["OnestBold".to_owned()]; + bold.extend(base_fonts.clone()); + + let emoji = vec!["NotoEmoji".to_owned()]; + + families.insert(egui::FontFamily::Proportional, proportional); + families.insert(egui::FontFamily::Monospace, mono); + families.insert( + egui::FontFamily::Name(NamedFontFamily::Medium.as_str().into()), + medium, + ); + families.insert( + egui::FontFamily::Name(NamedFontFamily::Bold.as_str().into()), + bold, + ); + families.insert( + egui::FontFamily::Name(NamedFontFamily::Emoji.as_str().into()), + emoji, + ); + + tracing::debug!("fonts: {:?}", families); + + let defs = FontDefinitions { + font_data, + families, + }; + + ctx.set_fonts(defs); +} diff --git a/crates/notedeck/src/lib.rs b/crates/notedeck/src/lib.rs @@ -25,6 +25,7 @@ pub mod profile; pub mod relay_debug; pub mod relayspec; mod result; +mod setup; pub mod storage; mod style; pub mod theme; diff --git a/crates/notedeck/src/setup.rs b/crates/notedeck/src/setup.rs @@ -0,0 +1,47 @@ +use crate::fonts; +use crate::theme; +use crate::NotedeckOptions; +use crate::NotedeckTextStyle; +use egui::FontId; +use egui::ThemePreference; + +pub fn setup_egui_context( + ctx: &egui::Context, + options: NotedeckOptions, + theme: ThemePreference, + note_body_font_size: f32, + zoom_factor: f32, +) { + let is_mobile = options.contains(NotedeckOptions::Mobile) || crate::ui::is_compiled_as_mobile(); + + let is_oled = crate::ui::is_oled(); + + ctx.options_mut(|o| { + tracing::info!("Loaded theme {:?} from disk", theme); + o.theme_preference = theme; + }); + ctx.set_visuals_of(egui::Theme::Dark, theme::dark_mode(is_oled)); + ctx.set_visuals_of(egui::Theme::Light, theme::light_mode()); + + fonts::setup_fonts(ctx); + + if crate::ui::is_compiled_as_mobile() { + ctx.set_pixels_per_point(ctx.pixels_per_point() + 0.2); + } + + egui_extras::install_image_loaders(ctx); + + ctx.options_mut(|o| { + o.input_options.max_click_duration = 0.4; + }); + ctx.all_styles_mut(|style| crate::theme::add_custom_style(is_mobile, style)); + + ctx.set_zoom_factor(zoom_factor); + + let mut style = (*ctx.style()).clone(); + style.text_styles.insert( + NotedeckTextStyle::NoteBody.text_style(), + FontId::proportional(note_body_font_size), + ); + ctx.set_style(style); +} diff --git a/crates/notedeck/src/theme.rs b/crates/notedeck/src/theme.rs @@ -1,7 +1,35 @@ -use egui::{ - style::{Selection, WidgetVisuals, Widgets}, - Color32, CornerRadius, Stroke, Visuals, -}; +use crate::{fonts, NotedeckTextStyle}; +use egui::style::Interaction; +use egui::style::Selection; +use egui::style::WidgetVisuals; +use egui::style::Widgets; +use egui::Color32; +use egui::CornerRadius; +use egui::FontId; +use egui::Stroke; +use egui::Style; +use egui::Visuals; +use strum::IntoEnumIterator; + +pub const PURPLE: Color32 = Color32::from_rgb(0xCC, 0x43, 0xC5); +const PURPLE_ALT: Color32 = Color32::from_rgb(0x82, 0x56, 0xDD); +//pub const DARK_BG: Color32 = egui::Color32::from_rgb(40, 44, 52); +pub const GRAY_SECONDARY: Color32 = Color32::from_rgb(0x8A, 0x8A, 0x8A); +const BLACK: Color32 = Color32::from_rgb(0x00, 0x00, 0x00); +const RED_700: Color32 = Color32::from_rgb(0xC7, 0x37, 0x5A); +const ORANGE_700: Color32 = Color32::from_rgb(0xF6, 0xB1, 0x4A); + +// BACKGROUNDS +const SEMI_DARKER_BG: Color32 = Color32::from_rgb(0x39, 0x39, 0x39); +const DARKER_BG: Color32 = Color32::from_rgb(0x1F, 0x1F, 0x1F); +const DARK_BG: Color32 = Color32::from_rgb(0x2C, 0x2C, 0x2C); +const DARK_ISH_BG: Color32 = Color32::from_rgb(0x25, 0x25, 0x25); +const SEMI_DARK_BG: Color32 = Color32::from_rgb(0x44, 0x44, 0x44); + +const LIGHTER_GRAY: Color32 = Color32::from_rgb(0xf8, 0xf8, 0xf8); +const LIGHT_GRAY: Color32 = Color32::from_rgb(0xc8, 0xc8, 0xc8); // 78% +const DARKER_GRAY: Color32 = Color32::from_rgb(0xa5, 0xa5, 0xa5); // 65% +const EVEN_DARKER_GRAY: Color32 = Color32::from_rgb(0x89, 0x89, 0x89); // 54% pub struct ColorTheme { // VISUALS @@ -86,3 +114,131 @@ pub fn create_themed_visuals(theme: ColorTheme, default: Visuals) -> Visuals { ..default } } + +pub fn desktop_dark_color_theme() -> ColorTheme { + ColorTheme { + // VISUALS + panel_fill: DARKER_BG, + extreme_bg_color: DARK_ISH_BG, + text_color: Color32::WHITE, + err_fg_color: RED_700, + warn_fg_color: ORANGE_700, + hyperlink_color: PURPLE, + selection_color: PURPLE_ALT, + + // WINDOW + window_fill: DARK_ISH_BG, + window_stroke_color: DARK_BG, + + // NONINTERACTIVE WIDGET + noninteractive_bg_fill: DARK_ISH_BG, + noninteractive_weak_bg_fill: DARK_BG, + noninteractive_bg_stroke_color: SEMI_DARKER_BG, + noninteractive_fg_stroke_color: GRAY_SECONDARY, + + // INACTIVE WIDGET + inactive_bg_stroke_color: SEMI_DARKER_BG, + inactive_bg_fill: Color32::from_rgb(0x25, 0x25, 0x25), + inactive_weak_bg_fill: SEMI_DARK_BG, + } +} + +pub fn mobile_dark_color_theme() -> ColorTheme { + ColorTheme { + panel_fill: Color32::BLACK, + noninteractive_weak_bg_fill: Color32::from_rgb(0x1F, 0x1F, 0x1F), + ..desktop_dark_color_theme() + } +} + +pub fn light_color_theme() -> ColorTheme { + ColorTheme { + // VISUALS + panel_fill: Color32::WHITE, + extreme_bg_color: LIGHTER_GRAY, + text_color: BLACK, + err_fg_color: RED_700, + warn_fg_color: ORANGE_700, + hyperlink_color: PURPLE, + selection_color: PURPLE_ALT, + + // WINDOW + window_fill: Color32::WHITE, + window_stroke_color: DARKER_GRAY, + + // NONINTERACTIVE WIDGET + noninteractive_bg_fill: Color32::WHITE, + noninteractive_weak_bg_fill: LIGHTER_GRAY, + noninteractive_bg_stroke_color: LIGHT_GRAY, + noninteractive_fg_stroke_color: GRAY_SECONDARY, + + // INACTIVE WIDGET + inactive_bg_stroke_color: EVEN_DARKER_GRAY, + inactive_bg_fill: LIGHTER_GRAY, + inactive_weak_bg_fill: LIGHTER_GRAY, + } +} + +/// Create custom text sizes for any FontSizes +pub fn add_custom_style(is_mobile: bool, style: &mut Style) { + let font_size = if is_mobile { + fonts::mobile_font_size + } else { + fonts::desktop_font_size + }; + + style.text_styles = NotedeckTextStyle::iter() + .map(|text_style| { + ( + text_style.text_style(), + FontId::new(font_size(&text_style), text_style.font_family()), + ) + }) + .collect(); + + style.interaction = Interaction { + tooltip_delay: 0.1, + show_tooltips_only_when_still: false, + ..Interaction::default() + }; + + // debug: show callstack for the current widget on hover if all + // modifier keys are pressed down. + /* + #[cfg(feature = "debug-widget-callstack")] + { + #[cfg(not(debug_assertions))] + compile_error!( + "The `debug-widget-callstack` feature requires a debug build, \ + release builds are unsupported." + ); + style.debug.debug_on_hover_with_all_modifiers = true; + } + + // debug: show an overlay on all interactive widgets + #[cfg(feature = "debug-interactive-widgets")] + { + #[cfg(not(debug_assertions))] + compile_error!( + "The `debug-interactive-widgets` feature requires a debug build, \ + release builds are unsupported." + ); + style.debug.show_interactive_widgets = true; + } + */ +} + +pub fn light_mode() -> Visuals { + create_themed_visuals(crate::theme::light_color_theme(), Visuals::light()) +} + +pub fn dark_mode(is_oled: bool) -> Visuals { + create_themed_visuals( + if is_oled { + mobile_dark_color_theme() + } else { + desktop_dark_color_theme() + }, + Visuals::dark(), + ) +} diff --git a/crates/notedeck_chrome/src/android.rs b/crates/notedeck_chrome/src/android.rs @@ -7,7 +7,7 @@ use notedeck_columns::Damus; use notedeck_dave::Dave; use notedeck_notebook::Notebook; -use crate::{app::NotedeckApp, chrome::Chrome, setup::setup_chrome}; +use crate::{app::NotedeckApp, chrome::Chrome, setup::setup_egui_context}; use notedeck::Notedeck; use tracing::error; @@ -70,44 +70,9 @@ pub async fn android_main(app: AndroidApp) { Box::new(move |cc| { let ctx = &cc.egui_ctx; let mut notedeck = Notedeck::new(ctx, path, &app_args); - setup_chrome( - ctx, - &notedeck.args(), - notedeck.theme(), - notedeck.note_body_font_size(), - notedeck.zoom_factor(), - ); - - let context = &mut notedeck.app_context(); - let dave = Dave::new(cc.wgpu_render_state.as_ref()); - let columns = Damus::new(context, &app_args); - let notebook = Notebook::new(); - let mut chrome = Chrome::new(); - - // ensure we recognized all the arguments - let completely_unrecognized: Vec<String> = notedeck - .unrecognized_args() - .intersection(columns.unrecognized_args()) - .cloned() - .collect(); - if !completely_unrecognized.is_empty() { - error!("Unrecognized arguments: {:?}", completely_unrecognized); - return Err(Error::Empty.into()); - } - - chrome.add_app(NotedeckApp::Columns(Box::new(columns))); - chrome.add_app(NotedeckApp::Dave(Box::new(dave))); - - if notedeck - .options() - .contains(NotedeckOptions::FeaturesNotebook) - { - chrome.add_app(NotedeckApp::Notebook(Box::default())); - } - - // test dav - chrome.set_active(0); + notedeck.setup()?; + let chrome = Chrome::new_with_apps(&mut notedeck); notedeck.set_app(chrome); Ok(Box::new(notedeck)) diff --git a/crates/notedeck_chrome/src/chrome.rs b/crates/notedeck_chrome/src/chrome.rs @@ -2,12 +2,14 @@ //#[cfg(target_arch = "wasm32")] //use wasm_bindgen::prelude::*; use crate::app::NotedeckApp; +use eframe::CreationContext; use egui::{vec2, Button, Color32, Label, Layout, Rect, RichText, ThemePreference, Widget}; use egui_extras::{Size, StripBuilder}; use nostrdb::{ProfileRecord, Transaction}; +use notedeck::Error; use notedeck::{ - tr, App, AppAction, AppContext, Localization, NotedeckOptions, NotedeckTextStyle, UserAccount, - WalletType, + tr, App, AppAction, AppContext, Localization, Notedeck, NotedeckOptions, NotedeckTextStyle, + UserAccount, WalletType, }; use notedeck_columns::{ column::SelectionResult, timeline::kind::ListKind, timeline::TimelineKind, Damus, @@ -168,9 +170,49 @@ impl ChromePanelAction { } } +/// Some people have been running notedeck in debug, let's catch that! +fn stop_debug_mode(options: NotedeckOptions) { + if !options.contains(NotedeckOptions::Tests) + && cfg!(debug_assertions) + && !options.contains(NotedeckOptions::Debug) + { + println!("--- WELCOME TO DAMUS NOTEDECK! ---"); + println!( + "It looks like are running notedeck in debug mode, unless you are a developer, this is not likely what you want." + ); + println!("If you are a developer, run `cargo run -- --debug` to skip this message."); + println!("For everyone else, try again with `cargo run --release`. Enjoy!"); + println!("---------------------------------"); + panic!(); + } +} + impl Chrome { - pub fn new() -> Self { - Chrome::default() + /// Create a new chrome with the default app setup + pub fn new_with_apps( + cc: &CreationContext, + app_args: &[String], + notedeck: &mut Notedeck, + ) -> Result<Self, Error> { + stop_debug_mode(notedeck.options()); + + let context = &mut notedeck.app_context(); + let dave = Dave::new(cc.wgpu_render_state.as_ref()); + let columns = Damus::new(context, app_args); + let mut chrome = Chrome::default(); + + notedeck.check_args(columns.unrecognized_args())?; + + chrome.add_app(NotedeckApp::Columns(Box::new(columns))); + chrome.add_app(NotedeckApp::Dave(Box::new(dave))); + + if notedeck.has_option(NotedeckOptions::FeatureNotebook) { + chrome.add_app(NotedeckApp::Notebook(Box::default())); + } + + chrome.set_active(0); + + Ok(chrome) } pub fn toggle(&mut self) { diff --git a/crates/notedeck_chrome/src/fonts.rs b/crates/notedeck_chrome/src/fonts.rs @@ -1,151 +0,0 @@ -use egui::{FontData, FontDefinitions, FontTweak}; -use std::collections::BTreeMap; -use std::sync::Arc; -use tracing::debug; - -use notedeck::fonts::NamedFontFamily; - -// Use gossip's approach to font loading. This includes japanese fonts -// for rending stuff from japanese users. -pub fn setup_fonts(ctx: &egui::Context) { - let mut font_data: BTreeMap<String, Arc<FontData>> = BTreeMap::new(); - let mut families = BTreeMap::new(); - - font_data.insert( - "Onest".to_owned(), - Arc::new(FontData::from_static(include_bytes!( - "../../../assets/fonts/onest/OnestRegular1602-hint.ttf" - ))), - ); - - font_data.insert( - "OnestMedium".to_owned(), - Arc::new(FontData::from_static(include_bytes!( - "../../../assets/fonts/onest/OnestMedium1602-hint.ttf" - ))), - ); - - font_data.insert( - "DejaVuSans".to_owned(), - Arc::new(FontData::from_static(include_bytes!( - "../../../assets/fonts/DejaVuSansSansEmoji.ttf" - ))), - ); - - font_data.insert( - "OnestBold".to_owned(), - Arc::new(FontData::from_static(include_bytes!( - "../../../assets/fonts/onest/OnestBold1602-hint.ttf" - ))), - ); - - /* - font_data.insert( - "DejaVuSansBold".to_owned(), - FontData::from_static(include_bytes!( - "../assets/fonts/DejaVuSans-Bold-SansEmoji.ttf" - )), - ); - - font_data.insert( - "DejaVuSans".to_owned(), - FontData::from_static(include_bytes!("../assets/fonts/DejaVuSansSansEmoji.ttf")), - ); - font_data.insert( - "DejaVuSansBold".to_owned(), - FontData::from_static(include_bytes!( - "../assets/fonts/DejaVuSans-Bold-SansEmoji.ttf" - )), - ); - */ - - font_data.insert( - "Inconsolata".to_owned(), - Arc::new( - FontData::from_static(include_bytes!( - "../../../assets/fonts/Inconsolata-Regular.ttf" - )) - .tweak(FontTweak { - scale: 1.22, // This font is smaller than DejaVuSans - y_offset_factor: -0.18, // and too low - y_offset: 0.0, - baseline_offset_factor: 0.0, - }), - ), - ); - - font_data.insert( - "NotoSansCJK".to_owned(), - Arc::new(FontData::from_static(include_bytes!( - "../../../assets/fonts/NotoSansCJK-Regular.ttc" - ))), - ); - - font_data.insert( - "NotoSansThai".to_owned(), - Arc::new(FontData::from_static(include_bytes!( - "../../../assets/fonts/NotoSansThai-Regular.ttf" - ))), - ); - - // Some good looking emojis. Use as first priority: - font_data.insert( - "NotoEmoji".to_owned(), - Arc::new( - FontData::from_static(include_bytes!( - "../../../assets/fonts/NotoEmoji-Regular.ttf" - )) - .tweak(FontTweak { - scale: 1.1, // make them a touch larger - y_offset_factor: 0.0, - y_offset: 0.0, - baseline_offset_factor: 0.0, - }), - ), - ); - - let base_fonts = vec![ - "DejaVuSans".to_owned(), - "NotoEmoji".to_owned(), - "NotoSansCJK".to_owned(), - "NotoSansThai".to_owned(), - ]; - - let mut proportional = vec!["Onest".to_owned()]; - proportional.extend(base_fonts.clone()); - - let mut medium = vec!["OnestMedium".to_owned()]; - medium.extend(base_fonts.clone()); - - let mut mono = vec!["Inconsolata".to_owned()]; - mono.extend(base_fonts.clone()); - - let mut bold = vec!["OnestBold".to_owned()]; - bold.extend(base_fonts.clone()); - - let emoji = vec!["NotoEmoji".to_owned()]; - - families.insert(egui::FontFamily::Proportional, proportional); - families.insert(egui::FontFamily::Monospace, mono); - families.insert( - egui::FontFamily::Name(NamedFontFamily::Medium.as_str().into()), - medium, - ); - families.insert( - egui::FontFamily::Name(NamedFontFamily::Bold.as_str().into()), - bold, - ); - families.insert( - egui::FontFamily::Name(NamedFontFamily::Emoji.as_str().into()), - emoji, - ); - - debug!("fonts: {:?}", families); - - let defs = FontDefinitions { - font_data, - families, - }; - - ctx.set_fonts(defs); -} diff --git a/crates/notedeck_chrome/src/lib.rs b/crates/notedeck_chrome/src/lib.rs @@ -1,6 +1,4 @@ -pub mod fonts; pub mod setup; -pub mod theme; #[cfg(target_os = "android")] mod android; diff --git a/crates/notedeck_chrome/src/notedeck.rs b/crates/notedeck_chrome/src/notedeck.rs @@ -9,15 +9,8 @@ use re_memory::AccountingAllocator; static GLOBAL: AccountingAllocator<std::alloc::System> = AccountingAllocator::new(std::alloc::System); -use notedeck::enostr::Error; -use notedeck::{DataPath, DataPathType, Notedeck, NotedeckOptions}; -use notedeck_chrome::{ - setup::{generate_native_options, setup_chrome}, - Chrome, NotedeckApp, -}; -use notedeck_columns::Damus; -use notedeck_dave::Dave; -use tracing::error; +use notedeck::{DataPath, DataPathType, Notedeck}; +use notedeck_chrome::{setup::generate_native_options, Chrome}; use tracing_appender::non_blocking::WorkerGuard; use tracing_subscriber::EnvFilter; @@ -93,42 +86,8 @@ async fn main() { let ctx = &cc.egui_ctx; let mut notedeck = Notedeck::new(ctx, base_path, &args); - - let mut chrome = Chrome::new(); - let columns = Damus::new(&mut notedeck.app_context(), &args); - let dave = Dave::new(cc.wgpu_render_state.as_ref()); - - setup_chrome( - ctx, - notedeck.args(), - notedeck.theme(), - notedeck.note_body_font_size(), - notedeck.zoom_factor(), - ); - - // ensure we recognized all the arguments - let completely_unrecognized: Vec<String> = notedeck - .unrecognized_args() - .intersection(columns.unrecognized_args()) - .cloned() - .collect(); - if !completely_unrecognized.is_empty() { - error!("Unrecognized arguments: {:?}", completely_unrecognized); - return Err(Error::Empty.into()); - } - - chrome.add_app(NotedeckApp::Columns(Box::new(columns))); - chrome.add_app(NotedeckApp::Dave(Box::new(dave))); - - if notedeck - .options() - .contains(NotedeckOptions::FeatureNotebook) - { - chrome.add_app(NotedeckApp::Notebook(Box::default())); - } - - chrome.set_active(0); - + notedeck.setup(ctx); + let chrome = Chrome::new_with_apps(cc, &args, &mut notedeck)?; notedeck.set_app(chrome); Ok(Box::new(notedeck)) @@ -162,7 +121,8 @@ pub fn main() { #[cfg(test)] mod tests { - use super::{Damus, Notedeck}; + use super::Notedeck; + use notedeck_columns::Damus; use std::path::{Path, PathBuf}; fn create_tmp_dir() -> PathBuf { diff --git a/crates/notedeck_chrome/src/setup.rs b/crates/notedeck_chrome/src/setup.rs @@ -1,75 +1,6 @@ -use crate::{fonts, theme}; - use eframe::NativeOptions; -use egui::{FontId, ThemePreference}; -use notedeck::{AppSizeHandler, DataPath, NotedeckOptions, NotedeckTextStyle}; +use notedeck::{AppSizeHandler, DataPath}; use notedeck_ui::app_images; -use tracing::info; - -pub fn setup_chrome( - ctx: &egui::Context, - args: &notedeck::Args, - theme: ThemePreference, - note_body_font_size: f32, - zoom_factor: f32, -) { - let is_mobile = - args.options.contains(NotedeckOptions::Mobile) || notedeck::ui::is_compiled_as_mobile(); - - let is_oled = notedeck::ui::is_oled(); - - // Some people have been running notedeck in debug, let's catch that! - if !args.options.contains(NotedeckOptions::Tests) - && cfg!(debug_assertions) - && !args.options.contains(NotedeckOptions::Debug) - { - println!("--- WELCOME TO DAMUS NOTEDECK! ---"); - println!( - "It looks like are running notedeck in debug mode, unless you are a developer, this is not likely what you want." - ); - println!("If you are a developer, run `cargo run -- --debug` to skip this message."); - println!("For everyone else, try again with `cargo run --release`. Enjoy!"); - println!("---------------------------------"); - panic!(); - } - - ctx.options_mut(|o| { - info!("Loaded theme {:?} from disk", theme); - o.theme_preference = theme; - }); - ctx.set_visuals_of(egui::Theme::Dark, theme::dark_mode(is_oled)); - ctx.set_visuals_of(egui::Theme::Light, theme::light_mode()); - - setup_cc(ctx, is_mobile); - - ctx.set_zoom_factor(zoom_factor); - - let mut style = (*ctx.style()).clone(); - style.text_styles.insert( - NotedeckTextStyle::NoteBody.text_style(), - FontId::proportional(note_body_font_size), - ); - ctx.set_style(style); -} - -pub fn setup_cc(ctx: &egui::Context, is_mobile: bool) { - fonts::setup_fonts(ctx); - - if notedeck::ui::is_compiled_as_mobile() { - ctx.set_pixels_per_point(ctx.pixels_per_point() + 0.2); - } - //ctx.set_pixels_per_point(1.0); - // - // - //ctx.tessellation_options_mut(|to| to.feathering = false); - - egui_extras::install_image_loaders(ctx); - - ctx.options_mut(|o| { - o.input_options.max_click_duration = 0.4; - }); - ctx.all_styles_mut(|style| theme::add_custom_style(is_mobile, style)); -} pub fn generate_native_options(paths: DataPath) -> NativeOptions { let window_builder = Box::new(move |builder: egui::ViewportBuilder| { diff --git a/crates/notedeck_chrome/src/theme.rs b/crates/notedeck_chrome/src/theme.rs @@ -1,149 +0,0 @@ -use egui::{style::Interaction, Color32, FontId, Style, Visuals}; -use notedeck::{ColorTheme, NotedeckTextStyle}; -use strum::IntoEnumIterator; - -pub const PURPLE: Color32 = Color32::from_rgb(0xCC, 0x43, 0xC5); -const PURPLE_ALT: Color32 = Color32::from_rgb(0x82, 0x56, 0xDD); -//pub const DARK_BG: Color32 = egui::Color32::from_rgb(40, 44, 52); -pub const GRAY_SECONDARY: Color32 = Color32::from_rgb(0x8A, 0x8A, 0x8A); -const BLACK: Color32 = Color32::from_rgb(0x00, 0x00, 0x00); -const RED_700: Color32 = Color32::from_rgb(0xC7, 0x37, 0x5A); -const ORANGE_700: Color32 = Color32::from_rgb(0xF6, 0xB1, 0x4A); - -// BACKGROUNDS -const SEMI_DARKER_BG: Color32 = Color32::from_rgb(0x39, 0x39, 0x39); -const DARKER_BG: Color32 = Color32::from_rgb(0x1F, 0x1F, 0x1F); -const DARK_BG: Color32 = Color32::from_rgb(0x2C, 0x2C, 0x2C); -const DARK_ISH_BG: Color32 = Color32::from_rgb(0x25, 0x25, 0x25); -const SEMI_DARK_BG: Color32 = Color32::from_rgb(0x44, 0x44, 0x44); - -const LIGHTER_GRAY: Color32 = Color32::from_rgb(0xf8, 0xf8, 0xf8); -const LIGHT_GRAY: Color32 = Color32::from_rgb(0xc8, 0xc8, 0xc8); // 78% -const DARKER_GRAY: Color32 = Color32::from_rgb(0xa5, 0xa5, 0xa5); // 65% -const EVEN_DARKER_GRAY: Color32 = Color32::from_rgb(0x89, 0x89, 0x89); // 54% - -pub fn desktop_dark_color_theme() -> ColorTheme { - ColorTheme { - // VISUALS - panel_fill: DARKER_BG, - extreme_bg_color: DARK_ISH_BG, - text_color: Color32::WHITE, - err_fg_color: RED_700, - warn_fg_color: ORANGE_700, - hyperlink_color: PURPLE, - selection_color: PURPLE_ALT, - - // WINDOW - window_fill: DARK_ISH_BG, - window_stroke_color: DARK_BG, - - // NONINTERACTIVE WIDGET - noninteractive_bg_fill: DARK_ISH_BG, - noninteractive_weak_bg_fill: DARK_BG, - noninteractive_bg_stroke_color: SEMI_DARKER_BG, - noninteractive_fg_stroke_color: GRAY_SECONDARY, - - // INACTIVE WIDGET - inactive_bg_stroke_color: SEMI_DARKER_BG, - inactive_bg_fill: Color32::from_rgb(0x25, 0x25, 0x25), - inactive_weak_bg_fill: SEMI_DARK_BG, - } -} - -pub fn mobile_dark_color_theme() -> ColorTheme { - ColorTheme { - panel_fill: Color32::BLACK, - noninteractive_weak_bg_fill: Color32::from_rgb(0x1F, 0x1F, 0x1F), - ..desktop_dark_color_theme() - } -} - -pub fn light_color_theme() -> ColorTheme { - ColorTheme { - // VISUALS - panel_fill: Color32::WHITE, - extreme_bg_color: LIGHTER_GRAY, - text_color: BLACK, - err_fg_color: RED_700, - warn_fg_color: ORANGE_700, - hyperlink_color: PURPLE, - selection_color: PURPLE_ALT, - - // WINDOW - window_fill: Color32::WHITE, - window_stroke_color: DARKER_GRAY, - - // NONINTERACTIVE WIDGET - noninteractive_bg_fill: Color32::WHITE, - noninteractive_weak_bg_fill: LIGHTER_GRAY, - noninteractive_bg_stroke_color: LIGHT_GRAY, - noninteractive_fg_stroke_color: GRAY_SECONDARY, - - // INACTIVE WIDGET - inactive_bg_stroke_color: EVEN_DARKER_GRAY, - inactive_bg_fill: LIGHTER_GRAY, - inactive_weak_bg_fill: LIGHTER_GRAY, - } -} - -pub fn light_mode() -> Visuals { - notedeck::theme::create_themed_visuals(light_color_theme(), Visuals::light()) -} - -pub fn dark_mode(is_oled: bool) -> Visuals { - notedeck::theme::create_themed_visuals( - if is_oled { - mobile_dark_color_theme() - } else { - desktop_dark_color_theme() - }, - Visuals::dark(), - ) -} - -/// Create custom text sizes for any FontSizes -pub fn add_custom_style(is_mobile: bool, style: &mut Style) { - let font_size = if is_mobile { - notedeck::fonts::mobile_font_size - } else { - notedeck::fonts::desktop_font_size - }; - - style.text_styles = NotedeckTextStyle::iter() - .map(|text_style| { - ( - text_style.text_style(), - FontId::new(font_size(&text_style), text_style.font_family()), - ) - }) - .collect(); - - style.interaction = Interaction { - tooltip_delay: 0.1, - show_tooltips_only_when_still: false, - ..Interaction::default() - }; - - // debug: show callstack for the current widget on hover if all - // modifier keys are pressed down. - #[cfg(feature = "debug-widget-callstack")] - { - #[cfg(not(debug_assertions))] - compile_error!( - "The `debug-widget-callstack` feature requires a debug build, \ - release builds are unsupported." - ); - style.debug.debug_on_hover_with_all_modifiers = true; - } - - // debug: show an overlay on all interactive widgets - #[cfg(feature = "debug-interactive-widgets")] - { - #[cfg(not(debug_assertions))] - compile_error!( - "The `debug-interactive-widgets` feature requires a debug build, \ - release builds are unsupported." - ); - style.debug.show_interactive_widgets = true; - } -}