mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 01:21:47 +03:00
Add notifications for accepted contact requests
Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
a5fd664b00
commit
3bc9b8ec85
@ -1687,7 +1687,7 @@
|
||||
"left": 6
|
||||
}
|
||||
},
|
||||
"incoming_request_notification": {
|
||||
"contact_notification": {
|
||||
"header_avatar": {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
|
@ -1687,7 +1687,7 @@
|
||||
"left": 6
|
||||
}
|
||||
},
|
||||
"incoming_request_notification": {
|
||||
"contact_notification": {
|
||||
"header_avatar": {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
|
@ -1687,7 +1687,7 @@
|
||||
"left": 6
|
||||
}
|
||||
},
|
||||
"incoming_request_notification": {
|
||||
"contact_notification": {
|
||||
"header_avatar": {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
|
@ -1687,7 +1687,7 @@
|
||||
"left": 6
|
||||
}
|
||||
},
|
||||
"incoming_request_notification": {
|
||||
"contact_notification": {
|
||||
"header_avatar": {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
|
@ -1687,7 +1687,7 @@
|
||||
"left": 6
|
||||
}
|
||||
},
|
||||
"incoming_request_notification": {
|
||||
"contact_notification": {
|
||||
"header_avatar": {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
|
@ -1687,7 +1687,7 @@
|
||||
"left": 6
|
||||
}
|
||||
},
|
||||
"incoming_request_notification": {
|
||||
"contact_notification": {
|
||||
"header_avatar": {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
|
@ -1687,7 +1687,7 @@
|
||||
"left": 6
|
||||
}
|
||||
},
|
||||
"incoming_request_notification": {
|
||||
"contact_notification": {
|
||||
"header_avatar": {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
|
@ -1687,7 +1687,7 @@
|
||||
"left": 6
|
||||
}
|
||||
},
|
||||
"incoming_request_notification": {
|
||||
"contact_notification": {
|
||||
"header_avatar": {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
|
@ -54,13 +54,21 @@ pub struct UserStore {
|
||||
_maintain_current_user: Task<()>,
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
ContactRequested(Arc<User>),
|
||||
ContactRequestCancelled(Arc<User>),
|
||||
#[derive(Clone)]
|
||||
pub struct ContactEvent {
|
||||
pub user: Arc<User>,
|
||||
pub kind: ContactEventKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ContactEventKind {
|
||||
Requested,
|
||||
Accepted,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
impl Entity for UserStore {
|
||||
type Event = Event;
|
||||
type Event = ContactEvent;
|
||||
}
|
||||
|
||||
enum UpdateContacts {
|
||||
@ -178,8 +186,10 @@ impl UserStore {
|
||||
// No need to paralellize here
|
||||
let mut updated_contacts = Vec::new();
|
||||
for contact in message.contacts {
|
||||
updated_contacts.push(Arc::new(
|
||||
Contact::from_proto(contact, &this, &mut cx).await?,
|
||||
let should_notify = contact.should_notify;
|
||||
updated_contacts.push((
|
||||
Arc::new(Contact::from_proto(contact, &this, &mut cx).await?),
|
||||
should_notify,
|
||||
));
|
||||
}
|
||||
|
||||
@ -215,7 +225,13 @@ impl UserStore {
|
||||
this.contacts
|
||||
.retain(|contact| !removed_contacts.contains(&contact.user.id));
|
||||
// Update existing contacts and insert new ones
|
||||
for updated_contact in updated_contacts {
|
||||
for (updated_contact, should_notify) in updated_contacts {
|
||||
if should_notify {
|
||||
cx.emit(ContactEvent {
|
||||
user: updated_contact.user.clone(),
|
||||
kind: ContactEventKind::Accepted,
|
||||
});
|
||||
}
|
||||
match this.contacts.binary_search_by_key(
|
||||
&&updated_contact.user.github_login,
|
||||
|contact| &contact.user.github_login,
|
||||
@ -228,7 +244,10 @@ impl UserStore {
|
||||
// Remove incoming contact requests
|
||||
this.incoming_contact_requests.retain(|user| {
|
||||
if removed_incoming_requests.contains(&user.id) {
|
||||
cx.emit(Event::ContactRequestCancelled(user.clone()));
|
||||
cx.emit(ContactEvent {
|
||||
user: user.clone(),
|
||||
kind: ContactEventKind::Cancelled,
|
||||
});
|
||||
false
|
||||
} else {
|
||||
true
|
||||
@ -237,7 +256,10 @@ impl UserStore {
|
||||
// Update existing incoming requests and insert new ones
|
||||
for (user, should_notify) in incoming_requests {
|
||||
if should_notify {
|
||||
cx.emit(Event::ContactRequested(user.clone()));
|
||||
cx.emit(ContactEvent {
|
||||
user: user.clone(),
|
||||
kind: ContactEventKind::Requested,
|
||||
});
|
||||
}
|
||||
|
||||
match this
|
||||
|
@ -420,7 +420,7 @@ impl Server {
|
||||
async fn update_user_contacts(self: &Arc<Server>, user_id: UserId) -> Result<()> {
|
||||
let contacts = self.app_state.db.get_contacts(user_id).await?;
|
||||
let store = self.store().await;
|
||||
let updated_contact = store.contact_for_user(user_id);
|
||||
let updated_contact = store.contact_for_user(user_id, false);
|
||||
for contact in contacts {
|
||||
if let db::Contact::Accepted {
|
||||
user_id: contact_user_id,
|
||||
@ -1049,7 +1049,9 @@ impl Server {
|
||||
// Update responder with new contact
|
||||
let mut update = proto::UpdateContacts::default();
|
||||
if accept {
|
||||
update.contacts.push(store.contact_for_user(requester_id));
|
||||
update
|
||||
.contacts
|
||||
.push(store.contact_for_user(requester_id, false));
|
||||
}
|
||||
update
|
||||
.remove_incoming_requests
|
||||
@ -1061,7 +1063,9 @@ impl Server {
|
||||
// Update requester with new contact
|
||||
let mut update = proto::UpdateContacts::default();
|
||||
if accept {
|
||||
update.contacts.push(store.contact_for_user(responder_id));
|
||||
update
|
||||
.contacts
|
||||
.push(store.contact_for_user(responder_id, true));
|
||||
}
|
||||
update
|
||||
.remove_outgoing_requests
|
||||
|
@ -225,8 +225,13 @@ impl Store {
|
||||
|
||||
for contact in contacts {
|
||||
match contact {
|
||||
db::Contact::Accepted { user_id, .. } => {
|
||||
update.contacts.push(self.contact_for_user(user_id));
|
||||
db::Contact::Accepted {
|
||||
user_id,
|
||||
should_notify,
|
||||
} => {
|
||||
update
|
||||
.contacts
|
||||
.push(self.contact_for_user(user_id, should_notify));
|
||||
}
|
||||
db::Contact::Outgoing { user_id } => {
|
||||
update.outgoing_requests.push(user_id.to_proto())
|
||||
@ -246,11 +251,12 @@ impl Store {
|
||||
update
|
||||
}
|
||||
|
||||
pub fn contact_for_user(&self, user_id: UserId) -> proto::Contact {
|
||||
pub fn contact_for_user(&self, user_id: UserId, should_notify: bool) -> proto::Contact {
|
||||
proto::Contact {
|
||||
user_id: user_id.to_proto(),
|
||||
projects: self.project_metadata_for_user(user_id),
|
||||
online: self.is_user_online(user_id),
|
||||
should_notify,
|
||||
}
|
||||
}
|
||||
|
||||
|
224
crates/contacts_panel/src/contact_notification.rs
Normal file
224
crates/contacts_panel/src/contact_notification.rs
Normal file
@ -0,0 +1,224 @@
|
||||
use client::{ContactEvent, ContactEventKind, UserStore};
|
||||
use gpui::{
|
||||
elements::*, impl_internal_actions, platform::CursorStyle, Entity, ModelHandle,
|
||||
MutableAppContext, RenderContext, View, ViewContext,
|
||||
};
|
||||
use settings::Settings;
|
||||
use workspace::Notification;
|
||||
|
||||
impl_internal_actions!(contact_notifications, [Dismiss, RespondToContactRequest]);
|
||||
|
||||
pub fn init(cx: &mut MutableAppContext) {
|
||||
cx.add_action(ContactNotification::dismiss);
|
||||
cx.add_action(ContactNotification::respond_to_contact_request);
|
||||
}
|
||||
|
||||
pub struct ContactNotification {
|
||||
user_store: ModelHandle<UserStore>,
|
||||
event: ContactEvent,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Dismiss(u64);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RespondToContactRequest {
|
||||
pub user_id: u64,
|
||||
pub accept: bool,
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
Dismiss,
|
||||
}
|
||||
|
||||
enum Reject {}
|
||||
enum Accept {}
|
||||
|
||||
impl Entity for ContactNotification {
|
||||
type Event = Event;
|
||||
}
|
||||
|
||||
impl View for ContactNotification {
|
||||
fn ui_name() -> &'static str {
|
||||
"ContactNotification"
|
||||
}
|
||||
|
||||
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
||||
match self.event.kind {
|
||||
ContactEventKind::Requested => self.render_incoming_request(cx),
|
||||
ContactEventKind::Accepted => self.render_acceptance(cx),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Notification for ContactNotification {
|
||||
fn should_dismiss_notification_on_event(&self, event: &<Self as Entity>::Event) -> bool {
|
||||
matches!(event, Event::Dismiss)
|
||||
}
|
||||
}
|
||||
|
||||
impl ContactNotification {
|
||||
pub fn new(
|
||||
event: ContactEvent,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
cx.subscribe(&user_store, move |this, _, event, cx| {
|
||||
if let client::ContactEvent {
|
||||
kind: ContactEventKind::Cancelled,
|
||||
user,
|
||||
} = event
|
||||
{
|
||||
if user.id == this.event.user.id {
|
||||
cx.emit(Event::Dismiss);
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
Self { event, user_store }
|
||||
}
|
||||
|
||||
fn render_incoming_request(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
||||
let theme = cx.global::<Settings>().theme.clone();
|
||||
let theme = &theme.contact_notification;
|
||||
let user = &self.event.user;
|
||||
let user_id = user.id;
|
||||
|
||||
Flex::column()
|
||||
.with_child(self.render_header("added you", theme, cx))
|
||||
.with_child(
|
||||
Label::new(
|
||||
"They won't know if you decline.".to_string(),
|
||||
theme.body_message.text.clone(),
|
||||
)
|
||||
.contained()
|
||||
.with_style(theme.body_message.container)
|
||||
.boxed(),
|
||||
)
|
||||
.with_child(
|
||||
Flex::row()
|
||||
.with_child(
|
||||
MouseEventHandler::new::<Reject, _, _>(
|
||||
self.event.user.id as usize,
|
||||
cx,
|
||||
|_, _| {
|
||||
Label::new("Reject".to_string(), theme.button.text.clone())
|
||||
.contained()
|
||||
.with_style(theme.button.container)
|
||||
.boxed()
|
||||
},
|
||||
)
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(move |_, cx| {
|
||||
cx.dispatch_action(RespondToContactRequest {
|
||||
user_id,
|
||||
accept: false,
|
||||
});
|
||||
})
|
||||
.boxed(),
|
||||
)
|
||||
.with_child(
|
||||
MouseEventHandler::new::<Accept, _, _>(user.id as usize, cx, |_, _| {
|
||||
Label::new("Accept".to_string(), theme.button.text.clone())
|
||||
.contained()
|
||||
.with_style(theme.button.container)
|
||||
.boxed()
|
||||
})
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(move |_, cx| {
|
||||
cx.dispatch_action(RespondToContactRequest {
|
||||
user_id,
|
||||
accept: true,
|
||||
});
|
||||
})
|
||||
.boxed(),
|
||||
)
|
||||
.aligned()
|
||||
.right()
|
||||
.boxed(),
|
||||
)
|
||||
.contained()
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn render_acceptance(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
||||
let theme = cx.global::<Settings>().theme.clone();
|
||||
let theme = &theme.contact_notification;
|
||||
|
||||
self.render_header("accepted your contact request", theme, cx)
|
||||
}
|
||||
|
||||
fn render_header(
|
||||
&self,
|
||||
message: &'static str,
|
||||
theme: &theme::ContactNotification,
|
||||
cx: &mut RenderContext<Self>,
|
||||
) -> ElementBox {
|
||||
let user = &self.event.user;
|
||||
let user_id = user.id;
|
||||
Flex::row()
|
||||
.with_children(user.avatar.clone().map(|avatar| {
|
||||
Image::new(avatar)
|
||||
.with_style(theme.header_avatar)
|
||||
.aligned()
|
||||
.left()
|
||||
.boxed()
|
||||
}))
|
||||
.with_child(
|
||||
Label::new(
|
||||
format!("{} {}", user.github_login, message),
|
||||
theme.header_message.text.clone(),
|
||||
)
|
||||
.contained()
|
||||
.with_style(theme.header_message.container)
|
||||
.aligned()
|
||||
.boxed(),
|
||||
)
|
||||
.with_child(
|
||||
MouseEventHandler::new::<Dismiss, _, _>(user.id as usize, cx, |_, _| {
|
||||
Svg::new("icons/reject.svg")
|
||||
.with_color(theme.dismiss_button.color)
|
||||
.constrained()
|
||||
.with_width(theme.dismiss_button.icon_width)
|
||||
.aligned()
|
||||
.contained()
|
||||
.with_style(theme.dismiss_button.container)
|
||||
.constrained()
|
||||
.with_width(theme.dismiss_button.button_width)
|
||||
.with_height(theme.dismiss_button.button_width)
|
||||
.aligned()
|
||||
.boxed()
|
||||
})
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(move |_, cx| cx.dispatch_action(Dismiss(user_id)))
|
||||
.flex_float()
|
||||
.boxed(),
|
||||
)
|
||||
.constrained()
|
||||
.with_height(theme.header_height)
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext<Self>) {
|
||||
self.user_store.update(cx, |store, cx| {
|
||||
store
|
||||
.dismiss_contact_request(self.event.user.id, cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
cx.emit(Event::Dismiss);
|
||||
}
|
||||
|
||||
fn respond_to_contact_request(
|
||||
&mut self,
|
||||
action: &RespondToContactRequest,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.user_store
|
||||
.update(cx, |store, cx| {
|
||||
store.respond_to_contact_request(action.user_id, action.accept, cx)
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
@ -1,206 +0,0 @@
|
||||
use client::{User, UserStore};
|
||||
use gpui::{
|
||||
elements::*, impl_internal_actions, platform::CursorStyle, Entity, ModelHandle,
|
||||
MutableAppContext, RenderContext, View, ViewContext,
|
||||
};
|
||||
use settings::Settings;
|
||||
use std::sync::Arc;
|
||||
use workspace::Notification;
|
||||
|
||||
impl_internal_actions!(contact_notifications, [Dismiss, RespondToContactRequest]);
|
||||
|
||||
pub fn init(cx: &mut MutableAppContext) {
|
||||
cx.add_action(IncomingRequestNotification::dismiss);
|
||||
cx.add_action(IncomingRequestNotification::respond_to_contact_request);
|
||||
}
|
||||
|
||||
pub struct IncomingRequestNotification {
|
||||
user: Arc<User>,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Dismiss(u64);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RespondToContactRequest {
|
||||
pub user_id: u64,
|
||||
pub accept: bool,
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
Dismiss,
|
||||
}
|
||||
|
||||
impl Entity for IncomingRequestNotification {
|
||||
type Event = Event;
|
||||
}
|
||||
|
||||
impl View for IncomingRequestNotification {
|
||||
fn ui_name() -> &'static str {
|
||||
"IncomingRequestNotification"
|
||||
}
|
||||
|
||||
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
||||
enum Dismiss {}
|
||||
enum Reject {}
|
||||
enum Accept {}
|
||||
|
||||
let theme = cx.global::<Settings>().theme.clone();
|
||||
let theme = &theme.incoming_request_notification;
|
||||
let user_id = self.user.id;
|
||||
|
||||
Flex::column()
|
||||
.with_child(
|
||||
Flex::row()
|
||||
.with_children(self.user.avatar.clone().map(|avatar| {
|
||||
Image::new(avatar)
|
||||
.with_style(theme.header_avatar)
|
||||
.aligned()
|
||||
.left()
|
||||
.boxed()
|
||||
}))
|
||||
.with_child(
|
||||
Label::new(
|
||||
format!("{} added you", self.user.github_login),
|
||||
theme.header_message.text.clone(),
|
||||
)
|
||||
.contained()
|
||||
.with_style(theme.header_message.container)
|
||||
.aligned()
|
||||
.boxed(),
|
||||
)
|
||||
.with_child(
|
||||
MouseEventHandler::new::<Dismiss, _, _>(
|
||||
self.user.id as usize,
|
||||
cx,
|
||||
|_, _| {
|
||||
Svg::new("icons/reject.svg")
|
||||
.with_color(theme.dismiss_button.color)
|
||||
.constrained()
|
||||
.with_width(theme.dismiss_button.icon_width)
|
||||
.aligned()
|
||||
.contained()
|
||||
.with_style(theme.dismiss_button.container)
|
||||
.constrained()
|
||||
.with_width(theme.dismiss_button.button_width)
|
||||
.with_height(theme.dismiss_button.button_width)
|
||||
.aligned()
|
||||
.boxed()
|
||||
},
|
||||
)
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(move |_, cx| cx.dispatch_action(Dismiss(user_id)))
|
||||
.flex_float()
|
||||
.boxed(),
|
||||
)
|
||||
.constrained()
|
||||
.with_height(theme.header_height)
|
||||
.boxed(),
|
||||
)
|
||||
.with_child(
|
||||
Label::new(
|
||||
"They won't know if you decline.".to_string(),
|
||||
theme.body_message.text.clone(),
|
||||
)
|
||||
.contained()
|
||||
.with_style(theme.body_message.container)
|
||||
.boxed(),
|
||||
)
|
||||
.with_child(
|
||||
Flex::row()
|
||||
.with_child(
|
||||
MouseEventHandler::new::<Reject, _, _>(
|
||||
self.user.id as usize,
|
||||
cx,
|
||||
|_, _| {
|
||||
Label::new("Reject".to_string(), theme.button.text.clone())
|
||||
.contained()
|
||||
.with_style(theme.button.container)
|
||||
.boxed()
|
||||
},
|
||||
)
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(move |_, cx| {
|
||||
cx.dispatch_action(RespondToContactRequest {
|
||||
user_id,
|
||||
accept: false,
|
||||
});
|
||||
})
|
||||
.boxed(),
|
||||
)
|
||||
.with_child(
|
||||
MouseEventHandler::new::<Accept, _, _>(
|
||||
self.user.id as usize,
|
||||
cx,
|
||||
|_, _| {
|
||||
Label::new("Accept".to_string(), theme.button.text.clone())
|
||||
.contained()
|
||||
.with_style(theme.button.container)
|
||||
.boxed()
|
||||
},
|
||||
)
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(move |_, cx| {
|
||||
cx.dispatch_action(RespondToContactRequest {
|
||||
user_id,
|
||||
accept: true,
|
||||
});
|
||||
})
|
||||
.boxed(),
|
||||
)
|
||||
.aligned()
|
||||
.right()
|
||||
.boxed(),
|
||||
)
|
||||
.contained()
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
impl Notification for IncomingRequestNotification {
|
||||
fn should_dismiss_notification_on_event(&self, event: &<Self as Entity>::Event) -> bool {
|
||||
matches!(event, Event::Dismiss)
|
||||
}
|
||||
}
|
||||
|
||||
impl IncomingRequestNotification {
|
||||
pub fn new(
|
||||
user: Arc<User>,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
let user_id = user.id;
|
||||
cx.subscribe(&user_store, move |_, _, event, cx| {
|
||||
if let client::Event::ContactRequestCancelled(user) = event {
|
||||
if user.id == user_id {
|
||||
cx.emit(Event::Dismiss);
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
Self { user, user_store }
|
||||
}
|
||||
|
||||
fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext<Self>) {
|
||||
self.user_store.update(cx, |store, cx| {
|
||||
store
|
||||
.dismiss_contact_request(self.user.id, cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
cx.emit(Event::Dismiss);
|
||||
}
|
||||
|
||||
fn respond_to_contact_request(
|
||||
&mut self,
|
||||
action: &RespondToContactRequest,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.user_store
|
||||
.update(cx, |store, cx| {
|
||||
store.respond_to_contact_request(action.user_id, action.accept, cx)
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
mod contact_finder;
|
||||
mod contact_notifications;
|
||||
mod contact_notification;
|
||||
|
||||
use client::{Contact, User, UserStore};
|
||||
use contact_notifications::IncomingRequestNotification;
|
||||
use client::{Contact, ContactEventKind, User, UserStore};
|
||||
use contact_notification::ContactNotification;
|
||||
use editor::{Cancel, Editor};
|
||||
use fuzzy::{match_strings, StringMatchCandidate};
|
||||
use gpui::{
|
||||
@ -55,7 +55,7 @@ pub struct RespondToContactRequest {
|
||||
|
||||
pub fn init(cx: &mut MutableAppContext) {
|
||||
contact_finder::init(cx);
|
||||
contact_notifications::init(cx);
|
||||
contact_notification::init(cx);
|
||||
cx.add_action(ContactsPanel::request_contact);
|
||||
cx.add_action(ContactsPanel::remove_contact);
|
||||
cx.add_action(ContactsPanel::respond_to_contact_request);
|
||||
@ -85,25 +85,22 @@ impl ContactsPanel {
|
||||
.detach();
|
||||
|
||||
cx.subscribe(&app_state.user_store, {
|
||||
let user_store = app_state.user_store.clone();
|
||||
move |_, _, event, cx| match event {
|
||||
client::Event::ContactRequested(user) => {
|
||||
if let Some(workspace) = workspace.upgrade(cx) {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.show_notification(
|
||||
let user_store = app_state.user_store.downgrade();
|
||||
move |_, _, event, cx| {
|
||||
if let Some((workspace, user_store)) =
|
||||
workspace.upgrade(cx).zip(user_store.upgrade(cx))
|
||||
{
|
||||
workspace.update(cx, |workspace, cx| match event.kind {
|
||||
ContactEventKind::Requested | ContactEventKind::Accepted => workspace
|
||||
.show_notification(
|
||||
cx.add_view(|cx| {
|
||||
IncomingRequestNotification::new(
|
||||
user.clone(),
|
||||
user_store.clone(),
|
||||
cx,
|
||||
)
|
||||
ContactNotification::new(event.clone(), user_store, cx)
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
}
|
||||
),
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
@ -877,6 +877,7 @@ message Contact {
|
||||
uint64 user_id = 1;
|
||||
repeated ProjectMetadata projects = 2;
|
||||
bool online = 3;
|
||||
bool should_notify = 4;
|
||||
}
|
||||
|
||||
message ProjectMetadata {
|
||||
|
@ -29,7 +29,7 @@ pub struct Theme {
|
||||
pub search: Search,
|
||||
pub project_diagnostics: ProjectDiagnostics,
|
||||
pub breadcrumbs: ContainedText,
|
||||
pub incoming_request_notification: IncomingRequestNotification,
|
||||
pub contact_notification: ContactNotification,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
@ -357,7 +357,7 @@ pub struct ProjectDiagnostics {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct IncomingRequestNotification {
|
||||
pub struct ContactNotification {
|
||||
pub header_avatar: ImageStyle,
|
||||
pub header_message: ContainedText,
|
||||
pub header_height: f32,
|
||||
|
@ -10,7 +10,7 @@ import search from "./search";
|
||||
import picker from "./picker";
|
||||
import workspace from "./workspace";
|
||||
import projectDiagnostics from "./projectDiagnostics";
|
||||
import incomingRequestNotification from "./incomingRequestNotification";
|
||||
import contactNotification from "./contactNotification";
|
||||
|
||||
export const panel = {
|
||||
padding: { top: 12, left: 12, bottom: 12, right: 12 },
|
||||
@ -34,6 +34,6 @@ export default function app(theme: Theme): Object {
|
||||
left: 6,
|
||||
},
|
||||
},
|
||||
incomingRequestNotification: incomingRequestNotification(theme),
|
||||
contactNotification: contactNotification(theme),
|
||||
};
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Theme from "../themes/theme";
|
||||
import { backgroundColor, iconColor, text } from "./components";
|
||||
|
||||
export default function incomingRequestNotification(theme: Theme): Object {
|
||||
export default function contactNotification(theme: Theme): Object {
|
||||
return {
|
||||
headerAvatar: {
|
||||
height: 12,
|
Loading…
Reference in New Issue
Block a user