Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sync button to playlist screen #534

Merged
merged 9 commits into from
Dec 24, 2023
10 changes: 8 additions & 2 deletions lib/components/AlbumScreen/album_screen_content.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import 'package:finamp/components/AlbumScreen/sync_album_or_playlist_button.dart';
import 'package:finamp/services/downloads_helper.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
import 'package:get_it/get_it.dart';

import '../../models/jellyfin_models.dart';
import '../../services/finamp_settings_helper.dart';
import '../../components/favourite_button.dart';
import 'album_screen_content_flexible_space_bar.dart';
import 'download_button.dart';
import 'delete_button.dart';
import 'song_list_tile.dart';
import 'playlist_name_edit_button.dart';

Expand Down Expand Up @@ -77,7 +80,10 @@ class _AlbumScreenContentState extends State<AlbumScreenContent> {
!FinampSettingsHelper.finampSettings.isOffline)
PlaylistNameEditButton(playlist: widget.parent),
FavoriteButton(item: widget.parent),
DownloadButton(parent: widget.parent, items: widget.children)
if (GetIt.instance<DownloadsHelper>().isAlbumDownloaded(widget.parent.id))
DeleteButton(parent: widget.parent, items: widget.children),
if (!FinampSettingsHelper.finampSettings.isOffline)
SyncAlbumOrPlaylistButton(parent: widget.parent, items: widget.children)
],
),
if (widget.children.length > 1 &&
Expand Down
92 changes: 92 additions & 0 deletions lib/components/AlbumScreen/delete_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart';

import '../../services/downloads_helper.dart';
import '../../services/finamp_settings_helper.dart';
import '../../models/jellyfin_models.dart';
import '../../models/finamp_models.dart';
import '../confirmation_prompt_dialog.dart';
import '../error_snackbar.dart';

class DeleteButton extends StatefulWidget {
const DeleteButton({
Key? key,
required this.parent,
required this.items,
}) : super(key: key);

final BaseItemDto parent;
final List<BaseItemDto> items;

@override
State<DeleteButton> createState() => _DeleteButtonState();
}

class _DeleteButtonState extends State<DeleteButton> {
final _downloadsHelper = GetIt.instance<DownloadsHelper>();

@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
void checkIfDownloaded() {
if (!mounted) return;
}

return ValueListenableBuilder<Box<FinampSettings>>(
valueListenable: FinampSettingsHelper.finampSettingsListener,
builder: (context, box, child) {
bool? isOffline = box.get("FinampSettings")?.isOffline;

return IconButton(
icon: const Icon(Icons.delete),
// If offline, we don't allow the user to delete items.
// If we did, we'd have to implement listeners for MusicScreenTabView so that the user can't delete a parent, go back, and select the same parent.
// If they did, AlbumScreen would show an error since the item no longer exists.
// Also, the user could delete the parent and immediately re-download it, which will either cause unwanted network usage or cause more errors because the user is offline.
onPressed: isOffline ?? false
? null
: () {
showDialog(
context: context,
builder: (context) => ConfirmationPromptDialog(
promptText: AppLocalizations.of(context)!
.deleteDownloadsPrompt(
widget.parent.name ?? "",
widget.parent.type == "Playlist"
? "playlist"
: "album"),
confirmButtonText: AppLocalizations.of(context)!
.deleteDownloadsConfirmButtonText,
abortButtonText: AppLocalizations.of(context)!
.deleteDownloadsAbortButtonText,
onConfirmed: () async {
final messenger = ScaffoldMessenger.of(context);
try {
await _downloadsHelper
.deleteParentAndChildDownloads(
jellyfinItemIds:
widget.items.map((e) => e.id).toList(),
deletedFor: widget.parent.id,
);
checkIfDownloaded();
messenger.showSnackBar(SnackBar(
content: Text(AppLocalizations.of(context)!
.downloadsDeleted)));
} catch (error) {
errorSnackbar(error, context);
}
},
onAborted: () {},
),
);
});
},
);
}
}
126 changes: 0 additions & 126 deletions lib/components/AlbumScreen/download_button.dart

This file was deleted.

47 changes: 47 additions & 0 deletions lib/components/AlbumScreen/sync_album_or_playlist_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'package:finamp/models/jellyfin_models.dart';
import 'package:finamp/services/downloads_helper.dart';
import 'package:finamp/services/sync_helper.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:logging/logging.dart';

class SyncAlbumOrPlaylistButton extends StatefulWidget {
const SyncAlbumOrPlaylistButton({
Key? key,
required this.parent,
required this.items,
}) : super(key: key);

final BaseItemDto parent;
final List<BaseItemDto> items;
@override
State<SyncAlbumOrPlaylistButton> createState() =>
_SyncAlbumOrPlaylistButtonState();
}
class _SyncAlbumOrPlaylistButtonState
extends State<SyncAlbumOrPlaylistButton> {
final _syncLogger = Logger("SyncPlaylistButton");
final _downloadHelper = GetIt.instance<DownloadsHelper>();
bool isAlbumDownloaded = false;


void syncAlbumOrPlaylist() async {
_syncLogger.info("Syncing playlist");

var syncHelper = DownloadsSyncHelper(_syncLogger);
syncHelper.sync(widget.parent, widget.items);
setState(() {
isAlbumDownloaded = _downloadHelper.isAlbumDownloaded(widget.parent.id);
});
}

@override
Widget build(BuildContext context) {
isAlbumDownloaded = _downloadHelper.isAlbumDownloaded(widget.parent.id);
return IconButton(
onPressed: () => syncAlbumOrPlaylist(), icon:
isAlbumDownloaded ?
const Icon(Icons.sync) :
const Icon(Icons.download));
}
}
2 changes: 1 addition & 1 deletion lib/components/ArtistScreen/artist_download_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class _ArtistDownloadButtonState extends State<ArtistDownloadButton> {
onConfirmed: () async {
try {
final deleteFutures = snapshot.data!.map((e) =>
_downloadsHelper.deleteDownloads(
_downloadsHelper.deleteParentAndChildDownloads(
jellyfinItemIds: _downloadsHelper
.getDownloadedParent(e.id)!
.downloadedChildren
Expand Down
4 changes: 2 additions & 2 deletions lib/components/DownloadsScreen/downloaded_albums_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class _DownloadedAlbumsListState extends State<DownloadedAlbumsList> {
for (BaseItemDto item in downloadedParent.downloadedChildren.values) {
itemIds.add(item.id);
}
await downloadsHelper.deleteDownloads(
await downloadsHelper.deleteParentAndChildDownloads(
jellyfinItemIds: itemIds, deletedFor: downloadedParent.item.id);
}

Expand Down Expand Up @@ -142,6 +142,6 @@ class _DownloadedSongsInAlbumListState
Future<void> deleteSong(BuildContext context, BaseItemDto itemDto) async {
widget.parent.downloadedChildren
.removeWhere((key, value) => value == itemDto);
await downloadsHelper.deleteDownloads(jellyfinItemIds: [itemDto.id]);
await downloadsHelper.deleteSong(jellyfinItemId: itemDto.id);
}
}
47 changes: 16 additions & 31 deletions lib/components/DownloadsScreen/sync_downloaded_playlists.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,35 @@ import 'package:finamp/models/finamp_models.dart';
import 'package:finamp/models/jellyfin_models.dart';
import 'package:finamp/services/downloads_helper.dart';
import 'package:finamp/services/jellyfin_api_helper.dart';
import 'package:flutter/material.dart';
import 'package:finamp/services/sync_helper.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:logging/logging.dart';

class SyncDownloadedPlaylistsButton extends StatelessWidget {
SyncDownloadedPlaylistsButton({super.key});
class SyncDownloadedAlbumsOrPlaylistsButton extends StatelessWidget {
SyncDownloadedAlbumsOrPlaylistsButton({super.key});

final _syncLogger = Logger("SyncDownloadedPlaylistsButton");
final _downloadsHelper = GetIt.instance<DownloadsHelper>();
final DownloadsHelper downloadsHelper = GetIt.instance<DownloadsHelper>();
final _jellyfinApiData = GetIt.instance<JellyfinApiHelper>();

void syncPlaylists() async {
_syncLogger.info("Syncing downloaded playlists");
final parents = _downloadsHelper.downloadedParents.toList();
final songs = _downloadsHelper.downloadedItems.toList();

for (DownloadedParent parent in parents) {
final children =
parent.downloadedChildren.values.map((e) => e.id).toSet();
final firstSong = songs.first;
final items = await _jellyfinApiData.getItems(
isGenres: false,
parentItem: parent.item,
);

if (items == null) continue;

for (BaseItemDto item in items) {
_syncLogger.info(item.id.toString());
final isInChildren = children.contains(item.id);
var syncHelper = DownloadsSyncHelper(_syncLogger);
List<DownloadedParent> parents = downloadsHelper.downloadedParents.toList();

if (isInChildren) {
_syncLogger.info("Need sync download of ${item.id}");
for (DownloadedParent parent in parents) {
List<BaseItemDto>? items = await _jellyfinApiData.getItems(
isGenres: false, parentItem: parent.item);

await _downloadsHelper.addDownloads(
items: [item],
parent: parent.item,
useHumanReadableNames: firstSong.useHumanReadableNames,
downloadLocation: firstSong.downloadLocation!,
viewId: firstSong.viewId,
);
}
if (items == null) {
_syncLogger.warning("Could not find any items for album or playlist id ${parent.item.id}");
continue;
}
syncHelper.sync(parent.item, items);
}
}

Expand All @@ -57,4 +42,4 @@ class SyncDownloadedPlaylistsButton extends StatelessWidget {
tooltip: AppLocalizations.of(context)!.syncDownloadedPlaylists,
);
}
}
}
Loading
Loading