diff --git a/lib/episodes/episode_detail.dart b/lib/episodes/episode_detail.dart index 0bac7a9..b13aed8 100644 --- a/lib/episodes/episode_detail.dart +++ b/lib/episodes/episode_detail.dart @@ -107,122 +107,101 @@ class _EpisodeDetailState extends State { }, child: Scaffold( backgroundColor: Theme.of(context).primaryColor, - appBar: AppBar( - title: _showTitle - ? Text( - widget.episodeItem.title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ) - : Text( - widget.episodeItem.feedTitle, - maxLines: 1, - style: TextStyle( - fontSize: 15, - color: context.textColor.withOpacity(0.7)), - ), - leading: CustomBackButton(), - elevation: _showTitle ? 1 : 0, - //actions: [ - // PopupMenuButton( - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.all(Radius.circular(10))), - // elevation: 1, - // tooltip: s.menu, - // itemBuilder: (context) => [ - // PopupMenuItem( - // value: 0, - // child: Container( - // padding: EdgeInsets.only(left: 10), - // child: Row( - // crossAxisAlignment: CrossAxisAlignment.center, - // children: [ - // SizedBox( - // width: 25, - // height: 25, - // child: CustomPaint( - // painter: ListenedAllPainter( - // context.textTheme.bodyText1.color, - // stroke: 2)), - // ), - // Padding( - // padding: EdgeInsets.symmetric(horizontal: 5.0), - // ), - // Text( - // s.markListened, - // ), - // ], - // ), - // ), - // ), - // ], - // onSelected: (value) async { - // switch (value) { - // case 0: - // await _markListened(widget.episodeItem); - // if (mounted) setState(() {}); - // Fluttertoast.showToast( - // msg: s.markListened, - // gravity: ToastGravity.BOTTOM, - // ); - // break; - // default: - // break; - // } - // }, - // ), - //], - ), - body: SafeArea( - child: Stack( - children: [ - Container( - color: context.primaryColor, - child: SingleChildScrollView( + body: Stack( + children: [ + SafeArea( + child: ScrollConfiguration( + behavior: NoGrowBehavior(), + child: NestedScrollView( scrollDirection: Axis.vertical, controller: _controller, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 20.0), - child: Align( - alignment: Alignment.centerLeft, - child: Text( - widget.episodeItem.title, - textAlign: TextAlign.left, - style: Theme.of(context).textTheme.headline5, + headerSliverBuilder: (context, innerBoxScrolled) { + return [ + SliverAppBar( + floating: true, + pinned: true, + title: _showTitle + ? Text( + widget.episodeItem.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ) + : Text( + widget.episodeItem.feedTitle, + maxLines: 1, + style: TextStyle( + fontSize: 15, + color: + context.textColor.withOpacity(0.7)), + ), + leading: CustomBackButton(), + elevation: _showTitle ? 1 : 0, + ), + ]; + }, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 20.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + widget.episodeItem.title, + textAlign: TextAlign.left, + style: Theme.of(context).textTheme.headline5, + ), ), ), - ), - Padding( - padding: EdgeInsets.fromLTRB(20, 10, 20, 10), - child: Row( - children: [ - Text( - s.published(DateFormat.yMMMd().format( - DateTime.fromMillisecondsSinceEpoch( - widget.episodeItem.pubDate))), - style: TextStyle(color: context.accentColor)), - SizedBox(width: 10), - if (widget.episodeItem.explicit == 1) - Text('E', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.red)), - Spacer(), - ], + Padding( + padding: EdgeInsets.fromLTRB(20, 10, 20, 10), + child: Row( + children: [ + Text( + s.published(DateFormat.yMMMd().format( + DateTime.fromMillisecondsSinceEpoch( + widget.episodeItem.pubDate))), + style: + TextStyle(color: context.accentColor)), + SizedBox(width: 10), + if (widget.episodeItem.explicit == 1) + Text('E', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.red)), + Spacer(), + ], + ), ), - ), - Padding( - padding: - EdgeInsets.symmetric(horizontal: 20, vertical: 5), - child: Row( - children: [ - if (widget.episodeItem.duration != 0) - Container( + Padding( + padding: EdgeInsets.symmetric( + horizontal: 20, vertical: 5), + child: Row( + children: [ + if (widget.episodeItem.duration != 0) + Container( + decoration: BoxDecoration( + color: Colors.cyan[300], + borderRadius: BorderRadius.all( + Radius.circular(16.0))), + height: 28.0, + margin: EdgeInsets.only(right: 10.0), + padding: EdgeInsets.symmetric( + horizontal: 10.0), + alignment: Alignment.center, + child: Text( + s.minsCount( + widget.episodeItem.duration ~/ 60, + ), + style: TextStyle(color: Colors.black), + )), + if (widget.episodeItem.enclosureLength != + null && + widget.episodeItem.enclosureLength != 0) + Container( decoration: BoxDecoration( - color: Colors.cyan[300], + color: Colors.lightBlue[300], borderRadius: BorderRadius.all( Radius.circular(16.0))), height: 28.0, @@ -231,127 +210,112 @@ class _EpisodeDetailState extends State { EdgeInsets.symmetric(horizontal: 10.0), alignment: Alignment.center, child: Text( - s.minsCount( - widget.episodeItem.duration ~/ 60, - ), + '${(widget.episodeItem.enclosureLength) ~/ 1000000}MB', style: TextStyle(color: Colors.black), - )), - if (widget.episodeItem.enclosureLength != null && - widget.episodeItem.enclosureLength != 0) - Container( - decoration: BoxDecoration( - color: Colors.lightBlue[300], - borderRadius: BorderRadius.all( - Radius.circular(16.0))), - height: 28.0, - margin: EdgeInsets.only(right: 10.0), - padding: - EdgeInsets.symmetric(horizontal: 10.0), - alignment: Alignment.center, - child: Text( - '${(widget.episodeItem.enclosureLength) ~/ 1000000}MB', - style: TextStyle(color: Colors.black), + ), ), - ), - FutureBuilder( - future: _getPosition(widget.episodeItem), - builder: (context, snapshot) { - if (snapshot.hasError) { - developer.log(snapshot.error); - } - if (snapshot.hasData && - snapshot.data.seekValue < 0.9 && - snapshot.data.seconds > 10) { - return ButtonTheme( - height: 28, - padding: - EdgeInsets.symmetric(horizontal: 0), - child: OutlineButton( - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(100.0), - side: BorderSide( - color: context.accentColor)), - highlightedBorderColor: - Colors.green[700], - onPressed: () => audio.episodeLoad( - widget.episodeItem, - startPosition: - (snapshot.data.seconds * 1000) - .toInt()), - child: Row( - children: [ - SizedBox( - width: 20, - height: 20, - child: CustomPaint( - painter: ListenedPainter( - context.textColor, - stroke: 2.0), + FutureBuilder( + future: _getPosition(widget.episodeItem), + builder: (context, snapshot) { + if (snapshot.hasError) { + developer.log(snapshot.error); + } + if (snapshot.hasData && + snapshot.data.seekValue < 0.9 && + snapshot.data.seconds > 10) { + return ButtonTheme( + height: 28, + padding: EdgeInsets.symmetric( + horizontal: 0), + child: OutlineButton( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular( + 100.0), + side: BorderSide( + color: + context.accentColor)), + highlightedBorderColor: + Colors.green[700], + onPressed: () => audio.episodeLoad( + widget.episodeItem, + startPosition: + (snapshot.data.seconds * + 1000) + .toInt()), + child: Row( + children: [ + SizedBox( + width: 20, + height: 20, + child: CustomPaint( + painter: ListenedPainter( + context.textColor, + stroke: 2.0), + ), ), - ), - SizedBox(width: 5), - Text( - snapshot.data.seconds.toTime, - style: TextStyle( - color: Colors.black), - ), - ], + SizedBox(width: 5), + Text( + snapshot.data.seconds.toTime, + style: TextStyle( + color: Colors.black), + ), + ], + ), ), - ), - ); - } else { - return Center(); - } - }), - ], + ); + } else { + return Center(); + } + }), + ], + ), ), - ), - _ShowNote(episode: widget.episodeItem), - Selector>( - selector: (_, audio) => - Tuple2(audio.playerRunning, audio.playerHeight), - builder: (_, data, __) { - var height = kMinPlayerHeight[data.item2.index]; - return SizedBox( - height: data.item1 ? height : 0, - ); - }), - ], + _ShowNote(episode: widget.episodeItem), + Selector>( + selector: (_, audio) => Tuple2( + audio.playerRunning, audio.playerHeight), + builder: (_, data, __) { + var height = kMinPlayerHeight[data.item2.index]; + return SizedBox( + height: data.item1 ? height : 0, + ); + }), + ], + ), ), ), ), - Selector>( - selector: (_, audio) => - Tuple2(audio.playerRunning, audio.playerHeight), - builder: (_, data, __) { - var height = kMinPlayerHeight[data.item2.index]; - return Container( - alignment: Alignment.bottomCenter, - padding: - EdgeInsets.only(bottom: data.item1 ? height : 0), - child: AnimatedContainer( - duration: Duration(milliseconds: 400), - height: _showMenu ? 50 : 0, - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: _MenuBar( - episodeItem: widget.episodeItem, - heroTag: widget.heroTag, - hide: widget.hide), - ), + ), + Selector>( + selector: (_, audio) => + Tuple2(audio.playerRunning, audio.playerHeight), + builder: (_, data, __) { + var height = kMinPlayerHeight[data.item2.index]; + return Container( + alignment: Alignment.bottomCenter, + padding: EdgeInsets.only(bottom: data.item1 ? height : 0), + child: AnimatedContainer( + duration: Duration(milliseconds: 400), + height: _showMenu ? 50 : 0, + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: _MenuBar( + episodeItem: widget.episodeItem, + heroTag: widget.heroTag, + hide: widget.hide), ), - ); - }), - Selector( - selector: (_, audio) => audio.episode, - builder: (_, data, __) => Container( - child: PlayerWidget( - playerKey: _playerKey, - isPlayingPage: data == widget.episodeItem))), - ], - ), + ), + ); + }), + Selector( + selector: (_, audio) => audio.episode, + builder: (_, data, __) => Container( + child: PlayerWidget( + playerKey: _playerKey, + isPlayingPage: data == widget.episodeItem))), + ], ), ), ), diff --git a/lib/home/audioplayer.dart b/lib/home/audioplayer.dart index b8e98ae..1962eee 100644 --- a/lib/home/audioplayer.dart +++ b/lib/home/audioplayer.dart @@ -236,7 +236,7 @@ class PlayerWidget extends StatelessWidget { return AudioPanel( minHeight: minHeight, maxHeight: maxHeight, - expandHeight: context.height - 40, + expandHeight: context.height - context.paddingTop - 20, key: playerKey, miniPanel: _miniPanel(context), expandedPanel: ControlPanel( @@ -411,7 +411,6 @@ class _PlaylistWidgetState extends State { borderRadius: BorderRadius.circular(10), child: Container( alignment: Alignment.topLeft, - height: context.height - 340, width: double.infinity, decoration: BoxDecoration( color: context.accentColor.withAlpha(70), @@ -422,6 +421,7 @@ class _PlaylistWidgetState extends State { builder: (_, data, __) { var episodes = data.item1.episodes; return Column( + mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded( child: ListView.builder( @@ -450,12 +450,12 @@ class _PlaylistWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - Container( + Padding( padding: EdgeInsets.all(10.0), child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(15.0)), - child: Container( + child: SizedBox( height: 30.0, width: 30.0, child: Image.file(File( @@ -1253,7 +1253,7 @@ class _ControlPanelState extends State child: SingleChildScrollView( physics: NeverScrollableScrollPhysics(), child: SizedBox( - height: context.height - 360, + height: context.height - context.paddingTop - 340, child: ScrollConfiguration( behavior: NoGrowBehavior(), child: TabBarView( @@ -1286,7 +1286,7 @@ class _ControlPanelState extends State audio.currentSpeed), builder: (_, data, __) { final currentSpeed = data.item4 ?? 1.0; - return Container( + return Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Row( @@ -1448,7 +1448,10 @@ class _ControlPanelState extends State indicatorSize: 20, fraction: (height + 16 - widget.maxHeight) / - 316, + (context.height - + context.paddingTop - + 20 - + widget.maxHeight), accentColor: context.accentColor, color: context.textColor)), ), @@ -1457,8 +1460,12 @@ class _ControlPanelState extends State ), if (_setSpeed == 0 && height > widget.maxHeight) Transform.translate( - offset: - Offset(0, 5) * (height - widget.maxHeight) / 300, + offset: Offset(0, 5) * + (height - widget.maxHeight) / + (context.height - + context.paddingTop - + 20 - + widget.maxHeight), child: Padding( padding: EdgeInsets.symmetric( horizontal: context.width / 2 - 80), diff --git a/lib/home/home.dart b/lib/home/home.dart index a4fba09..c8f986f 100644 --- a/lib/home/home.dart +++ b/lib/home/home.dart @@ -23,11 +23,11 @@ import '../type/episodebrief.dart'; import '../util/extension_helper.dart'; import '../widgets/audiopanel.dart'; import '../widgets/custom_popupmenu.dart'; +import '../widgets/custom_search_delegate.dart'; import '../widgets/custom_widget.dart'; import '../widgets/episodegrid.dart'; import '../widgets/feature_discovery.dart'; import '../widgets/muiliselect_bar.dart'; -import '../widgets/custom_search_delegate.dart'; import 'audioplayer.dart'; import 'download_list.dart'; import 'home_groups.dart'; @@ -90,8 +90,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { double top = 0; @override Widget build(BuildContext context) { - var width = MediaQuery.of(context).size.width; - var height = (width - 20) / 3 + 140; + var height = (context.width - 20) / 3 + 140; var settings = Provider.of(context, listen: false); final s = context.s; return AnnotatedRegion( @@ -209,7 +208,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { SliverToBoxAdapter( child: SizedBox( height: height, - width: width, + width: context.width, child: ScrollPodcasts(), ), ), diff --git a/lib/home/home_groups.dart b/lib/home/home_groups.dart index e611882..7304d8c 100644 --- a/lib/home/home_groups.dart +++ b/lib/home/home_groups.dart @@ -707,13 +707,13 @@ class ShowEpisode extends StatelessWidget { (context, index) { final c = podcastLocal.backgroudColor(context); return Selector>>( - selector: (_, audio) => tuple.Tuple2( - audio?.episode, - audio.queue.episodes - .map((e) => e.enclosureUrl) - .toList(), - ), + tuple.Tuple3, bool>>( + selector: (_, audio) => tuple.Tuple3( + audio?.episode, + audio.queue.episodes + .map((e) => e.enclosureUrl) + .toList(), + audio.playerRunning), builder: (_, data, __) => FutureBuilder< tuple.Tuple5>>( future: _initData(episodes[index]), @@ -754,7 +754,8 @@ class ShowEpisode extends StatelessWidget { context.brightness == Brightness.light ? context.primaryColor : context.dialogBackgroundColor, - title: Text(data.item1 != episodes[index] + title: Text(data.item1 != episodes[index] || + !data.item3 ? s.play : s.playing), trailingIcon: Icon( diff --git a/lib/widgets/audiopanel.dart b/lib/widgets/audiopanel.dart index fcfaa6c..e7460aa 100644 --- a/lib/widgets/audiopanel.dart +++ b/lib/widgets/audiopanel.dart @@ -55,8 +55,7 @@ class AudioPanelState extends State with TickerProviderStateMixin { _controller.forward(); _slideDirection = SlideDirection.up; super.initState(); - _expandHeight = widget.expandHeight; - // _expandHeight = widget.maxHeight + 316; + _expandHeight = widget.expandHeight; } @override @@ -70,7 +69,6 @@ class AudioPanelState extends State with TickerProviderStateMixin { void didUpdateWidget(AudioPanel oldWidget) { if (oldWidget.maxHeight != widget.maxHeight) { setState(() { - //_expandHeight = widget.maxHeight + 316; _expandHeight = widget.expandHeight; }); } @@ -96,8 +94,8 @@ class AudioPanelState extends State with TickerProviderStateMixin { child: GestureDetector( onTap: backToMini, child: Container( - color: context.scaffoldBackgroundColor.withOpacity( - 0.9 * math.min(_animation.value / widget.maxHeight, 1)), + color: context.scaffoldBackgroundColor.withOpacity(0.9 * + math.min(_animation.value / widget.maxHeight, 1)), ), ), ) diff --git a/lib/widgets/episodegrid.dart b/lib/widgets/episodegrid.dart index 8a89526..b678b90 100644 --- a/lib/widgets/episodegrid.dart +++ b/lib/widgets/episodegrid.dart @@ -546,11 +546,12 @@ class EpisodeGrid extends StatelessWidget { opacity: Tween(begin: index < initNum ? 0 : 1, end: 1) .animate(animation), child: Selector, bool>>( - selector: (_, audio) => Tuple3( + Tuple4, bool, bool>>( + selector: (_, audio) => Tuple4( audio?.episode, audio.queue.episodes.map((e) => e.enclosureUrl).toList(), - audio.episodeState), + audio.episodeState, + audio.playerRunning), builder: (_, data, __) => OpenContainerWrapper( avatarSize: layout == Layout.one ? context.width / 8 @@ -654,9 +655,11 @@ class EpisodeGrid extends StatelessWidget { context.brightness == Brightness.light ? context.primaryColor : context.dialogBackgroundColor, - title: Text(data.item1 != episodes[index] - ? s.play - : s.playing), + title: Text( + data.item1 != episodes[index] || + !data.item4 + ? s.play + : s.playing), trailingIcon: Icon( LineIcons.play_circle_solid, color: Theme.of(context).accentColor,