192 lines
6.2 KiB
Rust
192 lines
6.2 KiB
Rust
//! Menu actions and app state for sovereign_browser
|
|
//!
|
|
//! Port of the menu proxy functions from `main.c` in the C project.
|
|
//! These are called from the hamburger menu in `tab_manager.rs`.
|
|
//!
|
|
//! This module also owns the app state (signer, pubkey, method) so that
|
|
//! both the binary (`main.rs`) and the library modules (`tab_manager.rs`,
|
|
//! `menu.rs`) can share it without cross-crate-root references.
|
|
|
|
use gtk::prelude::*;
|
|
use nostr_signer::traits::NostrSigner;
|
|
use std::sync::Arc;
|
|
use std::sync::Mutex;
|
|
use once_cell::sync::Lazy;
|
|
|
|
use crate::key_store;
|
|
use crate::login_dialog;
|
|
use crate::nostr_bridge;
|
|
use crate::tab_manager;
|
|
|
|
/// App state (signer, identity, method).
|
|
pub struct AppState {
|
|
pub signer: Option<Arc<dyn NostrSigner>>,
|
|
pub pubkey_hex: String,
|
|
pub privkey_hex: String,
|
|
pub method: key_store::KeyStoreMethod,
|
|
pub readonly: bool,
|
|
}
|
|
|
|
impl Default for AppState {
|
|
fn default() -> Self {
|
|
AppState {
|
|
signer: None,
|
|
pubkey_hex: String::new(),
|
|
privkey_hex: String::new(),
|
|
method: key_store::KeyStoreMethod::None,
|
|
readonly: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Global app state.
|
|
static G_STATE: Lazy<Mutex<AppState>> = Lazy::new(|| Mutex::new(AppState::default()));
|
|
|
|
/// Set the signer and update dependent modules.
|
|
pub fn app_set_signer(
|
|
signer: Option<Arc<dyn NostrSigner>>,
|
|
pubkey_hex: &str,
|
|
privkey_hex: &str,
|
|
method: key_store::KeyStoreMethod,
|
|
readonly: bool,
|
|
) {
|
|
let mut state = G_STATE.lock().unwrap();
|
|
state.signer = signer;
|
|
state.pubkey_hex = pubkey_hex.to_string();
|
|
state.privkey_hex = privkey_hex.to_string();
|
|
state.method = method;
|
|
state.readonly = readonly;
|
|
|
|
nostr_bridge::nostr_bridge_set_signer(state.signer.clone(), &state.pubkey_hex, state.readonly);
|
|
crate::agent_login::agent_login_set_signer(state.signer.clone(), &state.pubkey_hex);
|
|
crate::settings_sync::settings_sync_init(state.signer.clone(), &state.pubkey_hex);
|
|
crate::agent_conversations::agent_conversations_init(state.signer.clone(), &state.pubkey_hex);
|
|
crate::agent_skills::agent_skills_init(state.signer.clone(), &state.pubkey_hex);
|
|
}
|
|
|
|
/// Clear the signer and reset app state (used by logout / lock session).
|
|
pub fn app_clear_signer() {
|
|
let mut state = G_STATE.lock().unwrap();
|
|
state.signer = None;
|
|
state.pubkey_hex.clear();
|
|
state.privkey_hex.clear();
|
|
state.method = key_store::KeyStoreMethod::None;
|
|
state.readonly = true;
|
|
nostr_bridge::nostr_bridge_set_signer(None, "", true);
|
|
}
|
|
|
|
/// Get the current pubkey.
|
|
pub fn app_get_pubkey_hex() -> String {
|
|
let state = G_STATE.lock().unwrap();
|
|
state.pubkey_hex.clone()
|
|
}
|
|
|
|
/// Get the current signer.
|
|
pub fn app_get_signer() -> Option<Arc<dyn NostrSigner>> {
|
|
let state = G_STATE.lock().unwrap();
|
|
state.signer.clone()
|
|
}
|
|
|
|
/// Get the current method.
|
|
pub fn app_get_method() -> key_store::KeyStoreMethod {
|
|
let state = G_STATE.lock().unwrap();
|
|
state.method
|
|
}
|
|
|
|
/// Get whether the session is read-only.
|
|
pub fn app_get_readonly() -> bool {
|
|
let state = G_STATE.lock().unwrap();
|
|
state.readonly
|
|
}
|
|
|
|
/// Run the login dialog and install the resulting identity.
|
|
/// Switch to the per-user profile database.
|
|
pub fn switch_to_user_db(pubkey_hex: &str) -> i32 {
|
|
match crate::db::db_init(pubkey_hex) {
|
|
Ok(_) => {
|
|
println!("[db] Switched to profile database for {}", pubkey_hex);
|
|
0
|
|
}
|
|
Err(e) => {
|
|
eprintln!("[db] Failed to open database: {}", e);
|
|
-1
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Run the login dialog and install the resulting identity.
|
|
fn do_login(parent: >k::Window) -> bool {
|
|
let result = login_dialog::login_dialog_run(parent);
|
|
match result {
|
|
Some(login_result) => {
|
|
let pubkey_hex = login_result.pubkey_hex.clone();
|
|
let privkey_hex = login_result.identity.privkey_hex.clone();
|
|
let method = login_result.method;
|
|
let readonly = login_result.signer.is_none();
|
|
|
|
if login_result.no_login || pubkey_hex.is_empty() {
|
|
println!("[login] No-login mode (browsing without Nostr identity)");
|
|
app_set_signer(None, "", "", key_store::KeyStoreMethod::None, true);
|
|
crate::settings::settings_load();
|
|
crate::shortcuts::shortcuts_load();
|
|
return true;
|
|
}
|
|
|
|
if switch_to_user_db(&pubkey_hex) != 0 {
|
|
return false;
|
|
}
|
|
|
|
println!(
|
|
"[login] signed in via {} as {}{}",
|
|
method.as_str(),
|
|
pubkey_hex,
|
|
if readonly { " (read-only)" } else { "" }
|
|
);
|
|
app_set_signer(login_result.signer, &pubkey_hex, &privkey_hex, method, readonly);
|
|
|
|
// Refresh the tab-bar avatar (the kind 0 profile may now be in
|
|
// the per-user database).
|
|
crate::tab_manager::tab_manager_set_avatar(Some(&pubkey_hex));
|
|
let _ = key_store::key_store_save_profile_identity(&pubkey_hex, method);
|
|
crate::settings::settings_load();
|
|
crate::shortcuts::shortcuts_load();
|
|
|
|
let pubkey = pubkey_hex.clone();
|
|
std::thread::spawn(move || {
|
|
crate::relay_fetch::relay_fetch_thread(pubkey);
|
|
});
|
|
|
|
true
|
|
}
|
|
None => false,
|
|
}
|
|
}
|
|
|
|
/// Menu action: switch identity (re-show the login dialog).
|
|
pub fn menu_switch_identity() {
|
|
if let Some(nb) = tab_manager::tab_manager_get_main_notebook() {
|
|
if let Some(win) = nb.toplevel().and_then(|w| w.downcast::<gtk::Window>().ok()) {
|
|
if do_login(&win) {
|
|
println!("[identity] switched identity");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Menu action: logout (clear signer, re-show login).
|
|
pub fn menu_logout() {
|
|
app_clear_signer();
|
|
println!("[identity] logged out");
|
|
if let Some(nb) = tab_manager::tab_manager_get_main_notebook() {
|
|
if let Some(win) = nb.toplevel().and_then(|w| w.downcast::<gtk::Window>().ok()) {
|
|
do_login(&win);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Menu action: lock session (clear signer, keep identity).
|
|
pub fn menu_lock_session() {
|
|
app_clear_signer();
|
|
println!("[identity] session locked (signer cleared, identity preserved)");
|
|
}
|