notedeck

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

commit 2305f1e50ae8a9ca518ac82fb0de8b18138e8293
parent 83eab711486aa38918ea67f3b23bf8eb6a1e0727
Author: William Casarin <jb55@jb55.com>
Date:   Fri, 31 May 2024 00:52:27 -0500

mobile: make mobile flag runtime-configurable

we need to pass a few more things around but it's not that bad. This
will allow you to launch damus with --mobile for mobile testing without
recompilation.

Diffstat:
MCargo.toml | 1-
Mpreview | 20++------------------
Msrc/app.rs | 50++++++++++++++++++++++++++------------------------
Msrc/app_creation.rs | 7+++----
Msrc/ui/account_login_view.rs | 20+++++++++++---------
Msrc/ui/account_management.rs | 16+++++++++++-----
Msrc/ui/account_switcher.rs | 18++++++++++++------
Msrc/ui/mod.rs | 10+++-------
Msrc/ui/note/mod.rs | 4++--
Msrc/ui/preview.rs | 6+++++-
Msrc/ui/profile/picture.rs | 4++--
Msrc/ui/profile/preview.rs | 4++--
Msrc/ui/relay.rs | 4++--
Msrc/ui/side_panel.rs | 8++++++--
Msrc/ui_preview/main.rs | 28++++++++++++++--------------
15 files changed, 101 insertions(+), 99 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -48,7 +48,6 @@ security-framework = "2.11.0" [features] default = [] -emulate_mobile = [] profiling = ["puffin", "puffin_egui", "eframe/puffin"] [profile.small] diff --git a/preview b/preview @@ -1,20 +1,4 @@ #!/usr/bin/env bash -MOBILE_FLAG=0 -FILTERED_ARGS=() - -# Loop through the command line arguments -for arg in "$@"; do - if [[ "$arg" == "--mobile" ]]; then - MOBILE_FLAG=1 - else - # Add non '--mobile' arguments to the filtered list - FILTERED_ARGS+=("$arg") - fi -done - -if [[ "$MOBILE_FLAG" -eq 1 ]]; then - cargo run --bin ui_preview --features emulate_mobile --release -- "${FILTERED_ARGS[@]}" -else - cargo run --bin ui_preview --release -- "$@" -fi +# pass --mobile for mobile previews +cargo run --bin ui_preview --release -- "$@" diff --git a/src/app.rs b/src/app.rs @@ -8,8 +8,9 @@ use crate::notecache::{CachedNote, NoteCache}; use crate::route::Route; use crate::timeline; use crate::timeline::{NoteRef, Timeline, ViewFilter}; +use crate::ui; use crate::ui::profile::SimpleProfilePreviewController; -use crate::ui::{is_mobile, DesktopSidePanel}; +use crate::ui::DesktopSidePanel; use crate::Result; use egui::{Context, Frame, Style}; @@ -38,6 +39,7 @@ pub struct Damus { //compose: String, note_cache: NoteCache, pool: RelayPool, + is_mobile: bool, /// global navigation for account management popups, etc. nav: Vec<Route>, @@ -599,7 +601,7 @@ fn process_message(damus: &mut Damus, relay: &str, msg: &RelayMessage) { } fn render_damus(damus: &mut Damus, ctx: &Context) { - if is_mobile() { + if damus.is_mobile() { render_damus_mobile(ctx, damus); } else { render_damus_desktop(ctx, damus); @@ -618,36 +620,32 @@ impl Damus { data_path: P, args: Vec<String>, ) -> Self { - // This is also where you can customized the look at feel of egui using - // `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`. - - // Load previous app state (if any). - // Note that you must enable the `persistence` feature for this to work. - //if let Some(storage) = cc.storage { - //return eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default(); - //} - // - - setup_cc(cc); - let mut timelines: Vec<Timeline> = vec![]; - let _initial_limit = 100; + let mut is_mobile: Option<bool> = None; if args.len() > 1 { for arg in &args[1..] { - let filter = serde_json::from_str(arg).unwrap(); - timelines.push(Timeline::new(filter)); + if arg == "--mobile" { + is_mobile = Some(true); + } else if let Ok(filter) = serde_json::from_str(arg) { + timelines.push(Timeline::new(filter)); + } } } else { let filter = serde_json::from_str(include_str!("../queries/timeline.json")).unwrap(); timelines.push(Timeline::new(filter)); }; + let is_mobile = is_mobile.unwrap_or(ui::is_compiled_as_mobile()); + + setup_cc(cc, is_mobile); + let imgcache_dir = data_path.as_ref().join(ImageCache::rel_datadir()); let _ = std::fs::create_dir_all(imgcache_dir.clone()); let mut config = Config::new(); config.set_ingester_threads(2); Self { + is_mobile, state: DamusState::Initializing, pool: RelayPool::new(), img_cache: ImageCache::new(imgcache_dir), @@ -668,9 +666,8 @@ impl Damus { } } - pub fn mock<P: AsRef<Path>>(data_path: P) -> Self { + pub fn mock<P: AsRef<Path>>(data_path: P, is_mobile: bool) -> Self { let mut timelines: Vec<Timeline> = vec![]; - let _initial_limit = 100; let filter = serde_json::from_str(include_str!("../queries/global.json")).unwrap(); timelines.push(Timeline::new(filter)); @@ -680,6 +677,7 @@ impl Damus { let mut config = Config::new(); config.set_ingester_threads(2); Self { + is_mobile, state: DamusState::Initializing, pool: RelayPool::new(), img_cache: ImageCache::new(imgcache_dir), @@ -727,6 +725,10 @@ impl Damus { } self.selected_timeline += 1; } + + pub fn is_mobile(&self) -> bool { + self.is_mobile + } } /* @@ -763,7 +765,7 @@ fn render_panel(ctx: &egui::Context, app: &mut Damus, timeline_ind: usize) { ui.visuals_mut().button_frame = false; if let Some(new_visuals) = - user_requested_visuals_change(is_mobile(), ctx.style().visuals.dark_mode, ui) + user_requested_visuals_change(app.is_mobile(), ctx.style().visuals.dark_mode, ui) { ctx.set_visuals(new_visuals) } @@ -820,14 +822,14 @@ fn render_damus_mobile(ctx: &egui::Context, app: &mut Damus) { #[cfg(feature = "profiling")] puffin::profile_function!(); - main_panel(&ctx.style()).show(ctx, |ui| { + main_panel(&ctx.style(), app.is_mobile()).show(ctx, |ui| { timeline::timeline_view(ui, app, 0); }); } -fn main_panel(style: &Style) -> egui::CentralPanel { +fn main_panel(style: &Style, mobile: bool) -> egui::CentralPanel { let inner_margin = egui::Margin { - top: if crate::ui::is_mobile() { 50.0 } else { 0.0 }, + top: if mobile { 50.0 } else { 0.0 }, left: 0.0, right: 0.0, bottom: 0.0, @@ -854,7 +856,7 @@ fn render_damus_desktop(ctx: &egui::Context, app: &mut Damus) { Size::remainder() }; - main_panel(&ctx.style()).show(ctx, |ui| { + main_panel(&ctx.style(), app.is_mobile()).show(ctx, |ui| { ui.spacing_mut().item_spacing.x = 0.0; if need_scroll { egui::ScrollArea::horizontal().show(ui, |ui| { diff --git a/src/app_creation.rs b/src/app_creation.rs @@ -1,6 +1,5 @@ use crate::app_style::{create_custom_style, dark_mode, desktop_font_size, mobile_font_size}; use crate::fonts::setup_fonts; -use crate::ui::is_mobile; use eframe::NativeOptions; //pub const UI_SCALE_FACTOR: f32 = 0.2; @@ -36,7 +35,7 @@ pub fn generate_mobile_emulator_native_options() -> eframe::NativeOptions { }) } -pub fn setup_cc(cc: &eframe::CreationContext<'_>) { +pub fn setup_cc(cc: &eframe::CreationContext<'_>, is_mobile: bool) { let ctx = &cc.egui_ctx; setup_fonts(ctx); @@ -48,9 +47,9 @@ pub fn setup_cc(cc: &eframe::CreationContext<'_>) { egui_extras::install_image_loaders(ctx); - ctx.set_visuals(dark_mode(is_mobile())); + ctx.set_visuals(dark_mode(is_mobile)); - ctx.set_style(if is_mobile() { + ctx.set_style(if is_mobile { create_custom_style(ctx, mobile_font_size) } else { create_custom_style(ctx, desktop_font_size) diff --git a/src/ui/account_login_view.rs b/src/ui/account_login_view.rs @@ -1,8 +1,7 @@ use crate::app_style::NotedeckTextStyle; use crate::key_parsing::LoginError; use crate::login_manager::LoginManager; -use crate::ui; -use crate::ui::{Preview, View}; +use crate::ui::{Preview, PreviewConfig, View}; use egui::{ Align, Align2, Button, Color32, Frame, Id, LayerId, Margin, Pos2, Rect, RichText, Rounding, Ui, Vec2, Window, @@ -10,25 +9,25 @@ use egui::{ use egui::{Image, TextEdit}; pub struct AccountLoginView<'a> { + is_mobile: bool, manager: &'a mut LoginManager, generate_y_intercept: Option<f32>, } impl<'a> View for AccountLoginView<'a> { fn ui(&mut self, ui: &mut egui::Ui) { - let is_mobile = ui::is_mobile(); if let Some(key) = self.manager.check_for_successful_login() { // TODO: route to "home" println!("successful login with key: {:?}", key); /* - return if is_mobile { + return if self.mobile { // route to "home" on mobile } else { // route to "home" on desktop }; */ } - if is_mobile { + if self.is_mobile { self.show_mobile(ui); } else { self.show(ui); @@ -37,8 +36,9 @@ impl<'a> View for AccountLoginView<'a> { } impl<'a> AccountLoginView<'a> { - pub fn new(manager: &'a mut LoginManager) -> Self { + pub fn new(manager: &'a mut LoginManager, is_mobile: bool) -> Self { AccountLoginView { + is_mobile, manager, generate_y_intercept: None, } @@ -361,20 +361,22 @@ fn login_textedit(manager: &mut LoginManager) -> TextEdit { } pub struct AccountLoginPreview { + is_mobile: bool, manager: LoginManager, } impl View for AccountLoginPreview { fn ui(&mut self, ui: &mut egui::Ui) { - AccountLoginView::new(&mut self.manager).ui(ui); + AccountLoginView::new(&mut self.manager, self.is_mobile).ui(ui); } } impl<'a> Preview for AccountLoginView<'a> { type Prev = AccountLoginPreview; - fn preview() -> Self::Prev { + fn preview(cfg: PreviewConfig) -> Self::Prev { let manager = LoginManager::new(); - AccountLoginPreview { manager } + let is_mobile = cfg.is_mobile; + AccountLoginPreview { is_mobile, manager } } } diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs @@ -2,7 +2,7 @@ use crate::colors::PINK; use crate::{ account_manager::AccountManager, app_style::NotedeckTextStyle, - ui::{self, Preview, View}, + ui::{Preview, PreviewConfig, View}, }; use egui::{Align, Button, Frame, Image, Layout, RichText, ScrollArea, Vec2}; @@ -10,13 +10,14 @@ use super::profile::preview::SimpleProfilePreview; use super::profile::{ProfilePreviewOp, SimpleProfilePreviewController}; pub struct AccountManagementView<'a> { + mobile: bool, account_manager: &'a mut AccountManager, simple_preview_controller: SimpleProfilePreviewController<'a>, } impl<'a> View for AccountManagementView<'a> { fn ui(&mut self, ui: &mut egui::Ui) { - if ui::is_mobile() { + if self.mobile { self.show_mobile(ui); } else { self.show(ui); @@ -26,10 +27,12 @@ impl<'a> View for AccountManagementView<'a> { impl<'a> AccountManagementView<'a> { pub fn new( + mobile: bool, account_manager: &'a mut AccountManager, simple_preview_controller: SimpleProfilePreviewController<'a>, ) -> Self { AccountManagementView { + mobile, account_manager, simple_preview_controller, } @@ -236,16 +239,18 @@ mod preview { use crate::{imgcache::ImageCache, test_data::get_accmgr_and_ndb_and_imgcache}; pub struct AccountManagementPreview { + is_mobile: bool, account_manager: AccountManager, ndb: Ndb, img_cache: ImageCache, } impl AccountManagementPreview { - fn new() -> Self { + fn new(is_mobile: bool) -> Self { let (account_manager, ndb, img_cache) = get_accmgr_and_ndb_and_imgcache(); AccountManagementPreview { + is_mobile, account_manager, ndb, img_cache, @@ -257,6 +262,7 @@ mod preview { fn ui(&mut self, ui: &mut egui::Ui) { ui.add_space(24.0); AccountManagementView::new( + self.is_mobile, &mut self.account_manager, SimpleProfilePreviewController::new(&self.ndb, &mut self.img_cache), ) @@ -267,8 +273,8 @@ mod preview { impl<'a> Preview for AccountManagementView<'a> { type Prev = AccountManagementPreview; - fn preview() -> Self::Prev { - AccountManagementPreview::new() + fn preview(cfg: PreviewConfig) -> Self::Prev { + AccountManagementPreview::new(cfg.is_mobile) } } } diff --git a/src/ui/account_switcher.rs b/src/ui/account_switcher.rs @@ -2,7 +2,7 @@ use crate::{ account_manager::{AccountManager, UserAccount}, colors::PINK, profile::DisplayName, - ui, Result, + Result, }; use egui::{ Align, Button, Color32, Frame, Id, Image, Layout, Margin, RichText, Rounding, ScrollArea, @@ -12,6 +12,7 @@ use egui::{ use super::profile::{preview::SimpleProfilePreview, SimpleProfilePreviewController}; pub struct AccountSelectionWidget<'a> { + is_mobile: bool, account_manager: &'a AccountManager, simple_preview_controller: SimpleProfilePreviewController<'a>, } @@ -29,17 +30,19 @@ struct AccountSelectResponse { impl<'a> AccountSelectionWidget<'a> { pub fn new( + is_mobile: bool, account_manager: &'a AccountManager, simple_preview_controller: SimpleProfilePreviewController<'a>, ) -> Self { AccountSelectionWidget { + is_mobile, account_manager, simple_preview_controller, } } pub fn ui(&'a mut self, ui: &mut egui::Ui) { - if ui::is_mobile() { + if self.is_mobile { self.show_mobile(ui); } else { self.show(ui); @@ -218,21 +221,23 @@ mod previews { account_manager::AccountManager, imgcache::ImageCache, test_data, - ui::{profile::SimpleProfilePreviewController, Preview, View}, + ui::{profile::SimpleProfilePreviewController, Preview, PreviewConfig, View}, }; use super::AccountSelectionWidget; pub struct AccountSelectionPreview { + is_mobile: bool, account_manager: AccountManager, ndb: Ndb, img_cache: ImageCache, } impl AccountSelectionPreview { - fn new() -> Self { + fn new(is_mobile: bool) -> Self { let (account_manager, ndb, img_cache) = test_data::get_accmgr_and_ndb_and_imgcache(); AccountSelectionPreview { + is_mobile, account_manager, ndb, img_cache, @@ -243,6 +248,7 @@ mod previews { impl View for AccountSelectionPreview { fn ui(&mut self, ui: &mut egui::Ui) { AccountSelectionWidget::new( + self.is_mobile, &self.account_manager, SimpleProfilePreviewController::new(&self.ndb, &mut self.img_cache), ) @@ -253,8 +259,8 @@ mod previews { impl<'a> Preview for AccountSelectionWidget<'a> { type Prev = AccountSelectionPreview; - fn preview() -> Self::Prev { - AccountSelectionPreview::new() + fn preview(cfg: PreviewConfig) -> Self::Prev { + AccountSelectionPreview::new(cfg.is_mobile) } } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs @@ -14,7 +14,7 @@ pub use account_management::AccountManagementView; pub use account_switcher::AccountSelectionWidget; pub use mention::Mention; pub use note::Note; -pub use preview::{Preview, PreviewApp}; +pub use preview::{Preview, PreviewApp, PreviewConfig}; pub use profile::{ProfilePic, ProfilePreview}; pub use relay::RelayView; pub use side_panel::DesktopSidePanel; @@ -53,16 +53,12 @@ pub fn hline(ui: &egui::Ui) { #[inline] #[allow(unreachable_code)] -pub fn is_mobile() -> bool { - #[cfg(feature = "emulate_mobile")] - { - return true; - } - +pub fn is_compiled_as_mobile() -> bool { #[cfg(any(target_os = "android", target_os = "ios"))] { true } + #[cfg(not(any(target_os = "android", target_os = "ios")))] { false diff --git a/src/ui/note/mod.rs b/src/ui/note/mod.rs @@ -4,7 +4,7 @@ pub mod options; pub use contents::NoteContents; pub use options::NoteOptions; -use crate::{colors, notecache::CachedNote, ui, ui::is_mobile, Damus}; +use crate::{colors, notecache::CachedNote, ui, Damus}; use egui::{Label, RichText, Sense}; use nostrdb::{NoteKey, Transaction}; use std::hash::{Hash, Hasher}; @@ -211,7 +211,7 @@ impl<'a> Note<'a> { let profile_key = profile.as_ref().unwrap().record().note_key(); let note_key = note_key.as_u64(); - if is_mobile() { + if self.app.is_mobile() { ui.add(ui::ProfilePic::new(&mut self.app.img_cache, pic)); } else { let (rect, size) = ui::anim::hover_expand( diff --git a/src/ui/preview.rs b/src/ui/preview.rs @@ -1,9 +1,13 @@ use crate::ui::View; +pub struct PreviewConfig { + pub is_mobile: bool, +} + pub trait Preview { type Prev: View; - fn preview() -> Self::Prev; + fn preview(cfg: PreviewConfig) -> Self::Prev; } pub struct PreviewApp { diff --git a/src/ui/profile/picture.rs b/src/ui/profile/picture.rs @@ -1,5 +1,5 @@ use crate::imgcache::ImageCache; -use crate::ui::{Preview, View}; +use crate::ui::{Preview, PreviewConfig, View}; use egui::{vec2, Sense, TextureHandle}; pub struct ProfilePic<'cache, 'url> { @@ -185,7 +185,7 @@ mod preview { impl<'cache, 'url> Preview for ProfilePic<'cache, 'url> { type Prev = ProfilePicPreview; - fn preview() -> Self::Prev { + fn preview(_cfg: PreviewConfig) -> Self::Prev { ProfilePicPreview::new() } } diff --git a/src/ui/profile/preview.rs b/src/ui/profile/preview.rs @@ -111,7 +111,7 @@ impl<'a, 'cache> egui::Widget for SimpleProfilePreview<'a, 'cache> { mod previews { use super::*; use crate::test_data::test_profile_record; - use crate::ui::{Preview, View}; + use crate::ui::{Preview, PreviewConfig, View}; pub struct ProfilePreviewPreview<'a> { profile: ProfileRecord<'a>, @@ -142,7 +142,7 @@ mod previews { /// A preview of the profile preview :D type Prev = ProfilePreviewPreview<'a>; - fn preview() -> Self::Prev { + fn preview(_cfg: PreviewConfig) -> Self::Prev { ProfilePreviewPreview::new() } } diff --git a/src/ui/relay.rs b/src/ui/relay.rs @@ -1,5 +1,5 @@ use crate::relay_pool_manager::{RelayPoolManager, RelayStatus}; -use crate::ui::{Preview, View}; +use crate::ui::{Preview, PreviewConfig, View}; use egui::{Align, Button, Frame, Layout, Margin, Rgba, RichText, Rounding, Ui, Vec2}; use crate::app_style::NotedeckTextStyle; @@ -203,7 +203,7 @@ mod preview { impl<'a> Preview for RelayView<'a> { type Prev = RelayViewPreview; - fn preview() -> Self::Prev { + fn preview(_cfg: PreviewConfig) -> Self::Prev { RelayViewPreview::new() } } diff --git a/src/ui/side_panel.rs b/src/ui/side_panel.rs @@ -125,7 +125,11 @@ fn add_column_button(dark_mode: bool) -> egui::Button<'static> { mod preview { use nostrdb::Ndb; - use crate::{imgcache::ImageCache, test_data, ui::Preview}; + use crate::{ + imgcache::ImageCache, + test_data, + ui::{Preview, PreviewConfig}, + }; use super::*; @@ -165,7 +169,7 @@ mod preview { impl<'a> Preview for DesktopSidePanel<'a> { type Prev = DesktopSidePanelPreview; - fn preview() -> Self::Prev { + fn preview(_cfg: PreviewConfig) -> Self::Prev { DesktopSidePanelPreview::new() } } diff --git a/src/ui_preview/main.rs b/src/ui_preview/main.rs @@ -4,7 +4,7 @@ use notedeck::app_creation::{ use notedeck::ui::account_login_view::AccountLoginView; use notedeck::ui::{ AccountManagementView, AccountSelectionWidget, DesktopSidePanel, Preview, PreviewApp, - ProfilePic, ProfilePreview, RelayView, + PreviewConfig, ProfilePic, ProfilePreview, RelayView, }; use std::env; @@ -29,11 +29,12 @@ impl PreviewRunner { generate_native_options() }; + let is_mobile = self.force_mobile; let _ = eframe::run_native( "UI Preview Runner", native_options, - Box::new(|cc| { - setup_cc(cc); + Box::new(move |cc| { + setup_cc(cc, is_mobile); Box::new(Into::<PreviewApp>::into(preview)) }), ); @@ -42,11 +43,11 @@ impl PreviewRunner { macro_rules! previews { // Accept a runner and name variable, followed by one or more identifiers for the views - ($runner:expr, $name:expr, $($view:ident),* $(,)?) => { + ($runner:expr, $name:expr, $is_mobile:expr, $($view:ident),* $(,)?) => { match $name.as_ref() { $( stringify!($view) => { - $runner.run($view::preview()).await; + $runner.run($view::preview(PreviewConfig { is_mobile: $is_mobile })).await; } )* _ => println!("Component not found."), @@ -57,17 +58,14 @@ macro_rules! previews { #[tokio::main] async fn main() { let mut name: Option<String> = None; - - #[allow(unused_assignments)] - #[allow(unused_mut)] - let mut is_mobile = false; - #[cfg(feature = "emulate_mobile")] - { - is_mobile = true - } + let mut is_mobile: Option<bool> = None; for arg in env::args() { - name = Some(arg); + if arg == "--mobile" { + is_mobile = Some(true); + } else { + name = Some(arg); + } } let name = if let Some(name) = name { @@ -77,11 +75,13 @@ async fn main() { return; }; + let is_mobile = is_mobile.unwrap_or(notedeck::ui::is_compiled_as_mobile()); let runner = PreviewRunner::new(is_mobile); previews!( runner, name, + is_mobile, RelayView, AccountLoginView, ProfilePreview,