.
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m19s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 1m23s
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m19s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 1m23s
This commit is contained in:
@@ -302,6 +302,11 @@ impl ChatRegistry {
|
||||
.map(|this| this.downgrade())
|
||||
}
|
||||
|
||||
/// Get all rooms.
|
||||
pub fn rooms(&self, _cx: &App) -> &Vec<Entity<Room>> {
|
||||
&self.rooms
|
||||
}
|
||||
|
||||
/// Get all ongoing rooms.
|
||||
pub fn ongoing_rooms(&self, cx: &App) -> Vec<Entity<Room>> {
|
||||
self.rooms
|
||||
|
||||
@@ -2,12 +2,12 @@ use std::ops::Range;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, Error};
|
||||
use chat::{ChatEvent, ChatRegistry, Room, RoomKind};
|
||||
use chat::{ChatEvent, ChatRegistry, Room};
|
||||
use common::{DebouncedDelay, RenderedTimestamp, TextUtils, BOOTSTRAP_RELAYS, SEARCH_RELAYS};
|
||||
use dock::panel::{Panel, PanelEvent};
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
deferred, div, relative, rems, uniform_list, App, AppContext, Context, Entity, EventEmitter,
|
||||
deferred, div, rems, uniform_list, App, AppContext, Context, Decorations, Entity, EventEmitter,
|
||||
FocusHandle, Focusable, InteractiveElement, IntoElement, ParentElement, Render,
|
||||
RetainAllImageCache, SharedString, Styled, Subscription, Task, Window,
|
||||
};
|
||||
@@ -17,12 +17,11 @@ use nostr_sdk::prelude::*;
|
||||
use person::PersonRegistry;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use state::{NostrRegistry, GIFTWRAP_SUBSCRIPTION};
|
||||
use theme::{ActiveTheme, TITLEBAR_HEIGHT};
|
||||
use theme::{ActiveTheme, CLIENT_SIDE_DECORATION_ROUNDING, TITLEBAR_HEIGHT};
|
||||
use ui::avatar::Avatar;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::input::{InputEvent, InputState, TextInput};
|
||||
use ui::popup_menu::PopupMenuExt;
|
||||
use ui::{h_flex, v_flex, Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension};
|
||||
use ui::{h_flex, v_flex, Icon, IconName, Sizable, StyledExt, WindowExtension};
|
||||
|
||||
use crate::actions::{RelayStatus, Reload};
|
||||
use crate::views::compose::compose_button;
|
||||
@@ -64,16 +63,12 @@ pub struct Sidebar {
|
||||
/// New request flag
|
||||
new_request: bool,
|
||||
|
||||
/// Current chat room filter
|
||||
active_filter: Entity<RoomKind>,
|
||||
|
||||
/// Event subscriptions
|
||||
_subscriptions: SmallVec<[Subscription; 2]>,
|
||||
}
|
||||
|
||||
impl Sidebar {
|
||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let active_filter = cx.new(|_| RoomKind::Ongoing);
|
||||
let search_results = cx.new(|_| None);
|
||||
|
||||
// Define the find input state
|
||||
@@ -131,7 +126,6 @@ impl Sidebar {
|
||||
find_debouncer: DebouncedDelay::new(),
|
||||
finding: false,
|
||||
new_request: false,
|
||||
active_filter,
|
||||
find_input,
|
||||
search_results,
|
||||
search_task: None,
|
||||
@@ -412,19 +406,6 @@ impl Sidebar {
|
||||
});
|
||||
}
|
||||
|
||||
fn filter(&self, kind: &RoomKind, cx: &Context<Self>) -> bool {
|
||||
self.active_filter.read(cx) == kind
|
||||
}
|
||||
|
||||
fn set_filter(&mut self, kind: RoomKind, cx: &mut Context<Self>) {
|
||||
self.active_filter.update(cx, |this, cx| {
|
||||
*this = kind;
|
||||
cx.notify();
|
||||
});
|
||||
self.new_request = false;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn open(&mut self, id: u64, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let chat = ChatRegistry::global(cx);
|
||||
|
||||
@@ -536,43 +517,53 @@ impl Sidebar {
|
||||
});
|
||||
}
|
||||
|
||||
fn list_items(
|
||||
fn render_list_items(
|
||||
&self,
|
||||
rooms: &[Entity<Room>],
|
||||
range: Range<usize>,
|
||||
_window: &Window,
|
||||
cx: &Context<Self>,
|
||||
) -> Vec<impl IntoElement> {
|
||||
let mut items = Vec::with_capacity(range.end - range.start);
|
||||
let chat = ChatRegistry::global(cx);
|
||||
|
||||
for ix in range {
|
||||
let Some(room) = rooms.get(ix) else {
|
||||
items.push(RoomListItem::new(ix));
|
||||
continue;
|
||||
};
|
||||
// Get all rooms from search results or chat registry
|
||||
let all_rooms = match self.search_results.read(cx).as_ref() {
|
||||
Some(results) => results,
|
||||
None => chat.read(cx).rooms(cx),
|
||||
};
|
||||
|
||||
let this = room.read(cx);
|
||||
let room_id = this.id;
|
||||
let member = this.display_member(cx);
|
||||
// If no rooms are found, return a placeholder element for each index in the range
|
||||
let Some(visible_rooms) = all_rooms.get(range.clone()) else {
|
||||
return range
|
||||
.into_iter()
|
||||
.map(|ix| RoomListItem::new(ix).into_any_element())
|
||||
.collect();
|
||||
};
|
||||
|
||||
let handler = cx.listener({
|
||||
move |this, _, window, cx| {
|
||||
this.open(room_id, window, cx);
|
||||
}
|
||||
});
|
||||
visible_rooms
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(ix, item)| {
|
||||
let this = item.read(cx);
|
||||
let room_id = this.id;
|
||||
let member = this.display_member(cx);
|
||||
|
||||
items.push(
|
||||
RoomListItem::new(ix)
|
||||
let handler = cx.listener({
|
||||
move |this, _ev, window, cx| {
|
||||
this.open(room_id, window, cx);
|
||||
}
|
||||
});
|
||||
|
||||
RoomListItem::new(range.start + ix)
|
||||
.room_id(room_id)
|
||||
.name(this.display_name(cx))
|
||||
.avatar(this.display_image(cx))
|
||||
.public_key(member.public_key())
|
||||
.kind(this.kind)
|
||||
.created_at(this.created_at.to_ago())
|
||||
.on_click(handler),
|
||||
)
|
||||
}
|
||||
|
||||
items
|
||||
.on_click(handler)
|
||||
.into_any_element()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,10 +582,8 @@ impl Focusable for Sidebar {
|
||||
}
|
||||
|
||||
impl Render for Sidebar {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
const EMPTY_HELP: &str = "Start a conversation with someone to get started.";
|
||||
const REQUEST_HELP: &str =
|
||||
"New message requests from people you don't know will appear here.";
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let decorations = window.window_decorations();
|
||||
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let identity = nostr.read(cx).identity();
|
||||
@@ -603,15 +592,9 @@ impl Render for Sidebar {
|
||||
let loading = chat.read(cx).loading();
|
||||
|
||||
// Get rooms from either search results or the chat registry
|
||||
let rooms = if let Some(results) = self.search_results.read(cx).as_ref() {
|
||||
results.to_owned()
|
||||
} else {
|
||||
// Filter rooms based on the active filter
|
||||
if self.active_filter.read(cx) == &RoomKind::Ongoing {
|
||||
chat.read(cx).ongoing_rooms(cx)
|
||||
} else {
|
||||
chat.read(cx).request_rooms(cx)
|
||||
}
|
||||
let rooms = match self.search_results.read(cx).as_ref() {
|
||||
Some(results) => results,
|
||||
None => chat.read(cx).rooms(cx),
|
||||
};
|
||||
|
||||
// Get total rooms count
|
||||
@@ -628,11 +611,18 @@ impl Render for Sidebar {
|
||||
.image_cache(self.image_cache.clone())
|
||||
.size_full()
|
||||
.relative()
|
||||
.gap_3()
|
||||
.gap_2()
|
||||
.bg(cx.theme().surface_background)
|
||||
.map(|this| match decorations {
|
||||
Decorations::Server => this,
|
||||
Decorations::Client { .. } => this
|
||||
.rounded_tl(CLIENT_SIDE_DECORATION_ROUNDING)
|
||||
.rounded_bl(CLIENT_SIDE_DECORATION_ROUNDING),
|
||||
})
|
||||
// Titlebar
|
||||
.child(
|
||||
h_flex()
|
||||
.px_2p5()
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
@@ -643,14 +633,15 @@ impl Render for Sidebar {
|
||||
let profile = persons.read(cx).get(&public_key, cx);
|
||||
|
||||
this.child(
|
||||
Button::new("user")
|
||||
.label(profile.name())
|
||||
.reverse()
|
||||
.transparent()
|
||||
.child(Avatar::new(profile.avatar()).size(rems(1.6))),
|
||||
h_flex()
|
||||
.gap_1p5()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(Avatar::new(profile.avatar()).size(rems(1.25)))
|
||||
.child(profile.name()),
|
||||
)
|
||||
})
|
||||
.child(div().pr_2p5().child(compose_button())),
|
||||
.child(compose_button()),
|
||||
)
|
||||
.h(TITLEBAR_HEIGHT),
|
||||
)
|
||||
@@ -678,132 +669,39 @@ impl Render for Sidebar {
|
||||
}),
|
||||
),
|
||||
)
|
||||
.when(!loading && total_rooms == 0, |this| {
|
||||
this.child(deferred(
|
||||
v_flex()
|
||||
.py_2()
|
||||
.px_3()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.text_center()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.font_semibold()
|
||||
.child(SharedString::from("No conversations")),
|
||||
)
|
||||
.child(div().text_xs().text_color(cx.theme().text_muted).child(
|
||||
SharedString::from("Start a conversation with someone to get started."),
|
||||
)),
|
||||
))
|
||||
})
|
||||
// Chat Rooms
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.flex_1()
|
||||
.px_1p5()
|
||||
.w_full()
|
||||
.flex_1()
|
||||
.gap_1()
|
||||
.overflow_y_hidden()
|
||||
.child(
|
||||
div()
|
||||
.px_1()
|
||||
.h_flex()
|
||||
.gap_2()
|
||||
.flex_none()
|
||||
.child(
|
||||
Button::new("all")
|
||||
.label("All")
|
||||
.tooltip("All ongoing conversations")
|
||||
.small()
|
||||
.cta()
|
||||
.bold()
|
||||
.secondary()
|
||||
.rounded()
|
||||
.selected(self.filter(&RoomKind::Ongoing, cx))
|
||||
.on_click(cx.listener(|this, _, _, cx| {
|
||||
this.set_filter(RoomKind::Ongoing, cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("requests")
|
||||
.label("Requests")
|
||||
.tooltip("Incoming new conversations")
|
||||
.when(self.new_request, |this| {
|
||||
this.child(
|
||||
div().size_1().rounded_full().bg(cx.theme().cursor),
|
||||
)
|
||||
})
|
||||
.small()
|
||||
.cta()
|
||||
.bold()
|
||||
.secondary()
|
||||
.rounded()
|
||||
.selected(!self.filter(&RoomKind::Ongoing, cx))
|
||||
.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()
|
||||
.popup_menu(move |this, _window, _cx| {
|
||||
this.menu("Reload", Box::new(Reload))
|
||||
.menu("Relay Status", Box::new(RelayStatus))
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
.when(!loading && total_rooms == 0, |this| {
|
||||
this.map(|this| {
|
||||
if self.filter(&RoomKind::Ongoing, cx) {
|
||||
this.child(deferred(
|
||||
v_flex()
|
||||
.py_2()
|
||||
.px_1p5()
|
||||
.gap_1p5()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.text_center()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.font_semibold()
|
||||
.line_height(relative(1.25))
|
||||
.child(SharedString::from("No conversations")),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.line_height(relative(1.25))
|
||||
.child(SharedString::from(EMPTY_HELP)),
|
||||
),
|
||||
))
|
||||
} else {
|
||||
this.child(deferred(
|
||||
v_flex()
|
||||
.py_2()
|
||||
.px_1p5()
|
||||
.gap_1p5()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.text_center()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.font_semibold()
|
||||
.line_height(relative(1.25))
|
||||
.child(SharedString::from("No message requests")),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.line_height(relative(1.25))
|
||||
.child(SharedString::from(REQUEST_HELP)),
|
||||
),
|
||||
))
|
||||
}
|
||||
})
|
||||
})
|
||||
.child(
|
||||
uniform_list(
|
||||
"rooms",
|
||||
total_rooms,
|
||||
cx.processor(move |this, range, _window, cx| {
|
||||
this.list_items(&rooms, range, cx)
|
||||
cx.processor(|this, range, window, cx| {
|
||||
this.render_list_items(range, window, cx)
|
||||
}),
|
||||
)
|
||||
.h_full(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Error;
|
||||
use common::{nip05_verify, shorten_pubkey};
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Error;
|
||||
use common::{nip05_verify, shorten_pubkey, RenderedProfile, RenderedTimestamp, BOOTSTRAP_RELAYS};
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
|
||||
@@ -75,13 +75,7 @@ impl RenderOnce for WindowControl {
|
||||
this.child(
|
||||
svg()
|
||||
.external_path(path.into_os_string().into_string().unwrap())
|
||||
.map(|this| {
|
||||
if cx.theme().is_dark() {
|
||||
this.text_color(gpui::white())
|
||||
} else {
|
||||
this.text_color(gpui::black())
|
||||
}
|
||||
})
|
||||
.text_color(cx.theme().text)
|
||||
.size_4(),
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -8,13 +8,10 @@ use crate::scale::{ColorScale, ColorScaleSet, ColorScales};
|
||||
pub struct ThemeColors {
|
||||
// Surface colors
|
||||
pub background: Hsla,
|
||||
pub overlay: Hsla,
|
||||
pub surface_background: Hsla,
|
||||
pub elevated_surface_background: Hsla,
|
||||
pub panel_background: Hsla,
|
||||
pub overlay: Hsla,
|
||||
pub title_bar: Hsla,
|
||||
pub title_bar_inactive: Hsla,
|
||||
pub window_border: Hsla,
|
||||
|
||||
// Border colors
|
||||
pub border: Hsla,
|
||||
@@ -108,9 +105,6 @@ impl ThemeColors {
|
||||
elevated_surface_background: neutral().dark().step_3(),
|
||||
panel_background: neutral().dark().step_1(),
|
||||
overlay: neutral().dark_alpha().step_3(),
|
||||
title_bar: gpui::transparent_black(),
|
||||
title_bar_inactive: neutral().dark().step_1(),
|
||||
window_border: hsl(240.0, 3.7, 28.0),
|
||||
|
||||
border: neutral().dark().step_6(),
|
||||
border_variant: neutral().dark().step_5(),
|
||||
|
||||
@@ -12,6 +12,7 @@ pub enum IconName {
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
Boom,
|
||||
ChevronDown,
|
||||
CaretDown,
|
||||
CaretRight,
|
||||
CaretUp,
|
||||
@@ -57,6 +58,7 @@ impl IconName {
|
||||
Self::ArrowLeft => "icons/arrow-left.svg",
|
||||
Self::ArrowRight => "icons/arrow-right.svg",
|
||||
Self::Boom => "icons/boom.svg",
|
||||
Self::ChevronDown => "icons/chevron-down.svg",
|
||||
Self::CaretDown => "icons/caret-down.svg",
|
||||
Self::CaretRight => "icons/caret-right.svg",
|
||||
Self::CaretUp => "icons/caret-up.svg",
|
||||
|
||||
@@ -2,9 +2,9 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
canvas, div, point, px, AnyView, App, AppContext, Bounds, Context, CursorStyle, Decorations,
|
||||
Edges, Entity, FocusHandle, HitboxBehavior, Hsla, InteractiveElement, IntoElement, MouseButton,
|
||||
ParentElement as _, Pixels, Point, Render, ResizeEdge, SharedString, Size, Styled,
|
||||
canvas, div, point, px, rgba, AnyView, App, AppContext, Bounds, Context, CursorStyle,
|
||||
Decorations, Edges, Entity, FocusHandle, HitboxBehavior, Hsla, InteractiveElement, IntoElement,
|
||||
MouseButton, ParentElement as _, Pixels, Point, Render, ResizeEdge, SharedString, Size, Styled,
|
||||
WeakFocusHandle, Window,
|
||||
};
|
||||
use theme::{
|
||||
@@ -324,7 +324,9 @@ impl Render for Root {
|
||||
.map(|div| match decorations {
|
||||
Decorations::Server => div,
|
||||
Decorations::Client { tiling } => div
|
||||
.border_color(cx.theme().window_border)
|
||||
.when(!cx.theme().platform.is_mac(), |div| {
|
||||
div.border_color(rgba(0x64748b33))
|
||||
})
|
||||
.when(!(tiling.top || tiling.right), |div| {
|
||||
div.rounded_tr(CLIENT_SIDE_DECORATION_ROUNDING)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user