Merge branch 'master' of https://github.com/pop-os/cosmic-files
This commit is contained in:
commit
1467351211
14 changed files with 148 additions and 144 deletions
|
|
@ -2,7 +2,7 @@ use cosmic_files::operation::{recursive::Context, Controller, ReplaceResult};
|
||||||
use std::{error::Error, io, path::PathBuf};
|
use std::{error::Error, io, path::PathBuf};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let mut context = Context::new(Controller::new())
|
let mut context = Context::new(Controller::default())
|
||||||
.on_progress(|op, progress| {
|
.on_progress(|op, progress| {
|
||||||
println!("{:?}: {:?}", op.to, progress);
|
println!("{:?}: {:?}", op.to, progress);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -798,7 +798,7 @@ impl App {
|
||||||
self.progress_operations.insert(id);
|
self.progress_operations.insert(id);
|
||||||
}
|
}
|
||||||
self.pending_operations
|
self.pending_operations
|
||||||
.insert(id, (operation, Controller::new()));
|
.insert(id, (operation, Controller::default()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_window(&mut self, id: &window::Id) {
|
fn remove_window(&mut self, id: &window::Id) {
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ impl Favorite {
|
||||||
Self::Videos,
|
Self::Videos,
|
||||||
] {
|
] {
|
||||||
if let Some(favorite_path) = favorite.path_opt() {
|
if let Some(favorite_path) = favorite.path_opt() {
|
||||||
if &favorite_path == &path {
|
if favorite_path == path {
|
||||||
return favorite.clone();
|
return favorite.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,13 +157,15 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
|
|
||||||
let (config_handler, config) = Config::load();
|
let (config_handler, config) = Config::load();
|
||||||
|
|
||||||
let mut settings = window::Settings::default();
|
let mut settings = window::Settings {
|
||||||
settings.decorations = false;
|
decorations: false,
|
||||||
settings.exit_on_close_request = false;
|
exit_on_close_request: false,
|
||||||
settings.min_size = Some(Size::new(360.0, 180.0));
|
min_size: Some(Size::new(360.0, 180.0)),
|
||||||
settings.resizable = true;
|
resizable: true,
|
||||||
settings.size = Size::new(1024.0, 640.0);
|
size: Size::new(1024.0, 640.0),
|
||||||
settings.transparent = true;
|
transparent: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
|
|
@ -296,6 +298,7 @@ struct Flags {
|
||||||
kind: DialogKind,
|
kind: DialogKind,
|
||||||
path_opt: Option<PathBuf>,
|
path_opt: Option<PathBuf>,
|
||||||
window_id: window::Id,
|
window_id: window::Id,
|
||||||
|
#[expect(dead_code)]
|
||||||
config_handler: Option<cosmic_config::Config>,
|
config_handler: Option<cosmic_config::Config>,
|
||||||
config: Config,
|
config: Config,
|
||||||
}
|
}
|
||||||
|
|
@ -324,6 +327,7 @@ enum Message {
|
||||||
SearchActivate,
|
SearchActivate,
|
||||||
SearchClear,
|
SearchClear,
|
||||||
SearchInput(String),
|
SearchInput(String),
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
TabMessage(tab::Message),
|
TabMessage(tab::Message),
|
||||||
TabRescan(Location, Option<tab::Item>, Vec<tab::Item>),
|
TabRescan(Location, Option<tab::Item>, Vec<tab::Item>),
|
||||||
TabView(tab::View),
|
TabView(tab::View),
|
||||||
|
|
@ -598,7 +602,7 @@ impl App {
|
||||||
.data(Location::Recents)
|
.data(Location::Recents)
|
||||||
});
|
});
|
||||||
|
|
||||||
for (_favorite_i, favorite) in self.flags.config.favorites.iter().enumerate() {
|
for favorite in self.flags.config.favorites.iter() {
|
||||||
if let Some(path) = favorite.path_opt() {
|
if let Some(path) = favorite.path_opt() {
|
||||||
let name = if matches!(favorite, Favorite::Home) {
|
let name = if matches!(favorite, Favorite::Home) {
|
||||||
fl!("home")
|
fl!("home")
|
||||||
|
|
@ -974,11 +978,8 @@ impl Application for App {
|
||||||
ContextPage::Preview(..) => self.core.window.show_context,
|
ContextPage::Preview(..) => self.core.window.show_context,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
elements.push(
|
elements
|
||||||
menu::dialog_menu(&self.tab, &self.key_binds, show_details)
|
.push(menu::dialog_menu(&self.tab, &self.key_binds, show_details).map(Message::from));
|
||||||
.map(Message::from)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
|
|
||||||
elements
|
elements
|
||||||
}
|
}
|
||||||
|
|
@ -1027,7 +1028,7 @@ impl Application for App {
|
||||||
return self.update(message);
|
return self.update(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(data) = self.nav_model.data::<MounterData>(entity).clone() {
|
if let Some(data) = self.nav_model.data::<MounterData>(entity) {
|
||||||
if let Some(mounter) = MOUNTERS.get(&data.0) {
|
if let Some(mounter) = MOUNTERS.get(&data.0) {
|
||||||
return mounter.mount(data.1.clone()).map(|_| message::none());
|
return mounter.mount(data.1.clone()).map(|_| message::none());
|
||||||
}
|
}
|
||||||
|
|
@ -1169,11 +1170,9 @@ impl Application for App {
|
||||||
let mut still_mounted = false;
|
let mut still_mounted = false;
|
||||||
for item in mounter_items.iter() {
|
for item in mounter_items.iter() {
|
||||||
if let Some(path) = item.path() {
|
if let Some(path) = item.path() {
|
||||||
if path == old_path {
|
if path == old_path && item.is_mounted() {
|
||||||
if item.is_mounted() {
|
still_mounted = true;
|
||||||
still_mounted = true;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1221,7 +1220,7 @@ impl Application for App {
|
||||||
let mut contains_change = false;
|
let mut contains_change = false;
|
||||||
for event in events.iter() {
|
for event in events.iter() {
|
||||||
for event_path in event.paths.iter() {
|
for event_path in event.paths.iter() {
|
||||||
if event_path.starts_with(&path) {
|
if event_path.starts_with(path) {
|
||||||
match event.kind {
|
match event.kind {
|
||||||
notify::EventKind::Modify(
|
notify::EventKind::Modify(
|
||||||
notify::event::ModifyKind::Metadata(_),
|
notify::event::ModifyKind::Metadata(_),
|
||||||
|
|
@ -1235,14 +1234,14 @@ impl Application for App {
|
||||||
for item in items.iter_mut() {
|
for item in items.iter_mut() {
|
||||||
if item.path_opt() == Some(event_path) {
|
if item.path_opt() == Some(event_path) {
|
||||||
//TODO: reload more, like mime types?
|
//TODO: reload more, like mime types?
|
||||||
match fs::metadata(&event_path) {
|
match fs::metadata(event_path) {
|
||||||
Ok(new_metadata) => {
|
Ok(new_metadata) => {
|
||||||
match &mut item.metadata {
|
if let ItemMetadata::Path {
|
||||||
ItemMetadata::Path {
|
metadata,
|
||||||
metadata,
|
..
|
||||||
..
|
} = &mut item.metadata
|
||||||
} => *metadata = new_metadata,
|
{
|
||||||
_ => {}
|
*metadata = new_metadata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -1322,12 +1321,9 @@ impl Application for App {
|
||||||
|
|
||||||
// If we are in directory mode, return the current directory
|
// If we are in directory mode, return the current directory
|
||||||
if self.flags.kind.is_dir() {
|
if self.flags.kind.is_dir() {
|
||||||
match &self.tab.location {
|
if let Location::Path(tab_path) = &self.tab.location {
|
||||||
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.flags.window_id);
|
||||||
return window::close(self.flags.window_id);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1344,7 +1340,7 @@ impl Application for App {
|
||||||
if let DialogKind::SaveFile { filename } = &self.flags.kind {
|
if let DialogKind::SaveFile { filename } = &self.flags.kind {
|
||||||
if !filename.is_empty() {
|
if !filename.is_empty() {
|
||||||
if let Some(tab_path) = self.tab.location.path_opt() {
|
if let Some(tab_path) = self.tab.location.path_opt() {
|
||||||
let path = tab_path.join(&filename);
|
let path = tab_path.join(filename);
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
// cd to directory
|
// cd to directory
|
||||||
let message = Message::TabMessage(tab::Message::Location(
|
let message = Message::TabMessage(tab::Message::Location(
|
||||||
|
|
@ -1592,11 +1588,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
col = col.push(
|
col = col.push(self.tab.view(&self.key_binds).map(Message::TabMessage));
|
||||||
self.tab
|
|
||||||
.view(&self.key_binds)
|
|
||||||
.map(move |message| Message::TabMessage(message)),
|
|
||||||
);
|
|
||||||
|
|
||||||
col.into()
|
col.into()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/menu.rs
20
src/menu.rs
|
|
@ -89,7 +89,7 @@ pub fn context_menu<'a>(
|
||||||
let mut selected_trash_only = false;
|
let mut selected_trash_only = false;
|
||||||
let mut selected_desktop_entry = None;
|
let mut selected_desktop_entry = None;
|
||||||
let mut selected_types: Vec<Mime> = vec![];
|
let mut selected_types: Vec<Mime> = vec![];
|
||||||
tab.items_opt().map(|items| {
|
if let Some(items) = tab.items_opt() {
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
if item.selected {
|
if item.selected {
|
||||||
selected += 1;
|
selected += 1;
|
||||||
|
|
@ -110,7 +110,7 @@ pub fn context_menu<'a>(
|
||||||
selected_types.push(item.mime.clone());
|
selected_types.push(item.mime.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
selected_types.sort_unstable();
|
selected_types.sort_unstable();
|
||||||
selected_types.dedup();
|
selected_types.dedup();
|
||||||
selected_trash_only = selected_trash_only && selected == 1;
|
selected_trash_only = selected_trash_only && selected == 1;
|
||||||
|
|
@ -342,7 +342,7 @@ pub fn context_menu<'a>(
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dialog_menu<'a>(
|
pub fn dialog_menu(
|
||||||
tab: &Tab,
|
tab: &Tab,
|
||||||
key_binds: &HashMap<KeyBind, Action>,
|
key_binds: &HashMap<KeyBind, Action>,
|
||||||
show_details: bool,
|
show_details: bool,
|
||||||
|
|
@ -359,15 +359,13 @@ pub fn dialog_menu<'a>(
|
||||||
let in_trash = tab.location == Location::Trash;
|
let in_trash = tab.location == Location::Trash;
|
||||||
|
|
||||||
let mut selected_gallery = 0;
|
let mut selected_gallery = 0;
|
||||||
tab.items_opt().map(|items| {
|
if let Some(items) = tab.items_opt() {
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
if item.selected {
|
if item.selected && item.can_gallery() {
|
||||||
if item.can_gallery() {
|
selected_gallery += 1;
|
||||||
selected_gallery += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
MenuBar::new(vec![
|
MenuBar::new(vec![
|
||||||
menu::Tree::with_children(
|
menu::Tree::with_children(
|
||||||
|
|
@ -504,7 +502,7 @@ pub fn menu_bar<'a>(
|
||||||
let mut selected_dir = 0;
|
let mut selected_dir = 0;
|
||||||
let mut selected = 0;
|
let mut selected = 0;
|
||||||
let mut selected_gallery = 0;
|
let mut selected_gallery = 0;
|
||||||
tab_opt.and_then(|tab| tab.items_opt()).map(|items| {
|
if let Some(items) = tab_opt.and_then(|tab| tab.items_opt()) {
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
if item.selected {
|
if item.selected {
|
||||||
selected += 1;
|
selected += 1;
|
||||||
|
|
@ -516,7 +514,7 @@ pub fn menu_bar<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
MenuBar::new(vec![
|
MenuBar::new(vec![
|
||||||
menu::Tree::with_children(
|
menu::Tree::with_children(
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ impl MimeAppCache {
|
||||||
.cache
|
.cache
|
||||||
.entry(mime.clone())
|
.entry(mime.clone())
|
||||||
.or_insert_with(|| Vec::with_capacity(1));
|
.or_insert_with(|| Vec::with_capacity(1));
|
||||||
if apps.iter().find(|x| x.id == app.id).is_none() {
|
if !apps.iter().any(|x| x.id == app.id) {
|
||||||
apps.push(MimeApp::from(app));
|
apps.push(MimeApp::from(app));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -191,11 +191,7 @@ impl MimeAppCache {
|
||||||
.cache
|
.cache
|
||||||
.entry(mime.clone())
|
.entry(mime.clone())
|
||||||
.or_insert_with(|| Vec::with_capacity(1));
|
.or_insert_with(|| Vec::with_capacity(1));
|
||||||
if apps
|
if !apps.iter().any(|x| filename_eq(&x.path, filename)) {
|
||||||
.iter()
|
|
||||||
.find(|x| filename_eq(&x.path, filename))
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
if let Some(app) =
|
if let Some(app) =
|
||||||
all_apps.iter().find(|x| filename_eq(&x.path, filename))
|
all_apps.iter().find(|x| filename_eq(&x.path, filename))
|
||||||
{
|
{
|
||||||
|
|
@ -263,9 +259,7 @@ impl MimeAppCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &Mime) -> Vec<MimeApp> {
|
pub fn get(&self, key: &Mime) -> Vec<MimeApp> {
|
||||||
self.cache
|
self.cache.get(key).map_or_else(Vec::new, |x| x.clone())
|
||||||
.get(&key)
|
|
||||||
.map_or_else(|| Vec::new(), |x| x.clone())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,5 +286,5 @@ pub fn terminal() -> Option<MimeApp> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return whatever was the first terminal found
|
// Return whatever was the first terminal found
|
||||||
mime_app_cache.terminals.first().map(|x| x.clone())
|
mime_app_cache.terminals.first().cloned()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ fn network_scan(uri: &str, sizes: IconSizes) -> Result<Vec<tab::Item>, String> {
|
||||||
info.icon()
|
info.icon()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|icon| gio_icon_to_path(icon, size))
|
.and_then(|icon| gio_icon_to_path(icon, size))
|
||||||
.map(|path| widget::icon::from_path(path))
|
.map(widget::icon::from_path)
|
||||||
.unwrap_or(
|
.unwrap_or(
|
||||||
widget::icon::from_name(if metadata.is_dir() {
|
widget::icon::from_name(if metadata.is_dir() {
|
||||||
"folder"
|
"folder"
|
||||||
|
|
@ -388,10 +388,7 @@ impl Gvfs {
|
||||||
let file = gio::File::for_uri(&uri);
|
let file = gio::File::for_uri(&uri);
|
||||||
let needs_mount = match file.find_enclosing_mount(gio::Cancellable::NONE) {
|
let needs_mount = match file.find_enclosing_mount(gio::Cancellable::NONE) {
|
||||||
Ok(_) => false,
|
Ok(_) => false,
|
||||||
Err(err) => match err.kind::<gio::IOErrorEnum>() {
|
Err(err) => matches!(err.kind::<gio::IOErrorEnum>(), Some(gio::IOErrorEnum::NotMounted))
|
||||||
Some(gio::IOErrorEnum::NotMounted) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
if needs_mount {
|
if needs_mount {
|
||||||
let mount_op = mount_op(uri.clone(), event_tx.clone());
|
let mount_op = mount_op(uri.clone(), event_tx.clone());
|
||||||
|
|
@ -468,7 +465,6 @@ impl Mounter for Gvfs {
|
||||||
Task::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
command_tx.send(Cmd::Mount(item)).unwrap();
|
command_tx.send(Cmd::Mount(item)).unwrap();
|
||||||
()
|
|
||||||
},
|
},
|
||||||
|x| x,
|
|x| x,
|
||||||
)
|
)
|
||||||
|
|
@ -479,7 +475,6 @@ impl Mounter for Gvfs {
|
||||||
Task::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
command_tx.send(Cmd::NetworkDrive(uri)).unwrap();
|
command_tx.send(Cmd::NetworkDrive(uri)).unwrap();
|
||||||
()
|
|
||||||
},
|
},
|
||||||
|x| x,
|
|x| x,
|
||||||
)
|
)
|
||||||
|
|
@ -498,7 +493,6 @@ impl Mounter for Gvfs {
|
||||||
Task::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
command_tx.send(Cmd::Unmount(item)).unwrap();
|
command_tx.send(Cmd::Unmount(item)).unwrap();
|
||||||
()
|
|
||||||
},
|
},
|
||||||
|x| x,
|
|x| x,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -117,4 +117,4 @@ pub fn mounters() -> Mounters {
|
||||||
Mounters::new(mounters)
|
Mounters::new(mounters)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static MOUNTERS: Lazy<Mounters> = Lazy::new(|| mounters());
|
pub static MOUNTERS: Lazy<Mounters> = Lazy::new(mounters);
|
||||||
|
|
|
||||||
|
|
@ -31,156 +31,150 @@ use crate::tab::DOUBLE_CLICK_DURATION;
|
||||||
pub struct MouseArea<'a, Message> {
|
pub struct MouseArea<'a, Message> {
|
||||||
id: Id,
|
id: Id,
|
||||||
content: Element<'a, Message>,
|
content: Element<'a, Message>,
|
||||||
on_drag: Option<Box<dyn Fn(Option<Rectangle>) -> Message + 'a>>,
|
on_drag: Option<Box<dyn OnDrag<'a, Message>>>,
|
||||||
on_double_click: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_double_click: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_press: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_press: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_drag_end: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_drag_end: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_release: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_release: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_resize: Option<Box<dyn Fn(Size) -> Message + 'a>>,
|
on_resize: Option<Box<dyn OnResize<'a, Message>>>,
|
||||||
on_right_press: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_right_press: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_right_press_no_capture: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_right_press_no_capture: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_right_release: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_right_release: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_middle_press: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_middle_press: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_middle_release: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_middle_release: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_back_press: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_back_press: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_back_release: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_back_release: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_forward_press: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_forward_press: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_forward_release: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
on_forward_release: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||||
on_scroll: Option<Box<dyn Fn(mouse::ScrollDelta, Modifiers) -> Option<Message> + 'a>>,
|
on_scroll: Option<Box<dyn OnScroll<'a, Message>>>,
|
||||||
on_enter: Option<Box<dyn Fn() -> Message + 'a>>,
|
on_enter: Option<Box<dyn OnEnterExit<'a, Message>>>,
|
||||||
on_exit: Option<Box<dyn Fn() -> Message + 'a>>,
|
on_exit: Option<Box<dyn OnEnterExit<'a, Message>>>,
|
||||||
show_drag_rect: bool,
|
show_drag_rect: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message> MouseArea<'a, Message> {
|
impl<'a, Message> MouseArea<'a, Message> {
|
||||||
/// The message to emit when a drag is initiated.
|
/// The message to emit when a drag is initiated.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_drag(mut self, message: impl Fn(Option<Rectangle>) -> Message + 'a) -> Self {
|
pub fn on_drag(mut self, message: impl OnDrag<'a, Message>) -> Self {
|
||||||
self.on_drag = Some(Box::new(message));
|
self.on_drag = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit when a drag ends.
|
/// The message to emit when a drag ends.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_drag_end(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_drag_end(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_drag_end = Some(Box::new(message));
|
self.on_drag_end = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a double click.
|
/// The message to emit on a double click.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_double_click(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_double_click(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_double_click = Some(Box::new(message));
|
self.on_double_click = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a left button press.
|
/// The message to emit on a left button press.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_press(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_press(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_press = Some(Box::new(message));
|
self.on_press = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a left button release.
|
/// The message to emit on a left button release.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_release(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_release(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_release = Some(Box::new(message));
|
self.on_release = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on resizing.
|
/// The message to emit on resizing.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_resize(mut self, message: impl Fn(Size) -> Message + 'a) -> Self {
|
pub fn on_resize(mut self, message: impl OnResize<'a, Message>) -> Self {
|
||||||
self.on_resize = Some(Box::new(message));
|
self.on_resize = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a right button press.
|
/// The message to emit on a right button press.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_right_press(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_right_press(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_right_press = Some(Box::new(message));
|
self.on_right_press = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a right button press without capturing.
|
/// The message to emit on a right button press without capturing.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_right_press_no_capture(
|
pub fn on_right_press_no_capture(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
mut self,
|
|
||||||
message: impl Fn(Option<Point>) -> Message + 'a,
|
|
||||||
) -> Self {
|
|
||||||
self.on_right_press_no_capture = Some(Box::new(message));
|
self.on_right_press_no_capture = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a right button release.
|
/// The message to emit on a right button release.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_right_release(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_right_release(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_right_release = Some(Box::new(message));
|
self.on_right_release = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a middle button press.
|
/// The message to emit on a middle button press.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_middle_press(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_middle_press(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_middle_press = Some(Box::new(message));
|
self.on_middle_press = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a middle button release.
|
/// The message to emit on a middle button release.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_middle_release(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_middle_release(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_middle_release = Some(Box::new(message));
|
self.on_middle_release = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a back button press.
|
/// The message to emit on a back button press.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_back_press(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_back_press(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_back_press = Some(Box::new(message));
|
self.on_back_press = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a back button release.
|
/// The message to emit on a back button release.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_back_release(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_back_release(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_back_release = Some(Box::new(message));
|
self.on_back_release = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a forward button press.
|
/// The message to emit on a forward button press.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_forward_press(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_forward_press(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_forward_press = Some(Box::new(message));
|
self.on_forward_press = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a forward button release.
|
/// The message to emit on a forward button release.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_forward_release(mut self, message: impl Fn(Option<Point>) -> Message + 'a) -> Self {
|
pub fn on_forward_release(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||||
self.on_forward_release = Some(Box::new(message));
|
self.on_forward_release = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit on a scroll.
|
/// The message to emit on a scroll.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_scroll(
|
pub fn on_scroll(mut self, message: impl OnScroll<'a, Message>) -> Self {
|
||||||
mut self,
|
|
||||||
message: impl Fn(mouse::ScrollDelta, Modifiers) -> Option<Message> + 'a,
|
|
||||||
) -> Self {
|
|
||||||
self.on_scroll = Some(Box::new(message));
|
self.on_scroll = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit when a mouse enters the area.
|
/// The message to emit when a mouse enters the area.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_enter(mut self, message: impl Fn() -> Message + 'a) -> Self {
|
pub fn on_enter(mut self, message: impl OnEnterExit<'a, Message>) -> Self {
|
||||||
self.on_enter = Some(Box::new(message));
|
self.on_enter = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message to emit when a mouse exits the area.
|
/// The message to emit when a mouse exits the area.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn on_exit(mut self, message: impl Fn() -> Message + 'a) -> Self {
|
pub fn on_exit(mut self, message: impl OnEnterExit<'a, Message>) -> Self {
|
||||||
self.on_exit = Some(Box::new(message));
|
self.on_exit = Some(Box::new(message));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
@ -199,6 +193,24 @@ impl<'a, Message> MouseArea<'a, Message> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait OnMouseButton<'a, Message>: Fn(Option<Point>) -> Message + 'a {}
|
||||||
|
impl<'a, Message, F> OnMouseButton<'a, Message> for F where F: Fn(Option<Point>) -> Message + 'a {}
|
||||||
|
|
||||||
|
pub trait OnDrag<'a, Message>: Fn(Option<Rectangle>) -> Message + 'a {}
|
||||||
|
impl<'a, Message, F> OnDrag<'a, Message> for F where F: Fn(Option<Rectangle>) -> Message + 'a {}
|
||||||
|
|
||||||
|
pub trait OnResize<'a, Message>: Fn(Size) -> Message + 'a {}
|
||||||
|
impl<'a, Message, F> OnResize<'a, Message> for F where F: Fn(Size) -> Message + 'a {}
|
||||||
|
|
||||||
|
pub trait OnScroll<'a, Message>: Fn(mouse::ScrollDelta, Modifiers) -> Option<Message> + 'a {}
|
||||||
|
impl<'a, Message, F> OnScroll<'a, Message> for F where
|
||||||
|
F: Fn(mouse::ScrollDelta, Modifiers) -> Option<Message> + 'a
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait OnEnterExit<'a, Message>: Fn() -> Message + 'a {}
|
||||||
|
impl<'a, Message, F> OnEnterExit<'a, Message> for F where F: Fn() -> Message + 'a {}
|
||||||
|
|
||||||
/// Local state of the [`MouseArea`].
|
/// Local state of the [`MouseArea`].
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct State {
|
struct State {
|
||||||
|
|
@ -250,7 +262,7 @@ impl State {
|
||||||
} else {
|
} else {
|
||||||
mouse::Click::new(pos, mouse::Button::Left, None)
|
mouse::Click::new(pos, mouse::Button::Left, None)
|
||||||
};
|
};
|
||||||
self.prev_click = Some((new.clone(), now));
|
self.prev_click = Some((new, now));
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -284,7 +296,7 @@ impl<'a, Message> MouseArea<'a, Message> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message> Widget<Message, Theme, Renderer> for MouseArea<'a, Message>
|
impl<Message> Widget<Message, Theme, Renderer> for MouseArea<'_, Message>
|
||||||
where
|
where
|
||||||
Message: Clone,
|
Message: Clone,
|
||||||
{
|
{
|
||||||
|
|
@ -659,7 +671,7 @@ fn update<Message: Clone>(
|
||||||
|
|
||||||
if let Some(on_scroll) = widget.on_scroll.as_ref() {
|
if let Some(on_scroll) = widget.on_scroll.as_ref() {
|
||||||
if let Event::Mouse(mouse::Event::WheelScrolled { delta }) = event {
|
if let Event::Mouse(mouse::Event::WheelScrolled { delta }) = event {
|
||||||
if let Some(message) = on_scroll(delta.clone(), state.modifiers) {
|
if let Some(message) = on_scroll(*delta, state.modifiers) {
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ pub struct Controller {
|
||||||
inner: Arc<ControllerInner>,
|
inner: Arc<ControllerInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Controller {
|
impl Default for Controller {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
primary: true,
|
primary: true,
|
||||||
inner: Arc::new(ControllerInner {
|
inner: Arc::new(ControllerInner {
|
||||||
|
|
@ -33,7 +33,9 @@ impl Controller {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Controller {
|
||||||
pub fn check(&self) -> Result<(), String> {
|
pub fn check(&self) -> Result<(), String> {
|
||||||
let mut state = self.inner.state.lock().unwrap();
|
let mut state = self.inner.state.lock().unwrap();
|
||||||
loop {
|
loop {
|
||||||
|
|
|
||||||
|
|
@ -683,7 +683,7 @@ impl Operation {
|
||||||
path.strip_prefix(relative_root).map_err(err_str)?.to_str()
|
path.strip_prefix(relative_root).map_err(err_str)?.to_str()
|
||||||
{
|
{
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
let mut file = fs::File::open(&path).map_err(err_str)?;
|
let mut file = fs::File::open(path).map_err(err_str)?;
|
||||||
let metadata = file.metadata().map_err(err_str)?;
|
let metadata = file.metadata().map_err(err_str)?;
|
||||||
let total = metadata.len();
|
let total = metadata.len();
|
||||||
if total >= 4 * 1024 * 1024 * 1024 {
|
if total >= 4 * 1024 * 1024 * 1024 {
|
||||||
|
|
@ -800,7 +800,7 @@ impl Operation {
|
||||||
op_sel.selected.push(new_dir.clone());
|
op_sel.selected.push(new_dir.clone());
|
||||||
|
|
||||||
let controller = controller.clone();
|
let controller = controller.clone();
|
||||||
let mime = mime_for_path(&path);
|
let mime = mime_for_path(path);
|
||||||
match mime.essence_str() {
|
match mime.essence_str() {
|
||||||
"application/gzip" | "application/x-compressed-tar" => {
|
"application/gzip" | "application/x-compressed-tar" => {
|
||||||
OpReader::new(path, controller)
|
OpReader::new(path, controller)
|
||||||
|
|
@ -960,7 +960,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
use cosmic::iced::futures::{channel::mpsc, StreamExt};
|
use cosmic::iced::futures::{channel::mpsc, StreamExt};
|
||||||
use log::{debug, trace};
|
use log::debug;
|
||||||
use test_log::test;
|
use test_log::test;
|
||||||
use tokio::sync;
|
use tokio::sync;
|
||||||
|
|
||||||
|
|
@ -968,8 +968,8 @@ mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{
|
app::{
|
||||||
test_utils::{
|
test_utils::{
|
||||||
empty_fs, filter_dirs, filter_files, read_dir_sorted, simple_fs, NAME_LEN,
|
empty_fs, filter_dirs, filter_files, simple_fs, NAME_LEN, NUM_DIRS, NUM_FILES,
|
||||||
NUM_DIRS, NUM_FILES, NUM_HIDDEN, NUM_NESTED,
|
NUM_HIDDEN, NUM_NESTED,
|
||||||
},
|
},
|
||||||
DialogPage, Message,
|
DialogPage, Message,
|
||||||
},
|
},
|
||||||
|
|
@ -993,7 +993,7 @@ mod tests {
|
||||||
paths: paths_clone,
|
paths: paths_clone,
|
||||||
to: to_clone,
|
to: to_clone,
|
||||||
}
|
}
|
||||||
.perform(&sync::Mutex::new(tx).into(), Controller::new())
|
.perform(&sync::Mutex::new(tx).into(), Controller::default())
|
||||||
.await
|
.await
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,18 @@ use super::{copy_unique_path, Controller, OperationSelection, ReplaceResult};
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
buf: Vec<u8>,
|
buf: Vec<u8>,
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
on_progress: Box<dyn Fn(&Op, &Progress) + 'static>,
|
on_progress: Box<dyn OnProgress>,
|
||||||
on_replace: Box<dyn Fn(&Op) -> ReplaceResult + 'static>,
|
on_replace: Box<dyn OnReplace>,
|
||||||
pub(crate) op_sel: OperationSelection,
|
pub(crate) op_sel: OperationSelection,
|
||||||
replace_result_opt: Option<ReplaceResult>,
|
replace_result_opt: Option<ReplaceResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait OnProgress: Fn(&Op, &Progress) + 'static {}
|
||||||
|
impl<F> OnProgress for F where F: Fn(&Op, &Progress) + 'static {}
|
||||||
|
|
||||||
|
pub trait OnReplace: Fn(&Op) -> ReplaceResult + 'static {}
|
||||||
|
impl<F> OnReplace for F where F: Fn(&Op) -> ReplaceResult + 'static {}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new(controller: Controller) -> Self {
|
pub fn new(controller: Controller) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -67,7 +73,7 @@ impl Context {
|
||||||
OpKind::Symlink { target }
|
OpKind::Symlink { target }
|
||||||
} else {
|
} else {
|
||||||
//TODO: present dialog and allow continue
|
//TODO: present dialog and allow continue
|
||||||
return Err(format!("{} is not a known file type", from.display()).into());
|
return Err(format!("{} is not a known file type", from.display()));
|
||||||
};
|
};
|
||||||
let to = if from == from_parent {
|
let to = if from == from_parent {
|
||||||
// When copying a file, from matches from_parent, and to_parent must be used
|
// When copying a file, from matches from_parent, and to_parent must be used
|
||||||
|
|
@ -130,12 +136,12 @@ impl Context {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_progress<F: Fn(&Op, &Progress) + 'static>(mut self, f: F) -> Self {
|
pub fn on_progress<F: OnProgress>(mut self, f: F) -> Self {
|
||||||
self.on_progress = Box::new(f);
|
self.on_progress = Box::new(f);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_replace<F: Fn(&Op) -> ReplaceResult + 'static>(mut self, f: F) -> Self {
|
pub fn on_replace<F: OnReplace>(mut self, f: F) -> Self {
|
||||||
self.on_replace = Box::new(f);
|
self.on_replace = Box::new(f);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
@ -153,9 +159,7 @@ impl Context {
|
||||||
Ok(ControlFlow::Continue(op.to.clone()))
|
Ok(ControlFlow::Continue(op.to.clone()))
|
||||||
}
|
}
|
||||||
ReplaceResult::KeepBoth => match op.to.parent() {
|
ReplaceResult::KeepBoth => match op.to.parent() {
|
||||||
Some(to_parent) => Ok(ControlFlow::Continue(copy_unique_path(
|
Some(to_parent) => Ok(ControlFlow::Continue(copy_unique_path(&op.from, to_parent))),
|
||||||
&op.from, &to_parent,
|
|
||||||
))),
|
|
||||||
None => Err(format!("failed to get parent of {:?}", op.to).into()),
|
None => Err(format!("failed to get parent of {:?}", op.to).into()),
|
||||||
},
|
},
|
||||||
ReplaceResult::Skip(apply_to_all) => {
|
ReplaceResult::Skip(apply_to_all) => {
|
||||||
|
|
@ -216,7 +220,7 @@ impl Op {
|
||||||
let metadata = from_file.metadata()?;
|
let metadata = from_file.metadata()?;
|
||||||
// Remove `to` if overwriting and it is an existing file
|
// Remove `to` if overwriting and it is an existing file
|
||||||
if self.to.is_file() {
|
if self.to.is_file() {
|
||||||
match ctx.replace(&self)? {
|
match ctx.replace(self)? {
|
||||||
ControlFlow::Continue(to) => {
|
ControlFlow::Continue(to) => {
|
||||||
self.to = to;
|
self.to = to;
|
||||||
}
|
}
|
||||||
|
|
@ -226,7 +230,7 @@ impl Op {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
progress.total_bytes = Some(metadata.len());
|
progress.total_bytes = Some(metadata.len());
|
||||||
(ctx.on_progress)(&self, &progress);
|
(ctx.on_progress)(self, &progress);
|
||||||
// This is atomic and ensures `to` is not created by any other process
|
// This is atomic and ensures `to` is not created by any other process
|
||||||
let mut to_file = fs::OpenOptions::new()
|
let mut to_file = fs::OpenOptions::new()
|
||||||
.create_new(true)
|
.create_new(true)
|
||||||
|
|
@ -242,14 +246,14 @@ impl Op {
|
||||||
}
|
}
|
||||||
to_file.write_all(&ctx.buf[..count])?;
|
to_file.write_all(&ctx.buf[..count])?;
|
||||||
progress.current_bytes += count as u64;
|
progress.current_bytes += count as u64;
|
||||||
(ctx.on_progress)(&self, &progress);
|
(ctx.on_progress)(self, &progress);
|
||||||
}
|
}
|
||||||
to_file.sync_all()?;
|
to_file.sync_all()?;
|
||||||
}
|
}
|
||||||
OpKind::Move => {
|
OpKind::Move => {
|
||||||
// Remove `to` if overwriting and it is an existing file
|
// Remove `to` if overwriting and it is an existing file
|
||||||
if self.to.is_file() {
|
if self.to.is_file() {
|
||||||
match ctx.replace(&self)? {
|
match ctx.replace(self)? {
|
||||||
ControlFlow::Continue(to) => {
|
ControlFlow::Continue(to) => {
|
||||||
self.to = to;
|
self.to = to;
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +293,7 @@ impl Op {
|
||||||
OpKind::Symlink { ref target } => {
|
OpKind::Symlink { ref target } => {
|
||||||
// Remove `to` if overwriting and it is an existing file
|
// Remove `to` if overwriting and it is an existing file
|
||||||
if self.to.is_file() {
|
if self.to.is_file() {
|
||||||
match ctx.replace(&self)? {
|
match ctx.replace(self)? {
|
||||||
ControlFlow::Continue(to) => {
|
ControlFlow::Continue(to) => {
|
||||||
self.to = to;
|
self.to = to;
|
||||||
}
|
}
|
||||||
|
|
@ -298,8 +302,18 @@ impl Op {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: use OS-specific function
|
#[cfg(unix)]
|
||||||
fs::soft_link(&target, &self.to)?;
|
{
|
||||||
|
std::os::unix::fs::symlink(target, &self.to)?;
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
if target.is_dir() {
|
||||||
|
std::os::windows::fs::symlink_dir(target, &self.to)?;
|
||||||
|
} else {
|
||||||
|
std::os::windows::fs::symlink_file(target, &self.to)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
|
|
|
||||||
|
|
@ -475,7 +475,7 @@ pub fn item_from_entry(
|
||||||
};
|
};
|
||||||
|
|
||||||
let dir_size = if metadata.is_dir() {
|
let dir_size = if metadata.is_dir() {
|
||||||
DirSize::Calculating(Controller::new())
|
DirSize::Calculating(Controller::default())
|
||||||
} else {
|
} else {
|
||||||
DirSize::NotDirectory
|
DirSize::NotDirectory
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -144,9 +144,7 @@ impl ThumbnailerCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &Mime) -> Vec<Thumbnailer> {
|
pub fn get(&self, key: &Mime) -> Vec<Thumbnailer> {
|
||||||
self.cache
|
self.cache.get(key).map_or_else(Vec::new, |x| x.clone())
|
||||||
.get(&key)
|
|
||||||
.map_or_else(|| Vec::new(), |x| x.clone())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue