0.6.7 - shows in search, album art resolution

This commit is contained in:
exttex 2020-12-14 18:29:28 +01:00
parent babd12bae2
commit c3a26b0e3b
18 changed files with 369 additions and 28 deletions

View file

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:wakelock/wakelock.dart';
import 'package:flutter/material.dart';
import 'package:audio_service/audio_service.dart';
import 'package:fluttertoast/fluttertoast.dart';
@ -585,6 +586,33 @@ class MenuSheet {
},
);
Widget wakelock() => ListTile(
title: Text('Keep the screen on'.i18n),
leading: Icon(Icons.screen_lock_portrait),
onTap: () async {
_close();
if (cache.wakelock == null)
cache.wakelock = false;
//Enable
if (!cache.wakelock) {
Wakelock.enable();
Fluttertoast.showToast(
msg: 'Wakelock enabled!'.i18n,
gravity: ToastGravity.BOTTOM
);
cache.wakelock = true;
return;
}
//Disable
Wakelock.disable();
Fluttertoast.showToast(
msg: 'Wakelock disabled!'.i18n,
gravity: ToastGravity.BOTTOM
);
cache.wakelock = false;
},
);
void _close() => Navigator.of(context).pop();
}

View file

@ -280,7 +280,7 @@ class _PlayerScreenVerticalState extends State<PlayerScreenVertical> {
children: <Widget>[
Container(
height: ScreenUtil().setSp(64),
child: AudioService.currentMediaItem.displayTitle.length >= 24 ?
child: AudioService.currentMediaItem.displayTitle.length >= 26 ?
Marquee(
text: AudioService.currentMediaItem.displayTitle,
style: TextStyle(
@ -410,12 +410,12 @@ class PlayerMenuButton extends StatelessWidget {
Track t = Track.fromMediaItem(AudioService.currentMediaItem);
MenuSheet m = MenuSheet(context);
if (AudioService.currentMediaItem.extras['show'] == null)
m.defaultTrackMenu(t, options: [m.sleepTimer()]);
m.defaultTrackMenu(t, options: [m.sleepTimer(), m.wakelock()]);
else
m.defaultShowEpisodeMenu(
Show.fromJson(jsonDecode(AudioService.currentMediaItem.extras['show'])),
ShowEpisode.fromMediaItem(AudioService.currentMediaItem),
options: [m.sleepTimer()]
options: [m.sleepTimer(), m.wakelock()]
);
},
);
@ -771,6 +771,13 @@ class _QueueScreenState extends State<QueueScreen> {
Navigator.of(context).pop();
},
key: Key(t.id),
trailing: IconButton(
icon: Icon(Icons.close),
onPressed: () async {
await AudioService.removeQueueItem(t.toMediaItem());
setState(() {});
},
),
);
}),
)

View file

@ -7,6 +7,7 @@ import 'package:flutter/src/services/keyboard_key.dart';
import 'package:freezer/api/cache.dart';
import 'package:freezer/api/download.dart';
import 'package:freezer/api/player.dart';
import 'package:freezer/main.dart';
import 'package:freezer/ui/details_screens.dart';
import 'package:freezer/ui/elements.dart';
import 'package:freezer/ui/home_screen.dart';
@ -657,6 +658,91 @@ class SearchResultsScreen extends StatelessWidget {
MaterialPageRoute(builder: (context) => SearchResultPlaylists(results.playlists))
);
},
),
FreezerDivider()
];
}
//Shows
List<Widget> shows = [];
if (results.shows != null && results.shows.length != 0) {
shows = [
Padding(
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0),
child: Text(
'Shows'.i18n,
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold
),
),
),
...List.generate(3, (i) {
if (results.shows.length <= i) return Container(height: 0, width: 0,);
Show s = results.shows[i];
return ShowTile(
s,
onTap: () async {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ShowScreen(s)
));
},
);
}),
ListTile(
title: Text('Show all shows'.i18n),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => ShowListScreen(results.shows))
);
},
),
FreezerDivider()
];
}
//Episodes
List<Widget> episodes = [];
if (results.episodes != null && results.episodes.length != 0) {
episodes = [
Padding(
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0),
child: Text(
'Episodes'.i18n,
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold
),
),
),
...List.generate(3, (i) {
if (results.episodes.length <= i) return Container(height: 0, width: 0,);
ShowEpisode e = results.episodes[i];
return ShowEpisodeTile(
e,
trailing: IconButton(
icon: Icon(Icons.more_vert),
onPressed: () {
MenuSheet m = MenuSheet(context);
m.defaultShowEpisodeMenu(e.show, e);
},
),
onTap: () async {
//Load entire show, then play
List<ShowEpisode> episodes = await deezerAPI.allShowEpisodes(e.show.id);
await playerHelper.playShowEpisode(e.show, episodes, index: episodes.indexWhere((ep) => e.id == ep.id));
},
);
}),
ListTile(
title: Text('Show all episodes'.i18n),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => EpisodeListScreen(results.episodes))
);
}
)
];
}
@ -670,7 +756,11 @@ class SearchResultsScreen extends StatelessWidget {
Container(height: 8.0,),
...artists,
Container(height: 8.0,),
...playlists
...playlists,
Container(height: 8.0,),
...shows,
Container(height: 8.0,),
...episodes
],
);
},
@ -773,3 +863,64 @@ class SearchResultPlaylists extends StatelessWidget {
);
}
}
class ShowListScreen extends StatelessWidget {
final List<Show> shows;
ShowListScreen(this.shows);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: FreezerAppBar('Shows'.i18n),
body: ListView.builder(
itemCount: shows.length,
itemBuilder: (context, i) {
Show s = shows[i];
return ShowTile(
s,
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ShowScreen(s)
));
},
);
},
),
);
}
}
class EpisodeListScreen extends StatelessWidget {
final List<ShowEpisode> episodes;
EpisodeListScreen(this.episodes);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: FreezerAppBar('Episodes'.i18n),
body: ListView.builder(
itemCount: episodes.length,
itemBuilder: (context, i) {
ShowEpisode e = episodes[i];
return ShowEpisodeTile(
e,
trailing: IconButton(
icon: Icon(Icons.more_vert),
onPressed: () {
MenuSheet m = MenuSheet(context);
m.defaultShowEpisodeMenu(e.show, e);
},
),
onTap: () async {
//Load entire show, then play
List<ShowEpisode> episodes = await deezerAPI.allShowEpisodes(e.show.id);
await playerHelper.playShowEpisode(e.show, episodes, index: episodes.indexWhere((ep) => e.id == ep.id));
},
);
},
)
);
}
}

View file

@ -856,6 +856,27 @@ class _DownloadsSettingsState extends State<DownloadsSettings> {
),
leading: Icon(Icons.image)
),
ListTile(
title: Text('Album cover resolution'.i18n),
subtitle: Text("WARNING: Resolutions above 1200 aren't officially supported".i18n),
leading: Icon(Icons.image),
trailing: Container(
width: 75.0,
child: DropdownButton<int>(
value: settings.albumArtResolution,
items: [400, 800, 1000, 1200, 1400, 1600, 1800].map<DropdownMenuItem<int>>((int i) => DropdownMenuItem<int>(
value: i,
child: Text(i.toString()),
)).toList(),
onChanged: (int n) async {
setState(() {
settings.albumArtResolution = n;
});
await settings.save();
},
)
)
),
ListTile(
title: Text('Create .nomedia files'.i18n),
subtitle: Text('To prevent gallery being filled with album art'.i18n),
@ -872,7 +893,7 @@ class _DownloadsSettingsState extends State<DownloadsSettings> {
title: Text('Artist separator'.i18n),
leading: Icon(WebSymbols.tag),
trailing: Container(
width: 100.0,
width: 75.0,
child: TextField(
controller: _artistSeparatorController,
onChanged: (s) async {

View file

@ -1,6 +1,8 @@
import 'package:audio_service/audio_service.dart';
import 'package:flutter/material.dart';
import 'package:fluttericon/octicons_icons.dart';
import 'package:freezer/api/deezer.dart';
import 'package:freezer/api/download.dart';
import 'package:freezer/translations.i18n.dart';
import '../api/definitions.dart';
@ -25,6 +27,7 @@ class TrackTile extends StatefulWidget {
class _TrackTileState extends State<TrackTile> {
StreamSubscription _subscription;
bool _isOffline = false;
bool get nowPlaying {
if (AudioService.currentMediaItem == null) return false;
@ -37,6 +40,9 @@ class _TrackTileState extends State<TrackTile> {
_subscription = AudioService.currentMediaItemStream.listen((event) {
setState(() {});
});
//Check if offline
downloadManager.checkOffline(track: widget.track).then((b) => setState(() => _isOffline = b));
super.initState();
}
@ -70,9 +76,18 @@ class _TrackTileState extends State<TrackTile> {
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if ((_isOffline??false))
Padding(
padding: EdgeInsets.symmetric(horizontal: 2.0),
child: Icon(
Octicons.primitive_dot,
color: Colors.green,
size: 12.0,
),
),
if (widget.track.explicit??false)
Padding(
padding: EdgeInsets.symmetric(horizontal: 4.0),
padding: EdgeInsets.symmetric(horizontal: 2.0),
child: Text(
'E',
style: TextStyle(
@ -80,9 +95,12 @@ class _TrackTileState extends State<TrackTile> {
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 2.0),
child: Text(widget.track.durationString),
Container(
width: 42.0,
child: Text(
widget.track.durationString,
textAlign: TextAlign.center,
),
),
widget.trailing??Container(width: 0, height: 0)
],
@ -497,6 +515,38 @@ class ShowCard extends StatelessWidget {
}
}
class ShowTile extends StatelessWidget {
final Show show;
final Function onTap;
final Function onHold;
ShowTile(this.show, {this.onTap, this.onHold});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(
show.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: Text(
show.description,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
onTap: onTap,
onLongPress: onHold,
leading: CachedImage(
url: show.art.thumb,
width: 48,
),
);
}
}
class ShowEpisodeTile extends StatelessWidget {
final ShowEpisode episode;