diff --git a/Cargo.lock b/Cargo.lock index 17bc7c4..9d162ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -870,18 +870,18 @@ dependencies = [ [[package]] name = "clipboard_wayland" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8134163bd07c47ae3cc29babc42c255fdb315facc790950ae2d0e561ea6f2ec0" +checksum = "003f886bc4e2987729d10c1db3424e7f80809f3fc22dbc16c685738887cb37b8" dependencies = [ "smithay-clipboard", ] [[package]] name = "clipboard_x11" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf45b436634fee64c6d3981639b46a87eeea3c64e422643273fcefd1baef56c" +checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c" dependencies = [ "thiserror", "x11rb", @@ -1122,7 +1122,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1139,7 +1139,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "quote", "syn 1.0.109", @@ -1175,7 +1175,7 @@ dependencies = [ [[package]] name = "cosmic-text" version = "0.11.2" -source = "git+https://github.com/pop-os/cosmic-text.git#0cb6eba6e708e2743313ee0016162de7a0146353" +source = "git+https://github.com/pop-os/cosmic-text.git#85821731285bf88d712dce8e7410453d908bc038" dependencies = [ "bitflags 2.4.2", "fontdb", @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "almost", "cosmic-config", @@ -2017,9 +2017,9 @@ dependencies = [ [[package]] name = "freedesktop-icons" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5339cbd60b2ff6b95ef212ab96bc80bf1a9dff2821b9966c417cdfae2808796" +checksum = "a8ef34245e0540c9a3ce7a28340b98d2c12b75da0d446da4e8224923fcaa0c16" dependencies = [ "dirs", "once_cell", @@ -2460,9 +2460,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -2578,7 +2578,7 @@ dependencies = [ [[package]] name = "iced" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "iced_accessibility", "iced_core", @@ -2593,7 +2593,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "accesskit", "accesskit_winit", @@ -2602,7 +2602,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "bitflags 1.3.2", "log", @@ -2619,7 +2619,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "futures", "iced_core", @@ -2632,7 +2632,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2656,7 +2656,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2668,7 +2668,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "iced_core", "iced_futures", @@ -2678,7 +2678,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "iced_core", "once_cell", @@ -2688,7 +2688,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "bytemuck", "cosmic-text", @@ -2705,7 +2705,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2724,7 +2724,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "iced_renderer", "iced_runtime", @@ -2738,7 +2738,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "iced_graphics", "iced_runtime", @@ -3066,7 +3066,7 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#02cee1d8051f504860d9b961245919fde1542355" +source = "git+https://github.com/pop-os/libcosmic.git#b430656966a24158270912a2ff827c77aae39de4" dependencies = [ "apply", "ashpd", @@ -5231,7 +5231,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.4", + "toml_edit 0.22.5", ] [[package]] @@ -5251,7 +5251,7 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -5262,20 +5262,20 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.4" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951" +checksum = "99e68c159e8f5ba8a28c4eb7b0c0c190d77bb479047ca713270048145a9ad28a" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.0", ] [[package]] @@ -6009,9 +6009,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window_clipboard" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a197337269a469b5b2583d65dd7dfe475fd79a525be0aa647ff6d37ac6612c" +checksum = "f6d692d46038c433f9daee7ad8757e002a4248c20b0a3fbc991d99521d3bcb6d" dependencies = [ "clipboard-win", "clipboard_macos", @@ -6361,9 +6361,18 @@ dependencies = [ [[package]] name = "winnow" -version = "0.5.39" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1dbce9e90e5404c5a52ed82b1d13fc8cfbdad85033b6f57546ffd1265f8451" dependencies = [ "memchr", ] diff --git a/examples/dialog.rs b/examples/dialog.rs index 6ac8c3d..24c5eeb 100644 --- a/examples/dialog.rs +++ b/examples/dialog.rs @@ -1,11 +1,113 @@ +use cosmic::{ + app::{self, Command, Core, Settings}, + executor, + iced::{subscription::Subscription, window}, + widget, Application, Element, +}; +use cosmic_files::dialog::{Dialog, DialogMessage, DialogResult}; + fn main() -> Result<(), Box> { - match cosmic_files::dialog()? { - Some(paths) => { - for path in paths { - println!("{}", path.display()); - } - } - None => {} - } + let settings = Settings::default(); + app::run::(settings, ())?; Ok(()) } + +#[derive(Clone, Debug)] +pub enum Message { + DialogMessage(DialogMessage), + DialogOpen, + DialogResult(DialogResult), +} + +pub struct App { + core: Core, + dialog_opt: Option>, + result_opt: Option, +} + +impl Application for App { + type Executor = executor::Default; + type Flags = (); + type Message = Message; + + const APP_ID: &'static str = "com.system76.CosmicFilesDialogExample"; + + fn core(&self) -> &Core { + &self.core + } + + fn core_mut(&mut self) -> &mut Core { + &mut self.core + } + + fn init(core: Core, _flags: Self::Flags) -> (Self, Command) { + ( + Self { + core, + dialog_opt: None, + result_opt: None, + }, + Command::none(), + ) + } + + fn update(&mut self, message: Message) -> Command { + match message { + Message::DialogMessage(dialog_message) => { + if let Some(dialog) = &mut self.dialog_opt { + return dialog.update(dialog_message); + } + } + Message::DialogOpen => { + if self.dialog_opt.is_none() { + let (dialog, command) = + Dialog::new(Message::DialogMessage, Message::DialogResult); + self.dialog_opt = Some(dialog); + return command; + } + } + Message::DialogResult(result) => { + self.dialog_opt = None; + self.result_opt = Some(result); + } + } + + Command::none() + } + + fn view_window(&self, window_id: window::Id) -> Element { + match &self.dialog_opt { + Some(dialog) => dialog.view(window_id), + None => widget::text("No dialog").into(), + } + } + + fn view(&self) -> Element { + let mut button = widget::button(widget::text("Open Dialog")); + if self.dialog_opt.is_none() { + button = button.on_press(Message::DialogOpen); + } + let mut column = widget::column(); + column = column.push(button); + if let Some(result) = &self.result_opt { + match result { + DialogResult::Cancel => { + column = column.push(widget::text("Cancel")); + } + DialogResult::Open(paths) => { + for path in paths.iter() { + column = column.push(widget::text(format!("{}", path.display()))); + } + } + } + } + column.into() + } + + fn subscription(&self) -> Subscription { + match &self.dialog_opt { + Some(dialog) => dialog.subscription(), + None => Subscription::none(), + } + } +} diff --git a/src/dialog.rs b/src/dialog.rs index e3f0f90..3be612f 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -2,12 +2,17 @@ // SPDX-License-Identifier: GPL-3.0-only use cosmic::{ - app::{message, Command, Core}, + app::{ + self, + cosmic::{Cosmic, Message as CosmicMessage}, + message, Command, Core, + }, cosmic_theme, executor, iced::{ event, futures::{self, SinkExt}, keyboard::{Event as KeyEvent, Modifiers}, + multi_window::Application as IcedApplication, subscription::{self, Subscription}, window, Event, Length, }, @@ -31,13 +36,89 @@ use crate::{ }; #[derive(Clone, Debug)] -pub struct Flags { - pub result_lock: Arc>>>, +pub struct DialogMessage(app::Message); + +#[derive(Clone, Debug)] +pub enum DialogResult { + Cancel, + Open(Vec), +} + +pub struct Dialog { + cosmic: Cosmic, + mapper: fn(DialogMessage) -> M, + on_result: fn(DialogResult) -> M, +} + +impl Dialog { + pub fn new( + mapper: fn(DialogMessage) -> M, + on_result: fn(DialogResult) -> M, + ) -> (Self, Command) { + let mut settings = window::Settings::default(); + settings.decorations = false; + settings.exit_on_close_request = false; + settings.transparent = true; + settings.platform_specific.application_id = App::APP_ID.to_string(); + let (window_id, window_command) = window::spawn(settings); + + let core = Core::default(); + let flags = Flags { window_id }; + let (cosmic, cosmic_command) = as IcedApplication>::new((core, flags)); + + ( + Self { + cosmic, + mapper, + on_result, + }, + Command::batch([window_command, cosmic_command]) + .map(DialogMessage) + .map(move |message| app::Message::App(mapper(message))), + ) + } + + pub fn subscription(&self) -> Subscription { + self.cosmic + .subscription() + .map(DialogMessage) + .map(self.mapper) + } + + pub fn update(&mut self, message: DialogMessage) -> Command { + let mapper = self.mapper; + let command = self + .cosmic + .update(message.0) + .map(DialogMessage) + .map(move |message| app::Message::App(mapper(message))); + if let Some(result) = self.cosmic.app.result_opt.take() { + let on_result = self.on_result; + Command::batch([ + command, + Command::perform(async move { app::Message::App(on_result(result)) }, |x| x), + ]) + } else { + command + } + } + + pub fn view(&self, window_id: window::Id) -> Element { + self.cosmic + .view(window_id) + .map(DialogMessage) + .map(self.mapper) + } +} + +#[derive(Clone, Debug)] +struct Flags { + window_id: window::Id, } /// Messages that are used specifically by our [`App`]. #[derive(Clone, Debug)] -pub enum Message { +enum Message { Cancel, Modifiers(Modifiers), NotifyEvent(notify::Event), @@ -51,7 +132,7 @@ pub enum Message { } #[derive(Debug)] -pub struct WatcherWrapper { +struct WatcherWrapper { watcher_opt: Option, } @@ -68,12 +149,13 @@ impl PartialEq for WatcherWrapper { } /// The [`App`] stores application-specific state. -pub struct App { +struct App { core: Core, flags: Flags, - nav_model: segmented_button::SingleSelectModel, - tab_model: segmented_button::Model, modifiers: Modifiers, + nav_model: segmented_button::SingleSelectModel, + result_opt: Option, + tab_model: segmented_button::Model, watcher_opt: Option<(notify::RecommendedWatcher, HashSet)>, } @@ -124,7 +206,7 @@ impl App { None => (String::new(), "COSMIC File Manager".to_string()), }; self.set_header_title(header_title); - self.set_window_title(window_title, window::Id::MAIN) + self.set_window_title(window_title, self.main_window_id()) } fn update_watcher(&mut self) -> Command { @@ -187,7 +269,7 @@ impl Application for App { type Message = Message; /// The unique application ID to supply to the window manager. - const APP_ID: &'static str = "com.system76.CosmicFiles"; + const APP_ID: &'static str = "com.system76.CosmicFilesDialog"; fn core(&self) -> &Core { &self.core @@ -198,7 +280,7 @@ impl Application for App { } /// Creates the application, and optionally emits command on initialize. - fn init(mut core: Core, flags: Self::Flags) -> (Self, Command) { + fn init(mut core: Core, flags: Self::Flags) -> (Self, Command) { core.window.show_maximize = false; core.window.show_minimize = false; @@ -232,9 +314,10 @@ impl Application for App { let mut app = App { core, flags, - nav_model: nav_model.build(), - tab_model: segmented_button::ModelBuilder::default().build(), modifiers: Modifiers::empty(), + nav_model: nav_model.build(), + result_opt: None, + tab_model: segmented_button::ModelBuilder::default().build(), watcher_opt: None, }; @@ -247,8 +330,12 @@ impl Application for App { (app, Command::batch(commands)) } + fn main_window_id(&self) -> window::Id { + self.flags.window_id + } + // The default nav_bar widget needs to have its width reduced for cosmic-files - fn nav_bar(&self) -> Option>> { + fn nav_bar(&self) -> Option>> { if !self.core().nav_bar_active() { return None; } @@ -270,7 +357,11 @@ impl Application for App { Some(&self.nav_model) } - fn on_nav_select(&mut self, entity: segmented_button::Entity) -> Command { + fn on_app_exit(&mut self) { + self.result_opt = Some(DialogResult::Cancel); + } + + fn on_nav_select(&mut self, entity: segmented_button::Entity) -> Command { let location_opt = self.nav_model.data::(entity).clone(); if let Some(location) = location_opt { @@ -282,11 +373,11 @@ impl Application for App { } /// Handle application events here. - fn update(&mut self, message: Self::Message) -> Command { + fn update(&mut self, message: Message) -> Command { match message { Message::Cancel => { - *self.flags.result_lock.lock().unwrap() = None; - return window::close(window::Id::MAIN); + self.result_opt = Some(DialogResult::Cancel); + return window::close(self.main_window_id()); } Message::Modifiers(modifiers) => { self.modifiers = modifiers; @@ -341,8 +432,8 @@ impl Application for App { } } } - *self.flags.result_lock.lock().unwrap() = Some(paths); - return window::close(window::Id::MAIN); + self.result_opt = Some(DialogResult::Open(paths)); + return window::close(self.main_window_id()); } Message::SelectAll(entity_opt) => { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); @@ -379,7 +470,7 @@ impl Application for App { // If that was the last tab, close window if self.tab_model.iter().next().is_none() { - return window::close(window::Id::MAIN); + return window::close(self.main_window_id()); } return Command::batch([self.update_title(), self.update_watcher()]); @@ -417,7 +508,7 @@ impl Application for App { } /// Creates a view after each update. - fn view(&self) -> Element { + fn view(&self) -> Element { let cosmic_theme::Spacing { space_xxs, .. } = self.core().system_theme().cosmic().spacing; let mut tab_column = widget::column::with_capacity(1); @@ -470,7 +561,7 @@ impl Application for App { content } - fn subscription(&self) -> Subscription { + fn subscription(&self) -> Subscription { struct WatcherSubscription; Subscription::batch([ diff --git a/src/lib.rs b/src/lib.rs index 37da796..555e6ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,11 +6,7 @@ use cosmic::{ cosmic_config::{self, CosmicConfigEntry}, iced::Limits, }; -use std::{ - path::PathBuf, - process, - sync::{Arc, Mutex}, -}; +use std::{path::PathBuf, process}; use app::{App, Flags}; mod app; @@ -35,24 +31,6 @@ pub fn home_dir() -> PathBuf { } } -/// Runs application with these settings -pub fn dialog() -> Result>, Box> { - localize::localize(); - - let mut settings = Settings::default(); - - let mut result_lock = Arc::new(Mutex::new(None)); - - let flags = dialog::Flags { - result_lock: result_lock.clone(), - }; - cosmic::app::run::(settings, flags)?; - - let mut result_guard = result_lock.lock().unwrap(); - let result = result_guard.take(); - Ok(result) -} - /// Runs application with these settings #[rustfmt::skip] pub fn main() -> Result<(), Box> { diff --git a/src/menu.rs b/src/menu.rs index 3dea369..0e8a57d 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -14,10 +14,10 @@ use cosmic::{ use std::collections::HashMap; use crate::{ - app::{Action, ContextPage, Message}, + app::{Action, Message}, fl, key_bind::KeyBind, - tab::{self, Location, Tab}, + tab::{Location, Tab}, }; macro_rules! menu_button { diff --git a/src/operation.rs b/src/operation.rs index c4040e7..45fa2d4 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -1,5 +1,5 @@ use cosmic::iced::futures::{channel::mpsc, SinkExt}; -use std::{error::Error, future::Future, io, path::PathBuf, time}; +use std::path::PathBuf; use crate::app::Message; diff --git a/src/tab.rs b/src/tab.rs index 71eb060..24aa934 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -23,7 +23,7 @@ use std::{ time::{Duration, Instant}, }; -use crate::{config::TabConfig, fl, home_dir, mime_icon::mime_icon}; +use crate::{config::TabConfig, fl, mime_icon::mime_icon}; const DOUBLE_CLICK_DURATION: Duration = Duration::from_millis(500); //TODO: configurable