Format Rust sources at 100 columns
This commit is contained in:
1 parent
4661f595f8
commit
610478f8c7
336 files changed
+23497
-7892
No files matched your search
@@ -21,8 +21,8 @@ pub(super) fn view<'a>(
|
||||
opacity: p,
|
||||
} = style;
|
||||
if let Some(a) = &shell.status.audio {
|
||||
let mut volume_heading =
|
||||
row![shell.render.text("Volume").size(13).width(Length::Fill)].align_y(Alignment::Center);
|
||||
let mut volume_heading = row![shell.render.text("Volume").size(13).width(Length::Fill)]
|
||||
.align_y(Alignment::Center);
|
||||
if combined {
|
||||
volume_heading = volume_heading.push(shell_switch(
|
||||
shell.render,
|
||||
@@ -35,7 +35,11 @@ pub(super) fn view<'a>(
|
||||
}
|
||||
let audio = column![
|
||||
volume_heading,
|
||||
shell.render.text(&a.output).size(12).class(theme::Text::Color(muted)),
|
||||
shell
|
||||
.render
|
||||
.text(&a.output)
|
||||
.size(12)
|
||||
.class(theme::Text::Color(muted)),
|
||||
slider_row(
|
||||
shell.render,
|
||||
audio_icon(a.volume, a.muted),
|
||||
@@ -62,7 +66,9 @@ pub(super) fn heading<'a>(
|
||||
mut heading: super::MenuHeading<'a>,
|
||||
style: MenuStyle,
|
||||
) -> super::MenuHeading<'a> {
|
||||
let MenuStyle { theme, opacity: p, .. } = style;
|
||||
let MenuStyle {
|
||||
theme, opacity: p, ..
|
||||
} = style;
|
||||
if let Some(audio) = &shell.status.audio {
|
||||
heading = heading.push(shell_switch(
|
||||
shell.render,
|
||||
|
||||
@@ -5,7 +5,9 @@ use cosmic::{Element, theme};
|
||||
|
||||
use super::Menu;
|
||||
use crate::status::Snapshot;
|
||||
use crate::{BarMetrics, FereseShell, Message, accented_icon, bar_content, color, motion, recording};
|
||||
use crate::{
|
||||
BarMetrics, FereseShell, Message, accented_icon, bar_content, color, motion, recording,
|
||||
};
|
||||
|
||||
impl FereseShell {
|
||||
pub(crate) fn view_media_item(
|
||||
@@ -48,8 +50,9 @@ impl FereseShell {
|
||||
} else {
|
||||
status_icon(kind, &self.status)
|
||||
};
|
||||
let selected =
|
||||
selected || (kind == Menu::Recording && matches!(self.recorder.state, recording::State::Recording(_)));
|
||||
let selected = selected
|
||||
|| (kind == Menu::Recording
|
||||
&& matches!(self.recorder.state, recording::State::Recording(_)));
|
||||
let foreground = color(if selected {
|
||||
theme.accent
|
||||
} else if enabled {
|
||||
@@ -82,20 +85,17 @@ impl FereseShell {
|
||||
.as_ref()
|
||||
.is_some_and(|n| n.count > 0 && !n.dnd)
|
||||
{
|
||||
content = content.push(
|
||||
container(self.render.text(""))
|
||||
.width(4)
|
||||
.height(4)
|
||||
.class(theme::Container::custom(move |_| container::Style {
|
||||
background: Some(Background::Color(foreground)),
|
||||
border: Border {
|
||||
shape: BorderShape::Continuous,
|
||||
radius: self.render.radius(2.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
content = content.push(container(self.render.text("")).width(4).height(4).class(
|
||||
theme::Container::custom(move |_| container::Style {
|
||||
background: Some(Background::Color(foreground)),
|
||||
border: Border {
|
||||
shape: BorderShape::Continuous,
|
||||
radius: self.render.radius(2.0).into(),
|
||||
..Default::default()
|
||||
})),
|
||||
);
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
}
|
||||
let content = bar_content(content, metrics.group_item_height);
|
||||
let recording_busy = kind == Menu::Recording && self.recorder.busy();
|
||||
@@ -107,7 +107,10 @@ impl FereseShell {
|
||||
} else {
|
||||
status_label(kind, &self.status)
|
||||
})
|
||||
.padding([0.0, ((metrics.height - f32::from(metrics.icon_size)) * 0.5).max(4.0)])
|
||||
.padding([
|
||||
0.0,
|
||||
((metrics.height - f32::from(metrics.icon_size)) * 0.5).max(4.0),
|
||||
])
|
||||
.height(metrics.group_item_height)
|
||||
.on_press_with_rectangle(move |offset, bounds| {
|
||||
if kind == Menu::Recording {
|
||||
@@ -134,7 +137,10 @@ impl FereseShell {
|
||||
fn status_label(kind: Menu, s: &Snapshot) -> String {
|
||||
match kind {
|
||||
Menu::Network => match &s.network {
|
||||
Some(n) if n.enabled => format!("Wi-Fi: {}", n.connection.as_deref().unwrap_or("not connected")),
|
||||
Some(n) if n.enabled => format!(
|
||||
"Wi-Fi: {}",
|
||||
n.connection.as_deref().unwrap_or("not connected")
|
||||
),
|
||||
_ => "Wi-Fi: off".into(),
|
||||
},
|
||||
Menu::Bluetooth => match &s.bluetooth {
|
||||
@@ -204,7 +210,9 @@ pub(super) fn status_icon(kind: Menu, s: &Snapshot) -> (&'static [u8], bool) {
|
||||
}
|
||||
}
|
||||
Menu::Bluetooth => match &s.bluetooth {
|
||||
Some(b) if b.enabled && !b.devices.is_empty() => (ferese_theme::icons::BLUETOOTH_CONNECTED, true),
|
||||
Some(b) if b.enabled && !b.devices.is_empty() => {
|
||||
(ferese_theme::icons::BLUETOOTH_CONNECTED, true)
|
||||
}
|
||||
Some(b) if b.enabled => (ferese_theme::icons::BLUETOOTH_ON, true),
|
||||
_ => (ferese_theme::icons::BLUETOOTH_OFF, false),
|
||||
},
|
||||
@@ -261,26 +269,41 @@ mod tests {
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(status_icon(Menu::Audio, &s), (ferese_theme::icons::VOLUME_MUTE, false));
|
||||
assert_eq!(
|
||||
status_icon(Menu::Audio, &s),
|
||||
(ferese_theme::icons::VOLUME_MUTE, false)
|
||||
);
|
||||
|
||||
s.battery = Some(status::Battery {
|
||||
percent: 2,
|
||||
status: "Charging".into(),
|
||||
});
|
||||
assert_eq!(status_icon(Menu::Battery, &s).0, ferese_theme::icons::BATTERY_CHARGING);
|
||||
assert_eq!(
|
||||
status_icon(Menu::Battery, &s).0,
|
||||
ferese_theme::icons::BATTERY_CHARGING
|
||||
);
|
||||
|
||||
s.notifications = Some(status::Notifications { count: 3, dnd: true });
|
||||
s.notifications = Some(status::Notifications {
|
||||
count: 3,
|
||||
dnd: true,
|
||||
});
|
||||
assert_eq!(
|
||||
status_icon(Menu::Notifications, &s).0,
|
||||
ferese_theme::icons::NOTIFICATIONS_OFF
|
||||
);
|
||||
assert_eq!(status_label(Menu::Notifications, &s), "Notifications: do not disturb");
|
||||
assert_eq!(
|
||||
status_label(Menu::Notifications, &s),
|
||||
"Notifications: do not disturb"
|
||||
);
|
||||
|
||||
s.bluetooth = Some(status::Bluetooth {
|
||||
enabled: false,
|
||||
devices: vec!["Headphones".into()],
|
||||
});
|
||||
assert_eq!(status_icon(Menu::Bluetooth, &s).0, ferese_theme::icons::BLUETOOTH_OFF);
|
||||
assert_eq!(
|
||||
status_icon(Menu::Bluetooth, &s).0,
|
||||
ferese_theme::icons::BLUETOOTH_OFF
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -7,7 +7,11 @@ use super::{MenuRows, MenuStyle};
|
||||
use crate::status::Action;
|
||||
use crate::{FereseShell, Message, ShellTheme, bar_icon, color_with_opacity, motion};
|
||||
|
||||
pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: MenuStyle) -> MenuRows<'a> {
|
||||
pub(super) fn view<'a>(
|
||||
shell: &'a FereseShell,
|
||||
mut rows: MenuRows<'a>,
|
||||
style: MenuStyle,
|
||||
) -> MenuRows<'a> {
|
||||
let MenuStyle {
|
||||
theme,
|
||||
primary: _,
|
||||
@@ -37,9 +41,17 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
if let Some(profiles) = &shell.status.power_profiles {
|
||||
let mut modes = row::with_capacity(3).spacing(6).width(Length::Fill);
|
||||
for (index, (label, icon, profile)) in [
|
||||
("Power saver", ferese_theme::icons::POWER_SAVER, "power-saver"),
|
||||
(
|
||||
"Power saver",
|
||||
ferese_theme::icons::POWER_SAVER,
|
||||
"power-saver",
|
||||
),
|
||||
("Balanced", ferese_theme::icons::POWER_BALANCED, "balanced"),
|
||||
("Performance", ferese_theme::icons::POWER_PERFORMANCE, "performance"),
|
||||
(
|
||||
"Performance",
|
||||
ferese_theme::icons::POWER_PERFORMANCE,
|
||||
"performance",
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -89,18 +101,33 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
),
|
||||
] {
|
||||
if enabled {
|
||||
power = power.push(power_tile_action(shell.render, label, icon, action, theme, p));
|
||||
power = power.push(power_tile_action(
|
||||
shell.render,
|
||||
label,
|
||||
icon,
|
||||
action,
|
||||
theme,
|
||||
p,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if shell.status.reboot || shell.status.poweroff || shell.status.suspend {
|
||||
rows = rows.push(ferese_theme::menus::section_label("Power", shell.render.font, muted));
|
||||
rows = rows.push(ferese_theme::menus::section_label(
|
||||
"Power",
|
||||
shell.render.font,
|
||||
muted,
|
||||
));
|
||||
rows = rows.push(power);
|
||||
}
|
||||
rows
|
||||
}
|
||||
|
||||
pub(super) fn brightness<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: MenuStyle) -> MenuRows<'a> {
|
||||
pub(super) fn brightness<'a>(
|
||||
shell: &'a FereseShell,
|
||||
mut rows: MenuRows<'a>,
|
||||
style: MenuStyle,
|
||||
) -> MenuRows<'a> {
|
||||
let MenuStyle {
|
||||
theme,
|
||||
primary,
|
||||
@@ -135,7 +162,14 @@ fn power_tile<'a>(
|
||||
theme: ShellTheme,
|
||||
opacity: f32,
|
||||
) -> Element<'a, cosmic::Action<Message>> {
|
||||
let foreground = color_with_opacity(if selected { theme.accent } else { theme.text_primary }, opacity);
|
||||
let foreground = color_with_opacity(
|
||||
if selected {
|
||||
theme.accent
|
||||
} else {
|
||||
theme.text_primary
|
||||
},
|
||||
opacity,
|
||||
);
|
||||
let tile = container(
|
||||
column![bar_icon(icon, 19, foreground), render.text(label).size(11)]
|
||||
.spacing(3)
|
||||
@@ -146,7 +180,9 @@ fn power_tile<'a>(
|
||||
let btn = button::custom(tile)
|
||||
.width(Length::FillPortion(1))
|
||||
.padding([8, 2])
|
||||
.on_press(cosmic::Action::App(Message::Control(Action::PowerProfile(profile))));
|
||||
.on_press(cosmic::Action::App(Message::Control(Action::PowerProfile(
|
||||
profile,
|
||||
))));
|
||||
|
||||
motion::button(render, btn, foreground, selected, opacity)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,12 @@ fn device_list_height(count: usize) -> Option<f32> {
|
||||
(count > 4).then_some(DEVICE_LIST_HEIGHT)
|
||||
}
|
||||
|
||||
pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: MenuStyle, in_hub: bool) -> MenuRows<'a> {
|
||||
pub(super) fn view<'a>(
|
||||
shell: &'a FereseShell,
|
||||
mut rows: MenuRows<'a>,
|
||||
style: MenuStyle,
|
||||
in_hub: bool,
|
||||
) -> MenuRows<'a> {
|
||||
let MenuStyle { muted, .. } = style;
|
||||
if let Some(b) = &shell.status.bluetooth {
|
||||
rows = rows.push(status_summary(
|
||||
@@ -43,7 +48,11 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
devices = devices.push(
|
||||
column![
|
||||
shell.render.text(device).size(14),
|
||||
shell.render.text("Connected").size(12).class(theme::Text::Color(muted)),
|
||||
shell
|
||||
.render
|
||||
.text("Connected")
|
||||
.size(12)
|
||||
.class(theme::Text::Color(muted)),
|
||||
]
|
||||
.spacing(3),
|
||||
);
|
||||
|
||||
@@ -35,11 +35,16 @@ pub(super) fn hub<'a>(
|
||||
let navigation = |label: &'static str, message: Message| {
|
||||
crate::motion::button(
|
||||
render,
|
||||
cosmic::widget::button::custom(render.text(label).size(11).class(cosmic::theme::Text::Color(primary)))
|
||||
.name(label)
|
||||
.padding([2, 4])
|
||||
.height(22)
|
||||
.on_press(cosmic::Action::App(message)),
|
||||
cosmic::widget::button::custom(
|
||||
render
|
||||
.text(label)
|
||||
.size(11)
|
||||
.class(cosmic::theme::Text::Color(primary)),
|
||||
)
|
||||
.name(label)
|
||||
.padding([2, 4])
|
||||
.height(22)
|
||||
.on_press(cosmic::Action::App(message)),
|
||||
primary,
|
||||
false,
|
||||
opacity,
|
||||
|
||||
@@ -30,7 +30,11 @@ pub(super) fn status_summary<'a>(
|
||||
.center_y(32)
|
||||
.class(theme::Container::custom(move |_| container::Style {
|
||||
background: Some(Background::Color(Color {
|
||||
a: if enabled { 0.22 * opacity } else { 0.06 * opacity },
|
||||
a: if enabled {
|
||||
0.22 * opacity
|
||||
} else {
|
||||
0.06 * opacity
|
||||
},
|
||||
..badge_color
|
||||
})),
|
||||
border: Border {
|
||||
@@ -58,7 +62,10 @@ pub(super) fn status_summary<'a>(
|
||||
badge,
|
||||
column![
|
||||
render.text(title).size(14),
|
||||
render.text(subtitle).size(12).class(theme::Text::Color(muted)),
|
||||
render
|
||||
.text(subtitle)
|
||||
.size(12)
|
||||
.class(theme::Text::Color(muted)),
|
||||
]
|
||||
.spacing(4)
|
||||
.width(Length::Fill)
|
||||
@@ -176,13 +183,17 @@ pub(super) fn slider_row(
|
||||
icon_accent: Color,
|
||||
opacity: f32,
|
||||
) -> Element<'static, cosmic::Action<Message>> {
|
||||
let control = slider(if brightness { 1..=100 } else { 0..=100 }, value, move |value| {
|
||||
cosmic::Action::App(Message::Control(if brightness {
|
||||
Action::Brightness(value)
|
||||
} else {
|
||||
Action::Volume(value)
|
||||
}))
|
||||
})
|
||||
let control = slider(
|
||||
if brightness { 1..=100 } else { 0..=100 },
|
||||
value,
|
||||
move |value| {
|
||||
cosmic::Action::App(Message::Control(if brightness {
|
||||
Action::Brightness(value)
|
||||
} else {
|
||||
Action::Volume(value)
|
||||
}))
|
||||
},
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.height(24)
|
||||
.class(ferese_theme::menus::slider(foreground, opacity));
|
||||
|
||||
@@ -10,7 +10,11 @@ use super::{Menu, OpenMenu, PopoverAnchor};
|
||||
use crate::status::Action;
|
||||
use crate::{FereseShell, Message};
|
||||
|
||||
fn menu_positioner(rectangle: Rectangle<i32>, height_limit: f32, edge: ferese_panel::Edge) -> SctkPositioner {
|
||||
fn menu_positioner(
|
||||
rectangle: Rectangle<i32>,
|
||||
height_limit: f32,
|
||||
edge: ferese_panel::Edge,
|
||||
) -> SctkPositioner {
|
||||
// xdg-positioner: bottom/bottom-left for top bars, top/top-left for bottom bars.
|
||||
let (anchor, gravity, gap) = match edge {
|
||||
ferese_panel::Edge::Top => (2u32, 6u32, 8),
|
||||
@@ -21,7 +25,9 @@ fn menu_positioner(rectangle: Rectangle<i32>, height_limit: f32, edge: ferese_pa
|
||||
anchor: anchor.try_into().unwrap(),
|
||||
gravity: gravity.try_into().unwrap(),
|
||||
offset: (rectangle.width / 2, gap),
|
||||
size_limits: Limits::NONE.max_width(368.0).max_height(720.0_f32.max(height_limit)),
|
||||
size_limits: Limits::NONE
|
||||
.max_width(368.0)
|
||||
.max_height(720.0_f32.max(height_limit)),
|
||||
constraint_adjustment: 3,
|
||||
..Default::default()
|
||||
}
|
||||
@@ -41,7 +47,10 @@ impl FereseShell {
|
||||
pub fn open_menu(&mut self, kind: Menu, anchor: PopoverAnchor) -> Task<Message> {
|
||||
if (self.snapshot.binding_mode.is_some() && anchor.item.is_some())
|
||||
|| !anchor.belongs_to(&self.config.panels[0])
|
||||
|| !self.outputs.iter().any(|output| output.bar == anchor.parent)
|
||||
|| !self
|
||||
.outputs
|
||||
.iter()
|
||||
.any(|output| output.bar == anchor.parent)
|
||||
|| self.bar_hidden(anchor.parent)
|
||||
|| !kind.available(&self.status)
|
||||
{
|
||||
@@ -60,7 +69,9 @@ impl FereseShell {
|
||||
return close.chain(open);
|
||||
}
|
||||
if self.menu.as_ref().is_some_and(|menu| {
|
||||
menu.kind == kind && menu.anchor.same_item(&anchor) && menu.anchor.rectangle == anchor.rectangle
|
||||
menu.kind == kind
|
||||
&& menu.anchor.same_item(&anchor)
|
||||
&& menu.anchor.rectangle == anchor.rectangle
|
||||
}) {
|
||||
if let Some(menu) = &mut self.menu
|
||||
&& menu.motion.closing()
|
||||
@@ -94,7 +105,11 @@ impl FereseShell {
|
||||
if !kind.available(&self.status) {
|
||||
return Task::none();
|
||||
}
|
||||
if self.menu.as_ref().is_some_and(|menu| menu.kind == Menu::Notifications) {
|
||||
if self
|
||||
.menu
|
||||
.as_ref()
|
||||
.is_some_and(|menu| menu.kind == Menu::Notifications)
|
||||
{
|
||||
self.notifications.history_open = false;
|
||||
self.notifications.hovered = None;
|
||||
}
|
||||
@@ -120,7 +135,9 @@ impl FereseShell {
|
||||
menu.switch_panel(kind, self.config.animations, Instant::now());
|
||||
return Task::batch([
|
||||
notifications,
|
||||
cosmic::iced::platform_specific::shell::commands::popup::reposition(menu.id, positioner),
|
||||
cosmic::iced::platform_specific::shell::commands::popup::reposition(
|
||||
menu.id, positioner,
|
||||
),
|
||||
]);
|
||||
}
|
||||
let id = window::Id::unique();
|
||||
@@ -166,7 +183,9 @@ impl FereseShell {
|
||||
}
|
||||
Task::batch([
|
||||
tooltip,
|
||||
cosmic::task::message(cosmic::Action::Surface(cosmic::surface::action::destroy_popup(menu.id))),
|
||||
cosmic::task::message(cosmic::Action::Surface(
|
||||
cosmic::surface::action::destroy_popup(menu.id),
|
||||
)),
|
||||
self.sync_notification_surface(),
|
||||
])
|
||||
}
|
||||
@@ -302,7 +321,9 @@ mod tests {
|
||||
width: 32,
|
||||
height: 30,
|
||||
};
|
||||
for (edge, anchor, gravity, gap) in [(Edge::Top, 2u32, 6u32, 8), (Edge::Bottom, 1u32, 5u32, -8)] {
|
||||
for (edge, anchor, gravity, gap) in
|
||||
[(Edge::Top, 2u32, 6u32, 8), (Edge::Bottom, 1u32, 5u32, -8)]
|
||||
{
|
||||
let positioner = menu_positioner(rectangle, 620., edge);
|
||||
assert_eq!(positioner.anchor_rect, rectangle);
|
||||
assert_eq!(positioner.anchor, anchor.try_into().unwrap());
|
||||
@@ -408,7 +429,10 @@ mod tests {
|
||||
},
|
||||
now,
|
||||
);
|
||||
assert_eq!(menu.motion.progress_at(now + Duration::from_millis(60)), normal);
|
||||
assert_eq!(
|
||||
menu.motion.progress_at(now + Duration::from_millis(60)),
|
||||
normal
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn popup_anchors_reject_removed_hidden_items_and_other_panel_definitions() {
|
||||
@@ -426,7 +450,10 @@ mod tests {
|
||||
};
|
||||
assert!(anchor.belongs_to(&panel));
|
||||
let items = &mut panel.end.groups[0].items;
|
||||
let network = items.iter().position(|item| item.id.0 == "network").unwrap();
|
||||
let network = items
|
||||
.iter()
|
||||
.position(|item| item.id.0 == "network")
|
||||
.unwrap();
|
||||
items[network].visible = false;
|
||||
assert!(!anchor.belongs_to(&panel));
|
||||
panel.end.groups[0].items.remove(network);
|
||||
|
||||
@@ -8,7 +8,8 @@ use serde_json::json;
|
||||
|
||||
use super::{Menu, MenuRows, MenuStyle};
|
||||
use crate::{
|
||||
BarMetrics, FereseShell, Message, ShellTheme, accented_icon, bar_content, color, color_with_opacity, motion,
|
||||
BarMetrics, FereseShell, Message, ShellTheme, accented_icon, bar_content, color,
|
||||
color_with_opacity, motion,
|
||||
};
|
||||
|
||||
const SEEK_THUMB_DIAMETER: f32 = 10.0;
|
||||
@@ -80,30 +81,39 @@ pub(super) fn bar<'a>(
|
||||
let Some(player) = &shell.media.snapshot.selected else {
|
||||
return shell.render.text("").into();
|
||||
};
|
||||
let foreground = color(if selected { palette.accent } else { palette.text_primary });
|
||||
let vertical_padding = ((metrics.group_item_height - f32::from(metrics.icon_size)) * 0.5).clamp(0.0, 2.0);
|
||||
let foreground = color(if selected {
|
||||
palette.accent
|
||||
} else {
|
||||
palette.text_primary
|
||||
});
|
||||
let vertical_padding =
|
||||
((metrics.group_item_height - f32::from(metrics.icon_size)) * 0.5).clamp(0.0, 2.0);
|
||||
let height = metrics.group_item_height - 2.0 * vertical_padding;
|
||||
let side = height.min(24.0);
|
||||
let cover: Element<'_, cosmic::Action<Message>> =
|
||||
match shell.media.artwork.as_ref().and_then(|art| art.handle.as_ref()) {
|
||||
Some(handle) => image(handle.clone())
|
||||
.width(side)
|
||||
.height(side)
|
||||
.content_fit(cosmic::iced::ContentFit::Cover)
|
||||
.border_radius(shell.render.radius(6.0))
|
||||
.shape(BorderShape::Continuous)
|
||||
.into(),
|
||||
None => container(accented_icon(
|
||||
icons::MEDIA,
|
||||
side as u16,
|
||||
foreground,
|
||||
color(palette.accent),
|
||||
))
|
||||
.center_x(side)
|
||||
.center_y(side)
|
||||
let cover: Element<'_, cosmic::Action<Message>> = match shell
|
||||
.media
|
||||
.artwork
|
||||
.as_ref()
|
||||
.and_then(|art| art.handle.as_ref())
|
||||
{
|
||||
Some(handle) => image(handle.clone())
|
||||
.width(side)
|
||||
.height(side)
|
||||
.content_fit(cosmic::iced::ContentFit::Cover)
|
||||
.border_radius(shell.render.radius(6.0))
|
||||
.shape(BorderShape::Continuous)
|
||||
.into(),
|
||||
};
|
||||
None => container(accented_icon(
|
||||
icons::MEDIA,
|
||||
side as u16,
|
||||
foreground,
|
||||
color(palette.accent),
|
||||
))
|
||||
.center_x(side)
|
||||
.center_y(side)
|
||||
.width(side)
|
||||
.into(),
|
||||
};
|
||||
let label = shell
|
||||
.render
|
||||
.text(player.label())
|
||||
@@ -120,7 +130,8 @@ pub(super) fn bar<'a>(
|
||||
let preferred_label_width: f32 = if compact { 112. } else { 320. };
|
||||
// Outer padding, the transport button, details padding, and cover spacing
|
||||
// share the allocation with the label.
|
||||
let chrome = 4. + 2. + f32::from(metrics.icon_size) + 12. + 8. + if compact { 0. } else { side + 8. };
|
||||
let chrome =
|
||||
4. + 2. + f32::from(metrics.icon_size) + 12. + 8. + if compact { 0. } else { side + 8. };
|
||||
let label_width = width.map_or(preferred_label_width, |width| {
|
||||
(width - chrome).max(0.).min(preferred_label_width)
|
||||
});
|
||||
@@ -150,7 +161,11 @@ pub(super) fn bar<'a>(
|
||||
let playing = player.status == Playback::Playing;
|
||||
let mut toggle = button::custom(bar_content(
|
||||
accented_icon(
|
||||
if playing { icons::MEDIA_PAUSE } else { icons::MEDIA_PLAY },
|
||||
if playing {
|
||||
icons::MEDIA_PAUSE
|
||||
} else {
|
||||
icons::MEDIA_PLAY
|
||||
},
|
||||
metrics.icon_size,
|
||||
foreground,
|
||||
color(palette.accent),
|
||||
@@ -186,7 +201,9 @@ pub(super) fn bar<'a>(
|
||||
|
||||
let mut area = mouse_area(controls);
|
||||
if player.can_raise {
|
||||
area = area.on_middle_release(cosmic::Action::App(Message::MediaAction(shell.media.action("raise"))));
|
||||
area = area.on_middle_release(cosmic::Action::App(Message::MediaAction(
|
||||
shell.media.action("raise"),
|
||||
)));
|
||||
}
|
||||
if player.can_control && player.volume.is_some() {
|
||||
let action = shell.media.action("volume");
|
||||
@@ -205,7 +222,11 @@ fn volume_delta(delta: mouse::ScrollDelta) -> f64 {
|
||||
mouse::ScrollDelta::Lines { y, .. } => f64::from(y) * 0.05,
|
||||
mouse::ScrollDelta::Pixels { y, .. } => f64::from(y) * 0.001,
|
||||
};
|
||||
if delta.is_finite() { delta.clamp(-1.0, 1.0) } else { 0.0 }
|
||||
if delta.is_finite() {
|
||||
delta.clamp(-1.0, 1.0)
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
fn transport<'a>(
|
||||
@@ -228,7 +249,8 @@ fn transport_sized<'a>(
|
||||
style: MenuStyle,
|
||||
size: f32,
|
||||
) -> Element<'a, cosmic::Action<Message>> {
|
||||
let fill = (action == "play-pause").then_some(if enabled { style.primary } else { style.muted });
|
||||
let fill =
|
||||
(action == "play-pause").then_some(if enabled { style.primary } else { style.muted });
|
||||
let foreground = match fill {
|
||||
Some(fill) => cosmic::iced::Color {
|
||||
a: fill.a,
|
||||
@@ -247,7 +269,10 @@ fn transport_sized<'a>(
|
||||
accented_icon(
|
||||
source,
|
||||
(size - 20.) as u16,
|
||||
cosmic::iced::Color { a: 1., ..foreground },
|
||||
cosmic::iced::Color {
|
||||
a: 1.,
|
||||
..foreground
|
||||
},
|
||||
color(style.theme.accent),
|
||||
)
|
||||
.opacity(foreground.a),
|
||||
@@ -260,13 +285,19 @@ fn transport_sized<'a>(
|
||||
.height(size)
|
||||
.name(label);
|
||||
if enabled {
|
||||
control = control.on_press(cosmic::Action::App(Message::MediaAction(shell.media.action(action))));
|
||||
control = control.on_press(cosmic::Action::App(Message::MediaAction(
|
||||
shell.media.action(action),
|
||||
)));
|
||||
}
|
||||
|
||||
motion::circular_button(shell.render, control, foreground, fill, style.opacity, size)
|
||||
}
|
||||
|
||||
pub(super) fn hub<'a>(shell: &'a FereseShell, rows: MenuRows<'a>, style: MenuStyle) -> MenuRows<'a> {
|
||||
pub(super) fn hub<'a>(
|
||||
shell: &'a FereseShell,
|
||||
rows: MenuRows<'a>,
|
||||
style: MenuStyle,
|
||||
) -> MenuRows<'a> {
|
||||
let Some(player) = &shell.media.snapshot.selected else {
|
||||
return rows.push(
|
||||
shell
|
||||
@@ -276,31 +307,35 @@ pub(super) fn hub<'a>(shell: &'a FereseShell, rows: MenuRows<'a>, style: MenuSty
|
||||
.class(theme::Text::Color(style.muted)),
|
||||
);
|
||||
};
|
||||
let cover: Element<'_, cosmic::Action<Message>> =
|
||||
match shell.media.artwork.as_ref().and_then(|art| art.handle.as_ref()) {
|
||||
Some(handle) => image(handle.clone())
|
||||
.width(64)
|
||||
.height(64)
|
||||
.opacity(style.opacity)
|
||||
.content_fit(cosmic::iced::ContentFit::Cover)
|
||||
.border_radius(10.)
|
||||
.into(),
|
||||
None => container(
|
||||
accented_icon(
|
||||
icons::MEDIA,
|
||||
26,
|
||||
color(style.theme.text_primary),
|
||||
color(style.theme.accent),
|
||||
)
|
||||
.opacity(style.opacity),
|
||||
)
|
||||
.center_x(64)
|
||||
.center_y(64)
|
||||
.class(theme::Container::custom(move |_| {
|
||||
ferese_theme::controls::surface_appearance(style.primary.scale_alpha(0.06), 10.)
|
||||
}))
|
||||
let cover: Element<'_, cosmic::Action<Message>> = match shell
|
||||
.media
|
||||
.artwork
|
||||
.as_ref()
|
||||
.and_then(|art| art.handle.as_ref())
|
||||
{
|
||||
Some(handle) => image(handle.clone())
|
||||
.width(64)
|
||||
.height(64)
|
||||
.opacity(style.opacity)
|
||||
.content_fit(cosmic::iced::ContentFit::Cover)
|
||||
.border_radius(10.)
|
||||
.into(),
|
||||
};
|
||||
None => container(
|
||||
accented_icon(
|
||||
icons::MEDIA,
|
||||
26,
|
||||
color(style.theme.text_primary),
|
||||
color(style.theme.accent),
|
||||
)
|
||||
.opacity(style.opacity),
|
||||
)
|
||||
.center_x(64)
|
||||
.center_y(64)
|
||||
.class(theme::Container::custom(move |_| {
|
||||
ferese_theme::controls::surface_appearance(style.primary.scale_alpha(0.06), 10.)
|
||||
}))
|
||||
.into(),
|
||||
};
|
||||
let mut info = column![
|
||||
shell
|
||||
.render
|
||||
@@ -327,8 +362,9 @@ pub(super) fn hub<'a>(shell: &'a FereseShell, rows: MenuRows<'a>, style: MenuSty
|
||||
player.length_us.filter(|length| *length > 0),
|
||||
player.position_at(shell.media.now_us),
|
||||
) {
|
||||
let value =
|
||||
(shell.media.seeking.unwrap_or(position).min(length) as f64 / length as f64 * 10_000.).round() as u32;
|
||||
let value = (shell.media.seeking.unwrap_or(position).min(length) as f64 / length as f64
|
||||
* 10_000.)
|
||||
.round() as u32;
|
||||
if player.can_control && player.can_seek && player.track_id.is_some() {
|
||||
info = info.push(
|
||||
slider(0..=10_000_u32, value, move |value| {
|
||||
@@ -358,7 +394,11 @@ pub(super) fn hub<'a>(shell: &'a FereseShell, rows: MenuRows<'a>, style: MenuSty
|
||||
),
|
||||
transport_sized(
|
||||
shell,
|
||||
if playing { icons::MEDIA_PAUSE } else { icons::MEDIA_PLAY },
|
||||
if playing {
|
||||
icons::MEDIA_PAUSE
|
||||
} else {
|
||||
icons::MEDIA_PLAY
|
||||
},
|
||||
if playing { "Pause" } else { "Play" },
|
||||
"play-pause",
|
||||
player.can_toggle(),
|
||||
@@ -381,22 +421,35 @@ pub(super) fn hub<'a>(shell: &'a FereseShell, rows: MenuRows<'a>, style: MenuSty
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: MenuStyle) -> MenuRows<'a> {
|
||||
pub(super) fn view<'a>(
|
||||
shell: &'a FereseShell,
|
||||
mut rows: MenuRows<'a>,
|
||||
style: MenuStyle,
|
||||
) -> MenuRows<'a> {
|
||||
if let Some(player) = &shell.media.snapshot.selected {
|
||||
let cover: Element<'_, cosmic::Action<Message>> =
|
||||
match shell.media.artwork.as_ref().and_then(|art| art.handle.as_ref()) {
|
||||
Some(handle) => image(handle.clone())
|
||||
.width(64)
|
||||
.height(64)
|
||||
.content_fit(cosmic::iced::ContentFit::Contain)
|
||||
.border_radius(shell.render.radius(12.0))
|
||||
.shape(BorderShape::Continuous)
|
||||
.into(),
|
||||
None => container(accented_icon(icons::MEDIA, 30, style.muted, color(style.theme.accent)))
|
||||
.center_x(64)
|
||||
.center_y(64)
|
||||
.into(),
|
||||
};
|
||||
let cover: Element<'_, cosmic::Action<Message>> = match shell
|
||||
.media
|
||||
.artwork
|
||||
.as_ref()
|
||||
.and_then(|art| art.handle.as_ref())
|
||||
{
|
||||
Some(handle) => image(handle.clone())
|
||||
.width(64)
|
||||
.height(64)
|
||||
.content_fit(cosmic::iced::ContentFit::Contain)
|
||||
.border_radius(shell.render.radius(12.0))
|
||||
.shape(BorderShape::Continuous)
|
||||
.into(),
|
||||
None => container(accented_icon(
|
||||
icons::MEDIA,
|
||||
30,
|
||||
style.muted,
|
||||
color(style.theme.accent),
|
||||
))
|
||||
.center_x(64)
|
||||
.center_y(64)
|
||||
.into(),
|
||||
};
|
||||
let text_size = if player.label().len() >= 24 { 13 } else { 15 };
|
||||
let mut info = column![
|
||||
shell
|
||||
@@ -470,20 +523,23 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
} else {
|
||||
progress = progress.push(seek_pill(
|
||||
container(
|
||||
cosmic::iced::widget::ProgressBar::new(0.0..=1.0, (position as f64 / length as f64) as f32)
|
||||
.girth(4)
|
||||
.length(Length::Fill)
|
||||
.class(cosmic::theme::iced::ProgressBar::custom(move |_| {
|
||||
cosmic::iced::widget::progress_bar::Style {
|
||||
background: style.muted.scale_alpha(0.35).into(),
|
||||
bar: color_with_opacity(style.theme.accent, style.opacity).into(),
|
||||
border: cosmic::iced::Border {
|
||||
shape: BorderShape::Circular,
|
||||
radius: 2.0.into(),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
})),
|
||||
cosmic::iced::widget::ProgressBar::new(
|
||||
0.0..=1.0,
|
||||
(position as f64 / length as f64) as f32,
|
||||
)
|
||||
.girth(4)
|
||||
.length(Length::Fill)
|
||||
.class(cosmic::theme::iced::ProgressBar::custom(move |_| {
|
||||
cosmic::iced::widget::progress_bar::Style {
|
||||
background: style.muted.scale_alpha(0.35).into(),
|
||||
bar: color_with_opacity(style.theme.accent, style.opacity).into(),
|
||||
border: cosmic::iced::Border {
|
||||
shape: BorderShape::Circular,
|
||||
radius: 2.0.into(),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
})),
|
||||
)
|
||||
.center_y(20),
|
||||
style,
|
||||
@@ -525,7 +581,11 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
),
|
||||
transport(
|
||||
shell,
|
||||
if playing { icons::MEDIA_PAUSE } else { icons::MEDIA_PLAY },
|
||||
if playing {
|
||||
icons::MEDIA_PAUSE
|
||||
} else {
|
||||
icons::MEDIA_PLAY
|
||||
},
|
||||
if playing { "Pause" } else { "Play" },
|
||||
"play-pause",
|
||||
player.can_toggle(),
|
||||
@@ -597,7 +657,11 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
shell.render,
|
||||
label,
|
||||
Message::MediaAction(pin),
|
||||
if player.ignored { style.muted } else { style.primary },
|
||||
if player.ignored {
|
||||
style.muted
|
||||
} else {
|
||||
style.primary
|
||||
},
|
||||
style.opacity
|
||||
),
|
||||
super::controls::menu_button(
|
||||
@@ -616,7 +680,13 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
}
|
||||
|
||||
if let Some(error) = &shell.media.error {
|
||||
rows = rows.push(shell.render.text(error).size(12).class(theme::Text::Color(style.muted)));
|
||||
rows = rows.push(
|
||||
shell
|
||||
.render
|
||||
.text(error)
|
||||
.size(12)
|
||||
.class(theme::Text::Color(style.muted)),
|
||||
);
|
||||
}
|
||||
|
||||
rows
|
||||
@@ -645,9 +715,24 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn wheel_changes_are_bounded_and_pixel_scrolling_is_not_a_full_step() {
|
||||
assert_eq!(volume_delta(mouse::ScrollDelta::Lines { x: 0.0, y: 1.0 }), 0.05);
|
||||
assert_eq!(volume_delta(mouse::ScrollDelta::Pixels { x: 0.0, y: 1.0 }), 0.001);
|
||||
assert_eq!(volume_delta(mouse::ScrollDelta::Lines { x: 0.0, y: f32::NAN }), 0.0);
|
||||
assert_eq!(volume_delta(mouse::ScrollDelta::Lines { x: 0.0, y: 1000.0 }), 1.0);
|
||||
assert_eq!(
|
||||
volume_delta(mouse::ScrollDelta::Lines { x: 0.0, y: 1.0 }),
|
||||
0.05
|
||||
);
|
||||
assert_eq!(
|
||||
volume_delta(mouse::ScrollDelta::Pixels { x: 0.0, y: 1.0 }),
|
||||
0.001
|
||||
);
|
||||
assert_eq!(
|
||||
volume_delta(mouse::ScrollDelta::Lines {
|
||||
x: 0.0,
|
||||
y: f32::NAN
|
||||
}),
|
||||
0.0
|
||||
);
|
||||
assert_eq!(
|
||||
volume_delta(mouse::ScrollDelta::Lines { x: 0.0, y: 1000.0 }),
|
||||
1.0
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,11 @@ use status::{Action, Snapshot};
|
||||
|
||||
use super::*;
|
||||
|
||||
type MenuHeading<'a> = cosmic::widget::Row<'a, cosmic::Action<Message>, cosmic::Theme, cosmic::Renderer>;
|
||||
type MenuHeading<'a> =
|
||||
cosmic::widget::Row<'a, cosmic::Action<Message>, cosmic::Theme, cosmic::Renderer>;
|
||||
|
||||
type MenuRows<'a> = cosmic::widget::Column<'a, cosmic::Action<Message>, cosmic::Theme, cosmic::Renderer>;
|
||||
type MenuRows<'a> =
|
||||
cosmic::widget::Column<'a, cosmic::Action<Message>, cosmic::Theme, cosmic::Renderer>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct MenuStyle {
|
||||
@@ -59,7 +61,10 @@ impl Menu {
|
||||
) | (Self::Network, Action::Wifi(_))
|
||||
| (Self::Bluetooth, Action::Bluetooth(_))
|
||||
| (Self::Audio, Action::Volume(_) | Action::Mute(_))
|
||||
| (Self::Battery, Action::Brightness(_) | Action::PowerProfile(_))
|
||||
| (
|
||||
Self::Battery,
|
||||
Action::Brightness(_) | Action::PowerProfile(_)
|
||||
)
|
||||
| (Self::Notifications, Action::Dnd(_) | Action::Notifications)
|
||||
);
|
||||
relevant.then_some(error.message.as_str())
|
||||
@@ -132,10 +137,9 @@ pub(crate) struct PopoverAnchor {
|
||||
impl PopoverAnchor {
|
||||
pub(crate) fn belongs_to(&self, panel: &crate::panel::Panel) -> bool {
|
||||
self.panel == panel.id
|
||||
&& self
|
||||
.item
|
||||
.as_ref()
|
||||
.is_none_or(|id| id.0 == "_overflow" || panel.item(id).is_some_and(|item| item.visible))
|
||||
&& self.item.as_ref().is_none_or(|id| {
|
||||
id.0 == "_overflow" || panel.item(id).is_some_and(|item| item.visible)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn same_item(&self, other: &Self) -> bool {
|
||||
@@ -176,7 +180,11 @@ impl OpenMenu {
|
||||
}
|
||||
|
||||
impl FereseShell {
|
||||
pub(crate) fn view_hub_menu(&self, kind: Menu, opacity: f32) -> Element<'_, cosmic::Action<Message>> {
|
||||
pub(crate) fn view_hub_menu(
|
||||
&self,
|
||||
kind: Menu,
|
||||
opacity: f32,
|
||||
) -> Element<'_, cosmic::Action<Message>> {
|
||||
let theme = self.config.theme;
|
||||
let style = MenuStyle {
|
||||
theme,
|
||||
@@ -216,7 +224,12 @@ impl FereseShell {
|
||||
Menu::Bluetooth => bluetooth::view(self, rows, style, true),
|
||||
Menu::Audio => audio::view(self, rows, style, false),
|
||||
Menu::Battery => battery::view(self, rows, style),
|
||||
Menu::Calendar => rows.push(calendar::hub(self.render, self.calendar_offset, theme, opacity)),
|
||||
Menu::Calendar => rows.push(calendar::hub(
|
||||
self.render,
|
||||
self.calendar_offset,
|
||||
theme,
|
||||
opacity,
|
||||
)),
|
||||
Menu::Media => media::hub(self, rows, style),
|
||||
Menu::Notifications => {
|
||||
let mut rows = notification_controls(self, rows, style, true);
|
||||
@@ -305,8 +318,17 @@ impl FereseShell {
|
||||
.class(theme::Text::Color(style.muted)),
|
||||
);
|
||||
}
|
||||
if let Some(error) = self.status_error.as_ref().and_then(|error| kind.action_error(error)) {
|
||||
rows = rows.push(self.render.text(error).size(12).class(theme::Text::Color(style.muted)));
|
||||
if let Some(error) = self
|
||||
.status_error
|
||||
.as_ref()
|
||||
.and_then(|error| kind.action_error(error))
|
||||
{
|
||||
rows = rows.push(
|
||||
self.render
|
||||
.text(error)
|
||||
.size(12)
|
||||
.class(theme::Text::Color(style.muted)),
|
||||
);
|
||||
}
|
||||
container(rows)
|
||||
.width(Length::Fill)
|
||||
@@ -377,7 +399,12 @@ impl FereseShell {
|
||||
.width(Length::Fixed(22.))
|
||||
.into()
|
||||
};
|
||||
let badge = ferese_theme::menus::badge(heading_icon, color(theme.accent), p, self.render.radius(20.));
|
||||
let badge = ferese_theme::menus::badge(
|
||||
heading_icon,
|
||||
color(theme.accent),
|
||||
p,
|
||||
self.render.radius(20.),
|
||||
);
|
||||
let mut heading = ferese_theme::menus::heading(badge, kind.title(), self.render.font);
|
||||
let style = MenuStyle {
|
||||
theme,
|
||||
@@ -402,7 +429,9 @@ impl FereseShell {
|
||||
Menu::Bluetooth => bluetooth::view(self, rows, style, false),
|
||||
Menu::Audio => audio::view(self, rows, style, false),
|
||||
Menu::Battery => battery::view(self, rows, style),
|
||||
Menu::Calendar => rows.push(calendar::view(self.render, self.calendar_offset, theme, p)),
|
||||
Menu::Calendar => {
|
||||
rows.push(calendar::view(self.render, self.calendar_offset, theme, p))
|
||||
}
|
||||
Menu::Notifications => notification_controls(self, rows, style, false),
|
||||
Menu::Activities => rows.push(self.activity_list(menu.anchor.parent, p)),
|
||||
Menu::Recording | Menu::Workspaces => rows,
|
||||
@@ -423,25 +452,34 @@ impl FereseShell {
|
||||
.as_ref()
|
||||
.and_then(|error| menu.kind.action_error(error))
|
||||
{
|
||||
rows = rows.push(self.render.text(error).size(12).class(theme::Text::Color(Color {
|
||||
a: p,
|
||||
..Color::from_rgb8(230, 172, 90)
|
||||
})));
|
||||
rows = rows.push(
|
||||
self.render
|
||||
.text(error)
|
||||
.size(12)
|
||||
.class(theme::Text::Color(Color {
|
||||
a: p,
|
||||
..Color::from_rgb8(230, 172, 90)
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
let compositor_material = menu.effects.is_some();
|
||||
let body: Element<'_, cosmic::Action<Message>> = if matches!(kind, Menu::Overflow | Menu::Activities) {
|
||||
cosmic::widget::scrollable(rows).height(Length::Shrink).into()
|
||||
} else {
|
||||
rows.into()
|
||||
};
|
||||
let body: Element<'_, cosmic::Action<Message>> =
|
||||
if matches!(kind, Menu::Overflow | Menu::Activities) {
|
||||
cosmic::widget::scrollable(rows)
|
||||
.height(Length::Shrink)
|
||||
.into()
|
||||
} else {
|
||||
rows.into()
|
||||
};
|
||||
let panel = container(body)
|
||||
.id("ferese-blur-card")
|
||||
.width(kind.width())
|
||||
.padding(16)
|
||||
.class(theme::Container::custom(move |_| container::Style {
|
||||
background: (!compositor_material)
|
||||
.then_some(Background::Color(color_with_opacity(theme.surface_popover, p))),
|
||||
background: (!compositor_material).then_some(Background::Color(
|
||||
color_with_opacity(theme.surface_popover, p),
|
||||
)),
|
||||
text_color: Some(primary),
|
||||
icon_color: Some(primary),
|
||||
border: Border {
|
||||
@@ -488,7 +526,14 @@ fn notification_controls<'a>(
|
||||
opacity: p,
|
||||
} = style;
|
||||
if let Some(n) = &shell.status.notifications {
|
||||
let toggle = toggle_row(shell.render, "Do Not Disturb", n.dnd, Action::Dnd(!n.dnd), theme, p);
|
||||
let toggle = toggle_row(
|
||||
shell.render,
|
||||
"Do Not Disturb",
|
||||
n.dnd,
|
||||
Action::Dnd(!n.dnd),
|
||||
theme,
|
||||
p,
|
||||
);
|
||||
rows = rows.push(if combined {
|
||||
control_card(shell.render, toggle, primary, p)
|
||||
} else {
|
||||
@@ -528,7 +573,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn activity_popups_scroll_to_the_last_row_in_regular_panels() {
|
||||
use cosmic::iced::advanced::{Layout, Shell, clipboard, layout, renderer::Headless, widget};
|
||||
use cosmic::iced::advanced::{
|
||||
Layout, Shell, clipboard, layout, renderer::Headless, widget,
|
||||
};
|
||||
use cosmic::iced::{Event, Rectangle, Size, Vector, mouse};
|
||||
use ferese_activities::{Data, Owner, Source, Store, Template, Value};
|
||||
#[derive(Default)]
|
||||
@@ -575,7 +622,10 @@ mod tests {
|
||||
for n in 0..24 {
|
||||
store
|
||||
.start(
|
||||
Owner { pid: n + 1, birth: 1 },
|
||||
Owner {
|
||||
pid: n + 1,
|
||||
birth: 1,
|
||||
},
|
||||
n.to_string(),
|
||||
Data {
|
||||
source: Source::Publisher,
|
||||
|
||||
@@ -7,9 +7,15 @@ use super::{Menu, MenuRows, MenuStyle};
|
||||
use crate::FereseShell;
|
||||
use crate::status::Action;
|
||||
|
||||
pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: MenuStyle) -> MenuRows<'a> {
|
||||
pub(super) fn view<'a>(
|
||||
shell: &'a FereseShell,
|
||||
mut rows: MenuRows<'a>,
|
||||
style: MenuStyle,
|
||||
) -> MenuRows<'a> {
|
||||
let MenuStyle {
|
||||
primary, opacity: p, ..
|
||||
primary,
|
||||
opacity: p,
|
||||
..
|
||||
} = style;
|
||||
if let Some(n) = &shell.status.network {
|
||||
let connected = n.enabled && n.connection.is_some();
|
||||
@@ -42,7 +48,11 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
rows = rows.push(
|
||||
column![
|
||||
row![
|
||||
shell.render.text("Signal strength").size(12).width(Length::Fill),
|
||||
shell
|
||||
.render
|
||||
.text("Signal strength")
|
||||
.size(12)
|
||||
.width(Length::Fill),
|
||||
shell.render.text(strength).size(12)
|
||||
],
|
||||
level_meter(shell.render, n.signal, primary, p),
|
||||
@@ -59,7 +69,9 @@ pub(super) fn heading<'a>(
|
||||
mut heading: super::MenuHeading<'a>,
|
||||
style: MenuStyle,
|
||||
) -> super::MenuHeading<'a> {
|
||||
let MenuStyle { theme, opacity: p, .. } = style;
|
||||
let MenuStyle {
|
||||
theme, opacity: p, ..
|
||||
} = style;
|
||||
if let Some(network) = &shell.status.network {
|
||||
heading = heading.push(shell_switch(
|
||||
shell.render,
|
||||
|
||||
@@ -2,7 +2,11 @@ use cosmic::widget::{column, slider};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: MenuStyle) -> MenuRows<'a> {
|
||||
pub(super) fn view<'a>(
|
||||
shell: &'a FereseShell,
|
||||
mut rows: MenuRows<'a>,
|
||||
style: MenuStyle,
|
||||
) -> MenuRows<'a> {
|
||||
let Some(status) = &shell.status.night_light else {
|
||||
return rows.push(shell.render.text("Night light is unavailable").size(13));
|
||||
};
|
||||
@@ -28,9 +32,19 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
|
||||
shell.render.text("Lower temperatures are warmer").size(12),
|
||||
]
|
||||
.spacing(8);
|
||||
rows = rows.push(control_card(shell.render, warmth.into(), style.primary, style.opacity));
|
||||
rows = rows.push(control_card(
|
||||
shell.render,
|
||||
warmth.into(),
|
||||
style.primary,
|
||||
style.opacity,
|
||||
));
|
||||
if status.supported_outputs == 0 {
|
||||
rows = rows.push(shell.render.text("No display supports night light").size(13));
|
||||
rows = rows.push(
|
||||
shell
|
||||
.render
|
||||
.text("No display supports night light")
|
||||
.size(13),
|
||||
);
|
||||
} else if status.enabled && status.failed_outputs > 0 {
|
||||
rows = rows.push(
|
||||
shell
|
||||
|
||||
@@ -22,7 +22,11 @@ pub(super) fn view<'a>(
|
||||
} = style;
|
||||
use ferese_config::theme::{Appearance, Mode};
|
||||
let mut modes = row([]).spacing(6);
|
||||
for (mode, label) in [(Mode::Light, "☀ Light"), (Mode::Dark, "☾ Dark"), (Mode::Auto, "◐ Auto")] {
|
||||
for (mode, label) in [
|
||||
(Mode::Light, "☀ Light"),
|
||||
(Mode::Dark, "☾ Dark"),
|
||||
(Mode::Auto, "◐ Auto"),
|
||||
] {
|
||||
modes = modes.push(motion::button(
|
||||
shell.render,
|
||||
button::custom(shell.render.text(label).font(shell.render.font).size(13))
|
||||
@@ -45,7 +49,12 @@ pub(super) fn view<'a>(
|
||||
let settings = motion::button(
|
||||
shell.render,
|
||||
button::custom(
|
||||
ferese_theme::icons::tinted(ferese_theme::icons::SETTINGS, 18, color(theme.text_primary)).opacity(p),
|
||||
ferese_theme::icons::tinted(
|
||||
ferese_theme::icons::SETTINGS,
|
||||
18,
|
||||
color(theme.text_primary),
|
||||
)
|
||||
.opacity(p),
|
||||
)
|
||||
.name("Open Ferese Settings")
|
||||
.width(30)
|
||||
@@ -135,7 +144,10 @@ pub(super) fn view<'a>(
|
||||
);
|
||||
}
|
||||
|
||||
if shell.status.network.is_some() || shell.status.bluetooth.is_some() || shell.status.battery.is_some() {
|
||||
if shell.status.network.is_some()
|
||||
|| shell.status.bluetooth.is_some()
|
||||
|| shell.status.battery.is_some()
|
||||
{
|
||||
rows = rows.push(control_card(shell.render, connections.into(), primary, p));
|
||||
}
|
||||
rows = audio::view(shell, rows, style, true);
|
||||
@@ -195,7 +207,10 @@ fn connection_control<'a>(
|
||||
.height(28)
|
||||
.align_x(alignment::Horizontal::Center)
|
||||
.align_y(alignment::Vertical::Center);
|
||||
let content = column![icon].spacing(2).width(Length::Fill).align_x(Alignment::Center);
|
||||
let content = column![icon]
|
||||
.spacing(2)
|
||||
.width(Length::Fill)
|
||||
.align_x(Alignment::Center);
|
||||
let content = content.push(
|
||||
render
|
||||
.text(connection_caption(detail))
|
||||
@@ -210,12 +225,18 @@ fn connection_control<'a>(
|
||||
.class(theme::Text::Color(muted)),
|
||||
);
|
||||
let Some(action) = action else {
|
||||
return container(content).width(Length::FillPortion(1)).padding(4).into();
|
||||
return container(content)
|
||||
.width(Length::FillPortion(1))
|
||||
.padding(4)
|
||||
.into();
|
||||
};
|
||||
let button = button::custom(content)
|
||||
.width(Length::Fill)
|
||||
.padding(4)
|
||||
.name(format!("{label}: {}, {detail}", if enabled { "on" } else { "off" }))
|
||||
.name(format!(
|
||||
"{label}: {}, {detail}",
|
||||
if enabled { "on" } else { "off" }
|
||||
))
|
||||
.on_press(cosmic::Action::App(Message::Control(action)));
|
||||
let tile: Element<'_, cosmic::Action<Message>> = if selected {
|
||||
button
|
||||
@@ -277,8 +298,14 @@ mod tests {
|
||||
assert_eq!(super::connection_caption("88%"), "88%");
|
||||
assert_eq!(super::connection_caption("Flow84@Lofree"), "Flow84@Lofr…");
|
||||
assert_eq!(super::connection_caption("123456789012"), "123456789012");
|
||||
assert_eq!(super::connection_caption("My very long headphones"), "My very lon…");
|
||||
assert_eq!(super::connection_caption(" Device\n name "), "Device name");
|
||||
assert_eq!(
|
||||
super::connection_caption("My very long headphones"),
|
||||
"My very lon…"
|
||||
);
|
||||
assert_eq!(
|
||||
super::connection_caption(" Device\n name "),
|
||||
"Device name"
|
||||
);
|
||||
let caption = super::connection_caption("耳機耳機耳機耳機耳機耳機耳機");
|
||||
assert_eq!(caption.chars().count(), 12);
|
||||
assert!(caption.ends_with('…'));
|
||||
|
||||
Reference in new issue
Block a user