mirror of
https://github.com/spotiflacapp/SpotiFLAC-Mobile.git
synced 2026-06-01 03:15:17 +07:00
- Extract home_tab.dart helpers/widgets into home_tab_helpers.dart and home_tab_widgets.dart using Dart part files - Extract queue_tab.dart helpers/widgets into queue_tab_helpers.dart and queue_tab_widgets.dart using Dart part files - Extract track_metadata_edit_sheet.dart from track_metadata_screen.dart using Dart part file - Refactor _FileExistsListenableCache into a standalone class in queue_tab_helpers.dart - Fix artist_screen.dart: replace unreliable findAncestorStateOfType with GlobalKey for _FetchingProgressDialog progress updates - DRY platform_bridge.dart: extract common JSON decode patterns into reusable helper methods (_decodeRequiredMapResult, _decodeNullableMapResult, _decodeMapListResult, _decodeStringListResult)
188 lines
5.1 KiB
Dart
188 lines
5.1 KiB
Dart
part of 'home_tab.dart';
|
|
|
|
class _RecentAccessView {
|
|
final List<RecentAccessItem> uniqueItems;
|
|
final List<String> downloadIds;
|
|
final Map<String, String> downloadFilePathByRecentKey;
|
|
final bool hasHiddenDownloads;
|
|
|
|
const _RecentAccessView({
|
|
required this.uniqueItems,
|
|
required this.downloadIds,
|
|
required this.downloadFilePathByRecentKey,
|
|
required this.hasHiddenDownloads,
|
|
});
|
|
}
|
|
|
|
class _RecentAlbumAggregate {
|
|
int count;
|
|
DownloadHistoryItem mostRecent;
|
|
|
|
_RecentAlbumAggregate({required this.count, required this.mostRecent});
|
|
}
|
|
|
|
class _CsvImportOptions {
|
|
final bool confirmed;
|
|
final bool skipDownloaded;
|
|
|
|
const _CsvImportOptions({
|
|
required this.confirmed,
|
|
required this.skipDownloaded,
|
|
});
|
|
}
|
|
|
|
class _SearchResultBuckets {
|
|
final List<Track> realTracks;
|
|
final List<int> realTrackIndexes;
|
|
final List<Track> albumItems;
|
|
final List<Track> playlistItems;
|
|
final List<Track> artistItems;
|
|
|
|
const _SearchResultBuckets({
|
|
required this.realTracks,
|
|
required this.realTrackIndexes,
|
|
required this.albumItems,
|
|
required this.playlistItems,
|
|
required this.artistItems,
|
|
});
|
|
}
|
|
|
|
enum _SearchSortOption {
|
|
defaultOrder,
|
|
titleAsc,
|
|
titleDesc,
|
|
artistAsc,
|
|
artistDesc,
|
|
durationAsc,
|
|
durationDesc,
|
|
dateAsc,
|
|
dateDesc,
|
|
}
|
|
|
|
const _homeHistoryPreviewLimit = 48;
|
|
|
|
class _HomeHistoryPreview {
|
|
final List<DownloadHistoryItem> items;
|
|
|
|
const _HomeHistoryPreview(this.items);
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
identical(this, other) ||
|
|
other is _HomeHistoryPreview && listEquals(items, other.items);
|
|
|
|
@override
|
|
int get hashCode => Object.hashAll(items);
|
|
}
|
|
|
|
final _homeHistoryPreviewProvider = Provider<List<DownloadHistoryItem>>((ref) {
|
|
final preview = ref.watch(
|
|
downloadHistoryProvider.select((s) {
|
|
final items = s.items;
|
|
if (items.length <= _homeHistoryPreviewLimit) {
|
|
return _HomeHistoryPreview(items);
|
|
}
|
|
return _HomeHistoryPreview(
|
|
items.take(_homeHistoryPreviewLimit).toList(growable: false),
|
|
);
|
|
}),
|
|
);
|
|
return preview.items;
|
|
});
|
|
|
|
_RecentAccessView _buildRecentAccessViewData(
|
|
List<RecentAccessItem> items,
|
|
List<DownloadHistoryItem> historyItems,
|
|
Set<String> hiddenIds,
|
|
) {
|
|
final albumGroups = <String, _RecentAlbumAggregate>{};
|
|
for (final h in historyItems) {
|
|
final artistForKey = (h.albumArtist != null && h.albumArtist!.isNotEmpty)
|
|
? h.albumArtist!
|
|
: h.artistName;
|
|
final albumKey = '${h.albumName}|$artistForKey';
|
|
final existing = albumGroups[albumKey];
|
|
if (existing == null) {
|
|
albumGroups[albumKey] = _RecentAlbumAggregate(count: 1, mostRecent: h);
|
|
} else {
|
|
existing.count++;
|
|
if (h.downloadedAt.isAfter(existing.mostRecent.downloadedAt)) {
|
|
existing.mostRecent = h;
|
|
}
|
|
}
|
|
}
|
|
|
|
final downloadIds = <String>[];
|
|
final visibleDownloads = <RecentAccessItem>[];
|
|
final downloadFilePathByRecentKey = <String, String>{};
|
|
for (final aggregate in albumGroups.values) {
|
|
final mostRecent = aggregate.mostRecent;
|
|
final artistForKey =
|
|
(mostRecent.albumArtist != null && mostRecent.albumArtist!.isNotEmpty)
|
|
? mostRecent.albumArtist!
|
|
: mostRecent.artistName;
|
|
|
|
final isSingleTrack = aggregate.count == 1;
|
|
final recentId = isSingleTrack
|
|
? (mostRecent.spotifyId ?? mostRecent.id)
|
|
: '${mostRecent.albumName}|$artistForKey';
|
|
final recent = RecentAccessItem(
|
|
id: recentId,
|
|
name: isSingleTrack ? mostRecent.trackName : mostRecent.albumName,
|
|
subtitle: isSingleTrack ? mostRecent.artistName : artistForKey,
|
|
imageUrl: mostRecent.coverUrl,
|
|
type: isSingleTrack ? RecentAccessType.track : RecentAccessType.album,
|
|
accessedAt: mostRecent.downloadedAt,
|
|
providerId: 'download',
|
|
);
|
|
|
|
downloadIds.add(recentId);
|
|
downloadFilePathByRecentKey['${recent.type.name}:${recent.id}'] =
|
|
mostRecent.filePath;
|
|
if (!hiddenIds.contains(recentId)) {
|
|
visibleDownloads.add(recent);
|
|
}
|
|
}
|
|
|
|
visibleDownloads.sort((a, b) => b.accessedAt.compareTo(a.accessedAt));
|
|
if (visibleDownloads.length > 10) {
|
|
visibleDownloads.removeRange(10, visibleDownloads.length);
|
|
}
|
|
|
|
final allItems = <RecentAccessItem>[...items, ...visibleDownloads];
|
|
allItems.sort((a, b) => b.accessedAt.compareTo(a.accessedAt));
|
|
|
|
final seen = <String>{};
|
|
final uniqueItems = <RecentAccessItem>[];
|
|
for (final item in allItems) {
|
|
final key = '${item.type.name}:${item.id}';
|
|
if (seen.add(key)) {
|
|
uniqueItems.add(item);
|
|
if (uniqueItems.length >= 10) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _RecentAccessView(
|
|
uniqueItems: uniqueItems,
|
|
downloadIds: downloadIds,
|
|
downloadFilePathByRecentKey: downloadFilePathByRecentKey,
|
|
hasHiddenDownloads: hiddenIds.isNotEmpty,
|
|
);
|
|
}
|
|
|
|
final recentAccessViewProvider = Provider<_RecentAccessView>((ref) {
|
|
final historyItems = ref.watch(_homeHistoryPreviewProvider);
|
|
final recentAccessItems = ref.watch(
|
|
recentAccessProvider.select((s) => s.items),
|
|
);
|
|
final hiddenDownloadIds = ref.watch(
|
|
recentAccessProvider.select((s) => s.hiddenDownloadIds),
|
|
);
|
|
return _buildRecentAccessViewData(
|
|
recentAccessItems,
|
|
historyItems,
|
|
hiddenDownloadIds,
|
|
);
|
|
});
|