refactor(appearance): use cosmic::dialog for xdg file chooser dialogs

This commit is contained in:
Michael Aaron Murphy 2025-02-28 11:59:21 +01:00
parent 61f2103b3e
commit 5aeeab9392
No known key found for this signature in database
GPG key ID: B2732D4240C9212C
3 changed files with 61 additions and 44 deletions

View file

@ -146,7 +146,7 @@ page-input = [
"dep:udev", "dep:udev",
] ]
page-networking = [ page-networking = [
"ashpd", "xdg-portal",
"dep:cosmic-dbus-networkmanager", "dep:cosmic-dbus-networkmanager",
"dep:cosmic-settings-subscriptions", "dep:cosmic-settings-subscriptions",
"dep:zbus", "dep:zbus",
@ -166,4 +166,4 @@ single-instance = ["libcosmic/single-instance"]
test = [] test = []
wayland = ["libcosmic/wayland", "dep:cosmic-panel-config", "dep:cosmic-randr"] wayland = ["libcosmic/wayland", "dep:cosmic-panel-config", "dep:cosmic-randr"]
wgpu = ["libcosmic/wgpu"] wgpu = ["libcosmic/wgpu"]
xdg-portal = ["libcosmic/xdg-portal"] xdg-portal = ["ashpd", "libcosmic/xdg-portal"]

View file

@ -8,8 +8,6 @@ use std::borrow::Cow;
use std::sync::Arc; use std::sync::Arc;
//TODO: use embedded cosmic-files for portability //TODO: use embedded cosmic-files for portability
#[cfg(feature = "ashpd")]
use ashpd::desktop::file_chooser::{FileFilter, SelectedFiles};
use cosmic::config::CosmicTk; use cosmic::config::CosmicTk;
use cosmic::cosmic_config::{Config, ConfigSet, CosmicConfigEntry}; use cosmic::cosmic_config::{Config, ConfigSet, CosmicConfigEntry};
use cosmic::cosmic_theme::palette::{FromColor, Hsv, Srgb, Srgba}; use cosmic::cosmic_theme::palette::{FromColor, Hsv, Srgb, Srgba};
@ -17,6 +15,7 @@ use cosmic::cosmic_theme::{
CornerRadii, Density, Spacing, Theme, ThemeBuilder, ThemeMode, DARK_THEME_BUILDER_ID, CornerRadii, Density, Spacing, Theme, ThemeBuilder, ThemeMode, DARK_THEME_BUILDER_ID,
LIGHT_THEME_BUILDER_ID, LIGHT_THEME_BUILDER_ID,
}; };
use cosmic::dialog::file_chooser::{self, FileFilter};
use cosmic::iced_core::{Alignment, Color, Length}; use cosmic::iced_core::{Alignment, Color, Length};
use cosmic::iced_widget::scrollable::{Direction, Scrollbar}; use cosmic::iced_widget::scrollable::{Direction, Scrollbar};
use cosmic::widget::icon::{from_name, icon}; use cosmic::widget::icon::{from_name, icon};
@ -323,6 +322,24 @@ impl
} }
} }
#[derive(Clone)]
pub struct SaveResponse(pub Arc<file_chooser::save::Response>);
impl std::fmt::Debug for SaveResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("SaveResponse")
}
}
#[derive(Clone)]
pub struct OpenResponse(pub Arc<file_chooser::open::FileResponse>);
impl std::fmt::Debug for OpenResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("OpenResponse")
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Message { pub enum Message {
AccentWindowHint(ColorPickerUpdate), AccentWindowHint(ColorPickerUpdate),
@ -338,22 +355,22 @@ pub enum Message {
DisplaySystemFont, DisplaySystemFont,
Entered((IconThemes, IconHandles)), Entered((IconThemes, IconHandles)),
IconsAndToolkit, IconsAndToolkit,
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
ExportError, ExportError,
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
ExportFile(Arc<SelectedFiles>), ExportFile(SaveResponse),
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
ExportSuccess, ExportSuccess,
FontConfig(font_config::Message), FontConfig(font_config::Message),
FontSearch(String), FontSearch(String),
FontSelect(bool, Arc<str>), FontSelect(bool, Arc<str>),
GapSize(u32), GapSize(u32),
IconTheme(usize), IconTheme(usize),
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
ImportError, ImportError,
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
ImportFile(Arc<SelectedFiles>), ImportFile(OpenResponse),
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
ImportSuccess(Box<ThemeBuilder>), ImportSuccess(Box<ThemeBuilder>),
InterfaceText(ColorPickerUpdate), InterfaceText(ColorPickerUpdate),
Left, Left,
@ -361,9 +378,9 @@ pub enum Message {
PaletteAccent(cosmic::iced::Color), PaletteAccent(cosmic::iced::Color),
Reset, Reset,
Roundness(Roundness), Roundness(Roundness),
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
StartExport, StartExport,
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
StartImport, StartImport,
UseDefaultWindowHint(bool), UseDefaultWindowHint(bool),
WindowHintSize(u32), WindowHintSize(u32),
@ -945,18 +962,17 @@ impl Page {
self.reload_theme_mode(); self.reload_theme_mode();
} }
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
Message::StartImport => { Message::StartImport => {
tasks.push(cosmic::task::future(async move { tasks.push(cosmic::task::future(async move {
let res = SelectedFiles::open_file() let res = file_chooser::open::Dialog::new()
.modal(true) .modal(true)
.filter(FileFilter::glob(FileFilter::new("ron"), "*.ron")) .filter(FileFilter::glob(FileFilter::new("ron"), "*.ron"))
.send() .open_file()
.await .await;
.and_then(|request| request.response());
if let Ok(f) = res { if let Ok(f) = res {
Message::ImportFile(Arc::new(f)) Message::ImportFile(OpenResponse(Arc::new(f)))
} else { } else {
// TODO Error toast? // TODO Error toast?
tracing::error!("failed to select a file for importing a custom theme."); tracing::error!("failed to select a file for importing a custom theme.");
@ -965,21 +981,20 @@ impl Page {
})); }));
} }
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
Message::StartExport => { Message::StartExport => {
let is_dark = self.theme_mode.is_dark; let is_dark = self.theme_mode.is_dark;
let name = format!("{}.ron", if is_dark { fl!("dark") } else { fl!("light") }); let name = format!("{}.ron", if is_dark { fl!("dark") } else { fl!("light") });
tasks.push(cosmic::task::future(async move { tasks.push(cosmic::task::future(async move {
let res = SelectedFiles::save_file() let res = file_chooser::save::Dialog::new()
.modal(true) .modal(true)
.current_name(Some(name.as_str())) .file_name(name)
.send() .save_file()
.await .await;
.and_then(|request| request.response());
if let Ok(f) = res { if let Ok(f) = res {
Message::ExportFile(Arc::new(f)) Message::ExportFile(SaveResponse(Arc::new(f)))
} else { } else {
// TODO Error toast? // TODO Error toast?
tracing::error!("failed to select a file for importing a custom theme."); tracing::error!("failed to select a file for importing a custom theme.");
@ -988,13 +1003,14 @@ impl Page {
})); }));
} }
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
Message::ImportFile(f) => { Message::ImportFile(f) => {
let path_res = f let path_res =
.uris() f.0 .0
.first() .uris()
.filter(|f| f.scheme() == "file") .first()
.and_then(|f| f.to_file_path().ok()); .filter(|f| f.scheme() == "file")
.and_then(|f| f.to_file_path().ok());
let Some(path) = path_res else { let Some(path) = path_res else {
return Task::none(); return Task::none();
@ -1012,13 +1028,14 @@ impl Page {
})); }));
} }
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
Message::ExportFile(f) => { Message::ExportFile(f) => {
let path_res = f let path_res =
.uris() f.0 .0
.first() .uris()
.filter(|f| f.scheme() == "file") .first()
.and_then(|f| f.to_file_path().ok()); .filter(|f| f.scheme() == "file")
.and_then(|f| f.to_file_path().ok());
let Some(path) = path_res else { let Some(path) = path_res else {
return Task::none(); return Task::none();
@ -1048,15 +1065,15 @@ impl Page {
} }
// TODO: error message toast? // TODO: error message toast?
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
Message::ExportError | Message::ImportError => return Task::none(), Message::ExportError | Message::ImportError => return Task::none(),
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
Message::ExportSuccess => { Message::ExportSuccess => {
tracing::trace!("Export successful"); tracing::trace!("Export successful");
} }
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
Message::ImportSuccess(builder) => { Message::ImportSuccess(builder) => {
tracing::trace!("Import successful"); tracing::trace!("Import successful");
self.theme_builder = *builder; self.theme_builder = *builder;
@ -1524,7 +1541,7 @@ impl page::Page<crate::pages::Message> for Page {
]) ])
} }
#[cfg(feature = "ashpd")] #[cfg(feature = "xdg-portal")]
fn header_view(&self) -> Option<Element<'_, crate::pages::Message>> { fn header_view(&self) -> Option<Element<'_, crate::pages::Message>> {
let content = row::with_capacity(2) let content = row::with_capacity(2)
.spacing(self.theme_builder.spacing.space_xxs) .spacing(self.theme_builder.spacing.space_xxs)

View file

@ -6,7 +6,7 @@ mod nmcli;
use std::sync::Arc; use std::sync::Arc;
use anyhow::Context; use anyhow::Context;
use ashpd::desktop::file_chooser::FileFilter; use cosmic::dialog::file_chooser::FileFilter;
use cosmic::{ use cosmic::{
iced::{Alignment, Length}, iced::{Alignment, Length},
iced_core::text::Wrapping, iced_core::text::Wrapping,