247 lines
5.8 KiB
Dart
247 lines
5.8 KiB
Dart
// lib/widgets/collection/album_controller.dart
|
|
import 'package:aves/model/db/db.dart';
|
|
import 'package:aves/model/db/folder_content_type.dart';
|
|
import 'package:aves/model/entry/entry.dart';
|
|
import 'package:aves/model/vaults/vaults.dart';
|
|
import 'package:aves/services/common/services.dart' as services;
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'album_sort.dart';
|
|
|
|
/// Controller che gestisce la lista degli album basata sulla tabella `folders`.
|
|
class AlbumController extends ChangeNotifier {
|
|
final LocalMediaDb localMediaDb;
|
|
|
|
AlbumController({
|
|
LocalMediaDb? localMediaDb,
|
|
}) : localMediaDb = localMediaDb ?? services.localMediaDb;
|
|
|
|
bool loading = true;
|
|
|
|
List<AlbumRow> _allAlbums = [];
|
|
|
|
AlbumSortType _sortType = AlbumSortType.priorityThenName;
|
|
|
|
List<AlbumRow> get allAlbums => List.unmodifiable(_allAlbums);
|
|
|
|
Future<void> load() async {
|
|
loading = true;
|
|
notifyListeners();
|
|
|
|
final rows = await localMediaDb.loadFolders(
|
|
contentType: FolderContentType.media,
|
|
);
|
|
|
|
final entries = await localMediaDb.loadEntries();
|
|
final entriesMap = <int, AvesEntry>{
|
|
for (final entry in entries) entry.id: entry,
|
|
};
|
|
|
|
final list = <AlbumRow>[];
|
|
|
|
for (final row in rows) {
|
|
final thumbEntryId = row.thumbEntryId;
|
|
|
|
list.add(
|
|
AlbumRow(
|
|
path: row.path,
|
|
displayName: row.displayName,
|
|
albumType: row.albumType,
|
|
priority: row.priority,
|
|
totalSize: row.totalSize,
|
|
fileCount: row.fileCount,
|
|
isRemote: row.isRemote != 0,
|
|
isVault: vaults.vaultDirectories.contains(row.path),
|
|
hybridFolder: _parseHybridFolder(row.hybridFolder),
|
|
hidden: row.hidden == 1,
|
|
thumbEntry: thumbEntryId != null ? entriesMap[thumbEntryId] : null,
|
|
),
|
|
);
|
|
}
|
|
|
|
_allAlbums = sortAlbums(list, _sortType);
|
|
|
|
loading = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> refresh() async => load();
|
|
|
|
List<AlbumRow> get pinnedAlbums {
|
|
final list = _allAlbums.where((album) => album.priority > 0 && !album.hidden).toList();
|
|
|
|
list.sort((a, b) => a.priority.compareTo(b.priority));
|
|
|
|
return list;
|
|
}
|
|
|
|
List<AlbumRow> get normalAlbums {
|
|
final list = _allAlbums.where((album) => album.priority == 0 && !album.hidden).toList();
|
|
|
|
list.sort(_compareByNameAsc);
|
|
|
|
return list;
|
|
}
|
|
|
|
void sortBy(AlbumSortType type) {
|
|
_sortType = type;
|
|
|
|
switch (type) {
|
|
case AlbumSortType.priorityThenName:
|
|
_allAlbums.sort(_compareByPriorityThenName);
|
|
break;
|
|
|
|
case AlbumSortType.nameAsc:
|
|
_allAlbums.sort(_compareByNameAsc);
|
|
break;
|
|
|
|
case AlbumSortType.nameDesc:
|
|
_allAlbums.sort(_compareByNameDesc);
|
|
break;
|
|
|
|
case AlbumSortType.sizeAsc:
|
|
_allAlbums.sort(_compareBySizeAsc);
|
|
break;
|
|
|
|
default:
|
|
_allAlbums.sort(_compareByPriorityThenName);
|
|
break;
|
|
}
|
|
|
|
notifyListeners();
|
|
}
|
|
|
|
static int _compareByPriorityThenName(AlbumRow a, AlbumRow b) {
|
|
final aPinned = a.priority > 0;
|
|
final bPinned = b.priority > 0;
|
|
|
|
if (aPinned && !bPinned) return -1;
|
|
if (!aPinned && bPinned) return 1;
|
|
|
|
if (aPinned && bPinned) {
|
|
final priorityCompare = a.priority.compareTo(b.priority);
|
|
if (priorityCompare != 0) return priorityCompare;
|
|
}
|
|
|
|
return _compareByNameAsc(a, b);
|
|
}
|
|
|
|
static int _compareByNameAsc(AlbumRow a, AlbumRow b) {
|
|
return a.displayName.toLowerCase().compareTo(
|
|
b.displayName.toLowerCase(),
|
|
);
|
|
}
|
|
|
|
static int _compareByNameDesc(AlbumRow a, AlbumRow b) {
|
|
return b.displayName.toLowerCase().compareTo(
|
|
a.displayName.toLowerCase(),
|
|
);
|
|
}
|
|
|
|
static int _compareBySizeAsc(AlbumRow a, AlbumRow b) {
|
|
final sizeCompare = a.totalSize.compareTo(b.totalSize);
|
|
if (sizeCompare != 0) return sizeCompare;
|
|
|
|
return _compareByNameAsc(a, b);
|
|
}
|
|
|
|
Future<void> togglePin(AlbumRow album) async {
|
|
final db = localMediaDb as dynamic;
|
|
final newPriority = album.priority > 0 ? 0 : _computeNewPinPriority();
|
|
|
|
await db.updateFolderPriority(
|
|
album.path,
|
|
newPriority,
|
|
);
|
|
|
|
await load();
|
|
}
|
|
|
|
int _computeNewPinPriority() {
|
|
final pinned = pinnedAlbums;
|
|
if (pinned.isEmpty) return 1000;
|
|
|
|
return pinned.first.priority + 1000;
|
|
}
|
|
|
|
Future<void> reorderPinned(int oldIndex, int newIndex) async {
|
|
final db = localMediaDb as dynamic;
|
|
final pinned = pinnedAlbums;
|
|
|
|
if (newIndex > oldIndex) {
|
|
newIndex -= 1;
|
|
}
|
|
|
|
final item = pinned.removeAt(oldIndex);
|
|
pinned.insert(newIndex, item);
|
|
|
|
for (var i = 0; i < pinned.length; i++) {
|
|
final album = pinned[i];
|
|
final newPriority = i + 1;
|
|
|
|
if (album.priority != newPriority) {
|
|
await db.updateFolderPriority(
|
|
album.path,
|
|
newPriority,
|
|
);
|
|
}
|
|
}
|
|
|
|
await load();
|
|
}
|
|
|
|
Future<void> toggleHidden(AlbumRow album) async {
|
|
final db = localMediaDb as dynamic;
|
|
final newHidden = album.hidden ? 0 : 1;
|
|
|
|
await db.updateFolderHidden(
|
|
album.path,
|
|
newHidden,
|
|
);
|
|
|
|
await load();
|
|
}
|
|
|
|
Future<void> renameAlbum(
|
|
AlbumRow album,
|
|
String newName,
|
|
) async {
|
|
final db = localMediaDb as dynamic;
|
|
|
|
await db.updateFolderDisplayName(
|
|
album.path,
|
|
newName,
|
|
);
|
|
|
|
await load();
|
|
}
|
|
|
|
Future<void> setCover(
|
|
AlbumRow album,
|
|
AvesEntry entry,
|
|
) async {
|
|
final db = localMediaDb as dynamic;
|
|
|
|
await db.updateFolderCover(
|
|
album.path,
|
|
entry.id,
|
|
);
|
|
|
|
await load();
|
|
}
|
|
|
|
Future<void> deleteAlbum(AlbumRow album) async {
|
|
final db = localMediaDb as dynamic;
|
|
|
|
await db.deleteFolder(album.path);
|
|
|
|
await load();
|
|
}
|
|
|
|
static int _parseHybridFolder(Object? value) {
|
|
if (value == null) return 0;
|
|
if (value is int) return value;
|
|
if (value is num) return value.toInt();
|
|
return int.tryParse('$value') ?? 0;
|
|
}
|
|
}
|