commit c3bbc6b977d752c4dec036e69336d7edc7cc9aff
parent 8b80096290d8978209ed2276b4ec828cf3b67931
Author: William Casarin <jb55@jb55.com>
Date: Fri, 13 Dec 2024 08:32:24 -0800
android: fix issues due to rearchitecture
Diffstat:
8 files changed, 306 insertions(+), 308 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -2526,6 +2526,7 @@ dependencies = [
"egui",
"egui_extras",
"enostr",
+ "log",
"nostrdb",
"notedeck",
"notedeck_columns",
@@ -2557,7 +2558,6 @@ dependencies = [
"hex",
"image",
"indexmap",
- "log",
"nostrdb",
"notedeck",
"open",
diff --git a/crates/notedeck_chrome/Cargo.toml b/crates/notedeck_chrome/Cargo.toml
@@ -40,6 +40,7 @@ profiling = ["notedeck_columns/puffin"]
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.11.1"
+log = { workspace = true }
android-activity = { version = "0.4", features = [ "native-activity" ] }
winit = { version = "0.30.5", features = [ "android-native-activity" ] }
diff --git a/crates/notedeck_chrome/src/android.rs b/crates/notedeck_chrome/src/android.rs
@@ -0,0 +1,102 @@
+//#[cfg(target_os = "android")]
+//use egui_android::run_android;
+
+use crate::app::Notedeck;
+use winit::platform::android::activity::AndroidApp;
+use winit::platform::android::EventLoopBuilderExtAndroid;
+
+#[no_mangle]
+#[tokio::main]
+pub async fn android_main(app: AndroidApp) {
+ std::env::set_var("RUST_BACKTRACE", "full");
+ android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info));
+
+ let path = app.internal_data_path().expect("data path");
+ let mut options = eframe::NativeOptions::default();
+ options.renderer = eframe::Renderer::Wgpu;
+ // Clone `app` to use it both in the closure and later in the function
+ let app_clone_for_event_loop = app.clone();
+ options.event_loop_builder = Some(Box::new(move |builder| {
+ builder.with_android_app(app_clone_for_event_loop);
+ }));
+
+ let app_args = get_app_args(app);
+
+ let _res = eframe::run_native(
+ "Damus Notedeck",
+ options,
+ Box::new(move |cc| Ok(Box::new(Notedeck::new(&cc.egui_ctx, path, &app_args)))),
+ );
+}
+
+use serde_json::Value;
+use std::fs;
+use std::path::PathBuf;
+
+/*
+Read args from a config file:
+- allows use of more interesting args w/o risk of checking them in by mistake
+- allows use of different args w/o rebuilding the app
+- uses compiled in defaults if config file missing or broken
+
+Example android-config.json:
+```
+{
+ "args": [
+ "--npub",
+ "npub1h50pnxqw9jg7dhr906fvy4mze2yzawf895jhnc3p7qmljdugm6gsrurqev",
+ "-c",
+ "contacts",
+ "-c",
+ "notifications"
+ ]
+}
+```
+
+Install/update android-config.json with:
+```
+adb push android-config.json /sdcard/Android/data/com.damus.app/files/android-config.json
+```
+
+Using internal storage would be better but it seems hard to get the config file onto
+the device ...
+*/
+
+fn get_app_args(app: AndroidApp) -> Vec<String> {
+ let external_data_path: PathBuf = app
+ .external_data_path()
+ .expect("external data path")
+ .to_path_buf();
+ let config_file = external_data_path.join("android-config.json");
+
+ let default_args = vec![
+ "--pub",
+ "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
+ "-c",
+ "contacts",
+ "-c",
+ "notifications",
+ "-c",
+ "notifications:3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681",
+ ]
+ .into_iter()
+ .map(|s| s.to_string())
+ .collect();
+
+ if config_file.exists() {
+ if let Ok(config_contents) = fs::read_to_string(config_file) {
+ if let Ok(json) = serde_json::from_str::<Value>(&config_contents) {
+ if let Some(args_array) = json.get("args").and_then(|v| v.as_array()) {
+ let config_args = args_array
+ .iter()
+ .filter_map(|v| v.as_str().map(String::from))
+ .collect();
+
+ return config_args;
+ }
+ }
+ }
+ }
+
+ default_args // Return the default args if config is missing or invalid
+}
diff --git a/crates/notedeck_chrome/src/app.rs b/crates/notedeck_chrome/src/app.rs
@@ -0,0 +1,191 @@
+use crate::{app_size::AppSizeHandler, setup::setup_cc, theme};
+
+use notedeck::{
+ Accounts, AppContext, Args, DataPath, DataPathType, Directory, FileKeyStorage, ImageCache,
+ KeyStorageType, NoteCache, ThemeHandler, UnknownIds,
+};
+
+use enostr::RelayPool;
+use nostrdb::{Config, Ndb, Transaction};
+use std::cell::RefCell;
+use std::path::Path;
+use std::rc::Rc;
+use tracing::info;
+
+/// Our browser app state
+pub struct Notedeck {
+ ndb: Ndb,
+ img_cache: ImageCache,
+ unknown_ids: UnknownIds,
+ pool: RelayPool,
+ note_cache: NoteCache,
+ accounts: Accounts,
+ path: DataPath,
+ args: Args,
+ theme: ThemeHandler,
+ tabs: Tabs,
+ app_rect_handler: AppSizeHandler,
+ egui: egui::Context,
+}
+
+impl eframe::App for Notedeck {
+ /// Called by the frame work to save state before shutdown.
+ fn save(&mut self, _storage: &mut dyn eframe::Storage) {
+ //eframe::set_value(storage, eframe::APP_KEY, self);
+ }
+
+ fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
+ // TODO: render chrome
+
+ // render app
+ if let Some(app) = &self.tabs.app {
+ let app = app.clone();
+ app.borrow_mut().update(&mut self.app_context());
+ }
+
+ self.app_rect_handler.try_save_app_size(ctx);
+ }
+}
+
+impl Notedeck {
+ pub fn new<P: AsRef<Path>>(ctx: &egui::Context, data_path: P, args: &[String]) -> Self {
+ let parsed_args = Args::parse(args);
+ let is_mobile = parsed_args
+ .is_mobile
+ .unwrap_or(notedeck::ui::is_compiled_as_mobile());
+
+ // Some people have been running notedeck in debug, let's catch that!
+ if !cfg!(test) && cfg!(debug_assertions) && !parsed_args.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!();
+ }
+
+ setup_cc(ctx, is_mobile, parsed_args.light);
+
+ let data_path = parsed_args
+ .datapath
+ .unwrap_or(data_path.as_ref().to_str().expect("db path ok").to_string());
+ let path = DataPath::new(&data_path);
+ let dbpath_str = parsed_args
+ .dbpath
+ .unwrap_or_else(|| path.path(DataPathType::Db).to_str().unwrap().to_string());
+
+ let _ = std::fs::create_dir_all(&dbpath_str);
+
+ let imgcache_dir = path.path(DataPathType::Cache).join(ImageCache::rel_dir());
+ let _ = std::fs::create_dir_all(imgcache_dir.clone());
+
+ let mapsize = if cfg!(target_os = "windows") {
+ // 16 Gib on windows because it actually creates the file
+ 1024usize * 1024usize * 1024usize * 16usize
+ } else {
+ // 1 TiB for everything else since its just virtually mapped
+ 1024usize * 1024usize * 1024usize * 1024usize
+ };
+
+ let theme = ThemeHandler::new(&path);
+ ctx.options_mut(|o| {
+ let cur_theme = theme.load();
+ info!("Loaded theme {:?} from disk", cur_theme);
+ o.theme_preference = cur_theme;
+ });
+ ctx.set_visuals_of(
+ egui::Theme::Dark,
+ theme::dark_mode(notedeck::ui::is_compiled_as_mobile()),
+ );
+ ctx.set_visuals_of(egui::Theme::Light, theme::light_mode());
+
+ let config = Config::new().set_ingester_threads(4).set_mapsize(mapsize);
+
+ let keystore = if parsed_args.use_keystore {
+ let keys_path = path.path(DataPathType::Keys);
+ let selected_key_path = path.path(DataPathType::SelectedKey);
+ KeyStorageType::FileSystem(FileKeyStorage::new(
+ Directory::new(keys_path),
+ Directory::new(selected_key_path),
+ ))
+ } else {
+ KeyStorageType::None
+ };
+
+ let mut accounts = Accounts::new(keystore, parsed_args.relays);
+
+ let num_keys = parsed_args.keys.len();
+
+ let mut unknown_ids = UnknownIds::default();
+ let ndb = Ndb::new(&dbpath_str, &config).expect("ndb");
+
+ {
+ let txn = Transaction::new(&ndb).expect("txn");
+ for key in parsed_args.keys {
+ info!("adding account: {}", key.pubkey);
+ accounts
+ .add_account(key)
+ .process_action(&mut unknown_ids, &ndb, &txn);
+ }
+ }
+
+ if num_keys != 0 {
+ accounts.select_account(0);
+ }
+
+ // AccountManager will setup the pool on first update
+ let pool = RelayPool::new();
+
+ let img_cache = ImageCache::new(imgcache_dir);
+ let note_cache = NoteCache::default();
+ let unknown_ids = UnknownIds::default();
+ let egui = ctx.clone();
+ let tabs = Tabs::new(None);
+ let parsed_args = Args::parse(args);
+ let app_rect_handler = AppSizeHandler::new(&path);
+
+ Self {
+ ndb,
+ img_cache,
+ app_rect_handler,
+ unknown_ids,
+ pool,
+ note_cache,
+ accounts,
+ path: path.clone(),
+ args: parsed_args,
+ theme,
+ egui,
+ tabs,
+ }
+ }
+
+ pub fn app_context(&mut self) -> AppContext<'_> {
+ AppContext {
+ ndb: &self.ndb,
+ img_cache: &mut self.img_cache,
+ unknown_ids: &mut self.unknown_ids,
+ pool: &mut self.pool,
+ note_cache: &mut self.note_cache,
+ accounts: &mut self.accounts,
+ path: &self.path,
+ args: &self.args,
+ theme: &mut self.theme,
+ egui: &self.egui,
+ }
+ }
+
+ pub fn add_app<T: notedeck::App + 'static>(&mut self, app: T) {
+ self.tabs.app = Some(Rc::new(RefCell::new(app)));
+ }
+}
+
+struct Tabs {
+ app: Option<Rc<RefCell<dyn notedeck::App>>>,
+}
+
+impl Tabs {
+ pub fn new(app: Option<Rc<RefCell<dyn notedeck::App>>>) -> Self {
+ Self { app }
+ }
+}
diff --git a/crates/notedeck_chrome/src/lib.rs b/crates/notedeck_chrome/src/lib.rs
@@ -2,3 +2,10 @@ pub mod app_size;
pub mod fonts;
pub mod setup;
pub mod theme;
+
+mod app;
+
+pub use app::Notedeck;
+
+#[cfg(target_os = "android")]
+mod android;
diff --git a/crates/notedeck_chrome/src/notedeck.rs b/crates/notedeck_chrome/src/notedeck.rs
@@ -1,204 +1,12 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
-use notedeck_chrome::{
- app_size::AppSizeHandler,
- setup::{generate_native_options, setup_cc},
- theme,
-};
+use notedeck_chrome::{setup::generate_native_options, Notedeck};
+use notedeck::{DataPath, DataPathType};
use notedeck_columns::Damus;
-
-use notedeck::{
- Accounts, AppContext, Args, DataPath, DataPathType, Directory, FileKeyStorage, ImageCache,
- KeyStorageType, NoteCache, ThemeHandler, UnknownIds,
-};
-
-use enostr::RelayPool;
-use nostrdb::{Config, Ndb, Transaction};
-use std::cell::RefCell;
-use std::path::Path;
-use std::rc::Rc;
-use std::{path::PathBuf, str::FromStr};
-use tracing::info;
+use std::path::PathBuf;
+use std::str::FromStr;
use tracing_subscriber::EnvFilter;
-/// Our browser app state
-struct Notedeck {
- ndb: Ndb,
- img_cache: ImageCache,
- unknown_ids: UnknownIds,
- pool: RelayPool,
- note_cache: NoteCache,
- accounts: Accounts,
- path: DataPath,
- args: Args,
- theme: ThemeHandler,
- tabs: Tabs,
- app_rect_handler: AppSizeHandler,
- egui: egui::Context,
-}
-
-struct Tabs {
- app: Option<Rc<RefCell<dyn notedeck::App>>>,
-}
-
-impl Tabs {
- pub fn new(app: Option<Rc<RefCell<dyn notedeck::App>>>) -> Self {
- Self { app }
- }
-}
-
-impl eframe::App for Notedeck {
- /// Called by the frame work to save state before shutdown.
- fn save(&mut self, _storage: &mut dyn eframe::Storage) {
- //eframe::set_value(storage, eframe::APP_KEY, self);
- }
-
- fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
- // TODO: render chrome
-
- // render app
- if let Some(app) = &self.tabs.app {
- let app = app.clone();
- app.borrow_mut().update(&mut self.app_context());
- }
-
- self.app_rect_handler.try_save_app_size(ctx);
- }
-}
-
-impl Notedeck {
- pub fn new<P: AsRef<Path>>(ctx: &egui::Context, data_path: P, args: &[String]) -> Self {
- let parsed_args = Args::parse(args);
- let is_mobile = parsed_args
- .is_mobile
- .unwrap_or(notedeck::ui::is_compiled_as_mobile());
-
- // Some people have been running notedeck in debug, let's catch that!
- if !cfg!(test) && cfg!(debug_assertions) && !parsed_args.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!();
- }
-
- setup_cc(ctx, is_mobile, parsed_args.light);
-
- let data_path = parsed_args
- .datapath
- .unwrap_or(data_path.as_ref().to_str().expect("db path ok").to_string());
- let path = DataPath::new(&data_path);
- let dbpath_str = parsed_args
- .dbpath
- .unwrap_or_else(|| path.path(DataPathType::Db).to_str().unwrap().to_string());
-
- let _ = std::fs::create_dir_all(&dbpath_str);
-
- let imgcache_dir = path.path(DataPathType::Cache).join(ImageCache::rel_dir());
- let _ = std::fs::create_dir_all(imgcache_dir.clone());
-
- let mapsize = if cfg!(target_os = "windows") {
- // 16 Gib on windows because it actually creates the file
- 1024usize * 1024usize * 1024usize * 16usize
- } else {
- // 1 TiB for everything else since its just virtually mapped
- 1024usize * 1024usize * 1024usize * 1024usize
- };
-
- let theme = ThemeHandler::new(&path);
- ctx.options_mut(|o| {
- let cur_theme = theme.load();
- info!("Loaded theme {:?} from disk", cur_theme);
- o.theme_preference = cur_theme;
- });
- ctx.set_visuals_of(
- egui::Theme::Dark,
- theme::dark_mode(notedeck::ui::is_compiled_as_mobile()),
- );
- ctx.set_visuals_of(egui::Theme::Light, theme::light_mode());
-
- let config = Config::new().set_ingester_threads(4).set_mapsize(mapsize);
-
- let keystore = if parsed_args.use_keystore {
- let keys_path = path.path(DataPathType::Keys);
- let selected_key_path = path.path(DataPathType::SelectedKey);
- KeyStorageType::FileSystem(FileKeyStorage::new(
- Directory::new(keys_path),
- Directory::new(selected_key_path),
- ))
- } else {
- KeyStorageType::None
- };
-
- let mut accounts = Accounts::new(keystore, parsed_args.relays);
-
- let num_keys = parsed_args.keys.len();
-
- let mut unknown_ids = UnknownIds::default();
- let ndb = Ndb::new(&dbpath_str, &config).expect("ndb");
-
- {
- let txn = Transaction::new(&ndb).expect("txn");
- for key in parsed_args.keys {
- info!("adding account: {}", key.pubkey);
- accounts
- .add_account(key)
- .process_action(&mut unknown_ids, &ndb, &txn);
- }
- }
-
- if num_keys != 0 {
- accounts.select_account(0);
- }
-
- // AccountManager will setup the pool on first update
- let pool = RelayPool::new();
-
- let img_cache = ImageCache::new(imgcache_dir);
- let note_cache = NoteCache::default();
- let unknown_ids = UnknownIds::default();
- let egui = ctx.clone();
- let tabs = Tabs::new(None);
- let parsed_args = Args::parse(args);
- let app_rect_handler = AppSizeHandler::new(&path);
-
- Self {
- ndb,
- img_cache,
- app_rect_handler,
- unknown_ids,
- pool,
- note_cache,
- accounts,
- path: path.clone(),
- args: parsed_args,
- theme,
- egui,
- tabs,
- }
- }
-
- pub fn app_context(&mut self) -> AppContext<'_> {
- AppContext {
- ndb: &self.ndb,
- img_cache: &mut self.img_cache,
- unknown_ids: &mut self.unknown_ids,
- pool: &mut self.pool,
- note_cache: &mut self.note_cache,
- accounts: &mut self.accounts,
- path: &self.path,
- args: &self.args,
- theme: &mut self.theme,
- egui: &self.egui,
- }
- }
-
- pub fn add_app<T: notedeck::App + 'static>(&mut self, app: T) {
- self.tabs.app = Some(Rc::new(RefCell::new(app)));
- }
-}
-
// Entry point for wasm
//#[cfg(target_arch = "wasm32")]
//use wasm_bindgen::prelude::*;
diff --git a/crates/notedeck_columns/Cargo.toml b/crates/notedeck_columns/Cargo.toml
@@ -27,7 +27,6 @@ env_logger = { workspace = true }
hex = { workspace = true }
image = { workspace = true }
indexmap = { workspace = true }
-log = { workspace = true }
nostrdb = { workspace = true }
open = { workspace = true }
poll-promise = { workspace = true }
diff --git a/crates/notedeck_columns/src/lib.rs b/crates/notedeck_columns/src/lib.rs
@@ -44,114 +44,4 @@ pub use app::Damus;
pub use error::Error;
pub use profile::DisplayName;
-#[cfg(target_os = "android")]
-use winit::platform::android::EventLoopBuilderExtAndroid;
-
pub type Result<T> = std::result::Result<T, error::Error>;
-
-//#[cfg(target_os = "android")]
-//use egui_android::run_android;
-
-#[cfg(target_os = "android")]
-use winit::platform::android::activity::AndroidApp;
-
-#[cfg(target_os = "android")]
-#[no_mangle]
-#[tokio::main]
-pub async fn android_main(app: AndroidApp) {
- std::env::set_var("RUST_BACKTRACE", "full");
- android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info));
-
- let path = app.internal_data_path().expect("data path");
- let mut options = eframe::NativeOptions::default();
- options.renderer = eframe::Renderer::Wgpu;
- // Clone `app` to use it both in the closure and later in the function
- let app_clone_for_event_loop = app.clone();
- options.event_loop_builder = Some(Box::new(move |builder| {
- builder.with_android_app(app_clone_for_event_loop);
- }));
-
- let app_args = get_app_args(app);
-
- let _res = eframe::run_native(
- "Damus Notedeck",
- options,
- Box::new(move |cc| Ok(Box::new(Damus::new(&cc.egui_ctx, path, app_args)))),
- );
-}
-
-#[cfg(target_os = "android")]
-use serde_json::Value;
-#[cfg(target_os = "android")]
-use std::fs;
-#[cfg(target_os = "android")]
-use std::path::PathBuf;
-
-/*
-Read args from a config file:
-- allows use of more interesting args w/o risk of checking them in by mistake
-- allows use of different args w/o rebuilding the app
-- uses compiled in defaults if config file missing or broken
-
-Example android-config.json:
-```
-{
- "args": [
- "--npub",
- "npub1h50pnxqw9jg7dhr906fvy4mze2yzawf895jhnc3p7qmljdugm6gsrurqev",
- "-c",
- "contacts",
- "-c",
- "notifications"
- ]
-}
-```
-
-Install/update android-config.json with:
-```
-adb push android-config.json /sdcard/Android/data/com.damus.app/files/android-config.json
-```
-
-Using internal storage would be better but it seems hard to get the config file onto
-the device ...
-*/
-
-#[cfg(target_os = "android")]
-fn get_app_args(app: AndroidApp) -> Vec<String> {
- let external_data_path: PathBuf = app
- .external_data_path()
- .expect("external data path")
- .to_path_buf();
- let config_file = external_data_path.join("android-config.json");
-
- let default_args = vec![
- "--pub",
- "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
- "-c",
- "contacts",
- "-c",
- "notifications",
- "-c",
- "notifications:3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681",
- ]
- .into_iter()
- .map(|s| s.to_string())
- .collect();
-
- if config_file.exists() {
- if let Ok(config_contents) = fs::read_to_string(config_file) {
- if let Ok(json) = serde_json::from_str::<Value>(&config_contents) {
- if let Some(args_array) = json.get("args").and_then(|v| v.as_array()) {
- let config_args = args_array
- .iter()
- .filter_map(|v| v.as_str().map(String::from))
- .collect();
-
- return config_args;
- }
- }
- }
- }
-
- default_args // Return the default args if config is missing or invalid
-}