simplify nip29 discovery and sync metadata via negentropy
This commit is contained in:
@@ -5,7 +5,7 @@ use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
|
||||
IntoElement, ParentElement, Render, ScrollStrategy, SharedString, Styled, Subscription,
|
||||
WeakEntity, Window, div, px, size,
|
||||
WeakEntity, Window, div, px, relative, size,
|
||||
};
|
||||
use gpui_base::{VirtualListScrollHandle, v_virtual_list};
|
||||
use nip29::{Discovery, GroupCandidate, GroupKey, GroupsEvent, GroupsRegistry};
|
||||
@@ -24,9 +24,7 @@ use ui::{Disableable, Icon, IconName, Sizable, StyledExt, WindowExtension, h_fle
|
||||
|
||||
const TITLE: &str = "Browse";
|
||||
const INPUT_PLACEHOLDER: &str = "wss://relay.example.com";
|
||||
|
||||
const CARD_HEIGHT: f32 = 150.0;
|
||||
const DESCRIPTION_HEIGHT: f32 = 32.0;
|
||||
const CARD_HEIGHT: f32 = 164.0;
|
||||
const NO_DESCRIPTION: &str = "No description";
|
||||
|
||||
pub fn init(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut App) -> Entity<BrowsePanel> {
|
||||
@@ -201,7 +199,7 @@ impl BrowsePanel {
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
self.render_card_rows(&cards, range, cx)
|
||||
self.render_card_rows(&cards, cx)
|
||||
}
|
||||
|
||||
fn render_browse_rows(
|
||||
@@ -213,20 +211,23 @@ impl BrowsePanel {
|
||||
let end = (range.end * 2).min(self.candidates.len());
|
||||
let cards = self.candidates.get(start..end).unwrap_or(&[]);
|
||||
|
||||
self.render_card_rows(cards, range, cx)
|
||||
self.render_card_rows(cards, cx)
|
||||
}
|
||||
|
||||
/// A row holds two group cards side by side.
|
||||
///
|
||||
/// The cards are the relative slice of the visible rows, so they pair up
|
||||
/// in order, two per row.
|
||||
fn render_card_rows(
|
||||
&self,
|
||||
cards: &[GroupCandidate],
|
||||
range: Range<usize>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Vec<AnyElement> {
|
||||
range
|
||||
.map(|row| {
|
||||
let first = cards.get(row * 2);
|
||||
let second = cards.get(row * 2 + 1);
|
||||
cards
|
||||
.chunks(2)
|
||||
.map(|pair| {
|
||||
let first = pair.first();
|
||||
let second = pair.get(1);
|
||||
|
||||
h_flex()
|
||||
.w_full()
|
||||
@@ -234,7 +235,12 @@ impl BrowsePanel {
|
||||
.p_2()
|
||||
.gap_2()
|
||||
.children(first.map(|card| self.render_card(card, cx)))
|
||||
.children(second.map(|card| self.render_card(card, cx)))
|
||||
// Keep an odd last card in one column: an empty spacer
|
||||
// takes the second slot so the card cannot stretch.
|
||||
.child(match second {
|
||||
Some(card) => self.render_card(card, cx),
|
||||
None => div().flex_1().into_any_element(),
|
||||
})
|
||||
.into_any_element()
|
||||
})
|
||||
.collect()
|
||||
@@ -261,7 +267,7 @@ impl BrowsePanel {
|
||||
let joined = registry.read(cx).group(&key, cx).is_some();
|
||||
|
||||
let action = if joined {
|
||||
Button::new(format!("browse-joined-{seed}"))
|
||||
Button::new(format!("joined-{seed}"))
|
||||
.label("Joined")
|
||||
.small()
|
||||
.ghost()
|
||||
@@ -271,7 +277,7 @@ impl BrowsePanel {
|
||||
let panel = cx.entity().downgrade();
|
||||
let clicked = key;
|
||||
|
||||
Button::new(format!("browse-join-{seed}"))
|
||||
Button::new(format!("join-{seed}"))
|
||||
.label("Join")
|
||||
.small()
|
||||
.ghost()
|
||||
@@ -290,37 +296,38 @@ impl BrowsePanel {
|
||||
.overflow_hidden()
|
||||
.border_1()
|
||||
.border_color(cx.theme().border)
|
||||
.rounded_lg()
|
||||
.bg(cx.theme().surface_background)
|
||||
.rounded(cx.theme().radius)
|
||||
.child(
|
||||
v_flex()
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.p_2()
|
||||
.gap_1p5()
|
||||
.gap_2()
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.gap_1p5()
|
||||
.gap_2()
|
||||
.when(!hide_avatar, |this| {
|
||||
this.child(
|
||||
Avatar::from_source(picture)
|
||||
.seed(seed)
|
||||
.small()
|
||||
.flex_shrink_0(),
|
||||
)
|
||||
this.child(Avatar::from_source(picture).seed(seed).flex_shrink_0())
|
||||
})
|
||||
.child(
|
||||
v_flex()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.child(div().text_sm().font_medium().truncate().child(name))
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.truncate()
|
||||
.font_semibold()
|
||||
.line_height(relative(1.2))
|
||||
.child(name),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.truncate()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_placeholder)
|
||||
.truncate()
|
||||
.child(relay),
|
||||
),
|
||||
)
|
||||
@@ -328,44 +335,37 @@ impl BrowsePanel {
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.h(px(DESCRIPTION_HEIGHT))
|
||||
.text_xs()
|
||||
.min_w_0()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.when_none(&about, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.text_color(cx.theme().text_placeholder)
|
||||
.child(NO_DESCRIPTION),
|
||||
)
|
||||
})
|
||||
.when_some(about, |this, about| this.child(about)),
|
||||
.text_ellipsis()
|
||||
.line_clamp(3)
|
||||
.map(|this| {
|
||||
if let Some(about) = about {
|
||||
this.child(about)
|
||||
} else {
|
||||
this.child(NO_DESCRIPTION)
|
||||
}
|
||||
}),
|
||||
)
|
||||
.child(div().flex_1())
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_placeholder)
|
||||
.child(Icon::new(IconName::Group).text_color(cx.theme().icon_muted))
|
||||
.child(format!("{members} members")),
|
||||
.gap_1p5()
|
||||
.child(Icon::new(IconName::Group))
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from(format!("{members} members"))),
|
||||
),
|
||||
),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
|
||||
fn notice(text: &'static str, cx: &App) -> AnyElement {
|
||||
h_flex()
|
||||
.size_full()
|
||||
.justify_center()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(text)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
impl Panel for BrowsePanel {
|
||||
fn panel_id(&self) -> SharedString {
|
||||
TITLE.into()
|
||||
@@ -460,7 +460,7 @@ impl Render for BrowsePanel {
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.p_3()
|
||||
.px_2()
|
||||
.flex_shrink_0()
|
||||
.child(Input::new(&self.input).cleanable(true).flex_1())
|
||||
.child(
|
||||
@@ -475,16 +475,6 @@ impl Render for BrowsePanel {
|
||||
this.child(Indicator::new().small().color(cx.theme().icon_accent))
|
||||
}),
|
||||
)
|
||||
.when(discover && discovered_count > 0, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.px_3()
|
||||
.pb_1()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child("Discovered groups"),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
@@ -495,3 +485,13 @@ impl Render for BrowsePanel {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn notice(text: &'static str, cx: &App) -> AnyElement {
|
||||
h_flex()
|
||||
.size_full()
|
||||
.justify_center()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(text)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user