add contact-based community suggestions
This commit is contained in:
@@ -35,6 +35,10 @@ pub struct BrowsePanel {
|
||||
relay: Option<RelayUrl>,
|
||||
/// The groups the relay has announced so far
|
||||
candidates: Vec<GroupCandidate>,
|
||||
/// The communities of the user's contacts
|
||||
contacts: Vec<GroupCandidate>,
|
||||
/// Whether the contacts' communities are still resolving
|
||||
contacts_loading: bool,
|
||||
/// Whether the relay is still answering
|
||||
loading: bool,
|
||||
_subscriptions: SmallVec<[Subscription; 2]>,
|
||||
@@ -63,21 +67,71 @@ impl BrowsePanel {
|
||||
GroupsEvent::BrowseSettled(relay) => {
|
||||
this.settle(relay.clone(), cx);
|
||||
}
|
||||
GroupsEvent::Suggested(candidate) => {
|
||||
this.push_contact(candidate.as_ref().clone(), cx);
|
||||
}
|
||||
GroupsEvent::SuggestSettled => {
|
||||
this.settle_contacts(cx);
|
||||
}
|
||||
_ => {}
|
||||
}),
|
||||
);
|
||||
|
||||
// Wait for the panel to leave the stack before kicking off the sync.
|
||||
cx.defer_in(window, |this, _window, cx| {
|
||||
this.load_contacts(cx);
|
||||
});
|
||||
|
||||
Self {
|
||||
focus_handle: cx.focus_handle(),
|
||||
dock,
|
||||
input,
|
||||
relay: None,
|
||||
candidates: Vec::new(),
|
||||
contacts: Vec::new(),
|
||||
contacts_loading: true,
|
||||
loading: false,
|
||||
_subscriptions: subscriptions,
|
||||
}
|
||||
}
|
||||
|
||||
/// Pull the resolved contacts' communities and start the contacts sync.
|
||||
fn load_contacts(&mut self, cx: &mut Context<Self>) {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
|
||||
let (candidates, loading) = registry.update(cx, |registry, cx| {
|
||||
registry.load_contacts_groups(cx);
|
||||
(
|
||||
registry.contacts_candidates().to_vec(),
|
||||
registry.contacts_loading(),
|
||||
)
|
||||
});
|
||||
|
||||
self.contacts = candidates;
|
||||
self.contacts_loading = loading;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn push_contact(&mut self, candidate: GroupCandidate, cx: &mut Context<Self>) {
|
||||
match self.contacts.iter_mut().find(|c| c.key == candidate.key) {
|
||||
Some(existing) => *existing = candidate,
|
||||
None => self.contacts.push(candidate),
|
||||
}
|
||||
|
||||
self.contacts.sort_by(|a, b| {
|
||||
a.display_name()
|
||||
.to_lowercase()
|
||||
.cmp(&b.display_name().to_lowercase())
|
||||
});
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn settle_contacts(&mut self, cx: &mut Context<Self>) {
|
||||
self.contacts_loading = false;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Browse the relay in the input.
|
||||
fn browse(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
@@ -150,7 +204,13 @@ impl BrowsePanel {
|
||||
);
|
||||
}
|
||||
|
||||
fn render_rows(&self, range: Range<usize>, cx: &mut Context<Self>) -> Vec<AnyElement> {
|
||||
fn render_rows(
|
||||
&self,
|
||||
candidates: &[GroupCandidate],
|
||||
relay_detail: bool,
|
||||
range: Range<usize>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Vec<AnyElement> {
|
||||
let hide_avatar = AppSettings::get_hide_avatar(cx);
|
||||
let panel = cx.entity().downgrade();
|
||||
|
||||
@@ -162,7 +222,7 @@ impl BrowsePanel {
|
||||
.map(|group| group.read(cx).key().clone())
|
||||
.collect();
|
||||
|
||||
self.candidates
|
||||
candidates
|
||||
.get(range)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
@@ -173,6 +233,11 @@ impl BrowsePanel {
|
||||
.display_image()
|
||||
.map(|picture| SharedString::from(picture.to_owned()));
|
||||
let seed = key.cache_tag();
|
||||
let detail = if relay_detail {
|
||||
key.relay().domain().unwrap_or_else(|| key.relay().as_str())
|
||||
} else {
|
||||
key.id().as_str()
|
||||
};
|
||||
let is_joined = joined.contains(&key);
|
||||
|
||||
let action = if is_joined {
|
||||
@@ -221,7 +286,7 @@ impl BrowsePanel {
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_placeholder)
|
||||
.truncate()
|
||||
.child(SharedString::from(key.id().as_str().to_owned())),
|
||||
.child(SharedString::from(detail.to_owned())),
|
||||
),
|
||||
)
|
||||
.child(action)
|
||||
@@ -270,14 +335,53 @@ impl Focusable for BrowsePanel {
|
||||
impl Render for BrowsePanel {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let count = self.candidates.len();
|
||||
let from_contacts = self.relay.is_none();
|
||||
|
||||
let body = if self.relay.is_none() {
|
||||
notice("Enter a relay to browse its groups.", cx)
|
||||
let (contacts, contact_count) = if from_contacts {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
let joined: Vec<GroupKey> = registry
|
||||
.read(cx)
|
||||
.groups()
|
||||
.iter()
|
||||
.map(|group| group.read(cx).key().clone())
|
||||
.collect();
|
||||
|
||||
let contacts: Vec<GroupCandidate> = self
|
||||
.contacts
|
||||
.iter()
|
||||
.filter(|candidate| !joined.contains(&candidate.key))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let count = contacts.len();
|
||||
(contacts, count)
|
||||
} else {
|
||||
(Vec::new(), 0)
|
||||
};
|
||||
|
||||
let body = if from_contacts {
|
||||
if contact_count > 0 {
|
||||
uniform_list(
|
||||
"browse-contacts",
|
||||
contact_count,
|
||||
cx.processor(move |this, range, _window, cx| {
|
||||
this.render_rows(&contacts, true, range, cx)
|
||||
}),
|
||||
)
|
||||
.h_full()
|
||||
.into_any_element()
|
||||
} else if self.contacts_loading {
|
||||
notice("Loading communities from your contacts…", cx)
|
||||
} else {
|
||||
notice("No communities from your contacts.", cx)
|
||||
}
|
||||
} else if count > 0 {
|
||||
uniform_list(
|
||||
"browse-groups",
|
||||
count,
|
||||
cx.processor(|this, range, _window, cx| this.render_rows(range, cx)),
|
||||
cx.processor(|this, range, _window, cx| {
|
||||
this.render_rows(&this.candidates, false, range, cx)
|
||||
}),
|
||||
)
|
||||
.h_full()
|
||||
.into_any_element()
|
||||
@@ -303,10 +407,21 @@ impl Render for BrowsePanel {
|
||||
this.browse(window, cx);
|
||||
})),
|
||||
)
|
||||
.when(self.loading, |this| {
|
||||
this.child(Indicator::new().small().color(cx.theme().icon_accent))
|
||||
}),
|
||||
.when(
|
||||
self.loading || (from_contacts && self.contacts_loading),
|
||||
|this| this.child(Indicator::new().small().color(cx.theme().icon_accent)),
|
||||
),
|
||||
)
|
||||
.when(from_contacts && contact_count > 0, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.px_3()
|
||||
.pb_1()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child("From your contacts"),
|
||||
)
|
||||
})
|
||||
.child(div().flex_1().min_h_0().child(body))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user