Files
noo/lib/models/selection_action.dart
ayushya 254db255a7 Add a Settings option to reorder the selection action bar's actions
NooSelectionBar's fixed inline slots (3 mobile / 4 desktop, the rest
behind "More") previously just took the first N actions in whatever
order each screen happened to build them in. Give bulk actions a
stable SelectionActionKind identity (independent of their dynamic
icon/label, e.g. favorite vs. unfavorite) so Settings can offer a
drag-to-reorder list - mirroring the existing Tabs section, minus the
pin/hide concept, which doesn't apply here - and each screen applies
that saved priority order via orderSelectionActions before handing
its action list to the bar.
2026-09-28 12:21:36 -04:00

92 lines
3.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
/// A bulk action's identity, stable across the dynamic icon/label a
/// [SelectionAction] actually renders (e.g. `favorite` covers both
/// "Favorite" and "Remove from favorites"). This is what the user's
/// configured [order] - Settings' "Action bar" reorder list - and
/// [NooSelectionBar]'s inline/overflow split key off, since the live
/// [SelectionAction] list is rebuilt fresh on every selection change and
/// can't be compared by icon/label alone.
///
/// Not every screen offers every kind (e.g. Favorites has no `rename` or
/// `sync`) - [orderSelectionActions] just skips whatever kind a screen
/// didn't build.
enum SelectionActionKind {
favorite,
share,
download,
delete,
copy,
move,
rename,
sync,
details;
/// Generic label for the Settings reorder row - the live bar uses each
/// screen's own contextual label (e.g. "Remove from favorites") instead.
String get label => switch (this) {
SelectionActionKind.favorite => 'Favorite',
SelectionActionKind.share => 'Share',
SelectionActionKind.download => 'Download',
SelectionActionKind.delete => 'Delete',
SelectionActionKind.copy => 'Copy',
SelectionActionKind.move => 'Move',
SelectionActionKind.rename => 'Rename',
SelectionActionKind.sync => 'Sync to device',
SelectionActionKind.details => 'Details',
};
IconData get icon => switch (this) {
SelectionActionKind.favorite => LucideIcons.star,
SelectionActionKind.share => LucideIcons.share2,
SelectionActionKind.download => LucideIcons.download,
SelectionActionKind.delete => LucideIcons.trash2,
SelectionActionKind.copy => LucideIcons.copy,
SelectionActionKind.move => LucideIcons.folderInput,
SelectionActionKind.rename => LucideIcons.filePen,
SelectionActionKind.sync => LucideIcons.hardDriveDownload,
SelectionActionKind.details => LucideIcons.info,
};
}
/// One bulk action available for the current multi-selection (e.g. favorite,
/// download, delete), shown as an icon button in the sticky selection
/// toolbar each tab (Files, Photos, ...) renders inline in its own content.
class SelectionAction {
final SelectionActionKind kind;
final IconData icon;
final String label;
final VoidCallback onTap;
const SelectionAction({
required this.kind,
required this.icon,
required this.label,
required this.onTap,
});
}
/// Reorders [actions] to match the user's configured [order] (Settings'
/// "Action bar" section, [SelectionActionKind] values) - this is what makes
/// that setting take effect, since it's [order] that decides which actions
/// land in `NooSelectionBar`'s inline slots vs. behind "More". A kind in
/// [order] the caller didn't build (e.g. `rename` on a multi-item
/// selection) is just skipped; a kind [actions] has that [order] doesn't
/// mention (e.g. a kind added in a later app update, before the saved
/// order is migrated - see [SettingsController.selectionActionOrder]) is
/// appended at the end in its original position.
List<SelectionAction> orderSelectionActions(
List<SelectionAction> actions,
List<SelectionActionKind> order,
) {
final byKind = {for (final a in actions) a.kind: a};
final ordered = <SelectionAction>[];
for (final kind in order) {
final action = byKind.remove(kind);
if (action != null) ordered.add(action);
}
ordered.addAll(byKind.values);
return ordered;
}