From d7bac3cea6ec08aabccb866db1eb593b376cc1aa Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 10 Oct 2022 11:36:39 +0200 Subject: [PATCH] Style incoming call notification --- .../src/incoming_call_notification.rs | 85 ++++++++++++++----- crates/gpui/src/platform.rs | 2 + crates/gpui/src/platform/mac/platform.rs | 14 ++- crates/gpui/src/platform/test.rs | 4 + crates/theme/src/theme.rs | 6 ++ .../src/styleTree/incomingCallNotification.ts | 28 ++++-- 6 files changed, 111 insertions(+), 28 deletions(-) diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index 47fe8cbbfbdc5976a144d0790603b2f1afb20850..a396f8728a9d45460c19a4ea9615210c85a64dc5 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -3,8 +3,8 @@ use futures::StreamExt; use gpui::{ elements::*, geometry::{rect::RectF, vector::vec2f}, - impl_internal_actions, Entity, MouseButton, MutableAppContext, RenderContext, View, - ViewContext, WindowBounds, WindowKind, WindowOptions, + impl_internal_actions, CursorStyle, Entity, MouseButton, MutableAppContext, RenderContext, + View, ViewContext, WindowBounds, WindowKind, WindowOptions, }; use settings::Settings; use util::ResultExt; @@ -24,11 +24,17 @@ pub fn init(cx: &mut MutableAppContext) { } if let Some(incoming_call) = incoming_call { + const PADDING: f32 = 16.; + let screen_size = cx.platform().screen_size(); + let window_size = vec2f(304., 64.); let (window_id, _) = cx.add_window( WindowOptions { - bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(300., 400.))), + bounds: WindowBounds::Fixed(RectF::new( + vec2f(screen_size.x() - window_size.x() - PADDING, PADDING), + window_size, + )), titlebar: None, - center: true, + center: false, kind: WindowKind::PopUp, is_movable: false, }, @@ -84,22 +90,40 @@ impl IncomingCallNotification { fn render_caller(&self, cx: &mut RenderContext) -> ElementBox { let theme = &cx.global::().theme.incoming_call_notification; Flex::row() - .with_children( - self.call - .caller - .avatar - .clone() - .map(|avatar| Image::new(avatar).with_style(theme.caller_avatar).boxed()), - ) + .with_children(self.call.caller.avatar.clone().map(|avatar| { + Image::new(avatar) + .with_style(theme.caller_avatar) + .aligned() + .boxed() + })) .with_child( - Label::new( - self.call.caller.github_login.clone(), - theme.caller_username.text.clone(), - ) - .contained() - .with_style(theme.caller_username.container) - .boxed(), + Flex::column() + .with_child( + Label::new( + self.call.caller.github_login.clone(), + theme.caller_username.text.clone(), + ) + .contained() + .with_style(theme.caller_username.container) + .boxed(), + ) + .with_child( + Label::new( + "Incoming Zed call...".into(), + theme.caller_message.text.clone(), + ) + .contained() + .with_style(theme.caller_message.container) + .boxed(), + ) + .contained() + .with_style(theme.caller_metadata) + .aligned() + .boxed(), ) + .contained() + .with_style(theme.caller_container) + .flex(1., true) .boxed() } @@ -107,33 +131,46 @@ impl IncomingCallNotification { enum Accept {} enum Decline {} - Flex::row() + Flex::column() .with_child( MouseEventHandler::::new(0, cx, |_, cx| { let theme = &cx.global::().theme.incoming_call_notification; Label::new("Accept".to_string(), theme.accept_button.text.clone()) + .aligned() .contained() .with_style(theme.accept_button.container) .boxed() }) + .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, |_, cx| { cx.dispatch_action(RespondToCall { accept: true }); }) + .flex(1., true) .boxed(), ) .with_child( MouseEventHandler::::new(0, cx, |_, cx| { let theme = &cx.global::().theme.incoming_call_notification; Label::new("Decline".to_string(), theme.decline_button.text.clone()) + .aligned() .contained() .with_style(theme.decline_button.container) .boxed() }) + .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, |_, cx| { cx.dispatch_action(RespondToCall { accept: false }); }) + .flex(1., true) .boxed(), ) + .constrained() + .with_width( + cx.global::() + .theme + .incoming_call_notification + .button_width, + ) .boxed() } } @@ -148,9 +185,17 @@ impl View for IncomingCallNotification { } fn render(&mut self, cx: &mut RenderContext) -> gpui::ElementBox { - Flex::column() + let background = cx + .global::() + .theme + .incoming_call_notification + .background; + Flex::row() .with_child(self.render_caller(cx)) .with_child(self.render_buttons(cx)) + .contained() + .with_background_color(background) + .expanded() .boxed() } } diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index a50698070c1ecd472041d1a2db6c7ee2ed600fcd..a0e8cedfe91ee2c79101b5ba1ee0762cb9af5632 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -44,6 +44,8 @@ pub trait Platform: Send + Sync { fn unhide_other_apps(&self); fn quit(&self); + fn screen_size(&self) -> Vector2F; + fn open_window( &self, id: usize, diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 7732da2b3efe9da6e9c584e77d82c99cf85f0334..cf2aeff466d34bd2918af25dd4e67704fd444f9d 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -2,7 +2,9 @@ use super::{ event::key_to_native, status_item::StatusItem, BoolExt as _, Dispatcher, FontSystem, Window, }; use crate::{ - executor, keymap, + executor, + geometry::vector::{vec2f, Vector2F}, + keymap, platform::{self, CursorStyle}, Action, ClipboardItem, Event, Menu, MenuItem, }; @@ -12,7 +14,7 @@ use cocoa::{ appkit::{ NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, - NSPasteboardTypeString, NSSavePanel, NSWindow, + NSPasteboardTypeString, NSSavePanel, NSScreen, NSWindow, }, base::{id, nil, selector, YES}, foundation::{ @@ -485,6 +487,14 @@ impl platform::Platform for MacPlatform { } } + fn screen_size(&self) -> Vector2F { + unsafe { + let screen = NSScreen::mainScreen(nil); + let frame = NSScreen::frame(screen); + vec2f(frame.size.width as f32, frame.size.height as f32) + } + } + fn open_window( &self, id: usize, diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index 9a458a1dd96609c70c6acc4ffed2e69b6e44faa3..613a2117b9845559ff0ee29388636fc43b3f0fbe 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -131,6 +131,10 @@ impl super::Platform for Platform { fn quit(&self) {} + fn screen_size(&self) -> Vector2F { + vec2f(1024., 768.) + } + fn open_window( &self, _: usize, diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index d69720322eb80fa9edac6f12fe61bcff11ea072e..3f9b64ce565c181a06f8626c88a14733bb896ae3 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -479,8 +479,14 @@ pub struct ProjectSharedNotification { #[derive(Deserialize, Default)] pub struct IncomingCallNotification { + #[serde(default)] + pub background: Color, + pub caller_container: ContainerStyle, pub caller_avatar: ImageStyle, + pub caller_metadata: ContainerStyle, pub caller_username: ContainedText, + pub caller_message: ContainedText, + pub button_width: f32, pub accept_button: ContainedText, pub decline_button: ContainedText, } diff --git a/styles/src/styleTree/incomingCallNotification.ts b/styles/src/styleTree/incomingCallNotification.ts index dcae47bff0b90ceb52809d99379ac97abf8e6964..d8ea7dbad90ccf84b760a39e9ea7581de71ccc6c 100644 --- a/styles/src/styleTree/incomingCallNotification.ts +++ b/styles/src/styleTree/incomingCallNotification.ts @@ -1,22 +1,38 @@ import Theme from "../themes/common/theme"; -import { text } from "./components"; +import { backgroundColor, borderColor, text } from "./components"; export default function incomingCallNotification(theme: Theme): Object { - const avatarSize = 12; + const avatarSize = 32; return { + background: backgroundColor(theme, 300), + callerContainer: { + padding: 12, + }, callerAvatar: { height: avatarSize, width: avatarSize, - cornerRadius: 6, + cornerRadius: avatarSize / 2, + }, + callerMetadata: { + margin: { left: 10 }, }, callerUsername: { - ...text(theme, "sans", "primary", { size: "xs" }), + ...text(theme, "sans", "active", { size: "sm", weight: "bold" }), + margin: { top: -3 }, + }, + callerMessage: { + ...text(theme, "sans", "secondary", { size: "xs" }), + margin: { top: -3 }, }, + buttonWidth: 96, acceptButton: { - ...text(theme, "sans", "primary", { size: "xs" }) + background: backgroundColor(theme, "ok", "active"), + border: { left: true, bottom: true, width: 1, color: borderColor(theme, "primary") }, + ...text(theme, "sans", "ok", { size: "xs", weight: "extra_bold" }) }, declineButton: { - ...text(theme, "sans", "primary", { size: "xs" }) + border: { left: true, width: 1, color: borderColor(theme, "primary") }, + ...text(theme, "sans", "error", { size: "xs", weight: "extra_bold" }) }, }; }