refactor app state
This commit is contained in:
@@ -12,8 +12,8 @@ components = { package = "ui", git = "https://github.com/longbridgeapp/gpui-comp
|
||||
reqwest_client = { git = "https://github.com/huacnlee/zed.git", branch = "export-platform-window" }
|
||||
|
||||
# Nostr
|
||||
nostr-relay-builder = { git = "https://github.com/rust-nostr/nostr" }
|
||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = [
|
||||
nostr-relay-builder = { git = "https://github.com/rust-nostr/nostr", branch = "nip17" }
|
||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", branch = "nip17", features = [
|
||||
"lmdb",
|
||||
"all-nips",
|
||||
] }
|
||||
|
||||
@@ -8,5 +8,3 @@ gpui.workspace = true
|
||||
nostr-sdk.workspace = true
|
||||
dirs.workspace = true
|
||||
tokio.workspace = true
|
||||
keyring-search.workspace = true
|
||||
keyring.workspace = true
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use gpui::Global;
|
||||
use keyring::Entry;
|
||||
use nostr_sdk::prelude::*;
|
||||
use state::get_client;
|
||||
|
||||
@@ -18,15 +17,4 @@ impl NostrClient {
|
||||
|
||||
Self { client }
|
||||
}
|
||||
|
||||
pub fn add_account(&self, keys: Keys) -> Result<()> {
|
||||
let public_key = keys.public_key().to_bech32()?;
|
||||
let secret = keys.secret_key().to_secret_hex();
|
||||
let entry = Entry::new("Coop Safe Storage", &public_key)?;
|
||||
|
||||
// Add secret to keyring
|
||||
entry.set_password(&secret)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use dirs::config_dir;
|
||||
use nostr_sdk::prelude::*;
|
||||
use std::fs;
|
||||
use std::{fs, time::Duration};
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
pub static CLIENT: OnceCell<Client> = OnceCell::const_new();
|
||||
@@ -17,15 +17,17 @@ pub async fn get_client() -> &'static Client {
|
||||
.expect("Database is NOT initialized");
|
||||
|
||||
// Setup Nostr Client
|
||||
let client = ClientBuilder::default().database(lmdb).build();
|
||||
let opts = Options::new().gossip(true).timeout(Duration::from_secs(5));
|
||||
let client = ClientBuilder::default().database(lmdb).opts(opts).build();
|
||||
|
||||
// Add some bootstrap relays
|
||||
let _ = client.add_relay("wss://relay.damus.io").await;
|
||||
let _ = client.add_relay("wss://relay.primal.net").await;
|
||||
let _ = client.add_relay("wss://nostr.fmt.wiz.biz").await;
|
||||
let _ = client.add_relay("wss://directory.yabu.me").await;
|
||||
let _ = client.add_relay("wss://purplepag.es").await;
|
||||
let _ = client.add_relay("wss://user.kindpag.es/").await;
|
||||
|
||||
let _ = client.add_discovery_relay("wss://user.kindpag.es/").await;
|
||||
let _ = client.add_discovery_relay("wss://purplepag.es").await;
|
||||
|
||||
// Connect to all relays
|
||||
client.connect().await;
|
||||
|
||||
@@ -22,4 +22,4 @@ reqwest_client.workspace = true
|
||||
|
||||
client = { version = "0.1.0", path = "../client" }
|
||||
rust-embed = "8.5.0"
|
||||
env_logger = "0.11.5"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["fmt"] }
|
||||
|
||||
@@ -15,11 +15,11 @@ actions!(main_menu, [Quit]);
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Initialize nostr client
|
||||
let nostr = NostrClient::init().await;
|
||||
// Initializ app state
|
||||
// Initialize app state
|
||||
let app_state = AppState::new();
|
||||
|
||||
App::new()
|
||||
@@ -31,9 +31,8 @@ async fn main() {
|
||||
|
||||
// Set custom theme
|
||||
let mut theme = Theme::from(ThemeColor::dark());
|
||||
// TODO: support light mode
|
||||
// Set dark mode by default
|
||||
theme.mode = ThemeMode::Dark;
|
||||
// TODO: adjust color set
|
||||
|
||||
// Set app state
|
||||
cx.set_global(theme);
|
||||
@@ -43,7 +42,7 @@ async fn main() {
|
||||
// Set quit action
|
||||
cx.on_action(quit);
|
||||
|
||||
// Rerender
|
||||
// Refresh
|
||||
cx.refresh();
|
||||
|
||||
// Set window size
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use gpui::Global;
|
||||
use nostr_sdk::prelude::*;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::utils::get_all_accounts_from_keyring;
|
||||
|
||||
pub struct AppState {
|
||||
pub accounts: HashSet<PublicKey>,
|
||||
pub signer: Option<PublicKey>,
|
||||
}
|
||||
|
||||
impl Global for AppState {}
|
||||
|
||||
impl AppState {
|
||||
pub fn new() -> Self {
|
||||
let accounts = get_all_accounts_from_keyring();
|
||||
Self { accounts }
|
||||
Self { signer: None }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use keyring_search::{Limit, List, Search};
|
||||
use nostr_sdk::prelude::*;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn get_all_accounts_from_keyring() -> HashSet<PublicKey> {
|
||||
pub fn get_all_accounts_from_keyring() -> Vec<PublicKey> {
|
||||
let search = Search::new().expect("Keyring not working.");
|
||||
let results = search.by_service("Coop Safe Storage");
|
||||
let list = List::list_credentials(&results, Limit::All);
|
||||
let accounts: HashSet<PublicKey> = list
|
||||
let accounts: Vec<PublicKey> = list
|
||||
.split_whitespace()
|
||||
.filter(|v| v.starts_with("npub1") && !v.ends_with("coop"))
|
||||
.filter_map(|i| PublicKey::from_bech32(i).ok())
|
||||
|
||||
@@ -11,9 +11,9 @@ pub struct AppView {
|
||||
|
||||
impl AppView {
|
||||
pub fn new(cx: &mut ViewContext<'_, Self>) -> AppView {
|
||||
// Onboarding model
|
||||
// Onboarding
|
||||
let onboarding = cx.new_view(Onboarding::new);
|
||||
// Chat Space view
|
||||
// Chat Space
|
||||
let chat_space = cx.new_view(ChatSpace::new);
|
||||
|
||||
AppView {
|
||||
@@ -27,7 +27,7 @@ impl Render for AppView {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let mut content = div().size_full().flex().items_center().justify_center();
|
||||
|
||||
if cx.global::<AppState>().accounts.is_empty() {
|
||||
if cx.global::<AppState>().signer.is_none() {
|
||||
content = content.child(self.onboarding.clone())
|
||||
} else {
|
||||
content = content.child(self.chat_space.clone())
|
||||
|
||||
@@ -74,27 +74,11 @@ impl RenderOnce for Account {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BottomBar {
|
||||
accounts: Vec<Account>,
|
||||
}
|
||||
pub struct BottomBar {}
|
||||
|
||||
impl BottomBar {
|
||||
pub fn new(cx: &mut ViewContext<'_, Self>) -> BottomBar {
|
||||
let state: Vec<PublicKey> = cx
|
||||
.global::<AppState>()
|
||||
.accounts
|
||||
.clone()
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let win_cx = cx.window_context();
|
||||
|
||||
let accounts = state
|
||||
.into_iter()
|
||||
.map(|pk| Account::new(pk, win_cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
BottomBar { accounts }
|
||||
BottomBar {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +92,5 @@ impl Render for BottomBar {
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.gap_1()
|
||||
.children(self.accounts.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ pub struct ChatSpace {
|
||||
impl ChatSpace {
|
||||
pub fn new(cx: &mut ViewContext<'_, Self>) -> Self {
|
||||
let navigation = cx.new_view(Navigation::new);
|
||||
let bottom_bar = cx.new_view(BottomBar::new);
|
||||
|
||||
let layout = cx.new_view(|cx| {
|
||||
h_resizable(cx)
|
||||
@@ -28,7 +27,6 @@ impl ChatSpace {
|
||||
.flex()
|
||||
.flex_col()
|
||||
.child(navigation.clone())
|
||||
.child(bottom_bar.clone())
|
||||
.into_any_element()
|
||||
}),
|
||||
cx,
|
||||
|
||||
@@ -4,6 +4,7 @@ use components::{
|
||||
label::Label,
|
||||
};
|
||||
use gpui::*;
|
||||
use keyring::Entry;
|
||||
use nostr_sdk::prelude::*;
|
||||
|
||||
use crate::state::AppState;
|
||||
@@ -21,17 +22,37 @@ impl Onboarding {
|
||||
});
|
||||
|
||||
cx.subscribe(&input, move |_, text_input, input_event, cx| {
|
||||
let mut async_cx = cx.to_async();
|
||||
let client = cx.global::<NostrClient>().client;
|
||||
let view_id = cx.parent_view_id();
|
||||
|
||||
if let InputEvent::PressEnter = input_event {
|
||||
let content = text_input.read(cx).text().to_string();
|
||||
|
||||
if let Ok(keys) = Keys::parse(content) {
|
||||
let public_key = keys.public_key();
|
||||
cx.foreground_executor()
|
||||
.spawn(async move {
|
||||
let public_key = keys.public_key();
|
||||
let secret = keys.secret_key().to_secret_hex();
|
||||
|
||||
if cx.global::<NostrClient>().add_account(keys).is_ok() {
|
||||
cx.global_mut::<AppState>().accounts.insert(public_key);
|
||||
cx.notify();
|
||||
}
|
||||
};
|
||||
let entry =
|
||||
Entry::new("Coop Safe Storage", &public_key.to_bech32().unwrap())
|
||||
.unwrap();
|
||||
|
||||
// Store private key to OS Keyring
|
||||
let _ = entry.set_password(&secret);
|
||||
|
||||
// Update signer
|
||||
client.set_signer(keys).await;
|
||||
|
||||
// Update view
|
||||
async_cx.update_global(|app_state: &mut AppState, cx| {
|
||||
app_state.signer = Some(public_key);
|
||||
cx.notify(view_id);
|
||||
})
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
Reference in New Issue
Block a user