diff --git a/lib/api/download.dart b/lib/api/download.dart index e33abaa..a43bd7a 100644 --- a/lib/api/download.dart +++ b/lib/api/download.dart @@ -598,6 +598,14 @@ class Download { this.path = p.join(this.path, _filename); } + + //Check if file exists + if (await File(this.path).exists() && !settings.overwriteDownload) { + this.state = DownloadState.DONE; + onDone(); + return; + } + //Download this.state = DownloadState.DOWNLOADING; diff --git a/lib/api/player.dart b/lib/api/player.dart index 0d47cbc..8b17c92 100644 --- a/lib/api/player.dart +++ b/lib/api/player.dart @@ -1,6 +1,7 @@ import 'package:audio_service/audio_service.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:freezer/api/deezer.dart'; +import 'package:freezer/ui/details_screens.dart'; import 'package:just_audio/just_audio.dart'; import 'package:connectivity/connectivity.dart'; import 'package:path/path.dart' as p; @@ -309,7 +310,12 @@ class AudioPlayerTask extends BackgroundAudioTask { MediaControl.skipToPrevious, if (_player.playing) MediaControl.pause else MediaControl.play, MediaControl.skipToNext, - MediaControl.stop + //Stop + MediaControl( + androidIcon: 'drawable/ic_action_stop', + label: 'stop', + action: MediaAction.stop + ) ], systemActions: [ MediaAction.seekTo, diff --git a/lib/settings.dart b/lib/settings.dart index 5766d71..dd02696 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -45,6 +45,8 @@ class Settings { bool artistFolder; @JsonKey(defaultValue: false) bool albumDiscFolder; + @JsonKey(defaultValue: false) + bool overwriteDownload; //Appearance diff --git a/lib/settings.g.dart b/lib/settings.g.dart index ee59dc9..a3a5451 100644 --- a/lib/settings.g.dart +++ b/lib/settings.g.dart @@ -28,6 +28,7 @@ Settings _$SettingsFromJson(Map json) { ..albumFolder = json['albumFolder'] as bool ?? true ..artistFolder = json['artistFolder'] as bool ?? true ..albumDiscFolder = json['albumDiscFolder'] as bool ?? false + ..overwriteDownload = json['overwriteDownload'] as bool ?? false ..theme = _$enumDecodeNullable(_$ThemesEnumMap, json['theme']) ?? Themes.Light ..primaryColor = Settings._colorFromJson(json['primaryColor'] as int) @@ -48,6 +49,7 @@ Map _$SettingsToJson(Settings instance) => { 'albumFolder': instance.albumFolder, 'artistFolder': instance.artistFolder, 'albumDiscFolder': instance.albumDiscFolder, + 'overwriteDownload': instance.overwriteDownload, 'theme': _$ThemesEnumMap[instance.theme], 'primaryColor': Settings._colorToJson(instance.primaryColor), 'useArtColor': instance.useArtColor, diff --git a/lib/ui/details_screens.dart b/lib/ui/details_screens.dart index fb72bb1..383889e 100644 --- a/lib/ui/details_screens.dart +++ b/lib/ui/details_screens.dart @@ -30,7 +30,7 @@ class AlbumDetails extends StatelessWidget { int get cdCount { int c = 1; for (Track t in album.tracks) { - if (t.diskNumber > c) c = t.diskNumber; + if ((t.diskNumber??1) > c) c = t.diskNumber; } return c; } @@ -163,7 +163,7 @@ class AlbumDetails extends StatelessWidget { ), ), ...List.generate(cdCount, (cdi) { - List tracks = album.tracks.where((t) => t.diskNumber == cdi + 1).toList(); + List tracks = album.tracks.where((t) => (t.diskNumber??1) == cdi + 1).toList(); return Column( children: [ Padding( @@ -601,7 +601,11 @@ class _DiscographyScreenState extends State { } } - +enum SortType { + DEFAULT, + ALPHABETIC, + ARTIST +} class PlaylistDetails extends StatefulWidget { @@ -617,8 +621,25 @@ class _PlaylistDetailsState extends State { Playlist playlist; bool _loading = false; bool _error = false; + SortType _sort = SortType.DEFAULT; ScrollController _scrollController = ScrollController(); + //Get sorted playlist + List get sorted { + List tracks = new List.from(playlist.tracks??[]); + switch (_sort) { + case SortType.ALPHABETIC: + tracks.sort((a, b) => a.title.compareTo(b.title)); + return tracks; + case SortType.ARTIST: + tracks.sort((a, b) => a.artists[0].name.compareTo(b.artists[0].name)); + return tracks; + case SortType.DEFAULT: + default: + return tracks; + } + } + //Load tracks from api void _load() async { if (playlist.tracks.length < playlist.trackCount && !_loading) { @@ -790,16 +811,40 @@ class _PlaylistDetailsState extends State { onPressed: () { downloadManager.addOfflinePlaylist(playlist, private: false); }, - ) + ), + PopupMenuButton( + child: Icon(Icons.sort, size: 32.0), + onSelected: (SortType s) => setState(() => _sort = s), + itemBuilder: (context) => >[ + const PopupMenuItem( + value: SortType.DEFAULT, + child: Text('Default'), + ), + const PopupMenuItem( + value: SortType.ALPHABETIC, + child: Text('Alphabetic'), + ), + const PopupMenuItem( + value: SortType.ARTIST, + child: Text('Artist'), + ), + ], + ), + Container(width: 4.0) ], ), ), ...List.generate(playlist.tracks.length, (i) { - Track t = playlist.tracks[i]; + Track t = sorted[i]; return TrackTile( t, onTap: () { - playerHelper.playFromPlaylist(playlist, t.id); + Playlist p = Playlist( + title: playlist.title, + id: playlist.id, + tracks: sorted + ); + playerHelper.playFromPlaylist(p, t.id); }, onHold: () { MenuSheet m = MenuSheet(context); diff --git a/lib/ui/settings_screen.dart b/lib/ui/settings_screen.dart index 7ca48fe..a3e7dc8 100644 --- a/lib/ui/settings_screen.dart +++ b/lib/ui/settings_screen.dart @@ -567,6 +567,16 @@ class _GeneralSettingsState extends State { }, ), ), + ListTile( + title: Text('Overwrite already downloaded files'), + leading: Switch( + value: settings.overwriteDownload, + onChanged: (v) { + setState(() => settings.overwriteDownload = v); + settings.save(); + }, + ), + ), ListTile( title: Text('Copy ARL'), subtitle: Text('Copy userToken/ARL Cookie for use in other apps.'),