mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-03 16:41:26 +01:00
feat(gui): shared selection and rubberband in My Files
The grid and column view wrap one MultiSelection instead of one each, so a selection survives switching layout, and both views enable rubberband selection.
This commit is contained in:
1 parent
8d0a575a7c
commit
abf76cd5e8
4 files changed
+30
-37
No files matched your search
@@ -435,8 +435,7 @@ fn build_window(app: &adw::Application) {
|
||||
details: browser_widgets.details,
|
||||
details_entry: RefCell::new(None),
|
||||
details_suppress: Cell::new(false),
|
||||
grid_selection: browser_widgets.grid_selection.clone(),
|
||||
list_selection: browser_widgets.list_selection.clone(),
|
||||
selection: browser_widgets.selection.clone(),
|
||||
},
|
||||
trash: TrashState {
|
||||
model: trash_widgets.model.clone(),
|
||||
|
||||
@@ -53,8 +53,7 @@ pub(crate) struct BrowserState {
|
||||
/// requested repeatedly, so comparing their text alone cannot reject an
|
||||
/// older response that finishes after a manual refresh.
|
||||
pub(crate) load_generation: Cell<u64>,
|
||||
/// The grid/list view stack, read to find out which of the two selections is
|
||||
/// the one the user is actually working in.
|
||||
/// The grid/list view stack, read to find out which view is on screen.
|
||||
pub(crate) views: gtk4::Stack,
|
||||
/// The bulk-action bar, revealed once more than one entry is selected.
|
||||
pub(crate) bulk: gtk4::Revealer,
|
||||
@@ -138,11 +137,10 @@ pub(crate) struct BrowserWidgets {
|
||||
/// Wraps the views + the details pane; the pane slides in on selection.
|
||||
pub(crate) split: adw::OverlaySplitView,
|
||||
pub(crate) details: DetailsWidgets,
|
||||
/// The two selection models, so a selection change can drive the details pane
|
||||
/// and so an action can re-read the entries the user has highlighted.
|
||||
pub(crate) grid_selection: gtk4::MultiSelection,
|
||||
pub(crate) list_selection: gtk4::MultiSelection,
|
||||
/// The grid/list stack, so the page can tell which selection is live.
|
||||
/// The selection shared by both views, so a selection change can drive the
|
||||
/// details pane and an action can re-read the entries the user highlighted.
|
||||
pub(crate) selection: gtk4::MultiSelection,
|
||||
/// The grid/list stack, so the page can tell which view is on screen.
|
||||
pub(crate) views: gtk4::Stack,
|
||||
pub(crate) bulk: gtk4::Revealer,
|
||||
pub(crate) bulk_label: gtk4::Label,
|
||||
@@ -310,11 +308,14 @@ pub(crate) fn build_browser_page() -> (gtk4::Widget, BrowserWidgets) {
|
||||
// Icon grid. Multi-select: acting on a batch is the common case for trashing
|
||||
// and for taking a folder's worth of files offline, and doing it one
|
||||
// confirmation dialog at a time is not a workflow.
|
||||
let grid_selection = gtk4::MultiSelection::new(Some(model.clone()));
|
||||
// One selection for both views: switching layout keeps what is selected.
|
||||
// Rubberband drags a selection box from empty space, as a file manager does.
|
||||
let selection = gtk4::MultiSelection::new(Some(model.clone()));
|
||||
let grid = gtk4::GridView::builder()
|
||||
.model(&grid_selection)
|
||||
.model(&selection)
|
||||
.min_columns(2)
|
||||
.max_columns(10)
|
||||
.enable_rubberband(true)
|
||||
.build();
|
||||
grid.add_css_class("file-grid");
|
||||
let grid_scroll = gtk4::ScrolledWindow::builder()
|
||||
@@ -322,9 +323,11 @@ pub(crate) fn build_browser_page() -> (gtk4::Widget, BrowserWidgets) {
|
||||
.child(&grid)
|
||||
.build();
|
||||
|
||||
// Column list, with its own selection over the same model.
|
||||
let list_selection = gtk4::MultiSelection::new(Some(model.clone()));
|
||||
let column_view = gtk4::ColumnView::builder().model(&list_selection).build();
|
||||
// Column list, over the same selection.
|
||||
let column_view = gtk4::ColumnView::builder()
|
||||
.model(&selection)
|
||||
.enable_rubberband(true)
|
||||
.build();
|
||||
column_view.add_css_class("data-table");
|
||||
let column_scroll = gtk4::ScrolledWindow::builder()
|
||||
.vexpand(true)
|
||||
@@ -519,8 +522,7 @@ pub(crate) fn build_browser_page() -> (gtk4::Widget, BrowserWidgets) {
|
||||
refresh,
|
||||
split,
|
||||
details,
|
||||
grid_selection,
|
||||
list_selection,
|
||||
selection,
|
||||
views: view_stack,
|
||||
bulk,
|
||||
bulk_label,
|
||||
@@ -550,15 +552,9 @@ pub(crate) fn browser_status(ui: &Rc<Ui>, icon: &str, title: &str, description:
|
||||
hide_details(ui);
|
||||
}
|
||||
|
||||
/// The selection model of whichever view is on screen. The grid and the list
|
||||
/// each own one over the same model, so "what is selected" depends on which the
|
||||
/// user is looking at.
|
||||
/// The selection model shared by the grid and the list.
|
||||
pub(crate) fn active_selection(ui: &Rc<Ui>) -> gtk4::MultiSelection {
|
||||
if ui.browser.views.visible_child_name().as_deref() == Some("list") {
|
||||
ui.details.list_selection.clone()
|
||||
} else {
|
||||
ui.details.grid_selection.clone()
|
||||
}
|
||||
ui.details.selection.clone()
|
||||
}
|
||||
|
||||
/// Every entry highlighted in the view on screen, in model order.
|
||||
@@ -575,10 +571,9 @@ pub(crate) fn selected_entries(ui: &Rc<Ui>) -> Vec<DirEntry> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Drop the selection in both views, which also retracts the bulk bar.
|
||||
/// Drop the selection, which also retracts the bulk bar.
|
||||
pub(crate) fn clear_selection(ui: &Rc<Ui>) {
|
||||
ui.details.grid_selection.unselect_all();
|
||||
ui.details.list_selection.unselect_all();
|
||||
ui.details.selection.unselect_all();
|
||||
}
|
||||
|
||||
/// Reflect the current selection in the bulk bar: how many are selected, and
|
||||
|
||||
@@ -9,10 +9,9 @@ pub(crate) struct DetailsState {
|
||||
/// Set while the details pane is being populated, so setting the offline
|
||||
/// switch programmatically doesn't fire a pin/unpin round-trip.
|
||||
pub(crate) details_suppress: Cell<bool>,
|
||||
/// The grid's and list's selection models. Both wrap the one browser model, so
|
||||
/// a selection in either drives the details pane.
|
||||
pub(crate) grid_selection: gtk4::MultiSelection,
|
||||
pub(crate) list_selection: gtk4::MultiSelection,
|
||||
/// The one selection model behind both the grid and the list, so switching
|
||||
/// views keeps what is selected; it drives the details pane.
|
||||
pub(crate) selection: gtk4::MultiSelection,
|
||||
}
|
||||
|
||||
/// The widgets in the browser's details pane that a selection repaints.
|
||||
@@ -152,13 +151,11 @@ pub(crate) fn build_details_pane() -> (gtk4::Widget, DetailsWidgets) {
|
||||
/// Connect the details pane: mirror the grid's and list's selection into it, and
|
||||
/// wire its buttons back onto the entry it's showing.
|
||||
pub(crate) fn wire_details(ui: &Rc<Ui>) {
|
||||
// Both views share one model but have their own selection, so watch both.
|
||||
for selection in [
|
||||
ui.details.grid_selection.clone(),
|
||||
ui.details.list_selection.clone(),
|
||||
] {
|
||||
{
|
||||
let ui_sel = ui.clone();
|
||||
selection.connect_selection_changed(move |_, _, _| {
|
||||
ui.details
|
||||
.selection
|
||||
.connect_selection_changed(move |_, _, _| {
|
||||
// The details pane describes *one* entry. A batch is the bulk bar's
|
||||
// business, so the pane steps aside rather than picking a member of
|
||||
// the selection to speak for the rest.
|
||||
|
||||
@@ -72,6 +72,8 @@ Schema: **31** (unchanged).
|
||||
Copy Link · Rename…, Move To…, Versions… · Move to Trash. Right-clicking empty space offers New
|
||||
Folder, the uploads, Select All, Refresh and Open in File Manager. Open With… asks which
|
||||
application to use.
|
||||
- **One selection in My Files.** The grid and the list share their selection, so switching views
|
||||
keeps what is selected, and dragging across empty space draws a selection box in both.
|
||||
- **US spelling throughout.** The app, the CLI and the docs say "Favorite" and "color", matching the
|
||||
`pdfs favorite` command.
|
||||
|
||||
|
||||
Reference in new issue
Block a user