Files
SpotiFLAC-Mobile/lib/screens/selection_mode_mixin.dart
T
zarzet 44de61a06a refactor(screens): share album-screen scaffolding and track flows
- SelectionModeMixin + CollapsingHeaderScrollMixin extracted;
  local/downloaded album screens now share AlbumTrackTile,
  AlbumScaffoldBody, DestructiveSelectionButton, HeaderMetaRow,
  and confirmAndDeleteTracks
- track_detail_actions.dart: shared downloadSingleTrack,
  queueTracksSkippingDownloaded, download-all confirm, queued
  snackbar, release-date formatter, list footer, love-all
- TtlCache<T> replaces the copied 10-minute static caches;
  album fetch branches share _applyAlbumMetadata
- playlist error card now uses ErrorCard; formatMegabytes shared
  by queue tab and update dialog
2026-07-12 19:19:22 +07:00

57 lines
1.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/// Shared multi-select state for list screens: enter/exit selection mode,
/// toggle individual items, select all, and prune ids that fell out of the
/// current item list. Mix into a `State<T>` alongside the screen's own
/// per-item lookups (e.g. queue_tab, library_folder, artist screens).
mixin SelectionModeMixin<T extends StatefulWidget> on State<T> {
bool isSelectionMode = false;
final Set<String> selectedIds = {};
void enterSelectionMode(String itemId) {
HapticFeedback.mediumImpact();
setState(() {
isSelectionMode = true;
selectedIds.add(itemId);
});
}
void exitSelectionMode() {
setState(() {
isSelectionMode = false;
selectedIds.clear();
});
}
void toggleSelection(String itemId) {
setState(() {
if (selectedIds.contains(itemId)) {
selectedIds.remove(itemId);
if (selectedIds.isEmpty) {
isSelectionMode = false;
}
} else {
selectedIds.add(itemId);
}
});
}
void selectAll(Iterable<String> ids) {
setState(() {
selectedIds.addAll(ids);
});
}
/// Drops ids no longer present in [validIds]; call from build() with the
/// current item ids. Exits selection mode next frame if that empties it.
void pruneSelection(Set<String> validIds) {
selectedIds.removeWhere((id) => !validIds.contains(id));
if (selectedIds.isEmpty && isSelectionMode) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) setState(() => isSelectionMode = false);
});
}
}
}