Style incoming call notification

This commit is contained in:
Antonio Scandurra 2022-10-10 11:36:39 +02:00
parent 79748803a9
commit d7bac3cea6
6 changed files with 111 additions and 28 deletions

View file

@ -3,8 +3,8 @@ use futures::StreamExt;
use gpui::{ use gpui::{
elements::*, elements::*,
geometry::{rect::RectF, vector::vec2f}, geometry::{rect::RectF, vector::vec2f},
impl_internal_actions, Entity, MouseButton, MutableAppContext, RenderContext, View, impl_internal_actions, CursorStyle, Entity, MouseButton, MutableAppContext, RenderContext,
ViewContext, WindowBounds, WindowKind, WindowOptions, View, ViewContext, WindowBounds, WindowKind, WindowOptions,
}; };
use settings::Settings; use settings::Settings;
use util::ResultExt; use util::ResultExt;
@ -24,11 +24,17 @@ pub fn init(cx: &mut MutableAppContext) {
} }
if let Some(incoming_call) = incoming_call { 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( let (window_id, _) = cx.add_window(
WindowOptions { 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, titlebar: None,
center: true, center: false,
kind: WindowKind::PopUp, kind: WindowKind::PopUp,
is_movable: false, is_movable: false,
}, },
@ -84,13 +90,14 @@ impl IncomingCallNotification {
fn render_caller(&self, cx: &mut RenderContext<Self>) -> ElementBox { fn render_caller(&self, cx: &mut RenderContext<Self>) -> ElementBox {
let theme = &cx.global::<Settings>().theme.incoming_call_notification; let theme = &cx.global::<Settings>().theme.incoming_call_notification;
Flex::row() Flex::row()
.with_children( .with_children(self.call.caller.avatar.clone().map(|avatar| {
self.call Image::new(avatar)
.caller .with_style(theme.caller_avatar)
.avatar .aligned()
.clone() .boxed()
.map(|avatar| Image::new(avatar).with_style(theme.caller_avatar).boxed()), }))
) .with_child(
Flex::column()
.with_child( .with_child(
Label::new( Label::new(
self.call.caller.github_login.clone(), self.call.caller.github_login.clone(),
@ -100,6 +107,23 @@ impl IncomingCallNotification {
.with_style(theme.caller_username.container) .with_style(theme.caller_username.container)
.boxed(), .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() .boxed()
} }
@ -107,33 +131,46 @@ impl IncomingCallNotification {
enum Accept {} enum Accept {}
enum Decline {} enum Decline {}
Flex::row() Flex::column()
.with_child( .with_child(
MouseEventHandler::<Accept>::new(0, cx, |_, cx| { MouseEventHandler::<Accept>::new(0, cx, |_, cx| {
let theme = &cx.global::<Settings>().theme.incoming_call_notification; let theme = &cx.global::<Settings>().theme.incoming_call_notification;
Label::new("Accept".to_string(), theme.accept_button.text.clone()) Label::new("Accept".to_string(), theme.accept_button.text.clone())
.aligned()
.contained() .contained()
.with_style(theme.accept_button.container) .with_style(theme.accept_button.container)
.boxed() .boxed()
}) })
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, |_, cx| { .on_click(MouseButton::Left, |_, cx| {
cx.dispatch_action(RespondToCall { accept: true }); cx.dispatch_action(RespondToCall { accept: true });
}) })
.flex(1., true)
.boxed(), .boxed(),
) )
.with_child( .with_child(
MouseEventHandler::<Decline>::new(0, cx, |_, cx| { MouseEventHandler::<Decline>::new(0, cx, |_, cx| {
let theme = &cx.global::<Settings>().theme.incoming_call_notification; let theme = &cx.global::<Settings>().theme.incoming_call_notification;
Label::new("Decline".to_string(), theme.decline_button.text.clone()) Label::new("Decline".to_string(), theme.decline_button.text.clone())
.aligned()
.contained() .contained()
.with_style(theme.decline_button.container) .with_style(theme.decline_button.container)
.boxed() .boxed()
}) })
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, |_, cx| { .on_click(MouseButton::Left, |_, cx| {
cx.dispatch_action(RespondToCall { accept: false }); cx.dispatch_action(RespondToCall { accept: false });
}) })
.flex(1., true)
.boxed(), .boxed(),
) )
.constrained()
.with_width(
cx.global::<Settings>()
.theme
.incoming_call_notification
.button_width,
)
.boxed() .boxed()
} }
} }
@ -148,9 +185,17 @@ impl View for IncomingCallNotification {
} }
fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox { fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
Flex::column() let background = cx
.global::<Settings>()
.theme
.incoming_call_notification
.background;
Flex::row()
.with_child(self.render_caller(cx)) .with_child(self.render_caller(cx))
.with_child(self.render_buttons(cx)) .with_child(self.render_buttons(cx))
.contained()
.with_background_color(background)
.expanded()
.boxed() .boxed()
} }
} }

View file

@ -44,6 +44,8 @@ pub trait Platform: Send + Sync {
fn unhide_other_apps(&self); fn unhide_other_apps(&self);
fn quit(&self); fn quit(&self);
fn screen_size(&self) -> Vector2F;
fn open_window( fn open_window(
&self, &self,
id: usize, id: usize,

View file

@ -2,7 +2,9 @@ use super::{
event::key_to_native, status_item::StatusItem, BoolExt as _, Dispatcher, FontSystem, Window, event::key_to_native, status_item::StatusItem, BoolExt as _, Dispatcher, FontSystem, Window,
}; };
use crate::{ use crate::{
executor, keymap, executor,
geometry::vector::{vec2f, Vector2F},
keymap,
platform::{self, CursorStyle}, platform::{self, CursorStyle},
Action, ClipboardItem, Event, Menu, MenuItem, Action, ClipboardItem, Event, Menu, MenuItem,
}; };
@ -12,7 +14,7 @@ use cocoa::{
appkit::{ appkit::{
NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular,
NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard,
NSPasteboardTypeString, NSSavePanel, NSWindow, NSPasteboardTypeString, NSSavePanel, NSScreen, NSWindow,
}, },
base::{id, nil, selector, YES}, base::{id, nil, selector, YES},
foundation::{ 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( fn open_window(
&self, &self,
id: usize, id: usize,

View file

@ -131,6 +131,10 @@ impl super::Platform for Platform {
fn quit(&self) {} fn quit(&self) {}
fn screen_size(&self) -> Vector2F {
vec2f(1024., 768.)
}
fn open_window( fn open_window(
&self, &self,
_: usize, _: usize,

View file

@ -479,8 +479,14 @@ pub struct ProjectSharedNotification {
#[derive(Deserialize, Default)] #[derive(Deserialize, Default)]
pub struct IncomingCallNotification { pub struct IncomingCallNotification {
#[serde(default)]
pub background: Color,
pub caller_container: ContainerStyle,
pub caller_avatar: ImageStyle, pub caller_avatar: ImageStyle,
pub caller_metadata: ContainerStyle,
pub caller_username: ContainedText, pub caller_username: ContainedText,
pub caller_message: ContainedText,
pub button_width: f32,
pub accept_button: ContainedText, pub accept_button: ContainedText,
pub decline_button: ContainedText, pub decline_button: ContainedText,
} }

View file

@ -1,22 +1,38 @@
import Theme from "../themes/common/theme"; import Theme from "../themes/common/theme";
import { text } from "./components"; import { backgroundColor, borderColor, text } from "./components";
export default function incomingCallNotification(theme: Theme): Object { export default function incomingCallNotification(theme: Theme): Object {
const avatarSize = 12; const avatarSize = 32;
return { return {
background: backgroundColor(theme, 300),
callerContainer: {
padding: 12,
},
callerAvatar: { callerAvatar: {
height: avatarSize, height: avatarSize,
width: avatarSize, width: avatarSize,
cornerRadius: 6, cornerRadius: avatarSize / 2,
},
callerMetadata: {
margin: { left: 10 },
}, },
callerUsername: { 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: { 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: { 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" })
}, },
}; };
} }