chore: restructure and refine the ui (#199)
* update deps * clean up * add account crate * add person crate * add chat and chat ui crates * . * clean up the ui crate * . * .
This commit is contained in:
@@ -34,9 +34,12 @@ theme = { path = "../theme" }
|
||||
common = { path = "../common" }
|
||||
states = { path = "../states" }
|
||||
key_store = { path = "../key_store" }
|
||||
registry = { path = "../registry" }
|
||||
chat = { path = "../chat" }
|
||||
chat_ui = { path = "../chat_ui" }
|
||||
settings = { path = "../settings" }
|
||||
auto_update = { path = "../auto_update" }
|
||||
account = { path = "../account" }
|
||||
person = { path = "../person" }
|
||||
|
||||
rust-i18n.workspace = true
|
||||
i18n.workspace = true
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
use gpui::{actions, App, AppContext};
|
||||
use gpui::{actions, App};
|
||||
use key_store::backend::KeyItem;
|
||||
use key_store::KeyStore;
|
||||
use nostr_connect::prelude::*;
|
||||
use registry::Registry;
|
||||
use states::app_state;
|
||||
|
||||
actions!(coop, [ReloadMetadata, DarkMode, Settings, Logout, Quit]);
|
||||
@@ -48,31 +47,30 @@ pub fn load_embedded_fonts(cx: &App) {
|
||||
}
|
||||
|
||||
pub fn reset(cx: &mut App) {
|
||||
let registry = Registry::global(cx);
|
||||
let backend = KeyStore::global(cx).read(cx).backend();
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
cx.background_spawn(async move {
|
||||
let client = app_state().client();
|
||||
client.unset_signer().await;
|
||||
})
|
||||
.await;
|
||||
let client = app_state().client();
|
||||
|
||||
// Remove the signer
|
||||
client.unset_signer().await;
|
||||
|
||||
// Delete user's credentials
|
||||
backend
|
||||
.delete_credentials(&KeyItem::User.to_string(), cx)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
// Remove bunker's credentials if available
|
||||
backend
|
||||
.delete_credentials(&KeyItem::Bunker.to_string(), cx)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
registry
|
||||
.update(cx, |this, cx| {
|
||||
this.reset(cx);
|
||||
})
|
||||
.ok();
|
||||
cx.update(|cx| {
|
||||
cx.restart();
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@ use std::borrow::Cow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
use account::Account;
|
||||
use anyhow::{anyhow, Error};
|
||||
use auto_update::AutoUpdater;
|
||||
use chat::{ChatEvent, ChatRegistry};
|
||||
use chat_ui::{CopyPublicKey, OpenPublicKey};
|
||||
use common::display::{shorten_pubkey, RenderedProfile};
|
||||
use common::event::EventUtils;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
@@ -18,7 +21,7 @@ use key_store::backend::KeyItem;
|
||||
use key_store::KeyStore;
|
||||
use nostr_connect::prelude::*;
|
||||
use nostr_sdk::prelude::*;
|
||||
use registry::{Registry, RegistryEvent};
|
||||
use person::PersonRegistry;
|
||||
use settings::AppSettings;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use states::{
|
||||
@@ -27,7 +30,6 @@ use states::{
|
||||
};
|
||||
use theme::{ActiveTheme, Theme, ThemeMode};
|
||||
use title_bar::TitleBar;
|
||||
use ui::actions::{CopyPublicKey, OpenPublicKey};
|
||||
use ui::avatar::Avatar;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::dock_area::dock::DockPlacement;
|
||||
@@ -42,7 +44,8 @@ use crate::actions::{reset, DarkMode, Logout, ReloadMetadata, Settings};
|
||||
use crate::views::compose::compose_button;
|
||||
use crate::views::setup_relay::SetupRelay;
|
||||
use crate::views::{
|
||||
account, chat, login, new_account, onboarding, preferences, sidebar, user_profile, welcome,
|
||||
account as account_view, login, new_account, onboarding, preferences, sidebar, user_profile,
|
||||
welcome,
|
||||
};
|
||||
|
||||
pub fn init(window: &mut Window, cx: &mut App) -> Entity<ChatSpace> {
|
||||
@@ -59,6 +62,7 @@ pub fn new_account(window: &mut Window, cx: &mut App) {
|
||||
ChatSpace::set_center_panel(panel, window, cx);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChatSpace {
|
||||
/// App's Title Bar
|
||||
title_bar: Entity<TitleBar>,
|
||||
@@ -84,7 +88,7 @@ pub struct ChatSpace {
|
||||
|
||||
impl ChatSpace {
|
||||
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let registry = Registry::global(cx);
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let keystore = KeyStore::global(cx);
|
||||
|
||||
let title_bar = cx.new(|_| TitleBar::new());
|
||||
@@ -102,55 +106,49 @@ impl ChatSpace {
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
// Observe device changes
|
||||
cx.observe_in(&keystore, window, move |this, state, window, cx| {
|
||||
// Observe keystore changes
|
||||
cx.observe_in(&keystore, window, move |_this, state, window, cx| {
|
||||
if state.read(cx).initialized {
|
||||
let backend = state.read(cx).backend();
|
||||
|
||||
if state.read(cx).initialized {
|
||||
if state.read(cx).is_using_file_keystore() {
|
||||
this.render_keyring_installation(window, cx);
|
||||
}
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let result = backend
|
||||
.read_credentials(&KeyItem::User.to_string(), cx)
|
||||
.await;
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let result = backend
|
||||
.read_credentials(&KeyItem::User.to_string(), cx)
|
||||
.await;
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
match result {
|
||||
Ok(Some((user, secret))) => {
|
||||
let public_key = PublicKey::parse(&user).unwrap();
|
||||
let secret = String::from_utf8(secret).unwrap();
|
||||
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
match result {
|
||||
Ok(Some((user, secret))) => {
|
||||
let public_key = PublicKey::parse(&user).unwrap();
|
||||
let secret = String::from_utf8(secret).unwrap();
|
||||
|
||||
this.set_account_layout(public_key, secret, window, cx);
|
||||
}
|
||||
_ => {
|
||||
this.set_onboarding_layout(window, cx);
|
||||
}
|
||||
};
|
||||
})
|
||||
.ok();
|
||||
this.set_account_layout(public_key, secret, window, cx);
|
||||
}
|
||||
_ => {
|
||||
this.set_onboarding_layout(window, cx);
|
||||
}
|
||||
};
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
// Handle registry events
|
||||
cx.subscribe_in(®istry, window, move |this, _, ev, window, cx| {
|
||||
cx.subscribe_in(&chat, window, move |this, chat, ev, window, cx| {
|
||||
match ev {
|
||||
RegistryEvent::Open(room) => {
|
||||
if let Some(room) = room.upgrade() {
|
||||
ChatEvent::OpenRoom(id) => {
|
||||
if let Some(room) = chat.read(cx).room(id, cx) {
|
||||
this.dock.update(cx, |this, cx| {
|
||||
let panel = chat::init(room, window, cx);
|
||||
let panel = chat_ui::init(room, window, cx);
|
||||
this.add_panel(Arc::new(panel), DockPlacement::Center, window, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
RegistryEvent::Close(..) => {
|
||||
ChatEvent::CloseRoom(..) => {
|
||||
this.dock.update(cx, |this, cx| {
|
||||
this.focus_tab_panel(window, cx);
|
||||
|
||||
@@ -217,7 +215,8 @@ impl ChatSpace {
|
||||
|
||||
while let Ok(signal) = states.signal().receiver().recv_async().await {
|
||||
view.update_in(cx, |this, window, cx| {
|
||||
let registry = Registry::global(cx);
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let settings = AppSettings::global(cx);
|
||||
|
||||
match signal {
|
||||
@@ -234,8 +233,8 @@ impl ChatSpace {
|
||||
this.receive_encryption(response, window, cx);
|
||||
}
|
||||
SignalKind::SignerSet(public_key) => {
|
||||
// Close all opened modals
|
||||
window.close_all_modals(cx);
|
||||
// Set the global account state
|
||||
account::init(public_key, cx);
|
||||
|
||||
// Load user's settings
|
||||
settings.update(cx, |this, cx| {
|
||||
@@ -243,11 +242,13 @@ impl ChatSpace {
|
||||
});
|
||||
|
||||
// Load all chat rooms
|
||||
registry.update(cx, |this, cx| {
|
||||
this.set_signer_pubkey(public_key, cx);
|
||||
chat.update(cx, |this, cx| {
|
||||
this.load_rooms(window, cx);
|
||||
});
|
||||
|
||||
// Close all opened modals
|
||||
window.close_all_modals(cx);
|
||||
|
||||
// Setup the default layout for current workspace
|
||||
this.set_default_layout(window, cx);
|
||||
}
|
||||
@@ -271,7 +272,7 @@ impl ChatSpace {
|
||||
if matches!(s, UnwrappingStatus::Processing | UnwrappingStatus::Complete) {
|
||||
let all_panels = this.get_all_panel_ids(cx);
|
||||
|
||||
registry.update(cx, |this, cx| {
|
||||
chat.update(cx, |this, cx| {
|
||||
this.load_rooms(window, cx);
|
||||
this.refresh_rooms(all_panels, cx);
|
||||
|
||||
@@ -282,13 +283,13 @@ impl ChatSpace {
|
||||
}
|
||||
}
|
||||
SignalKind::NewProfile(profile) => {
|
||||
registry.update(cx, |this, cx| {
|
||||
persons.update(cx, |this, cx| {
|
||||
this.insert_or_update_person(profile, cx);
|
||||
});
|
||||
}
|
||||
SignalKind::NewMessage((gift_wrap_id, event)) => {
|
||||
registry.update(cx, |this, cx| {
|
||||
this.event_to_message(gift_wrap_id, event, window, cx);
|
||||
SignalKind::NewMessage(msg) => {
|
||||
chat.update(cx, |this, cx| {
|
||||
this.new_message(msg, window, cx);
|
||||
});
|
||||
}
|
||||
SignalKind::GossipRelaysNotFound => {
|
||||
@@ -621,7 +622,7 @@ impl ChatSpace {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let panel = Arc::new(account::init(public_key, secret, window, cx));
|
||||
let panel = Arc::new(account_view::init(public_key, secret, window, cx));
|
||||
let center = DockItem::panel(panel);
|
||||
|
||||
self.dock.update(cx, |this, cx| {
|
||||
@@ -785,32 +786,6 @@ impl ChatSpace {
|
||||
}
|
||||
}
|
||||
|
||||
fn render_keyring_installation(&mut self, window: &mut Window, cx: &mut App) {
|
||||
window.open_modal(cx, move |this, _window, cx| {
|
||||
this.overlay_closable(false)
|
||||
.show_close(false)
|
||||
.keyboard(false)
|
||||
.alert()
|
||||
.button_props(ModalButtonProps::default().ok_text(t!("common.continue")))
|
||||
.title(shared_t!("keyring_disable.label"))
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_2()
|
||||
.text_sm()
|
||||
.child(shared_t!("keyring_disable.body_1"))
|
||||
.child(shared_t!("keyring_disable.body_2"))
|
||||
.child(shared_t!("keyring_disable.body_3"))
|
||||
.child(shared_t!("keyring_disable.body_4"))
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().danger_foreground)
|
||||
.child(shared_t!("keyring_disable.body_5")),
|
||||
),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn render_request(&mut self, ann: Announcement, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let client_name = SharedString::from(ann.client().to_string());
|
||||
let target = ann.public_key();
|
||||
@@ -907,8 +882,25 @@ impl ChatSpace {
|
||||
),
|
||||
)
|
||||
.on_cancel(move |_ev, window, cx| {
|
||||
_ = view.update(cx, |this, cx| {
|
||||
this.render_reset(window, cx);
|
||||
_ = view.update(cx, |_, cx| {
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let state = app_state();
|
||||
let result = state.init_encryption_keys().await;
|
||||
|
||||
this.update_in(cx, |_, window, cx| {
|
||||
match result {
|
||||
Ok(_) => {
|
||||
window.push_notification(t!("encryption.success"), cx);
|
||||
window.close_all_modals(cx);
|
||||
}
|
||||
Err(e) => {
|
||||
window.push_notification(e.to_string(), cx);
|
||||
}
|
||||
};
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
});
|
||||
// false to keep modal open
|
||||
false
|
||||
@@ -916,27 +908,6 @@ impl ChatSpace {
|
||||
});
|
||||
}
|
||||
|
||||
fn render_reset(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let state = app_state();
|
||||
let result = state.init_encryption_keys().await;
|
||||
|
||||
this.update_in(cx, |_, window, cx| {
|
||||
match result {
|
||||
Ok(_) => {
|
||||
window.push_notification(t!("encryption.success"), cx);
|
||||
window.close_all_modals(cx);
|
||||
}
|
||||
Err(e) => {
|
||||
window.push_notification(e.to_string(), cx);
|
||||
}
|
||||
};
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn render_setup_gossip_relays_modal(&mut self, window: &mut Window, cx: &mut App) {
|
||||
let relays = default_nip65_relays();
|
||||
|
||||
@@ -1139,13 +1110,39 @@ impl ChatSpace {
|
||||
})
|
||||
}
|
||||
|
||||
fn render_titlebar_left_side(
|
||||
&mut self,
|
||||
_window: &mut Window,
|
||||
cx: &Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let registry = Registry::global(cx);
|
||||
let status = registry.read(cx).loading;
|
||||
fn render_keyring_warning(window: &mut Window, cx: &mut App) {
|
||||
window.open_modal(cx, move |this, _window, cx| {
|
||||
this.overlay_closable(false)
|
||||
.show_close(false)
|
||||
.keyboard(false)
|
||||
.alert()
|
||||
.button_props(ModalButtonProps::default().ok_text(t!("common.continue")))
|
||||
.title(shared_t!("keyring_disable.label"))
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_2()
|
||||
.text_sm()
|
||||
.child(shared_t!("keyring_disable.body_1"))
|
||||
.child(shared_t!("keyring_disable.body_2"))
|
||||
.child(shared_t!("keyring_disable.body_3"))
|
||||
.child(shared_t!("keyring_disable.body_4"))
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().danger_foreground)
|
||||
.child(shared_t!("keyring_disable.body_5")),
|
||||
),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn titlebar_left(&mut self, _window: &mut Window, cx: &Context<Self>) -> impl IntoElement {
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let status = chat.read(cx).loading;
|
||||
|
||||
if !Account::has_global(cx) {
|
||||
return div();
|
||||
}
|
||||
|
||||
h_flex()
|
||||
.gap_2()
|
||||
@@ -1166,12 +1163,8 @@ impl ChatSpace {
|
||||
})
|
||||
}
|
||||
|
||||
fn render_titlebar_right_side(
|
||||
&mut self,
|
||||
profile: &Profile,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
fn titlebar_right(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let file_keystore = KeyStore::global(cx).read(cx).is_using_file_keystore();
|
||||
let proxy = AppSettings::get_proxy_user_avatars(cx);
|
||||
let updating = AutoUpdater::read_global(cx).status.is_updating();
|
||||
let updated = AutoUpdater::read_global(cx).status.is_updated();
|
||||
@@ -1179,6 +1172,19 @@ impl ChatSpace {
|
||||
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.when(file_keystore, |this| {
|
||||
this.child(
|
||||
Button::new("keystore-warning")
|
||||
.icon(IconName::Warning)
|
||||
.label("Keyring Disabled")
|
||||
.ghost()
|
||||
.xsmall()
|
||||
.rounded()
|
||||
.on_click(move |_ev, window, cx| {
|
||||
Self::render_keyring_warning(window, cx);
|
||||
}),
|
||||
)
|
||||
})
|
||||
.when(updating, |this| {
|
||||
this.child(
|
||||
h_flex()
|
||||
@@ -1236,7 +1242,7 @@ impl ChatSpace {
|
||||
Button::new("setup-relays-button")
|
||||
.icon(IconName::Info)
|
||||
.label(t!("messaging.button"))
|
||||
.warning()
|
||||
.ghost()
|
||||
.xsmall()
|
||||
.rounded()
|
||||
.on_click(move |_ev, window, cx| {
|
||||
@@ -1244,22 +1250,29 @@ impl ChatSpace {
|
||||
}),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
Button::new("user")
|
||||
.small()
|
||||
.reverse()
|
||||
.transparent()
|
||||
.icon(IconName::CaretDown)
|
||||
.child(Avatar::new(profile.avatar(proxy)).size(rems(1.49)))
|
||||
.popup_menu(|this, _window, _cx| {
|
||||
this.menu(t!("user.dark_mode"), Box::new(DarkMode))
|
||||
.menu(t!("user.settings"), Box::new(Settings))
|
||||
.separator()
|
||||
.menu(t!("user.reload_metadata"), Box::new(ReloadMetadata))
|
||||
.separator()
|
||||
.menu(t!("user.sign_out"), Box::new(Logout))
|
||||
}),
|
||||
)
|
||||
.when(Account::has_global(cx), |this| {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let account = Account::global(cx);
|
||||
let public_key = account.read(cx).public_key();
|
||||
let profile = persons.read(cx).get_person(&public_key, cx);
|
||||
|
||||
this.child(
|
||||
Button::new("user")
|
||||
.small()
|
||||
.reverse()
|
||||
.transparent()
|
||||
.icon(IconName::CaretDown)
|
||||
.child(Avatar::new(profile.avatar(proxy)).size(rems(1.49)))
|
||||
.popup_menu(|this, _window, _cx| {
|
||||
this.menu(t!("user.dark_mode"), Box::new(DarkMode))
|
||||
.menu(t!("user.settings"), Box::new(Settings))
|
||||
.separator()
|
||||
.menu(t!("user.reload_metadata"), Box::new(ReloadMetadata))
|
||||
.separator()
|
||||
.menu(t!("user.sign_out"), Box::new(Logout))
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1267,24 +1280,14 @@ impl Render for ChatSpace {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let modal_layer = Root::render_modal_layer(window, cx);
|
||||
let notification_layer = Root::render_notification_layer(window, cx);
|
||||
let registry = Registry::read_global(cx);
|
||||
|
||||
// Only render titlebar child elements if user is logged in
|
||||
if let Some(public_key) = registry.signer_pubkey() {
|
||||
let profile = registry.get_person(&public_key, cx);
|
||||
let left = self.titlebar_left(window, cx).into_any_element();
|
||||
let right = self.titlebar_right(window, cx).into_any_element();
|
||||
|
||||
let left_side = self
|
||||
.render_titlebar_left_side(window, cx)
|
||||
.into_any_element();
|
||||
|
||||
let right_side = self
|
||||
.render_titlebar_right_side(&profile, window, cx)
|
||||
.into_any_element();
|
||||
|
||||
self.title_bar.update(cx, |this, _cx| {
|
||||
this.set_children(vec![left_side, right_side]);
|
||||
})
|
||||
}
|
||||
// Update title bar children
|
||||
self.title_bar.update(cx, |this, _cx| {
|
||||
this.set_children(vec![left, right]);
|
||||
});
|
||||
|
||||
div()
|
||||
.id(SharedString::from("chatspace"))
|
||||
|
||||
@@ -83,9 +83,12 @@ fn main() {
|
||||
ui::init(cx);
|
||||
|
||||
// Initialize app registry
|
||||
registry::init(cx);
|
||||
chat::init(cx);
|
||||
|
||||
// Initialize backend for credentials storage
|
||||
// Initialize person registry
|
||||
person::init(cx);
|
||||
|
||||
// Initialize backend for keys storage
|
||||
key_store::init(cx);
|
||||
|
||||
// Initialize settings
|
||||
|
||||
@@ -12,7 +12,7 @@ use i18n::{shared_t, t};
|
||||
use key_store::backend::KeyItem;
|
||||
use key_store::KeyStore;
|
||||
use nostr_connect::prelude::*;
|
||||
use registry::Registry;
|
||||
use person::PersonRegistry;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use states::{app_state, BUNKER_TIMEOUT};
|
||||
use theme::ActiveTheme;
|
||||
@@ -207,8 +207,8 @@ impl Focusable for Account {
|
||||
|
||||
impl Render for Account {
|
||||
fn render(&mut self, _window: &mut gpui::Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let registry = Registry::global(cx);
|
||||
let profile = registry.read(cx).get_person(&self.public_key, cx);
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let profile = persons.read(cx).get_person(&self.public_key, cx);
|
||||
let bunker = self.secret.starts_with("bunker://");
|
||||
|
||||
v_flex()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,55 +0,0 @@
|
||||
use gpui::{
|
||||
div, App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString,
|
||||
Styled, Window,
|
||||
};
|
||||
use i18n::{shared_t, t};
|
||||
use theme::ActiveTheme;
|
||||
use ui::input::{InputState, TextInput};
|
||||
use ui::{v_flex, Sizable};
|
||||
|
||||
pub fn init(subject: Option<String>, window: &mut Window, cx: &mut App) -> Entity<Subject> {
|
||||
Subject::new(subject, window, cx)
|
||||
}
|
||||
|
||||
pub struct Subject {
|
||||
input: Entity<InputState>,
|
||||
}
|
||||
|
||||
impl Subject {
|
||||
pub fn new(subject: Option<String>, window: &mut Window, cx: &mut App) -> Entity<Self> {
|
||||
let input = cx.new(|cx| {
|
||||
let mut this = InputState::new(window, cx).placeholder(t!("subject.placeholder"));
|
||||
if let Some(text) = subject.as_ref() {
|
||||
this.set_value(text, window, cx);
|
||||
}
|
||||
this
|
||||
});
|
||||
|
||||
cx.new(|_| Self { input })
|
||||
}
|
||||
|
||||
pub fn new_subject(&self, cx: &App) -> String {
|
||||
self.input.read(cx).value().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Subject {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(shared_t!("subject.title")),
|
||||
)
|
||||
.child(TextInput::new(&self.input).small())
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.italic()
|
||||
.text_color(cx.theme().text_placeholder)
|
||||
.child(shared_t!("subject.help_text")),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ use std::ops::Range;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, Error};
|
||||
use chat::room::Room;
|
||||
use chat::ChatRegistry;
|
||||
use common::display::{RenderedProfile, TextUtils};
|
||||
use common::nip05::nip05_profile;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
@@ -13,8 +15,7 @@ use gpui::{
|
||||
use gpui_tokio::Tokio;
|
||||
use i18n::{shared_t, t};
|
||||
use nostr_sdk::prelude::*;
|
||||
use registry::room::Room;
|
||||
use registry::Registry;
|
||||
use person::PersonRegistry;
|
||||
use settings::AppSettings;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use states::{app_state, BOOTSTRAP_RELAYS};
|
||||
@@ -311,7 +312,7 @@ impl Compose {
|
||||
}
|
||||
|
||||
fn submit(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let registry = Registry::global(cx);
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let receivers: Vec<PublicKey> = self.selected(cx);
|
||||
let subject_input = self.title_input.read(cx).value();
|
||||
let subject = (!subject_input.is_empty()).then(|| subject_input.to_string());
|
||||
@@ -327,10 +328,9 @@ impl Compose {
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
match result {
|
||||
Ok(room) => {
|
||||
registry.update(cx, |this, cx| {
|
||||
chat.update(cx, |this, cx| {
|
||||
this.push_room(cx.new(|_| room), cx);
|
||||
});
|
||||
|
||||
window.close_modal(cx);
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -372,7 +372,7 @@ impl Compose {
|
||||
|
||||
fn list_items(&self, range: Range<usize>, cx: &Context<Self>) -> Vec<impl IntoElement> {
|
||||
let proxy = AppSettings::get_proxy_user_avatars(cx);
|
||||
let registry = Registry::read_global(cx);
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let mut items = Vec::with_capacity(self.contacts.read(cx).len());
|
||||
|
||||
for ix in range {
|
||||
@@ -381,7 +381,7 @@ impl Compose {
|
||||
};
|
||||
|
||||
let public_key = contact.public_key;
|
||||
let profile = registry.get_person(&public_key, cx);
|
||||
let profile = persons.read(cx).get_person(&public_key, cx);
|
||||
|
||||
items.push(
|
||||
h_flex()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
pub mod account;
|
||||
pub mod backup_keys;
|
||||
pub mod chat;
|
||||
pub mod compose;
|
||||
pub mod edit_profile;
|
||||
pub mod login;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use account::Account;
|
||||
use common::display::RenderedProfile;
|
||||
use gpui::http_client::Url;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
div, px, relative, rems, App, AppContext, Context, Entity, InteractiveElement, IntoElement,
|
||||
ParentElement, Render, SharedString, StatefulInteractiveElement, Styled, Window,
|
||||
};
|
||||
use i18n::{shared_t, t};
|
||||
use registry::Registry;
|
||||
use person::PersonRegistry;
|
||||
use settings::AppSettings;
|
||||
use theme::ActiveTheme;
|
||||
use ui::avatar::Avatar;
|
||||
@@ -53,7 +53,7 @@ impl Preferences {
|
||||
.on_ok(move |_, window, cx| {
|
||||
weak_view
|
||||
.update(cx, |this, cx| {
|
||||
let registry = Registry::global(cx);
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let set_metadata = this.set_metadata(cx);
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
@@ -62,7 +62,7 @@ impl Preferences {
|
||||
this.update_in(cx, |_, window, cx| {
|
||||
match result {
|
||||
Ok(profile) => {
|
||||
registry.update(cx, |this, cx| {
|
||||
persons.update(cx, |this, cx| {
|
||||
this.insert_or_update_person(profile, cx);
|
||||
});
|
||||
}
|
||||
@@ -115,7 +115,11 @@ impl Render for Preferences {
|
||||
let proxy = AppSettings::get_proxy_user_avatars(cx);
|
||||
let hide = AppSettings::get_hide_user_avatars(cx);
|
||||
|
||||
let registry = Registry::read_global(cx);
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let account = Account::global(cx);
|
||||
let public_key = account.read(cx).public_key();
|
||||
let profile = persons.read(cx).get_person(&public_key, cx);
|
||||
|
||||
let input_state = self.media_input.downgrade();
|
||||
|
||||
v_flex()
|
||||
@@ -130,54 +134,48 @@ impl Render for Preferences {
|
||||
.font_semibold()
|
||||
.child(shared_t!("preferences.account_header")),
|
||||
)
|
||||
.when_some(registry.signer_pubkey(), |this, public_key| {
|
||||
let profile = registry.get_person(&public_key, cx);
|
||||
|
||||
this.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.child(
|
||||
h_flex()
|
||||
.id("user")
|
||||
.gap_2()
|
||||
.child(Avatar::new(profile.avatar(proxy)).size(rems(2.4)))
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.text_sm()
|
||||
.child(
|
||||
div()
|
||||
.font_semibold()
|
||||
.line_height(relative(1.3))
|
||||
.child(profile.display_name()),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.line_height(relative(1.3))
|
||||
.child(shared_t!(
|
||||
"preferences.account_btn"
|
||||
)),
|
||||
),
|
||||
)
|
||||
.on_click(cx.listener(move |this, _e, window, cx| {
|
||||
this.open_edit_profile(window, cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("relays")
|
||||
.label("Messaging Relays")
|
||||
.xsmall()
|
||||
.ghost_alt()
|
||||
.rounded()
|
||||
.on_click(cx.listener(move |this, _e, window, cx| {
|
||||
this.open_relays(window, cx);
|
||||
})),
|
||||
),
|
||||
)
|
||||
}),
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.child(
|
||||
h_flex()
|
||||
.id("user")
|
||||
.gap_2()
|
||||
.child(Avatar::new(profile.avatar(proxy)).size(rems(2.4)))
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.text_sm()
|
||||
.child(
|
||||
div()
|
||||
.font_semibold()
|
||||
.line_height(relative(1.3))
|
||||
.child(profile.display_name()),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.line_height(relative(1.3))
|
||||
.child(shared_t!("preferences.account_btn")),
|
||||
),
|
||||
)
|
||||
.on_click(cx.listener(move |this, _e, window, cx| {
|
||||
this.open_edit_profile(window, cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("relays")
|
||||
.label("Messaging Relays")
|
||||
.xsmall()
|
||||
.ghost_alt()
|
||||
.rounded()
|
||||
.on_click(cx.listener(move |this, _e, window, cx| {
|
||||
this.open_relays(window, cx);
|
||||
})),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
|
||||
@@ -10,7 +10,7 @@ use gpui::{
|
||||
use gpui_tokio::Tokio;
|
||||
use i18n::{shared_t, t};
|
||||
use nostr_sdk::prelude::*;
|
||||
use registry::Registry;
|
||||
use person::PersonRegistry;
|
||||
use settings::AppSettings;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use states::{app_state, BOOTSTRAP_RELAYS};
|
||||
@@ -35,8 +35,8 @@ pub struct Screening {
|
||||
|
||||
impl Screening {
|
||||
pub fn new(public_key: PublicKey, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let registry = Registry::read_global(cx);
|
||||
let profile = registry.get_person(&public_key, cx);
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let profile = persons.read(cx).get_person(&public_key, cx);
|
||||
|
||||
let mut tasks = smallvec![];
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use chat::room::RoomKind;
|
||||
use chat::ChatRegistry;
|
||||
use chat_ui::{CopyPublicKey, OpenPublicKey};
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
div, rems, App, ClickEvent, InteractiveElement, IntoElement, ParentElement as _, RenderOnce,
|
||||
@@ -7,11 +10,8 @@ use gpui::{
|
||||
};
|
||||
use i18n::t;
|
||||
use nostr_sdk::prelude::*;
|
||||
use registry::room::RoomKind;
|
||||
use registry::Registry;
|
||||
use settings::AppSettings;
|
||||
use theme::ActiveTheme;
|
||||
use ui::actions::{CopyPublicKey, OpenPublicKey};
|
||||
use ui::avatar::Avatar;
|
||||
use ui::context_menu::ContextMenuExt;
|
||||
use ui::modal::ModalButtonProps;
|
||||
@@ -187,7 +187,7 @@ impl RenderOnce for RoomListItem {
|
||||
.ok_text(t!("screening.response")),
|
||||
)
|
||||
.on_cancel(move |_event, _window, cx| {
|
||||
Registry::global(cx).update(cx, |this, cx| {
|
||||
ChatRegistry::global(cx).update(cx, |this, cx| {
|
||||
this.close_room(room_id, cx);
|
||||
});
|
||||
// false to prevent closing the modal
|
||||
|
||||
@@ -3,6 +3,8 @@ use std::ops::Range;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, Error};
|
||||
use chat::room::{Room, RoomKind};
|
||||
use chat::{ChatEvent, ChatRegistry};
|
||||
use common::debounced_delay::DebouncedDelay;
|
||||
use common::display::{RenderedProfile, RenderedTimestamp, TextUtils};
|
||||
use gpui::prelude::FluentBuilder;
|
||||
@@ -16,8 +18,6 @@ use i18n::{shared_t, t};
|
||||
use itertools::Itertools;
|
||||
use list_item::RoomListItem;
|
||||
use nostr_sdk::prelude::*;
|
||||
use registry::room::{Room, RoomKind};
|
||||
use registry::{Registry, RegistryEvent};
|
||||
use settings::AppSettings;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use states::{app_state, BOOTSTRAP_RELAYS, SEARCH_RELAYS};
|
||||
@@ -73,7 +73,7 @@ impl Sidebar {
|
||||
let find_input =
|
||||
cx.new(|cx| InputState::new(window, cx).placeholder(t!("sidebar.search_label")));
|
||||
|
||||
let registry = Registry::global(cx);
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let mut subscriptions = smallvec![];
|
||||
|
||||
subscriptions.push(
|
||||
@@ -87,8 +87,8 @@ impl Sidebar {
|
||||
|
||||
subscriptions.push(
|
||||
// Subscribe for registry new events
|
||||
cx.subscribe_in(®istry, window, move |this, _, event, _window, cx| {
|
||||
if let RegistryEvent::NewRequest(kind) = event {
|
||||
cx.subscribe_in(&chat, window, move |this, _, event, _window, cx| {
|
||||
if let ChatEvent::NewChatRequest(kind) = event {
|
||||
this.indicator.update(cx, |this, cx| {
|
||||
*this = Some(kind.to_owned());
|
||||
cx.notify();
|
||||
@@ -326,8 +326,8 @@ impl Sidebar {
|
||||
Ok(room) => {
|
||||
cx.update(|window, cx| {
|
||||
this.update(cx, |this, cx| {
|
||||
let registry = Registry::read_global(cx);
|
||||
let result = registry.search_by_public_key(public_key, cx);
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let result = chat.read(cx).search_by_public_key(public_key, cx);
|
||||
|
||||
if !result.is_empty() {
|
||||
this.results(result, false, window, cx);
|
||||
@@ -394,9 +394,9 @@ impl Sidebar {
|
||||
}
|
||||
}
|
||||
|
||||
let chats = Registry::read_global(cx);
|
||||
let chat = ChatRegistry::global(cx);
|
||||
// Get all local results with current query
|
||||
let local_results = chats.search(&query, cx);
|
||||
let local_results = chat.read(cx).search(&query, cx);
|
||||
|
||||
if !local_results.is_empty() {
|
||||
// Try to update with local results first
|
||||
@@ -495,7 +495,7 @@ impl Sidebar {
|
||||
}
|
||||
|
||||
fn open_room(&mut self, id: u64, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let room = if let Some(room) = Registry::read_global(cx).room(&id, cx) {
|
||||
let room = if let Some(room) = ChatRegistry::global(cx).read(cx).room(&id, cx) {
|
||||
room
|
||||
} else {
|
||||
let Some(result) = self.global_result.read(cx).as_ref() else {
|
||||
@@ -514,13 +514,13 @@ impl Sidebar {
|
||||
room
|
||||
};
|
||||
|
||||
Registry::global(cx).update(cx, |this, cx| {
|
||||
ChatRegistry::global(cx).update(cx, |this, cx| {
|
||||
this.push_room(room, cx);
|
||||
});
|
||||
}
|
||||
|
||||
fn on_reload(&mut self, _ev: &Reload, window: &mut Window, cx: &mut Context<Self>) {
|
||||
Registry::global(cx).update(cx, |this, cx| {
|
||||
ChatRegistry::global(cx).update(cx, |this, cx| {
|
||||
this.load_rooms(window, cx);
|
||||
});
|
||||
window.push_notification(t!("common.refreshed"), cx);
|
||||
@@ -661,8 +661,8 @@ impl Focusable for Sidebar {
|
||||
|
||||
impl Render for Sidebar {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let registry = Registry::read_global(cx);
|
||||
let loading = registry.loading;
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let loading = chat.read(cx).loading;
|
||||
|
||||
// Get rooms from either search results or the chat registry
|
||||
let rooms = if let Some(results) = self.local_result.read(cx).as_ref() {
|
||||
@@ -672,9 +672,9 @@ impl Render for Sidebar {
|
||||
} else {
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
if self.active_filter.read(cx) == &RoomKind::Ongoing {
|
||||
registry.ongoing_rooms(cx)
|
||||
chat.read(cx).ongoing_rooms(cx)
|
||||
} else {
|
||||
registry.request_rooms(cx)
|
||||
chat.read(cx).request_rooms(cx)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -738,9 +738,9 @@ impl Render for Sidebar {
|
||||
.tooltip(t!("sidebar.all_conversations_tooltip"))
|
||||
.when_some(self.indicator.read(cx).as_ref(), |this, kind| {
|
||||
this.when(kind == &RoomKind::Ongoing, |this| {
|
||||
this.child(deferred(
|
||||
this.child(
|
||||
div().size_1().rounded_full().bg(cx.theme().cursor),
|
||||
))
|
||||
)
|
||||
})
|
||||
})
|
||||
.small()
|
||||
@@ -759,9 +759,9 @@ impl Render for Sidebar {
|
||||
.tooltip(t!("sidebar.requests_tooltip"))
|
||||
.when_some(self.indicator.read(cx).as_ref(), |this, kind| {
|
||||
this.when(kind != &RoomKind::Ongoing, |this| {
|
||||
this.child(deferred(
|
||||
this.child(
|
||||
div().size_1().rounded_full().bg(cx.theme().cursor),
|
||||
))
|
||||
)
|
||||
})
|
||||
})
|
||||
.small()
|
||||
|
||||
@@ -10,7 +10,7 @@ use gpui::{
|
||||
use gpui_tokio::Tokio;
|
||||
use i18n::{shared_t, t};
|
||||
use nostr_sdk::prelude::*;
|
||||
use registry::Registry;
|
||||
use person::PersonRegistry;
|
||||
use settings::AppSettings;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use states::app_state;
|
||||
@@ -33,8 +33,8 @@ pub struct UserProfile {
|
||||
|
||||
impl UserProfile {
|
||||
pub fn new(target: PublicKey, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let registry = Registry::read_global(cx);
|
||||
let profile = registry.get_person(&target, cx);
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let profile = persons.read(cx).get_person(&target, cx);
|
||||
|
||||
let mut tasks = smallvec![];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user