Skip to content

Commit

Permalink
Add info syncing of favorites collection for better syncing of favori…
Browse files Browse the repository at this point in the history
…te info offline. Add info sync of all playlists item to allow showing partially downloaded playlists while offline.
  • Loading branch information
Komodo5197 committed May 19, 2024
1 parent ad5554b commit c4bd402
Show file tree
Hide file tree
Showing 24 changed files with 439 additions and 256 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@ class _AddToPlaylistButtonState extends ConsumerState<AddToPlaylistButton> {
return const SizedBox.shrink();
}

bool isFav = ref
.watch(isFavoriteProvider(widget.item?.id, DefaultValue(widget.item)));
bool isFav = ref.watch(isFavoriteProvider(FavoriteRequest(widget.item)));
return GestureDetector(
onLongPress: () async {
ref
.read(isFavoriteProvider(widget.item?.id, DefaultValue()).notifier)
.read(isFavoriteProvider(FavoriteRequest(widget.item)).notifier)
.updateFavorite(!isFav);
},
child: IconButton(
Expand Down
4 changes: 1 addition & 3 deletions lib/components/AddToPlaylistScreen/new_playlist_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ class _NewPlaylistDialogState extends State<NewPlaylistDialog> {
final downloadsService = GetIt.instance<DownloadsService>();
unawaited(downloadsService.resync(
DownloadStub.fromFinampCollection(
collection:
FinampCollection(type: FinampCollectionType.allPlaylists),
name: null),
FinampCollection(type: FinampCollectionType.allPlaylists)),
null,
keepSlow: true));
return newId.id!;
Expand Down
5 changes: 2 additions & 3 deletions lib/components/AddToPlaylistScreen/playlist_actions_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Future<void> showPlaylistActionsMenu({
Consumer(
builder: (context, ref, child) {
bool isFavorite =
ref.watch(isFavoriteProvider(item.id, DefaultValue(item)));
ref.watch(isFavoriteProvider(FavoriteRequest(item)));
return ToggleableListTile(
title: AppLocalizations.of(context)!.favourites,
leading: AspectRatio(
Expand All @@ -77,8 +77,7 @@ Future<void> showPlaylistActionsMenu({
tapFeedback: false,
onToggle: (bool currentState) async {
return ref
.read(
isFavoriteProvider(item.id, DefaultValue()).notifier)
.read(isFavoriteProvider(FavoriteRequest(item)).notifier)
.updateFavorite(!isFavorite);
},
enabled: !isOffline,
Expand Down
24 changes: 18 additions & 6 deletions lib/components/AlbumScreen/download_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,27 @@ class DownloadButton extends ConsumerWidget {
required this.item,
this.children,
this.isLibrary = false,
this.infoOnly = false,
});

final DownloadStub item;
final int? children;
final bool isLibrary;
final bool infoOnly;

@override
Widget build(BuildContext context, WidgetRef ref) {
final downloadsService = GetIt.instance<DownloadsService>();
var status =
ref.watch(downloadsService.statusProvider((item, children))).value;
DownloadItemStatus? status;
if (infoOnly) {
status = (ref.watch(downloadsService.infoForAnchorProvider(item)).value ??
false)
? DownloadItemStatus.required
: DownloadItemStatus.notNeeded;
} else {
status =
ref.watch(downloadsService.statusProvider((item, children))).value;
}
var isOffline = ref.watch(finampSettingsProvider
.select((value) => value.valueOrNull?.isOffline)) ??
true;
Expand Down Expand Up @@ -67,12 +77,13 @@ class DownloadButton extends ConsumerWidget {
AppLocalizations.of(context)!.addButtonLabel,
abortButtonText:
MaterialLocalizations.of(context).cancelButtonLabel,
onConfirmed: () =>
DownloadDialog.show(context, item, viewId),
onConfirmed: () => DownloadDialog.show(
context, item, viewId,
infoOnly: infoOnly),
onAborted: () {},
));
} else {
await DownloadDialog.show(context, item, viewId);
await DownloadDialog.show(context, item, viewId, infoOnly: infoOnly);
}
},
tooltip: parentTooltip,
Expand All @@ -95,7 +106,8 @@ class DownloadButton extends ConsumerWidget {
AppLocalizations.of(context)!.deleteDownloadsAbortButtonText,
onConfirmed: () async {
try {
await downloadsService.deleteDownload(stub: item);
await downloadsService.deleteDownload(
stub: item, asInfo: infoOnly);
GlobalSnackbar.message((scaffold) =>
AppLocalizations.of(scaffold)!.downloadsDeleted);
} catch (error) {
Expand Down
28 changes: 19 additions & 9 deletions lib/components/AlbumScreen/download_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:async';

import 'package:file_sizes/file_sizes.dart';
import 'package:Finamp/models/jellyfin_models.dart';
import 'package:file_sizes/file_sizes.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:get_it/get_it.dart';
Expand All @@ -21,13 +21,15 @@ class DownloadDialog extends StatefulWidget {
required this.downloadLocationId,
required this.needsTranscode,
required this.children,
required this.infoOnly,
});

final DownloadStub item;
final String viewId;
final String? downloadLocationId;
final bool needsTranscode;
final List<BaseItemDto>? children;
final bool infoOnly;

@override
State<DownloadDialog> createState() => _DownloadDialogState();
Expand All @@ -37,7 +39,8 @@ class DownloadDialog extends StatefulWidget {
/// if transcode downloads is set to ask. If neither is needed, the
/// download is initiated immediately with no dialog.
static Future<void> show(
BuildContext context, DownloadStub item, String? viewId) async {
BuildContext context, DownloadStub item, String? viewId,
{bool infoOnly = false}) async {
if (viewId == null) {
final finampUserHelper = GetIt.instance<FinampUserHelper>();
viewId = finampUserHelper.currentUser!.currentViewId;
Expand Down Expand Up @@ -74,7 +77,11 @@ class DownloadDialog extends StatefulWidget {
(scaffold) => AppLocalizations.of(scaffold)!.confirmDownloadStarted,
isConfirmation: true);
unawaited(downloadsService
.addDownload(stub: item, viewId: viewId!, transcodeProfile: profile)
.addDownload(
stub: item,
viewId: viewId!,
transcodeProfile: profile,
asInfo: infoOnly)
// TODO only show the enqueued confirmation if the enqueuing took longer than ~10 seconds
.then((value) => GlobalSnackbar.message(
(scaffold) => AppLocalizations.of(scaffold)!.downloadsQueued)));
Expand All @@ -93,11 +100,13 @@ class DownloadDialog extends StatefulWidget {
await showDialog(
context: context,
builder: (context) => DownloadDialog._build(
item: item,
viewId: viewId!,
downloadLocationId: downloadLocation,
needsTranscode: needTranscode,
children: children),
item: item,
viewId: viewId!,
downloadLocationId: downloadLocation,
needsTranscode: needTranscode,
children: children,
infoOnly: infoOnly,
),
);
}
}
Expand Down Expand Up @@ -217,7 +226,8 @@ class _DownloadDialogState extends State<DownloadDialog> {
.addDownload(
stub: widget.item,
viewId: widget.viewId,
transcodeProfile: profile)
transcodeProfile: profile,
asInfo: widget.infoOnly)
.onError(
(error, stackTrace) => GlobalSnackbar.error(error));

Expand Down
36 changes: 22 additions & 14 deletions lib/components/AlbumScreen/song_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ class _SongMenuState extends ConsumerState<SongMenu> {
null);
var iconColor = Theme.of(context).colorScheme.primary;

final isInCurrentPlaylist = widget.isInPlaylist && widget.parentItem != null;
final isInCurrentPlaylist =
widget.isInPlaylist && widget.parentItem != null;

final currentTrack = _queueService.getCurrentTrack();
FinampQueueItem? queueItem;
Expand Down Expand Up @@ -243,7 +244,9 @@ class _SongMenuState extends ConsumerState<SongMenu> {
Icons.playlist_add,
color: iconColor,
),
title: Text(isInCurrentPlaylist ? AppLocalizations.of(context)!.addToMorePlaylistsTitle : AppLocalizations.of(context)!.addToPlaylistTitle),
title: Text(isInCurrentPlaylist
? AppLocalizations.of(context)!.addToMorePlaylistsTitle
: AppLocalizations.of(context)!.addToPlaylistTitle),
enabled: !widget.isOffline,
onTap: () {
Navigator.pop(context); // close menu
Expand Down Expand Up @@ -443,8 +446,8 @@ class _SongMenuState extends ConsumerState<SongMenu> {
),
Consumer(
builder: (context, ref, child) {
bool isFav = ref.watch(
isFavoriteProvider(widget.item.id, DefaultValue(widget.item)));
bool isFav =
ref.watch(isFavoriteProvider(FavoriteRequest(widget.item)));
return ListTile(
enabled: !widget.isOffline,
leading: isFav
Expand All @@ -465,8 +468,8 @@ class _SongMenuState extends ConsumerState<SongMenu> {
: AppLocalizations.of(context)!.addFavourite),
onTap: () async {
ref
.read(isFavoriteProvider(widget.item.id, DefaultValue())
.notifier)
.read(
isFavoriteProvider(FavoriteRequest(widget.item)).notifier)
.updateFavorite(!isFav);
if (context.mounted) Navigator.pop(context);
},
Expand Down Expand Up @@ -787,7 +790,7 @@ class SongInfo extends ConsumerStatefulWidget {

final BaseItemDto item;
final bool useThemeImage;
final bool condensed;
final bool condensed;

@override
ConsumerState createState() => _SongInfoState();
Expand All @@ -800,7 +803,8 @@ class _SongInfoState extends ConsumerState<SongInfo> {
color: Colors.transparent,
child: Center(
child: Container(
margin: EdgeInsets.symmetric(horizontal: widget.condensed ? 28.0 : 12.0),
margin:
EdgeInsets.symmetric(horizontal: widget.condensed ? 28.0 : 12.0),
height: widget.condensed ? 80 : 120,
clipBehavior: Clip.antiAlias,
decoration: ShapeDecoration(
Expand Down Expand Up @@ -848,7 +852,9 @@ class _SongInfoState extends ConsumerState<SongInfo> {
maxLines: 2,
),
Padding(
padding: widget.condensed ? const EdgeInsets.only(top: 6.0) : const EdgeInsets.symmetric(vertical: 4.0),
padding: widget.condensed
? const EdgeInsets.only(top: 6.0)
: const EdgeInsets.symmetric(vertical: 4.0),
child: ArtistChips(
baseItem: widget.item,
backgroundColor: IconTheme.of(context)
Expand All @@ -864,12 +870,14 @@ class _SongInfoState extends ConsumerState<SongInfo> {
if (!widget.condensed)
AlbumChip(
item: widget.item,
color: Theme.of(context).textTheme.bodyMedium?.color ??
Colors.white,
backgroundColor:
IconTheme.of(context).color?.withOpacity(0.1) ??
Theme.of(context).textTheme.bodyMedium?.color ??
color:
Theme.of(context).textTheme.bodyMedium?.color ??
Colors.white,
backgroundColor: IconTheme.of(context)
.color
?.withOpacity(0.1) ??
Theme.of(context).textTheme.bodyMedium?.color ??
Colors.white,
key: widget.item.album == null
? null
: ValueKey("${widget.item.album}-album"),
Expand Down
9 changes: 3 additions & 6 deletions lib/components/MusicScreen/album_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,7 @@ class _AlbumItemState extends ConsumerState<AlbumItem> {
screenSize.height - globalPosition.dy,
),
items: [
ref.watch(isFavoriteProvider(
mutableAlbum.id, DefaultValue(mutableAlbum)))
ref.watch(isFavoriteProvider(FavoriteRequest(mutableAlbum)))
? PopupMenuItem<_AlbumListTileMenuItems>(
enabled: !isOffline,
value: _AlbumListTileMenuItems.removeFavourite,
Expand Down Expand Up @@ -283,14 +282,12 @@ class _AlbumItemState extends ConsumerState<AlbumItem> {
switch (selection) {
case _AlbumListTileMenuItems.addFavourite:
ref
.read(
isFavoriteProvider(mutableAlbum.id, DefaultValue()).notifier)
.read(isFavoriteProvider(FavoriteRequest(mutableAlbum)).notifier)
.updateFavorite(true);
break;
case _AlbumListTileMenuItems.removeFavourite:
ref
.read(
isFavoriteProvider(mutableAlbum.id, DefaultValue()).notifier)
.read(isFavoriteProvider(FavoriteRequest(mutableAlbum)).notifier)
.updateFavorite(false);
break;
case _AlbumListTileMenuItems.addToMixList:
Expand Down
9 changes: 7 additions & 2 deletions lib/components/MusicScreen/music_screen_tab_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ class _MusicScreenTabViewState extends State<MusicScreenTabView>
offlineItems = await _isarDownloader.getAllSongs(
nameFilter: widget.searchTerm,
viewFilter: widget.view?.id,
nullableViewFilters: settings.showDownloadsWithUnknownLibrary);
nullableViewFilters: settings.showDownloadsWithUnknownLibrary,
onlyFavorites:
settings.onlyShowFavourite && settings.trackOfflineFavorites);
} else {
offlineItems = await _isarDownloader.getAllCollections(
nameFilter: widget.searchTerm,
Expand All @@ -152,7 +154,9 @@ class _MusicScreenTabViewState extends State<MusicScreenTabView>
? widget.view?.id
: null,
nullableViewFilters: widget.tabContentType == TabContentType.albums &&
settings.showDownloadsWithUnknownLibrary);
settings.showDownloadsWithUnknownLibrary,
onlyFavorites:
settings.onlyShowFavourite && settings.trackOfflineFavorites);
}

var items = offlineItems.map((e) => e.baseItem).whereNotNull().toList();
Expand Down Expand Up @@ -301,6 +305,7 @@ class _MusicScreenTabViewState extends State<MusicScreenTabView>
widget.view?.id,
settings.isOffline,
settings.tabOrder.indexOf(widget.tabContentType),
settings.trackOfflineFavorites,
);
if (refreshHash == null) {
refreshHash = newRefreshHash;
Expand Down
4 changes: 2 additions & 2 deletions lib/components/PlayerScreen/player_screen_album_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ class PlayerScreenAlbumImage extends ConsumerWidget {
if (currentTrack?.baseItem != null &&
!FinampSettingsHelper.finampSettings.isOffline) {
ref
.read(isFavoriteProvider(currentTrack!.baseItem!.id,
DefaultValue(currentTrack.baseItem))
.read(isFavoriteProvider(
FavoriteRequest(currentTrack!.baseItem))
.notifier)
.toggleFavorite();
}
Expand Down
8 changes: 4 additions & 4 deletions lib/components/album_list_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ class _AlbumListTileState extends ConsumerState<AlbumListTile> {
type: DownloadItemType.collection, item: widget.item),
null)
.isRequired;
final bool isFav = ref
.watch(isFavoriteProvider(widget.item.id, DefaultValue(widget.item)));
final bool isFav =
ref.watch(isFavoriteProvider(FavoriteRequest(widget.item)));

final selection = await showMenu<AlbumListTileMenuItems>(
context: context,
Expand Down Expand Up @@ -216,12 +216,12 @@ class _AlbumListTileState extends ConsumerState<AlbumListTile> {
switch (selection) {
case AlbumListTileMenuItems.addFavourite:
ref
.read(isFavoriteProvider(widget.item.id, DefaultValue()).notifier)
.read(isFavoriteProvider(FavoriteRequest(widget.item)).notifier)
.updateFavorite(true);
break;
case AlbumListTileMenuItems.removeFavourite:
ref
.read(isFavoriteProvider(widget.item.id, DefaultValue()).notifier)
.read(isFavoriteProvider(FavoriteRequest(widget.item)).notifier)
.updateFavorite(false);
break;
case AlbumListTileMenuItems.addToMixList:
Expand Down
5 changes: 2 additions & 3 deletions lib/components/favourite_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ class _FavoriteButtonState extends ConsumerState<FavoriteButton> {
return const SizedBox.shrink();
}

bool isFav = ref
.watch(isFavoriteProvider(widget.item?.id, DefaultValue(widget.item)));
bool isFav = ref.watch(isFavoriteProvider(FavoriteRequest(widget.item)));
if (widget.onlyIfFav) {
if (isFav && !FinampSettingsHelper.finampSettings.onlyShowFavourite) {
return Icon(
Expand All @@ -65,7 +64,7 @@ class _FavoriteButtonState extends ConsumerState<FavoriteButton> {
? null
: () {
ref
.read(isFavoriteProvider(widget.item?.id, DefaultValue())
.read(isFavoriteProvider(FavoriteRequest(widget.item))
.notifier)
.updateFavorite(!isFav);
},
Expand Down
4 changes: 3 additions & 1 deletion lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1502,5 +1502,7 @@
"addPlaylistSubheader": "Add track to a playlist",
"@addPlaylistSubheader": {
"description": "Subheader for adding to a playlist in the add to/remove from playlist popup menu"
}
},
"trackOfflineFavorites": "Sync all favorite statuses",
"trackOfflineFavoritesSubtitle": "This allows showing more up-to-date favorite statuses while offline. Does not download any additional files."
}
Loading

0 comments on commit c4bd402

Please sign in to comment.