project_shared_notification.rs

  1use call::{room, ActiveCall};
  2use client::User;
  3use gpui::{
  4    actions,
  5    elements::*,
  6    geometry::{rect::RectF, vector::vec2f},
  7    Entity, MouseButton, MutableAppContext, RenderContext, View, ViewContext, WindowBounds,
  8    WindowKind, WindowOptions,
  9};
 10use project::Project;
 11use settings::Settings;
 12use std::sync::Arc;
 13use workspace::{AppState, Workspace};
 14
 15actions!(project_shared_notification, [JoinProject, DismissProject]);
 16
 17pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
 18    cx.add_action(ProjectSharedNotification::join);
 19    cx.add_action(ProjectSharedNotification::dismiss);
 20
 21    let active_call = ActiveCall::global(cx);
 22    let mut _room_subscription = None;
 23    cx.observe(&active_call, move |active_call, cx| {
 24        if let Some(room) = active_call.read(cx).room().cloned() {
 25            let app_state = app_state.clone();
 26            _room_subscription = Some(cx.subscribe(&room, move |_, event, cx| match event {
 27                room::Event::RemoteProjectShared { owner, project_id } => {
 28                    cx.add_window(
 29                        WindowOptions {
 30                            bounds: WindowBounds::Fixed(RectF::new(
 31                                vec2f(0., 0.),
 32                                vec2f(300., 400.),
 33                            )),
 34                            titlebar: None,
 35                            center: true,
 36                            kind: WindowKind::PopUp,
 37                            is_movable: false,
 38                        },
 39                        |_| {
 40                            ProjectSharedNotification::new(
 41                                *project_id,
 42                                owner.clone(),
 43                                app_state.clone(),
 44                            )
 45                        },
 46                    );
 47                }
 48            }));
 49        } else {
 50            _room_subscription = None;
 51        }
 52    })
 53    .detach();
 54}
 55
 56pub struct ProjectSharedNotification {
 57    project_id: u64,
 58    owner: Arc<User>,
 59    app_state: Arc<AppState>,
 60}
 61
 62impl ProjectSharedNotification {
 63    fn new(project_id: u64, owner: Arc<User>, app_state: Arc<AppState>) -> Self {
 64        Self {
 65            project_id,
 66            owner,
 67            app_state,
 68        }
 69    }
 70
 71    fn join(&mut self, _: &JoinProject, cx: &mut ViewContext<Self>) {
 72        let project_id = self.project_id;
 73        let app_state = self.app_state.clone();
 74        cx.spawn_weak(|_, mut cx| async move {
 75            let project = Project::remote(
 76                project_id,
 77                app_state.client.clone(),
 78                app_state.user_store.clone(),
 79                app_state.project_store.clone(),
 80                app_state.languages.clone(),
 81                app_state.fs.clone(),
 82                cx.clone(),
 83            )
 84            .await?;
 85
 86            cx.add_window((app_state.build_window_options)(), |cx| {
 87                let mut workspace = Workspace::new(project, app_state.default_item_factory, cx);
 88                (app_state.initialize_workspace)(&mut workspace, &app_state, cx);
 89                workspace
 90            });
 91
 92            anyhow::Ok(())
 93        })
 94        .detach_and_log_err(cx);
 95
 96        let window_id = cx.window_id();
 97        cx.remove_window(window_id);
 98    }
 99
100    fn dismiss(&mut self, _: &DismissProject, cx: &mut ViewContext<Self>) {
101        let window_id = cx.window_id();
102        cx.remove_window(window_id);
103    }
104
105    fn render_owner(&self, cx: &mut RenderContext<Self>) -> ElementBox {
106        let theme = &cx.global::<Settings>().theme.project_shared_notification;
107        Flex::row()
108            .with_children(
109                self.owner
110                    .avatar
111                    .clone()
112                    .map(|avatar| Image::new(avatar).with_style(theme.owner_avatar).boxed()),
113            )
114            .with_child(
115                Label::new(
116                    format!("{} has shared a new project", self.owner.github_login),
117                    theme.message.text.clone(),
118                )
119                .boxed(),
120            )
121            .boxed()
122    }
123
124    fn render_buttons(&self, cx: &mut RenderContext<Self>) -> ElementBox {
125        enum Join {}
126        enum Dismiss {}
127
128        Flex::row()
129            .with_child(
130                MouseEventHandler::<Join>::new(0, cx, |_, cx| {
131                    let theme = &cx.global::<Settings>().theme.project_shared_notification;
132                    Label::new("Join".to_string(), theme.join_button.text.clone())
133                        .contained()
134                        .with_style(theme.join_button.container)
135                        .boxed()
136                })
137                .on_click(MouseButton::Left, |_, cx| {
138                    cx.dispatch_action(JoinProject);
139                })
140                .boxed(),
141            )
142            .with_child(
143                MouseEventHandler::<Dismiss>::new(0, cx, |_, cx| {
144                    let theme = &cx.global::<Settings>().theme.project_shared_notification;
145                    Label::new("Dismiss".to_string(), theme.dismiss_button.text.clone())
146                        .contained()
147                        .with_style(theme.dismiss_button.container)
148                        .boxed()
149                })
150                .on_click(MouseButton::Left, |_, cx| {
151                    cx.dispatch_action(DismissProject);
152                })
153                .boxed(),
154            )
155            .boxed()
156    }
157}
158
159impl Entity for ProjectSharedNotification {
160    type Event = ();
161}
162
163impl View for ProjectSharedNotification {
164    fn ui_name() -> &'static str {
165        "ProjectSharedNotification"
166    }
167
168    fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
169        Flex::row()
170            .with_child(self.render_owner(cx))
171            .with_child(self.render_buttons(cx))
172            .boxed()
173    }
174}