Merge pull request #618 from pop-os/libcosmic-rebase
Update libcosmic/iced
This commit is contained in:
commit
2ae97c167c
11 changed files with 1097 additions and 1116 deletions
1236
Cargo.lock
generated
1236
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -63,19 +63,18 @@ uzers = "0.12.0"
|
||||||
[dependencies.libcosmic]
|
[dependencies.libcosmic]
|
||||||
git = "https://github.com/pop-os/libcosmic.git"
|
git = "https://github.com/pop-os/libcosmic.git"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["a11y", "clipboard", "multi-window", "tokio"]
|
features = ["a11y", "multi-window", "tokio", "winit"]
|
||||||
|
|
||||||
[dependencies.smol_str]
|
[dependencies.smol_str]
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
features = ["serde"]
|
features = ["serde"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["bzip2", "desktop", "gvfs", "liblzma", "notify", "winit", "wgpu"]
|
default = ["bzip2", "desktop", "gvfs", "liblzma", "notify", "wgpu"]
|
||||||
desktop = ["libcosmic/desktop", "dep:xdg"]
|
desktop = ["libcosmic/desktop", "dep:xdg"]
|
||||||
gvfs = ["dep:gio", "dep:glib"]
|
gvfs = ["dep:gio", "dep:glib"]
|
||||||
notify = ["dep:notify-rust"]
|
notify = ["dep:notify-rust"]
|
||||||
wayland = ["libcosmic/wayland", "dep:wayland-client"]
|
wayland = ["libcosmic/wayland", "dep:wayland-client"]
|
||||||
winit = ["libcosmic/winit"]
|
|
||||||
wgpu = ["libcosmic/wgpu"]
|
wgpu = ["libcosmic/wgpu"]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app::{self, Command, Core, Settings},
|
app::{self, Core, Settings, Task},
|
||||||
executor,
|
executor,
|
||||||
iced::{subscription::Subscription, window},
|
iced::{window, Subscription},
|
||||||
widget, Application, Element,
|
widget, Application, Element,
|
||||||
};
|
};
|
||||||
use cosmic_files::dialog::{Dialog, DialogKind, DialogMessage, DialogResult};
|
use cosmic_files::dialog::{Dialog, DialogKind, DialogMessage, DialogResult};
|
||||||
|
|
@ -42,18 +42,18 @@ impl Application for App {
|
||||||
&mut self.core
|
&mut self.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(core: Core, _flags: Self::Flags) -> (Self, Command<Message>) {
|
fn init(core: Core, _flags: Self::Flags) -> (Self, Task<Message>) {
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
core,
|
core,
|
||||||
dialog_opt: None,
|
dialog_opt: None,
|
||||||
result_opt: None,
|
result_opt: None,
|
||||||
},
|
},
|
||||||
Command::none(),
|
Task::none(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> Command<Message> {
|
fn update(&mut self, message: Message) -> Task<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::DialogMessage(dialog_message) => {
|
Message::DialogMessage(dialog_message) => {
|
||||||
if let Some(dialog) = &mut self.dialog_opt {
|
if let Some(dialog) = &mut self.dialog_opt {
|
||||||
|
|
@ -78,7 +78,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, window_id: window::Id) -> Element<Message> {
|
fn view_window(&self, window_id: window::Id) -> Element<Message> {
|
||||||
|
|
|
||||||
337
src/app.rs
337
src/app.rs
|
|
@ -4,26 +4,26 @@
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
use cosmic::iced::{
|
use cosmic::iced::{
|
||||||
event::wayland::{Event as WaylandEvent, OutputEvent},
|
event::wayland::{Event as WaylandEvent, OutputEvent},
|
||||||
wayland::{
|
platform_specific::runtime::wayland::layer_surface::{
|
||||||
actions::layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings},
|
IcedMargin, IcedOutput, SctkLayerSurfaceSettings,
|
||||||
layer_surface::{
|
},
|
||||||
destroy_layer_surface, get_layer_surface, Anchor, KeyboardInteractivity, Layer,
|
platform_specific::shell::wayland::commands::layer_surface::{
|
||||||
},
|
destroy_layer_surface, get_layer_surface, Anchor, KeyboardInteractivity, Layer,
|
||||||
},
|
},
|
||||||
Limits,
|
Limits,
|
||||||
};
|
};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app::{self, message, Command, Core},
|
app::{self, message, Core, Task},
|
||||||
cosmic_config, cosmic_theme, executor,
|
cosmic_config, cosmic_theme, executor,
|
||||||
iced::{
|
iced::{
|
||||||
clipboard::dnd::DndAction,
|
clipboard::dnd::DndAction,
|
||||||
event,
|
event,
|
||||||
futures::{self, SinkExt},
|
futures::{self, SinkExt},
|
||||||
keyboard::{Event as KeyEvent, Key, Modifiers},
|
keyboard::{Event as KeyEvent, Key, Modifiers},
|
||||||
subscription::{self, Subscription},
|
stream,
|
||||||
widget::scrollable,
|
widget::scrollable,
|
||||||
window::{self, Event as WindowEvent, Id as WindowId},
|
window::{self, Event as WindowEvent, Id as WindowId},
|
||||||
Alignment, Event, Length, Size,
|
Alignment, Event, Length, Size, Subscription,
|
||||||
},
|
},
|
||||||
iced_runtime::clipboard,
|
iced_runtime::clipboard,
|
||||||
style, theme,
|
style, theme,
|
||||||
|
|
@ -619,7 +619,7 @@ impl App {
|
||||||
location: Location,
|
location: Location,
|
||||||
activate: bool,
|
activate: bool,
|
||||||
selection_path: Option<PathBuf>,
|
selection_path: Option<PathBuf>,
|
||||||
) -> (Entity, Command<Message>) {
|
) -> (Entity, Task<Message>) {
|
||||||
let mut tab = Tab::new(location.clone(), self.config.tab);
|
let mut tab = Tab::new(location.clone(), self.config.tab);
|
||||||
tab.mode = match self.mode {
|
tab.mode = match self.mode {
|
||||||
Mode::App => tab::Mode::App,
|
Mode::App => tab::Mode::App,
|
||||||
|
|
@ -643,7 +643,7 @@ impl App {
|
||||||
|
|
||||||
(
|
(
|
||||||
entity,
|
entity,
|
||||||
Command::batch([
|
Task::batch([
|
||||||
self.update_title(),
|
self.update_title(),
|
||||||
self.update_watcher(),
|
self.update_watcher(),
|
||||||
self.rescan_tab(entity, location, selection_path),
|
self.rescan_tab(entity, location, selection_path),
|
||||||
|
|
@ -656,7 +656,7 @@ impl App {
|
||||||
location: Location,
|
location: Location,
|
||||||
activate: bool,
|
activate: bool,
|
||||||
selection_path: Option<PathBuf>,
|
selection_path: Option<PathBuf>,
|
||||||
) -> Command<Message> {
|
) -> Task<Message> {
|
||||||
self.open_tab_entity(location, activate, selection_path).1
|
self.open_tab_entity(location, activate, selection_path).1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -681,10 +681,10 @@ impl App {
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
location: Location,
|
location: Location,
|
||||||
selection_path: Option<PathBuf>,
|
selection_path: Option<PathBuf>,
|
||||||
) -> Command<Message> {
|
) -> Task<Message> {
|
||||||
log::info!("rescan_tab {entity:?} {location:?} {selection_path:?}");
|
log::info!("rescan_tab {entity:?} {location:?} {selection_path:?}");
|
||||||
let icon_sizes = self.config.tab.icon_sizes;
|
let icon_sizes = self.config.tab.icon_sizes;
|
||||||
Command::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
let location2 = location.clone();
|
let location2 = location.clone();
|
||||||
match tokio::task::spawn_blocking(move || location2.scan(icon_sizes)).await {
|
match tokio::task::spawn_blocking(move || location2.scan(icon_sizes)).await {
|
||||||
|
|
@ -705,7 +705,7 @@ impl App {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rescan_trash(&mut self) -> Command<Message> {
|
fn rescan_trash(&mut self) -> Task<Message> {
|
||||||
let mut needs_reload = Vec::new();
|
let mut needs_reload = Vec::new();
|
||||||
for entity in self.tab_model.iter() {
|
for entity in self.tab_model.iter() {
|
||||||
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
||||||
|
|
@ -719,14 +719,14 @@ impl App {
|
||||||
for (entity, location) in needs_reload {
|
for (entity, location) in needs_reload {
|
||||||
commands.push(self.rescan_tab(entity, location, None));
|
commands.push(self.rescan_tab(entity, location, None));
|
||||||
}
|
}
|
||||||
Command::batch(commands)
|
Task::batch(commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search(&mut self) -> Command<Message> {
|
fn search(&mut self) -> Task<Message> {
|
||||||
if let Some(term) = self.search_get() {
|
if let Some(term) = self.search_get() {
|
||||||
self.search_set(Some(term.to_string()))
|
self.search_set(Some(term.to_string()))
|
||||||
} else {
|
} else {
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -739,7 +739,7 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_set(&mut self, term_opt: Option<String>) -> Command<Message> {
|
fn search_set(&mut self, term_opt: Option<String>) -> Task<Message> {
|
||||||
let entity = self.tab_model.active();
|
let entity = self.tab_model.active();
|
||||||
let mut title_location_opt = None;
|
let mut title_location_opt = None;
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||||
|
|
@ -768,18 +768,18 @@ impl App {
|
||||||
}
|
}
|
||||||
if let Some((title, location, focus_search)) = title_location_opt {
|
if let Some((title, location, focus_search)) = title_location_opt {
|
||||||
self.tab_model.text_set(entity, title);
|
self.tab_model.text_set(entity, title);
|
||||||
return Command::batch([
|
return Task::batch([
|
||||||
self.update_title(),
|
self.update_title(),
|
||||||
self.update_watcher(),
|
self.update_watcher(),
|
||||||
self.rescan_tab(entity, location, None),
|
self.rescan_tab(entity, location, None),
|
||||||
if focus_search {
|
if focus_search {
|
||||||
widget::text_input::focus(self.search_id.clone())
|
widget::text_input::focus(self.search_id.clone())
|
||||||
} else {
|
} else {
|
||||||
Command::none()
|
Task::none()
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selected_paths(&self, entity_opt: Option<Entity>) -> Vec<PathBuf> {
|
fn selected_paths(&self, entity_opt: Option<Entity>) -> Vec<PathBuf> {
|
||||||
|
|
@ -795,7 +795,7 @@ impl App {
|
||||||
paths
|
paths
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_config(&mut self) -> Command<Message> {
|
fn update_config(&mut self) -> Task<Message> {
|
||||||
self.update_nav_model();
|
self.update_nav_model();
|
||||||
// Tabs are collected first to placate the borrowck
|
// Tabs are collected first to placate the borrowck
|
||||||
let tabs: Vec<_> = self.tab_model.iter().collect();
|
let tabs: Vec<_> = self.tab_model.iter().collect();
|
||||||
|
|
@ -810,10 +810,10 @@ impl App {
|
||||||
))
|
))
|
||||||
}))
|
}))
|
||||||
.collect();
|
.collect();
|
||||||
Command::batch(commands)
|
Task::batch(commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_desktop(&mut self) -> Command<Message> {
|
fn update_desktop(&mut self) -> Task<Message> {
|
||||||
let mut needs_reload = Vec::new();
|
let mut needs_reload = Vec::new();
|
||||||
for entity in self.tab_model.iter() {
|
for entity in self.tab_model.iter() {
|
||||||
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
||||||
|
|
@ -826,7 +826,7 @@ impl App {
|
||||||
for (entity, location) in needs_reload {
|
for (entity, location) in needs_reload {
|
||||||
commands.push(self.rescan_tab(entity, location, None));
|
commands.push(self.rescan_tab(entity, location, None));
|
||||||
}
|
}
|
||||||
Command::batch(commands)
|
Task::batch(commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate_nav_model_location(&mut self, location: &Location) {
|
fn activate_nav_model_location(&mut self, location: &Location) {
|
||||||
|
|
@ -941,12 +941,12 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_notification(&mut self) -> Command<Message> {
|
fn update_notification(&mut self) -> Task<Message> {
|
||||||
// Handle closing notification if there are no operations
|
// Handle closing notification if there are no operations
|
||||||
if self.pending_operations.is_empty() {
|
if self.pending_operations.is_empty() {
|
||||||
#[cfg(feature = "notify")]
|
#[cfg(feature = "notify")]
|
||||||
if let Some(notification_arc) = self.notification_opt.take() {
|
if let Some(notification_arc) = self.notification_opt.take() {
|
||||||
return Command::perform(
|
return Task::perform(
|
||||||
async move {
|
async move {
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
//TODO: this is nasty
|
//TODO: this is nasty
|
||||||
|
|
@ -963,18 +963,22 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_title(&mut self) -> Command<Message> {
|
fn update_title(&mut self) -> Task<Message> {
|
||||||
let window_title = match self.tab_model.text(self.tab_model.active()) {
|
let window_title = match self.tab_model.text(self.tab_model.active()) {
|
||||||
Some(tab_title) => format!("{tab_title} — {}", fl!("cosmic-files")),
|
Some(tab_title) => format!("{tab_title} — {}", fl!("cosmic-files")),
|
||||||
None => fl!("cosmic-files"),
|
None => fl!("cosmic-files"),
|
||||||
};
|
};
|
||||||
self.set_window_title(window_title, window::Id::MAIN)
|
if let Some(window_id) = &self.window_id_opt {
|
||||||
|
self.set_window_title(window_title, *window_id)
|
||||||
|
} else {
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_watcher(&mut self) -> Command<Message> {
|
fn update_watcher(&mut self) -> Task<Message> {
|
||||||
if let Some((mut watcher, old_paths)) = self.watcher_opt.take() {
|
if let Some((mut watcher, old_paths)) = self.watcher_opt.take() {
|
||||||
let mut new_paths = HashSet::new();
|
let mut new_paths = HashSet::new();
|
||||||
for entity in self.tab_model.iter() {
|
for entity in self.tab_model.iter() {
|
||||||
|
|
@ -1021,7 +1025,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: should any of this run in a command?
|
//TODO: should any of this run in a command?
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn about(&self) -> Element<Message> {
|
fn about(&self) -> Element<Message> {
|
||||||
|
|
@ -1051,7 +1055,7 @@ impl App {
|
||||||
.padding(0)
|
.padding(0)
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.align_items(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
@ -1093,11 +1097,8 @@ impl App {
|
||||||
text_input.into(),
|
text_input.into(),
|
||||||
widget::text(fl!("network-drive-description")).into(),
|
widget::text(fl!("network-drive-description")).into(),
|
||||||
table.into(),
|
table.into(),
|
||||||
widget::row::with_children(vec![
|
widget::row::with_children(vec![widget::horizontal_space().into(), button.into()])
|
||||||
widget::horizontal_space(Length::Fill).into(),
|
.into(),
|
||||||
button.into(),
|
|
||||||
])
|
|
||||||
.into(),
|
|
||||||
])
|
])
|
||||||
.spacing(space_m)
|
.spacing(space_m)
|
||||||
.into()
|
.into()
|
||||||
|
|
@ -1322,7 +1323,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the application, and optionally emits command on initialize.
|
/// Creates the application, and optionally emits command on initialize.
|
||||||
fn init(mut core: Core, flags: Self::Flags) -> (Self, Command<Self::Message>) {
|
fn init(mut core: Core, flags: Self::Flags) -> (Self, Task<Self::Message>) {
|
||||||
core.window.context_is_overlay = false;
|
core.window.context_is_overlay = false;
|
||||||
match flags.mode {
|
match flags.mode {
|
||||||
Mode::App => {
|
Mode::App => {
|
||||||
|
|
@ -1346,6 +1347,8 @@ impl Application for App {
|
||||||
Mode::Desktop => tab::Mode::Desktop,
|
Mode::Desktop => tab::Mode::Desktop,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let window_id_opt = core.main_window_id();
|
||||||
|
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
core,
|
core,
|
||||||
nav_bar_context_id: segmented_button::Entity::null(),
|
nav_bar_context_id: segmented_button::Entity::null(),
|
||||||
|
|
@ -1376,7 +1379,7 @@ impl Application for App {
|
||||||
surface_names: HashMap::new(),
|
surface_names: HashMap::new(),
|
||||||
toasts: widget::toaster::Toasts::new(Message::CloseToast),
|
toasts: widget::toaster::Toasts::new(Message::CloseToast),
|
||||||
watcher_opt: None,
|
watcher_opt: None,
|
||||||
window_id_opt: Some(window::Id::MAIN),
|
window_id_opt,
|
||||||
windows: HashMap::new(),
|
windows: HashMap::new(),
|
||||||
nav_dnd_hover: None,
|
nav_dnd_hover: None,
|
||||||
tab_dnd_hover: None,
|
tab_dnd_hover: None,
|
||||||
|
|
@ -1398,11 +1401,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(app, Command::batch(commands))
|
(app, Task::batch(commands))
|
||||||
}
|
|
||||||
|
|
||||||
fn main_window_id(&self) -> window::Id {
|
|
||||||
self.window_id_opt.unwrap_or(window::Id::MAIN)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nav_bar(&self) -> Option<Element<message::Message<Self::Message>>> {
|
fn nav_bar(&self) -> Option<Element<message::Message<Self::Message>>> {
|
||||||
|
|
@ -1504,7 +1503,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_nav_select(&mut self, entity: Entity) -> Command<Self::Message> {
|
fn on_nav_select(&mut self, entity: Entity) -> Task<Self::Message> {
|
||||||
self.nav_model.activate(entity);
|
self.nav_model.activate(entity);
|
||||||
if let Some(location) = self.nav_model.data::<Location>(entity) {
|
if let Some(location) = self.nav_model.data::<Location>(entity) {
|
||||||
let message = Message::TabMessage(None, tab::Message::Location(location.clone()));
|
let message = Message::TabMessage(None, tab::Message::Location(location.clone()));
|
||||||
|
|
@ -1516,7 +1515,7 @@ impl Application for App {
|
||||||
return mounter.mount(data.1.clone()).map(|_| message::none());
|
return mounter.mount(data.1.clone()).map(|_| message::none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_app_exit(&mut self) -> Option<Message> {
|
fn on_app_exit(&mut self) -> Option<Message> {
|
||||||
|
|
@ -1527,7 +1526,7 @@ impl Application for App {
|
||||||
Some(Message::WindowCloseRequested(id))
|
Some(Message::WindowCloseRequested(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_context_drawer(&mut self) -> Command<Self::Message> {
|
fn on_context_drawer(&mut self) -> Task<Self::Message> {
|
||||||
match self.context_page {
|
match self.context_page {
|
||||||
ContextPage::Preview(..) => {
|
ContextPage::Preview(..) => {
|
||||||
// Persist state of preview page
|
// Persist state of preview page
|
||||||
|
|
@ -1537,22 +1536,22 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_escape(&mut self) -> Command<Self::Message> {
|
fn on_escape(&mut self) -> Task<Self::Message> {
|
||||||
let entity = self.tab_model.active();
|
let entity = self.tab_model.active();
|
||||||
|
|
||||||
// Close dialog if open
|
// Close dialog if open
|
||||||
if self.dialog_pages.pop_front().is_some() {
|
if self.dialog_pages.pop_front().is_some() {
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close gallery mode if open
|
// Close gallery mode if open
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||||
if tab.gallery {
|
if tab.gallery {
|
||||||
tab.gallery = false;
|
tab.gallery = false;
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1562,7 +1561,7 @@ impl Application for App {
|
||||||
// of closing everything on one press
|
// of closing everything on one press
|
||||||
if self.core.window.show_context {
|
if self.core.window.show_context {
|
||||||
self.set_show_context(false);
|
self.set_show_context(false);
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
if self.search_get().is_some() {
|
if self.search_get().is_some() {
|
||||||
// Close search if open
|
// Close search if open
|
||||||
|
|
@ -1571,12 +1570,12 @@ impl Application for App {
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||||
if tab.context_menu.is_some() {
|
if tab.context_menu.is_some() {
|
||||||
tab.context_menu = None;
|
tab.context_menu = None;
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
if tab.edit_location.is_some() {
|
if tab.edit_location.is_some() {
|
||||||
tab.edit_location = None;
|
tab.edit_location = None;
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
let had_focused_button = tab.select_focus_id().is_some();
|
let had_focused_button = tab.select_focus_id().is_some();
|
||||||
|
|
@ -1585,15 +1584,15 @@ impl Application for App {
|
||||||
// Unfocus if there was a focused button
|
// Unfocus if there was a focused button
|
||||||
return widget::button::focus(widget::Id::unique());
|
return widget::button::focus(widget::Id::unique());
|
||||||
}
|
}
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle application events here.
|
/// Handle application events here.
|
||||||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
||||||
// Helper for updating config values efficiently
|
// Helper for updating config values efficiently
|
||||||
macro_rules! config_set {
|
macro_rules! config_set {
|
||||||
($name: ident, $value: expr) => {
|
($name: ident, $value: expr) => {
|
||||||
|
|
@ -1709,9 +1708,9 @@ impl Application for App {
|
||||||
"com.system76.CosmicFilesDialog".to_string();
|
"com.system76.CosmicFilesDialog".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (id, command) = window::spawn(settings);
|
let (id, command) = window::open(settings);
|
||||||
self.windows.insert(id, WindowKind::DesktopViewOptions);
|
self.windows.insert(id, WindowKind::DesktopViewOptions);
|
||||||
return command;
|
return command.map(|_id| message::none());
|
||||||
}
|
}
|
||||||
Message::DialogCancel => {
|
Message::DialogCancel => {
|
||||||
self.dialog_pages.pop_front();
|
self.dialog_pages.pop_front();
|
||||||
|
|
@ -1755,7 +1754,7 @@ impl Application for App {
|
||||||
auth,
|
auth,
|
||||||
auth_tx,
|
auth_tx,
|
||||||
} => {
|
} => {
|
||||||
return Command::perform(
|
return Task::perform(
|
||||||
async move {
|
async move {
|
||||||
auth_tx.send(auth).await.unwrap();
|
auth_tx.send(auth).await.unwrap();
|
||||||
message::none()
|
message::none()
|
||||||
|
|
@ -1769,7 +1768,7 @@ impl Application for App {
|
||||||
error: _,
|
error: _,
|
||||||
} => {
|
} => {
|
||||||
//TODO: re-use mounter_key?
|
//TODO: re-use mounter_key?
|
||||||
return Command::batch([
|
return Task::batch([
|
||||||
self.update(Message::NetworkDriveInput(uri)),
|
self.update(Message::NetworkDriveInput(uri)),
|
||||||
self.update(Message::NetworkDriveSubmit),
|
self.update(Message::NetworkDriveSubmit),
|
||||||
]);
|
]);
|
||||||
|
|
@ -1841,7 +1840,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::DialogUpdateComplete(dialog_page) => {
|
Message::DialogUpdateComplete(dialog_page) => {
|
||||||
return Command::batch([
|
return Task::batch([
|
||||||
self.update(Message::DialogUpdate(dialog_page)),
|
self.update(Message::DialogUpdate(dialog_page)),
|
||||||
self.update(Message::DialogComplete),
|
self.update(Message::DialogComplete),
|
||||||
]);
|
]);
|
||||||
|
|
@ -1951,7 +1950,7 @@ impl Application for App {
|
||||||
// Update desktop tabs
|
// Update desktop tabs
|
||||||
commands.push(self.update_desktop());
|
commands.push(self.update_desktop());
|
||||||
|
|
||||||
return Command::batch(commands);
|
return Task::batch(commands);
|
||||||
}
|
}
|
||||||
Message::MountResult(mounter_key, item, res) => match res {
|
Message::MountResult(mounter_key, item, res) => match res {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
|
|
@ -2099,7 +2098,7 @@ impl Application for App {
|
||||||
for (entity, location) in needs_reload {
|
for (entity, location) in needs_reload {
|
||||||
commands.push(self.rescan_tab(entity, location, None));
|
commands.push(self.rescan_tab(entity, location, None));
|
||||||
}
|
}
|
||||||
return Command::batch(commands);
|
return Task::batch(commands);
|
||||||
}
|
}
|
||||||
Message::NotifyWatcher(mut watcher_wrapper) => match watcher_wrapper.watcher_opt.take()
|
Message::NotifyWatcher(mut watcher_wrapper) => match watcher_wrapper.watcher_opt.take()
|
||||||
{
|
{
|
||||||
|
|
@ -2152,7 +2151,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::OpenInNewTab(entity_opt) => {
|
Message::OpenInNewTab(entity_opt) => {
|
||||||
return Command::batch(self.selected_paths(entity_opt).into_iter().filter_map(
|
return Task::batch(self.selected_paths(entity_opt).into_iter().filter_map(
|
||||||
|path| {
|
|path| {
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
Some(self.open_tab(Location::Path(path), false, None))
|
Some(self.open_tab(Location::Path(path), false, None))
|
||||||
|
|
@ -2178,7 +2177,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Message::OpenItemLocation(entity_opt) => {
|
Message::OpenItemLocation(entity_opt) => {
|
||||||
return Command::batch(self.selected_paths(entity_opt).into_iter().filter_map(
|
return Task::batch(self.selected_paths(entity_opt).into_iter().filter_map(
|
||||||
|path| {
|
|path| {
|
||||||
if let Some(parent) = path.parent() {
|
if let Some(parent) = path.parent() {
|
||||||
Some(self.open_tab(
|
Some(self.open_tab(
|
||||||
|
|
@ -2259,7 +2258,7 @@ impl Application for App {
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||||
if let Some(path) = tab.location.path_opt() {
|
if let Some(path) = tab.location.path_opt() {
|
||||||
let to = path.clone();
|
let to = path.clone();
|
||||||
return clipboard::read_data::<ClipboardPaste, _>(move |contents_opt| {
|
return clipboard::read_data::<ClipboardPaste>().map(move |contents_opt| {
|
||||||
match contents_opt {
|
match contents_opt {
|
||||||
Some(contents) => {
|
Some(contents) => {
|
||||||
message::app(Message::PasteContents(to.clone(), contents))
|
message::app(Message::PasteContents(to.clone(), contents))
|
||||||
|
|
@ -2340,7 +2339,7 @@ impl Application for App {
|
||||||
commands.push(self.rescan_trash());
|
commands.push(self.rescan_trash());
|
||||||
// if search is active, update "search" tab view
|
// if search is active, update "search" tab view
|
||||||
commands.push(self.search());
|
commands.push(self.search());
|
||||||
return Command::batch(commands);
|
return Task::batch(commands);
|
||||||
}
|
}
|
||||||
Message::PendingError(id, err) => {
|
Message::PendingError(id, err) => {
|
||||||
if let Some((op, _)) = self.pending_operations.remove(&id) {
|
if let Some((op, _)) = self.pending_operations.remove(&id) {
|
||||||
|
|
@ -2384,7 +2383,7 @@ impl Application for App {
|
||||||
"com.system76.CosmicFilesDialog".to_string();
|
"com.system76.CosmicFilesDialog".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (id, command) = window::spawn(settings);
|
let (id, command) = window::open(settings);
|
||||||
self.windows.insert(
|
self.windows.insert(
|
||||||
id,
|
id,
|
||||||
WindowKind::Preview(
|
WindowKind::Preview(
|
||||||
|
|
@ -2392,9 +2391,9 @@ impl Application for App {
|
||||||
PreviewKind::Location(Location::Path(path)),
|
PreviewKind::Location(Location::Path(path)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
commands.push(command);
|
commands.push(command.map(|_id| message::none()));
|
||||||
}
|
}
|
||||||
return Command::batch(commands);
|
return Task::batch(commands);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2411,7 +2410,7 @@ impl Application for App {
|
||||||
.icon_set(entity, widget::icon::icon(tab::trash_icon_symbolic(16)));
|
.icon_set(entity, widget::icon::icon(tab::trash_icon_symbolic(16)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Command::batch([self.rescan_trash(), self.update_desktop()]);
|
return Task::batch([self.rescan_trash(), self.update_desktop()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::Rename(entity_opt) => {
|
Message::Rename(entity_opt) => {
|
||||||
|
|
@ -2452,7 +2451,7 @@ impl Application for App {
|
||||||
if let Some(dialog_page) = self.dialog_pages.pop_front() {
|
if let Some(dialog_page) = self.dialog_pages.pop_front() {
|
||||||
match dialog_page {
|
match dialog_page {
|
||||||
DialogPage::Replace { tx, .. } => {
|
DialogPage::Replace { tx, .. } => {
|
||||||
return Command::perform(
|
return Task::perform(
|
||||||
async move {
|
async move {
|
||||||
let _ = tx.send(replace_result).await;
|
let _ = tx.send(replace_result).await;
|
||||||
message::none()
|
message::none()
|
||||||
|
|
@ -2572,10 +2571,12 @@ impl Application for App {
|
||||||
|
|
||||||
// If that was the last tab, close window
|
// If that was the last tab, close window
|
||||||
if self.tab_model.iter().next().is_none() {
|
if self.tab_model.iter().next().is_none() {
|
||||||
return window::close(window::Id::MAIN);
|
if let Some(window_id) = &self.window_id_opt {
|
||||||
|
return window::close(*window_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Command::batch([self.update_title(), self.update_watcher()]);
|
return Task::batch([self.update_title(), self.update_watcher()]);
|
||||||
}
|
}
|
||||||
Message::TabConfig(config) => {
|
Message::TabConfig(config) => {
|
||||||
if config != self.config.tab {
|
if config != self.config.tab {
|
||||||
|
|
@ -2591,7 +2592,7 @@ impl Application for App {
|
||||||
Message::TabMessage(entity_opt, tab_message) => {
|
Message::TabMessage(entity_opt, tab_message) => {
|
||||||
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||||
|
|
||||||
//TODO: move to Command?
|
//TODO: move to Task?
|
||||||
if let tab::Message::ContextMenu(_point_opt) = tab_message {
|
if let tab::Message::ContextMenu(_point_opt) = tab_message {
|
||||||
// Disable side context page
|
// Disable side context page
|
||||||
self.set_show_context(false);
|
self.set_show_context(false);
|
||||||
|
|
@ -2626,7 +2627,7 @@ impl Application for App {
|
||||||
self.activate_nav_model_location(&tab_path);
|
self.activate_nav_model_location(&tab_path);
|
||||||
|
|
||||||
self.tab_model.text_set(entity, tab_title);
|
self.tab_model.text_set(entity, tab_title);
|
||||||
commands.push(Command::batch([
|
commands.push(Task::batch([
|
||||||
self.update_title(),
|
self.update_title(),
|
||||||
self.update_watcher(),
|
self.update_watcher(),
|
||||||
self.rescan_tab(entity, tab_path, selection_path),
|
self.rescan_tab(entity, tab_path, selection_path),
|
||||||
|
|
@ -2639,7 +2640,7 @@ impl Application for App {
|
||||||
self.dialog_pages.push_back(DialogPage::EmptyTrash);
|
self.dialog_pages.push_back(DialogPage::EmptyTrash);
|
||||||
}
|
}
|
||||||
tab::Command::Iced(iced_command) => {
|
tab::Command::Iced(iced_command) => {
|
||||||
commands.push(iced_command.map(move |tab_message| {
|
commands.push(iced_command.0.map(move |tab_message| {
|
||||||
message::app(Message::TabMessage(Some(entity), tab_message))
|
message::app(Message::TabMessage(Some(entity), tab_message))
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
@ -2678,14 +2679,18 @@ impl Application for App {
|
||||||
self.set_context_title(self.context_page.title());
|
self.set_context_title(self.context_page.title());
|
||||||
}
|
}
|
||||||
tab::Command::WindowDrag => {
|
tab::Command::WindowDrag => {
|
||||||
commands.push(window::drag(self.main_window_id()));
|
if let Some(window_id) = &self.window_id_opt {
|
||||||
|
commands.push(window::drag(*window_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tab::Command::WindowToggleMaximize => {
|
tab::Command::WindowToggleMaximize => {
|
||||||
commands.push(window::toggle_maximize(self.main_window_id()));
|
if let Some(window_id) = &self.window_id_opt {
|
||||||
|
commands.push(window::toggle_maximize(*window_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Command::batch(commands);
|
return Task::batch(commands);
|
||||||
}
|
}
|
||||||
Message::TabNew => {
|
Message::TabNew => {
|
||||||
let active = self.tab_model.active();
|
let active = self.tab_model.active();
|
||||||
|
|
@ -2766,9 +2771,9 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
Message::WindowClose => {
|
Message::WindowClose => {
|
||||||
if let Some(window_id) = self.window_id_opt.take() {
|
if let Some(window_id) = self.window_id_opt.take() {
|
||||||
return Command::batch([
|
return Task::batch([
|
||||||
window::close(window_id),
|
window::close(window_id),
|
||||||
Command::perform(async move { message::app(Message::MaybeExit) }, |x| x),
|
Task::perform(async move { message::app(Message::MaybeExit) }, |x| x),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2849,8 +2854,8 @@ impl Application for App {
|
||||||
if let Some(location) = self.nav_model.data::<Location>(entity) {
|
if let Some(location) = self.nav_model.data::<Location>(entity) {
|
||||||
self.nav_dnd_hover = Some((location.clone(), Instant::now()));
|
self.nav_dnd_hover = Some((location.clone(), Instant::now()));
|
||||||
let location = location.clone();
|
let location = location.clone();
|
||||||
return Command::perform(tokio::time::sleep(HOVER_DURATION), move |_| {
|
return Task::perform(tokio::time::sleep(HOVER_DURATION), move |_| {
|
||||||
cosmic::app::Message::App(Message::DndHoverLocTimeout(location))
|
cosmic::app::Message::App(Message::DndHoverLocTimeout(location.clone()))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2874,11 +2879,11 @@ impl Application for App {
|
||||||
)),
|
)),
|
||||||
Location::Trash if matches!(action, DndAction::Move) => {
|
Location::Trash if matches!(action, DndAction::Move) => {
|
||||||
self.operation(Operation::Delete { paths: data.paths });
|
self.operation(Operation::Delete { paths: data.paths });
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!("Copy to trash is not supported.");
|
log::warn!("Copy to trash is not supported.");
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -2901,7 +2906,7 @@ impl Application for App {
|
||||||
};
|
};
|
||||||
if let Some(title) = title_opt {
|
if let Some(title) = title_opt {
|
||||||
self.tab_model.text_set(entity, title);
|
self.tab_model.text_set(entity, title);
|
||||||
return Command::batch([
|
return Task::batch([
|
||||||
self.update_title(),
|
self.update_title(),
|
||||||
self.update_watcher(),
|
self.update_watcher(),
|
||||||
self.rescan_tab(entity, location, None),
|
self.rescan_tab(entity, location, None),
|
||||||
|
|
@ -2911,7 +2916,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
Message::DndEnterTab(entity) => {
|
Message::DndEnterTab(entity) => {
|
||||||
self.tab_dnd_hover = Some((entity, Instant::now()));
|
self.tab_dnd_hover = Some((entity, Instant::now()));
|
||||||
return Command::perform(tokio::time::sleep(HOVER_DURATION), move |_| {
|
return Task::perform(tokio::time::sleep(HOVER_DURATION), move |_| {
|
||||||
cosmic::app::Message::App(Message::DndHoverTabTimeout(entity))
|
cosmic::app::Message::App(Message::DndHoverTabTimeout(entity))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -2935,11 +2940,11 @@ impl Application for App {
|
||||||
)),
|
)),
|
||||||
Location::Trash if matches!(action, DndAction::Move) => {
|
Location::Trash if matches!(action, DndAction::Move) => {
|
||||||
self.operation(Operation::Delete { paths: data.paths });
|
self.operation(Operation::Delete { paths: data.paths });
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!("Copy to trash is not supported.");
|
log::warn!("Copy to trash is not supported.");
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -3131,7 +3136,7 @@ impl Application for App {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
self.windows.insert(surface_id, WindowKind::Desktop(entity));
|
self.windows.insert(surface_id, WindowKind::Desktop(entity));
|
||||||
return Command::batch([
|
return Task::batch([
|
||||||
command,
|
command,
|
||||||
get_layer_surface(SctkLayerSurfaceSettings {
|
get_layer_surface(SctkLayerSurfaceSettings {
|
||||||
id: surface_id,
|
id: surface_id,
|
||||||
|
|
@ -3173,12 +3178,12 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
Message::Cosmic(cosmic) => {
|
Message::Cosmic(cosmic) => {
|
||||||
// Forward cosmic messages
|
// Forward cosmic messages
|
||||||
return Command::perform(async move { cosmic }, |cosmic| message::cosmic(cosmic));
|
return Task::perform(async move { cosmic }, |cosmic| message::cosmic(cosmic));
|
||||||
}
|
}
|
||||||
Message::None => {}
|
Message::None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn context_drawer(&self) -> Option<Element<Message>> {
|
fn context_drawer(&self) -> Option<Element<Message>> {
|
||||||
|
|
@ -3288,7 +3293,7 @@ impl Application for App {
|
||||||
})
|
})
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
|
|
@ -3396,18 +3401,19 @@ impl Application for App {
|
||||||
//TODO: what should submit do?
|
//TODO: what should submit do?
|
||||||
//TODO: button for showing password
|
//TODO: button for showing password
|
||||||
controls.push(
|
controls.push(
|
||||||
widget::checkbox(fl!("remember-password"), *remember, move |value| {
|
widget::checkbox(fl!("remember-password"), *remember)
|
||||||
Message::DialogUpdate(DialogPage::NetworkAuth {
|
.on_toggle(move |value| {
|
||||||
mounter_key: *mounter_key,
|
Message::DialogUpdate(DialogPage::NetworkAuth {
|
||||||
uri: uri.clone(),
|
mounter_key: *mounter_key,
|
||||||
auth: MounterAuth {
|
uri: uri.clone(),
|
||||||
remember_opt: Some(value),
|
auth: MounterAuth {
|
||||||
..auth.clone()
|
remember_opt: Some(value),
|
||||||
},
|
..auth.clone()
|
||||||
auth_tx: auth_tx.clone(),
|
},
|
||||||
|
auth_tx: auth_tx.clone(),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
.into(),
|
||||||
.into(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3540,21 +3546,21 @@ impl Application for App {
|
||||||
} else {
|
} else {
|
||||||
widget::text(app.name.to_string()).into()
|
widget::text(app.name.to_string()).into()
|
||||||
},
|
},
|
||||||
widget::horizontal_space(Length::Fill).into(),
|
widget::horizontal_space().into(),
|
||||||
if *selected == i {
|
if *selected == i {
|
||||||
widget::icon::from_name("checkbox-checked-symbolic")
|
widget::icon::from_name("checkbox-checked-symbolic")
|
||||||
.size(16)
|
.size(16)
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
widget::horizontal_space(Length::Fixed(16.0)).into()
|
widget::Space::with_width(Length::Fixed(16.0)).into()
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
.spacing(space_s)
|
.spacing(space_s)
|
||||||
.height(Length::Fixed(32.0))
|
.height(Length::Fixed(32.0))
|
||||||
.align_items(Alignment::Center),
|
.align_y(Alignment::Center),
|
||||||
)
|
)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.style(theme::Button::MenuItem)
|
.class(theme::Button::MenuItem)
|
||||||
.on_press(Message::OpenWithSelection(i)),
|
.on_press(Message::OpenWithSelection(i)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -3668,19 +3674,19 @@ impl Application for App {
|
||||||
));
|
));
|
||||||
if *multiple {
|
if *multiple {
|
||||||
dialog
|
dialog
|
||||||
.control(widget::checkbox(
|
.control(
|
||||||
fl!("apply-to-all"),
|
widget::checkbox(fl!("apply-to-all"), *apply_to_all).on_toggle(
|
||||||
*apply_to_all,
|
|apply_to_all| {
|
||||||
|apply_to_all| {
|
Message::DialogUpdate(DialogPage::Replace {
|
||||||
Message::DialogUpdate(DialogPage::Replace {
|
from: from.clone(),
|
||||||
from: from.clone(),
|
to: to.clone(),
|
||||||
to: to.clone(),
|
multiple: *multiple,
|
||||||
multiple: *multiple,
|
apply_to_all,
|
||||||
apply_to_all,
|
tx: tx.clone(),
|
||||||
tx: tx.clone(),
|
})
|
||||||
})
|
},
|
||||||
},
|
),
|
||||||
))
|
)
|
||||||
.secondary_action(
|
.secondary_action(
|
||||||
widget::button::standard(fl!("skip")).on_press(Message::ReplaceResult(
|
widget::button::standard(fl!("skip")).on_press(Message::ReplaceResult(
|
||||||
ReplaceResult::Skip(*apply_to_all),
|
ReplaceResult::Skip(*apply_to_all),
|
||||||
|
|
@ -3710,12 +3716,12 @@ impl Application for App {
|
||||||
widget::dialog(fl!("set-executable-and-launch"))
|
widget::dialog(fl!("set-executable-and-launch"))
|
||||||
.primary_action(
|
.primary_action(
|
||||||
widget::button::text(fl!("set-and-launch"))
|
widget::button::text(fl!("set-and-launch"))
|
||||||
.style(theme::Button::Suggested)
|
.class(theme::Button::Suggested)
|
||||||
.on_press(Message::DialogComplete),
|
.on_press(Message::DialogComplete),
|
||||||
)
|
)
|
||||||
.secondary_action(
|
.secondary_action(
|
||||||
widget::button::text(fl!("cancel"))
|
widget::button::text(fl!("cancel"))
|
||||||
.style(theme::Button::Standard)
|
.class(theme::Button::Standard)
|
||||||
.on_press(Message::DialogCancel),
|
.on_press(Message::DialogCancel),
|
||||||
)
|
)
|
||||||
.control(widget::text::text(fl!(
|
.control(widget::text::text(fl!(
|
||||||
|
|
@ -3818,7 +3824,7 @@ impl Application for App {
|
||||||
})
|
})
|
||||||
.drag_id(self.tab_drag_id),
|
.drag_id(self.tab_drag_id),
|
||||||
)
|
)
|
||||||
.style(style::Container::Background)
|
.class(style::Container::Background)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.padding([0, space_s]),
|
.padding([0, space_s]),
|
||||||
);
|
);
|
||||||
|
|
@ -3838,10 +3844,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The toaster is added on top of an empty element to ensure that it does not override context menus
|
// The toaster is added on top of an empty element to ensure that it does not override context menus
|
||||||
tab_column = tab_column.push(widget::toaster(
|
tab_column = tab_column.push(widget::toaster(&self.toasts, widget::horizontal_space()));
|
||||||
&self.toasts,
|
|
||||||
widget::horizontal_space(Length::Fill),
|
|
||||||
));
|
|
||||||
|
|
||||||
let content: Element<_> = tab_column.into();
|
let content: Element<_> = tab_column.into();
|
||||||
|
|
||||||
|
|
@ -3859,7 +3862,7 @@ impl Application for App {
|
||||||
Some(tab) => tab
|
Some(tab) => tab
|
||||||
.view(&self.key_binds)
|
.view(&self.key_binds)
|
||||||
.map(move |message| Message::TabMessage(Some(*entity), message)),
|
.map(move |message| Message::TabMessage(Some(*entity), message)),
|
||||||
None => widget::vertical_space(Length::Fill).into(),
|
None => widget::vertical_space().into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut popover = widget::popover(tab_view);
|
let mut popover = widget::popover(tab_view);
|
||||||
|
|
@ -3869,10 +3872,8 @@ impl Application for App {
|
||||||
tab_column = tab_column.push(popover);
|
tab_column = tab_column.push(popover);
|
||||||
|
|
||||||
// The toaster is added on top of an empty element to ensure that it does not override context menus
|
// The toaster is added on top of an empty element to ensure that it does not override context menus
|
||||||
tab_column = tab_column.push(widget::toaster(
|
tab_column =
|
||||||
&self.toasts,
|
tab_column.push(widget::toaster(&self.toasts, widget::horizontal_space()));
|
||||||
widget::horizontal_space(Length::Fill),
|
|
||||||
));
|
|
||||||
|
|
||||||
return tab_column.into();
|
return tab_column.into();
|
||||||
}
|
}
|
||||||
|
|
@ -3895,13 +3896,13 @@ impl Application for App {
|
||||||
widget::container(
|
widget::container(
|
||||||
widget::scrollable(widget::row::with_children(vec![
|
widget::scrollable(widget::row::with_children(vec![
|
||||||
content,
|
content,
|
||||||
widget::horizontal_space(Length::Fixed(
|
widget::Space::with_width(Length::Fixed(
|
||||||
(scrollbar_width + scrollbar_margin).into(),
|
(scrollbar_width + scrollbar_margin).into(),
|
||||||
))
|
))
|
||||||
.into(),
|
.into(),
|
||||||
]))
|
]))
|
||||||
.direction(scrollable::Direction::Vertical(
|
.direction(scrollable::Direction::Vertical(
|
||||||
scrollable::Properties::new()
|
scrollable::Scrollbar::new()
|
||||||
.width(scrollbar_width)
|
.width(scrollbar_width)
|
||||||
.scroller_width(scrollbar_width),
|
.scroller_width(scrollbar_width),
|
||||||
)),
|
)),
|
||||||
|
|
@ -3914,7 +3915,7 @@ impl Application for App {
|
||||||
space_l,
|
space_l,
|
||||||
space_l,
|
space_l,
|
||||||
])
|
])
|
||||||
.style(theme::Container::WindowBackground)
|
.class(theme::Container::WindowBackground)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3924,7 +3925,7 @@ impl Application for App {
|
||||||
struct TrashWatcherSubscription;
|
struct TrashWatcherSubscription;
|
||||||
|
|
||||||
let mut subscriptions = vec![
|
let mut subscriptions = vec![
|
||||||
event::listen_with(|event, status| match event {
|
event::listen_with(|event, status, _window_id| match event {
|
||||||
Event::Keyboard(KeyEvent::KeyPressed { key, modifiers, .. }) => match status {
|
Event::Keyboard(KeyEvent::KeyPressed { key, modifiers, .. }) => match status {
|
||||||
event::Status::Ignored => Some(Message::Key(modifiers, key)),
|
event::Status::Ignored => Some(Message::Key(modifiers, key)),
|
||||||
event::Status::Captured => None,
|
event::Status::Captured => None,
|
||||||
|
|
@ -3932,7 +3933,7 @@ impl Application for App {
|
||||||
Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => {
|
Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => {
|
||||||
Some(Message::Modifiers(modifiers))
|
Some(Message::Modifiers(modifiers))
|
||||||
}
|
}
|
||||||
Event::Window(_id, WindowEvent::CloseRequested) => Some(Message::WindowClose),
|
Event::Window(WindowEvent::CloseRequested) => Some(Message::WindowClose),
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
Event::PlatformSpecific(event::PlatformSpecific::Wayland(wayland_event)) => {
|
Event::PlatformSpecific(event::PlatformSpecific::Wayland(wayland_event)) => {
|
||||||
match wayland_event {
|
match wayland_event {
|
||||||
|
|
@ -3969,10 +3970,9 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
Message::SystemThemeModeChange(update.config)
|
Message::SystemThemeModeChange(update.config)
|
||||||
}),
|
}),
|
||||||
subscription::channel(
|
Subscription::run_with_id(
|
||||||
TypeId::of::<WatcherSubscription>(),
|
TypeId::of::<WatcherSubscription>(),
|
||||||
100,
|
stream::channel(100, |mut output| async move {
|
||||||
|mut output| async move {
|
|
||||||
let watcher_res = {
|
let watcher_res = {
|
||||||
let mut output = output.clone();
|
let mut output = output.clone();
|
||||||
new_debouncer(
|
new_debouncer(
|
||||||
|
|
@ -4044,12 +4044,11 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future::pending().await
|
std::future::pending().await
|
||||||
},
|
}),
|
||||||
),
|
),
|
||||||
subscription::channel(
|
Subscription::run_with_id(
|
||||||
TypeId::of::<TrashWatcherSubscription>(),
|
TypeId::of::<TrashWatcherSubscription>(),
|
||||||
25,
|
stream::channel(25, |mut output| async move {
|
||||||
|mut output| async move {
|
|
||||||
let watcher_res = new_debouncer(
|
let watcher_res = new_debouncer(
|
||||||
time::Duration::from_millis(250),
|
time::Duration::from_millis(250),
|
||||||
Some(time::Duration::from_millis(250)),
|
Some(time::Duration::from_millis(250)),
|
||||||
|
|
@ -4110,7 +4109,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future::pending().await
|
std::future::pending().await
|
||||||
},
|
}),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -4137,10 +4136,9 @@ impl Application for App {
|
||||||
#[cfg(feature = "notify")]
|
#[cfg(feature = "notify")]
|
||||||
{
|
{
|
||||||
struct NotificationSubscription;
|
struct NotificationSubscription;
|
||||||
subscriptions.push(subscription::channel(
|
subscriptions.push(Subscription::run_with_id(
|
||||||
TypeId::of::<NotificationSubscription>(),
|
TypeId::of::<NotificationSubscription>(),
|
||||||
1,
|
stream::channel(1, move |msg_tx| async move {
|
||||||
move |msg_tx| async move {
|
|
||||||
let msg_tx = Arc::new(tokio::sync::Mutex::new(msg_tx));
|
let msg_tx = Arc::new(tokio::sync::Mutex::new(msg_tx));
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
match notify_rust::Notification::new()
|
match notify_rust::Notification::new()
|
||||||
|
|
@ -4168,7 +4166,7 @@ impl Application for App {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
std::future::pending().await
|
std::future::pending().await
|
||||||
},
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4178,23 +4176,26 @@ impl Application for App {
|
||||||
//TODO: use recipe?
|
//TODO: use recipe?
|
||||||
let id = *id;
|
let id = *id;
|
||||||
let pending_operation = pending_operation.clone();
|
let pending_operation = pending_operation.clone();
|
||||||
subscriptions.push(subscription::channel(id, 16, move |msg_tx| async move {
|
subscriptions.push(Subscription::run_with_id(
|
||||||
let msg_tx = Arc::new(tokio::sync::Mutex::new(msg_tx));
|
id,
|
||||||
match pending_operation.perform(id, &msg_tx).await {
|
stream::channel(16, move |msg_tx| async move {
|
||||||
Ok(()) => {
|
let msg_tx = Arc::new(tokio::sync::Mutex::new(msg_tx));
|
||||||
let _ = msg_tx.lock().await.send(Message::PendingComplete(id)).await;
|
match pending_operation.perform(id, &msg_tx).await {
|
||||||
|
Ok(()) => {
|
||||||
|
let _ = msg_tx.lock().await.send(Message::PendingComplete(id)).await;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
let _ = msg_tx
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.send(Message::PendingError(id, err.to_string()))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
|
||||||
let _ = msg_tx
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.send(Message::PendingError(id, err.to_string()))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::future::pending().await
|
std::future::pending().await
|
||||||
}));
|
}),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
for entity in self.tab_model.iter() {
|
for entity in self.tab_model.iter() {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::{any::TypeId, num::NonZeroU16, path::PathBuf};
|
||||||
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
cosmic_config::{self, cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry},
|
cosmic_config::{self, cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry},
|
||||||
iced::subscription::Subscription,
|
iced::Subscription,
|
||||||
theme, Application,
|
theme, Application,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
||||||
129
src/dialog.rs
129
src/dialog.rs
|
|
@ -1,19 +1,14 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
#[cfg(feature = "winit")]
|
|
||||||
use cosmic::iced::multi_window::Application as IcedApplication;
|
|
||||||
#[cfg(feature = "wayland")]
|
|
||||||
use cosmic::iced::Application as IcedApplication;
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app::{self, cosmic::Cosmic, message, Command, Core},
|
app::{self, cosmic::Cosmic, message, Core, Task},
|
||||||
cosmic_config, cosmic_theme, executor,
|
cosmic_config, cosmic_theme, executor,
|
||||||
iced::{
|
iced::{
|
||||||
event,
|
event,
|
||||||
futures::{self, SinkExt},
|
futures::{self, SinkExt},
|
||||||
keyboard::{Event as KeyEvent, Key, Modifiers},
|
keyboard::{Event as KeyEvent, Key, Modifiers},
|
||||||
subscription::{self, Subscription},
|
stream, window, Alignment, Event, Length, Size, Subscription,
|
||||||
window, Alignment, Event, Length, Size,
|
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
widget::{
|
widget::{
|
||||||
|
|
@ -156,7 +151,7 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
path_opt: Option<PathBuf>,
|
path_opt: Option<PathBuf>,
|
||||||
mapper: fn(DialogMessage) -> M,
|
mapper: fn(DialogMessage) -> M,
|
||||||
on_result: impl Fn(DialogResult) -> M + 'static,
|
on_result: impl Fn(DialogResult) -> M + 'static,
|
||||||
) -> (Self, Command<M>) {
|
) -> (Self, Task<M>) {
|
||||||
//TODO: only do this once somehow?
|
//TODO: only do this once somehow?
|
||||||
crate::localize::localize();
|
crate::localize::localize();
|
||||||
|
|
||||||
|
|
@ -175,9 +170,10 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
settings.platform_specific.application_id = App::APP_ID.to_string();
|
settings.platform_specific.application_id = App::APP_ID.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (window_id, window_command) = window::spawn(settings);
|
let (window_id, window_command) = window::open(settings.clone());
|
||||||
|
|
||||||
let core = Core::default();
|
let mut core = Core::default();
|
||||||
|
core.set_main_window_id(Some(window_id));
|
||||||
let flags = Flags {
|
let flags = Flags {
|
||||||
kind,
|
kind,
|
||||||
path_opt: path_opt
|
path_opt: path_opt
|
||||||
|
|
@ -193,21 +189,24 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
config_handler,
|
config_handler,
|
||||||
config,
|
config,
|
||||||
};
|
};
|
||||||
let (cosmic, cosmic_command) = <Cosmic<App> as IcedApplication>::new((core, flags));
|
|
||||||
|
|
||||||
|
let (cosmic, cosmic_command) = Cosmic::<App>::init((core, flags));
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
cosmic,
|
cosmic,
|
||||||
mapper,
|
mapper,
|
||||||
on_result: Box::new(on_result),
|
on_result: Box::new(on_result),
|
||||||
},
|
},
|
||||||
Command::batch([window_command, cosmic_command])
|
Task::batch([
|
||||||
.map(DialogMessage)
|
window_command.map(|_id| message::none()),
|
||||||
.map(move |message| app::Message::App(mapper(message))),
|
cosmic_command
|
||||||
|
.map(DialogMessage)
|
||||||
|
.map(move |message| app::Message::App(mapper(message))),
|
||||||
|
]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_title(&mut self, title: impl Into<String>) -> Command<M> {
|
pub fn set_title(&mut self, title: impl Into<String>) -> Task<M> {
|
||||||
let mapper = self.mapper;
|
let mapper = self.mapper;
|
||||||
self.cosmic.app.title = title.into();
|
self.cosmic.app.title = title.into();
|
||||||
self.cosmic
|
self.cosmic
|
||||||
|
|
@ -237,7 +236,7 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
&mut self,
|
&mut self,
|
||||||
filters: impl Into<Vec<DialogFilter>>,
|
filters: impl Into<Vec<DialogFilter>>,
|
||||||
filter_selected: Option<usize>,
|
filter_selected: Option<usize>,
|
||||||
) -> Command<M> {
|
) -> Task<M> {
|
||||||
let mapper = self.mapper;
|
let mapper = self.mapper;
|
||||||
self.cosmic.app.filters = filters.into();
|
self.cosmic.app.filters = filters.into();
|
||||||
self.cosmic.app.filter_selected = filter_selected;
|
self.cosmic.app.filter_selected = filter_selected;
|
||||||
|
|
@ -255,7 +254,7 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
.map(self.mapper)
|
.map(self.mapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, message: DialogMessage) -> Command<M> {
|
pub fn update(&mut self, message: DialogMessage) -> Task<M> {
|
||||||
let mapper = self.mapper;
|
let mapper = self.mapper;
|
||||||
let command = self
|
let command = self
|
||||||
.cosmic
|
.cosmic
|
||||||
|
|
@ -264,9 +263,9 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
.map(move |message| app::Message::App(mapper(message)));
|
.map(move |message| app::Message::App(mapper(message)));
|
||||||
if let Some(result) = self.cosmic.app.result_opt.take() {
|
if let Some(result) = self.cosmic.app.result_opt.take() {
|
||||||
let on_result_message = (self.on_result)(result);
|
let on_result_message = (self.on_result)(result);
|
||||||
Command::batch([
|
Task::batch([
|
||||||
command,
|
command,
|
||||||
Command::perform(async move { app::Message::App(on_result_message) }, |x| x),
|
Task::perform(async move { app::Message::App(on_result_message) }, |x| x),
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
command
|
command
|
||||||
|
|
@ -281,7 +280,7 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_id(&self) -> window::Id {
|
pub fn window_id(&self) -> window::Id {
|
||||||
self.cosmic.app.main_window_id()
|
self.cosmic.app.flags.window_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,7 +420,7 @@ impl App {
|
||||||
let mut row = widget::row::with_capacity(
|
let mut row = widget::row::with_capacity(
|
||||||
if !self.filters.is_empty() { 1 } else { 0 } + self.choices.len() * 2 + 3,
|
if !self.filters.is_empty() { 1 } else { 0 } + self.choices.len() * 2 + 3,
|
||||||
)
|
)
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs);
|
.spacing(space_xxs);
|
||||||
if !self.filters.is_empty() {
|
if !self.filters.is_empty() {
|
||||||
row = row.push(widget::dropdown(
|
row = row.push(widget::dropdown(
|
||||||
|
|
@ -433,7 +432,7 @@ impl App {
|
||||||
for (choice_i, choice) in self.choices.iter().enumerate() {
|
for (choice_i, choice) in self.choices.iter().enumerate() {
|
||||||
match choice {
|
match choice {
|
||||||
DialogChoice::CheckBox { label, value, .. } => {
|
DialogChoice::CheckBox { label, value, .. } => {
|
||||||
row = row.push(widget::checkbox(label, *value, move |checked| {
|
row = row.push(widget::checkbox(label, *value).on_toggle(move |checked| {
|
||||||
Message::Choice(choice_i, if checked { 1 } else { 0 })
|
Message::Choice(choice_i, if checked { 1 } else { 0 })
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
@ -450,7 +449,7 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
row = row.push(widget::horizontal_space(Length::Fill));
|
row = row.push(widget::horizontal_space());
|
||||||
row = row.push(widget::button::standard(fl!("cancel")).on_press(Message::Cancel));
|
row = row.push(widget::button::standard(fl!("cancel")).on_press(Message::Cancel));
|
||||||
row = row.push(if self.flags.kind.save() {
|
row = row.push(if self.flags.kind.save() {
|
||||||
widget::button::suggested(&self.accept_label).on_press(Message::Save(false))
|
widget::button::suggested(&self.accept_label).on_press(Message::Save(false))
|
||||||
|
|
@ -505,10 +504,10 @@ impl App {
|
||||||
widget::settings::view_column(children).into()
|
widget::settings::view_column(children).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rescan_tab(&self) -> Command<Message> {
|
fn rescan_tab(&self) -> Task<Message> {
|
||||||
let location = self.tab.location.clone();
|
let location = self.tab.location.clone();
|
||||||
let icon_sizes = self.tab.config.icon_sizes;
|
let icon_sizes = self.tab.config.icon_sizes;
|
||||||
Command::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
let location2 = location.clone();
|
let location2 = location.clone();
|
||||||
match tokio::task::spawn_blocking(move || location2.scan(icon_sizes)).await {
|
match tokio::task::spawn_blocking(move || location2.scan(icon_sizes)).await {
|
||||||
|
|
@ -532,7 +531,7 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_set(&mut self, term_opt: Option<String>) -> Command<Message> {
|
fn search_set(&mut self, term_opt: Option<String>) -> Task<Message> {
|
||||||
let location_opt = match term_opt {
|
let location_opt = match term_opt {
|
||||||
Some(term) => match &self.tab.location {
|
Some(term) => match &self.tab.location {
|
||||||
Location::Path(path) | Location::Search(path, ..) => Some((
|
Location::Path(path) | Location::Search(path, ..) => Some((
|
||||||
|
|
@ -553,23 +552,23 @@ impl App {
|
||||||
};
|
};
|
||||||
if let Some((location, focus_search)) = location_opt {
|
if let Some((location, focus_search)) = location_opt {
|
||||||
self.tab.change_location(&location, None);
|
self.tab.change_location(&location, None);
|
||||||
return Command::batch([
|
return Task::batch([
|
||||||
self.update_title(),
|
self.update_title(),
|
||||||
self.update_watcher(),
|
self.update_watcher(),
|
||||||
self.rescan_tab(),
|
self.rescan_tab(),
|
||||||
if focus_search {
|
if focus_search {
|
||||||
widget::text_input::focus(self.search_id.clone())
|
widget::text_input::focus(self.search_id.clone())
|
||||||
} else {
|
} else {
|
||||||
Command::none()
|
Task::none()
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_config(&mut self) -> Command<Message> {
|
fn update_config(&mut self) -> Task<Message> {
|
||||||
self.update_nav_model();
|
self.update_nav_model();
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate_nav_model_location(&mut self, location: &Location) {
|
fn activate_nav_model_location(&mut self, location: &Location) {
|
||||||
|
|
@ -657,12 +656,12 @@ impl App {
|
||||||
self.activate_nav_model_location(&self.tab.location.clone());
|
self.activate_nav_model_location(&self.tab.location.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_title(&mut self) -> Command<Message> {
|
fn update_title(&mut self) -> Task<Message> {
|
||||||
self.set_header_title(self.title.clone());
|
self.set_header_title(self.title.clone());
|
||||||
self.set_window_title(self.title.clone(), self.main_window_id())
|
self.set_window_title(self.title.clone(), self.flags.window_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_watcher(&mut self) -> Command<Message> {
|
fn update_watcher(&mut self) -> Task<Message> {
|
||||||
if let Some((mut watcher, old_paths)) = self.watcher_opt.take() {
|
if let Some((mut watcher, old_paths)) = self.watcher_opt.take() {
|
||||||
let mut new_paths = HashSet::new();
|
let mut new_paths = HashSet::new();
|
||||||
if let Some(path) = &self.tab.location.path_opt() {
|
if let Some(path) = &self.tab.location.path_opt() {
|
||||||
|
|
@ -705,7 +704,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: should any of this run in a command?
|
//TODO: should any of this run in a command?
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -732,7 +731,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the application, and optionally emits command on initialize.
|
/// Creates the application, and optionally emits command on initialize.
|
||||||
fn init(mut core: Core, flags: Self::Flags) -> (Self, Command<Message>) {
|
fn init(mut core: Core, flags: Self::Flags) -> (Self, Task<Message>) {
|
||||||
core.window.context_is_overlay = false;
|
core.window.context_is_overlay = false;
|
||||||
core.window.show_close = false;
|
core.window.show_close = false;
|
||||||
core.window.show_maximize = false;
|
core.window.show_maximize = false;
|
||||||
|
|
@ -785,7 +784,7 @@ impl Application for App {
|
||||||
watcher_opt: None,
|
watcher_opt: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let commands = Command::batch([
|
let commands = Task::batch([
|
||||||
app.update_config(),
|
app.update_config(),
|
||||||
app.update_title(),
|
app.update_title(),
|
||||||
app.update_watcher(),
|
app.update_watcher(),
|
||||||
|
|
@ -795,10 +794,6 @@ impl Application for App {
|
||||||
(app, commands)
|
(app, commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_window_id(&self) -> window::Id {
|
|
||||||
self.flags.window_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn context_drawer(&self) -> Option<Element<Message>> {
|
fn context_drawer(&self) -> Option<Element<Message>> {
|
||||||
if !self.core.window.show_context {
|
if !self.core.window.show_context {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -822,7 +817,7 @@ impl Application for App {
|
||||||
widget::container(self.button_view())
|
widget::container(self.button_view())
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.padding(space_xxs)
|
.padding(space_xxs)
|
||||||
.style(theme::Container::WindowBackground)
|
.class(theme::Container::WindowBackground)
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.into(),
|
.into(),
|
||||||
|
|
@ -1004,7 +999,7 @@ impl Application for App {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_nav_select(&mut self, entity: segmented_button::Entity) -> Command<Message> {
|
fn on_nav_select(&mut self, entity: segmented_button::Entity) -> Task<Message> {
|
||||||
self.nav_model.activate(entity);
|
self.nav_model.activate(entity);
|
||||||
if let Some(location) = self.nav_model.data::<Location>(entity) {
|
if let Some(location) = self.nav_model.data::<Location>(entity) {
|
||||||
let message = Message::TabMessage(tab::Message::Location(location.clone()));
|
let message = Message::TabMessage(tab::Message::Location(location.clone()));
|
||||||
|
|
@ -1016,14 +1011,14 @@ impl Application for App {
|
||||||
return mounter.mount(data.1.clone()).map(|_| message::none());
|
return mounter.mount(data.1.clone()).map(|_| message::none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_escape(&mut self) -> Command<Message> {
|
fn on_escape(&mut self) -> Task<Message> {
|
||||||
if self.tab.gallery {
|
if self.tab.gallery {
|
||||||
// Close gallery if open
|
// Close gallery if open
|
||||||
self.tab.gallery = false;
|
self.tab.gallery = false;
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.search_get().is_some() {
|
if self.search_get().is_some() {
|
||||||
|
|
@ -1033,13 +1028,13 @@ impl Application for App {
|
||||||
|
|
||||||
if self.tab.context_menu.is_some() {
|
if self.tab.context_menu.is_some() {
|
||||||
self.tab.context_menu = None;
|
self.tab.context_menu = None;
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tab.edit_location.is_some() {
|
if self.tab.edit_location.is_some() {
|
||||||
// Close location editing if enabled
|
// Close location editing if enabled
|
||||||
self.tab.edit_location = None;
|
self.tab.edit_location = None;
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
let had_focused_button = self.tab.select_focus_id().is_some();
|
let had_focused_button = self.tab.select_focus_id().is_some();
|
||||||
|
|
@ -1048,19 +1043,19 @@ impl Application for App {
|
||||||
// Unfocus if there was a focused button
|
// Unfocus if there was a focused button
|
||||||
return widget::button::focus(widget::Id::unique());
|
return widget::button::focus(widget::Id::unique());
|
||||||
}
|
}
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update(Message::Cancel)
|
self.update(Message::Cancel)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle application events here.
|
/// Handle application events here.
|
||||||
fn update(&mut self, message: Message) -> Command<Message> {
|
fn update(&mut self, message: Message) -> Task<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::None => {}
|
Message::None => {}
|
||||||
Message::Cancel => {
|
Message::Cancel => {
|
||||||
self.result_opt = Some(DialogResult::Cancel);
|
self.result_opt = Some(DialogResult::Cancel);
|
||||||
return window::close(self.main_window_id());
|
return window::close(self.flags.window_id);
|
||||||
}
|
}
|
||||||
Message::Choice(choice_i, option_i) => {
|
Message::Choice(choice_i, option_i) => {
|
||||||
if let Some(choice) = self.choices.get_mut(choice_i) {
|
if let Some(choice) = self.choices.get_mut(choice_i) {
|
||||||
|
|
@ -1187,7 +1182,7 @@ impl Application for App {
|
||||||
//TODO: this could change favorites IDs while they are in use
|
//TODO: this could change favorites IDs while they are in use
|
||||||
self.update_nav_model();
|
self.update_nav_model();
|
||||||
|
|
||||||
return Command::batch(commands);
|
return Task::batch(commands);
|
||||||
}
|
}
|
||||||
Message::NewFolder => {
|
Message::NewFolder => {
|
||||||
if let Some(path) = self.tab.location.path_opt() {
|
if let Some(path) = self.tab.location.path_opt() {
|
||||||
|
|
@ -1293,7 +1288,7 @@ impl Application for App {
|
||||||
return self.update(message);
|
return self.update(message);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, this is not a legal selection
|
// Otherwise, this is not a legal selection
|
||||||
return Command::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1301,7 +1296,7 @@ impl Application for App {
|
||||||
// If there are proper matching items, return them
|
// If there are proper matching items, return them
|
||||||
if !paths.is_empty() {
|
if !paths.is_empty() {
|
||||||
self.result_opt = Some(DialogResult::Open(paths));
|
self.result_opt = Some(DialogResult::Open(paths));
|
||||||
return window::close(self.main_window_id());
|
return window::close(self.flags.window_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are in directory mode, return the current directory
|
// If we are in directory mode, return the current directory
|
||||||
|
|
@ -1309,7 +1304,7 @@ impl Application for App {
|
||||||
match &self.tab.location {
|
match &self.tab.location {
|
||||||
Location::Path(tab_path) => {
|
Location::Path(tab_path) => {
|
||||||
self.result_opt = Some(DialogResult::Open(vec![tab_path.clone()]));
|
self.result_opt = Some(DialogResult::Open(vec![tab_path.clone()]));
|
||||||
return window::close(self.main_window_id());
|
return window::close(self.flags.window_id);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -1341,7 +1336,7 @@ impl Application for App {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.result_opt = Some(DialogResult::Open(vec![path]));
|
self.result_opt = Some(DialogResult::Open(vec![path]));
|
||||||
return window::close(self.main_window_id());
|
return window::close(self.flags.window_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1388,12 +1383,11 @@ impl Application for App {
|
||||||
commands.push(self.update(Message::from(action.message())));
|
commands.push(self.update(Message::from(action.message())));
|
||||||
}
|
}
|
||||||
tab::Command::ChangeLocation(_tab_title, _tab_path, _selection_path) => {
|
tab::Command::ChangeLocation(_tab_title, _tab_path, _selection_path) => {
|
||||||
commands
|
commands.push(Task::batch([self.update_watcher(), self.rescan_tab()]));
|
||||||
.push(Command::batch([self.update_watcher(), self.rescan_tab()]));
|
|
||||||
}
|
}
|
||||||
tab::Command::Iced(iced_command) => {
|
tab::Command::Iced(iced_command) => {
|
||||||
commands.push(
|
commands.push(
|
||||||
iced_command.map(|tab_message| {
|
iced_command.0.map(|tab_message| {
|
||||||
message::app(Message::TabMessage(tab_message))
|
message::app(Message::TabMessage(tab_message))
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -1411,17 +1405,17 @@ impl Application for App {
|
||||||
self.set_context_title(self.context_page.title());
|
self.set_context_title(self.context_page.title());
|
||||||
}
|
}
|
||||||
tab::Command::WindowDrag => {
|
tab::Command::WindowDrag => {
|
||||||
commands.push(window::drag(self.main_window_id()));
|
commands.push(window::drag(self.flags.window_id));
|
||||||
}
|
}
|
||||||
tab::Command::WindowToggleMaximize => {
|
tab::Command::WindowToggleMaximize => {
|
||||||
commands.push(window::toggle_maximize(self.main_window_id()));
|
commands.push(window::toggle_maximize(self.flags.window_id));
|
||||||
}
|
}
|
||||||
unsupported => {
|
unsupported => {
|
||||||
log::warn!("{unsupported:?} not supported in dialog mode");
|
log::warn!("{unsupported:?} not supported in dialog mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Command::batch(commands);
|
return Task::batch(commands);
|
||||||
}
|
}
|
||||||
Message::TabRescan(location, parent_item_opt, mut items) => {
|
Message::TabRescan(location, parent_item_opt, mut items) => {
|
||||||
if location == self.tab.location {
|
if location == self.tab.location {
|
||||||
|
|
@ -1554,7 +1548,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a view after each update.
|
/// Creates a view after each update.
|
||||||
|
|
@ -1590,7 +1584,7 @@ impl Application for App {
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
struct WatcherSubscription;
|
struct WatcherSubscription;
|
||||||
let mut subscriptions = vec![
|
let mut subscriptions = vec![
|
||||||
event::listen_with(|event, status| match event {
|
event::listen_with(|event, status, _window_id| match event {
|
||||||
Event::Keyboard(KeyEvent::KeyPressed { key, modifiers, .. }) => match status {
|
Event::Keyboard(KeyEvent::KeyPressed { key, modifiers, .. }) => match status {
|
||||||
event::Status::Ignored => Some(Message::Key(modifiers, key)),
|
event::Status::Ignored => Some(Message::Key(modifiers, key)),
|
||||||
event::Status::Captured => None,
|
event::Status::Captured => None,
|
||||||
|
|
@ -1610,10 +1604,9 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
Message::Config(update.config)
|
Message::Config(update.config)
|
||||||
}),
|
}),
|
||||||
subscription::channel(
|
Subscription::run_with_id(
|
||||||
TypeId::of::<WatcherSubscription>(),
|
TypeId::of::<WatcherSubscription>(),
|
||||||
100,
|
stream::channel(100, |mut output| async move {
|
||||||
|mut output| async move {
|
|
||||||
let watcher_res = {
|
let watcher_res = {
|
||||||
let mut output = output.clone();
|
let mut output = output.clone();
|
||||||
new_debouncer(
|
new_debouncer(
|
||||||
|
|
@ -1683,7 +1676,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future::pending().await
|
std::future::pending().await
|
||||||
},
|
}),
|
||||||
),
|
),
|
||||||
self.tab.subscription().map(Message::TabMessage),
|
self.tab.subscription().map(Message::TabMessage),
|
||||||
];
|
];
|
||||||
|
|
|
||||||
24
src/menu.rs
24
src/menu.rs
|
|
@ -27,11 +27,11 @@ macro_rules! menu_button {
|
||||||
vec![$(Element::from($x)),+]
|
vec![$(Element::from($x)),+]
|
||||||
)
|
)
|
||||||
.height(Length::Fixed(24.0))
|
.height(Length::Fixed(24.0))
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
)
|
)
|
||||||
.padding([theme::active().cosmic().spacing.space_xxxs, 16])
|
.padding([theme::active().cosmic().spacing.space_xxxs, 16])
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.style(theme::Button::MenuItem)
|
.class(theme::Button::MenuItem)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,12 +62,8 @@ pub fn context_menu<'a>(
|
||||||
|
|
||||||
let menu_item = |label, action| {
|
let menu_item = |label, action| {
|
||||||
let key = find_key(&action);
|
let key = find_key(&action);
|
||||||
menu_button!(
|
menu_button!(text::body(label), horizontal_space(), text::body(key))
|
||||||
text::body(label),
|
.on_press(tab::Message::ContextAction(action))
|
||||||
horizontal_space(Length::Fill),
|
|
||||||
text::body(key)
|
|
||||||
)
|
|
||||||
.on_press(tab::Message::ContextAction(action))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (sort_name, sort_direction, _) = tab.sort_options();
|
let (sort_name, sort_direction, _) = tab.sort_options();
|
||||||
|
|
@ -291,10 +287,10 @@ pub fn context_menu<'a>(
|
||||||
container(column::with_children(children))
|
container(column::with_children(children))
|
||||||
.padding(1)
|
.padding(1)
|
||||||
//TODO: move style to libcosmic
|
//TODO: move style to libcosmic
|
||||||
.style(theme::Container::custom(|theme| {
|
.style(|theme| {
|
||||||
let cosmic = theme.cosmic();
|
let cosmic = theme.cosmic();
|
||||||
let component = &cosmic.background.component;
|
let component = &cosmic.background.component;
|
||||||
container::Appearance {
|
container::Style {
|
||||||
icon_color: Some(component.on.into()),
|
icon_color: Some(component.on.into()),
|
||||||
text_color: Some(component.on.into()),
|
text_color: Some(component.on.into()),
|
||||||
background: Some(Background::Color(component.base.into())),
|
background: Some(Background::Color(component.base.into())),
|
||||||
|
|
@ -305,7 +301,7 @@ pub fn context_menu<'a>(
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
.width(Length::Fixed(260.0))
|
.width(Length::Fixed(260.0))
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
@ -641,10 +637,10 @@ pub fn location_context_menu<'a>(ancestor_index: usize) -> Element<'a, tab::Mess
|
||||||
|
|
||||||
container(column::with_children(children))
|
container(column::with_children(children))
|
||||||
.padding(1)
|
.padding(1)
|
||||||
.style(theme::Container::custom(|theme| {
|
.style(|theme| {
|
||||||
let cosmic = theme.cosmic();
|
let cosmic = theme.cosmic();
|
||||||
let component = &cosmic.background.component;
|
let component = &cosmic.background.component;
|
||||||
container::Appearance {
|
container::Style {
|
||||||
icon_color: Some(component.on.into()),
|
icon_color: Some(component.on.into()),
|
||||||
text_color: Some(component.on.into()),
|
text_color: Some(component.on.into()),
|
||||||
background: Some(Background::Color(component.base.into())),
|
background: Some(Background::Color(component.base.into())),
|
||||||
|
|
@ -655,7 +651,7 @@ pub fn location_context_menu<'a>(ancestor_index: usize) -> Element<'a, tab::Mess
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
.width(Length::Fixed(240.0))
|
.width(Length::Fixed(240.0))
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
iced::{futures::SinkExt, subscription},
|
iced::{futures::SinkExt, stream, Subscription},
|
||||||
widget, Command,
|
widget, Task,
|
||||||
};
|
};
|
||||||
use gio::{glib, prelude::*};
|
use gio::{glib, prelude::*};
|
||||||
use std::{any::TypeId, cell::Cell, future::pending, path::PathBuf, sync::Arc};
|
use std::{any::TypeId, cell::Cell, future::pending, path::PathBuf, sync::Arc};
|
||||||
|
|
@ -460,9 +460,9 @@ impl Mounter for Gvfs {
|
||||||
items_rx.blocking_recv()
|
items_rx.blocking_recv()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mount(&self, item: MounterItem) -> Command<()> {
|
fn mount(&self, item: MounterItem) -> Task<()> {
|
||||||
let command_tx = self.command_tx.clone();
|
let command_tx = self.command_tx.clone();
|
||||||
Command::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
command_tx.send(Cmd::Mount(item)).unwrap();
|
command_tx.send(Cmd::Mount(item)).unwrap();
|
||||||
()
|
()
|
||||||
|
|
@ -471,9 +471,9 @@ impl Mounter for Gvfs {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn network_drive(&self, uri: String) -> Command<()> {
|
fn network_drive(&self, uri: String) -> Task<()> {
|
||||||
let command_tx = self.command_tx.clone();
|
let command_tx = self.command_tx.clone();
|
||||||
Command::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
command_tx.send(Cmd::NetworkDrive(uri)).unwrap();
|
command_tx.send(Cmd::NetworkDrive(uri)).unwrap();
|
||||||
()
|
()
|
||||||
|
|
@ -490,9 +490,9 @@ impl Mounter for Gvfs {
|
||||||
items_rx.blocking_recv()
|
items_rx.blocking_recv()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmount(&self, item: MounterItem) -> Command<()> {
|
fn unmount(&self, item: MounterItem) -> Task<()> {
|
||||||
let command_tx = self.command_tx.clone();
|
let command_tx = self.command_tx.clone();
|
||||||
Command::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
command_tx.send(Cmd::Unmount(item)).unwrap();
|
command_tx.send(Cmd::Unmount(item)).unwrap();
|
||||||
()
|
()
|
||||||
|
|
@ -501,30 +501,35 @@ impl Mounter for Gvfs {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> subscription::Subscription<MounterMessage> {
|
fn subscription(&self) -> Subscription<MounterMessage> {
|
||||||
let command_tx = self.command_tx.clone();
|
let command_tx = self.command_tx.clone();
|
||||||
let event_rx = self.event_rx.clone();
|
let event_rx = self.event_rx.clone();
|
||||||
subscription::channel(TypeId::of::<Self>(), 1, |mut output| async move {
|
Subscription::run_with_id(
|
||||||
command_tx.send(Cmd::Rescan).unwrap();
|
TypeId::of::<Self>(),
|
||||||
while let Some(event) = event_rx.lock().await.recv().await {
|
stream::channel(1, |mut output| async move {
|
||||||
match event {
|
command_tx.send(Cmd::Rescan).unwrap();
|
||||||
Event::Changed => command_tx.send(Cmd::Rescan).unwrap(),
|
while let Some(event) = event_rx.lock().await.recv().await {
|
||||||
Event::Items(items) => output.send(MounterMessage::Items(items)).await.unwrap(),
|
match event {
|
||||||
Event::MountResult(item, res) => output
|
Event::Changed => command_tx.send(Cmd::Rescan).unwrap(),
|
||||||
.send(MounterMessage::MountResult(item, res))
|
Event::Items(items) => {
|
||||||
.await
|
output.send(MounterMessage::Items(items)).await.unwrap()
|
||||||
.unwrap(),
|
}
|
||||||
Event::NetworkAuth(uri, auth, auth_tx) => output
|
Event::MountResult(item, res) => output
|
||||||
.send(MounterMessage::NetworkAuth(uri, auth, auth_tx))
|
.send(MounterMessage::MountResult(item, res))
|
||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Event::NetworkResult(uri, res) => output
|
Event::NetworkAuth(uri, auth, auth_tx) => output
|
||||||
.send(MounterMessage::NetworkResult(uri, res))
|
.send(MounterMessage::NetworkAuth(uri, auth, auth_tx))
|
||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
Event::NetworkResult(uri, res) => output
|
||||||
|
.send(MounterMessage::NetworkResult(uri, res))
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
pending().await
|
||||||
pending().await
|
}),
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use cosmic::{iced::subscription, widget, Command};
|
use cosmic::{iced::Subscription, widget, Task};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{collections::BTreeMap, fmt, path::PathBuf, sync::Arc};
|
use std::{collections::BTreeMap, fmt, path::PathBuf, sync::Arc};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
@ -93,11 +93,11 @@ pub enum MounterMessage {
|
||||||
pub trait Mounter: Send + Sync {
|
pub trait Mounter: Send + Sync {
|
||||||
fn items(&self, sizes: IconSizes) -> Option<MounterItems>;
|
fn items(&self, sizes: IconSizes) -> Option<MounterItems>;
|
||||||
//TODO: send result
|
//TODO: send result
|
||||||
fn mount(&self, item: MounterItem) -> Command<()>;
|
fn mount(&self, item: MounterItem) -> Task<()>;
|
||||||
fn network_drive(&self, uri: String) -> Command<()>;
|
fn network_drive(&self, uri: String) -> Task<()>;
|
||||||
fn network_scan(&self, uri: &str, sizes: IconSizes) -> Option<Result<Vec<tab::Item>, String>>;
|
fn network_scan(&self, uri: &str, sizes: IconSizes) -> Option<Result<Vec<tab::Item>, String>>;
|
||||||
fn unmount(&self, item: MounterItem) -> Command<()>;
|
fn unmount(&self, item: MounterItem) -> Task<()>;
|
||||||
fn subscription(&self) -> subscription::Subscription<MounterMessage>;
|
fn subscription(&self) -> Subscription<MounterMessage>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ use cosmic::{
|
||||||
overlay,
|
overlay,
|
||||||
renderer::{self, Quad, Renderer as _},
|
renderer::{self, Quad, Renderer as _},
|
||||||
touch,
|
touch,
|
||||||
widget::{tree, Operation, OperationOutputWrapper, Tree},
|
widget::{tree, Operation, Tree},
|
||||||
Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Size, Widget,
|
Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget,
|
||||||
},
|
},
|
||||||
widget::Id,
|
widget::Id,
|
||||||
Element, Renderer, Theme,
|
Element, Renderer, Theme,
|
||||||
|
|
@ -218,15 +218,21 @@ impl State {
|
||||||
let new = if let Some((prev_click, prev_time)) = self.prev_click.take() {
|
let new = if let Some((prev_click, prev_time)) = self.prev_click.take() {
|
||||||
if now.duration_since(prev_time) < DOUBLE_CLICK_DURATION {
|
if now.duration_since(prev_time) < DOUBLE_CLICK_DURATION {
|
||||||
match prev_click.kind() {
|
match prev_click.kind() {
|
||||||
mouse::click::Kind::Single => mouse::Click::new(pos, Some(prev_click)),
|
mouse::click::Kind::Single => {
|
||||||
mouse::click::Kind::Double => mouse::Click::new(pos, Some(prev_click)),
|
mouse::Click::new(pos, mouse::Button::Left, Some(prev_click))
|
||||||
mouse::click::Kind::Triple => mouse::Click::new(pos, Some(prev_click)),
|
}
|
||||||
|
mouse::click::Kind::Double => {
|
||||||
|
mouse::Click::new(pos, mouse::Button::Left, Some(prev_click))
|
||||||
|
}
|
||||||
|
mouse::click::Kind::Triple => {
|
||||||
|
mouse::Click::new(pos, mouse::Button::Left, Some(prev_click))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mouse::Click::new(pos, None)
|
mouse::Click::new(pos, mouse::Button::Left, None)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mouse::Click::new(pos, None)
|
mouse::Click::new(pos, mouse::Button::Left, None)
|
||||||
};
|
};
|
||||||
self.prev_click = Some((new.clone(), now));
|
self.prev_click = Some((new.clone(), now));
|
||||||
new
|
new
|
||||||
|
|
@ -300,7 +306,7 @@ where
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
operation: &mut dyn Operation<OperationOutputWrapper<Message>>,
|
operation: &mut dyn Operation,
|
||||||
) {
|
) {
|
||||||
self.content
|
self.content
|
||||||
.as_widget()
|
.as_widget()
|
||||||
|
|
@ -406,10 +412,11 @@ where
|
||||||
tree: &'b mut Tree,
|
tree: &'b mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
|
translation: Vector,
|
||||||
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
||||||
self.content
|
self.content
|
||||||
.as_widget_mut()
|
.as_widget_mut()
|
||||||
.overlay(&mut tree.children[0], layout, renderer)
|
.overlay(&mut tree.children[0], layout, renderer, translation)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drag_destinations(
|
fn drag_destinations(
|
||||||
|
|
|
||||||
368
src/tab.rs
368
src/tab.rs
|
|
@ -11,10 +11,10 @@ use cosmic::{
|
||||||
futures,
|
futures,
|
||||||
futures::SinkExt,
|
futures::SinkExt,
|
||||||
keyboard::Modifiers,
|
keyboard::Modifiers,
|
||||||
subscription::{self, Subscription},
|
stream,
|
||||||
//TODO: export in cosmic::widget
|
//TODO: export in cosmic::widget
|
||||||
widget::{
|
widget::{
|
||||||
container, horizontal_rule,
|
container, horizontal_rule, rule,
|
||||||
scrollable::{self, AbsoluteOffset, Viewport},
|
scrollable::{self, AbsoluteOffset, Viewport},
|
||||||
},
|
},
|
||||||
Alignment,
|
Alignment,
|
||||||
|
|
@ -25,16 +25,16 @@ use cosmic::{
|
||||||
Point,
|
Point,
|
||||||
Rectangle,
|
Rectangle,
|
||||||
Size,
|
Size,
|
||||||
|
Subscription,
|
||||||
},
|
},
|
||||||
iced_core::{mouse::ScrollDelta, widget::tree},
|
iced_core::{mouse::ScrollDelta, widget::tree},
|
||||||
iced_style::rule,
|
|
||||||
theme,
|
theme,
|
||||||
widget::{
|
widget::{
|
||||||
self,
|
self,
|
||||||
menu::{action::MenuAction, key_bind::KeyBind},
|
menu::{action::MenuAction, key_bind::KeyBind},
|
||||||
vertical_space, DndDestination, DndSource, Id, Widget,
|
DndDestination, DndSource, Id, Space, Widget,
|
||||||
},
|
},
|
||||||
Element, Theme,
|
Element,
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
@ -122,9 +122,9 @@ fn button_appearance(
|
||||||
accent: bool,
|
accent: bool,
|
||||||
condensed_radius: bool,
|
condensed_radius: bool,
|
||||||
desktop: bool,
|
desktop: bool,
|
||||||
) -> widget::button::Appearance {
|
) -> widget::button::Style {
|
||||||
let cosmic = theme.cosmic();
|
let cosmic = theme.cosmic();
|
||||||
let mut appearance = widget::button::Appearance::new();
|
let mut appearance = widget::button::Style::new();
|
||||||
if selected {
|
if selected {
|
||||||
if accent {
|
if accent {
|
||||||
appearance.background = Some(Color::from(cosmic.accent_color()).into());
|
appearance.background = Some(Color::from(cosmic.accent_color()).into());
|
||||||
|
|
@ -938,6 +938,20 @@ impl Location {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TaskWrapper(pub cosmic::Task<Message>);
|
||||||
|
|
||||||
|
impl From<cosmic::Task<Message>> for TaskWrapper {
|
||||||
|
fn from(task: cosmic::Task<Message>) -> Self {
|
||||||
|
Self(task)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for TaskWrapper {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("TaskWrapper").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
Action(Action),
|
Action(Action),
|
||||||
|
|
@ -946,7 +960,7 @@ pub enum Command {
|
||||||
ChangeLocation(String, Location, Option<PathBuf>),
|
ChangeLocation(String, Location, Option<PathBuf>),
|
||||||
DropFiles(PathBuf, ClipboardPaste),
|
DropFiles(PathBuf, ClipboardPaste),
|
||||||
EmptyTrash,
|
EmptyTrash,
|
||||||
Iced(cosmic::Command<Message>),
|
Iced(TaskWrapper),
|
||||||
MoveToTrash(Vec<PathBuf>),
|
MoveToTrash(Vec<PathBuf>),
|
||||||
OpenFile(PathBuf),
|
OpenFile(PathBuf),
|
||||||
OpenInNewTab(PathBuf),
|
OpenInNewTab(PathBuf),
|
||||||
|
|
@ -1127,7 +1141,7 @@ impl ItemThumbnail {
|
||||||
let thumbnail =
|
let thumbnail =
|
||||||
image.thumbnail(thumbnail_size, thumbnail_size).into_rgba8();
|
image.thumbnail(thumbnail_size, thumbnail_size).into_rgba8();
|
||||||
return ItemThumbnail::Image(
|
return ItemThumbnail::Image(
|
||||||
widget::image::Handle::from_pixels(
|
widget::image::Handle::from_rgba(
|
||||||
thumbnail.width(),
|
thumbnail.width(),
|
||||||
thumbnail.height(),
|
thumbnail.height(),
|
||||||
thumbnail.into_raw(),
|
thumbnail.into_raw(),
|
||||||
|
|
@ -1186,7 +1200,7 @@ impl ItemThumbnail {
|
||||||
Ok(reader) => match reader.decode().map(|image| image.into_rgba8()) {
|
Ok(reader) => match reader.decode().map(|image| image.into_rgba8()) {
|
||||||
Ok(image) => {
|
Ok(image) => {
|
||||||
return ItemThumbnail::Image(
|
return ItemThumbnail::Image(
|
||||||
widget::image::Handle::from_pixels(
|
widget::image::Handle::from_rgba(
|
||||||
image.width(),
|
image.width(),
|
||||||
image.height(),
|
image.height(),
|
||||||
image.into_raw(),
|
image.into_raw(),
|
||||||
|
|
@ -1315,9 +1329,9 @@ impl Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
column = column.push(widget::row::with_children(vec![
|
column = column.push(widget::row::with_children(vec![
|
||||||
widget::horizontal_space(Length::Fill).into(),
|
widget::horizontal_space().into(),
|
||||||
self.preview(sizes),
|
self.preview(sizes),
|
||||||
widget::horizontal_space(Length::Fill).into(),
|
widget::horizontal_space().into(),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
let mut details = widget::column().spacing(space_xxxs);
|
let mut details = widget::column().spacing(space_xxxs);
|
||||||
|
|
@ -2223,23 +2237,25 @@ impl Tab {
|
||||||
self.select_rect(rect, mod_ctrl, mod_shift);
|
self.select_rect(rect, mod_ctrl, mod_shift);
|
||||||
if self.select_focus.take().is_some() {
|
if self.select_focus.take().is_some() {
|
||||||
// Unfocus currently focused button
|
// Unfocus currently focused button
|
||||||
commands.push(Command::Iced(widget::button::focus(widget::Id::unique())));
|
commands.push(Command::Iced(
|
||||||
|
widget::button::focus(widget::Id::unique()).into(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
},
|
},
|
||||||
Message::EditLocation(edit_location) => {
|
Message::EditLocation(edit_location) => {
|
||||||
if self.edit_location.is_none() && edit_location.is_some() {
|
if self.edit_location.is_none() && edit_location.is_some() {
|
||||||
commands.push(Command::Iced(widget::text_input::focus(
|
commands.push(Command::Iced(
|
||||||
self.edit_location_id.clone(),
|
widget::text_input::focus(self.edit_location_id.clone()).into(),
|
||||||
)));
|
));
|
||||||
}
|
}
|
||||||
self.edit_location = edit_location;
|
self.edit_location = edit_location;
|
||||||
}
|
}
|
||||||
Message::EditLocationEnable => {
|
Message::EditLocationEnable => {
|
||||||
commands.push(Command::Iced(widget::text_input::focus(
|
commands.push(Command::Iced(
|
||||||
self.edit_location_id.clone(),
|
widget::text_input::focus(self.edit_location_id.clone()).into(),
|
||||||
)));
|
));
|
||||||
self.edit_location = Some(self.location.clone());
|
self.edit_location = Some(self.location.clone());
|
||||||
}
|
}
|
||||||
Message::OpenInNewTab(path) => {
|
Message::OpenInNewTab(path) => {
|
||||||
|
|
@ -2281,13 +2297,12 @@ impl Tab {
|
||||||
self.select_position(row, col, mod_shift);
|
self.select_position(row, col, mod_shift);
|
||||||
}
|
}
|
||||||
if let Some(offset) = self.select_focus_scroll() {
|
if let Some(offset) = self.select_focus_scroll() {
|
||||||
commands.push(Command::Iced(scrollable::scroll_to(
|
commands.push(Command::Iced(
|
||||||
self.scrollable_id.clone(),
|
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||||
offset,
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
if let Some(id) = self.select_focus_id() {
|
if let Some(id) = self.select_focus_id() {
|
||||||
commands.push(Command::Iced(widget::button::focus(id)));
|
commands.push(Command::Iced(widget::button::focus(id).into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::GalleryToggle => {
|
Message::GalleryToggle => {
|
||||||
|
|
@ -2342,13 +2357,12 @@ impl Tab {
|
||||||
self.select_position(0, 0, mod_shift);
|
self.select_position(0, 0, mod_shift);
|
||||||
}
|
}
|
||||||
if let Some(offset) = self.select_focus_scroll() {
|
if let Some(offset) = self.select_focus_scroll() {
|
||||||
commands.push(Command::Iced(scrollable::scroll_to(
|
commands.push(Command::Iced(
|
||||||
self.scrollable_id.clone(),
|
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||||
offset,
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
if let Some(id) = self.select_focus_id() {
|
if let Some(id) = self.select_focus_id() {
|
||||||
commands.push(Command::Iced(widget::button::focus(id)));
|
commands.push(Command::Iced(widget::button::focus(id).into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2396,13 +2410,12 @@ impl Tab {
|
||||||
self.select_position(0, 0, mod_shift);
|
self.select_position(0, 0, mod_shift);
|
||||||
}
|
}
|
||||||
if let Some(offset) = self.select_focus_scroll() {
|
if let Some(offset) = self.select_focus_scroll() {
|
||||||
commands.push(Command::Iced(scrollable::scroll_to(
|
commands.push(Command::Iced(
|
||||||
self.scrollable_id.clone(),
|
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||||
offset,
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
if let Some(id) = self.select_focus_id() {
|
if let Some(id) = self.select_focus_id() {
|
||||||
commands.push(Command::Iced(widget::button::focus(id)));
|
commands.push(Command::Iced(widget::button::focus(id).into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2433,13 +2446,12 @@ impl Tab {
|
||||||
self.select_position(0, 0, mod_shift);
|
self.select_position(0, 0, mod_shift);
|
||||||
}
|
}
|
||||||
if let Some(offset) = self.select_focus_scroll() {
|
if let Some(offset) = self.select_focus_scroll() {
|
||||||
commands.push(Command::Iced(scrollable::scroll_to(
|
commands.push(Command::Iced(
|
||||||
self.scrollable_id.clone(),
|
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||||
offset,
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
if let Some(id) = self.select_focus_id() {
|
if let Some(id) = self.select_focus_id() {
|
||||||
commands.push(Command::Iced(widget::button::focus(id)));
|
commands.push(Command::Iced(widget::button::focus(id).into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2472,13 +2484,12 @@ impl Tab {
|
||||||
self.select_position(0, 0, mod_shift);
|
self.select_position(0, 0, mod_shift);
|
||||||
}
|
}
|
||||||
if let Some(offset) = self.select_focus_scroll() {
|
if let Some(offset) = self.select_focus_scroll() {
|
||||||
commands.push(Command::Iced(scrollable::scroll_to(
|
commands.push(Command::Iced(
|
||||||
self.scrollable_id.clone(),
|
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||||
offset,
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
if let Some(id) = self.select_focus_id() {
|
if let Some(id) = self.select_focus_id() {
|
||||||
commands.push(Command::Iced(widget::button::focus(id)));
|
commands.push(Command::Iced(widget::button::focus(id).into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2587,10 +2598,9 @@ impl Tab {
|
||||||
}
|
}
|
||||||
Message::ScrollToFocus => {
|
Message::ScrollToFocus => {
|
||||||
if let Some(offset) = self.select_focus_scroll() {
|
if let Some(offset) = self.select_focus_scroll() {
|
||||||
commands.push(Command::Iced(scrollable::scroll_to(
|
commands.push(Command::Iced(
|
||||||
self.scrollable_id.clone(),
|
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||||
offset,
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SearchContext(location, context) => {
|
Message::SearchContext(location, context) => {
|
||||||
|
|
@ -2653,7 +2663,9 @@ impl Tab {
|
||||||
self.select_all();
|
self.select_all();
|
||||||
if self.select_focus.take().is_some() {
|
if self.select_focus.take().is_some() {
|
||||||
// Unfocus currently focused button
|
// Unfocus currently focused button
|
||||||
commands.push(Command::Iced(widget::button::focus(widget::Id::unique())));
|
commands.push(Command::Iced(
|
||||||
|
widget::button::focus(widget::Id::unique()).into(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SetSort(heading_option, dir) => {
|
Message::SetSort(heading_option, dir) => {
|
||||||
|
|
@ -2756,13 +2768,16 @@ impl Tab {
|
||||||
Message::DndEnter(loc) => {
|
Message::DndEnter(loc) => {
|
||||||
self.dnd_hovered = Some((loc.clone(), Instant::now()));
|
self.dnd_hovered = Some((loc.clone(), Instant::now()));
|
||||||
if loc != self.location {
|
if loc != self.location {
|
||||||
commands.push(Command::Iced(cosmic::Command::perform(
|
commands.push(Command::Iced(
|
||||||
async move {
|
cosmic::Task::perform(
|
||||||
tokio::time::sleep(HOVER_DURATION).await;
|
async move {
|
||||||
Message::DndHover(loc)
|
tokio::time::sleep(HOVER_DURATION).await;
|
||||||
},
|
Message::DndHover(loc)
|
||||||
|x| x,
|
},
|
||||||
)));
|
|x| x,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::DndLeave(loc) => {
|
Message::DndLeave(loc) => {
|
||||||
|
|
@ -2788,10 +2803,9 @@ impl Tab {
|
||||||
if self.scroll_opt.is_none() {
|
if self.scroll_opt.is_none() {
|
||||||
let offset = AbsoluteOffset { x: 0.0, y: 0.0 };
|
let offset = AbsoluteOffset { x: 0.0, y: 0.0 };
|
||||||
self.scroll_opt = Some(offset);
|
self.scroll_opt = Some(offset);
|
||||||
commands.push(Command::Iced(scrollable::scroll_to(
|
commands.push(Command::Iced(
|
||||||
self.scrollable_id.clone(),
|
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||||
offset,
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change directory if requested
|
// Change directory if requested
|
||||||
|
|
@ -2940,7 +2954,7 @@ impl Tab {
|
||||||
let location2 = location.clone();
|
let location2 = location.clone();
|
||||||
let location3 = location.clone();
|
let location3 = location.clone();
|
||||||
let is_dnd_hovered = self.dnd_hovered.as_ref().map(|(l, _)| l) == Some(&location);
|
let is_dnd_hovered = self.dnd_hovered.as_ref().map(|(l, _)| l) == Some(&location);
|
||||||
widget::container(
|
let mut container = widget::container(
|
||||||
DndDestination::for_data::<ClipboardPaste>(element, move |data, action| {
|
DndDestination::for_data::<ClipboardPaste>(element, move |data, action| {
|
||||||
if let Some(mut data) = data {
|
if let Some(mut data) = data {
|
||||||
if action == DndAction::Copy {
|
if action == DndAction::Copy {
|
||||||
|
|
@ -2958,13 +2972,10 @@ impl Tab {
|
||||||
})
|
})
|
||||||
.on_enter(move |_, _, _| Message::DndEnter(location2.clone()))
|
.on_enter(move |_, _, _| Message::DndEnter(location2.clone()))
|
||||||
.on_leave(move || Message::DndLeave(location3.clone())),
|
.on_leave(move || Message::DndLeave(location3.clone())),
|
||||||
)
|
);
|
||||||
.style(if is_dnd_hovered {
|
if is_dnd_hovered {
|
||||||
theme::Container::custom(|t| {
|
container = container.style(|t| {
|
||||||
let mut a = cosmic::iced_style::container::StyleSheet::appearance(
|
let mut a = widget::container::Style::default();
|
||||||
t,
|
|
||||||
&theme::Container::default(),
|
|
||||||
);
|
|
||||||
let t = t.cosmic();
|
let t = t.cosmic();
|
||||||
// todo use theme drop target color
|
// todo use theme drop target color
|
||||||
let mut bg = t.accent_color();
|
let mut bg = t.accent_color();
|
||||||
|
|
@ -2976,11 +2987,9 @@ impl Tab {
|
||||||
radius: t.radius_s().into(),
|
radius: t.radius_s().into(),
|
||||||
};
|
};
|
||||||
a
|
a
|
||||||
})
|
});
|
||||||
} else {
|
}
|
||||||
theme::Container::default()
|
container.into()
|
||||||
})
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gallery_view(&self) -> Element<Message> {
|
pub fn gallery_view(&self) -> Element<Message> {
|
||||||
|
|
@ -3007,19 +3016,27 @@ impl Tab {
|
||||||
ItemThumbnail::Image(handle, _) => {
|
ItemThumbnail::Image(handle, _) => {
|
||||||
if let Some(path) = item.path_opt() {
|
if let Some(path) = item.path_opt() {
|
||||||
element_opt = Some(
|
element_opt = Some(
|
||||||
//TODO: use widget::image::viewer, when its zoom can be reset
|
widget::container(
|
||||||
widget::image(widget::image::Handle::from_path(path))
|
//TODO: use widget::image::viewer, when its zoom can be reset
|
||||||
.width(Length::Fill)
|
widget::image(widget::image::Handle::from_path(path)),
|
||||||
.height(Length::Fill)
|
)
|
||||||
.into(),
|
.align_x(Alignment::Center)
|
||||||
|
.align_y(Alignment::Center)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.into(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
element_opt = Some(
|
element_opt = Some(
|
||||||
//TODO: use widget::image::viewer, when its zoom can be reset
|
widget::container(
|
||||||
widget::image(handle.clone())
|
//TODO: use widget::image::viewer, when its zoom can be reset
|
||||||
.width(Length::Fill)
|
widget::image(handle.clone()),
|
||||||
.height(Length::Fill)
|
)
|
||||||
.into(),
|
.align_x(Alignment::Center)
|
||||||
|
.align_y(Alignment::Center)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3040,20 +3057,20 @@ impl Tab {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut column = widget::column::with_capacity(2);
|
let mut column = widget::column::with_capacity(2);
|
||||||
column = column.push(widget::vertical_space(Length::Fixed(space_m.into())));
|
column = column.push(widget::Space::with_height(Length::Fixed(space_m.into())));
|
||||||
{
|
{
|
||||||
let mut row = widget::row::with_capacity(5).align_items(Alignment::Center);
|
let mut row = widget::row::with_capacity(5).align_y(Alignment::Center);
|
||||||
row = row.push(widget::horizontal_space(Length::Fill));
|
row = row.push(widget::horizontal_space());
|
||||||
if let Some(name) = name_opt {
|
if let Some(name) = name_opt {
|
||||||
row = row.push(name);
|
row = row.push(name);
|
||||||
}
|
}
|
||||||
row = row.push(widget::horizontal_space(Length::Fill));
|
row = row.push(widget::horizontal_space());
|
||||||
row = row.push(
|
row = row.push(
|
||||||
widget::button::icon(widget::icon::from_name("window-close-symbolic"))
|
widget::button::icon(widget::icon::from_name("window-close-symbolic"))
|
||||||
.style(theme::Button::Standard)
|
.class(theme::Button::Standard)
|
||||||
.on_press(Message::Gallery(false)),
|
.on_press(Message::Gallery(false)),
|
||||||
);
|
);
|
||||||
row = row.push(widget::horizontal_space(Length::Fixed(space_m.into())));
|
row = row.push(widget::Space::with_width(Length::Fixed(space_m.into())));
|
||||||
// This mouse area provides window drag while the header bar is hidden
|
// This mouse area provides window drag while the header bar is hidden
|
||||||
let mouse_area = mouse_area::MouseArea::new(row)
|
let mouse_area = mouse_area::MouseArea::new(row)
|
||||||
.on_drag(|_| Message::WindowDrag)
|
.on_drag(|_| Message::WindowDrag)
|
||||||
|
|
@ -3061,44 +3078,44 @@ impl Tab {
|
||||||
column = column.push(mouse_area);
|
column = column.push(mouse_area);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut row = widget::row::with_capacity(7).align_items(Alignment::Center);
|
let mut row = widget::row::with_capacity(7).align_y(Alignment::Center);
|
||||||
row = row.push(widget::horizontal_space(Length::Fixed(space_m.into())));
|
row = row.push(widget::Space::with_width(Length::Fixed(space_m.into())));
|
||||||
row = row.push(
|
row = row.push(
|
||||||
widget::button::icon(widget::icon::from_name("go-previous-symbolic"))
|
widget::button::icon(widget::icon::from_name("go-previous-symbolic"))
|
||||||
.padding(space_xs)
|
.padding(space_xs)
|
||||||
.style(theme::Button::Standard)
|
.class(theme::Button::Standard)
|
||||||
.on_press(Message::GalleryPrevious),
|
.on_press(Message::GalleryPrevious),
|
||||||
);
|
);
|
||||||
row = row.push(widget::horizontal_space(Length::Fixed(space_xxs.into())));
|
row = row.push(widget::Space::with_width(Length::Fixed(space_xxs.into())));
|
||||||
if let Some(element) = element_opt {
|
if let Some(element) = element_opt {
|
||||||
row = row.push(element);
|
row = row.push(element);
|
||||||
} else {
|
} else {
|
||||||
//TODO: what to do when no image?
|
//TODO: what to do when no image?
|
||||||
row = row.push(widget::Space::new(Length::Fill, Length::Fill));
|
row = row.push(widget::Space::new(Length::Fill, Length::Fill));
|
||||||
}
|
}
|
||||||
row = row.push(widget::horizontal_space(Length::Fixed(space_xxs.into())));
|
row = row.push(widget::Space::with_width(Length::Fixed(space_xxs.into())));
|
||||||
row = row.push(
|
row = row.push(
|
||||||
widget::button::icon(widget::icon::from_name("go-next-symbolic"))
|
widget::button::icon(widget::icon::from_name("go-next-symbolic"))
|
||||||
.padding(space_xs)
|
.padding(space_xs)
|
||||||
.style(theme::Button::Standard)
|
.class(theme::Button::Standard)
|
||||||
.on_press(Message::GalleryNext),
|
.on_press(Message::GalleryNext),
|
||||||
);
|
);
|
||||||
row = row.push(widget::horizontal_space(Length::Fixed(space_m.into())));
|
row = row.push(widget::Space::with_width(Length::Fixed(space_m.into())));
|
||||||
column = column.push(row);
|
column = column.push(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
widget::container(column)
|
widget::container(column)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.height(Length::Fill)
|
.height(Length::Fill)
|
||||||
.style(theme::Container::Custom(Box::new(|theme| {
|
.style(|theme| {
|
||||||
let cosmic = theme.cosmic();
|
let cosmic = theme.cosmic();
|
||||||
let mut bg = cosmic.bg_color();
|
let mut bg = cosmic.bg_color();
|
||||||
bg.alpha = 0.75;
|
bg.alpha = 0.75;
|
||||||
widget::container::Appearance {
|
widget::container::Style {
|
||||||
background: Some(Color::from(bg).into()),
|
background: Some(Color::from(bg).into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
})))
|
})
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3110,7 +3127,7 @@ impl Tab {
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
line_height: f32,
|
line_height: f32,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
let text: text::Text<'a, font::Font> = text::Text {
|
let text: text::Text<&'a str, font::Font> = text::Text {
|
||||||
content,
|
content,
|
||||||
bounds: Size::INFINITY,
|
bounds: Size::INFINITY,
|
||||||
size: font_size.into(),
|
size: font_size.into(),
|
||||||
|
|
@ -3119,7 +3136,7 @@ impl Tab {
|
||||||
horizontal_alignment: Horizontal::Left,
|
horizontal_alignment: Horizontal::Left,
|
||||||
vertical_alignment: Vertical::Top,
|
vertical_alignment: Vertical::Top,
|
||||||
shaping: text::Shaping::default(),
|
shaping: text::Shaping::default(),
|
||||||
wrap: text::Wrap::None,
|
wrapping: text::Wrapping::None,
|
||||||
};
|
};
|
||||||
graphics::text::Paragraph::with_text(text)
|
graphics::text::Paragraph::with_text(text)
|
||||||
.min_bounds()
|
.min_bounds()
|
||||||
|
|
@ -3144,14 +3161,14 @@ impl Tab {
|
||||||
let size = self.size_opt.get().unwrap_or(Size::new(0.0, 0.0));
|
let size = self.size_opt.get().unwrap_or(Size::new(0.0, 0.0));
|
||||||
|
|
||||||
let mut row = widget::row::with_capacity(5)
|
let mut row = widget::row::with_capacity(5)
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.padding([space_xxxs, 0]);
|
.padding([space_xxxs, 0]);
|
||||||
let mut w = 0.0;
|
let mut w = 0.0;
|
||||||
|
|
||||||
let mut prev_button =
|
let mut prev_button =
|
||||||
widget::button::custom(widget::icon::from_name("go-previous-symbolic").size(16))
|
widget::button::custom(widget::icon::from_name("go-previous-symbolic").size(16))
|
||||||
.padding(space_xxs)
|
.padding(space_xxs)
|
||||||
.style(theme::Button::Icon);
|
.class(theme::Button::Icon);
|
||||||
if self.history_i > 0 && !self.history.is_empty() {
|
if self.history_i > 0 && !self.history.is_empty() {
|
||||||
prev_button = prev_button.on_press(Message::GoPrevious);
|
prev_button = prev_button.on_press(Message::GoPrevious);
|
||||||
}
|
}
|
||||||
|
|
@ -3161,14 +3178,14 @@ impl Tab {
|
||||||
let mut next_button =
|
let mut next_button =
|
||||||
widget::button::custom(widget::icon::from_name("go-next-symbolic").size(16))
|
widget::button::custom(widget::icon::from_name("go-next-symbolic").size(16))
|
||||||
.padding(space_xxs)
|
.padding(space_xxs)
|
||||||
.style(theme::Button::Icon);
|
.class(theme::Button::Icon);
|
||||||
if self.history_i + 1 < self.history.len() {
|
if self.history_i + 1 < self.history.len() {
|
||||||
next_button = next_button.on_press(Message::GoNext);
|
next_button = next_button.on_press(Message::GoNext);
|
||||||
}
|
}
|
||||||
row = row.push(next_button);
|
row = row.push(next_button);
|
||||||
w += 16.0 + 2.0 * space_xxs as f32;
|
w += 16.0 + 2.0 * space_xxs as f32;
|
||||||
|
|
||||||
row = row.push(widget::horizontal_space(Length::Fixed(space_s.into())));
|
row = row.push(widget::Space::with_width(Length::Fixed(space_s.into())));
|
||||||
w += space_s as f32;
|
w += space_s as f32;
|
||||||
|
|
||||||
//TODO: allow resizing?
|
//TODO: allow resizing?
|
||||||
|
|
@ -3180,7 +3197,7 @@ impl Tab {
|
||||||
let (sort_name, sort_direction, _) = self.sort_options();
|
let (sort_name, sort_direction, _) = self.sort_options();
|
||||||
let heading_item = |name, width, msg| {
|
let heading_item = |name, width, msg| {
|
||||||
let mut row = widget::row::with_capacity(2)
|
let mut row = widget::row::with_capacity(2)
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
.width(width);
|
.width(width);
|
||||||
row = row.push(widget::text::heading(name));
|
row = row.push(widget::text::heading(name));
|
||||||
|
|
@ -3216,7 +3233,7 @@ impl Tab {
|
||||||
},
|
},
|
||||||
heading_item(fl!("size"), Length::Fixed(size_width), HeadingOptions::Size),
|
heading_item(fl!("size"), Length::Fixed(size_width), HeadingOptions::Size),
|
||||||
])
|
])
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.height(Length::Fixed((space_m + 4).into()))
|
.height(Length::Fixed((space_m + 4).into()))
|
||||||
.padding([0, space_xxs])
|
.padding([0, space_xxs])
|
||||||
.spacing(space_xxs);
|
.spacing(space_xxs);
|
||||||
|
|
@ -3230,7 +3247,7 @@ impl Tab {
|
||||||
)
|
)
|
||||||
.on_press(Message::EditLocation(None))
|
.on_press(Message::EditLocation(None))
|
||||||
.padding(space_xxs)
|
.padding(space_xxs)
|
||||||
.style(theme::Button::Icon),
|
.class(theme::Button::Icon),
|
||||||
);
|
);
|
||||||
row = row.push(
|
row = row.push(
|
||||||
widget::text_input("", path.to_string_lossy())
|
widget::text_input("", path.to_string_lossy())
|
||||||
|
|
@ -3243,8 +3260,8 @@ impl Tab {
|
||||||
);
|
);
|
||||||
let mut column = widget::column::with_capacity(4).padding([0, space_s]);
|
let mut column = widget::column::with_capacity(4).padding([0, space_s]);
|
||||||
column = column.push(row);
|
column = column.push(row);
|
||||||
column = column.push(horizontal_rule(1).style(theme::Rule::Custom(Box::new(
|
column = column.push(horizontal_rule(1).class(theme::Rule::Custom(Box::new(
|
||||||
|theme: &Theme| rule::Appearance {
|
|theme| rule::Style {
|
||||||
color: theme.cosmic().accent_color().into(),
|
color: theme.cosmic().accent_color().into(),
|
||||||
width: 1,
|
width: 1,
|
||||||
radius: 0.0.into(),
|
radius: 0.0.into(),
|
||||||
|
|
@ -3262,7 +3279,7 @@ impl Tab {
|
||||||
crate::mouse_area::MouseArea::new(
|
crate::mouse_area::MouseArea::new(
|
||||||
widget::button::custom(widget::icon::from_name("edit-symbolic").size(16))
|
widget::button::custom(widget::icon::from_name("edit-symbolic").size(16))
|
||||||
.padding(space_xxs)
|
.padding(space_xxs)
|
||||||
.style(theme::Button::Icon)
|
.class(theme::Button::Icon)
|
||||||
.on_press(Message::EditLocation(Some(self.location.clone()))),
|
.on_press(Message::EditLocation(Some(self.location.clone()))),
|
||||||
)
|
)
|
||||||
.on_middle_press(move |_| Message::OpenInNewTab(path.clone())),
|
.on_middle_press(move |_| Message::OpenInNewTab(path.clone())),
|
||||||
|
|
@ -3280,7 +3297,7 @@ impl Tab {
|
||||||
let (name_width, name_text) = if children.is_empty() {
|
let (name_width, name_text) = if children.is_empty() {
|
||||||
(
|
(
|
||||||
text_width_heading(&name),
|
text_width_heading(&name),
|
||||||
widget::text::heading(name).wrap(text::Wrap::None),
|
widget::text::heading(name).wrapping(text::Wrapping::None),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
children.push(
|
children.push(
|
||||||
|
|
@ -3292,7 +3309,7 @@ impl Tab {
|
||||||
w += 16.0;
|
w += 16.0;
|
||||||
(
|
(
|
||||||
text_width_body(&name),
|
text_width_body(&name),
|
||||||
widget::text::body(name).wrap(text::Wrap::None),
|
widget::text::body(name).wrapping(text::Wrapping::None),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -3300,7 +3317,7 @@ impl Tab {
|
||||||
w += 2.0 * space_xxxs as f32;
|
w += 2.0 * space_xxxs as f32;
|
||||||
|
|
||||||
let mut row = widget::row::with_capacity(2)
|
let mut row = widget::row::with_capacity(2)
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxxs);
|
.spacing(space_xxxs);
|
||||||
//TODO: figure out why this hardcoded offset is needed after the first item is ellipsed
|
//TODO: figure out why this hardcoded offset is needed after the first item is ellipsed
|
||||||
let overflow_offset = 64.0;
|
let overflow_offset = 64.0;
|
||||||
|
|
@ -3317,7 +3334,7 @@ impl Tab {
|
||||||
let mut mouse_area = crate::mouse_area::MouseArea::new(
|
let mut mouse_area = crate::mouse_area::MouseArea::new(
|
||||||
widget::button::custom(row)
|
widget::button::custom(row)
|
||||||
.padding(space_xxxs)
|
.padding(space_xxxs)
|
||||||
.style(theme::Button::Link)
|
.class(theme::Button::Link)
|
||||||
.on_press(Message::Location(location.clone())),
|
.on_press(Message::Location(location.clone())),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -3351,7 +3368,7 @@ impl Tab {
|
||||||
widget::button::custom(widget::text::heading(fl!("trash")))
|
widget::button::custom(widget::text::heading(fl!("trash")))
|
||||||
.padding(space_xxxs)
|
.padding(space_xxxs)
|
||||||
.on_press(Message::Location(Location::Trash))
|
.on_press(Message::Location(Location::Trash))
|
||||||
.style(theme::Button::Text)
|
.class(theme::Button::Text)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -3360,7 +3377,7 @@ impl Tab {
|
||||||
widget::button::custom(widget::text::heading(fl!("recents")))
|
widget::button::custom(widget::text::heading(fl!("recents")))
|
||||||
.padding(space_xxxs)
|
.padding(space_xxxs)
|
||||||
.on_press(Message::Location(Location::Recents))
|
.on_press(Message::Location(Location::Recents))
|
||||||
.style(theme::Button::Text)
|
.class(theme::Button::Text)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -3372,7 +3389,7 @@ impl Tab {
|
||||||
uri.clone(),
|
uri.clone(),
|
||||||
display_name.clone(),
|
display_name.clone(),
|
||||||
)))
|
)))
|
||||||
.style(theme::Button::Text)
|
.class(theme::Button::Text)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -3383,14 +3400,14 @@ impl Tab {
|
||||||
}
|
}
|
||||||
let mut column = widget::column::with_capacity(4).padding([0, space_s]);
|
let mut column = widget::column::with_capacity(4).padding([0, space_s]);
|
||||||
column = column.push(row);
|
column = column.push(row);
|
||||||
column = column.push(horizontal_rule(1).style(theme::Rule::Custom(Box::new(
|
column = column.push(
|
||||||
|theme: &Theme| rule::Appearance {
|
horizontal_rule(1).class(theme::Rule::Custom(Box::new(|theme| rule::Style {
|
||||||
color: theme.cosmic().accent_color().into(),
|
color: theme.cosmic().accent_color().into(),
|
||||||
width: 1,
|
width: 1,
|
||||||
radius: 0.0.into(),
|
radius: 0.0.into(),
|
||||||
fill_mode: rule::FillMode::Full,
|
fill_mode: rule::FillMode::Full,
|
||||||
},
|
}))),
|
||||||
))));
|
);
|
||||||
|
|
||||||
if self.config.view == View::List && !condensed {
|
if self.config.view == View::List && !condensed {
|
||||||
column = column.push(heading_row);
|
column = column.push(heading_row);
|
||||||
|
|
@ -3435,7 +3452,7 @@ impl Tab {
|
||||||
],
|
],
|
||||||
Mode::Desktop => Vec::new(),
|
Mode::Desktop => Vec::new(),
|
||||||
})
|
})
|
||||||
.align_items(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
.spacing(space_xxs),
|
.spacing(space_xxs),
|
||||||
)
|
)
|
||||||
.align_x(Horizontal::Center)
|
.align_x(Horizontal::Center)
|
||||||
|
|
@ -3446,13 +3463,7 @@ impl Tab {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grid_view(
|
pub fn grid_view(&self) -> (Option<Element<'static, Message>>, Element<Message>, bool) {
|
||||||
&self,
|
|
||||||
) -> (
|
|
||||||
Option<Element<'static, cosmic::app::Message<crate::app::Message>>>,
|
|
||||||
Element<Message>,
|
|
||||||
bool,
|
|
||||||
) {
|
|
||||||
let cosmic_theme::Spacing {
|
let cosmic_theme::Spacing {
|
||||||
space_m,
|
space_m,
|
||||||
space_xxs,
|
space_xxs,
|
||||||
|
|
@ -3543,26 +3554,26 @@ impl Tab {
|
||||||
.size(icon_sizes.grid()),
|
.size(icon_sizes.grid()),
|
||||||
)
|
)
|
||||||
.padding(space_xxxs)
|
.padding(space_xxxs)
|
||||||
.style(button_style(item.selected, false, false, false))
|
.class(button_style(item.selected, false, false, false))
|
||||||
.into(),
|
.into(),
|
||||||
widget::tooltip(
|
widget::tooltip(
|
||||||
widget::button::custom(widget::text::body(&item.display_name))
|
widget::button::custom(widget::text::body(&item.display_name))
|
||||||
.id(item.button_id.clone())
|
.id(item.button_id.clone())
|
||||||
.padding([0, space_xxxs])
|
.padding([0, space_xxxs])
|
||||||
.style(button_style(
|
.class(button_style(
|
||||||
item.selected,
|
item.selected,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
matches!(self.mode, Mode::Desktop),
|
matches!(self.mode, Mode::Desktop),
|
||||||
)),
|
)),
|
||||||
&item.name,
|
widget::text::body(&item.name),
|
||||||
widget::tooltip::Position::Bottom,
|
widget::tooltip::Position::Bottom,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut column = widget::column::with_capacity(buttons.len())
|
let mut column = widget::column::with_capacity(buttons.len())
|
||||||
.align_items(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
.height(Length::Fixed(item_height as f32))
|
.height(Length::Fixed(item_height as f32))
|
||||||
.width(Length::Fixed(item_width as f32));
|
.width(Length::Fixed(item_width as f32));
|
||||||
for button in buttons {
|
for button in buttons {
|
||||||
|
|
@ -3660,7 +3671,7 @@ impl Tab {
|
||||||
let spacer_height = height.checked_sub(max_bottom + top_deduct).unwrap_or(0);
|
let spacer_height = height.checked_sub(max_bottom + top_deduct).unwrap_or(0);
|
||||||
if spacer_height > 0 {
|
if spacer_height > 0 {
|
||||||
children.push(
|
children.push(
|
||||||
widget::container(vertical_space(Length::Fixed(spacer_height as f32)))
|
widget::container(Space::with_height(Length::Fixed(spacer_height as f32)))
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -3690,7 +3701,7 @@ impl Tab {
|
||||||
)
|
)
|
||||||
.on_press(Message::Click(Some(*i)))
|
.on_press(Message::Click(Some(*i)))
|
||||||
.padding(space_xxxs)
|
.padding(space_xxxs)
|
||||||
.style(button_style(
|
.class(button_style(
|
||||||
item.selected,
|
item.selected,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
@ -3700,11 +3711,11 @@ impl Tab {
|
||||||
.id(item.button_id.clone())
|
.id(item.button_id.clone())
|
||||||
.on_press(Message::Click(Some(*i)))
|
.on_press(Message::Click(Some(*i)))
|
||||||
.padding([0, space_xxxs])
|
.padding([0, space_xxxs])
|
||||||
.style(button_style(item.selected, true, true, false)),
|
.class(button_style(item.selected, true, true, false)),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut column = widget::column::with_capacity(buttons.len())
|
let mut column = widget::column::with_capacity(buttons.len())
|
||||||
.align_items(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
.height(Length::Fixed(item_height as f32))
|
.height(Length::Fixed(item_height as f32))
|
||||||
.width(Length::Fixed(item_width as f32));
|
.width(Length::Fixed(item_width as f32));
|
||||||
for button in buttons {
|
for button in buttons {
|
||||||
|
|
@ -3715,14 +3726,13 @@ impl Tab {
|
||||||
dnd_item_i += 1;
|
dnd_item_i += 1;
|
||||||
} else {
|
} else {
|
||||||
dnd_grid = dnd_grid.push(
|
dnd_grid = dnd_grid.push(
|
||||||
widget::container(vertical_space(item_width as f32))
|
widget::container(Space::with_height(item_width as f32))
|
||||||
.height(Length::Fixed(item_height as f32)),
|
.height(Length::Fixed(item_height as f32)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Element::from(dnd_grid)
|
Element::from(dnd_grid)
|
||||||
.map(|m| cosmic::app::Message::App(crate::app::Message::TabMessage(None, m)))
|
|
||||||
}),
|
}),
|
||||||
mouse_area::MouseArea::new(
|
mouse_area::MouseArea::new(
|
||||||
widget::container(widget::column::with_children(children)).width(Length::Fill),
|
widget::container(widget::column::with_children(children)).width(Length::Fill),
|
||||||
|
|
@ -3737,13 +3747,7 @@ impl Tab {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_view(
|
pub fn list_view(&self) -> (Option<Element<'static, Message>>, Element<Message>, bool) {
|
||||||
&self,
|
|
||||||
) -> (
|
|
||||||
Option<Element<'static, cosmic::app::Message<crate::app::Message>>>,
|
|
||||||
Element<Message>,
|
|
||||||
bool,
|
|
||||||
) {
|
|
||||||
let cosmic_theme::Spacing {
|
let cosmic_theme::Spacing {
|
||||||
space_m,
|
space_m,
|
||||||
space_s,
|
space_s,
|
||||||
|
|
@ -3863,7 +3867,7 @@ impl Tab {
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.height(Length::Fixed(row_height as f32))
|
.height(Length::Fixed(row_height as f32))
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
} else if is_search {
|
} else if is_search {
|
||||||
widget::row::with_children(vec![
|
widget::row::with_children(vec![
|
||||||
|
|
@ -3889,7 +3893,7 @@ impl Tab {
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.height(Length::Fixed(row_height as f32))
|
.height(Length::Fixed(row_height as f32))
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
} else {
|
} else {
|
||||||
widget::row::with_children(vec![
|
widget::row::with_children(vec![
|
||||||
|
|
@ -3908,7 +3912,7 @@ impl Tab {
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.height(Length::Fixed(row_height as f32))
|
.height(Length::Fixed(row_height as f32))
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -3918,7 +3922,7 @@ impl Tab {
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.id(item.button_id.clone())
|
.id(item.button_id.clone())
|
||||||
.padding([0, space_xxs])
|
.padding([0, space_xxs])
|
||||||
.style(button_style(item.selected, true, false, false)),
|
.class(button_style(item.selected, true, false, false)),
|
||||||
)
|
)
|
||||||
.on_press(move |_| Message::Click(Some(i)))
|
.on_press(move |_| Message::Click(Some(i)))
|
||||||
.on_double_click(move |_| Message::DoubleClick(Some(i)))
|
.on_double_click(move |_| Message::DoubleClick(Some(i)))
|
||||||
|
|
@ -3944,7 +3948,7 @@ impl Tab {
|
||||||
|
|
||||||
if item.selected || !drag_items.is_empty() {
|
if item.selected || !drag_items.is_empty() {
|
||||||
let dnd_row = if !item.selected {
|
let dnd_row = if !item.selected {
|
||||||
Element::from(vertical_space(Length::Fixed(row_height as f32)))
|
Element::from(Space::with_height(Length::Fixed(row_height as f32)))
|
||||||
} else if condensed {
|
} else if condensed {
|
||||||
widget::row::with_children(vec![
|
widget::row::with_children(vec![
|
||||||
widget::icon::icon(item.icon_handle_list_condensed.clone())
|
widget::icon::icon(item.icon_handle_list_condensed.clone())
|
||||||
|
|
@ -3958,7 +3962,7 @@ impl Tab {
|
||||||
])
|
])
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
.into()
|
.into()
|
||||||
} else if is_search {
|
} else if is_search {
|
||||||
|
|
@ -3984,7 +3988,7 @@ impl Tab {
|
||||||
.width(Length::Fixed(size_width))
|
.width(Length::Fixed(size_width))
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -4003,7 +4007,7 @@ impl Tab {
|
||||||
.width(Length::Fixed(size_width))
|
.width(Length::Fixed(size_width))
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.align_items(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
.into()
|
.into()
|
||||||
};
|
};
|
||||||
|
|
@ -4039,14 +4043,13 @@ impl Tab {
|
||||||
|
|
||||||
let spacer_height = size.height - y as f32 - top_deduct as f32;
|
let spacer_height = size.height - y as f32 - top_deduct as f32;
|
||||||
if spacer_height > 0. {
|
if spacer_height > 0. {
|
||||||
children
|
children.push(
|
||||||
.push(widget::container(vertical_space(Length::Fixed(spacer_height))).into());
|
widget::container(Space::with_height(Length::Fixed(spacer_height))).into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let drag_col = (!drag_items.is_empty()).then(|| {
|
let drag_col = (!drag_items.is_empty())
|
||||||
Element::from(widget::column::with_children(drag_items))
|
.then(|| Element::from(widget::column::with_children(drag_items)));
|
||||||
.map(|m| cosmic::app::Message::App(crate::app::Message::TabMessage(None, m)))
|
|
||||||
});
|
|
||||||
|
|
||||||
(
|
(
|
||||||
drag_col,
|
drag_col,
|
||||||
|
|
@ -4099,22 +4102,19 @@ impl Tab {
|
||||||
.collect::<Vec<PathBuf>>()
|
.collect::<Vec<PathBuf>>()
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let item_view = DndSource::<_, cosmic::app::Message<app::Message>, ClipboardCopy>::with_id(
|
let item_view =
|
||||||
item_view,
|
DndSource::<Message, ClipboardCopy>::with_id(item_view, Id::new("tab-view"));
|
||||||
Id::new("tab-view"),
|
|
||||||
);
|
|
||||||
|
|
||||||
let item_view = match drag_list {
|
let item_view = match drag_list {
|
||||||
Some(drag_list) if self.selected_clicked => {
|
Some(drag_list) if self.selected_clicked => {
|
||||||
let drag_list = ArcElementWrapper(Arc::new(Mutex::new(drag_list)));
|
let drag_list = ArcElementWrapper::<Message>(Arc::new(Mutex::new(drag_list)));
|
||||||
item_view
|
item_view
|
||||||
.drag_content(move || {
|
.drag_content(move || {
|
||||||
ClipboardCopy::new(crate::clipboard::ClipboardKind::Copy, &files)
|
ClipboardCopy::new(crate::clipboard::ClipboardKind::Copy, &files)
|
||||||
})
|
})
|
||||||
.drag_icon(move || {
|
.drag_icon(move || {
|
||||||
let state: tree::State =
|
let state: tree::State = Widget::<Message, _, _>::state(&drag_list);
|
||||||
Widget::<cosmic::app::Message<app::Message>, _, _>::state(&drag_list);
|
(Element::from(drag_list.clone()).map(|_m| ()), state)
|
||||||
(drag_list.clone().into(), state)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => item_view,
|
_ => item_view,
|
||||||
|
|
@ -4164,7 +4164,7 @@ impl Tab {
|
||||||
if !items.is_empty() {
|
if !items.is_empty() {
|
||||||
tab_column = tab_column.push(
|
tab_column = tab_column.push(
|
||||||
widget::layer_container(widget::row::with_children(vec![
|
widget::layer_container(widget::row::with_children(vec![
|
||||||
widget::horizontal_space(Length::Fill).into(),
|
widget::horizontal_space().into(),
|
||||||
widget::button::standard(fl!("empty-trash"))
|
widget::button::standard(fl!("empty-trash"))
|
||||||
.on_press(Message::EmptyTrash)
|
.on_press(Message::EmptyTrash)
|
||||||
.into(),
|
.into(),
|
||||||
|
|
@ -4178,7 +4178,7 @@ impl Tab {
|
||||||
Location::Network(uri, _display_name) if uri == "network:///" => {
|
Location::Network(uri, _display_name) if uri == "network:///" => {
|
||||||
tab_column = tab_column.push(
|
tab_column = tab_column.push(
|
||||||
widget::layer_container(widget::row::with_children(vec![
|
widget::layer_container(widget::row::with_children(vec![
|
||||||
widget::horizontal_space(Length::Fill).into(),
|
widget::horizontal_space().into(),
|
||||||
widget::button::standard(fl!("add-network-drive"))
|
widget::button::standard(fl!("add-network-drive"))
|
||||||
.on_press(Message::AddNetworkDrive)
|
.on_press(Message::AddNetworkDrive)
|
||||||
.into(),
|
.into(),
|
||||||
|
|
@ -4194,11 +4194,8 @@ impl Tab {
|
||||||
.width(Length::Fill);
|
.width(Length::Fill);
|
||||||
|
|
||||||
if self.dnd_hovered.as_ref().map(|(l, _)| l) == Some(&tab_location) {
|
if self.dnd_hovered.as_ref().map(|(l, _)| l) == Some(&tab_location) {
|
||||||
tab_view = tab_view.style(cosmic::theme::Container::custom(|t| {
|
tab_view = tab_view.style(|t| {
|
||||||
let mut a = cosmic::iced_style::container::StyleSheet::appearance(
|
let mut a = widget::container::Style::default();
|
||||||
t,
|
|
||||||
&cosmic::theme::Container::default(),
|
|
||||||
);
|
|
||||||
let c = t.cosmic();
|
let c = t.cosmic();
|
||||||
a.border = cosmic::iced_core::Border {
|
a.border = cosmic::iced_core::Border {
|
||||||
color: (c.accent_color()).into(),
|
color: (c.accent_color()).into(),
|
||||||
|
|
@ -4206,7 +4203,7 @@ impl Tab {
|
||||||
radius: c.radius_0().into(),
|
radius: c.radius_0().into(),
|
||||||
};
|
};
|
||||||
a
|
a
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let tab_location_2 = self.location.clone();
|
let tab_location_2 = self.location.clone();
|
||||||
|
|
@ -4287,10 +4284,9 @@ impl Tab {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let mime = item.mime.clone();
|
let mime = item.mime.clone();
|
||||||
subscriptions.push(subscription::channel(
|
subscriptions.push(Subscription::run_with_id(
|
||||||
path.clone(),
|
path.clone(),
|
||||||
1,
|
stream::channel(1, |mut output| async move {
|
||||||
|mut output| async move {
|
|
||||||
let message = {
|
let message = {
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
|
@ -4312,7 +4308,7 @@ impl Tab {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future::pending().await
|
std::future::pending().await
|
||||||
},
|
}),
|
||||||
));
|
));
|
||||||
|
|
||||||
if subscriptions.len() >= jobs {
|
if subscriptions.len() >= jobs {
|
||||||
|
|
@ -4327,10 +4323,9 @@ impl Tab {
|
||||||
let term = term.clone();
|
let term = term.clone();
|
||||||
let show_hidden = *show_hidden;
|
let show_hidden = *show_hidden;
|
||||||
let start = start.clone();
|
let start = start.clone();
|
||||||
subscriptions.push(subscription::channel(
|
subscriptions.push(Subscription::run_with_id(
|
||||||
location.clone(),
|
location.clone(),
|
||||||
2,
|
stream::channel(2, move |mut output| async move {
|
||||||
move |mut output| async move {
|
|
||||||
//TODO: optimal size?
|
//TODO: optimal size?
|
||||||
let (results_tx, results_rx) = mpsc::channel(65536);
|
let (results_tx, results_rx) = mpsc::channel(65536);
|
||||||
|
|
||||||
|
|
@ -4408,7 +4403,7 @@ impl Tab {
|
||||||
let _ = output.lock().await.send(Message::SearchReady(true)).await;
|
let _ = output.lock().await.send(Message::SearchReady(true)).await;
|
||||||
|
|
||||||
std::future::pending().await
|
std::future::pending().await
|
||||||
},
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4846,7 +4841,7 @@ impl<M> Widget<M, cosmic::Theme, cosmic::Renderer> for ArcElementWrapper<M> {
|
||||||
state: &mut tree::Tree,
|
state: &mut tree::Tree,
|
||||||
layout: cosmic::iced_core::Layout<'_>,
|
layout: cosmic::iced_core::Layout<'_>,
|
||||||
renderer: &cosmic::Renderer,
|
renderer: &cosmic::Renderer,
|
||||||
operation: &mut dyn widget::Operation<cosmic::iced_core::widget::OperationOutputWrapper<M>>,
|
operation: &mut dyn widget::Operation,
|
||||||
) {
|
) {
|
||||||
self.0
|
self.0
|
||||||
.lock()
|
.lock()
|
||||||
|
|
@ -4891,6 +4886,7 @@ impl<M> Widget<M, cosmic::Theme, cosmic::Renderer> for ArcElementWrapper<M> {
|
||||||
_state: &'a mut tree::Tree,
|
_state: &'a mut tree::Tree,
|
||||||
_layout: cosmic::iced_core::Layout<'_>,
|
_layout: cosmic::iced_core::Layout<'_>,
|
||||||
_renderer: &cosmic::Renderer,
|
_renderer: &cosmic::Renderer,
|
||||||
|
_translation: cosmic::iced_core::Vector,
|
||||||
) -> Option<cosmic::iced_core::overlay::Element<'a, M, cosmic::Theme, cosmic::Renderer>> {
|
) -> Option<cosmic::iced_core::overlay::Element<'a, M, cosmic::Theme, cosmic::Renderer>> {
|
||||||
// TODO
|
// TODO
|
||||||
None
|
None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue