@@ -3,6 +3,7 @@ use std::sync::Mutex;
|
||||
use gpui::{actions, App};
|
||||
|
||||
actions!(coop, [DarkMode, Settings, Logout, Quit]);
|
||||
actions!(sidebar, [Reload, RelayStatus]);
|
||||
|
||||
pub fn load_embedded_fonts(cx: &App) {
|
||||
let asset_source = cx.asset_source();
|
||||
|
||||
@@ -1313,7 +1313,7 @@ impl ChatSpace {
|
||||
)
|
||||
})
|
||||
.when(!self.has_nip17_relays, |this| {
|
||||
this.child(setup_nip17_relay(t!("relays.button_label")))
|
||||
this.child(setup_nip17_relay(t!("relays.button")))
|
||||
})
|
||||
.child(
|
||||
Button::new("user")
|
||||
|
||||
@@ -86,7 +86,6 @@ impl Preferences {
|
||||
}
|
||||
|
||||
fn open_relays(&self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let title = SharedString::new(t!("relays.modal_title"));
|
||||
let view = setup_relay::init(Kind::InboxRelays, window, cx);
|
||||
let weak_view = view.downgrade();
|
||||
|
||||
@@ -94,7 +93,7 @@ impl Preferences {
|
||||
let weak_view = weak_view.clone();
|
||||
|
||||
this.confirm()
|
||||
.title(title.clone())
|
||||
.title(shared_t!("relays.modal"))
|
||||
.child(view.clone())
|
||||
.button_props(ModalButtonProps::default().ok_text(t!("common.update")))
|
||||
.on_ok(move |_, window, cx| {
|
||||
|
||||
@@ -45,7 +45,7 @@ where
|
||||
|
||||
modal
|
||||
.confirm()
|
||||
.title(shared_t!("relays.modal_title"))
|
||||
.title(shared_t!("relays.modal"))
|
||||
.child(view.clone())
|
||||
.button_props(ModalButtonProps::default().ok_text(t!("common.update")))
|
||||
.on_ok(move |_, window, cx| {
|
||||
@@ -299,7 +299,7 @@ impl SetupRelay {
|
||||
.justify_center()
|
||||
.text_sm()
|
||||
.text_align(TextAlign::Center)
|
||||
.child(shared_t!("relays.add_some_relays"))
|
||||
.child(shared_t!("relays.help_text"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ impl Render for SetupRelay {
|
||||
.text_xs()
|
||||
.font_semibold()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(shared_t!("relays.recommended")),
|
||||
.child(shared_t!("common.recommended")),
|
||||
)
|
||||
.child(h_flex().gap_1().children({
|
||||
NIP17_RELAYS.iter().map(|&relay| {
|
||||
|
||||
@@ -6,15 +6,15 @@ use anyhow::{anyhow, Error};
|
||||
use common::debounced_delay::DebouncedDelay;
|
||||
use common::display::{ReadableTimestamp, TextUtils};
|
||||
use global::constants::{BOOTSTRAP_RELAYS, SEARCH_RELAYS};
|
||||
use global::{nostr_client, UnwrappingStatus};
|
||||
use global::{css, nostr_client, UnwrappingStatus};
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
div, uniform_list, AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle,
|
||||
Focusable, IntoElement, ParentElement, Render, RetainAllImageCache, SharedString, Styled,
|
||||
Subscription, Task, Window,
|
||||
Focusable, InteractiveElement, IntoElement, ParentElement, Render, RetainAllImageCache,
|
||||
SharedString, Styled, Subscription, Task, Window,
|
||||
};
|
||||
use gpui_tokio::Tokio;
|
||||
use i18n::t;
|
||||
use i18n::{shared_t, t};
|
||||
use itertools::Itertools;
|
||||
use list_item::RoomListItem;
|
||||
use nostr_sdk::prelude::*;
|
||||
@@ -26,8 +26,10 @@ use theme::ActiveTheme;
|
||||
use ui::button::{Button, ButtonRounded, ButtonVariants};
|
||||
use ui::dock_area::panel::{Panel, PanelEvent};
|
||||
use ui::input::{InputEvent, InputState, TextInput};
|
||||
use ui::popup_menu::PopupMenu;
|
||||
use ui::{v_flex, ContextModal, IconName, Selectable, Sizable, StyledExt};
|
||||
use ui::popup_menu::{PopupMenu, PopupMenuExt};
|
||||
use ui::{h_flex, v_flex, ContextModal, Icon, IconName, Selectable, Sizable, StyledExt};
|
||||
|
||||
use crate::actions::{RelayStatus, Reload};
|
||||
|
||||
mod list_item;
|
||||
|
||||
@@ -69,17 +71,16 @@ impl Sidebar {
|
||||
let global_result = cx.new(|_| None);
|
||||
let cancel_handle = cx.new(|_| None);
|
||||
|
||||
let find_input = cx.new(|cx| {
|
||||
InputState::new(window, cx).placeholder(t!("sidebar.find_or_start_conversation"))
|
||||
});
|
||||
let find_input =
|
||||
cx.new(|cx| InputState::new(window, cx).placeholder(t!("sidebar.search_label")));
|
||||
|
||||
let chats = Registry::global(cx);
|
||||
let registry = Registry::global(cx);
|
||||
let mut subscriptions = smallvec![];
|
||||
|
||||
subscriptions.push(cx.subscribe_in(
|
||||
&chats,
|
||||
®istry,
|
||||
window,
|
||||
move |this, _chats, event, _window, cx| {
|
||||
move |this, _, event, _window, cx| {
|
||||
if let RegistryEvent::NewRequest(kind) = event {
|
||||
this.indicator.update(cx, |this, cx| {
|
||||
*this = Some(kind.to_owned());
|
||||
@@ -519,6 +520,88 @@ impl Sidebar {
|
||||
});
|
||||
}
|
||||
|
||||
fn on_reload(&mut self, _ev: &Reload, window: &mut Window, cx: &mut Context<Self>) {
|
||||
Registry::global(cx).update(cx, |this, cx| {
|
||||
this.load_rooms(window, cx);
|
||||
});
|
||||
window.push_notification(t!("common.refreshed"), cx);
|
||||
}
|
||||
|
||||
fn on_manage(&mut self, _ev: &RelayStatus, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let task: Task<Result<Vec<Relay>, Error>> = cx.background_spawn(async move {
|
||||
let client = nostr_client();
|
||||
let css = css();
|
||||
let subscription = client.subscription(&css.gift_wrap_sub_id).await;
|
||||
let mut relays: Vec<Relay> = vec![];
|
||||
|
||||
for (url, _filter) in subscription.into_iter() {
|
||||
relays.push(client.pool().relay(url).await?);
|
||||
}
|
||||
|
||||
Ok(relays)
|
||||
});
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
if let Ok(relays) = task.await {
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
this.manage_relays(relays, window, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn manage_relays(&mut self, relays: Vec<Relay>, window: &mut Window, cx: &mut Context<Self>) {
|
||||
window.open_modal(cx, move |this, _window, cx| {
|
||||
this.show_close(true)
|
||||
.overlay_closable(true)
|
||||
.keyboard(true)
|
||||
.title(shared_t!("manage_relays.modal"))
|
||||
.child(v_flex().pb_4().gap_2().children({
|
||||
let mut items = Vec::with_capacity(relays.len());
|
||||
|
||||
for relay in relays.clone().into_iter() {
|
||||
let url = relay.url().to_string();
|
||||
let time = relay.stats().connected_at().to_ago();
|
||||
let connected = relay.is_connected();
|
||||
|
||||
items.push(
|
||||
h_flex()
|
||||
.h_8()
|
||||
.px_2()
|
||||
.justify_between()
|
||||
.text_xs()
|
||||
.bg(cx.theme().elevated_surface_background)
|
||||
.rounded(cx.theme().radius)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.font_semibold()
|
||||
.child(
|
||||
Icon::new(IconName::Signal)
|
||||
.small()
|
||||
.text_color(cx.theme().danger_active)
|
||||
.when(connected, |this| {
|
||||
this.text_color(gpui::green().alpha(0.75))
|
||||
}),
|
||||
)
|
||||
.child(url),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_right()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(shared_t!("manage_relays.time", t = time)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
items
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
fn list_items(
|
||||
&self,
|
||||
rooms: &[Entity<Room>],
|
||||
@@ -610,6 +693,8 @@ impl Render for Sidebar {
|
||||
}
|
||||
|
||||
v_flex()
|
||||
.on_action(cx.listener(Self::on_reload))
|
||||
.on_action(cx.listener(Self::on_manage))
|
||||
.image_cache(self.image_cache.clone())
|
||||
.size_full()
|
||||
.relative()
|
||||
@@ -632,7 +717,7 @@ impl Render for Sidebar {
|
||||
.suffix(
|
||||
Button::new("find")
|
||||
.icon(IconName::Search)
|
||||
.tooltip(t!("sidebar.press_enter_to_search"))
|
||||
.tooltip(t!("sidebar.search_tooltip"))
|
||||
.transparent()
|
||||
.small(),
|
||||
),
|
||||
@@ -693,6 +778,31 @@ impl Render for Sidebar {
|
||||
.on_click(cx.listener(|this, _, _, cx| {
|
||||
this.set_filter(RoomKind::default(), cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.flex_1()
|
||||
.w_full()
|
||||
.justify_end()
|
||||
.items_center()
|
||||
.text_xs()
|
||||
.child(
|
||||
Button::new("option")
|
||||
.icon(IconName::Ellipsis)
|
||||
.xsmall()
|
||||
.ghost()
|
||||
.rounded(ButtonRounded::Full)
|
||||
.popup_menu(move |this, _window, _cx| {
|
||||
this.menu(
|
||||
t!("sidebar.reload_menu"),
|
||||
Box::new(Reload),
|
||||
)
|
||||
.menu(
|
||||
t!("sidebar.status_menu"),
|
||||
Box::new(RelayStatus),
|
||||
)
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
|
||||
@@ -14,8 +14,6 @@ pub enum IconName {
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
ArrowUp,
|
||||
ArrowUpCircle,
|
||||
Bell,
|
||||
CaretUp,
|
||||
CaretDown,
|
||||
CaretDownFill,
|
||||
@@ -28,7 +26,6 @@ pub enum IconName {
|
||||
CloseCircleFill,
|
||||
Copy,
|
||||
Edit,
|
||||
EditFill,
|
||||
Ellipsis,
|
||||
Eye,
|
||||
EyeOff,
|
||||
@@ -52,9 +49,8 @@ pub enum IconName {
|
||||
Reply,
|
||||
Report,
|
||||
Refresh,
|
||||
Forward,
|
||||
Signal,
|
||||
Search,
|
||||
SearchFill,
|
||||
Settings,
|
||||
SortAscending,
|
||||
SortDescending,
|
||||
@@ -62,8 +58,8 @@ pub enum IconName {
|
||||
ThumbsDown,
|
||||
ThumbsUp,
|
||||
Upload,
|
||||
UsersThreeFill,
|
||||
OpenUrl,
|
||||
Warning,
|
||||
WindowClose,
|
||||
WindowMaximize,
|
||||
WindowMinimize,
|
||||
@@ -78,8 +74,6 @@ impl IconName {
|
||||
Self::ArrowLeft => "icons/arrow-left.svg",
|
||||
Self::ArrowRight => "icons/arrow-right.svg",
|
||||
Self::ArrowUp => "icons/arrow-up.svg",
|
||||
Self::ArrowUpCircle => "icons/arrow-up-circle.svg",
|
||||
Self::Bell => "icons/bell.svg",
|
||||
Self::CaretRight => "icons/caret-right.svg",
|
||||
Self::CaretUp => "icons/caret-up.svg",
|
||||
Self::CaretDown => "icons/caret-down.svg",
|
||||
@@ -92,7 +86,6 @@ impl IconName {
|
||||
Self::CloseCircleFill => "icons/close-circle-fill.svg",
|
||||
Self::Copy => "icons/copy.svg",
|
||||
Self::Edit => "icons/edit.svg",
|
||||
Self::EditFill => "icons/edit-fill.svg",
|
||||
Self::Ellipsis => "icons/ellipsis.svg",
|
||||
Self::Eye => "icons/eye.svg",
|
||||
Self::EmojiFill => "icons/emoji-fill.svg",
|
||||
@@ -116,9 +109,8 @@ impl IconName {
|
||||
Self::Reply => "icons/reply.svg",
|
||||
Self::Report => "icons/report.svg",
|
||||
Self::Refresh => "icons/refresh.svg",
|
||||
Self::Forward => "icons/forward.svg",
|
||||
Self::Signal => "icons/signal.svg",
|
||||
Self::Search => "icons/search.svg",
|
||||
Self::SearchFill => "icons/search-fill.svg",
|
||||
Self::Settings => "icons/settings.svg",
|
||||
Self::SortAscending => "icons/sort-ascending.svg",
|
||||
Self::SortDescending => "icons/sort-descending.svg",
|
||||
@@ -126,8 +118,8 @@ impl IconName {
|
||||
Self::ThumbsDown => "icons/thumbs-down.svg",
|
||||
Self::ThumbsUp => "icons/thumbs-up.svg",
|
||||
Self::Upload => "icons/upload.svg",
|
||||
Self::UsersThreeFill => "icons/users-three-fill.svg",
|
||||
Self::OpenUrl => "icons/open-url.svg",
|
||||
Self::Warning => "icons/warning.svg",
|
||||
Self::WindowClose => "icons/window-close.svg",
|
||||
Self::WindowMaximize => "icons/window-maximize.svg",
|
||||
Self::WindowMinimize => "icons/window-minimize.svg",
|
||||
|
||||
@@ -30,14 +30,10 @@ pub enum NotificationType {
|
||||
impl NotificationType {
|
||||
fn icon(&self, cx: &App) -> Icon {
|
||||
match self {
|
||||
Self::Info => Icon::new(IconName::Info).text_color(cx.theme().element_active),
|
||||
Self::Warning => Icon::new(IconName::Report).text_color(cx.theme().warning_foreground),
|
||||
Self::Success => {
|
||||
Icon::new(IconName::CheckCircle).text_color(cx.theme().element_foreground)
|
||||
}
|
||||
Self::Error => {
|
||||
Icon::new(IconName::CloseCircle).text_color(cx.theme().danger_foreground)
|
||||
}
|
||||
Self::Info => Icon::new(IconName::Info).text_color(cx.theme().element_foreground),
|
||||
Self::Success => Icon::new(IconName::Info).text_color(cx.theme().secondary_foreground),
|
||||
Self::Warning => Icon::new(IconName::Warning).text_color(cx.theme().warning_foreground),
|
||||
Self::Error => Icon::new(IconName::Warning).text_color(cx.theme().danger_foreground),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user