fix clippy warnings

This commit is contained in:
Samuel Onoja committed 2026-10-01 13:24:21 +01:00
1 parent 7b88083020
commit bdc3ba435f
39 files changed
+825 -688

No files matched your search

+30 -30
View File
@@ -169,6 +169,35 @@ fn account_picture(user: &str) -> Option<image::Handle> {
})
}
pub fn load_wallpaper(path: &std::path::Path, blur: f32) -> Result<image::Handle, String> {
use ::image::ImageDecoder;
let mut reader = ::image::ImageReader::open(path)
.map_err(|e| e.to_string())?
.with_guessed_format()
.map_err(|e| e.to_string())?;
let mut limits = ::image::Limits::default();
limits.max_alloc = Some(256 * 1024 * 1024);
reader.limits(limits);
let decoder = reader.into_decoder().map_err(|e| e.to_string())?;
let (width, height) = decoder.dimensions();
if u64::from(width) * u64::from(height) * 4 > 256 * 1024 * 1024 {
return Err("Lock wallpaper exceeds the decode limit".into());
}
let pixels = ::image::DynamicImage::from_decoder(decoder)
.map_err(|e| e.to_string())?
.into_rgba8();
let pixels = if blur > 0. {
::image::imageops::blur(&::image::imageops::thumbnail(&pixels, 640, 640), blur)
} else {
pixels
};
Ok(image::Handle::from_rgba(
pixels.width(),
pixels.height(),
pixels.into_raw(),
))
}
#[cfg(test)]
mod tests {
use super::*;
@@ -215,39 +244,10 @@ mod tests {
appearance.accent,
ferese_theme::parse_color(&theme.tokens.colors.accent).unwrap()
);
assert!(ferese_theme::contrast(appearance.accent.into(), appearance.on_accent.into()) >= 4.5);
assert!(ferese_theme::contrast(appearance.accent, appearance.on_accent) >= 4.5);
assert!(!appearance.show_clock && !appearance.show_date);
assert_eq!(appearance.clock_format(), "%I:%M %p");
assert_eq!(appearance.dim, 0.7);
assert_eq!(appearance.theme().cosmic().corner_radii.radius_m, [0.; 4]);
}
}
pub fn load_wallpaper(path: &std::path::Path, blur: f32) -> Result<image::Handle, String> {
use ::image::ImageDecoder;
let mut reader = ::image::ImageReader::open(path)
.map_err(|e| e.to_string())?
.with_guessed_format()
.map_err(|e| e.to_string())?;
let mut limits = ::image::Limits::default();
limits.max_alloc = Some(256 * 1024 * 1024);
reader.limits(limits);
let decoder = reader.into_decoder().map_err(|e| e.to_string())?;
let (width, height) = decoder.dimensions();
if u64::from(width) * u64::from(height) * 4 > 256 * 1024 * 1024 {
return Err("Lock wallpaper exceeds the decode limit".into());
}
let pixels = ::image::DynamicImage::from_decoder(decoder)
.map_err(|e| e.to_string())?
.into_rgba8();
let pixels = if blur > 0. {
::image::imageops::blur(&::image::imageops::thumbnail(&pixels, 640, 640), blur)
} else {
pixels
};
Ok(image::Handle::from_rgba(
pixels.width(),
pixels.height(),
pixels.into_raw(),
))
}
+2 -2
View File
@@ -82,7 +82,7 @@ fn main() -> iced::Result {
#[derive(Clone)]
enum Message {
ThemeChanged(ferese_config::theme::Snapshot),
ThemeChanged(Box<ferese_config::theme::Snapshot>),
WallpaperLoaded(u64, Result<widget::image::Handle, String>),
Event(Box<Event>),
Input(String),
@@ -193,7 +193,7 @@ impl cosmic::Application for Locker {
if self.preview {
Subscription::none()
} else {
ferese_theme::service::subscription().map(Message::ThemeChanged)
ferese_theme::service::subscription().map(|snapshot| Message::ThemeChanged(Box::new(snapshot)))
},
event::listen_with(|event, _, _| match event {
Event::PlatformSpecific(PlatformSpecific::Wayland(
+4 -4
View File
@@ -52,7 +52,7 @@ enum Message {
RefreshDisplays,
DisplaysLoaded(Result<Vec<displays::Display>, String>),
RefreshRate(String, displays::Mode, bool),
ThemeChanged(ferese_config::theme::Snapshot),
ThemeChanged(Box<ferese_config::theme::Snapshot>),
DragWindow,
Page(Page),
Search(String),
@@ -207,7 +207,7 @@ impl cosmic::Application for App {
return self.edit_many(displays::edits(&prefix, mode, automatic));
}
Message::ThemeChanged(snapshot) => {
self.resolved = snapshot;
self.resolved = *snapshot;
self.font = ferese_theme::font(Some(&self.resolved.presented.tokens.typography.font_family));
return self.update_theme();
}
@@ -596,8 +596,8 @@ impl cosmic::Application for App {
fn subscription(&self) -> cosmic::iced::Subscription<Message> {
cosmic::iced::Subscription::batch([
cosmic::iced::Subscription::run_with(self.path.clone(), watch::changes),
ferese_theme::service::subscription().map(Message::ThemeChanged),
cosmic::iced::Subscription::run_with(self.path.clone(), |path| watch::changes(path)),
ferese_theme::service::subscription().map(|snapshot| Message::ThemeChanged(Box::new(snapshot))),
if self.page == Page::Displays {
cosmic::iced::time::every(std::time::Duration::from_secs(2)).map(|_| Message::RefreshDisplays)
} else {
+8 -6
View File
@@ -412,12 +412,14 @@ impl App {
format!("{prefix}.scale"),
"Scale",
"Logical size of text and controls.",
1.,
0.75,
3.,
0.25,
"×",
false,
schema::RangeSpec {
default: 1.,
min: 0.75,
max: 3.,
step: 0.25,
suffix: "×",
integer: false,
},
)));
body = body.push(container(group).padding(8).class(visuals::surface(palette.card, 14.)));
}
+347 -252
View File
@@ -148,17 +148,30 @@ fn toggle(path: &str, label: &str, description: &str, default: bool) -> Field {
Field::new(path, label, description, Kind::Toggle(default))
}
#[derive(Clone, Copy, Debug)]
pub struct RangeSpec {
pub default: f64,
pub min: f64,
pub max: f64,
pub step: f64,
pub suffix: &'static str,
pub integer: bool,
}
pub fn range(
path: impl Into<String>,
label: impl Into<String>,
description: impl Into<String>,
default: f64,
min: f64,
max: f64,
step: f64,
suffix: &'static str,
integer: bool,
spec: RangeSpec,
) -> Field {
let RangeSpec {
default,
min,
max,
step,
suffix,
integer,
} = spec;
Field::new(
path,
label,
@@ -278,100 +291,118 @@ fn clock_fields() -> Vec<Field> {
"desktop_widgets.clock.margin_x",
"Horizontal margin",
"Distance from left/right edge; ignored when horizontally centered.",
64.0,
0.0,
1000.0,
1.0,
" px",
true,
RangeSpec {
default: 64.0,
min: 0.0,
max: 1000.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
"desktop_widgets.clock.margin_y",
"Vertical margin",
"Distance from top/bottom edge; ignored when vertically centered.",
80.0,
0.0,
1000.0,
1.0,
" px",
true,
RangeSpec {
default: 80.0,
min: 0.0,
max: 1000.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
"desktop_widgets.clock.width",
"Widget width",
"Logical pixels; increase for longer formats.",
440.0,
64.0,
1600.0,
1.0,
" px",
true,
RangeSpec {
default: 440.0,
min: 64.0,
max: 1600.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
"desktop_widgets.clock.height",
"Widget height",
"Leave room for both text lines.",
320.0,
32.0,
800.0,
1.0,
" px",
true,
RangeSpec {
default: 320.0,
min: 32.0,
max: 800.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
"desktop_widgets.clock.time_size",
"Time size",
"Logical pixels; scales with your output.",
128.0,
8.0,
240.0,
1.0,
" px",
false,
RangeSpec {
default: 128.0,
min: 8.0,
max: 240.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
"desktop_widgets.clock.date_size",
"Date size",
"Separate size for the date line.",
18.0,
8.0,
96.0,
1.0,
" px",
false,
RangeSpec {
default: 18.0,
min: 8.0,
max: 96.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
"desktop_widgets.clock.opacity",
"Opacity",
"Applies to text and the optional background.",
0.9,
0.0,
1.0,
0.05,
"",
false,
RangeSpec {
default: 0.9,
min: 0.0,
max: 1.0,
step: 0.05,
suffix: "",
integer: false,
},
),
range(
"desktop_widgets.clock.gap",
"Line spacing",
"Space between time and date.",
4.0,
0.0,
64.0,
1.0,
" px",
false,
RangeSpec {
default: 4.0,
min: 0.0,
max: 64.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
"desktop_widgets.clock.padding",
"Inner padding",
"Space around the labels.",
12.0,
0.0,
64.0,
1.0,
" px",
false,
RangeSpec {
default: 12.0,
min: 0.0,
max: 64.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
choice(
"desktop_widgets.clock.alignment",
@@ -422,100 +453,118 @@ pub fn note_fields(index: usize) -> Vec<Field> {
format!("{prefix}.width"),
"Width",
"Logical pixels; centered axes ignore margins.",
320.0,
120.0,
1200.0,
1.0,
" px",
true,
RangeSpec {
default: 320.0,
min: 120.0,
max: 1200.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
format!("{prefix}.height"),
"Height",
"Logical pixels; centered axes ignore margins.",
240.0,
80.0,
1200.0,
1.0,
" px",
true,
RangeSpec {
default: 240.0,
min: 80.0,
max: 1200.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
format!("{prefix}.margin_x"),
"Horizontal margin",
"Logical pixels; centered axes ignore margins.",
48.0,
0.0,
1000.0,
1.0,
" px",
true,
RangeSpec {
default: 48.0,
min: 0.0,
max: 1000.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
format!("{prefix}.margin_y"),
"Vertical margin",
"Logical pixels; centered axes ignore margins.",
80.0,
0.0,
1000.0,
1.0,
" px",
true,
RangeSpec {
default: 80.0,
min: 0.0,
max: 1000.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
format!("{prefix}.text_size"),
"Text size",
"Logical pixels; centered axes ignore margins.",
16.0,
8.0,
96.0,
1.0,
" px",
false,
RangeSpec {
default: 16.0,
min: 8.0,
max: 96.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
format!("{prefix}.title_size"),
"Title size",
"Logical pixels; centered axes ignore margins.",
18.0,
8.0,
96.0,
1.0,
" px",
false,
RangeSpec {
default: 18.0,
min: 8.0,
max: 96.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
format!("{prefix}.opacity"),
"Opacity",
"Logical pixels; centered axes ignore margins.",
0.9,
0.0,
1.0,
0.05,
"",
false,
RangeSpec {
default: 0.9,
min: 0.0,
max: 1.0,
step: 0.05,
suffix: "",
integer: false,
},
),
range(
format!("{prefix}.padding"),
"Padding",
"Logical pixels; centered axes ignore margins.",
20.0,
0.0,
64.0,
1.0,
" px",
false,
RangeSpec {
default: 20.0,
min: 0.0,
max: 64.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
format!("{prefix}.gap"),
"Title spacing",
"Logical pixels; centered axes ignore margins.",
8.0,
0.0,
64.0,
1.0,
" px",
false,
RangeSpec {
default: 8.0,
min: 0.0,
max: 64.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
Field::new(
format!("{prefix}.alignment"),
@@ -536,23 +585,27 @@ pub fn fields(page: Page) -> Vec<Field> {
"lock_screen.dim_after_seconds",
"Dim after",
"Dim the locked display after inactivity. Zero disables dimming.",
30.0,
0.0,
600.0,
5.0,
"s",
true,
RangeSpec {
default: 30.0,
min: 0.0,
max: 600.0,
step: 5.0,
suffix: "s",
integer: true,
},
),
range(
"lock_screen.sleep_after_seconds",
"Display sleep after",
"Turn off locked displays after inactivity. Input wakes them; zero disables display sleep.",
120.0,
0.0,
1800.0,
15.0,
"s",
true,
RangeSpec {
default: 120.0,
min: 0.0,
max: 1800.0,
step: 15.0,
suffix: "s",
integer: true,
},
),
toggle(
"lock_screen.show_clock",
@@ -577,23 +630,27 @@ pub fn fields(page: Page) -> Vec<Field> {
"lock_screen.background_blur",
"Wallpaper softness",
"Blur the lock screen wallpaper. Zero keeps the original image sharp.",
18.0,
0.0,
40.0,
1.0,
"",
false,
RangeSpec {
default: 18.0,
min: 0.0,
max: 40.0,
step: 1.0,
suffix: "",
integer: false,
},
),
range(
"lock_screen.background_dim",
"Wallpaper dimming",
"Darken the wallpaper behind the clock and sign-in card.",
0.48,
0.0,
0.9,
0.02,
"",
false,
RangeSpec {
default: 0.48,
min: 0.0,
max: 0.9,
step: 0.02,
suffix: "",
integer: false,
},
),
],
Page::Accessibility => vec![
@@ -664,12 +721,14 @@ pub fn fields(page: Page) -> Vec<Field> {
"theme.geometry.shell_radius",
"Shell corner radius",
"Rounds the bar, menus, notifications, desktop widgets and hover backgrounds. Window corners are separate.",
14.0,
0.0,
32.0,
1.0,
" px",
false,
RangeSpec {
default: 14.0,
min: 0.0,
max: 32.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
text(
"theme.accent",
@@ -688,23 +747,27 @@ pub fn fields(page: Page) -> Vec<Field> {
"theme.material.opacity",
"Shell opacity",
"Background opacity for the bar, popovers, menus, notifications and sharing dialog. Text and icons stay opaque.",
ferese_config::DEFAULT_MATERIAL_OPACITY,
0.0,
1.0,
0.01,
"",
false,
RangeSpec {
default: ferese_config::DEFAULT_MATERIAL_OPACITY,
min: 0.0,
max: 1.0,
step: 0.01,
suffix: "",
integer: false,
},
),
range(
"theme.material.blur_radius",
"Background blur",
"Softness behind translucent surfaces.",
12.0,
0.0,
32.0,
1.0,
" px",
false,
RangeSpec {
default: 12.0,
min: 0.0,
max: 32.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
text(
"theme.typography.font_family",
@@ -716,12 +779,14 @@ pub fn fields(page: Page) -> Vec<Field> {
"theme.geometry.focus_ring_width",
"Focus border",
"A subtle outline around the active window.",
2.0,
0.0,
4.0,
0.5,
" px",
false,
RangeSpec {
default: 2.0,
min: 0.0,
max: 4.0,
step: 0.5,
suffix: " px",
integer: false,
},
),
],
Page::Wallpaper => vec![
@@ -757,12 +822,14 @@ pub fn fields(page: Page) -> Vec<Field> {
"notifications.timeout_ms",
"Popup timeout",
"Default duration; apps can request another timeout. Pauses while hovered.",
6000.0,
1000.0,
30000.0,
1000.0,
" ms",
true,
RangeSpec {
default: 6000.0,
min: 1000.0,
max: 30000.0,
step: 1000.0,
suffix: " ms",
integer: true,
},
),
],
Page::Bar => vec![
@@ -776,45 +843,53 @@ pub fn fields(page: Page) -> Vec<Field> {
"theme.geometry.top_bar_height",
"Height",
"Keeps icon and text sizes unchanged.",
28.0,
24.0,
48.0,
1.0,
" px",
false,
RangeSpec {
default: 28.0,
min: 24.0,
max: 48.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
"theme.geometry.top_bar_margin_top",
"Top margin",
"Set to zero for an edge-to-edge bar.",
0.0,
0.0,
24.0,
1.0,
" px",
true,
RangeSpec {
default: 0.0,
min: 0.0,
max: 24.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
"theme.geometry.top_bar_margin_horizontal",
"Side margins",
"Space between the bar and the display edges.",
0.0,
0.0,
32.0,
1.0,
" px",
true,
RangeSpec {
default: 0.0,
min: 0.0,
max: 32.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
range(
"theme.geometry.top_bar_window_gap",
"Window clearance",
"Space below the menu bar.",
0.0,
0.0,
24.0,
1.0,
" px",
true,
RangeSpec {
default: 0.0,
min: 0.0,
max: 24.0,
step: 1.0,
suffix: " px",
integer: true,
},
),
toggle(
"status.battery_percentage",
@@ -852,45 +927,53 @@ pub fn fields(page: Page) -> Vec<Field> {
"scrolling.default_column_width",
"New window width",
"Fraction of the available workspace.",
0.5,
0.25,
1.0,
0.05,
"",
false,
RangeSpec {
default: 0.5,
min: 0.25,
max: 1.0,
step: 0.05,
suffix: "",
integer: false,
},
),
range(
"layout.inner_gap",
"Between windows",
"Space between neighboring windows.",
10.0,
0.0,
32.0,
1.0,
" px",
false,
RangeSpec {
default: 10.0,
min: 0.0,
max: 32.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
"layout.outer_gap",
"Workspace edges",
"Space around the outside of the layout.",
4.0,
0.0,
32.0,
1.0,
" px",
false,
RangeSpec {
default: 4.0,
min: 0.0,
max: 32.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
range(
"theme.geometry.window_radius",
"Corner radius",
"Rounded corners for application windows.",
14.0,
0.0,
28.0,
1.0,
" px",
false,
RangeSpec {
default: 14.0,
min: 0.0,
max: 28.0,
step: 1.0,
suffix: " px",
integer: false,
},
),
toggle(
"appearance.inactive_dim.enabled",
@@ -902,12 +985,14 @@ pub fn fields(page: Page) -> Vec<Field> {
"appearance.inactive_dim.amount",
"Dimming amount",
"How much inactive windows recede.",
0.15,
0.0,
0.5,
0.01,
"",
false,
RangeSpec {
default: 0.15,
min: 0.0,
max: 0.5,
step: 0.01,
suffix: "",
integer: false,
},
),
],
Page::Motion => vec![
@@ -921,23 +1006,27 @@ pub fn fields(page: Page) -> Vec<Field> {
"animations.speed",
"Animation speed",
"Lower values give transitions more time.",
1.0,
0.25,
2.0,
0.05,
"×",
false,
RangeSpec {
default: 1.0,
min: 0.25,
max: 2.0,
step: 0.05,
suffix: "×",
integer: false,
},
),
range(
"appearance.inactive_dim.duration_ms",
"Focus transition",
"Time taken to dim an inactive window.",
150.0,
0.0,
600.0,
10.0,
" ms",
false,
RangeSpec {
default: 150.0,
min: 0.0,
max: 600.0,
step: 10.0,
suffix: " ms",
integer: false,
},
),
],
Page::Keyboard => vec![
@@ -957,23 +1046,27 @@ pub fn fields(page: Page) -> Vec<Field> {
"input.repeat_rate",
"Key repeat",
"Characters repeated each second while a key is held.",
25.0,
1.0,
70.0,
1.0,
" /s",
true,
RangeSpec {
default: 25.0,
min: 1.0,
max: 70.0,
step: 1.0,
suffix: " /s",
integer: true,
},
),
range(
"input.repeat_delay_ms",
"Delay before repeat",
"How long to hold a key before it starts repeating.",
600.0,
150.0,
1000.0,
25.0,
" ms",
true,
RangeSpec {
default: 600.0,
min: 150.0,
max: 1000.0,
step: 25.0,
suffix: " ms",
integer: true,
},
),
toggle(
"input.focus_follows_mouse",
@@ -1003,12 +1096,14 @@ pub fn fields(page: Page) -> Vec<Field> {
"input.touchpad.swipe_threshold",
"Swipe distance",
"Distance needed to navigate. Larger values reduce accidental swipes.",
80.0,
16.0,
1000.0,
8.0,
" px",
true,
RangeSpec {
default: 80.0,
min: 16.0,
max: 1000.0,
step: 8.0,
suffix: " px",
integer: true,
},
),
],
Page::Shortcuts => vec![toggle(
+8 -6
View File
@@ -199,12 +199,14 @@ impl App {
let tile_id = gallery_id(&id, appearance);
tiles = tiles.push(gallery::tile(
family,
appearance,
active,
selected,
palette,
self.font,
tile_id,
gallery::TileOptions {
variant: appearance,
active,
selected,
palette,
font: self.font,
id: tile_id,
},
Message::Family(id, appearance),
move |key| {
gallery::neighbor(index, ids.len(), key)
+12 -8
View File
@@ -294,9 +294,11 @@ mod tests {
fn presets_are_distinct_and_readable_on_settings_surfaces() {
for (index, preset) in PRESETS.iter().enumerate() {
let tokens = ferese_config::theme::preset(preset.id, preset.appearance).unwrap();
let mut theme = ferese_config::theme::ResolvedTheme::default();
theme.appearance = preset.appearance;
theme.tokens = tokens;
let theme = ferese_config::theme::ResolvedTheme {
appearance: preset.appearance,
tokens,
..Default::default()
};
let palette = Palette::from_resolved(&theme);
for background in [palette.background, palette.sidebar, palette.card] {
assert!(contrast(palette.text, background) >= 4.5, "{} text", preset.name);
@@ -313,10 +315,10 @@ mod tests {
#[test]
fn selection_tracks_all_preset_colors_and_gradient_changes() {
for index in 0..PRESETS.len() {
for (index, preset) in PRESETS.iter().enumerate() {
let mut snapshot = configured_preset(index);
assert!(preset_selected(&snapshot, index));
let kind = if PRESETS[index].appearance == ferese_config::theme::Appearance::Light {
let kind = if preset.appearance == ferese_config::theme::Appearance::Light {
"light"
} else {
"dark"
@@ -343,9 +345,11 @@ mod tests {
for (index, item) in PRESETS.iter().enumerate() {
let _ = index;
let mut resolved = ferese_config::theme::ResolvedTheme::default();
resolved.appearance = item.appearance;
resolved.tokens = ferese_config::theme::preset(item.id, item.appearance).unwrap();
let resolved = ferese_config::theme::ResolvedTheme {
appearance: item.appearance,
tokens: ferese_config::theme::preset(item.id, item.appearance).unwrap(),
..Default::default()
};
assert_eq!(
Palette::from_resolved(&resolved).native_theme().cosmic().is_dark,
item.appearance == ferese_config::theme::Appearance::Dark
+3 -3
View File
@@ -1,5 +1,5 @@
//! Watch the parent directory so atomic editor saves keep working.
use std::path::PathBuf;
use std::path::Path;
use std::time::Duration;
use cosmic::iced::futures::{SinkExt, Stream};
@@ -8,8 +8,8 @@ use notify::{RecursiveMode, Watcher};
use crate::Message;
use crate::store::Snapshot;
pub fn changes(path: &PathBuf) -> impl Stream<Item = Message> + use<> {
let path = path.clone();
pub fn changes(path: &Path) -> impl Stream<Item = Message> + use<> {
let path = path.to_path_buf();
cosmic::iced::stream::channel(1, async move |mut output| {
let (send, mut events) = tokio::sync::mpsc::channel(1);
+2 -10
View File
@@ -37,7 +37,6 @@ pub(crate) struct WorkspaceSnapshot {
#[derive(Clone, Debug)]
pub(crate) struct WindowSnapshot {
pub(crate) id: u64,
pub(crate) workspace: u64,
pub(crate) app_id: String,
pub(crate) title: String,
@@ -138,12 +137,6 @@ impl ShellControl {
let _ = self.connection.flush();
}
pub(crate) fn activate_window(&self, id: u64) {
let (hi, lo) = split_id(id);
self.shell.activate_window(hi, lo);
let _ = self.connection.flush();
}
pub(crate) fn confirm_logout(&self, serial: u32, revision: u32, token: u32, force: bool) {
self.shell
.confirm_logout_with_inhibitors(serial, revision, token, u32::from(force));
@@ -268,8 +261,8 @@ impl Dispatch<FereseShellV1, ()> for ControlState {
});
}
ferese_shell_v1::Event::Window {
window_hi,
window_lo,
window_hi: _,
window_lo: _,
workspace_hi,
workspace_lo,
app_id,
@@ -285,7 +278,6 @@ impl Dispatch<FereseShellV1, ()> for ControlState {
};
state.pending.windows.push(WindowSnapshot {
id: join_id(window_hi, window_lo),
workspace: join_id(workspace_hi, workspace_lo),
app_id,
title,
+2 -3
View File
@@ -221,7 +221,7 @@ struct OutputSurfaces {
#[derive(Clone, Debug)]
enum Message {
ThemeChanged(ferese_config::theme::Snapshot),
ThemeChanged(Box<ferese_config::theme::Snapshot>),
ThemeMode(ferese_config::theme::Mode),
ThemeModeSet(Result<(), String>),
BeginNoteEdit(String),
@@ -340,7 +340,7 @@ impl cosmic::Application for FereseShell {
fn subscription(&self) -> Subscription<Self::Message> {
Subscription::batch([
ferese_theme::service::subscription().map(Message::ThemeChanged),
ferese_theme::service::subscription().map(|snapshot| Message::ThemeChanged(Box::new(snapshot))),
if self
.system_modal
.as_ref()
@@ -1208,7 +1208,6 @@ mod tests {
}],
workspaces: Vec::new(),
windows: vec![WindowSnapshot {
id: 1,
workspace,
app_id: "dev.ferese.Test".to_owned(),
title: "Test".to_owned(),
+3 -11
View File
@@ -6,7 +6,7 @@ use super::bar::status_icon;
use super::controls::status_summary;
use super::{Menu, MenuRows, MenuStyle};
use crate::status::Action;
use crate::{FereseShell, Message, color_with_opacity, text};
use crate::{FereseShell, Message, text};
const DEVICE_LIST_HEIGHT: f32 = 180.0;
@@ -15,12 +15,7 @@ fn device_list_height(count: usize) -> Option<f32> {
}
pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: MenuStyle) -> MenuRows<'a> {
let MenuStyle {
theme,
primary,
muted,
opacity: p,
} = style;
let MenuStyle { muted, .. } = style;
if let Some(b) = &shell.status.bluetooth {
rows = rows.push(status_summary(
status_icon(Menu::Bluetooth, &shell.status).0,
@@ -36,10 +31,7 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
} else {
"Your connected devices"
},
primary,
muted,
color_with_opacity(theme.accent, p),
p,
style,
b.enabled,
Some((b.enabled, Action::Bluetooth(!b.enabled))),
));
+9 -5
View File
@@ -3,19 +3,23 @@ use cosmic::widget::{button, column, container, row, slider};
use cosmic::{Element, theme};
use crate::status::Action;
use crate::{Message, ShellTheme, accented_icon, color, motion, shell_font, text};
use crate::{Message, ShellTheme, accented_icon, color, color_with_opacity, motion, shell_font, text};
pub(super) fn status_summary<'a>(
source: &'static [u8],
title: &'a str,
subtitle: &'a str,
primary: Color,
muted: Color,
accent: Color,
opacity: f32,
style: super::MenuStyle,
enabled: bool,
toggle: Option<(bool, Action)>,
) -> Element<'a, cosmic::Action<Message>> {
let super::MenuStyle {
theme,
primary,
muted,
opacity,
} = style;
let accent = color_with_opacity(theme.accent, opacity);
let badge_color = if enabled { accent } else { primary };
let badge = container(accented_icon(source, 22, primary, accent))
.width(32)
+3 -9
View File
@@ -5,14 +5,11 @@ use super::bar::status_icon;
use super::controls::{level_meter, shell_switch, status_summary};
use super::{Menu, MenuRows, MenuStyle};
use crate::status::Action;
use crate::{FereseShell, color_with_opacity, text};
use crate::{FereseShell, text};
pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: MenuStyle) -> MenuRows<'a> {
let MenuStyle {
theme,
primary,
muted,
opacity: p,
primary, opacity: p, ..
} = style;
if let Some(n) = &shell.status.network {
let connected = n.enabled && n.connection.is_some();
@@ -30,10 +27,7 @@ pub(super) fn view<'a>(shell: &'a FereseShell, mut rows: MenuRows<'a>, style: Me
} else {
"Wireless connections are paused"
},
primary,
muted,
color_with_opacity(theme.accent, p),
p,
style,
n.enabled,
None,
));
+15 -15
View File
@@ -178,21 +178,6 @@ fn connection_control<'a>(
container(tile).width(Length::FillPortion(1)).into()
}
#[cfg(test)]
mod tests {
#[test]
fn connection_captions_fit_one_short_line() {
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");
let caption = super::connection_caption("耳機耳機耳機耳機耳機耳機耳機");
assert_eq!(caption.chars().count(), 12);
assert!(caption.ends_with('…'));
}
}
pub(super) fn heading<'a>(
shell: &'a FereseShell,
mut heading: super::MenuHeading<'a>,
@@ -229,3 +214,18 @@ pub(super) fn heading<'a>(
}
heading
}
#[cfg(test)]
mod tests {
#[test]
fn connection_captions_fit_one_short_line() {
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");
let caption = super::connection_caption("耳機耳機耳機耳機耳機耳機耳機");
assert_eq!(caption.chars().count(), 12);
assert!(caption.ends_with('…'));
}
}