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