Start work on styling of follower avatars in facepiles

* Make follower avatars smaller than top-level avatars
* Make avatars in facepiles overlap
* Render an opaque background behind avatars in facepiles.
This commit is contained in:
Max Brunsfeld 2023-02-20 23:20:22 -08:00 committed by Julia
parent 0dc92bec5c
commit b7cf426908
3 changed files with 50 additions and 23 deletions

View file

@ -17,7 +17,7 @@ use gpui::{
}; };
use settings::Settings; use settings::Settings;
use std::{ops::Range, sync::Arc}; use std::{ops::Range, sync::Arc};
use theme::Theme; use theme::{AvatarStyle, Theme};
use util::ResultExt; use util::ResultExt;
use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace}; use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace};
@ -614,21 +614,22 @@ impl CollabTitlebarItem {
if let Some(location) = location { if let Some(location) = location {
if let ParticipantLocation::SharedProject { project_id } = location { if let ParticipantLocation::SharedProject { project_id } = location {
if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() { if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() {
avatar_style = theme.workspace.titlebar.avatar; avatar_style = &theme.workspace.titlebar.avatar;
} else { } else {
avatar_style = theme.workspace.titlebar.inactive_avatar; avatar_style = &theme.workspace.titlebar.inactive_avatar;
} }
} else { } else {
avatar_style = theme.workspace.titlebar.inactive_avatar; avatar_style = &theme.workspace.titlebar.inactive_avatar;
} }
} else { } else {
avatar_style = theme.workspace.titlebar.avatar; avatar_style = &theme.workspace.titlebar.avatar;
} }
let content = Stack::new() let content = Stack::new()
.with_children(user.avatar.as_ref().map(|avatar| { .with_children(user.avatar.as_ref().map(|avatar| {
let flex = Flex::row() let flex = Flex::row()
.with_child(Self::render_face(avatar.clone(), avatar_style, theme)) // .with_reversed_paint_order()
.with_child(Self::render_face(avatar.clone(), avatar_style.clone()))
.with_children( .with_children(
(|| { (|| {
let room = room?.read(cx); let room = room?.read(cx);
@ -652,14 +653,22 @@ impl CollabTitlebarItem {
} }
})?; })?;
Some(Self::render_face(avatar.clone(), avatar_style, theme)) Some(
Container::new(Self::render_face(
avatar.clone(),
theme.workspace.titlebar.follower_avatar.clone(),
))
.with_margin_left(
-1.0 * theme.workspace.titlebar.follower_avatar_overlap,
)
.boxed(),
)
})) }))
})() })()
.into_iter() .into_iter()
.flatten(), .flatten(),
); );
let room = ActiveCall::global(cx).read(cx).room();
if let (Some(replica_id), Some(room)) = (replica_id, room) { if let (Some(replica_id), Some(room)) = (replica_id, room) {
let followed_by_self = is_being_followed let followed_by_self = is_being_followed
&& room && room
@ -669,7 +678,6 @@ impl CollabTitlebarItem {
.any(|&follower| { .any(|&follower| {
Some(follower) == workspace.read(cx).client().peer_id() Some(follower) == workspace.read(cx).client().peer_id()
}); });
if followed_by_self { if followed_by_self {
let color = theme.editor.replica_selection_style(replica_id).selection; let color = theme.editor.replica_selection_style(replica_id).selection;
return flex.contained().with_background_color(color).boxed(); return flex.contained().with_background_color(color).boxed();
@ -742,11 +750,14 @@ impl CollabTitlebarItem {
} }
} }
fn render_face(avatar: Arc<ImageData>, avatar_style: ImageStyle, theme: &Theme) -> ElementBox { fn render_face(avatar: Arc<ImageData>, avatar_style: AvatarStyle) -> ElementBox {
Image::new(avatar) Image::new(avatar)
.with_style(avatar_style) .with_style(avatar_style.image)
.constrained() .constrained()
.with_width(theme.workspace.titlebar.avatar_width) .with_width(avatar_style.width)
.contained()
.with_background_color(Color::white())
.with_corner_radius(avatar_style.image.corner_radius)
.aligned() .aligned()
.boxed() .boxed()
} }

View file

@ -74,12 +74,13 @@ pub struct Titlebar {
pub container: ContainerStyle, pub container: ContainerStyle,
pub height: f32, pub height: f32,
pub title: TextStyle, pub title: TextStyle,
pub avatar_width: f32,
pub avatar_margin: f32, pub avatar_margin: f32,
pub avatar_ribbon: AvatarRibbon, pub avatar_ribbon: AvatarRibbon,
pub follower_avatar_overlap: f32,
pub offline_icon: OfflineIcon, pub offline_icon: OfflineIcon,
pub avatar: ImageStyle, pub avatar: AvatarStyle,
pub inactive_avatar: ImageStyle, pub inactive_avatar: AvatarStyle,
pub follower_avatar: AvatarStyle,
pub sign_in_prompt: Interactive<ContainedText>, pub sign_in_prompt: Interactive<ContainedText>,
pub outdated_warning: ContainedText, pub outdated_warning: ContainedText,
pub share_button: Interactive<ContainedText>, pub share_button: Interactive<ContainedText>,
@ -88,6 +89,13 @@ pub struct Titlebar {
pub toggle_contacts_badge: ContainerStyle, pub toggle_contacts_badge: ContainerStyle,
} }
#[derive(Clone, Deserialize, Default)]
pub struct AvatarStyle {
#[serde(flatten)]
pub image: ImageStyle,
pub width: f32,
}
#[derive(Deserialize, Default)] #[derive(Deserialize, Default)]
pub struct ContactsPopover { pub struct ContactsPopover {
#[serde(flatten)] #[serde(flatten)]

View file

@ -41,6 +41,7 @@ export default function workspace(colorScheme: ColorScheme) {
}, },
}; };
const avatarWidth = 18; const avatarWidth = 18;
const followerAvatarWidth = 14;
return { return {
background: background(layer), background: background(layer),
@ -80,7 +81,6 @@ export default function workspace(colorScheme: ColorScheme) {
}, },
statusBar: statusBar(colorScheme), statusBar: statusBar(colorScheme),
titlebar: { titlebar: {
avatarWidth,
avatarMargin: 8, avatarMargin: 8,
height: 33, // 32px + 1px for overlaid border height: 33, // 32px + 1px for overlaid border
background: background(layer), background: background(layer),
@ -95,6 +95,7 @@ export default function workspace(colorScheme: ColorScheme) {
// Collaborators // Collaborators
avatar: { avatar: {
width: avatarWidth,
cornerRadius: avatarWidth / 2, cornerRadius: avatarWidth / 2,
border: { border: {
color: "#00000088", color: "#00000088",
@ -102,6 +103,7 @@ export default function workspace(colorScheme: ColorScheme) {
}, },
}, },
inactiveAvatar: { inactiveAvatar: {
width: avatarWidth,
cornerRadius: avatarWidth / 2, cornerRadius: avatarWidth / 2,
border: { border: {
color: "#00000088", color: "#00000088",
@ -109,6 +111,15 @@ export default function workspace(colorScheme: ColorScheme) {
}, },
grayscale: true, grayscale: true,
}, },
followerAvatar: {
width: followerAvatarWidth,
cornerRadius: followerAvatarWidth / 2,
border: {
color: "#00000088",
width: 1,
},
},
followerAvatarOverlap: 4,
avatarRibbon: { avatarRibbon: {
height: 3, height: 3,
width: 12, width: 12,
@ -118,7 +129,7 @@ export default function workspace(colorScheme: ColorScheme) {
// Sign in buttom // Sign in buttom
// FlatButton, Variant // FlatButton, Variant
signInPrompt: { signInPrompt: {
...titlebarButton ...titlebarButton,
}, },
// Offline Indicator // Offline Indicator
@ -184,8 +195,8 @@ export default function workspace(colorScheme: ColorScheme) {
background: foreground(layer, "accent"), background: foreground(layer, "accent"),
}, },
shareButton: { shareButton: {
...titlebarButton ...titlebarButton,
} },
}, },
toolbar: { toolbar: {
@ -241,9 +252,6 @@ export default function workspace(colorScheme: ColorScheme) {
shadow: colorScheme.modalShadow, shadow: colorScheme.modalShadow,
}, },
}, },
dropTargetOverlayColor: withOpacity( dropTargetOverlayColor: withOpacity(foreground(layer, "variant"), 0.5),
foreground(layer, "variant"),
0.5
),
}; };
} }