cosmic_files/
trash.rs

1use cosmic::widget;
2use regex::Regex;
3use std::collections::HashSet;
4use std::path::PathBuf;
5
6use crate::config::IconSizes;
7use crate::tab::{Item, SearchItem};
8
9pub trait TrashExt {
10    fn is_empty() -> bool {
11        true
12    }
13
14    fn entries() -> usize {
15        0
16    }
17
18    fn folders() -> Result<HashSet<PathBuf>, trash::Error> {
19        Err(trash::Error::Unknown {
20            description: "reading trash folders not supported on this platform".into(),
21        })
22    }
23
24    fn scan(_sizes: IconSizes) -> Vec<Item> {
25        log::warn!("viewing trash not supported on this platform");
26        Vec::new()
27    }
28
29    fn scan_search<F: Fn(SearchItem) -> bool + Sync>(_callback: F, _regex: &Regex) {}
30
31    fn icon(icon_size: u16) -> widget::icon::Handle {
32        widget::icon::from_name(if Self::is_empty() {
33            "user-trash"
34        } else {
35            "user-trash-full"
36        })
37        .size(icon_size)
38        .handle()
39    }
40
41    fn icon_symbolic(icon_size: u16) -> widget::icon::Handle {
42        widget::icon::from_name(if Self::is_empty() {
43            "user-trash-symbolic"
44        } else {
45            "user-trash-full-symbolic"
46        })
47        .size(icon_size)
48        .handle()
49    }
50}
51
52pub struct Trash;
53
54// This config statement is from trash::os_limited
55#[cfg(any(
56    target_os = "windows",
57    all(
58        unix,
59        not(target_os = "macos"),
60        not(target_os = "ios"),
61        not(target_os = "android")
62    )
63))]
64impl TrashExt for Trash {
65    fn is_empty() -> bool {
66        trash::os_limited::is_empty().unwrap_or(true)
67    }
68
69    fn entries() -> usize {
70        match trash::os_limited::list() {
71            Ok(entries) => entries.len(),
72            Err(_err) => 0,
73        }
74    }
75
76    // Not available on Windows only
77    #[cfg(not(target_os = "windows"))]
78    fn folders() -> Result<HashSet<PathBuf>, trash::Error> {
79        trash::os_limited::trash_folders()
80    }
81
82    fn scan(sizes: IconSizes) -> Vec<Item> {
83        use crate::localize::LANGUAGE_SORTER;
84        use crate::tab::item_from_trash_entry;
85        use std::cmp::Ordering;
86
87        let entries = match trash::os_limited::list() {
88            Ok(entry) => entry,
89            Err(err) => {
90                log::warn!("failed to read trash items: {err}");
91                return Vec::new();
92            }
93        };
94        let mut items: Vec<_> = entries
95            .into_iter()
96            .filter_map(|entry| {
97                let metadata = trash::os_limited::metadata(&entry)
98                    .inspect_err(|err| {
99                        log::warn!("failed to get metadata for trash item {entry:?}: {err}")
100                    })
101                    .ok()?;
102                Some(item_from_trash_entry(entry, metadata, sizes))
103            })
104            .collect();
105        items.sort_by(|a, b| match (a.metadata.is_dir(), b.metadata.is_dir()) {
106            (true, false) => Ordering::Less,
107            (false, true) => Ordering::Greater,
108            _ => LANGUAGE_SORTER.compare(&a.display_name, &b.display_name),
109        });
110        items
111    }
112
113    fn scan_search<F: Fn(SearchItem) -> bool + Sync>(callback: F, regex: &Regex) {
114        let entries = match trash::os_limited::list() {
115            Ok(entries) => entries,
116            Err(err) => {
117                log::warn!("failed to read trash items: {err}");
118                return;
119            }
120        };
121
122        for entry in entries {
123            if let Ok(metadata) = trash::os_limited::metadata(&entry).inspect_err(|err| {
124                log::warn!("failed to get metadata for trash item {entry:?}: {err}")
125            }) {
126                let name = entry.name.to_string_lossy();
127                if regex.is_match(&name) && !callback(SearchItem::Trash(entry, metadata)) {
128                    break;
129                }
130            }
131        }
132    }
133}
134
135// This config statement is from trash::os_limited, inverted
136#[cfg(not(any(
137    target_os = "windows",
138    all(
139        unix,
140        not(target_os = "macos"),
141        not(target_os = "ios"),
142        not(target_os = "android")
143    )
144)))]
145impl TrashExt for Trash {}