code fixes:

- remove unused imports
- remove clipboard plugin and directly use flutter's clipboard class
- replace deprecated stuff
This commit is contained in:
pato05 2021-04-05 00:58:39 +02:00
parent 3105ed6c1d
commit 519adc910f
17 changed files with 682 additions and 691 deletions

View file

@ -1,9 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:freezer/api/deezer.dart';
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
import 'package:freezer/ui/details_screens.dart';
import 'package:freezer/ui/library.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;

View file

@ -4,7 +4,6 @@ import 'package:freezer/api/spotify.dart';
import 'package:freezer/settings.dart'; import 'package:freezer/settings.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'dart:io';
import 'dart:convert'; import 'dart:convert';
import 'dart:async'; import 'dart:async';
@ -32,7 +31,7 @@ class DeezerAPI {
"Accept-Charset": "utf-8,ISO-8859-1;q=0.7,*;q=0.3", "Accept-Charset": "utf-8,ISO-8859-1;q=0.7,*;q=0.3",
"Accept-Language": "${settings.deezerLanguage??"en"}-${settings.deezerCountry??'US'},${settings.deezerLanguage??"en"};q=0.9,en-US;q=0.8,en;q=0.7", "Accept-Language": "${settings.deezerLanguage??"en"}-${settings.deezerCountry??'US'},${settings.deezerLanguage??"en"};q=0.9,en-US;q=0.8,en;q=0.7",
"Connection": "keep-alive", "Connection": "keep-alive",
"Cookie": "arl=${arl}" + ((sid == null) ? '' : '; sid=${sid}') "Cookie": "arl=$arl" + ((sid == null) ? '' : '; sid=$sid')
}; };
//Call private API //Call private API

View file

@ -279,7 +279,7 @@ class Artist {
Map<dynamic, dynamic> json, { Map<dynamic, dynamic> json, {
Map<dynamic, dynamic> albumsJson = const {}, Map<dynamic, dynamic> albumsJson = const {},
Map<dynamic, dynamic> topJson = const {}, Map<dynamic, dynamic> topJson = const {},
Map<dynamic, dynamic> highlight = null, Map<dynamic, dynamic> highlight,
bool library = false bool library = false
}) { }) {
//Get wether radio is available //Get wether radio is available

View file

@ -373,14 +373,14 @@ class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateM
items: <BottomNavigationBarItem>[ items: <BottomNavigationBarItem>[
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Icons.home), icon: Icon(Icons.home),
title: Text('Home'.i18n)), label: 'Home'.i18n),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Icons.search), icon: Icon(Icons.search),
title: Text('Search'.i18n), label: 'Search'.i18n,
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Icons.library_music), icon: Icon(Icons.library_music),
title: Text('Library'.i18n)) label: 'Library'.i18n)
], ],
) )
], ],

View file

@ -213,8 +213,8 @@ class Settings {
case AudioQuality.MP3_128: return 1; case AudioQuality.MP3_128: return 1;
case AudioQuality.MP3_320: return 3; case AudioQuality.MP3_320: return 3;
case AudioQuality.FLAC: return 9; case AudioQuality.FLAC: return 9;
default: return 8;
} }
return 8; //default
} }
//Check if is dark, can't use theme directly, because of system themes, and Theme.of(context).brightness broke //Check if is dark, can't use theme directly, because of system themes, and Theme.of(context).brightness broke
@ -242,6 +242,7 @@ class Settings {
sliderTheme: _sliderTheme, sliderTheme: _sliderTheme,
toggleableActiveColor: primaryColor, toggleableActiveColor: primaryColor,
bottomAppBarColor: Color(0xfff5f5f5), bottomAppBarColor: Color(0xfff5f5f5),
appBarTheme: AppBarTheme(brightness: Brightness.light),
), ),
Themes.Dark: ThemeData( Themes.Dark: ThemeData(
textTheme: _textTheme, textTheme: _textTheme,
@ -251,6 +252,7 @@ class Settings {
accentColor: primaryColor, accentColor: primaryColor,
sliderTheme: _sliderTheme, sliderTheme: _sliderTheme,
toggleableActiveColor: primaryColor, toggleableActiveColor: primaryColor,
appBarTheme: AppBarTheme(brightness: Brightness.dark),
), ),
Themes.Deezer: ThemeData( Themes.Deezer: ThemeData(
textTheme: _textTheme, textTheme: _textTheme,
@ -267,6 +269,7 @@ class Settings {
bottomSheetTheme: BottomSheetThemeData( bottomSheetTheme: BottomSheetThemeData(
backgroundColor: deezerBottom backgroundColor: deezerBottom
), ),
appBarTheme: AppBarTheme(brightness: Brightness.dark),
cardColor: deezerBg cardColor: deezerBg
), ),
Themes.Black: ThemeData( Themes.Black: ThemeData(
@ -283,7 +286,8 @@ class Settings {
toggleableActiveColor: primaryColor, toggleableActiveColor: primaryColor,
bottomSheetTheme: BottomSheetThemeData( bottomSheetTheme: BottomSheetThemeData(
backgroundColor: Colors.black, backgroundColor: Colors.black,
) ),
appBarTheme: AppBarTheme(brightness: Brightness.dark),
) )
}; };

View file

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:palette_generator/palette_generator.dart'; import 'package:palette_generator/palette_generator.dart';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
@ -114,7 +113,7 @@ class _ZoomableImageState extends State<ZoomableImage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
ctx = context; ctx = context;
return FlatButton( return TextButton(
child: CachedImage( child: CachedImage(
url: widget.url, url: widget.url,
rounded: widget.rounded, rounded: widget.rounded,

View file

@ -1,7 +1,4 @@
import 'dart:convert';
import 'package:draggable_scrollbar/draggable_scrollbar.dart'; import 'package:draggable_scrollbar/draggable_scrollbar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttericon/font_awesome5_icons.dart'; import 'package:fluttericon/font_awesome5_icons.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
@ -21,7 +18,7 @@ import 'menu.dart';
class AlbumDetails extends StatefulWidget { class AlbumDetails extends StatefulWidget {
Album album; final Album album;
AlbumDetails(this.album, {Key key}): super(key: key); AlbumDetails(this.album, {Key key}): super(key: key);
@override @override
@ -165,7 +162,7 @@ class _AlbumDetailsState extends State<AlbumDetails> {
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[ children: <Widget>[
FlatButton( TextButton(
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Icon((album.library??false)? Icons.favorite : Icons.favorite_border, size: 32), Icon((album.library??false)? Icons.favorite : Icons.favorite_border, size: 32),
@ -196,7 +193,7 @@ class _AlbumDetailsState extends State<AlbumDetails> {
}, },
), ),
MakeAlbumOffline(album: album), MakeAlbumOffline(album: album),
FlatButton( TextButton(
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Icon(Icons.file_download, size: 32.0,), Icon(Icons.file_download, size: 32.0,),
@ -248,7 +245,7 @@ class _AlbumDetailsState extends State<AlbumDetails> {
class MakeAlbumOffline extends StatefulWidget { class MakeAlbumOffline extends StatefulWidget {
Album album; final Album album;
MakeAlbumOffline({Key key, this.album}): super(key: key); MakeAlbumOffline({Key key, this.album}): super(key: key);
@override @override
@ -266,6 +263,7 @@ class _MakeAlbumOfflineState extends State<MakeAlbumOffline> {
_offline = v; _offline = v;
}); });
}); });
super.initState();
} }
@override @override
@ -399,7 +397,7 @@ class ArtistDetails extends StatelessWidget {
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[ children: <Widget>[
FlatButton( TextButton(
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Icon(Icons.favorite, size: 32), Icon(Icons.favorite, size: 32),
@ -417,7 +415,7 @@ class ArtistDetails extends StatelessWidget {
}, },
), ),
if ((artist.radio??false)) if ((artist.radio??false))
FlatButton( TextButton(
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Icon(Icons.radio, size: 32), Icon(Icons.radio, size: 32),
@ -714,7 +712,7 @@ class _DiscographyScreenState extends State<DiscographyScreen> {
class PlaylistDetails extends StatefulWidget { class PlaylistDetails extends StatefulWidget {
Playlist playlist; final Playlist playlist;
PlaylistDetails(this.playlist, {Key key}): super(key: key); PlaylistDetails(this.playlist, {Key key}): super(key: key);
@override @override
@ -1060,7 +1058,7 @@ class _PlaylistDetailsState extends State<PlaylistDetails> {
} }
class MakePlaylistOffline extends StatefulWidget { class MakePlaylistOffline extends StatefulWidget {
Playlist playlist; final Playlist playlist;
MakePlaylistOffline(this.playlist, {Key key}): super(key: key); MakePlaylistOffline(this.playlist, {Key key}): super(key: key);
@override @override
@ -1077,6 +1075,7 @@ class _MakePlaylistOfflineState extends State<MakePlaylistOffline> {
_offline = v; _offline = v;
}); });
}); });
super.initState();
} }
@override @override
@ -1115,7 +1114,7 @@ class _MakePlaylistOfflineState extends State<MakePlaylistOffline> {
class ShowScreen extends StatefulWidget { class ShowScreen extends StatefulWidget {
Show show; final Show show;
ShowScreen(this.show, {Key key}): super(key: key); ShowScreen(this.show, {Key key}): super(key: key);
@override @override

View file

@ -239,11 +239,11 @@ class DownloadTile extends StatelessWidget {
title: Text('Delete'.i18n), title: Text('Delete'.i18n),
content: Text('Are you sure you want to delete this download?'.i18n), content: Text('Are you sure you want to delete this download?'.i18n),
actions: [ actions: [
FlatButton( TextButton(
child: Text('Cancel'.i18n), child: Text('Cancel'.i18n),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
FlatButton( TextButton(
child: Text('Delete'.i18n), child: Text('Delete'.i18n),
onPressed: () async { onPressed: () async {
await downloadManager.removeDownload(download.id); await downloadManager.removeDownload(download.id);

View file

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:freezer/api/deezer.dart'; import 'package:freezer/api/deezer.dart';
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
import 'package:freezer/api/player.dart'; import 'package:freezer/api/player.dart';
import 'package:freezer/main.dart';
import 'package:freezer/ui/elements.dart'; import 'package:freezer/ui/elements.dart';
import 'package:freezer/ui/error.dart'; import 'package:freezer/ui/error.dart';
import 'package:freezer/ui/menu.dart'; import 'package:freezer/ui/menu.dart';
@ -180,7 +179,7 @@ class HomepageSectionWidget extends StatelessWidget {
//Has more items //Has more items
if (j == section.items.length) { if (j == section.items.length) {
if (section.hasMore ?? false) { if (section.hasMore ?? false) {
return FlatButton( return TextButton(
child: Text( child: Text(
'Show more'.i18n, 'Show more'.i18n,
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -217,7 +216,7 @@ class HomepageSectionWidget extends StatelessWidget {
class HomePageItemWidget extends StatelessWidget { class HomePageItemWidget extends StatelessWidget {
HomePageItem item; final HomePageItem item;
HomePageItemWidget(this.item); HomePageItemWidget(this.item);
@override @override

View file

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:freezer/api/deezer.dart'; import 'package:freezer/api/deezer.dart';
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
@ -141,9 +140,8 @@ class _ImporterWidgetState extends State<ImporterWidget> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[ children: <Widget>[
RaisedButton( ElevatedButton(
child: Text('Convert'.i18n), child: Text('Convert'.i18n),
color: Theme.of(context).primaryColor,
onPressed: () { onPressed: () {
spotify.convertPlaylist(widget.playlist); spotify.convertPlaylist(widget.playlist);
Navigator.of(context).pushReplacement(MaterialPageRoute( Navigator.of(context).pushReplacement(MaterialPageRoute(
@ -151,9 +149,8 @@ class _ImporterWidgetState extends State<ImporterWidget> {
)); ));
}, },
), ),
RaisedButton( ElevatedButton(
child: Text('Download only'.i18n), child: Text('Download only'.i18n),
color: Theme.of(context).primaryColor,
onPressed: () async { onPressed: () async {
//Ask for quality //Ask for quality
AudioQuality quality; AudioQuality quality;
@ -263,7 +260,7 @@ class CurrentlyImportingScreen extends StatelessWidget {
], ],
), ),
if (snapshot.data != null) if (snapshot.data != null)
FlatButton( TextButton(
child: Text('Playlist menu'.i18n), child: Text('Playlist menu'.i18n),
onPressed: () async { onPressed: () async {
Playlist p = await deezerAPI.playlist(snapshot.data); Playlist p = await deezerAPI.playlist(snapshot.data);

View file

@ -22,7 +22,6 @@ import '../api/spotify.dart';
import '../api/download.dart'; import '../api/download.dart';
class LibraryAppBar extends StatelessWidget implements PreferredSizeWidget { class LibraryAppBar extends StatelessWidget implements PreferredSizeWidget {
@override @override
Size get preferredSize => AppBar().preferredSize; Size get preferredSize => AppBar().preferredSize;
@ -35,22 +34,19 @@ class LibraryAppBar extends StatelessWidget implements PreferredSizeWidget {
icon: Icon(Icons.file_download), icon: Icon(Icons.file_download),
onPressed: () { onPressed: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => DownloadsScreen()) MaterialPageRoute(builder: (context) => DownloadsScreen()));
);
}, },
), ),
IconButton( IconButton(
icon: Icon(Icons.settings), icon: Icon(Icons.settings),
onPressed: () { onPressed: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SettingsScreen()) MaterialPageRoute(builder: (context) => SettingsScreen()));
);
}, },
), ),
], ],
); );
} }
} }
class LibraryScreen extends StatelessWidget { class LibraryScreen extends StatelessWidget {
@ -60,17 +56,20 @@ class LibraryScreen extends StatelessWidget {
appBar: LibraryAppBar(), appBar: LibraryAppBar(),
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
Container(height: 4.0,), Container(
height: 4.0,
),
if (!downloadManager.running && downloadManager.queueSize > 0) if (!downloadManager.running && downloadManager.queueSize > 0)
ListTile( ListTile(
title: Text('Downloads'.i18n), title: Text('Downloads'.i18n),
leading: LeadingIcon(Icons.file_download, color: Colors.grey), leading: LeadingIcon(Icons.file_download, color: Colors.grey),
subtitle: Text('Downloading is currently stopped, click here to resume.'.i18n), subtitle: Text(
'Downloading is currently stopped, click here to resume.'
.i18n),
onTap: () { onTap: () {
downloadManager.start(); downloadManager.start();
Navigator.of(context).push(MaterialPageRoute( Navigator.of(context).push(
builder: (context) => DownloadsScreen() MaterialPageRoute(builder: (context) => DownloadsScreen()));
));
}, },
), ),
ListTile( ListTile(
@ -78,11 +77,13 @@ class LibraryScreen extends StatelessWidget {
leading: LeadingIcon(Icons.shuffle, color: Color(0xffeca704)), leading: LeadingIcon(Icons.shuffle, color: Color(0xffeca704)),
onTap: () async { onTap: () async {
List<Track> tracks = await deezerAPI.libraryShuffle(); List<Track> tracks = await deezerAPI.libraryShuffle();
playerHelper.playFromTrackList(tracks, tracks[0].id, QueueSource( playerHelper.playFromTrackList(
tracks,
tracks[0].id,
QueueSource(
id: 'libraryshuffle', id: 'libraryshuffle',
source: 'libraryshuffle', source: 'libraryshuffle',
text: 'Library shuffle'.i18n text: 'Library shuffle'.i18n));
));
}, },
), ),
FreezerDivider(), FreezerDivider(),
@ -91,8 +92,7 @@ class LibraryScreen extends StatelessWidget {
leading: LeadingIcon(Icons.audiotrack, color: Color(0xffbe3266)), leading: LeadingIcon(Icons.audiotrack, color: Color(0xffbe3266)),
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => LibraryTracks()) MaterialPageRoute(builder: (context) => LibraryTracks()));
);
}, },
), ),
ListTile( ListTile(
@ -100,8 +100,7 @@ class LibraryScreen extends StatelessWidget {
leading: LeadingIcon(Icons.album, color: Color(0xff4b2e7e)), leading: LeadingIcon(Icons.album, color: Color(0xff4b2e7e)),
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => LibraryAlbums()) MaterialPageRoute(builder: (context) => LibraryAlbums()));
);
}, },
), ),
ListTile( ListTile(
@ -109,8 +108,7 @@ class LibraryScreen extends StatelessWidget {
leading: LeadingIcon(Icons.recent_actors, color: Color(0xff384697)), leading: LeadingIcon(Icons.recent_actors, color: Color(0xff384697)),
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => LibraryArtists()) MaterialPageRoute(builder: (context) => LibraryArtists()));
);
}, },
), ),
ListTile( ListTile(
@ -118,8 +116,7 @@ class LibraryScreen extends StatelessWidget {
leading: LeadingIcon(Icons.playlist_play, color: Color(0xff0880b5)), leading: LeadingIcon(Icons.playlist_play, color: Color(0xff0880b5)),
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => LibraryPlaylists()) MaterialPageRoute(builder: (context) => LibraryPlaylists()));
);
}, },
), ),
FreezerDivider(), FreezerDivider(),
@ -128,8 +125,7 @@ class LibraryScreen extends StatelessWidget {
leading: LeadingIcon(Icons.history, color: Color(0xff009a85)), leading: LeadingIcon(Icons.history, color: Color(0xff009a85)),
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => HistoryScreen()) MaterialPageRoute(builder: (context) => HistoryScreen()));
);
}, },
), ),
FreezerDivider(), FreezerDivider(),
@ -139,16 +135,14 @@ class LibraryScreen extends StatelessWidget {
subtitle: Text('Import playlists from Spotify'.i18n), subtitle: Text('Import playlists from Spotify'.i18n),
onTap: () { onTap: () {
if (spotify.doneImporting != null) { if (spotify.doneImporting != null) {
Navigator.of(context).push( Navigator.of(context).push(MaterialPageRoute(
MaterialPageRoute(builder: (context) => CurrentlyImportingScreen()) builder: (context) => CurrentlyImportingScreen()));
);
if (spotify.doneImporting) spotify.doneImporting = null; if (spotify.doneImporting) spotify.doneImporting = null;
return; return;
} }
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => ImporterScreen()) MaterialPageRoute(builder: (context) => ImporterScreen()));
);
}, },
), ),
ExpansionTile( ExpansionTile(
@ -159,13 +153,12 @@ class LibraryScreen extends StatelessWidget {
future: downloadManager.getStats(), future: downloadManager.getStats(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasError) return ErrorScreen(); if (snapshot.hasError) return ErrorScreen();
if (!snapshot.hasData) return Padding( if (!snapshot.hasData)
return Padding(
padding: EdgeInsets.symmetric(vertical: 4.0), padding: EdgeInsets.symmetric(vertical: 4.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[CircularProgressIndicator()],
CircularProgressIndicator()
],
), ),
); );
List<String> data = snapshot.data; List<String> data = snapshot.data;
@ -214,7 +207,6 @@ class LibraryTracks extends StatefulWidget {
} }
class _LibraryTracksState extends State<LibraryTracks> { class _LibraryTracksState extends State<LibraryTracks> {
bool _loading = false; bool _loading = false;
bool _loadingTracks = false; bool _loadingTracks = false;
ScrollController _scrollController = ScrollController(); ScrollController _scrollController = ScrollController();
@ -233,15 +225,16 @@ class _LibraryTracksState extends State<LibraryTracks> {
tcopy.sort((a, b) => a.title.compareTo(b.title)); tcopy.sort((a, b) => a.title.compareTo(b.title));
break; break;
case SortType.ARTIST: case SortType.ARTIST:
tcopy.sort((a, b) => a.artists[0].name.toLowerCase().compareTo(b.artists[0].name.toLowerCase())); tcopy.sort((a, b) => a.artists[0].name
.toLowerCase()
.compareTo(b.artists[0].name.toLowerCase()));
break; break;
case SortType.DEFAULT: case SortType.DEFAULT:
default: default:
break; break;
} }
//Reverse //Reverse
if (_sort.reverse) if (_sort.reverse) return tcopy.reversed.toList();
return tcopy.reversed.toList();
return tcopy; return tcopy;
} }
@ -257,15 +250,15 @@ class _LibraryTracksState extends State<LibraryTracks> {
await cache.save(); await cache.save();
//Preload for sorting //Preload for sorting
if (tracks.length < (trackCount??0)) if (tracks.length < (trackCount ?? 0)) _loadFull();
_loadFull();
} }
Future _load() async { Future _load() async {
//Already loaded //Already loaded
if (trackCount != null && tracks.length >= trackCount) { if (trackCount != null && tracks.length >= trackCount) {
//Update tracks cache if fully loaded //Update tracks cache if fully loaded
if (cache.libraryTracks == null || cache.libraryTracks.length != trackCount) { if (cache.libraryTracks == null ||
cache.libraryTracks.length != trackCount) {
setState(() { setState(() {
cache.libraryTracks = tracks.map((t) => t.id).toList(); cache.libraryTracks = tracks.map((t) => t.id).toList();
}); });
@ -293,8 +286,7 @@ class _LibraryTracksState extends State<LibraryTracks> {
//Update //Update
setState(() { setState(() {
trackCount = favPlaylist.trackCount; trackCount = favPlaylist.trackCount;
if (tracks.length == 0) if (tracks.length == 0) tracks = favPlaylist.tracks;
tracks = favPlaylist.tracks;
_makeFavorite(); _makeFavorite();
_loading = false; _loading = false;
}); });
@ -307,7 +299,8 @@ class _LibraryTracksState extends State<LibraryTracks> {
List<Track> _t; List<Track> _t;
try { try {
_t = await deezerAPI.playlistTracksPage(deezerAPI.favoritesPlaylistId, pos); _t = await deezerAPI.playlistTracksPage(
deezerAPI.favoritesPlaylistId, pos);
} catch (e) {} } catch (e) {}
//On error load offline //On error load offline
if (_t == null) { if (_t == null) {
@ -320,13 +313,12 @@ class _LibraryTracksState extends State<LibraryTracks> {
_loading = false; _loading = false;
_loadingTracks = false; _loadingTracks = false;
}); });
} }
} }
//Load all tracks //Load all tracks
Future _loadFull() async { Future _loadFull() async {
if (tracks.length == 0 || tracks.length < (trackCount??0)) { if (tracks.length == 0 || tracks.length < (trackCount ?? 0)) {
Playlist p; Playlist p;
try { try {
p = await deezerAPI.fullPlaylist(deezerAPI.favoritesPlaylistId); p = await deezerAPI.fullPlaylist(deezerAPI.favoritesPlaylistId);
@ -342,8 +334,10 @@ class _LibraryTracksState extends State<LibraryTracks> {
} }
Future _loadOffline() async { Future _loadOffline() async {
Playlist p = await downloadManager.getPlaylist(deezerAPI.favoritesPlaylistId); Playlist p =
if (p != null) setState(() { await downloadManager.getPlaylist(deezerAPI.favoritesPlaylistId);
if (p != null)
setState(() {
tracks = p.tracks; tracks = p.tracks;
}); });
} }
@ -357,8 +351,7 @@ class _LibraryTracksState extends State<LibraryTracks> {
//Update tracks with favorite true //Update tracks with favorite true
void _makeFavorite() { void _makeFavorite() {
for (int i=0; i<tracks.length; i++) for (int i = 0; i < tracks.length; i++) tracks[i].favorite = true;
tracks[i].favorite = true;
} }
@override @override
@ -375,11 +368,9 @@ class _LibraryTracksState extends State<LibraryTracks> {
//Load sorting //Load sorting
int index = Sorting.index(SortSourceTypes.TRACKS); int index = Sorting.index(SortSourceTypes.TRACKS);
if (index != null) if (index != null) setState(() => _sort = cache.sorts[index]);
setState(() => _sort = cache.sorts[index]);
if (_sort.type != SortType.DEFAULT || _sort.reverse) if (_sort.type != SortType.DEFAULT || _sort.reverse) _loadFull();
_loadFull();
super.initState(); super.initState();
} }
@ -391,18 +382,18 @@ class _LibraryTracksState extends State<LibraryTracks> {
'Tracks'.i18n, 'Tracks'.i18n,
actions: [ actions: [
IconButton( IconButton(
icon: Icon(_sort.reverse ? FontAwesome5.sort_alpha_up : FontAwesome5.sort_alpha_down), icon: Icon(_sort.reverse
? FontAwesome5.sort_alpha_up
: FontAwesome5.sort_alpha_down),
onPressed: () async { onPressed: () async {
await _reverse(); await _reverse();
} }),
),
PopupMenuButton( PopupMenuButton(
child: Icon(Icons.sort, size: 32.0), child: Icon(Icons.sort, size: 32.0),
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
onSelected: (SortType s) async { onSelected: (SortType s) async {
//Preload for sorting //Preload for sorting
if (tracks.length < (trackCount??0)) if (tracks.length < (trackCount ?? 0)) await _loadFull();
await _loadFull();
setState(() => _sort.type = s); setState(() => _sort.type = s);
//Save sorting in cache //Save sorting in cache
@ -444,45 +435,54 @@ class _LibraryTracksState extends State<LibraryTracks> {
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[ children: <Widget>[
MakePlaylistOffline(_playlist), MakePlaylistOffline(_playlist),
FlatButton( TextButton(
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Icon(Icons.file_download, size: 32.0,), Icon(
Container(width: 4,), Icons.file_download,
size: 32.0,
),
Container(
width: 4,
),
Text('Download'.i18n) Text('Download'.i18n)
], ],
), ),
onPressed: () async { onPressed: () async {
if (await downloadManager.addOfflinePlaylist(_playlist, private: false, context: context) != false) if (await downloadManager.addOfflinePlaylist(_playlist,
private: false, context: context) !=
false)
MenuSheet(context).showDownloadStartedToast(); MenuSheet(context).showDownloadStartedToast();
}, },
) )
], ],
) )),
),
FreezerDivider(), FreezerDivider(),
//Loved tracks //Loved tracks
...List.generate(tracks.length, (i) { ...List.generate(tracks.length, (i) {
Track t = (tracks.length == (trackCount??0))?_sorted[i]:tracks[i]; Track t = (tracks.length == (trackCount ?? 0))
? _sorted[i]
: tracks[i];
return TrackTile( return TrackTile(
t, t,
onTap: () { onTap: () {
playerHelper.playFromTrackList((tracks.length == (trackCount??0))?_sorted:tracks, t.id, QueueSource( playerHelper.playFromTrackList(
(tracks.length == (trackCount ?? 0))
? _sorted
: tracks,
t.id,
QueueSource(
id: deezerAPI.favoritesPlaylistId, id: deezerAPI.favoritesPlaylistId,
text: 'Favorites'.i18n, text: 'Favorites'.i18n,
source: 'playlist' source: 'playlist'));
));
}, },
onHold: () { onHold: () {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
m.defaultTrackMenu( m.defaultTrackMenu(t, onRemove: () {
t,
onRemove: () {
setState(() { setState(() {
tracks.removeWhere((track) => t.id == track.id); tracks.removeWhere((track) => t.id == track.id);
}); });
} });
);
}, },
); );
}), }),
@ -500,22 +500,23 @@ class _LibraryTracksState extends State<LibraryTracks> {
Text( Text(
'All offline tracks'.i18n, 'All offline tracks'.i18n,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
fontSize: 24,
fontWeight: FontWeight.bold
), ),
Container(
height: 8,
), ),
Container(height: 8,),
...List.generate(allTracks.length, (i) { ...List.generate(allTracks.length, (i) {
Track t = allTracks[i]; Track t = allTracks[i];
return TrackTile( return TrackTile(
t, t,
onTap: () { onTap: () {
playerHelper.playFromTrackList(allTracks, t.id, QueueSource( playerHelper.playFromTrackList(
allTracks,
t.id,
QueueSource(
id: 'allTracks', id: 'allTracks',
text: 'All offline tracks'.i18n, text: 'All offline tracks'.i18n,
source: 'offline' source: 'offline'));
));
}, },
onHold: () { onHold: () {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
@ -524,19 +525,16 @@ class _LibraryTracksState extends State<LibraryTracks> {
); );
}) })
], ],
) )));
));
} }
} }
class LibraryAlbums extends StatefulWidget { class LibraryAlbums extends StatefulWidget {
@override @override
_LibraryAlbumsState createState() => _LibraryAlbumsState(); _LibraryAlbumsState createState() => _LibraryAlbumsState();
} }
class _LibraryAlbumsState extends State<LibraryAlbums> { class _LibraryAlbumsState extends State<LibraryAlbums> {
List<Album> _albums; List<Album> _albums;
Sorting _sort = Sorting(sourceType: SortSourceTypes.ALBUMS); Sorting _sort = Sorting(sourceType: SortSourceTypes.ALBUMS);
ScrollController _scrollController = ScrollController(); ScrollController _scrollController = ScrollController();
@ -548,22 +546,26 @@ class _LibraryAlbumsState extends State<LibraryAlbums> {
case SortType.DEFAULT: case SortType.DEFAULT:
break; break;
case SortType.ALPHABETIC: case SortType.ALPHABETIC:
albums.sort((a, b) => a.title.toLowerCase().compareTo(b.title.toLowerCase())); albums.sort(
(a, b) => a.title.toLowerCase().compareTo(b.title.toLowerCase()));
break; break;
case SortType.ARTIST: case SortType.ARTIST:
albums.sort((a, b) => a.artists[0].name.toLowerCase().compareTo(b.artists[0].name.toLowerCase())); albums.sort((a, b) => a.artists[0].name
.toLowerCase()
.compareTo(b.artists[0].name.toLowerCase()));
break; break;
case SortType.RELEASE_DATE: case SortType.RELEASE_DATE:
albums.sort((a, b) => DateTime.parse(a.releaseDate).compareTo(DateTime.parse(b.releaseDate))); albums.sort((a, b) => DateTime.parse(a.releaseDate)
.compareTo(DateTime.parse(b.releaseDate)));
break;
default:
break; break;
} }
//Reverse //Reverse
if (_sort.reverse) if (_sort.reverse) return albums.reversed.toList();
return albums.reversed.toList();
return albums; return albums;
} }
Future _load() async { Future _load() async {
if (settings.offlineMode) return; if (settings.offlineMode) return;
try { try {
@ -577,8 +579,7 @@ class _LibraryAlbumsState extends State<LibraryAlbums> {
_load(); _load();
//Load sorting //Load sorting
int index = Sorting.index(SortSourceTypes.ALBUMS); int index = Sorting.index(SortSourceTypes.ALBUMS);
if (index != null) if (index != null) _sort = cache.sorts[index];
_sort = cache.sorts[index];
super.initState(); super.initState();
} }
@ -602,7 +603,9 @@ class _LibraryAlbumsState extends State<LibraryAlbums> {
'Albums'.i18n, 'Albums'.i18n,
actions: [ actions: [
IconButton( IconButton(
icon: Icon(_sort.reverse ? FontAwesome5.sort_alpha_up : FontAwesome5.sort_alpha_down), icon: Icon(_sort.reverse
? FontAwesome5.sort_alpha_up
: FontAwesome5.sort_alpha_down),
onPressed: () => _reverse(), onPressed: () => _reverse(),
), ),
PopupMenuButton( PopupMenuButton(
@ -647,24 +650,22 @@ class _LibraryAlbumsState extends State<LibraryAlbums> {
child: ListView( child: ListView(
controller: _scrollController, controller: _scrollController,
children: <Widget>[ children: <Widget>[
Container(height: 8.0,), Container(
height: 8.0,
),
if (!settings.offlineMode && _albums == null) if (!settings.offlineMode && _albums == null)
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[CircularProgressIndicator()],
CircularProgressIndicator()
],
), ),
if (_albums != null) if (_albums != null)
...List.generate(_albums.length, (int i) { ...List.generate(_albums.length, (int i) {
Album a = _sorted[i]; Album a = _sorted[i];
return AlbumTile( return AlbumTile(
a, a,
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(MaterialPageRoute(
MaterialPageRoute(builder: (context) => AlbumDetails(a)) builder: (context) => AlbumDetails(a)));
);
}, },
onHold: () async { onHold: () async {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
@ -674,11 +675,16 @@ class _LibraryAlbumsState extends State<LibraryAlbums> {
}, },
); );
}), }),
FutureBuilder( FutureBuilder(
future: downloadManager.getOfflineAlbums(), future: downloadManager.getOfflineAlbums(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasError || !snapshot.hasData || snapshot.data.length == 0) return Container(height: 0, width: 0,); if (snapshot.hasError ||
!snapshot.hasData ||
snapshot.data.length == 0)
return Container(
height: 0,
width: 0,
);
List<Album> albums = snapshot.data; List<Album> albums = snapshot.data;
return Column( return Column(
@ -688,18 +694,15 @@ class _LibraryAlbumsState extends State<LibraryAlbums> {
'Offline albums'.i18n, 'Offline albums'.i18n,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold, fontSize: 24.0),
fontSize: 24.0
),
), ),
...List.generate(albums.length, (i) { ...List.generate(albums.length, (i) {
Album a = albums[i]; Album a = albums[i];
return AlbumTile( return AlbumTile(
a, a,
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(MaterialPageRoute(
MaterialPageRoute(builder: (context) => AlbumDetails(a)) builder: (context) => AlbumDetails(a)));
);
}, },
onHold: () async { onHold: () async {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
@ -722,14 +725,12 @@ class _LibraryAlbumsState extends State<LibraryAlbums> {
} }
} }
class LibraryArtists extends StatefulWidget { class LibraryArtists extends StatefulWidget {
@override @override
_LibraryArtistsState createState() => _LibraryArtistsState(); _LibraryArtistsState createState() => _LibraryArtistsState();
} }
class _LibraryArtistsState extends State<LibraryArtists> { class _LibraryArtistsState extends State<LibraryArtists> {
List<Artist> _artists; List<Artist> _artists;
Sorting _sort = Sorting(sourceType: SortSourceTypes.ARTISTS); Sorting _sort = Sorting(sourceType: SortSourceTypes.ARTISTS);
bool _loading = true; bool _loading = true;
@ -746,12 +747,14 @@ class _LibraryArtistsState extends State<LibraryArtists> {
artists.sort((a, b) => b.fans - a.fans); artists.sort((a, b) => b.fans - a.fans);
break; break;
case SortType.ALPHABETIC: case SortType.ALPHABETIC:
artists.sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase())); artists.sort(
(a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
break;
default:
break; break;
} }
//Reverse //Reverse
if (_sort.reverse) if (_sort.reverse) return artists.reversed.toList();
return artists.reversed.toList();
return artists; return artists;
} }
@ -786,13 +789,11 @@ class _LibraryArtistsState extends State<LibraryArtists> {
await cache.save(); await cache.save();
} }
@override @override
void initState() { void initState() {
//Restore sort //Restore sort
int index = Sorting.index(SortSourceTypes.ARTISTS); int index = Sorting.index(SortSourceTypes.ARTISTS);
if (index != null) if (index != null) _sort = cache.sorts[index];
_sort = cache.sorts[index];
_load(); _load();
super.initState(); super.initState();
@ -805,7 +806,9 @@ class _LibraryArtistsState extends State<LibraryArtists> {
'Artists'.i18n, 'Artists'.i18n,
actions: [ actions: [
IconButton( IconButton(
icon: Icon(_sort.reverse ? FontAwesome5.sort_alpha_up : FontAwesome5.sort_alpha_down), icon: Icon(_sort.reverse
? FontAwesome5.sort_alpha_up
: FontAwesome5.sort_alpha_down),
onPressed: () => _reverse(), onPressed: () => _reverse(),
), ),
PopupMenuButton( PopupMenuButton(
@ -854,19 +857,15 @@ class _LibraryArtistsState extends State<LibraryArtists> {
children: [CircularProgressIndicator()], children: [CircularProgressIndicator()],
), ),
), ),
if (_error) Center(child: ErrorScreen()),
if (_error)
Center(child: ErrorScreen()),
if (!_loading && !_error) if (!_loading && !_error)
...List.generate(_artists.length, (i) { ...List.generate(_artists.length, (i) {
Artist a = _sorted[i]; Artist a = _sorted[i];
return ArtistHorizontalTile( return ArtistHorizontalTile(
a, a,
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(MaterialPageRoute(
MaterialPageRoute(builder: (context) => ArtistDetails(a)) builder: (context) => ArtistDetails(a)));
);
}, },
onHold: () { onHold: () {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
@ -890,29 +889,33 @@ class LibraryPlaylists extends StatefulWidget {
} }
class _LibraryPlaylistsState extends State<LibraryPlaylists> { class _LibraryPlaylistsState extends State<LibraryPlaylists> {
List<Playlist> _playlists; List<Playlist> _playlists;
Sorting _sort = Sorting(sourceType: SortSourceTypes.PLAYLISTS); Sorting _sort = Sorting(sourceType: SortSourceTypes.PLAYLISTS);
ScrollController _scrollController = ScrollController(); ScrollController _scrollController = ScrollController();
String _filter = ''; String _filter = '';
List<Playlist> get _sorted { List<Playlist> get _sorted {
List<Playlist> playlists = List.from(_playlists.where((p) => p.title.toLowerCase().contains(_filter.toLowerCase()))); List<Playlist> playlists = List.from(_playlists
.where((p) => p.title.toLowerCase().contains(_filter.toLowerCase())));
switch (_sort.type) { switch (_sort.type) {
case SortType.DEFAULT: case SortType.DEFAULT:
break; break;
case SortType.USER: case SortType.USER:
playlists.sort((a, b) => (a.user.name??deezerAPI.userName).toLowerCase().compareTo((b.user.name??deezerAPI.userName).toLowerCase())); playlists.sort((a, b) => (a.user.name ?? deezerAPI.userName)
.toLowerCase()
.compareTo((b.user.name ?? deezerAPI.userName).toLowerCase()));
break; break;
case SortType.TRACK_COUNT: case SortType.TRACK_COUNT:
playlists.sort((a, b) => b.trackCount - a.trackCount); playlists.sort((a, b) => b.trackCount - a.trackCount);
break; break;
case SortType.ALPHABETIC: case SortType.ALPHABETIC:
playlists.sort((a, b) => a.title.toLowerCase().compareTo(b.title.toLowerCase())); playlists.sort(
(a, b) => a.title.toLowerCase().compareTo(b.title.toLowerCase()));
break;
default:
break; break;
} }
if (_sort.reverse) if (_sort.reverse) return playlists.reversed.toList();
return playlists.reversed.toList();
return playlists; return playlists;
} }
@ -941,8 +944,7 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
void initState() { void initState() {
//Restore sort //Restore sort
int index = Sorting.index(SortSourceTypes.PLAYLISTS); int index = Sorting.index(SortSourceTypes.PLAYLISTS);
if (index != null) if (index != null) _sort = cache.sorts[index];
_sort = cache.sorts[index];
_load(); _load();
super.initState(); super.initState();
@ -955,9 +957,7 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
image: ImageDetails(thumbUrl: 'assets/favorites_thumb.jpg'), image: ImageDetails(thumbUrl: 'assets/favorites_thumb.jpg'),
tracks: [], tracks: [],
trackCount: 1, trackCount: 1,
duration: Duration(seconds: 0) duration: Duration(seconds: 0));
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -966,7 +966,9 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
'Playlists'.i18n, 'Playlists'.i18n,
actions: [ actions: [
IconButton( IconButton(
icon: Icon(_sort.reverse ? FontAwesome5.sort_alpha_up : FontAwesome5.sort_alpha_down), icon: Icon(_sort.reverse
? FontAwesome5.sort_alpha_up
: FontAwesome5.sort_alpha_down),
onPressed: () => _reverse(), onPressed: () => _reverse(),
), ),
PopupMenuButton( PopupMenuButton(
@ -1021,23 +1023,20 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
fillColor: Theme.of(context).bottomAppBarColor, fillColor: Theme.of(context).bottomAppBarColor,
filled: true, filled: true,
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey) borderSide: BorderSide(color: Colors.grey)),
),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey) borderSide: BorderSide(color: Colors.grey)),
), )),
)
),
), ),
ListTile( ListTile(
title: Text('Create new playlist'.i18n), title: Text('Create new playlist'.i18n),
leading: LeadingIcon(Icons.playlist_add, color: Color(0xff009a85)), leading:
LeadingIcon(Icons.playlist_add, color: Color(0xff009a85)),
onTap: () async { onTap: () async {
if (settings.offlineMode) { if (settings.offlineMode) {
Fluttertoast.showToast( Fluttertoast.showToast(
msg: 'Cannot create playlists in offline mode'.i18n, msg: 'Cannot create playlists in offline mode'.i18n,
gravity: ToastGravity.BOTTOM gravity: ToastGravity.BOTTOM);
);
return; return;
} }
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
@ -1060,8 +1059,8 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
favoritesPlaylist, favoritesPlaylist,
onTap: () async { onTap: () async {
Navigator.of(context).push(MaterialPageRoute( Navigator.of(context).push(MaterialPageRoute(
builder: (context) => PlaylistDetails(favoritesPlaylist) builder: (context) =>
)); PlaylistDetails(favoritesPlaylist)));
}, },
onHold: () { onHold: () {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
@ -1072,18 +1071,18 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
if (_playlists != null) if (_playlists != null)
...List.generate(_sorted.length, (int i) { ...List.generate(_sorted.length, (int i) {
Playlist p = (_sorted??[])[i]; Playlist p = (_sorted ?? [])[i];
return PlaylistTile( return PlaylistTile(
p, p,
onTap: () => Navigator.of(context).push(MaterialPageRoute( onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => PlaylistDetails(p) builder: (context) => PlaylistDetails(p))),
)),
onHold: () { onHold: () {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
m.defaultPlaylistMenu( m.defaultPlaylistMenu(p, onRemove: () {
p, setState(() => _playlists.remove(p));
onRemove: () {setState(() => _playlists.remove(p));}, }, onUpdate: () {
onUpdate: () {_load();}); _load();
});
}, },
); );
}), }),
@ -1091,8 +1090,16 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
FutureBuilder( FutureBuilder(
future: downloadManager.getOfflinePlaylists(), future: downloadManager.getOfflinePlaylists(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasError || !snapshot.hasData) return Container(height: 0, width: 0,); if (snapshot.hasError || !snapshot.hasData)
if (snapshot.data.length == 0) return Container(height: 0, width: 0,); return Container(
height: 0,
width: 0,
);
if (snapshot.data.length == 0)
return Container(
height: 0,
width: 0,
);
List<Playlist> playlists = snapshot.data; List<Playlist> playlists = snapshot.data;
return Column( return Column(
@ -1102,17 +1109,15 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
'Offline playlists'.i18n, 'Offline playlists'.i18n,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 24.0, fontSize: 24.0, fontWeight: FontWeight.bold),
fontWeight: FontWeight.bold
),
), ),
...List.generate(playlists.length, (i) { ...List.generate(playlists.length, (i) {
Playlist p = playlists[i]; Playlist p = playlists[i];
return PlaylistTile( return PlaylistTile(
p, p,
onTap: () => Navigator.of(context).push(MaterialPageRoute( onTap: () => Navigator.of(context).push(
builder: (context) => PlaylistDetails(p) MaterialPageRoute(
)), builder: (context) => PlaylistDetails(p))),
onHold: () { onHold: () {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
m.defaultPlaylistMenu(p, onRemove: () { m.defaultPlaylistMenu(p, onRemove: () {
@ -1128,7 +1133,6 @@ class _LibraryPlaylistsState extends State<LibraryPlaylists> {
); );
}, },
) )
], ],
), ),
)); ));
@ -1162,17 +1166,17 @@ class _HistoryScreenState extends State<HistoryScreen> {
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
child: ListView.builder( child: ListView.builder(
controller: _scrollController, controller: _scrollController,
itemCount: (cache.history??[]).length, itemCount: (cache.history ?? []).length,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
Track t = cache.history[cache.history.length - i - 1]; Track t = cache.history[cache.history.length - i - 1];
return TrackTile( return TrackTile(
t, t,
onTap: () { onTap: () {
playerHelper.playFromTrackList(cache.history.reversed.toList(), t.id, QueueSource( playerHelper.playFromTrackList(
id: null, cache.history.reversed.toList(),
text: 'History'.i18n, t.id,
source: 'history' QueueSource(
)); id: null, text: 'History'.i18n, source: 'history'));
}, },
onHold: () { onHold: () {
MenuSheet m = MenuSheet(context); MenuSheet m = MenuSheet(context);
@ -1180,9 +1184,7 @@ class _HistoryScreenState extends State<HistoryScreen> {
}, },
); );
}, },
) )),
),
); );
} }
} }

View file

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:freezer/main.dart'; import 'package:freezer/main.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -697,14 +696,14 @@ class _SleepTimerDialogState extends State<SleepTimerDialog> {
], ],
), ),
actions: [ actions: [
FlatButton( TextButton(
child: Text('Dismiss'.i18n), child: Text('Dismiss'.i18n),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
), ),
if (cache.sleepTimer != null) if (cache.sleepTimer != null)
FlatButton( TextButton(
child: Text('Cancel current timer'.i18n), child: Text('Cancel current timer'.i18n),
onPressed: () { onPressed: () {
cache.sleepTimer.cancel(); cache.sleepTimer.cancel();
@ -714,7 +713,7 @@ class _SleepTimerDialogState extends State<SleepTimerDialog> {
}, },
), ),
FlatButton( TextButton(
child: Text('Save'.i18n), child: Text('Save'.i18n),
onPressed: () { onPressed: () {
Duration duration = Duration(hours: hours, minutes: minutes); Duration duration = Duration(hours: hours, minutes: minutes);
@ -891,11 +890,11 @@ class _CreatePlaylistDialogState extends State<CreatePlaylistDialog> {
], ],
), ),
actions: <Widget>[ actions: <Widget>[
FlatButton( TextButton(
child: Text('Cancel'.i18n), child: Text('Cancel'.i18n),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
FlatButton( TextButton(
child: Text(edit ? 'Update'.i18n : 'Create'.i18n), child: Text(edit ? 'Update'.i18n : 'Create'.i18n),
onPressed: () async { onPressed: () async {
if (edit) { if (edit) {

View file

@ -63,13 +63,15 @@ class _PlayerScreenState extends State<PlayerScreen> {
if (settings.blurPlayerBackground) if (settings.blurPlayerBackground)
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: palette.dominantColor.color.withOpacity(0.25), statusBarColor: palette.dominantColor.color.withOpacity(0.25),
systemNavigationBarColor: Color.alphaBlend(palette.dominantColor.color.withOpacity(0.25), Theme.of(context).scaffoldBackgroundColor) systemNavigationBarColor: Color.alphaBlend(palette.dominantColor.color.withOpacity(0.25), Theme.of(context).scaffoldBackgroundColor),
systemNavigationBarIconBrightness: ThemeData.estimateBrightnessForColor(palette.dominantColor.color) == Brightness.light ? Brightness.dark : Brightness.light
)); ));
//Color gradient //Color gradient
if (!settings.blurPlayerBackground) { if (!settings.blurPlayerBackground) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: palette.dominantColor.color.withOpacity(0.7), statusBarColor: palette.dominantColor.color.withOpacity(0.7),
statusBarIconBrightness: ThemeData.estimateBrightnessForColor(palette.dominantColor.color.withOpacity(0.7)) == Brightness.light ? Brightness.dark : Brightness.light
)); ));
setState(() => _bgGradient = LinearGradient( setState(() => _bgGradient = LinearGradient(
begin: Alignment.topCenter, begin: Alignment.topCenter,
@ -425,7 +427,7 @@ class _QualityInfoWidgetState extends State<QualityInfoWidget> {
_load(); _load();
if (streamSubscription == null) if (streamSubscription == null)
streamSubscription = AudioService.currentMediaItemStream.listen((event) async { streamSubscription = AudioService.currentMediaItemStream.listen((event) async {
await _load(); _load();
}); });
super.initState(); super.initState();
} }
@ -439,7 +441,7 @@ class _QualityInfoWidgetState extends State<QualityInfoWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FlatButton( return TextButton(
child: Text(value), child: Text(value),
onPressed: () { onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => QualitySettings())); Navigator.of(context).push(MaterialPageRoute(builder: (context) => QualitySettings()));
@ -641,10 +643,10 @@ class _BigAlbumArtState extends State<BigAlbumArt> {
//Top row containing QueueSource, queue... //Top row containing QueueSource, queue...
class PlayerScreenTopRow extends StatelessWidget { class PlayerScreenTopRow extends StatelessWidget {
double textSize; final double textSize;
double iconSize; final double iconSize;
double textWidth; final double textWidth;
bool short; final bool short;
PlayerScreenTopRow({this.textSize, this.iconSize, this.textWidth, this.short}); PlayerScreenTopRow({this.textSize, this.iconSize, this.textWidth, this.short});
@override @override

View file

@ -7,7 +7,6 @@ import 'package:flutter/src/services/keyboard_key.dart';
import 'package:freezer/api/cache.dart'; import 'package:freezer/api/cache.dart';
import 'package:freezer/api/download.dart'; import 'package:freezer/api/download.dart';
import 'package:freezer/api/player.dart'; import 'package:freezer/api/player.dart';
import 'package:freezer/main.dart';
import 'package:freezer/ui/details_screens.dart'; import 'package:freezer/ui/details_screens.dart';
import 'package:freezer/ui/elements.dart'; import 'package:freezer/ui/elements.dart';
import 'package:freezer/ui/home_screen.dart'; import 'package:freezer/ui/home_screen.dart';
@ -59,7 +58,7 @@ class _SearchScreenState extends State<SearchScreen> {
List _suggestions = []; List _suggestions = [];
bool _cancel = false; bool _cancel = false;
bool _showCards = true; bool _showCards = true;
FocusNode _focus = FocusNode(); //FocusNode _focus = FocusNode();
void _submit(BuildContext context, {String query}) async { void _submit(BuildContext context, {String query}) async {
if (query != null) _query = query; if (query != null) _query = query;
@ -94,7 +93,7 @@ class _SearchScreenState extends State<SearchScreen> {
} }
//Load search suggestions //Load search suggestions
Future<List<String>> _loadSuggestions() async { Future<void> _loadSuggestions() async {
if (_query == null || _query.length < 2 || _query.startsWith('http')) return null; if (_query == null || _query.length < 2 || _query.startsWith('http')) return null;
String q = _query; String q = _query;
await Future.delayed(Duration(milliseconds: 300)); await Future.delayed(Duration(milliseconds: 300));

View file

@ -2,7 +2,6 @@ import 'package:audio_service/audio_service.dart';
import 'package:country_pickers/country.dart'; import 'package:country_pickers/country.dart';
import 'package:country_pickers/country_picker_dialog.dart'; import 'package:country_pickers/country_picker_dialog.dart';
import 'package:filesize/filesize.dart'; import 'package:filesize/filesize.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart';
@ -23,7 +22,6 @@ import 'package:package_info/package_info.dart';
import 'package:path_provider_ex/path_provider_ex.dart'; import 'package:path_provider_ex/path_provider_ex.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:freezer/translations.i18n.dart'; import 'package:freezer/translations.i18n.dart';
import 'package:clipboard/clipboard.dart';
import 'package:scrobblenaut/scrobblenaut.dart'; import 'package:scrobblenaut/scrobblenaut.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -106,7 +104,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
title: Text('Language'.i18n), title: Text('Language'.i18n),
content: Text('Language changed, please restart Freezer to apply!'.i18n), content: Text('Language changed, please restart Freezer to apply!'.i18n),
actions: [ actions: [
FlatButton( TextButton(
child: Text('OK'), child: Text('OK'),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -387,7 +385,7 @@ class _FontSelectorState extends State<FontSelector> {
title: Text('Warning'.i18n), title: Text('Warning'.i18n),
content: Text("This app isn't made for supporting many fonts, it can break layouts and overflow. Use at your own risk!".i18n), content: Text("This app isn't made for supporting many fonts, it can break layouts and overflow. Use at your own risk!".i18n),
actions: [ actions: [
FlatButton( TextButton(
onPressed: () async { onPressed: () async {
setState(() => settings.font = font); setState(() => settings.font = font);
await settings.save(); await settings.save();
@ -398,7 +396,7 @@ class _FontSelectorState extends State<FontSelector> {
}, },
child: Text('Apply'.i18n), child: Text('Apply'.i18n),
), ),
FlatButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
widget.callback(); widget.callback();
@ -739,8 +737,8 @@ class _DeezerSettingsState extends State<DeezerSettings> {
class FilenameTemplateDialog extends StatefulWidget { class FilenameTemplateDialog extends StatefulWidget {
String initial; final String initial;
Function onSave; final Function onSave;
FilenameTemplateDialog(this.initial, this.onSave, {Key key}): super(key: key); FilenameTemplateDialog(this.initial, this.onSave, {Key key}): super(key: key);
@override @override
@ -782,22 +780,22 @@ class _FilenameTemplateDialogState extends State<FilenameTemplateDialog> {
], ],
), ),
actions: [ actions: [
FlatButton( TextButton(
child: Text('Cancel'.i18n), child: Text('Cancel'.i18n),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
FlatButton( TextButton(
child: Text('Reset'.i18n), child: Text('Reset'.i18n),
onPressed: () { onPressed: () {
_controller.value = _controller.value.copyWith(text: '%artist% - %title%'); _controller.value = _controller.value.copyWith(text: '%artist% - %title%');
_new = '%artist% - %title%'; _new = '%artist% - %title%';
}, },
), ),
FlatButton( TextButton(
child: Text('Clear'.i18n), child: Text('Clear'.i18n),
onPressed: () => _controller.clear(), onPressed: () => _controller.clear(),
), ),
FlatButton( TextButton(
child: Text('Save'.i18n), child: Text('Save'.i18n),
onPressed: () async { onPressed: () async {
widget.onSave(_new); widget.onSave(_new);
@ -907,7 +905,7 @@ class _DownloadsSettingsState extends State<DownloadsSettings> {
title: Text('Warning'.i18n), title: Text('Warning'.i18n),
content: Text('Using too many concurrent downloads on older/weaker devices might cause crashes!'.i18n), content: Text('Using too many concurrent downloads on older/weaker devices might cause crashes!'.i18n),
actions: [ actions: [
FlatButton( TextButton(
child: Text('Dismiss'.i18n), child: Text('Dismiss'.i18n),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
) )
@ -1195,7 +1193,7 @@ class _GeneralSettingsState extends State<GeneralSettings> {
subtitle: Text('Copy userToken/ARL Cookie for use in other apps.'.i18n), subtitle: Text('Copy userToken/ARL Cookie for use in other apps.'.i18n),
leading: Icon(Icons.lock), leading: Icon(Icons.lock),
onTap: () async { onTap: () async {
await FlutterClipboard.copy(settings.arl); Clipboard.setData(ClipboardData(text: settings.arl));
await Fluttertoast.showToast( await Fluttertoast.showToast(
msg: 'Copied'.i18n, msg: 'Copied'.i18n,
); );
@ -1251,7 +1249,7 @@ class _GeneralSettingsState extends State<GeneralSettings> {
// content: Text('Due to plugin incompatibility, login using browser is unavailable without restart.'.i18n), // content: Text('Due to plugin incompatibility, login using browser is unavailable without restart.'.i18n),
content: Text('Restart of app is required to properly log out!'.i18n), content: Text('Restart of app is required to properly log out!'.i18n),
actions: <Widget>[ actions: <Widget>[
FlatButton( TextButton(
child: Text('Cancel'.i18n), child: Text('Cancel'.i18n),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
@ -1262,7 +1260,7 @@ class _GeneralSettingsState extends State<GeneralSettings> {
// Navigator.of(context).pop(); // Navigator.of(context).pop();
// }, // },
// ), // ),
FlatButton( TextButton(
child: Text('Log out & Exit'.i18n), child: Text('Log out & Exit'.i18n),
onPressed: () async { onPressed: () async {
try {AudioService.stop();} catch (e) {} try {AudioService.stop();} catch (e) {}
@ -1329,11 +1327,11 @@ class _LastFMLoginState extends State<LastFMLogin> {
], ],
), ),
actions: [ actions: [
FlatButton( TextButton(
child: Text('Cancel'.i18n), child: Text('Cancel'.i18n),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
FlatButton( TextButton(
child: Text('Login'.i18n), child: Text('Login'.i18n),
onPressed: () async { onPressed: () async {
LastFM last; LastFM last;
@ -1398,7 +1396,6 @@ class _DirectoryPickerState extends State<DirectoryPicker> {
IconButton( IconButton(
icon: Icon(Icons.sd_card), icon: Icon(Icons.sd_card),
onPressed: () { onPressed: () {
String path = '';
//Chose storage //Chose storage
showDialog( showDialog(
context: context, context: context,

View file

@ -1,6 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:freezer/api/cache.dart'; import 'package:freezer/api/cache.dart';
@ -168,12 +167,12 @@ class _UpdaterScreenState extends State<UpdaterScreen> {
//Available download //Available download
if (_versionDownload != null) if (_versionDownload != null)
Column(children: [ Column(children: [
RaisedButton( ElevatedButton(
child: Text('Download'.i18n + ' (${_versionDownload.version})'), child: Text('Download'.i18n + ' (${_versionDownload.version})'),
onPressed: _buttonEnabled ? () { onPressed: _buttonEnabled ? () {
setState(() => _buttonEnabled = false); setState(() => _buttonEnabled = false);
_download(); _download();
}:null } : null
), ),
Padding( Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),

View file

@ -58,7 +58,6 @@ dependencies:
marquee: ^1.5.2 marquee: ^1.5.2
flutter_cache_manager: ^1.4.1 flutter_cache_manager: ^1.4.1
cached_network_image: ^2.3.2+1 cached_network_image: ^2.3.2+1
clipboard: ^0.1.2+8
i18n_extension: ^4.0.0 i18n_extension: ^4.0.0
fluttericon: ^1.0.7 fluttericon: ^1.0.7
url_launcher: ^5.7.2 url_launcher: ^5.7.2