From b82dce29d98b01f69fba1ea44bee7e131dd44a41 Mon Sep 17 00:00:00 2001 From: MSOB7YY Date: Fri, 20 Oct 2023 17:56:32 +0300 Subject: [PATCH] feat: subpages tracks sorting --- lib/controller/folders_controller.dart | 3 + lib/controller/indexer_controller.dart | 50 +++++-- lib/controller/search_sort_controller.dart | 69 +++++++++- lib/controller/settings_controller.dart | 22 ++- lib/core/enums.dart | 1 + lib/core/functions.dart | 102 ++++++++++++++ lib/core/namida_converter_ext.dart | 31 +++++ lib/ui/pages/folders_page.dart | 58 ++++---- .../pages/subpages/album_tracks_subpage.dart | 68 +++++----- .../pages/subpages/artist_tracks_subpage.dart | 126 +++++++++--------- .../pages/subpages/genre_tracks_subpage.dart | 38 +++--- lib/ui/widgets/custom_widgets.dart | 8 +- lib/ui/widgets/settings/extra_settings.dart | 2 +- lib/ui/widgets/sort_by_button.dart | 1 + pubspec.lock | 8 +- pubspec.yaml | 4 +- 16 files changed, 435 insertions(+), 156 deletions(-) diff --git a/lib/controller/folders_controller.dart b/lib/controller/folders_controller.dart index e4b23cb0..a22db01e 100644 --- a/lib/controller/folders_controller.dart +++ b/lib/controller/folders_controller.dart @@ -3,8 +3,10 @@ import 'package:get/get.dart'; import 'package:namida/class/folder.dart'; import 'package:namida/class/track.dart'; import 'package:namida/controller/scroll_search_controller.dart'; +import 'package:namida/controller/search_sort_controller.dart'; import 'package:namida/controller/settings_controller.dart'; import 'package:namida/core/enums.dart'; +import 'package:namida/core/extensions.dart'; class Folders { static Folders get inst => _instance; @@ -64,6 +66,7 @@ class Folders { if (LibraryTab.folders.scrollController.hasClients) { LibraryTab.folders.scrollController.jumpTo(0); } + currentFolder.value?.tracks.sortByAlts(SearchSortController.inst.getMediaTracksSortingComparables(MediaType.folder)); } void stepOut() { diff --git a/lib/controller/indexer_controller.dart b/lib/controller/indexer_controller.dart index b326b62d..663277ce 100644 --- a/lib/controller/indexer_controller.dart +++ b/lib/controller/indexer_controller.dart @@ -149,14 +149,42 @@ class Indexer { mainMapFolders.addForce(tr.folder, tr); }); - mainMapAlbums.value.updateAll((key, value) => value..sortByAlts((e) => e.year, [(e) => e.trackNo, (e) => e.title])); - mainMapArtists.value.updateAll((key, value) => value..sortByAlt((e) => e.year, (e) => e.title)); - mainMapGenres.value.updateAll((key, value) => value..sortByAlt((e) => e.year, (e) => e.title)); - mainMapFolders.updateAll((key, value) => value..sortBy((e) => e.filename.toLowerCase())); - + sortMediaTracksSubLists(MediaType.values); _sortAll(); } + void sortMediaTracksSubLists(List medias) { + medias.loop((e, index) { + final sorters = SearchSortController.inst.getMediaTracksSortingComparables(e); + void sortPls(Iterable> trs) { + for (final e in trs) { + e.sortByAlts(sorters); + } + } + + switch (e) { + case MediaType.album: + sortPls(mainMapAlbums.value.values); + mainMapAlbums.refresh(); + break; + case MediaType.artist: + sortPls(mainMapArtists.value.values); + mainMapArtists.refresh(); + break; + case MediaType.genre: + sortPls(mainMapGenres.value.values); + mainMapGenres.refresh(); + break; + case MediaType.folder: + sortPls(mainMapFolders.values); + mainMapFolders.refresh(); + break; + default: + null; + } + }); + } + void _sortAll() => SearchSortController.inst.sortAll(); /// Removes Specific tracks from their corresponding media, useful when updating track metadata or reindexing a track. @@ -209,25 +237,29 @@ class Indexer { addedFolders.add(tr.folder); }); + final albumSorters = SearchSortController.inst.getMediaTracksSortingComparables(MediaType.album); + final artistSorters = SearchSortController.inst.getMediaTracksSortingComparables(MediaType.artist); + final genreSorters = SearchSortController.inst.getMediaTracksSortingComparables(MediaType.genre); + final folderSorters = SearchSortController.inst.getMediaTracksSortingComparables(MediaType.folder); addedAlbums ..removeDuplicates() ..loop((e, index) { - mainMapAlbums.value[e]?.sortByAlts((e) => e.year, [(e) => e.trackNo, (e) => e.title]); + mainMapAlbums.value[e]?.sortByAlts(albumSorters); }); addedArtists ..removeDuplicates() ..loop((e, index) { - mainMapArtists.value[e]?.sortByAlt((e) => e.year, (e) => e.title); + mainMapArtists.value[e]?.sortByAlts(artistSorters); }); addedGenres ..removeDuplicates() ..loop((e, index) { - mainMapGenres.value[e]?.sortByAlt((e) => e.year, (e) => e.title); + mainMapGenres.value[e]?.sortByAlts(genreSorters); }); addedFolders ..removeDuplicates() ..loop((e, index) { - mainMapFolders[e]?.sortBy((e) => e.filename.toLowerCase()); + mainMapFolders[e]?.sortByAlts(folderSorters); }); _sortAll(); diff --git a/lib/controller/search_sort_controller.dart b/lib/controller/search_sort_controller.dart index bf2ec14c..d5dbf67b 100644 --- a/lib/controller/search_sort_controller.dart +++ b/lib/controller/search_sort_controller.dart @@ -97,6 +97,35 @@ class SearchSortController { } } + List getMediaTracksSortingComparables(MediaType media) { + final sorts = settings.mediaItemsTrackSorting[media] ?? [SortType.title]; + + final map = { + SortType.title: (e) => e.title.toLowerCase(), + SortType.album: (e) => e.album.toLowerCase(), + SortType.albumArtist: (e) => e.albumArtist.toLowerCase(), + SortType.year: (e) => e.year, + SortType.artistsList: (e) => e.artistsList.join().toLowerCase(), + SortType.genresList: (e) => e.genresList.join().toLowerCase(), + SortType.dateAdded: (e) => e.dateAdded, + SortType.dateModified: (e) => e.dateModified, + SortType.bitrate: (e) => e.bitrate, + SortType.composer: (e) => e.composer.toLowerCase(), + SortType.trackNo: (e) => e.trackNo, + SortType.discNo: (e) => e.discNo, + SortType.filename: (e) => e.filename.toLowerCase(), + SortType.duration: (e) => e.duration, + SortType.sampleRate: (e) => e.sampleRate, + SortType.size: (e) => e.size, + SortType.rating: (e) => e.stats.rating, + }; + final l = []; + sorts.loop((e, index) { + if (map[e] != null) l.add(map[e]!); + }); + return l; + } + void _searchTracks(String text, {bool temp = false}) async { if (text == '') { if (temp) { @@ -262,25 +291,50 @@ class SearchSortController { sortBy ??= settings.tracksSort.value; reverse ??= settings.tracksSortReversed.value; - void sortThis(Comparable Function(Track tr) comparable) => reverse! ? tracksInfoList.sortByReverse(comparable) : tracksInfoList.sortBy(comparable); + void sortThis(Comparable Function(Track e) comparable) => reverse! ? tracksInfoList.sortByReverse(comparable) : tracksInfoList.sortBy(comparable); + void sortThisAlts(List Function(Track tr)> alternatives) => + reverse! ? tracksInfoList.sortByReverseAlts(alternatives) : tracksInfoList.sortByAlts(alternatives); + final sameAlbumSorters = getMediaTracksSortingComparables(MediaType.album); + final sameArtistSorters = getMediaTracksSortingComparables(MediaType.artist); + final sameGenreSorters = getMediaTracksSortingComparables(MediaType.genre); switch (sortBy) { case SortType.title: sortThis((e) => e.title.toLowerCase()); case SortType.album: - sortThis((e) => e.album.toLowerCase()); + sortThisAlts( + [ + (tr) => tr.album.toLowerCase(), + ...sameAlbumSorters, + ], + ); break; case SortType.albumArtist: - sortThis((e) => e.albumArtist.toLowerCase()); + sortThisAlts( + [ + (tr) => tr.albumArtist.toLowerCase(), + ...sameAlbumSorters, + ], + ); break; case SortType.year: sortThis((e) => e.year); break; case SortType.artistsList: - sortThis((e) => e.artistsList.join().toLowerCase()); + sortThisAlts( + [ + (tr) => tr.artistsList.join().toLowerCase(), + ...sameArtistSorters, + ], + ); break; case SortType.genresList: - sortThis((e) => e.genresList.join().toLowerCase()); + sortThisAlts( + [ + (tr) => tr.genresList.join().toLowerCase(), + ...sameGenreSorters, + ], + ); break; case SortType.dateAdded: sortThis((e) => e.dateAdded); @@ -292,7 +346,10 @@ class SearchSortController { sortThis((e) => e.bitrate); break; case SortType.composer: - sortThis((e) => e.composer); + sortThis((e) => e.composer.toLowerCase()); + break; + case SortType.trackNo: + sortThis((e) => e.trackNo); break; case SortType.discNo: sortThis((e) => e.discNo); diff --git a/lib/controller/settings_controller.dart b/lib/controller/settings_controller.dart index 3ed91498..a9efe69a 100644 --- a/lib/controller/settings_controller.dart +++ b/lib/controller/settings_controller.dart @@ -241,6 +241,13 @@ class SettingsController { AlbumIdentifier.albumName, ].obs; + final mediaItemsTrackSorting = >{ + MediaType.album: [SortType.trackNo, SortType.year, SortType.title], + MediaType.artist: [SortType.year, SortType.title], + MediaType.genre: [SortType.year, SortType.title], + MediaType.folder: [SortType.filename], + }.obs; + bool didSupportNamida = false; Future prepareSettingsFile() async { @@ -432,7 +439,11 @@ class SettingsController { )) ?? queueInsertion.map((key, value) => MapEntry(key, value)); - /// + final mediaItemsTrackSortingInStorage = json["mediaItemsTrackSorting"] as Map? ?? {}; + mediaItemsTrackSorting.value = { + for (final e in mediaItemsTrackSortingInStorage.entries) + MediaType.values.getEnum(e.key) ?? MediaType.track: (e.value as List?)?.map((v) => SortType.values.getEnum(v) ?? SortType.title).toList() ?? [SortType.year] + }; } catch (e) { printy(e, isError: true); await file.delete(); @@ -594,6 +605,7 @@ class SettingsController { 'trackItem': trackItem.map((key, value) => MapEntry(key.convertToString, value.convertToString)), 'playerOnInterrupted': playerOnInterrupted.map((key, value) => MapEntry(key.convertToString, value.convertToString)), 'queueInsertion': queueInsertion.map((key, value) => MapEntry(key.convertToString, value.toJson())), + 'mediaItemsTrackSorting': mediaItemsTrackSorting.map((key, value) => MapEntry(key.convertToString, value.map((e) => e.convertToString).toList())), }; await file.writeAsJson(res); @@ -1185,6 +1197,7 @@ class SettingsController { if (mostPlayedCustomisStartOfDay != null) { this.mostPlayedCustomisStartOfDay.value = mostPlayedCustomisStartOfDay; } + if (didSupportNamida != null) { this.didSupportNamida = didSupportNamida; } @@ -1210,6 +1223,7 @@ class SettingsController { if (tagFieldsToEdit1 != null) { tagFieldsToEdit.insertSafe(index, tagFieldsToEdit1); } + _writeToStorage(); } @@ -1335,6 +1349,7 @@ class SettingsController { tagFieldsToEdit.remove(t); }); } + _writeToStorage(); } @@ -1352,4 +1367,9 @@ class SettingsController { queueInsertion[type] = qi; _writeToStorage(); } + + void updateMediaItemsTrackSorting(MediaType media, List allsorts) { + mediaItemsTrackSorting[media] = allsorts; + _writeToStorage(); + } } diff --git a/lib/core/enums.dart b/lib/core/enums.dart index 46a7c992..2e152526 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -14,6 +14,7 @@ enum SortType { dateModified, bitrate, composer, + trackNo, discNo, filename, duration, diff --git a/lib/core/functions.dart b/lib/core/functions.dart index 4afee5a6..99d3e9e6 100644 --- a/lib/core/functions.dart +++ b/lib/core/functions.dart @@ -7,14 +7,17 @@ import 'package:namida/class/queue.dart'; import 'package:namida/class/track.dart'; import 'package:namida/controller/folders_controller.dart'; import 'package:namida/controller/history_controller.dart'; +import 'package:namida/controller/indexer_controller.dart'; import 'package:namida/controller/miniplayer_controller.dart'; import 'package:namida/controller/navigator_controller.dart'; import 'package:namida/controller/player_controller.dart'; import 'package:namida/controller/playlist_controller.dart'; import 'package:namida/controller/scroll_search_controller.dart'; +import 'package:namida/controller/settings_controller.dart'; import 'package:namida/core/constants.dart'; import 'package:namida/core/enums.dart'; import 'package:namida/core/extensions.dart'; +import 'package:namida/core/icon_fonts/broken_icons.dart'; import 'package:namida/core/namida_converter_ext.dart'; import 'package:namida/core/translations/language.dart'; import 'package:namida/ui/pages/subpages/album_tracks_subpage.dart'; @@ -161,6 +164,105 @@ class NamidaOnTaps { ); } } + + void onSubPageTracksSortIconTap(MediaType media) { + final sorters = (settings.mediaItemsTrackSorting[media] ?? []).obs; + final defaultSorts = >{ + MediaType.album: [SortType.trackNo, SortType.year, SortType.title], + MediaType.artist: [SortType.year, SortType.title], + MediaType.genre: [SortType.year, SortType.title], + MediaType.folder: [SortType.filename], + }; + + final allSorts = List.from(SortType.values).obs; + void resortVisualItems() => allSorts.sortByReverse((e) { + final active = sorters.contains(e); + return active ? sorters.length - sorters.indexOf(e) : sorters.indexOf(e); + }); + resortVisualItems(); + + void resortMedia() { + settings.updateMediaItemsTrackSorting(media, sorters); + Indexer.inst.sortMediaTracksSubLists([media]); + } + + NamidaNavigator.inst.navigateDialog( + onDismissing: resortMedia, + dialog: CustomBlurryDialog( + title: "${lang.SORT_BY} (${lang.REORDERABLE})", + actions: [ + IconButton( + icon: const Icon(Broken.refresh), + tooltip: lang.RESTORE_DEFAULTS, + onPressed: () { + final defaults = defaultSorts[media] ?? [SortType.year]; + sorters + ..clear() + ..addAll(defaults); + settings.updateMediaItemsTrackSorting(media, defaults); + }, + ), + NamidaButton( + text: lang.DONE, + onPressed: () { + resortMedia(); + NamidaNavigator.inst.closeDialog(); + }, + ), + ], + child: SizedBox( + width: Get.width, + height: Get.height * 0.4, + child: Obx( + () => NamidaListView( + padding: EdgeInsets.zero, + itemCount: allSorts.length, + itemExtents: null, + onReorder: (oldIndex, newIndex) { + if (newIndex > oldIndex) { + newIndex -= 1; + } + final item = allSorts.removeAt(oldIndex); + allSorts.insert(newIndex, item); + final activeSorts = allSorts.where((element) => sorters.contains(element)).toList(); + sorters + ..clear() + ..addAll(activeSorts); + settings.updateMediaItemsTrackSorting(media, activeSorts); + }, + itemBuilder: (context, i) { + final sorting = allSorts[i]; + return Padding( + key: ValueKey(i), + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 3.0), + child: Obx( + () { + final isActive = sorters.contains(sorting); + return ListTileWithCheckMark( + title: "${i + 1}. ${sorting.toText()}", + active: isActive, + onTap: () { + if (isActive && sorters.length <= 1) { + showMinimumItemsSnack(); + return; + } + if (sorters.contains(sorting)) { + sorters.remove(sorting); + } else { + sorters.insert(i, sorting); + } + }, + ); + }, + ), + ); + }, + ), + ), + ), + ), + ); + } } Future showCalendarDialog({ diff --git a/lib/core/namida_converter_ext.dart b/lib/core/namida_converter_ext.dart index 195c63ca..5c987ed5 100644 --- a/lib/core/namida_converter_ext.dart +++ b/lib/core/namida_converter_ext.dart @@ -34,6 +34,7 @@ import 'package:namida/controller/selected_tracks_controller.dart'; import 'package:namida/controller/settings_controller.dart'; import 'package:namida/core/constants.dart'; import 'package:namida/core/dimensions.dart'; +import 'package:namida/core/functions.dart'; import 'package:namida/core/enums.dart'; import 'package:namida/core/extensions.dart'; import 'package:namida/core/icon_fonts/broken_icons.dart'; @@ -807,6 +808,26 @@ extension RouteUtils on NamidaRoute { final queue = route == RouteType.SUBPAGE_queueTracks ? name.getQueue() : null; + MediaType? sortingTracksMediaType; + switch (route) { + case RouteType.SUBPAGE_albumTracks: + sortingTracksMediaType = MediaType.album; + break; + case RouteType.SUBPAGE_artistTracks: + sortingTracksMediaType = MediaType.artist; + break; + case RouteType.SUBPAGE_genreTracks: + sortingTracksMediaType = MediaType.genre; + break; + // -- sorting icon is displayed in folder page itself + // case RouteType.PAGE_folders: + // sortingTracksMediaType = MediaType.folder; + // break; + + default: + null; + } + return [ // -- Stats Icon getAnimatedCrossFade( @@ -851,6 +872,15 @@ extension RouteUtils on NamidaRoute { ), shouldShow: queue != null, ), + getAnimatedCrossFade( + child: NamidaAppBarIcon( + icon: Broken.sort, + onPressed: () { + NamidaOnTaps.inst.onSubPageTracksSortIconTap(sortingTracksMediaType!); + }, + ), + shouldShow: sortingTracksMediaType != null, + ), getAnimatedCrossFade( child: getMoreIcon(() { @@ -1064,6 +1094,7 @@ class _NamidaConverters { SortType.dateAdded: lang.DATE_ADDED, SortType.dateModified: lang.DATE_MODIFIED, SortType.discNo: lang.DISC_NUMBER, + SortType.trackNo: lang.TRACK_NUMBER, SortType.filename: lang.FILE_NAME, SortType.duration: lang.DURATION, SortType.genresList: lang.GENRES, diff --git a/lib/ui/pages/folders_page.dart b/lib/ui/pages/folders_page.dart index cd8049de..f4c2a2d6 100644 --- a/lib/ui/pages/folders_page.dart +++ b/lib/ui/pages/folders_page.dart @@ -12,6 +12,7 @@ import 'package:namida/core/constants.dart'; import 'package:namida/core/dimensions.dart'; import 'package:namida/core/enums.dart'; import 'package:namida/core/extensions.dart'; +import 'package:namida/core/functions.dart'; import 'package:namida/core/icon_fonts/broken_icons.dart'; import 'package:namida/core/translations/language.dart'; import 'package:namida/ui/widgets/custom_widgets.dart'; @@ -46,31 +47,42 @@ class FoldersPage extends StatelessWidget { /// Folders in heirarchy ? Column( children: [ - ListTile( - leading: iconWidget, - title: Obx( - () => Text( - //todo .formatPath() - Folders.inst.currentFolder.value?.path ?? lang.HOME, - style: context.textTheme.displaySmall, - maxLines: 2, - overflow: TextOverflow.ellipsis, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 2.0), + child: Obx( + () => CustomListTile( + borderR: 16.0, + icon: Folders.inst.isHome.value ? Broken.home_2 : Broken.folder_2, + title: Folders.inst.currentFolder.value?.path.formatPath() ?? lang.HOME, + titleStyle: context.textTheme.displaySmall, + onTap: () => Folders.inst.stepOut(), + trailing: Row( + children: [ + Obx( + () { + final pathOfDefault = Folders.inst.isHome.value ? '' : Folders.inst.currentFolder.value?.path; + return NamidaIconButton( + horizontalPadding: 8.0, + tooltip: lang.SET_AS_DEFAULT, + icon: settings.defaultFolderStartupLocation.value == pathOfDefault ? Broken.archive_tick : Broken.save_2, + iconSize: 22.0, + onPressed: () => settings.save( + defaultFolderStartupLocation: Folders.inst.currentFolder.value?.path ?? '', + ), + ); + }, + ), + NamidaIconButton( + horizontalPadding: 8.0, + icon: Broken.sort, + onPressed: () { + NamidaOnTaps.inst.onSubPageTracksSortIconTap(MediaType.folder); + }, + ) + ], + ), ), ), - onTap: () => Folders.inst.stepOut(), - trailing: Obx( - () { - final pathOfDefault = Folders.inst.isHome.value ? '' : Folders.inst.currentFolder.value?.path; - return NamidaIconButton( - tooltip: lang.SET_AS_DEFAULT, - icon: settings.defaultFolderStartupLocation.value == pathOfDefault ? Broken.archive_tick : Broken.save_2, - iconSize: 22.0, - onPressed: () => settings.save( - defaultFolderStartupLocation: Folders.inst.currentFolder.value?.path ?? '', - ), - ); - }, - ), ), Expanded( child: CupertinoScrollbar( diff --git a/lib/ui/pages/subpages/album_tracks_subpage.dart b/lib/ui/pages/subpages/album_tracks_subpage.dart index 084b2901..f6761bed 100644 --- a/lib/ui/pages/subpages/album_tracks_subpage.dart +++ b/lib/ui/pages/subpages/album_tracks_subpage.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:namida/class/track.dart'; +import 'package:namida/controller/indexer_controller.dart'; import 'package:namida/controller/settings_controller.dart'; import 'package:namida/core/constants.dart'; import 'package:namida/core/enums.dart'; @@ -26,40 +27,43 @@ class AlbumTracksPage extends StatelessWidget { final name = tracks.album; return BackgroundWrapper( child: Obx( - () => NamidaTracksList( - queueSource: QueueSource.album, - queueLength: tracks.length, - queue: tracks, - displayTrackNumber: settings.displayTrackNumberinAlbumPage.value, - header: SubpagesTopContainer( - title: name, - source: QueueSource.album, - subtitle: [tracks.displayTrackKeyword, tracks.totalDurationFormatted].join(' - '), - thirdLineText: tracks.albumArtist, - heroTag: 'album_$albumIdentifier', - imageWidget: shouldAlbumBeSquared - ? MultiArtworkContainer( - size: Get.width * 0.35, - heroTag: 'album_$albumIdentifier', - paths: [tracks.pathToImage], - ) - : Container( - margin: const EdgeInsets.symmetric(horizontal: 12.0), - padding: const EdgeInsets.all(3.0), - child: NamidaHero( - tag: 'album_$albumIdentifier', - child: ArtworkWidget( - thumbnailSize: Get.width * 0.35, - forceSquared: false, - path: tracks.pathToImage, - compressed: false, - borderRadius: 12.0, + () { + Indexer.inst.mainMapAlbums.value; // to update after sorting + return NamidaTracksList( + queueSource: QueueSource.album, + queueLength: tracks.length, + queue: tracks, + displayTrackNumber: settings.displayTrackNumberinAlbumPage.value, + header: SubpagesTopContainer( + title: name, + source: QueueSource.album, + subtitle: [tracks.displayTrackKeyword, tracks.totalDurationFormatted].join(' - '), + thirdLineText: tracks.albumArtist, + heroTag: 'album_$albumIdentifier', + imageWidget: shouldAlbumBeSquared + ? MultiArtworkContainer( + size: Get.width * 0.35, + heroTag: 'album_$albumIdentifier', + paths: [tracks.pathToImage], + ) + : Container( + margin: const EdgeInsets.symmetric(horizontal: 12.0), + padding: const EdgeInsets.all(3.0), + child: NamidaHero( + tag: 'album_$albumIdentifier', + child: ArtworkWidget( + thumbnailSize: Get.width * 0.35, + forceSquared: false, + path: tracks.pathToImage, + compressed: false, + borderRadius: 12.0, + ), ), ), - ), - tracks: tracks, - ), - ), + tracks: tracks, + ), + ); + }, ), ); } diff --git a/lib/ui/pages/subpages/artist_tracks_subpage.dart b/lib/ui/pages/subpages/artist_tracks_subpage.dart index f1e875a7..e3e359bc 100644 --- a/lib/ui/pages/subpages/artist_tracks_subpage.dart +++ b/lib/ui/pages/subpages/artist_tracks_subpage.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:namida/class/track.dart'; +import 'package:namida/controller/indexer_controller.dart'; import 'package:namida/core/dimensions.dart'; import 'package:namida/core/enums.dart'; import 'package:namida/core/extensions.dart'; @@ -29,72 +30,77 @@ class ArtistTracksPage extends StatelessWidget { Widget build(BuildContext context) { final albumDimensions = Dimensions.inst.getAlbumCardDimensions(Dimensions.albumInsideArtistGridCount); return BackgroundWrapper( - child: NamidaTracksList( - queueSource: QueueSource.artist, - queueLength: tracks.length, - queue: tracks, - paddingAfterHeader: const EdgeInsets.only(bottom: 12.0), - header: Column( - children: [ - SubpagesTopContainer( - topPadding: 8.0, - bottomPadding: 8.0, - title: name, - source: QueueSource.artist, - subtitle: [ - tracks.displayTrackKeyword, - if (tracks.year != 0) tracks.year.yearFormatted, - ].join(' - '), - heroTag: 'artist_$name', - imageWidget: NamidaHero( - tag: 'artist_$name', - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 0.0, horizontal: 2), - child: ContainerWithBorder( - child: ArtworkWidget( - thumbnailSize: Get.width * 0.35, - path: tracks.pathToImage, - forceSquared: true, - blur: 0, - iconSize: 32.0, - ), - ), - ), - ), - tracks: tracks, - ), - NamidaExpansionTile( - icon: Broken.music_dashboard, - titleText: "${lang.ALBUMS} ${albumIdentifiers.length}", - initiallyExpanded: true, + child: Obx( + () { + Indexer.inst.mainMapArtists.value; // to update after sorting + return NamidaTracksList( + queueSource: QueueSource.artist, + queueLength: tracks.length, + queue: tracks, + paddingAfterHeader: const EdgeInsets.only(bottom: 12.0), + header: Column( children: [ - SizedBox( - height: 130.0 + 28.0, - child: ListView.builder( - padding: const EdgeInsets.symmetric(vertical: 14.0), - scrollDirection: Axis.horizontal, - itemExtent: 100.0, - itemCount: albumIdentifiers.length, - itemBuilder: (context, i) { - final albumId = albumIdentifiers.elementAt(i); - return Container( - width: 100.0, - margin: const EdgeInsets.only(left: 2.0), - child: AlbumCard( - dimensions: albumDimensions, - identifier: albumId, - album: albumId.getAlbumTracks(), - staggered: false, - compact: true, + SubpagesTopContainer( + topPadding: 8.0, + bottomPadding: 8.0, + title: name, + source: QueueSource.artist, + subtitle: [ + tracks.displayTrackKeyword, + if (tracks.year != 0) tracks.year.yearFormatted, + ].join(' - '), + heroTag: 'artist_$name', + imageWidget: NamidaHero( + tag: 'artist_$name', + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 0.0, horizontal: 2), + child: ContainerWithBorder( + child: ArtworkWidget( + thumbnailSize: Get.width * 0.35, + path: tracks.pathToImage, + forceSquared: true, + blur: 0, + iconSize: 32.0, ), - ); - }, + ), + ), ), + tracks: tracks, + ), + NamidaExpansionTile( + icon: Broken.music_dashboard, + titleText: "${lang.ALBUMS} ${albumIdentifiers.length}", + initiallyExpanded: true, + children: [ + SizedBox( + height: 130.0 + 28.0, + child: ListView.builder( + padding: const EdgeInsets.symmetric(vertical: 14.0), + scrollDirection: Axis.horizontal, + itemExtent: 100.0, + itemCount: albumIdentifiers.length, + itemBuilder: (context, i) { + final albumId = albumIdentifiers.elementAt(i); + return Container( + width: 100.0, + margin: const EdgeInsets.only(left: 2.0), + child: AlbumCard( + dimensions: albumDimensions, + identifier: albumId, + album: albumId.getAlbumTracks(), + staggered: false, + compact: true, + ), + ); + }, + ), + ), + ], ), ], ), - ], - ), + ); + }, ), ); } diff --git a/lib/ui/pages/subpages/genre_tracks_subpage.dart b/lib/ui/pages/subpages/genre_tracks_subpage.dart index 9fe656e5..1194f4c6 100644 --- a/lib/ui/pages/subpages/genre_tracks_subpage.dart +++ b/lib/ui/pages/subpages/genre_tracks_subpage.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:namida/class/track.dart'; +import 'package:namida/controller/indexer_controller.dart'; import 'package:namida/core/enums.dart'; import 'package:namida/core/extensions.dart'; import 'package:namida/ui/widgets/custom_widgets.dart'; @@ -19,22 +20,27 @@ class GenreTracksPage extends StatelessWidget { @override Widget build(BuildContext context) { return BackgroundWrapper( - child: NamidaTracksList( - queueSource: QueueSource.genre, - queueLength: tracks.length, - queue: tracks, - header: SubpagesTopContainer( - title: name, - source: QueueSource.genre, - subtitle: [tracks.displayTrackKeyword, tracks.totalDurationFormatted].join(' - '), - heroTag: 'genre_$name', - imageWidget: MultiArtworkContainer( - size: Get.width * 0.35, - heroTag: 'genre_$name', - paths: tracks.toImagePaths(), - ), - tracks: tracks, - ), + child: Obx( + () { + Indexer.inst.mainMapGenres.value; // to update after sorting + return NamidaTracksList( + queueSource: QueueSource.genre, + queueLength: tracks.length, + queue: tracks, + header: SubpagesTopContainer( + title: name, + source: QueueSource.genre, + subtitle: [tracks.displayTrackKeyword, tracks.totalDurationFormatted].join(' - '), + heroTag: 'genre_$name', + imageWidget: MultiArtworkContainer( + size: Get.width * 0.35, + heroTag: 'genre_$name', + paths: tracks.toImagePaths(), + ), + tracks: tracks, + ), + ); + }, ), ); } diff --git a/lib/ui/widgets/custom_widgets.dart b/lib/ui/widgets/custom_widgets.dart index 47126620..aba99aaa 100644 --- a/lib/ui/widgets/custom_widgets.dart +++ b/lib/ui/widgets/custom_widgets.dart @@ -237,6 +237,8 @@ class CustomListTile extends StatelessWidget { final int maxSubtitleLines; final Widget? trailingRaw; final VisualDensity? visualDensity; + final TextStyle? titleStyle; + final double borderR; const CustomListTile({ Key? key, @@ -254,6 +256,8 @@ class CustomListTile extends StatelessWidget { this.maxSubtitleLines = 4, this.trailingRaw, this.visualDensity, + this.titleStyle, + this.borderR = 20.0, }) : super(key: key); @override @@ -265,7 +269,7 @@ class CustomListTile extends StatelessWidget { child: ListTile( enabled: enabled, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20.0.multipliedRadius), + borderRadius: BorderRadius.circular(borderR.multipliedRadius), ), visualDensity: visualDensity, onTap: onTap, @@ -290,7 +294,7 @@ class CustomListTile extends StatelessWidget { : leading, title: Text( title, - style: largeTitle ? context.theme.textTheme.displayLarge : context.theme.textTheme.displayMedium, + style: titleStyle ?? (largeTitle ? context.theme.textTheme.displayLarge : context.theme.textTheme.displayMedium), maxLines: subtitle != null ? 2 : 3, overflow: TextOverflow.ellipsis, ), diff --git a/lib/ui/widgets/settings/extra_settings.dart b/lib/ui/widgets/settings/extra_settings.dart index 7386c09a..b974ab7b 100644 --- a/lib/ui/widgets/settings/extra_settings.dart +++ b/lib/ui/widgets/settings/extra_settings.dart @@ -147,7 +147,7 @@ class ExtrasSettings extends StatelessWidget { }, ), NamidaButton( - text: lang.SAVE, + text: lang.DONE, onPressed: NamidaNavigator.inst.closeDialog, ), ], diff --git a/lib/ui/widgets/sort_by_button.dart b/lib/ui/widgets/sort_by_button.dart index ea8eca8a..6aa5de47 100644 --- a/lib/ui/widgets/sort_by_button.dart +++ b/lib/ui/widgets/sort_by_button.dart @@ -32,6 +32,7 @@ class SortByMenuTracks extends StatelessWidget { SortType.year, SortType.dateModified, SortType.bitrate, + SortType.trackNo, SortType.discNo, SortType.filename, SortType.duration, diff --git a/pubspec.lock b/pubspec.lock index 02088fca..351284b9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -184,8 +184,8 @@ packages: dependency: "direct overridden" description: path: "." - ref: ca4344e147827a38c813902fc995b788f3e7f8d9 - resolved-ref: ca4344e147827a38c813902fc995b788f3e7f8d9 + ref: "0a4d65044b5767d266730cc67894ef648e7f1afd" + resolved-ref: "0a4d65044b5767d266730cc67894ef648e7f1afd" url: "https://github.com/MSOB7YY/dart_extensions" source: git version: "0.0.1" @@ -265,8 +265,8 @@ packages: dependency: "direct main" description: path: "." - ref: e6bd5b3d3303e68b513924cf31789b2246f0e5e4 - resolved-ref: e6bd5b3d3303e68b513924cf31789b2246f0e5e4 + ref: cb8399eec6bc9d238e53125d294c9a3cb5b91434 + resolved-ref: cb8399eec6bc9d238e53125d294c9a3cb5b91434 url: "https://github.com/MSOB7YY/faudiotagger" source: git version: "0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index da4aad91..c2aa6d1a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ dependency_overrides: dart_extensions: git: url: https://github.com/MSOB7YY/dart_extensions - ref: ca4344e147827a38c813902fc995b788f3e7f8d9 + ref: 0a4d65044b5767d266730cc67894ef648e7f1afd archive: ^3.3.8 dependencies: @@ -83,7 +83,7 @@ dependencies: faudiotagger: git: url: https://github.com/MSOB7YY/faudiotagger - ref: e6bd5b3d3303e68b513924cf31789b2246f0e5e4 + ref: cb8399eec6bc9d238e53125d294c9a3cb5b91434 waveform_extractor: ^1.0.1 basic_audio_handler: git: