From 42c93a6404e56f63d76c9e50cd991c131a438768 Mon Sep 17 00:00:00 2001 From: stonegate Date: Wed, 14 Oct 2020 15:39:25 +0800 Subject: [PATCH] Minor change. --- CHANGELOG.md | 3 + lib/util/episodegrid.dart | 642 ++++++++++++++--------------------- lib/util/open_container.dart | 8 +- 3 files changed, 266 insertions(+), 387 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81080b4..9853b7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,12 +14,15 @@ Release date 2020/10/13 ### Bug fixed * Feed pubdate parse error. +* Episodes load with initial position failed. ### Minor changes * Single colume layout update. * About page UI update. * More smooth animation when open podcast detail page. +* Change sort by button style in podcast detail page. +* Auto rewind 3 seconds when resuming from paused state. ## 0.4.20 diff --git a/lib/util/episodegrid.dart b/lib/util/episodegrid.dart index df84d82..3ab8de2 100644 --- a/lib/util/episodegrid.dart +++ b/lib/util/episodegrid.dart @@ -534,393 +534,266 @@ class EpisodeGrid extends StatelessWidget { audio.queue.playlist.map((e) => e.enclosureUrl).toList(), audio.episodeState), builder: (_, data, __) => OpenContainerWrapper( + avatarSize: layout == Layout.one + ? context.width / 8 + : context.width / 16, episode: episodes[index], - closedBuilder: (context, action, boo) => FutureBuilder< - Tuple5>>( - future: _initData(episodes[index]), - initialData: Tuple5(0, false, false, false, []), - builder: (context, snapshot) { - var isListened = snapshot.data.item1; - var isLiked = snapshot.data.item2; - var isDownloaded = snapshot.data.item3; - var tapToOpen = snapshot.data.item4; - var menuList = snapshot.data.item5; - return Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(5.0)), - color: isListened > 0 - ? context.brightness == Brightness.light - ? Colors.grey[200] - : Color.fromRGBO(50, 50, 50, 1) - : context.scaffoldBackgroundColor, - boxShadow: [ - BoxShadow( - color: context.brightness == Brightness.light - ? context.primaryColor - : Color.fromRGBO(40, 40, 40, 1), - blurRadius: 0.5, - spreadRadius: 0.5, - ), - ]), - alignment: Alignment.center, - child: multiSelect - ? Material( - color: Colors.transparent, - child: InkWell( - onTap: () { - if (!selectedList - .contains(episodes[index])) { - _selectedList = selectedList; - _selectedList.add(episodes[index]); - } else { - _selectedList = selectedList; - _selectedList.remove(episodes[index]); - } - onSelect(_selectedList); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5.0), - border: Border.all( - color: selectedList - .contains(episodes[index]) - ? context.accentColor - : context.brightness == - Brightness.light - ? context.primaryColor - : context - .scaffoldBackgroundColor, - width: 1.0, - ), + closedBuilder: (context, action, boo) => + FutureBuilder>>( + future: _initData(episodes[index]), + initialData: Tuple5(0, false, false, false, []), + builder: (context, snapshot) { + var isListened = snapshot.data.item1; + var isLiked = snapshot.data.item2; + var isDownloaded = snapshot.data.item3; + var tapToOpen = snapshot.data.item4; + var menuList = snapshot.data.item5; + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.0)), + color: isListened > 0 + ? context.brightness == Brightness.light + ? Colors.grey[200] + : Color.fromRGBO(50, 50, 50, 1) + : context.scaffoldBackgroundColor, + boxShadow: [ + BoxShadow( + color: context.brightness == Brightness.light + ? context.primaryColor + : Color.fromRGBO(40, 40, 40, 1), + blurRadius: 0.5, + spreadRadius: 0.5, + ), + ]), + alignment: Alignment.center, + child: multiSelect + ? Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + if (!selectedList.contains(episodes[index])) { + _selectedList = selectedList; + _selectedList.add(episodes[index]); + } else { + _selectedList = selectedList; + _selectedList.remove(episodes[index]); + } + onSelect(_selectedList); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5.0), + border: Border.all( + color: selectedList + .contains(episodes[index]) + ? context.accentColor + : context.brightness == + Brightness.light + ? context.primaryColor + : context.scaffoldBackgroundColor, + width: 1.0, ), - child: _episodeCard(context, - index: index, - isLiked: isLiked, - isDownloaded: isDownloaded, - color: c, - boo: boo), ), - ), - ) - : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5.0), - border: Border.all( - color: - context.brightness == Brightness.light - ? context.primaryColor - : context.scaffoldBackgroundColor, - width: 1.0, - ), - ), - child: FocusedMenuHolder( - blurSize: 0.0, - menuItemExtent: 45, - menuBoxDecoration: BoxDecoration( - color: Colors.transparent, - borderRadius: - BorderRadius.circular(15.0)), - duration: Duration(milliseconds: 100), - tapMode: tapToOpen - ? TapMode.onTap - : TapMode.onLongPress, - animateMenuItems: false, - blurBackgroundColor: - context.brightness == Brightness.light - ? Colors.white38 - : Colors.black38, - bottomOffsetHeight: 10, - menuOffset: 6, - menuItems: [ - FocusedMenuItem( - backgroundColor: context.brightness == - Brightness.light - ? context.primaryColor - : context.dialogBackgroundColor, - title: Text( - data.item1 != episodes[index] - ? s.play - : s.playing), - trailingIcon: Icon( - LineIcons.play_circle_solid, - color: Theme.of(context).accentColor, - ), - onPressed: () { - if (data.item1 != episodes[index]) { - audio.episodeLoad(episodes[index]); - } - }), - menuList.contains(1) - ? FocusedMenuItem( - backgroundColor: context - .brightness == - Brightness.light - ? context.primaryColor - : context.dialogBackgroundColor, - title: data.item2.contains( - episodes[index] - .enclosureUrl) - ? Text(s.remove) - : Text(s.later), - trailingIcon: Icon( - LineIcons.clock_solid, - color: Colors.cyan, - ), - onPressed: () { - if (!data.item2.contains( - episodes[index] - .enclosureUrl)) { - audio.addToPlaylist( - episodes[index]); - Fluttertoast.showToast( - msg: s.toastAddPlaylist, - gravity: ToastGravity.BOTTOM, - ); - } else { - audio.delFromPlaylist( - episodes[index]); - Fluttertoast.showToast( - msg: s.toastRemovePlaylist, - gravity: ToastGravity.BOTTOM, - ); - } - }) - : null, - menuList.contains(2) - ? FocusedMenuItem( - backgroundColor: context - .brightness == - Brightness.light - ? context.primaryColor - : context.dialogBackgroundColor, - title: isLiked - ? Text(s.unlike) - : Text(s.like), - trailingIcon: Icon(LineIcons.heart, - color: Colors.red, size: 21), - onPressed: () async { - if (isLiked) { - await _setUnliked( - episodes[index] - .enclosureUrl); - audio.setEpisodeState = true; - Fluttertoast.showToast( - msg: s.unliked, - gravity: ToastGravity.BOTTOM, - ); - } else { - await _saveLiked(episodes[index] - .enclosureUrl); - audio.setEpisodeState = true; - Fluttertoast.showToast( - msg: s.liked, - gravity: ToastGravity.BOTTOM, - ); - } - }) - : null, - menuList.contains(3) - ? FocusedMenuItem( - backgroundColor: context - .brightness == - Brightness.light - ? context.primaryColor - : context.dialogBackgroundColor, - title: isListened > 0 - ? Text(s.markNotListened, - style: TextStyle( - color: context.textColor - .withOpacity(0.5))) - : Text( - s.markListened, - maxLines: 1, - overflow: - TextOverflow.ellipsis, - ), - trailingIcon: SizedBox( - width: 23, - height: 23, - child: CustomPaint( - painter: ListenedAllPainter( - Colors.blue, - stroke: 1.5)), - ), - onPressed: () async { - if (isListened < 1) { - await _markListened( - episodes[index]); - audio.setEpisodeState = true; - Fluttertoast.showToast( - msg: s.markListened, - gravity: ToastGravity.BOTTOM, - ); - } else { - await _markNotListened( - episodes[index] - .enclosureUrl); - audio.setEpisodeState = true; - Fluttertoast.showToast( - msg: s.markNotListened, - gravity: ToastGravity.BOTTOM, - ); - } - }) - : null, - menuList.contains(4) - ? FocusedMenuItem( - backgroundColor: context - .brightness == - Brightness.light - ? context.primaryColor - : context.dialogBackgroundColor, - title: isDownloaded - ? Text(s.downloaded, - style: TextStyle( - color: context.textColor - .withOpacity(0.5))) - : Text(s.download), - trailingIcon: Icon( - LineIcons.download_solid, - color: Colors.green), - onPressed: () async { - if (!isDownloaded) { - await _requestDownload(context, - episode: episodes[index]); - // downloader - // .startTask(episodes[index]); - } - }) - : null - ], - action: action, child: _episodeCard(context, index: index, isLiked: isLiked, isDownloaded: isDownloaded, color: c, boo: boo), - // Padding( - // padding: const EdgeInsets.all(8.0), - // child: Column( - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // Expanded( - // flex: layout == Layout.one ? 1 : 2, - // child: Row( - // mainAxisAlignment: - // MainAxisAlignment.start, - // crossAxisAlignment: - // CrossAxisAlignment.center, - // children: [ - // layout != Layout.one - // ? _circleImage(context, - // episode: episodes[index], - // color: c, - // boo: boo) - // : _pubDate(context, - // episode: episodes[index], - // color: c), - // Spacer(), - // _isNewIndicator(episodes[index]), - // _downloadIndicater(context, - // episode: episodes[index], - // isDownloaded: isDownloaded), - // _numberIndicater(context, - // index: index, color: c) - // ], - // ), - // ), - // Expanded( - // flex: layout == Layout.one ? 3 : 5, - // child: layout != Layout.one - // ? _title(episodes[index]) - // : Row( - // crossAxisAlignment: - // CrossAxisAlignment.center, - // children: [ - // _circleImage(context, - // episode: episodes[index], - // color: c, - // boo: boo), - // SizedBox( - // width: 5, - // ), - // Expanded( - // child: - // _title(episodes[index])) - // ], - // ), - // ), - // Expanded( - // flex: 1, - // child: Row( - // crossAxisAlignment: - // CrossAxisAlignment.start, - // mainAxisAlignment: - // MainAxisAlignment.start, - // children: [ - // if (layout != Layout.one) - // _pubDate(context, - // episode: episodes[index], - // color: c), - // Spacer(), - // if (layout != Layout.three && - // episodes[index].duration != 0) - // Align( - // alignment: Alignment.center, - // child: Text( - // episodes[index].duration.toTime, - // style: TextStyle( - // fontSize: _width / 35), - // ), - // ), - // if (episodes[index].duration != 0 && - // episodes[index].enclosureLength != - // null && - // episodes[index].enclosureLength != - // 0 && - // layout != Layout.three) - // Text( - // '|', - // style: TextStyle( - // fontSize: _width / 35, - // ), - // ), - // if (layout != Layout.three && - // episodes[index].enclosureLength != - // null && - // episodes[index].enclosureLength != - // 0) - // Align( - // alignment: Alignment.center, - // child: Text( - // '${(episodes[index].enclosureLength) ~/ 1000000}MB', - // style: TextStyle( - // fontSize: _width / 35), - // ), - // ), - // Padding( - // padding: EdgeInsets.all(1), - // ), - // if ((showFavorite || - // layout != Layout.three) && - // isLiked) - // Icon( - // Icons.favorite, - // color: Colors.red, - // size: _width / 35, - // ) - // ], - // ), - // ), - // ], - // ), - // ), ), ), - ); - }), + ) + : Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5.0), + border: Border.all( + color: context.brightness == Brightness.light + ? context.primaryColor + : context.scaffoldBackgroundColor, + width: 1.0, + ), + ), + child: FocusedMenuHolder( + blurSize: 0.0, + menuItemExtent: 45, + menuBoxDecoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(15.0)), + duration: Duration(milliseconds: 100), + tapMode: tapToOpen + ? TapMode.onTap + : TapMode.onLongPress, + animateMenuItems: false, + blurBackgroundColor: + context.brightness == Brightness.light + ? Colors.white38 + : Colors.black38, + bottomOffsetHeight: 10, + menuOffset: 6, + menuItems: [ + FocusedMenuItem( + backgroundColor: + context.brightness == Brightness.light + ? context.primaryColor + : context.dialogBackgroundColor, + title: Text(data.item1 != episodes[index] + ? s.play + : s.playing), + trailingIcon: Icon( + LineIcons.play_circle_solid, + color: Theme.of(context).accentColor, + ), + onPressed: () { + if (data.item1 != episodes[index]) { + audio.episodeLoad(episodes[index]); + } + }), + menuList.contains(1) + ? FocusedMenuItem( + backgroundColor: context.brightness == + Brightness.light + ? context.primaryColor + : context.dialogBackgroundColor, + title: data.item2.contains( + episodes[index].enclosureUrl) + ? Text(s.remove) + : Text(s.later), + trailingIcon: Icon( + LineIcons.clock_solid, + color: Colors.cyan, + ), + onPressed: () { + if (!data.item2.contains( + episodes[index].enclosureUrl)) { + audio.addToPlaylist( + episodes[index]); + Fluttertoast.showToast( + msg: s.toastAddPlaylist, + gravity: ToastGravity.BOTTOM, + ); + } else { + audio.delFromPlaylist( + episodes[index]); + Fluttertoast.showToast( + msg: s.toastRemovePlaylist, + gravity: ToastGravity.BOTTOM, + ); + } + }) + : null, + menuList.contains(2) + ? FocusedMenuItem( + backgroundColor: context.brightness == + Brightness.light + ? context.primaryColor + : context.dialogBackgroundColor, + title: isLiked + ? Text(s.unlike) + : Text(s.like), + trailingIcon: Icon(LineIcons.heart, + color: Colors.red, size: 21), + onPressed: () async { + if (isLiked) { + await _setUnliked( + episodes[index].enclosureUrl); + audio.setEpisodeState = true; + Fluttertoast.showToast( + msg: s.unliked, + gravity: ToastGravity.BOTTOM, + ); + } else { + await _saveLiked( + episodes[index].enclosureUrl); + audio.setEpisodeState = true; + Fluttertoast.showToast( + msg: s.liked, + gravity: ToastGravity.BOTTOM, + ); + } + }) + : null, + menuList.contains(3) + ? FocusedMenuItem( + backgroundColor: context.brightness == + Brightness.light + ? context.primaryColor + : context.dialogBackgroundColor, + title: isListened > 0 + ? Text(s.markNotListened, + style: TextStyle( + color: context.textColor + .withOpacity(0.5))) + : Text( + s.markListened, + maxLines: 1, + overflow: + TextOverflow.ellipsis, + ), + trailingIcon: SizedBox( + width: 23, + height: 23, + child: CustomPaint( + painter: ListenedAllPainter( + Colors.blue, + stroke: 1.5)), + ), + onPressed: () async { + if (isListened < 1) { + await _markListened( + episodes[index]); + audio.setEpisodeState = true; + Fluttertoast.showToast( + msg: s.markListened, + gravity: ToastGravity.BOTTOM, + ); + } else { + await _markNotListened( + episodes[index].enclosureUrl); + audio.setEpisodeState = true; + Fluttertoast.showToast( + msg: s.markNotListened, + gravity: ToastGravity.BOTTOM, + ); + } + }) + : null, + menuList.contains(4) + ? FocusedMenuItem( + backgroundColor: context.brightness == + Brightness.light + ? context.primaryColor + : context.dialogBackgroundColor, + title: isDownloaded + ? Text(s.downloaded, + style: TextStyle( + color: context.textColor + .withOpacity(0.5))) + : Text(s.download), + trailingIcon: Icon( + LineIcons.download_solid, + color: Colors.green), + onPressed: () async { + if (!isDownloaded) { + await _requestDownload(context, + episode: episodes[index]); + // downloader + // .startTask(episodes[index]); + } + }) + : null + ], + action: action, + child: _episodeCard(context, + index: index, + isLiked: isLiked, + isDownloaded: isDownloaded, + color: c, + boo: boo), + ), + ), + ); + }, + ), ), ), ); @@ -931,15 +804,13 @@ class EpisodeGrid extends StatelessWidget { } class OpenContainerWrapper extends StatelessWidget { - const OpenContainerWrapper({ - this.closedBuilder, - this.episode, - this.playerRunning, - }); + const OpenContainerWrapper( + {this.closedBuilder, this.episode, this.playerRunning, this.avatarSize}); final OpenContainerBuilder closedBuilder; final EpisodeBrief episode; final bool playerRunning; + final double avatarSize; @override Widget build(BuildContext context) { @@ -949,6 +820,7 @@ class OpenContainerWrapper extends StatelessWidget { playerRunning: data.item1, playerHeight: kMinPlayerHeight[data.item2.index], flightWidget: CircleAvatar(backgroundImage: episode.avatarImage), + flightWidgetSize: avatarSize, transitionDuration: Duration(milliseconds: 400), beginColor: Theme.of(context).primaryColor, endColor: Theme.of(context).primaryColor, @@ -958,10 +830,10 @@ class OpenContainerWrapper extends StatelessWidget { openColor: Theme.of(context).scaffoldBackgroundColor, openElevation: 0, closedElevation: 0, - openShape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(10.0))), - closedShape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0))), + openShape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)), + closedShape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)), transitionType: ContainerTransitionType.fadeThrough, openBuilder: (context, _, boo) { return EpisodeDetail( diff --git a/lib/util/open_container.dart b/lib/util/open_container.dart index 8695a2a..ee64edc 100644 --- a/lib/util/open_container.dart +++ b/lib/util/open_container.dart @@ -72,6 +72,7 @@ class OpenContainer extends StatefulWidget { @required this.closedBuilder, @required this.openBuilder, this.flightWidget, + this.flightWidgetSize, this.playerRunning, this.playerHeight, this.tappable = true, @@ -106,6 +107,7 @@ class OpenContainer extends StatefulWidget { final Color endColor; final Color closedColor; final Widget flightWidget; + final double flightWidgetSize; final bool playerRunning; final double playerHeight; @@ -249,6 +251,7 @@ class _OpenContainerState extends State { transitionDuration: widget.transitionDuration, transitionType: widget.transitionType, flightWidget: widget.flightWidget, + flightWidgetSize: widget.flightWidgetSize, playerRunning: widget.playerRunning, playerHeight: widget.playerHeight, )); @@ -364,6 +367,7 @@ class _OpenContainerRoute extends ModalRoute { @required this.transitionDuration, @required this.transitionType, this.flightWidget, + this.flightWidgetSize, this.playerRunning, this.playerHeight, }) : assert(closedColor != null), @@ -394,6 +398,7 @@ class _OpenContainerRoute extends ModalRoute { _openOpacityTween = _getOpenOpacityTween(transitionType); final Widget flightWidget; + final double flightWidgetSize; final bool playerRunning; final double playerHeight; static _FlippableTweenSequence _getColorTween({ @@ -733,8 +738,7 @@ class _OpenContainerRoute extends ModalRoute { ? MediaQuery.of(context).size.height - 40 - playerHeight : MediaQuery.of(context).size.height - 40); - var _width = MediaQuery.of(context).size.width; - _avatarScaleTween.begin = _width / 16; + _avatarScaleTween.begin = flightWidgetSize; _avatarScaleTween.end = 30; return SizedBox.expand( child: Stack(