Offline albums fix, adaptive icon, option to replace downloads
This commit is contained in:
parent
a494601ab0
commit
24e598fe99
|
@ -598,6 +598,14 @@ class Download {
|
||||||
|
|
||||||
this.path = p.join(this.path, _filename);
|
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
|
//Download
|
||||||
this.state = DownloadState.DOWNLOADING;
|
this.state = DownloadState.DOWNLOADING;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:freezer/api/deezer.dart';
|
import 'package:freezer/api/deezer.dart';
|
||||||
|
import 'package:freezer/ui/details_screens.dart';
|
||||||
import 'package:just_audio/just_audio.dart';
|
import 'package:just_audio/just_audio.dart';
|
||||||
import 'package:connectivity/connectivity.dart';
|
import 'package:connectivity/connectivity.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
|
@ -309,7 +310,12 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||||
MediaControl.skipToPrevious,
|
MediaControl.skipToPrevious,
|
||||||
if (_player.playing) MediaControl.pause else MediaControl.play,
|
if (_player.playing) MediaControl.pause else MediaControl.play,
|
||||||
MediaControl.skipToNext,
|
MediaControl.skipToNext,
|
||||||
MediaControl.stop
|
//Stop
|
||||||
|
MediaControl(
|
||||||
|
androidIcon: 'drawable/ic_action_stop',
|
||||||
|
label: 'stop',
|
||||||
|
action: MediaAction.stop
|
||||||
|
)
|
||||||
],
|
],
|
||||||
systemActions: [
|
systemActions: [
|
||||||
MediaAction.seekTo,
|
MediaAction.seekTo,
|
||||||
|
|
|
@ -45,6 +45,8 @@ class Settings {
|
||||||
bool artistFolder;
|
bool artistFolder;
|
||||||
@JsonKey(defaultValue: false)
|
@JsonKey(defaultValue: false)
|
||||||
bool albumDiscFolder;
|
bool albumDiscFolder;
|
||||||
|
@JsonKey(defaultValue: false)
|
||||||
|
bool overwriteDownload;
|
||||||
|
|
||||||
|
|
||||||
//Appearance
|
//Appearance
|
||||||
|
|
|
@ -28,6 +28,7 @@ Settings _$SettingsFromJson(Map<String, dynamic> json) {
|
||||||
..albumFolder = json['albumFolder'] as bool ?? true
|
..albumFolder = json['albumFolder'] as bool ?? true
|
||||||
..artistFolder = json['artistFolder'] as bool ?? true
|
..artistFolder = json['artistFolder'] as bool ?? true
|
||||||
..albumDiscFolder = json['albumDiscFolder'] as bool ?? false
|
..albumDiscFolder = json['albumDiscFolder'] as bool ?? false
|
||||||
|
..overwriteDownload = json['overwriteDownload'] as bool ?? false
|
||||||
..theme =
|
..theme =
|
||||||
_$enumDecodeNullable(_$ThemesEnumMap, json['theme']) ?? Themes.Light
|
_$enumDecodeNullable(_$ThemesEnumMap, json['theme']) ?? Themes.Light
|
||||||
..primaryColor = Settings._colorFromJson(json['primaryColor'] as int)
|
..primaryColor = Settings._colorFromJson(json['primaryColor'] as int)
|
||||||
|
@ -48,6 +49,7 @@ Map<String, dynamic> _$SettingsToJson(Settings instance) => <String, dynamic>{
|
||||||
'albumFolder': instance.albumFolder,
|
'albumFolder': instance.albumFolder,
|
||||||
'artistFolder': instance.artistFolder,
|
'artistFolder': instance.artistFolder,
|
||||||
'albumDiscFolder': instance.albumDiscFolder,
|
'albumDiscFolder': instance.albumDiscFolder,
|
||||||
|
'overwriteDownload': instance.overwriteDownload,
|
||||||
'theme': _$ThemesEnumMap[instance.theme],
|
'theme': _$ThemesEnumMap[instance.theme],
|
||||||
'primaryColor': Settings._colorToJson(instance.primaryColor),
|
'primaryColor': Settings._colorToJson(instance.primaryColor),
|
||||||
'useArtColor': instance.useArtColor,
|
'useArtColor': instance.useArtColor,
|
||||||
|
|
|
@ -30,7 +30,7 @@ class AlbumDetails extends StatelessWidget {
|
||||||
int get cdCount {
|
int get cdCount {
|
||||||
int c = 1;
|
int c = 1;
|
||||||
for (Track t in album.tracks) {
|
for (Track t in album.tracks) {
|
||||||
if (t.diskNumber > c) c = t.diskNumber;
|
if ((t.diskNumber??1) > c) c = t.diskNumber;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ class AlbumDetails extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
...List.generate(cdCount, (cdi) {
|
...List.generate(cdCount, (cdi) {
|
||||||
List<Track> tracks = album.tracks.where((t) => t.diskNumber == cdi + 1).toList();
|
List<Track> tracks = album.tracks.where((t) => (t.diskNumber??1) == cdi + 1).toList();
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -601,7 +601,11 @@ class _DiscographyScreenState extends State<DiscographyScreen> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SortType {
|
||||||
|
DEFAULT,
|
||||||
|
ALPHABETIC,
|
||||||
|
ARTIST
|
||||||
|
}
|
||||||
|
|
||||||
class PlaylistDetails extends StatefulWidget {
|
class PlaylistDetails extends StatefulWidget {
|
||||||
|
|
||||||
|
@ -617,8 +621,25 @@ class _PlaylistDetailsState extends State<PlaylistDetails> {
|
||||||
Playlist playlist;
|
Playlist playlist;
|
||||||
bool _loading = false;
|
bool _loading = false;
|
||||||
bool _error = false;
|
bool _error = false;
|
||||||
|
SortType _sort = SortType.DEFAULT;
|
||||||
ScrollController _scrollController = ScrollController();
|
ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
//Get sorted playlist
|
||||||
|
List<Track> get sorted {
|
||||||
|
List<Track> 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
|
//Load tracks from api
|
||||||
void _load() async {
|
void _load() async {
|
||||||
if (playlist.tracks.length < playlist.trackCount && !_loading) {
|
if (playlist.tracks.length < playlist.trackCount && !_loading) {
|
||||||
|
@ -790,16 +811,40 @@ class _PlaylistDetailsState extends State<PlaylistDetails> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
downloadManager.addOfflinePlaylist(playlist, private: false);
|
downloadManager.addOfflinePlaylist(playlist, private: false);
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
|
PopupMenuButton(
|
||||||
|
child: Icon(Icons.sort, size: 32.0),
|
||||||
|
onSelected: (SortType s) => setState(() => _sort = s),
|
||||||
|
itemBuilder: (context) => <PopupMenuEntry<SortType>>[
|
||||||
|
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) {
|
...List.generate(playlist.tracks.length, (i) {
|
||||||
Track t = playlist.tracks[i];
|
Track t = sorted[i];
|
||||||
return TrackTile(
|
return TrackTile(
|
||||||
t,
|
t,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
playerHelper.playFromPlaylist(playlist, t.id);
|
Playlist p = Playlist(
|
||||||
|
title: playlist.title,
|
||||||
|
id: playlist.id,
|
||||||
|
tracks: sorted
|
||||||
|
);
|
||||||
|
playerHelper.playFromPlaylist(p, t.id);
|
||||||
},
|
},
|
||||||
onHold: () {
|
onHold: () {
|
||||||
MenuSheet m = MenuSheet(context);
|
MenuSheet m = MenuSheet(context);
|
||||||
|
|
|
@ -567,6 +567,16 @@ class _GeneralSettingsState extends State<GeneralSettings> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('Overwrite already downloaded files'),
|
||||||
|
leading: Switch(
|
||||||
|
value: settings.overwriteDownload,
|
||||||
|
onChanged: (v) {
|
||||||
|
setState(() => settings.overwriteDownload = v);
|
||||||
|
settings.save();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text('Copy ARL'),
|
title: Text('Copy ARL'),
|
||||||
subtitle: Text('Copy userToken/ARL Cookie for use in other apps.'),
|
subtitle: Text('Copy userToken/ARL Cookie for use in other apps.'),
|
||||||
|
|
Loading…
Reference in New Issue