263 lines
7.5 KiB
Dart
263 lines
7.5 KiB
Dart
import 'dart:async';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:aves/model/entry/entry.dart';
|
||
import 'package:aves/model/selection.dart';
|
||
import 'package:aves/model/settings/settings.dart';
|
||
import 'package:aves/model/source/collection_lens.dart';
|
||
import 'package:aves/model/source/collection_source.dart';
|
||
import 'package:aves/services/common/services.dart';
|
||
import 'package:aves/widgets/collection/actions/entry_actions.dart';
|
||
import 'package:aves/widgets/collection/actions/entry_action_dialogs.dart';
|
||
import 'package:aves/widgets/collection/actions/entry_action_edit.dart';
|
||
import 'package:aves/widgets/collection/actions/entry_action_cast.dart';
|
||
import 'package:aves/widgets/collection/actions/entry_action_utils.dart';
|
||
import 'package:aves/widgets/dialogs/aves_confirmation_dialog.dart';
|
||
import 'package:aves/widgets/dialogs/convert_entry_dialog.dart';
|
||
import 'package:aves/widgets/map/map_page.dart';
|
||
import 'package:aves/widgets/common/search/route.dart';
|
||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||
|
||
/// Gestore principale delle azioni sugli entry.
|
||
/// Versione ultra‑ottimizzata, senza album, senza filter_grids.
|
||
class EntryActionHandlers {
|
||
final BuildContext context;
|
||
final CollectionLens collection;
|
||
final AvesSelection selection;
|
||
|
||
EntryActionHandlers({
|
||
required this.context,
|
||
required this.collection,
|
||
required this.selection,
|
||
});
|
||
|
||
/// Esegue l’azione richiesta.
|
||
Future<void> run(EntryAction action) async {
|
||
final entries = selection.selectedEntries.toList();
|
||
if (entries.isEmpty && !_actionAllowsEmptySelection(action)) {
|
||
return;
|
||
}
|
||
|
||
switch (action) {
|
||
// Navigazione
|
||
case EntryAction.configureView:
|
||
return _configureView();
|
||
case EntryAction.searchCollection:
|
||
return _search();
|
||
case EntryAction.map:
|
||
return _openMap(entries);
|
||
case EntryAction.slideshow:
|
||
return _slideshow(entries);
|
||
case EntryAction.stats:
|
||
return _stats(entries);
|
||
case EntryAction.rescan:
|
||
return _rescan();
|
||
|
||
// Selezione
|
||
case EntryAction.select:
|
||
return selection.toggle(entries.first);
|
||
case EntryAction.selectAll:
|
||
return selection.selectAll();
|
||
case EntryAction.selectNone:
|
||
return selection.clear();
|
||
|
||
// Cast
|
||
case EntryAction.cast:
|
||
return EntryActionCast(context, entries).startCast();
|
||
|
||
// File operations
|
||
case EntryAction.share:
|
||
return _share(entries);
|
||
case EntryAction.delete:
|
||
return _delete(entries);
|
||
case EntryAction.copy:
|
||
return _copy(entries);
|
||
case EntryAction.move:
|
||
return _move(entries);
|
||
case EntryAction.rename:
|
||
return _rename(entries);
|
||
case EntryAction.convert:
|
||
return _convert(entries);
|
||
|
||
// Metadata
|
||
case EntryAction.toggleFavourite:
|
||
return _toggleFavourite(entries);
|
||
case EntryAction.rotateCW:
|
||
return EntryActionEdit.rotateCW(context, entries);
|
||
case EntryAction.rotateCCW:
|
||
return EntryActionEdit.rotateCCW(context, entries);
|
||
case EntryAction.flip:
|
||
return EntryActionEdit.flip(context, entries);
|
||
case EntryAction.editDate:
|
||
return _editDate(entries);
|
||
case EntryAction.editLocation:
|
||
return _editLocation(entries);
|
||
case EntryAction.editTitleDescription:
|
||
return _editTitleDescription(entries);
|
||
case EntryAction.editRating:
|
||
return _editRating(entries);
|
||
case EntryAction.editTags:
|
||
return _editTags(entries);
|
||
case EntryAction.removeMetadata:
|
||
return _removeMetadata(entries);
|
||
}
|
||
}
|
||
|
||
// ------------------------------------------------------------
|
||
// NAVIGAZIONE
|
||
// ------------------------------------------------------------
|
||
|
||
Future<void> _configureView() async {
|
||
settings.configureView = !settings.configureView;
|
||
}
|
||
|
||
Future<void> _search() async {
|
||
Navigator.push(
|
||
context,
|
||
SearchPageRoute(
|
||
collection: collection,
|
||
),
|
||
);
|
||
}
|
||
|
||
Future<void> _openMap(List<AvesEntry> entries) async {
|
||
if (entries.isEmpty) return;
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (_) => MapPage(entries: entries),
|
||
),
|
||
);
|
||
}
|
||
|
||
Future<void> _slideshow(List<AvesEntry> entries) async {
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => SlideshowDialog(entries: entries),
|
||
);
|
||
}
|
||
|
||
Future<void> _stats(List<AvesEntry> entries) async {
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => StatsDialog(entries: entries),
|
||
);
|
||
}
|
||
|
||
Future<void> _rescan() async {
|
||
await collection.source.reload();
|
||
}
|
||
|
||
// ------------------------------------------------------------
|
||
// FILE OPERATIONS
|
||
// ------------------------------------------------------------
|
||
|
||
Future<void> _share(List<AvesEntry> entries) async {
|
||
await appService.share(entries);
|
||
}
|
||
|
||
Future<void> _delete(List<AvesEntry> entries) async {
|
||
final confirmed = await showDialog<bool>(
|
||
context: context,
|
||
builder: (_) => AvesConfirmationDialog(
|
||
title: 'Elimina',
|
||
message: 'Vuoi eliminare ${entries.length} elementi?',
|
||
),
|
||
);
|
||
if (confirmed != true) return;
|
||
|
||
await appService.delete(entries);
|
||
selection.clear();
|
||
}
|
||
|
||
Future<void> _copy(List<AvesEntry> entries) async {
|
||
await EntryActionUtils.copyEntries(context, entries);
|
||
}
|
||
|
||
Future<void> _move(List<AvesEntry> entries) async {
|
||
await EntryActionUtils.moveEntries(context, entries);
|
||
}
|
||
|
||
Future<void> _rename(List<AvesEntry> entries) async {
|
||
if (entries.length != 1) return;
|
||
|
||
await Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (_) => RenameEntrySetPage(entries: entries),
|
||
),
|
||
);
|
||
}
|
||
|
||
Future<void> _convert(List<AvesEntry> entries) async {
|
||
if (entries.length != 1) return;
|
||
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => ConvertEntryDialog(entry: entries.first),
|
||
);
|
||
}
|
||
|
||
// ------------------------------------------------------------
|
||
// METADATA
|
||
// ------------------------------------------------------------
|
||
|
||
Future<void> _toggleFavourite(List<AvesEntry> entries) async {
|
||
for (final entry in entries) {
|
||
entry.toggleFavourite();
|
||
}
|
||
}
|
||
|
||
Future<void> _editDate(List<AvesEntry> entries) async {
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => EditDateDialog(entries: entries),
|
||
);
|
||
}
|
||
|
||
Future<void> _editLocation(List<AvesEntry> entries) async {
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => EditLocationDialog(entries: entries),
|
||
);
|
||
}
|
||
|
||
Future<void> _editTitleDescription(List<AvesEntry> entries) async {
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => EditTitleDescriptionDialog(entries: entries),
|
||
);
|
||
}
|
||
|
||
Future<void> _editRating(List<AvesEntry> entries) async {
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => EditRatingDialog(entries: entries),
|
||
);
|
||
}
|
||
|
||
Future<void> _editTags(List<AvesEntry> entries) async {
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => EditTagsDialog(entries: entries),
|
||
);
|
||
}
|
||
|
||
Future<void> _removeMetadata(List<AvesEntry> entries) async {
|
||
await showDialog(
|
||
context: context,
|
||
builder: (_) => RemoveMetadataDialog(entries: entries),
|
||
);
|
||
}
|
||
|
||
// ------------------------------------------------------------
|
||
// UTILS
|
||
// ------------------------------------------------------------
|
||
|
||
bool _actionAllowsEmptySelection(EntryAction action) {
|
||
return {
|
||
EntryAction.configureView,
|
||
EntryAction.searchCollection,
|
||
EntryAction.rescan,
|
||
}.contains(action);
|
||
}
|
||
}
|