From 7df500bc9c785ebc82233e22927b008bc3d9670d Mon Sep 17 00:00:00 2001 From: exttex Date: Wed, 24 Jun 2020 15:19:14 +0200 Subject: [PATCH] Cached image performace, background audio bug --- lib/api/deezer.dart | 2 +- lib/api/player.dart | 19 +- lib/ui/cached_image.dart | 3 + lib/ui/home_screen.dart | 189 ++++++++--------- lib/ui/player_screen.dart | 416 +++++++++++++++++++------------------- lib/ui/tiles.dart | 15 +- pubspec.yaml | 2 +- 7 files changed, 334 insertions(+), 312 deletions(-) diff --git a/lib/api/deezer.dart b/lib/api/deezer.dart index 3f6eb4c..9f127f8 100644 --- a/lib/api/deezer.dart +++ b/lib/api/deezer.dart @@ -61,7 +61,7 @@ class DeezerAPI { 'gateway_input': gatewayInput }, data: jsonEncode(params??{}), - options: Options(responseType: ResponseType.json, sendTimeout: 7000, receiveTimeout: 7000) + options: Options(responseType: ResponseType.json, sendTimeout: 5000, receiveTimeout: 5000) ); return response.data; } diff --git a/lib/api/player.dart b/lib/api/player.dart index 9d9491d..3f4af45 100644 --- a/lib/api/player.dart +++ b/lib/api/player.dart @@ -545,8 +545,15 @@ class AudioPlayerTask extends BackgroundAudioTask { source = 'Stream'; } //Calculate - int bitrate = ((size / 125) / duration.inSeconds).floor(); - return '$format ${bitrate}kbps ($source)'; + return '$format ${_bitrateString(size, duration.inSeconds)} ($source)'; + } + + String _bitrateString(int size, int duration) { + int bitrate = ((size / 125) / duration).floor(); + //Prettify + if (bitrate > 315 && bitrate < 325) return '320kbps'; + if (bitrate > 125 && bitrate < 135) return '128kbps'; + return '${bitrate}kbps'; } //Magic number to string, source: https://en.wikipedia.org/wiki/List_of_file_signatures @@ -564,17 +571,15 @@ class AudioPlayerTask extends BackgroundAudioTask { @override void onTaskRemoved() async { - await _saveQueue(); - onStop(); + await onStop(); } @override Future onStop() async { - await _saveQueue(); - - if (_playing != null) _audioPlayer.stop(); + _audioPlayer.stop(); if (_playerStateSub != null) _playerStateSub.cancel(); if (_eventSub != null) _eventSub.cancel(); + await _saveQueue(); await super.onStop(); } diff --git a/lib/ui/cached_image.dart b/lib/ui/cached_image.dart index 06c0159..3863325 100644 --- a/lib/ui/cached_image.dart +++ b/lib/ui/cached_image.dart @@ -124,6 +124,7 @@ class _CachedImageState extends State { ImageProvider _image = AssetImage('assets/cover.jpg'); double _opacity = 0.0; bool _disposed = false; + String _prevUrl; Future _getImage() async { //Image already path @@ -146,6 +147,7 @@ class _CachedImageState extends State { _image = image; _opacity = 1.0; }); + _prevUrl = widget.url; } @override @@ -162,6 +164,7 @@ class _CachedImageState extends State { @override void didUpdateWidget(CachedImage oldWidget) { + if (_prevUrl == widget.url) return; _load(); super.didUpdateWidget(oldWidget); } diff --git a/lib/ui/home_screen.dart b/lib/ui/home_screen.dart index 6ce4030..a9b3e33 100644 --- a/lib/ui/home_screen.dart +++ b/lib/ui/home_screen.dart @@ -126,99 +126,108 @@ class _HomePageScreenState extends State { return ErrorScreen(); return SingleChildScrollView( child: Column( - children: [ - ...List.generate(_homePage.sections.length, (i) { - HomePageSection section = _homePage.sections[i]; - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - child: Text( - section.title, - textAlign: TextAlign.left, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 24.0), - ), - padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0) - ), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: List.generate(section.items.length, (i) { - HomePageItem item = section.items[i]; - - switch (item.type) { - case HomePageItemType.SMARTTRACKLIST: - return SmartTrackListTile( - item.value, - onTap: () { - playerHelper.playFromSmartTrackList(item.value); - }, - ); - case HomePageItemType.ALBUM: - return AlbumCard( - item.value, - onTap: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => AlbumDetails(item.value) - )); - }, - onHold: () { - MenuSheet m = MenuSheet(context); - m.defaultAlbumMenu(item.value); - }, - ); - case HomePageItemType.ARTIST: - return ArtistTile( - item.value, - onTap: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => ArtistDetails(item.value) - )); - }, - onHold: () { - MenuSheet m = MenuSheet(context); - m.defaultArtistMenu(item.value); - }, - ); - case HomePageItemType.PLAYLIST: - return PlaylistCardTile( - item.value, - onTap: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => PlaylistDetails(item.value) - )); - }, - onHold: () { - MenuSheet m = MenuSheet(context); - m.defaultPlaylistMenu(item.value); - }, - ); - case HomePageItemType.CHANNEL: - return ChannelTile( - item.value, - onTap: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => Scaffold( - appBar: AppBar(title: Text(item.value.title.toString()),), - body: HomePageScreen(channel: item.value,), - ) - )); - }, - ); - } - return Container(height: 0, width: 0); - }), + crossAxisAlignment: CrossAxisAlignment.start, + children: List.generate(_homePage.sections.length, (i) { + HomePageSection section = _homePage.sections[i]; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + child: Text( + section.title, + textAlign: TextAlign.left, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 24.0), ), + padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0) + ), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: List.generate(section.items.length, (i) { + HomePageItem item = section.items[i]; + return HomePageItemWidget(item); + }), ), - Container(height: 16.0,) - ], - ); - }) - ], + ), + ], + ); + }), ), ); } } + + +class HomePageItemWidget extends StatelessWidget { + + HomePageItem item; + HomePageItemWidget(this.item); + + @override + Widget build(BuildContext context) { + switch (item.type) { + case HomePageItemType.SMARTTRACKLIST: + return SmartTrackListTile( + item.value, + onTap: () { + playerHelper.playFromSmartTrackList(item.value); + }, + ); + case HomePageItemType.ALBUM: + return AlbumCard( + item.value, + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => AlbumDetails(item.value) + )); + }, + onHold: () { + MenuSheet m = MenuSheet(context); + m.defaultAlbumMenu(item.value); + }, + ); + case HomePageItemType.ARTIST: + return ArtistTile( + item.value, + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => ArtistDetails(item.value) + )); + }, + onHold: () { + MenuSheet m = MenuSheet(context); + m.defaultArtistMenu(item.value); + }, + ); + case HomePageItemType.PLAYLIST: + return PlaylistCardTile( + item.value, + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => PlaylistDetails(item.value) + )); + }, + onHold: () { + MenuSheet m = MenuSheet(context); + m.defaultPlaylistMenu(item.value); + }, + ); + case HomePageItemType.CHANNEL: + return ChannelTile( + item.value, + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => Scaffold( + appBar: AppBar(title: Text(item.value.title.toString()),), + body: HomePageScreen(channel: item.value,), + ) + )); + }, + ); + } + return Container(height: 0, width: 0); + } +} diff --git a/lib/ui/player_screen.dart b/lib/ui/player_screen.dart index 5e5ba21..3988761 100644 --- a/lib/ui/player_screen.dart +++ b/lib/ui/player_screen.dart @@ -27,229 +27,231 @@ class _PlayerScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: StreamBuilder( - stream: AudioService.playbackStateStream, - builder: (BuildContext context, AsyncSnapshot snapshot) { + body: SafeArea( + child: StreamBuilder( + stream: AudioService.playbackStateStream, + builder: (BuildContext context, AsyncSnapshot snapshot) { - //Disable lyrics when skipping songs, loading - PlaybackState s = snapshot.data; - if (s != null && s.processingState != AudioProcessingState.ready && s.processingState != AudioProcessingState.buffering) _lyrics = false; + //Disable lyrics when skipping songs, loading + PlaybackState s = snapshot.data; + if (s != null && s.processingState != AudioProcessingState.ready && s.processingState != AudioProcessingState.buffering) _lyrics = false; - return OrientationBuilder( - builder: (context, orientation) { - //Landscape - if (orientation == Orientation.landscape) { - return Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(16, 32, 16, 8), - child: Container( - width: 320, - child: Stack( - children: [ - CachedImage( - url: AudioService.currentMediaItem.artUri, - ), - if (_lyrics) LyricsWidget( - artUri: AudioService.currentMediaItem.artUri, - trackId: AudioService.currentMediaItem.id, - lyrics: Track.fromMediaItem(AudioService.currentMediaItem).lyrics, - height: 320.0, - ), - ], - ), - ) - ), - SizedBox( - width: MediaQuery.of(context).size.width / 2 - 32, - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(8, 42, 8, 0), - child: Container( - width: 300, - child: PlayerScreenTopRow(), - ) - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AudioService.currentMediaItem.displayTitle, - maxLines: 1, - textAlign: TextAlign.center, - overflow: TextOverflow.clip, - style: TextStyle( - fontSize: 24.0, - fontWeight: FontWeight.bold + return OrientationBuilder( + builder: (context, orientation) { + //Landscape + if (orientation == Orientation.landscape) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(16, 0, 16, 8), + child: Container( + width: 320, + child: Stack( + children: [ + CachedImage( + url: AudioService.currentMediaItem.artUri, ), + if (_lyrics) LyricsWidget( + artUri: AudioService.currentMediaItem.artUri, + trackId: AudioService.currentMediaItem.id, + lyrics: Track.fromMediaItem(AudioService.currentMediaItem).lyrics, + height: 320.0, + ), + ], + ), + ) + ), + SizedBox( + width: MediaQuery.of(context).size.width / 2 - 32, + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(8, 16, 8, 0), + child: Container( + width: 300, + child: PlayerScreenTopRow(), + ) + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + AudioService.currentMediaItem.displayTitle, + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 24.0, + fontWeight: FontWeight.bold + ), + ), + Container(height: 4,), + Text( + AudioService.currentMediaItem.displaySubtitle, + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 18.0, + color: Theme.of(context).primaryColor, + ), + ), + ], + ), + Container( + width: 320, + child: SeekBar(), + ), + Container( + width: 320, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisSize: MainAxisSize.max, + children: [ + PrevNextButton(iconSize, prev: true,), + PlayPauseButton(iconSize), + PrevNextButton(iconSize) + ], ), - Container(height: 4,), - Text( - AudioService.currentMediaItem.displaySubtitle, - maxLines: 1, - textAlign: TextAlign.center, - overflow: TextOverflow.clip, - style: TextStyle( - fontSize: 18.0, - color: Theme.of(context).primaryColor, - ), + ), + Padding( + padding: EdgeInsets.fromLTRB(8, 0, 8, 16), + child: Container( + width: 300, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: Icon(Icons.subtitles), + onPressed: () { + setState(() => _lyrics = !_lyrics); + }, + ), + Text( + AudioService.currentMediaItem.extras['qualityString'] + ), + IconButton( + icon: Icon(Icons.more_vert), + onPressed: () { + Track t = Track.fromMediaItem(AudioService.currentMediaItem); + MenuSheet m = MenuSheet(context); + m.defaultTrackMenu(t); + }, + ) + ], + ), + ) + ) + ], + ), + ) + ], + ); + } + + //Portrait + return Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(28, 16, 28, 0), + child: PlayerScreenTopRow() + ), + Padding( + padding: EdgeInsets.fromLTRB(16, 8, 16, 8), + child: Container( + height: 360, + child: Stack( + children: [ + CachedImage( + url: AudioService.currentMediaItem.artUri, + ), + if (_lyrics) LyricsWidget( + artUri: AudioService.currentMediaItem.artUri, + trackId: AudioService.currentMediaItem.id, + lyrics: Track.fromMediaItem(AudioService.currentMediaItem).lyrics, + height: 360.0, ), ], ), - Container( - width: 320, - child: SeekBar(), + ) + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + AudioService.currentMediaItem.displayTitle, + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 24.0, + fontWeight: FontWeight.bold ), - Container( - width: 320, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - mainAxisSize: MainAxisSize.max, - children: [ - PrevNextButton(iconSize, prev: true,), - PlayPauseButton(iconSize), - PrevNextButton(iconSize) - ], - ), + ), + Container(height: 4,), + Text( + AudioService.currentMediaItem.displaySubtitle, + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 18.0, + color: Theme.of(context).primaryColor, ), - Padding( - padding: EdgeInsets.fromLTRB(8, 0, 8, 16), - child: Container( - width: 300, - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - icon: Icon(Icons.subtitles), - onPressed: () { - setState(() => _lyrics = !_lyrics); - }, - ), - Text( - AudioService.currentMediaItem.extras['qualityString'] - ), - IconButton( - icon: Icon(Icons.more_vert), - onPressed: () { - Track t = Track.fromMediaItem(AudioService.currentMediaItem); - MenuSheet m = MenuSheet(context); - m.defaultTrackMenu(t); - }, - ) - ], - ), - ) + ), + ], + ), + SeekBar(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisSize: MainAxisSize.max, + children: [ + PrevNextButton(iconSize, prev: true,), + PlayPauseButton(iconSize), + PrevNextButton(iconSize) + ], + ), + //Container(height: 8.0,), + Padding( + padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: Icon(Icons.subtitles), + onPressed: () { + setState(() => _lyrics = !_lyrics); + }, + ), + Text( + AudioService.currentMediaItem.extras['qualityString'] + ), + IconButton( + icon: Icon(Icons.more_vert), + onPressed: () { + Track t = Track.fromMediaItem(AudioService.currentMediaItem); + MenuSheet m = MenuSheet(context); + m.defaultTrackMenu(t); + }, ) ], ), ) ], ); - } - //Portrait - return Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(28, 28, 28, 0), - child: PlayerScreenTopRow() - ), - Padding( - padding: EdgeInsets.fromLTRB(16, 8, 16, 8), - child: Container( - height: 360, - child: Stack( - children: [ - CachedImage( - url: AudioService.currentMediaItem.artUri, - ), - if (_lyrics) LyricsWidget( - artUri: AudioService.currentMediaItem.artUri, - trackId: AudioService.currentMediaItem.id, - lyrics: Track.fromMediaItem(AudioService.currentMediaItem).lyrics, - height: 360.0, - ), - ], - ), - ) - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AudioService.currentMediaItem.displayTitle, - maxLines: 1, - textAlign: TextAlign.center, - overflow: TextOverflow.clip, - style: TextStyle( - fontSize: 24.0, - fontWeight: FontWeight.bold - ), - ), - Container(height: 4,), - Text( - AudioService.currentMediaItem.displaySubtitle, - maxLines: 1, - textAlign: TextAlign.center, - overflow: TextOverflow.clip, - style: TextStyle( - fontSize: 18.0, - color: Theme.of(context).primaryColor, - ), - ), - ], - ), - SeekBar(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - mainAxisSize: MainAxisSize.max, - children: [ - PrevNextButton(iconSize, prev: true,), - PlayPauseButton(iconSize), - PrevNextButton(iconSize) - ], - ), - //Container(height: 8.0,), - Padding( - padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - icon: Icon(Icons.subtitles), - onPressed: () { - setState(() => _lyrics = !_lyrics); - }, - ), - Text( - AudioService.currentMediaItem.extras['qualityString'] - ), - IconButton( - icon: Icon(Icons.more_vert), - onPressed: () { - Track t = Track.fromMediaItem(AudioService.currentMediaItem); - MenuSheet m = MenuSheet(context); - m.defaultTrackMenu(t); - }, - ) - ], - ), - ) - ], - ); - - }, - ); - }, + }, + ); + }, + ), ) ); } diff --git a/lib/ui/tiles.dart b/lib/ui/tiles.dart index 14e3378..5248d2a 100644 --- a/lib/ui/tiles.dart +++ b/lib/ui/tiles.dart @@ -230,7 +230,8 @@ class PlaylistCardTile extends StatelessWidget { overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 16.0), ), - ) + ), + Container(height: 8.0,) ], ), ) @@ -272,7 +273,8 @@ class SmartTrackListTile extends StatelessWidget { fontSize: 16.0 ), ), - ) + ), + Container(height: 8.0,) ], ), ), @@ -315,7 +317,8 @@ class AlbumCard extends StatelessWidget { fontSize: 16.0 ), ), - ) + ), + Container(height: 8.0,) ], ), ) @@ -350,9 +353,9 @@ class ChannelTile extends StatelessWidget { maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.bold, - color: _textColor() + fontSize: 18.0, + fontWeight: FontWeight.bold, + color: _textColor() ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 9b84b6e..a67b96e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.1.0 +version: 0.1.0+1 environment: sdk: ">=2.7.0 <3.0.0"