diff --git a/crates/pdfs-gui/src/app/main.rs b/crates/pdfs-gui/src/app/main.rs index ba41ea3..242a798 100644 --- a/crates/pdfs-gui/src/app/main.rs +++ b/crates/pdfs-gui/src/app/main.rs @@ -457,6 +457,8 @@ fn build_window(app: &adw::Application) { files: browser_widgets.files.clone(), history: RefCell::new(Vec::new()), future: RefCell::new(Vec::new()), + places: RefCell::new(HashMap::new()), + restore: RefCell::new(None), crumb: browser_widgets.crumb.clone(), content: browser_widgets.content.clone(), status: browser_widgets.status.clone(), @@ -1548,6 +1550,7 @@ fn show_shortcuts(window: &adw::ApplicationWindow) { ("minus", gettext_noop("Smaller thumbnails")), ("0", gettext_noop("Reset thumbnail size")), ("a", gettext_noop("Select all")), + ("Escape Left", gettext_noop("Back")), ], ), ( @@ -1584,8 +1587,17 @@ fn install_shortcuts(ui: &Rc, window: &adw::ApplicationWindow) { controller.connect_key_pressed(move |_, key, _, state| { let ctrl = state.contains(gtk4::gdk::ModifierType::CONTROL_MASK); let alt = state.contains(gtk4::gdk::ModifierType::ALT_MASK); - let on_browser = ui.stack.visible_child_name().as_deref() == Some("browser"); - let on_trash = ui.stack.visible_child_name().as_deref() == Some("trash"); + let page = ui.stack.visible_child_name(); + let on_browser = page.as_deref() == Some("browser"); + let on_trash = page.as_deref() == Some("trash"); + let on_gallery = page.as_deref() == Some("gallery"); + // Pages with a level to go back to, besides My files' own history. + let in_collection = on_gallery && ui.gallery.in_collection(); + let in_shared_folder = + page.as_deref() == Some("shared") && !ui.shared.nav.borrow().is_empty(); + let in_device_folder = + page.as_deref() == Some("devices") && !ui.devices.nav.borrow().is_empty(); + let back_key = (key == gtk4::gdk::Key::Left && alt) || key == gtk4::gdk::Key::BackSpace; match key { // Refresh works on every page, so it is matched before the // browser-only bindings. @@ -1642,6 +1654,21 @@ fn install_shortcuts(ui: &Rc, window: &adw::ApplicationWindow) { gtk4::gdk::Key::BackSpace if on_browser => { ui.browser.actions.activate_action("back", None) } + // Selection mode ends before Escape leaves anything; the grid + // handles this itself while it has the focus. + gtk4::gdk::Key::Escape if on_gallery && ui.gallery.selecting.get() => { + set_selection_mode(&ui, false) + } + // An album or a place is a level below Photos, as a folder is + // below its parent: Back leaves it, and so does Escape. + _ if in_collection + && !ui.gallery.selecting.get() + && (back_key || key == gtk4::gdk::Key::Escape) => + { + ui.gallery.back.emit_clicked() + } + _ if in_shared_folder && back_key => shared_back(&ui), + _ if in_device_folder && back_key => devices_back(&ui), gtk4::gdk::Key::u | gtk4::gdk::Key::U if ctrl && on_browser => prompt_upload(&ui), gtk4::gdk::Key::Menu if visible_file_list(&ui).is_some() => { if let Some(list) = visible_file_list(&ui) { diff --git a/crates/pdfs-gui/src/app/pages/browser.rs b/crates/pdfs-gui/src/app/pages/browser.rs index b6fb218..4977ecb 100644 --- a/crates/pdfs-gui/src/app/pages/browser.rs +++ b/crates/pdfs-gui/src/app/pages/browser.rs @@ -1,6 +1,14 @@ use crate::activation::{DriveActivation, drive_activation, mounted_path, present_within}; use crate::*; +/// How a folder in My files was left: scrolled `offset` px down, with the +/// entries named `selected` highlighted. +#[derive(Clone, Debug, Default, PartialEq)] +pub(crate) struct FolderPlace { + pub(crate) offset: f64, + pub(crate) selected: Vec, +} + pub(crate) struct BrowserState { // Files (browser) page. /// The grid and list; the model is repopulated per directory. @@ -10,6 +18,13 @@ pub(crate) struct BrowserState { /// breadcrumb. pub(crate) history: RefCell>, pub(crate) future: RefCell>, + /// Where each folder left by Back, Forward, Up or a descent was scrolled + /// and what was selected in it, by path. Back, Forward and Up put the + /// folder back that way; opening it afresh starts at the top. + pub(crate) places: RefCell>, + /// The folder whose [`Self::places`] entry the next listing restores, set + /// by Back, Forward and Up. + pub(crate) restore: RefCell>, /// Clickable breadcrumb trail (a button per path segment); rebuilt per load /// by [`repaint_crumb`] so each ancestor folder navigates on click. pub(crate) crumb: gtk4::Box, @@ -1556,8 +1571,29 @@ pub(crate) fn sort_entries(entries: &mut [DirEntry], view: FilesView) { }); } +/// Remember how the folder on screen is scrolled and what is selected in it, +/// for Back, Forward or Up to bring it back that way. Only a listing of the +/// folder itself counts; search hits are not its rows. +fn remember_place(ui: &Rc) { + let path = ui.browser.path.borrow().clone(); + if ui.browser.listed.borrow().as_deref() != Some(path.as_str()) { + return; + } + let files = &ui.browser.files; + let place = FolderPlace { + offset: files.scroll_offset(), + selected: files + .selected() + .into_iter() + .map(|entry| entry.name) + .collect(), + }; + ui.browser.places.borrow_mut().insert(path, place); +} + /// Open the folder on screen in a new place, remembering where we were. pub(crate) fn browse_to(ui: &Rc, target: String) { + remember_place(ui); let left = ui.browser.path.replace(target.clone()); if left != target { ui.browser.history.borrow_mut().push(left); @@ -1582,6 +1618,8 @@ fn browse_back(ui: &Rc) { let Some(previous) = ui.browser.history.borrow_mut().pop() else { return; }; + remember_place(ui); + *ui.browser.restore.borrow_mut() = Some(previous.clone()); let left = ui.browser.path.replace(previous); ui.browser.future.borrow_mut().push(left); load_browser(ui); @@ -1592,6 +1630,8 @@ fn browse_forward(ui: &Rc) { return; }; ui.browser.search.set_text(""); + remember_place(ui); + *ui.browser.restore.borrow_mut() = Some(next.clone()); let left = ui.browser.path.replace(next); ui.browser.history.borrow_mut().push(left); load_browser(ui); @@ -1604,6 +1644,7 @@ fn browse_up(ui: &Rc) { } ui.browser.search.set_text(""); let parent = path.rfind('/').map(|i| &path[..i]).unwrap_or_default(); + *ui.browser.restore.borrow_mut() = Some(parent.to_string()); browse_to(ui, parent.to_string()); } @@ -3003,8 +3044,15 @@ pub(crate) fn repaint_browser(ui: &Rc, entries: &[DirEntry]) { // Only the rows that changed are swapped, so a refresh keeps the // selection, the scroll position and the thumbnails already drawn. replace_items(&ui.browser.files.model, &sorted); + // Back, Forward and Up return to a folder as it was left; any other way + // in starts at the top. + let restore = ui.browser.restore.take().filter(|target| *target == path); if another_folder { - ui.browser.files.scroll_to_top(); + let place = restore.and_then(|path| ui.browser.places.borrow().get(&path).cloned()); + match place { + Some(place) => ui.browser.files.restore(place.offset, &place.selected), + None => ui.browser.files.scroll_to_top(), + } } } diff --git a/crates/pdfs-gui/src/app/pages/devices.rs b/crates/pdfs-gui/src/app/pages/devices.rs index cbf4286..4628f21 100644 --- a/crates/pdfs-gui/src/app/pages/devices.rs +++ b/crates/pdfs-gui/src/app/pages/devices.rs @@ -190,10 +190,9 @@ pub(crate) fn wire_devices(ui: &Rc, widgets: &DevicesWidgets) { })); let ui_back = ui.clone(); - widgets.back.connect_clicked(move |_| { - ui_back.devices.nav.borrow_mut().pop(); - load_devices(&ui_back); - }); + widgets + .back + .connect_clicked(move |_| devices_back(&ui_back)); let ui_retry = ui.clone(); widgets .retry @@ -211,6 +210,14 @@ pub(crate) fn devices_status(ui: &Rc, icon: &str, title: &str, description: ui.devices.content.set_visible_child_name("status"); } +/// Back out of a computer's folder to the level above: the page's Back button, and +/// Alt+Left or Backspace. A no-op at the top. +pub(crate) fn devices_back(ui: &Rc) { + if ui.devices.nav.borrow_mut().pop().is_some() { + load_devices(ui); + } +} + /// Load the view [`DevicesState::nav`] points at: the device list, or a folder /// of another computer's backup. pub(crate) fn load_devices(ui: &Rc) { diff --git a/crates/pdfs-gui/src/app/pages/photo_viewer.rs b/crates/pdfs-gui/src/app/pages/photo_viewer.rs index c4d507d..e67cb01 100644 --- a/crates/pdfs-gui/src/app/pages/photo_viewer.rs +++ b/crates/pdfs-gui/src/app/pages/photo_viewer.rs @@ -1428,8 +1428,10 @@ pub(crate) fn open_photo_viewer(ui: &Rc, initial_uid: String) -> gtk4::Windo // kept every closed lightbox, its window and its full-size photo in memory // for the life of the app. let keep = RefCell::new(Some(viewer.clone())); + let ui_close = ui.clone(); window.connect_close_request(move |_| { if let Some(viewer) = keep.borrow_mut().take() { + reveal_photo(&ui_close, &viewer.uid.borrow()); stop_video(&viewer); disarm_slide(&viewer); if let Some(source) = viewer.chrome_source.borrow_mut().take() { diff --git a/crates/pdfs-gui/src/app/pages/photos.rs b/crates/pdfs-gui/src/app/pages/photos.rs index dd3c76a..9070db5 100644 --- a/crates/pdfs-gui/src/app/pages/photos.rs +++ b/crates/pdfs-gui/src/app/pages/photos.rs @@ -3288,6 +3288,16 @@ fn top_anchor(ui: &Rc) -> Option<(String, f32)> { .or(first) } +/// Scroll the grid just far enough to show photo `uid`, as the lightbox +/// closes: paging with the arrow keys may have left the grid far behind. +pub(crate) fn reveal_photo(ui: &Rc, uid: &str) { + if let Some(row) = row_of_photo(&ui.gallery.groups, uid) { + ui.gallery + .list + .scroll_to(row, gtk4::ListScrollFlags::NONE, None); + } +} + /// Which row of the rendered model holds `uid`, if any. fn row_of_photo(store: &gio::ListStore, uid: &str) -> Option { (0..store.n_items()).find(|i| { @@ -4035,6 +4045,8 @@ pub(crate) fn load_gallery(ui: &Rc, append: bool) { // be read again when they switch back to it. if !photo_grid_shown(ui) { ui.gallery.timeline_stale.set(true); + // A scrubber jump was paging the grid the user has just left. + ui.gallery.jump.set(None); return; } if ui.gallery.loading.get() { @@ -4052,6 +4064,9 @@ pub(crate) fn load_gallery(ui: &Rc, append: bool) { let place = ui.gallery.place.borrow().as_ref().map(|p| p.id); let collection = album.is_some() || place.is_some(); if !append { + // A scrubber jump looks for a month of the listing being replaced: + // another filter, album or place has its own months, if any. + ui.gallery.jump.set(None); // Fresh load: clear the timeline and show Loading until the first page lands. ui.gallery.model.remove_all(); gallery_status( diff --git a/crates/pdfs-gui/src/app/pages/shared.rs b/crates/pdfs-gui/src/app/pages/shared.rs index 9fd3038..24065c9 100644 --- a/crates/pdfs-gui/src/app/pages/shared.rs +++ b/crates/pdfs-gui/src/app/pages/shared.rs @@ -279,10 +279,7 @@ pub(crate) fn wire_shared(ui: &Rc, widgets: &SharedWidgets) { })); let ui_back = ui.clone(); - widgets.back.connect_clicked(move |_| { - ui_back.shared.nav.borrow_mut().pop(); - load_shared(&ui_back); - }); + widgets.back.connect_clicked(move |_| shared_back(&ui_back)); let ui_retry = ui.clone(); widgets .retry @@ -318,6 +315,14 @@ pub(crate) fn shared_status(ui: &Rc, icon: &str, title: &str, description: & ui.shared.content.set_visible_child_name("status"); } +/// Back out of a shared folder to the level above: the page's Back button, and +/// Alt+Left or Backspace. A no-op at the top. +pub(crate) fn shared_back(ui: &Rc) { + if ui.shared.nav.borrow_mut().pop().is_some() { + load_shared(ui); + } +} + /// Fetch the top level (shared-with-me, invitations, saved links) in parallel /// and repaint the page once all three land. /// diff --git a/crates/pdfs-gui/src/app/widgets/file_list.rs b/crates/pdfs-gui/src/app/widgets/file_list.rs index 94b5455..97f6d8e 100644 --- a/crates/pdfs-gui/src/app/widgets/file_list.rs +++ b/crates/pdfs-gui/src/app/widgets/file_list.rs @@ -237,6 +237,36 @@ impl FileList { .scroll_to(0, None, gtk4::ListScrollFlags::NONE, None); } + /// How far the view on screen is scrolled, in px from the top. + pub(crate) fn scroll_offset(&self) -> f64 { + self.views + .visible_child() + .and_downcast::() + .map_or(0.0, |scroll| scroll.vadjustment().value()) + } + + /// Select the entries named `selected` and scroll the view on screen to + /// `offset`, as they were when the folder was left. The scroll waits for + /// an idle, when the views have measured the rows just put in. + pub(crate) fn restore(&self, offset: f64, selected: &[String]) { + self.selection.unselect_all(); + for i in 0..self.selection.n_items() { + if entry_at(Some(&self.selection), i) + .is_some_and(|entry| selected.contains(&entry.name)) + { + self.selection.select_item(i, false); + } + } + let Some(scroll) = self + .views + .visible_child() + .and_downcast::() + else { + return; + }; + glib::idle_add_local_once(move || scroll.vadjustment().set_value(offset)); + } + /// Whether the list, rather than the grid, is on screen. pub(crate) fn shows_list(&self) -> bool { self.views.visible_child_name().as_deref() == Some("list") diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 51e5579..fa46e1a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -74,6 +74,11 @@ Existing folders stay device backups. Older builds cannot open the upgraded data tell photos apart by their thumbnail. Ctrl+scroll, Ctrl+plus, Ctrl+minus and Ctrl+0 change it too, and the size is remembered between runs. +- **Back takes you to where you were.** Back, Forward and Up in My files return to a folder + scrolled where it was left, with the same items selected, and closing the photo viewer scrolls + the grid to the photo it was showing. Alt+Left and Backspace go back a level in Shared with me + and Computers and leave an open album or place in Photos, as Escape does too. + ### Changed - **`proton-sdk` and `proton-drive-rs` 0.11.0.** Timestamps are converted where they enter @@ -131,6 +136,9 @@ Existing folders stay device backups. Older builds cannot open the upgraded data - **A search in My files stays.** It was replaced by the folder's listing whenever files changed, on refresh and on coming back to the page, while the query stayed in the box. +- **A date jump in Photos stops when you look elsewhere.** A jump still loading the timeline + kept going after another filter, album or place was opened. + ## [3.7.0] — 2026-11-02 Schema: **44**, unchanged. diff --git a/po/de.po b/po/de.po index 57e8372..a656e2d 100644 --- a/po/de.po +++ b/po/de.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: proton-drive-linux 2.1.0\n" "Report-Msgid-Bugs-To: https://github.com/narrrl/proton-drive-linux/issues\n" -"POT-Creation-Date: 2026-11-14 02:49+0100\n" +"POT-Creation-Date: 2026-11-14 12:53+0100\n" "PO-Revision-Date: 2026-09-23 12:00+0200\n" "Last-Translator: Proton Drive for Linux contributors\n" "Language-Team: German\n" @@ -31,7 +31,7 @@ msgstr[1] "vor {n} Min." #. Translators: strftime format for the time a photo was taken, shown on its tile, such as "14:05". #: crates/pdfs-gui/src/app/dates.rs:44 #: crates/pdfs-gui/src/app/pages/activity.rs:840 -#: crates/pdfs-gui/src/app/pages/photos.rs:3534 +#: crates/pdfs-gui/src/app/pages/photos.rs:3544 msgid "%H:%M" msgstr "%H:%M" @@ -57,87 +57,87 @@ msgstr "%-d. %b %Y" msgid "%A, %B %-d, %Y, %H:%M" msgstr "%A, %-d. %B %Y, %H:%M" -#: crates/pdfs-gui/src/app/main.rs:865 +#: crates/pdfs-gui/src/app/main.rs:876 #: crates/pdfs-gui/src/app/pages/activity_text.rs:543 -#: crates/pdfs-gui/src/app/pages/browser.rs:458 -#: crates/pdfs-gui/src/app/pages/browser.rs:865 -#: crates/pdfs-gui/src/app/pages/browser.rs:1281 -#: crates/pdfs-gui/src/app/pages/browser.rs:2240 -#: crates/pdfs-gui/src/app/pages/browser.rs:2319 +#: crates/pdfs-gui/src/app/pages/browser.rs:473 +#: crates/pdfs-gui/src/app/pages/browser.rs:880 +#: crates/pdfs-gui/src/app/pages/browser.rs:1296 +#: crates/pdfs-gui/src/app/pages/browser.rs:2281 +#: crates/pdfs-gui/src/app/pages/browser.rs:2360 #: crates/pdfs-gui/src/app/pages/locations.rs:1721 #: crates/pdfs-gui/src/app/pages/shared_by_me.rs:252 #: crates/pdfs-gui/src/app/pages/trash.rs:191 crates/pdfs-gui/src/prompt.rs:171 msgid "My files" msgstr "Meine Dateien" -#: crates/pdfs-gui/src/app/main.rs:866 crates/pdfs-gui/src/app/main.rs:1536 +#: crates/pdfs-gui/src/app/main.rs:877 crates/pdfs-gui/src/app/main.rs:1547 #: crates/pdfs-gui/src/app/pages/albums.rs:636 #: crates/pdfs-gui/src/app/pages/photos.rs:898 -#: crates/pdfs-gui/src/app/pages/places.rs:439 +#: crates/pdfs-gui/src/app/pages/places.rs:463 msgid "Photos" msgstr "Fotos" -#: crates/pdfs-gui/src/app/main.rs:869 +#: crates/pdfs-gui/src/app/main.rs:880 #: crates/pdfs-gui/src/app/pages/shared.rs:168 -#: crates/pdfs-gui/src/app/pages/shared.rs:484 +#: crates/pdfs-gui/src/app/pages/shared.rs:493 msgid "Shared with me" msgstr "Mit mir geteilt" -#: crates/pdfs-gui/src/app/main.rs:874 +#: crates/pdfs-gui/src/app/main.rs:885 #: crates/pdfs-gui/src/app/pages/shared_by_me.rs:120 msgid "Shared by me" msgstr "Von mir geteilt" -#: crates/pdfs-gui/src/app/main.rs:877 +#: crates/pdfs-gui/src/app/main.rs:888 #: crates/pdfs-gui/src/app/pages/devices.rs:140 -#: crates/pdfs-gui/src/app/pages/devices.rs:493 +#: crates/pdfs-gui/src/app/pages/devices.rs:505 msgid "Computers" msgstr "Computer" -#: crates/pdfs-gui/src/app/main.rs:878 +#: crates/pdfs-gui/src/app/main.rs:889 #: crates/pdfs-gui/src/app/pages/trash.rs:101 msgid "Trash" msgstr "Papierkorb" #. Translators: sidebar entry for the page listing this computer's synced folders. -#: crates/pdfs-gui/src/app/main.rs:880 +#: crates/pdfs-gui/src/app/main.rs:891 msgid "Sync" msgstr "Synchronisierung" #. Translators: a failed action's toast. {what} says what failed, such as #. "Couldn't rename"; {detail} is the reason, usually untranslated text #. from the mount service. -#: crates/pdfs-gui/src/app/main.rs:1230 +#: crates/pdfs-gui/src/app/main.rs:1241 #: crates/pdfs-gui/src/app/pages/takeout.rs:714 #, rust-format msgid "{what}: {detail}" msgstr "{what}: {detail}" -#: crates/pdfs-gui/src/app/main.rs:1253 +#: crates/pdfs-gui/src/app/main.rs:1264 msgid "You're offline" msgstr "Keine Internetverbindung" -#: crates/pdfs-gui/src/app/main.rs:1254 +#: crates/pdfs-gui/src/app/main.rs:1265 msgid "That's not there any more" msgstr "Das ist nicht mehr vorhanden" -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1266 msgid "You don't have access to that" msgstr "Kein Zugriff darauf" -#: crates/pdfs-gui/src/app/main.rs:1256 +#: crates/pdfs-gui/src/app/main.rs:1267 msgid "Something changed this first" msgstr "Etwas anderes hat dies zuerst geändert" -#: crates/pdfs-gui/src/app/main.rs:1257 +#: crates/pdfs-gui/src/app/main.rs:1268 msgid "Your Proton Drive is full" msgstr "Das Proton Drive ist voll" -#: crates/pdfs-gui/src/app/main.rs:1344 +#: crates/pdfs-gui/src/app/main.rs:1355 msgid "Proton Drive for Linux" msgstr "Proton Drive for Linux" -#: crates/pdfs-gui/src/app/main.rs:1352 +#: crates/pdfs-gui/src/app/main.rs:1363 msgid "" "Files-on-demand Proton Drive for the Linux desktop.\n" "\n" @@ -149,23 +149,23 @@ msgstr "" "Inoffizieller Client – nicht mit Proton AG verbunden, von Proton AG " "unterstützt oder befürwortet." -#: crates/pdfs-gui/src/app/main.rs:1357 +#: crates/pdfs-gui/src/app/main.rs:1368 msgid "Source Code" msgstr "Quellcode" -#: crates/pdfs-gui/src/app/main.rs:1361 +#: crates/pdfs-gui/src/app/main.rs:1372 msgid "Proton Terms of Service" msgstr "Nutzungsbedingungen von Proton" -#: crates/pdfs-gui/src/app/main.rs:1365 +#: crates/pdfs-gui/src/app/main.rs:1376 msgid "Proton Privacy Policy" msgstr "Datenschutzerklärung von Proton" -#: crates/pdfs-gui/src/app/main.rs:1370 +#: crates/pdfs-gui/src/app/main.rs:1381 msgid "Disclaimer" msgstr "Haftungsausschluss" -#: crates/pdfs-gui/src/app/main.rs:1374 +#: crates/pdfs-gui/src/app/main.rs:1385 msgid "" "This is an unofficial, community-built client. It is not affiliated with, " "endorsed by, or supported by Proton AG.\n" @@ -190,7 +190,7 @@ msgstr "" "bereitgestellt. Daten, deren Verlust nicht hinnehmbar ist, sollten " "zusätzlich gesichert werden." -#: crates/pdfs-gui/src/app/main.rs:1382 +#: crates/pdfs-gui/src/app/main.rs:1393 msgid "" "Places are named with data from GeoNames, licensed under GeoNames, lizenziert unter CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -210,7 +210,7 @@ msgstr "" "href=\"https://www.naturalearthdata.com/\">Natural Earth gezeichnet, die " "gemeinfrei sind." -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, licensed under CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -207,7 +207,7 @@ msgstr "" "\">Natural Earth land outlines and country borders, which are in the " "public domain." -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, con licencia CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -208,7 +208,7 @@ msgstr "" "fronteras de países de Natural " "Earth, que son de dominio público." -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, sous licence CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -209,7 +209,7 @@ msgstr "" "frontières des pays de Natural " "Earth, qui sont dans le domaine public." -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, con licenza CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -207,7 +207,7 @@ msgstr "" "confini nazionali di Natural " "Earth, che sono di pubblico dominio." -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, gelicentieerd onder CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -208,7 +208,7 @@ msgstr "" "href=\"https://www.naturalearthdata.com/\">Natural Earth, die in het " "publieke domein vallen." -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the \n" "Language-Team: LANGUAGE \n" @@ -34,7 +34,7 @@ msgstr[1] "" #. Translators: strftime format for the time a photo was taken, shown on its tile, such as "14:05". #: crates/pdfs-gui/src/app/dates.rs:44 #: crates/pdfs-gui/src/app/pages/activity.rs:840 -#: crates/pdfs-gui/src/app/pages/photos.rs:3534 +#: crates/pdfs-gui/src/app/pages/photos.rs:3544 msgid "%H:%M" msgstr "" @@ -60,87 +60,87 @@ msgstr "" msgid "%A, %B %-d, %Y, %H:%M" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:865 +#: crates/pdfs-gui/src/app/main.rs:876 #: crates/pdfs-gui/src/app/pages/activity_text.rs:543 -#: crates/pdfs-gui/src/app/pages/browser.rs:458 -#: crates/pdfs-gui/src/app/pages/browser.rs:865 -#: crates/pdfs-gui/src/app/pages/browser.rs:1281 -#: crates/pdfs-gui/src/app/pages/browser.rs:2240 -#: crates/pdfs-gui/src/app/pages/browser.rs:2319 +#: crates/pdfs-gui/src/app/pages/browser.rs:473 +#: crates/pdfs-gui/src/app/pages/browser.rs:880 +#: crates/pdfs-gui/src/app/pages/browser.rs:1296 +#: crates/pdfs-gui/src/app/pages/browser.rs:2281 +#: crates/pdfs-gui/src/app/pages/browser.rs:2360 #: crates/pdfs-gui/src/app/pages/locations.rs:1721 #: crates/pdfs-gui/src/app/pages/shared_by_me.rs:252 #: crates/pdfs-gui/src/app/pages/trash.rs:191 crates/pdfs-gui/src/prompt.rs:171 msgid "My files" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:866 crates/pdfs-gui/src/app/main.rs:1536 +#: crates/pdfs-gui/src/app/main.rs:877 crates/pdfs-gui/src/app/main.rs:1547 #: crates/pdfs-gui/src/app/pages/albums.rs:636 #: crates/pdfs-gui/src/app/pages/photos.rs:898 -#: crates/pdfs-gui/src/app/pages/places.rs:439 +#: crates/pdfs-gui/src/app/pages/places.rs:463 msgid "Photos" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:869 +#: crates/pdfs-gui/src/app/main.rs:880 #: crates/pdfs-gui/src/app/pages/shared.rs:168 -#: crates/pdfs-gui/src/app/pages/shared.rs:484 +#: crates/pdfs-gui/src/app/pages/shared.rs:493 msgid "Shared with me" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:874 +#: crates/pdfs-gui/src/app/main.rs:885 #: crates/pdfs-gui/src/app/pages/shared_by_me.rs:120 msgid "Shared by me" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:877 +#: crates/pdfs-gui/src/app/main.rs:888 #: crates/pdfs-gui/src/app/pages/devices.rs:140 -#: crates/pdfs-gui/src/app/pages/devices.rs:493 +#: crates/pdfs-gui/src/app/pages/devices.rs:505 msgid "Computers" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:878 +#: crates/pdfs-gui/src/app/main.rs:889 #: crates/pdfs-gui/src/app/pages/trash.rs:101 msgid "Trash" msgstr "" #. Translators: sidebar entry for the page listing this computer's synced folders. -#: crates/pdfs-gui/src/app/main.rs:880 +#: crates/pdfs-gui/src/app/main.rs:891 msgid "Sync" msgstr "" #. Translators: a failed action's toast. {what} says what failed, such as #. "Couldn't rename"; {detail} is the reason, usually untranslated text #. from the mount service. -#: crates/pdfs-gui/src/app/main.rs:1230 +#: crates/pdfs-gui/src/app/main.rs:1241 #: crates/pdfs-gui/src/app/pages/takeout.rs:714 #, rust-format msgid "{what}: {detail}" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1253 +#: crates/pdfs-gui/src/app/main.rs:1264 msgid "You're offline" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1254 +#: crates/pdfs-gui/src/app/main.rs:1265 msgid "That's not there any more" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1266 msgid "You don't have access to that" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1256 +#: crates/pdfs-gui/src/app/main.rs:1267 msgid "Something changed this first" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1257 +#: crates/pdfs-gui/src/app/main.rs:1268 msgid "Your Proton Drive is full" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1344 +#: crates/pdfs-gui/src/app/main.rs:1355 msgid "Proton Drive for Linux" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1352 +#: crates/pdfs-gui/src/app/main.rs:1363 msgid "" "Files-on-demand Proton Drive for the Linux desktop.\n" "\n" @@ -148,23 +148,23 @@ msgid "" "AG." msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1357 +#: crates/pdfs-gui/src/app/main.rs:1368 msgid "Source Code" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1361 +#: crates/pdfs-gui/src/app/main.rs:1372 msgid "Proton Terms of Service" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1365 +#: crates/pdfs-gui/src/app/main.rs:1376 msgid "Proton Privacy Policy" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1370 +#: crates/pdfs-gui/src/app/main.rs:1381 msgid "Disclaimer" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1374 +#: crates/pdfs-gui/src/app/main.rs:1385 msgid "" "This is an unofficial, community-built client. It is not affiliated with, " "endorsed by, or supported by Proton AG.\n" @@ -177,21 +177,21 @@ msgid "" "of any data you cannot afford to lose." msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1382 +#: crates/pdfs-gui/src/app/main.rs:1393 msgid "" "Places are named with data from GeoNames, licensed under CC BY 4.0." msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " "public domain." msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames udostępnionych na licencji CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -211,7 +211,7 @@ msgstr "" "www.naturalearthdata.com/\">Natural Earth, które należą do domeny " "publicznej." -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, licenciados sob CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1390 +#: crates/pdfs-gui/src/app/main.rs:1401 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -207,7 +207,7 @@ msgstr "" "fronteiras de países do Natural Earth, que são de domínio público." -#: crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:1409 msgid "" "The street map, when turned on, comes from OpenFreeMap in the