mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-20 09:54:19 +01:00
android: fix issues due to rearchitecture
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -2526,6 +2526,7 @@ dependencies = [
|
|||||||
"egui",
|
"egui",
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
"enostr",
|
"enostr",
|
||||||
|
"log",
|
||||||
"nostrdb",
|
"nostrdb",
|
||||||
"notedeck",
|
"notedeck",
|
||||||
"notedeck_columns",
|
"notedeck_columns",
|
||||||
@@ -2557,7 +2558,6 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"image",
|
"image",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"log",
|
|
||||||
"nostrdb",
|
"nostrdb",
|
||||||
"notedeck",
|
"notedeck",
|
||||||
"open",
|
"open",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ profiling = ["notedeck_columns/puffin"]
|
|||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies]
|
[target.'cfg(target_os = "android")'.dependencies]
|
||||||
android_logger = "0.11.1"
|
android_logger = "0.11.1"
|
||||||
|
log = { workspace = true }
|
||||||
android-activity = { version = "0.4", features = [ "native-activity" ] }
|
android-activity = { version = "0.4", features = [ "native-activity" ] }
|
||||||
winit = { version = "0.30.5", features = [ "android-native-activity" ] }
|
winit = { version = "0.30.5", features = [ "android-native-activity" ] }
|
||||||
|
|
||||||
|
|||||||
102
crates/notedeck_chrome/src/android.rs
Normal file
102
crates/notedeck_chrome/src/android.rs
Normal file
@@ -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
|
||||||
|
}
|
||||||
191
crates/notedeck_chrome/src/app.rs
Normal file
191
crates/notedeck_chrome/src/app.rs
Normal file
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,3 +2,10 @@ pub mod app_size;
|
|||||||
pub mod fonts;
|
pub mod fonts;
|
||||||
pub mod setup;
|
pub mod setup;
|
||||||
pub mod theme;
|
pub mod theme;
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
|
||||||
|
pub use app::Notedeck;
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
mod android;
|
||||||
|
|||||||
@@ -1,204 +1,12 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
use notedeck_chrome::{
|
use notedeck_chrome::{setup::generate_native_options, Notedeck};
|
||||||
app_size::AppSizeHandler,
|
|
||||||
setup::{generate_native_options, setup_cc},
|
|
||||||
theme,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
use notedeck::{DataPath, DataPathType};
|
||||||
use notedeck_columns::Damus;
|
use notedeck_columns::Damus;
|
||||||
|
use std::path::PathBuf;
|
||||||
use notedeck::{
|
use std::str::FromStr;
|
||||||
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 tracing_subscriber::EnvFilter;
|
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
|
// Entry point for wasm
|
||||||
//#[cfg(target_arch = "wasm32")]
|
//#[cfg(target_arch = "wasm32")]
|
||||||
//use wasm_bindgen::prelude::*;
|
//use wasm_bindgen::prelude::*;
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ env_logger = { workspace = true }
|
|||||||
hex = { workspace = true }
|
hex = { workspace = true }
|
||||||
image = { workspace = true }
|
image = { workspace = true }
|
||||||
indexmap = { workspace = true }
|
indexmap = { workspace = true }
|
||||||
log = { workspace = true }
|
|
||||||
nostrdb = { workspace = true }
|
nostrdb = { workspace = true }
|
||||||
open = { workspace = true }
|
open = { workspace = true }
|
||||||
poll-promise = { workspace = true }
|
poll-promise = { workspace = true }
|
||||||
|
|||||||
@@ -44,114 +44,4 @@ pub use app::Damus;
|
|||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use profile::DisplayName;
|
pub use profile::DisplayName;
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use winit::platform::android::EventLoopBuilderExtAndroid;
|
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, error::Error>;
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user