feat: add community ui (#52)

Reviewed-on: #52
This commit was merged in pull request #52.
This commit is contained in:
2026-09-23 01:12:51 +00:00
parent 6ff1eeddbb
commit 1032ac3751
80 changed files with 12888 additions and 3143 deletions
+40 -16
View File
@@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize};
use smallvec::{SmallVec, smallvec};
use theme::{Theme, ThemeFamily, ThemeMode};
pub fn init(window: &mut Window, cx: &mut App) {
AppSettings::set_global(cx.new(|cx| AppSettings::new(window, cx)), cx)
pub fn init(cx: &mut App) {
AppSettings::set_global(cx.new(AppSettings::new), cx)
}
const DEFAULT_FILE_SERVER: &str = "https://nostr.download/";
@@ -46,8 +46,11 @@ setting_accessors! {
pub nip4e: bool,
pub trusted_relays: Vec<String>,
pub file_server: Url,
pub recent_communities: Vec<String>,
}
const RECENT_COMMUNITIES_CAP: usize = 10;
/// Signer kind
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum SignerKind {
@@ -130,6 +133,10 @@ pub struct Settings {
/// Server for blossom media attachments
pub file_server: Url,
/// Recently opened community ids, newest first
#[serde(default)]
pub recent_communities: Vec<String>,
}
impl Default for Settings {
@@ -142,6 +149,7 @@ impl Default for Settings {
nip4e: false,
trusted_relays: vec![],
file_server: Url::parse(DEFAULT_FILE_SERVER).unwrap(),
recent_communities: vec![],
}
}
}
@@ -160,7 +168,6 @@ impl Global for GlobalAppSettings {}
pub struct AppSettings {
/// Settings
inner: Entity<Settings>,
/// Event subscriptions
_subscriptions: SmallVec<[Subscription; 2]>,
}
@@ -171,12 +178,18 @@ impl AppSettings {
cx.global::<GlobalAppSettings>().0.clone()
}
/// The underlying settings entity, which notifies whenever any field changes.
pub fn entity(&self) -> &Entity<Settings> {
&self.inner
}
/// Set the global settings instance
fn set_global(state: Entity<Self>, cx: &mut App) {
cx.set_global(GlobalAppSettings(state));
}
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
fn new(cx: &mut Context<Self>) -> Self {
let entity = cx.entity().downgrade();
let inner = cx.new(|_| Settings::default());
let mut subscriptions = smallvec![];
@@ -188,8 +201,8 @@ impl AppSettings {
);
// Run at the end of current cycle
cx.defer_in(window, |this, window, cx| {
this.load(window, cx);
cx.defer(move |cx| {
entity.update(cx, |this, cx| this.load(cx)).ok();
});
Self {
@@ -207,7 +220,7 @@ impl AppSettings {
}
/// Load settings
fn load(&mut self, window: &mut Window, cx: &mut Context<Self>) {
fn load(&mut self, cx: &mut Context<Self>) {
let task: Task<Result<Settings, Error>> = cx.background_spawn(async move {
#[cfg(not(target_arch = "wasm32"))]
{
@@ -219,7 +232,7 @@ impl AppSettings {
Err(anyhow!("Not found"))
});
cx.spawn_in(window, async move |this, cx| {
cx.spawn(async move |this, cx| {
let mut settings = task.await.unwrap_or(Settings::default());
// Move settings still pointed at the old default file server over to the new one
@@ -228,9 +241,10 @@ impl AppSettings {
}
// Update settings
this.update_in(cx, |this, window, cx| {
this.update(cx, |this, cx| {
this.set_settings(settings, cx);
this.apply_theme(window, cx);
this.apply_theme(None, cx);
cx.refresh_windows();
})
.ok();
})
@@ -262,7 +276,7 @@ impl AppSettings {
});
// Apply the new theme
self.apply_theme(window, cx);
self.apply_theme(Some(window), cx);
}
/// Reset theme
@@ -271,22 +285,22 @@ impl AppSettings {
this.theme = None;
cx.notify();
});
self.apply_theme(window, cx);
self.apply_theme(Some(window), cx);
}
/// Apply theme
pub fn apply_theme(&mut self, window: &mut Window, cx: &mut Context<Self>) {
pub fn apply_theme(&mut self, mut window: Option<&mut Window>, cx: &mut Context<Self>) {
if let Some(name) = self.inner.read(cx).theme.as_ref() {
let mode = self.inner.read(cx).theme_mode;
if let Ok(new_theme) = ThemeFamily::from_assets(name) {
Theme::apply_theme(Rc::new(new_theme), Some(window), cx);
Theme::change(mode, Some(window), cx);
Theme::apply_theme(Rc::new(new_theme), window.as_deref_mut(), cx);
Theme::change(mode, window, cx);
} else {
log::info!("Failed to load theme: {name}");
}
} else {
Theme::apply_theme(Rc::new(ThemeFamily::default()), Some(window), cx);
Theme::apply_theme(Rc::new(ThemeFamily::default()), window, cx);
}
}
@@ -318,4 +332,14 @@ impl AppSettings {
}
});
}
/// Move a community to the front of the recently opened list
pub fn record_recent_community(&mut self, id: String, cx: &mut Context<Self>) {
self.inner.update(cx, |this, cx| {
this.recent_communities.retain(|existing| existing != &id);
this.recent_communities.insert(0, id);
this.recent_communities.truncate(RECENT_COMMUNITIES_CAP);
cx.notify();
});
}
}