From 5dc490f83f914d4c98b3ec6e72757e36093d2c6d Mon Sep 17 00:00:00 2001 From: stonegate Date: Thu, 2 Apr 2020 17:52:26 +0800 Subject: [PATCH] Bug fixes Change home group preview grid to 2 --- assets/shownote.png | Bin 0 -> 29836 bytes lib/class/audiostate.dart | 44 ++-- lib/episodes/episodedetail.dart | 94 +++++--- lib/home/appbar/about.dart | 9 +- lib/home/audioplayer.dart | 27 ++- lib/home/home_groups.dart | 61 ++--- lib/home/playlist.dart | 236 +++++++++++--------- lib/local_storage/sqflite_localpodcast.dart | 6 +- lib/podcasts/podcastdetail.dart | 2 +- lib/settings/history.dart | 189 +++++++++------- lib/settings/licenses.dart | 5 +- lib/settings/settting.dart | 4 +- lib/settings/storage.dart | 2 +- lib/util/context_extension.dart | 1 + lib/util/day_night_switch.dart | 3 + lib/util/episodegrid.dart | 4 +- lib/webfeed/README.md | 4 +- pubspec.yaml | 3 +- 18 files changed, 394 insertions(+), 300 deletions(-) create mode 100644 assets/shownote.png diff --git a/assets/shownote.png b/assets/shownote.png new file mode 100644 index 0000000000000000000000000000000000000000..03735f37952be7dbb0ab5fe5649ad0ffedb181c6 GIT binary patch literal 29836 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 _queueUpdate; EpisodeBrief get episode => _episode; bool get stopOnComplete => _stopOnComplete; - bool get showStopWatch => _showStopWatch; + bool get startSleepTimer => _startSleepTimer; bool get autoPlay => _autoPlay; int get timeLeft => _timeLeft; double get switchValue => _switchValue; @@ -165,8 +165,7 @@ class AudioPlayerNotifier extends ChangeNotifier { _queueUpdate = false; await AudioService.connect(); bool running = await AudioService.running; - if (running) { - } + if (running) {} } loadPlaylist() async { @@ -217,13 +216,13 @@ class AudioPlayerNotifier extends ChangeNotifier { await AudioService.connect(); } await AudioService.start( - backgroundTaskEntrypoint: _audioPlayerTaskEntrypoint, - androidNotificationChannelName: 'Tsacdop', - notificationColor: 0xFF4d91be, - androidNotificationIcon: 'drawable/ic_notification', - enableQueue: true, - androidStopOnRemoveTask: true, - androidStopForegroundOnPause: true); + backgroundTaskEntrypoint: _audioPlayerTaskEntrypoint, + androidNotificationChannelName: 'Tsacdop', + notificationColor: 0xFF4d91be, + androidNotificationIcon: 'drawable/ic_notification', + enableQueue: true, + androidStopOnRemoveTask: true, + ); _playerRunning = true; if (_autoPlay) { await Future.forEach(_queue.playlist, (episode) async { @@ -312,7 +311,7 @@ class AudioPlayerNotifier extends ChangeNotifier { } notifyListeners(); } - if (_audioState == BasicPlaybackState.stopped) { + if (_audioState == BasicPlaybackState.stopped || _playerRunning == false) { timer.cancel(); } }); @@ -325,6 +324,7 @@ class AudioPlayerNotifier extends ChangeNotifier { _seekSliderValue = 0; _episode = _queue.playlist.first; _playerRunning = true; + _queueUpdate = !_queueUpdate; notifyListeners(); _startAudioService(_lastPostion ?? 0); } @@ -397,9 +397,9 @@ class AudioPlayerNotifier extends ChangeNotifier { int pos = _backgroundAudioPosition + s * 1000; AudioService.seekTo(pos); } - - seekTo(int position) async{ - if (_audioState != BasicPlaybackState.connecting && + + seekTo(int position) async { + if (_audioState != BasicPlaybackState.connecting && _audioState != BasicPlaybackState.none) await AudioService.seekTo(position); } @@ -417,9 +417,9 @@ class AudioPlayerNotifier extends ChangeNotifier { } } - //Set sleep time + //Set sleep timer sleepTimer(int mins) { - _showStopWatch = true; + _startSleepTimer= true; _switchValue = 1; notifyListeners(); _timeLeft = mins * 60; @@ -432,12 +432,14 @@ class AudioPlayerNotifier extends ChangeNotifier { notifyListeners(); } }); - _stopTimer = Timer(Duration(minutes: mins), () { + _stopTimer = Timer(Duration(minutes: mins), () { _stopOnComplete = false; - _showStopWatch = false; + _startSleepTimer= false; _switchValue = 0; + _playerRunning = false; + notifyListeners(); AudioService.stop(); - notifyListeners(); + AudioService.disconnect(); }); } @@ -445,7 +447,7 @@ class AudioPlayerNotifier extends ChangeNotifier { cancelTimer() { _stopTimer.cancel(); _timeLeft = 0; - _showStopWatch = false; + _startSleepTimer= false; _switchValue = 0; notifyListeners(); } diff --git a/lib/episodes/episodedetail.dart b/lib/episodes/episodedetail.dart index 8c88f41..8073823 100644 --- a/lib/episodes/episodedetail.dart +++ b/lib/episodes/episodedetail.dart @@ -16,13 +16,16 @@ import 'package:flutter_linkify/flutter_linkify.dart'; import 'package:tsacdop/class/audiostate.dart'; import 'package:tsacdop/class/episodebrief.dart'; import 'package:tsacdop/local_storage/sqflite_localpodcast.dart'; +import 'package:tsacdop/util/context_extension.dart'; import 'episodedownload.dart'; class EpisodeDetail extends StatefulWidget { final EpisodeBrief episodeItem; final String heroTag; final bool hide; - EpisodeDetail({this.episodeItem, this.heroTag = '',this.hide = false, Key key}) : super(key: key); + EpisodeDetail( + {this.episodeItem, this.heroTag = '', this.hide = false, Key key}) + : super(key: key); @override _EpisodeDetailState createState() => _EpisodeDetailState(); @@ -38,7 +41,8 @@ class _EpisodeDetailState extends State { Future getSDescription(String url) async { var dbHelper = DBHelper(); _description = (await dbHelper.getDescription(url)) - .replaceAll(RegExp(r'\s?

(
)?

\s?'), '').replaceAll('\r', ''); + .replaceAll(RegExp(r'\s?

(
)?

\s?'), '') + .replaceAll('\r', ''); if (mounted) setState(() { _loaddes = true; @@ -93,7 +97,7 @@ class _EpisodeDetailState extends State { child: Scaffold( backgroundColor: Theme.of(context).primaryColor, appBar: AppBar( - // title: Text(widget.episodeItem.feedTitle), + // title: Text(widget.episodeItem.feedTitle), centerTitle: true, ), body: Stack( @@ -197,13 +201,12 @@ class _EpisodeDetailState extends State { padding: EdgeInsets.only(top: 5.0), child: SingleChildScrollView( scrollDirection: Axis.vertical, - //physics: AlwaysScrollableScrollPhysics(), controller: _controller, child: _loaddes ? (_description.contains('<')) ? Html( - padding: - EdgeInsets.only(left: 20.0, right: 20, bottom: 10), + padding: EdgeInsets.only( + left: 20.0, right: 20, bottom: 10), defaultTextStyle: TextStyle(height: 1.8), data: _description, linkStyle: TextStyle( @@ -215,24 +218,48 @@ class _EpisodeDetailState extends State { }, useRichText: true, ) - : Container( - padding: - EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0), - alignment: Alignment.topLeft, - child: SelectableLinkify( - onOpen: (link) { - _launchUrl(link.url); - }, - text: _description, - style: TextStyle( - height: 1.8, - ), - linkStyle: TextStyle( - color: Theme.of(context).accentColor, - decoration: TextDecoration.underline, - ), - ), - ) + : _description.length > 0 + ? Container( + padding: EdgeInsets.only( + left: 20.0, + right: 20.0, + bottom: 10.0), + alignment: Alignment.topLeft, + child: SelectableLinkify( + onOpen: (link) { + _launchUrl(link.url); + }, + text: _description, + style: TextStyle( + height: 1.8, + ), + linkStyle: TextStyle( + color: + Theme.of(context).accentColor, + decoration: + TextDecoration.underline, + ), + ), + ) + : Container( + height: context.width, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Image( + image: AssetImage( + 'assets/shownote.png'), + height: 100.0, + ), + Padding(padding: EdgeInsets.all(5.0)), + Text( + 'Still no shownote received\n for this episode.', textAlign: TextAlign.center, + style: TextStyle(color: context.textTheme.bodyText1.color.withOpacity(0.5))), + ], + ), + ) : Center(), ), ), @@ -259,10 +286,9 @@ class _EpisodeDetailState extends State { child: SingleChildScrollView( scrollDirection: Axis.vertical, child: MenuBar( - episodeItem: widget.episodeItem, - heroTag: widget.heroTag, - hide: widget.hide - ), + episodeItem: widget.episodeItem, + heroTag: widget.heroTag, + hide: widget.hide), ), ), ); @@ -279,7 +305,8 @@ class MenuBar extends StatefulWidget { final EpisodeBrief episodeItem; final String heroTag; final bool hide; - MenuBar({this.episodeItem, this.heroTag, this.hide, Key key}) : super(key: key); + MenuBar({this.episodeItem, this.heroTag, this.hide, Key key}) + : super(key: key); @override _MenuBarState createState() => _MenuBarState(); } @@ -349,10 +376,11 @@ class _MenuBarState extends State { height: 30.0, width: 30.0, color: Theme.of(context).scaffoldBackgroundColor, - child: widget.hide ? Center() : - CircleAvatar( - backgroundImage: - FileImage(File("${widget.episodeItem.imagePath}"))), + child: widget.hide + ? Center() + : CircleAvatar( + backgroundImage: + FileImage(File("${widget.episodeItem.imagePath}"))), ), ), ), diff --git a/lib/home/appbar/about.dart b/lib/home/appbar/about.dart index de34a20..ef5764d 100644 --- a/lib/home/appbar/about.dart +++ b/lib/home/appbar/about.dart @@ -72,20 +72,19 @@ class AboutApp extends StatelessWidget { image: AssetImage('assets/logo.png'), height: 80, ), - Text('Version: 0.1.5'), + Text('Version: 0.1.6'), ], ), ), Container( padding: EdgeInsets.symmetric(horizontal: 50), - height: 50, child: Text( - 'Tsacdop is a podcast player developed in flutter, a simple, beautiful, and easy-use application.', + 'Tsacdop is a podcast player developed in flutter, a simply beautiful, and friendly app.', textAlign: TextAlign.center, ), ), Padding( - padding: EdgeInsets.all(5.0), + padding: EdgeInsets.all(10.0), ), Container( padding: EdgeInsets.only(top: 20.0, bottom: 10.0), @@ -113,7 +112,7 @@ class AboutApp extends StatelessWidget { 'https://twitter.com/shimenmen'), _listItem( context, - 'Stone Gate', + 'Medium', LineIcons.medium, 'https://medium.com/@stonegate'), ], diff --git a/lib/home/audioplayer.dart b/lib/home/audioplayer.dart index e2804e9..929e0ff 100644 --- a/lib/home/audioplayer.dart +++ b/lib/home/audioplayer.dart @@ -71,10 +71,10 @@ class MyRoundSliderThumpShape extends SliderComponentShape { begin: _disabledThumbRadius, end: enabledThumbRadius, ); - final ColorTween colorTween = ColorTween( - begin: sliderTheme.disabledThumbColor, - end: sliderTheme.thumbColor, - ); + // final ColorTween colorTween = ColorTween( + // begin: sliderTheme.disabledThumbColor, + // end: sliderTheme.thumbColor, + // ); canvas.drawCircle( center, @@ -157,7 +157,7 @@ class _PlayerWidgetState extends State { var audio = Provider.of(context, listen: false); return Selector>( selector: (_, audio) => - Tuple3(audio.showStopWatch, audio.timeLeft, audio.switchValue), + Tuple3(audio.startSleepTimer, audio.timeLeft, audio.switchValue), builder: (_, data, __) { return Container( height: 300, @@ -547,17 +547,14 @@ class _PlayerWidgetState extends State { Spacer(), Selector>( selector: (_, audio) => Tuple3( - audio.episode, audio.stopOnComplete, audio.showStopWatch), + audio.episode, audio.stopOnComplete, audio.startSleepTimer), builder: (_, data, __) { return Container( - padding: EdgeInsets.all(12.0), + padding: EdgeInsets.all(5.0), child: Row( mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - Padding( - padding: EdgeInsets.all(5.0), - ), Container( height: 30.0, width: 30.0, @@ -568,7 +565,7 @@ class _PlayerWidgetState extends State { ), Container( padding: EdgeInsets.symmetric(horizontal: 5.0), - width: 200, + width: 150, child: Text( data.item1.feedTitle, maxLines: 1, @@ -578,6 +575,7 @@ class _PlayerWidgetState extends State { Spacer(), LastPosition(), IconButton( + padding: EdgeInsets.zero, onPressed: () => Navigator.push( context, SlideUptRoute( @@ -1007,8 +1005,9 @@ class _PlayerWidgetState extends State { builder: (_, audioplay, __) { return Row( mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisAlignment: MainAxisAlignment.start, children: [ + Spacer(), audioplay == BasicPlaybackState.playing ? InkWell( onTap: @@ -1032,7 +1031,7 @@ class _PlayerWidgetState extends State { alignment: Alignment.center, children: [ Container( - padding: EdgeInsets.all(10.0), + padding: EdgeInsets.symmetric(vertical: 10.0), child: Container( height: 30.0, width: 30.0, @@ -1214,7 +1213,7 @@ class _ImageRotateState extends State return Transform.rotate( angle: 2 * math.pi * _value, child: Container( - padding: EdgeInsets.all(10.0), + padding: EdgeInsets.symmetric(vertical: 10.0), child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(15.0)), child: Container( diff --git a/lib/home/home_groups.dart b/lib/home/home_groups.dart index 4bbe733..f20679d 100644 --- a/lib/home/home_groups.dart +++ b/lib/home/home_groups.dart @@ -482,8 +482,8 @@ class ShowEpisode extends StatelessWidget { padding: const EdgeInsets.all(5.0), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - childAspectRatio: 1.0, - crossAxisCount: 3, + childAspectRatio: 1.5, + crossAxisCount: 2, mainAxisSpacing: 6.0, crossAxisSpacing: 6.0, ), @@ -529,15 +529,6 @@ class ShowEpisode extends StatelessWidget { ); }, child: Container( - // decoration: BoxDecoration( - // border: Border.all( - // color: Theme.of(context).brightness == - // Brightness.light - // ? Theme.of(context).primaryColor - // : Theme.of(context).scaffoldBackgroundColor, - // width: 0.0, - // ), - // ), padding: EdgeInsets.all(10.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -560,7 +551,7 @@ class ShowEpisode extends StatelessWidget { ), ), Spacer(), - episodes[index].isNew == 1 + episodes[index].isNew == 1 ? Text( 'New', style: TextStyle( @@ -579,8 +570,8 @@ class ShowEpisode extends StatelessWidget { child: Text( episodes[index].title, style: TextStyle( - fontSize: _width / 32, - ), + //fontSize: _width / 32, + ), maxLines: 4, overflow: TextOverflow.fade, ), @@ -588,17 +579,37 @@ class ShowEpisode extends StatelessWidget { ), Expanded( flex: 1, - child: Container( - alignment: Alignment.bottomLeft, - child: Text( - episodes[index].dateToString(), - //podcast[index].pubDate.substring(4, 16), - style: TextStyle( - fontSize: _width / 35, - color: _c, - fontStyle: FontStyle.italic, + child: Row( + children: [ + Container( + alignment: Alignment.bottomLeft, + child: Text( + episodes[index].dateToString(), + //podcast[index].pubDate.substring(4, 16), + style: TextStyle( + fontSize: _width / 35, + color: _c, + fontStyle: FontStyle.italic, + ), + ), ), - ), + Spacer(), + episodes[index].duration != 0 + ? Container( + alignment: Alignment.center, + child: Text( + (episodes[index].duration) + .toString() + + 'mins', + style: TextStyle( + fontSize: _width / 35, + // color: _c, + // fontStyle: FontStyle.italic, + ), + ), + ) + : Center(), + ], )), ], ), @@ -608,7 +619,7 @@ class ShowEpisode extends StatelessWidget { ), ); }, - childCount: (episodes.length > 3) ? 3 : episodes.length, + childCount: (episodes.length > 2) ? 2 : episodes.length, ), ), ), diff --git a/lib/home/playlist.dart b/lib/home/playlist.dart index 7fe5f21..c89880e 100644 --- a/lib/home/playlist.dart +++ b/lib/home/playlist.dart @@ -88,121 +88,142 @@ class _PlaylistPageState extends State { height: _topHeight, child: Row( children: [ - Container( - height: _topHeight, - padding: EdgeInsets.only( - left: 70, - ), - alignment: Alignment.centerLeft, - child: RichText( - text: TextSpan( - text: _topHeight > 90 ? 'Playlist\n' : '', - style: TextStyle( - color: - Theme.of(context).textTheme.bodyText1.color, - fontSize: 30, - ), - children: [ - TextSpan( - text: episodes.length.toString(), - style: GoogleFonts.cairo( - textStyle: TextStyle( - color: Theme.of(context).accentColor, - fontSize: 30, + Expanded( + flex: 2, + child: Container( + height: _topHeight, + padding: EdgeInsets.only( + left: 60, + ), + alignment: Alignment.centerLeft, + child: RichText( + text: TextSpan( + text: _topHeight > 90 ? 'Playlist\n' : '', + style: TextStyle( + color: Theme.of(context) + .textTheme + .bodyText1 + .color, + fontSize: 30, + ), + children: [ + TextSpan( + text: episodes.length.toString(), + style: GoogleFonts.cairo( + textStyle: TextStyle( + color: Theme.of(context).accentColor, + fontSize: 25, + ), ), ), - ), - TextSpan( - text: episodes.length < 2 - ? ' episode ' - : ' episodes ', - style: TextStyle( + TextSpan( + text: episodes.length < 2 + ? 'episode' + : 'episodes', + style: TextStyle( + color: Theme.of(context).accentColor, + fontSize: 15, + )), + TextSpan( + text: + _sumPlaylistLength(episodes).toString(), + style: GoogleFonts.cairo( + textStyle: TextStyle( color: Theme.of(context).accentColor, - fontSize: 20, + fontSize: 25, )), - TextSpan( - text: _sumPlaylistLength(episodes).toString(), - style: GoogleFonts.cairo( - textStyle: TextStyle( - color: Theme.of(context).accentColor, - fontSize: 30, - )), - ), - TextSpan( - text: ' mins', - style: TextStyle( - color: Theme.of(context).accentColor, - fontSize: 20, - )), - ], + ), + TextSpan( + text: 'mins', + style: TextStyle( + color: Theme.of(context).accentColor, + fontSize: 15, + )), + ], + ), ), ), ), - Spacer(), - Container( - padding: EdgeInsets.only( - right: 20, - ), - child: data.item2 - ? _topHeight < 90 - ? Row( - mainAxisAlignment: - MainAxisAlignment.center, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - CircleAvatar( - radius: 12, - backgroundImage: FileImage(File( - "${episodes.first.imagePath}")), - ), - Padding( - padding: EdgeInsets.symmetric( - horizontal: 15), - child: SizedBox( - width: 20, - height: 15, - child: WaveLoader()), - ), - ], - ) - : Column( - mainAxisAlignment: - MainAxisAlignment.center, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - CircleAvatar( - radius: 15, - //backgroundColor: _c.withOpacity(0.5), - backgroundImage: FileImage(File( - "${episodes.first.imagePath}")), - ), - Container( - width: 150, - alignment: Alignment.center, - child: Text( - episodes.first.title, - maxLines: 1, - overflow: TextOverflow.fade, + Expanded( + flex: 1, + child: Container( + padding: EdgeInsets.all(5.0), + margin: EdgeInsets.only(right: 20.0, bottom: 5.0), + decoration: data.item2 ? BoxDecoration( + color: context.brightness == Brightness.dark ? Colors.grey[800] : Colors.grey[200], + borderRadius: + BorderRadius.all(Radius.circular(10.0)), + ) : + BoxDecoration( + shape: BoxShape.circle, + color: Colors.transparent + ), + child: data.item2 + ? _topHeight < 90 + ? Row( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + CircleAvatar( + radius: 12, + backgroundImage: FileImage(File( + "${episodes.first.imagePath}")), ), - ), - Padding( - padding: EdgeInsets.symmetric( - horizontal: 15), - child: SizedBox( - width: 20, - height: 15, - child: WaveLoader()), - ), - ], - ) - : IconButton( - icon: Icon(Icons.play_circle_filled, - size: 40, - color: Theme.of(context).accentColor), - onPressed: () => audio.playlistLoad(), - ), + Padding( + padding: EdgeInsets.symmetric( + horizontal: 15), + child: SizedBox( + width: 20, + height: 15, + child: WaveLoader()), + ), + ], + ) + : Column( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + CircleAvatar( + radius: 15, + //backgroundColor: _c.withOpacity(0.5), + backgroundImage: FileImage(File( + "${episodes.first.imagePath}")), + ), + Container( + width: 150, + alignment: Alignment.center, + child: Text( + episodes.first.title, + maxLines: 1, + overflow: TextOverflow.fade, + textAlign: TextAlign.center, + ), + ), + Padding( + padding: EdgeInsets.symmetric( + horizontal: 15), + child: SizedBox( + width: 20, + height: 15, + child: WaveLoader()), + ), + ], + ) + : IconButton( + padding: EdgeInsets.all(0), + alignment: Alignment.center, + icon: Icon(Icons.play_circle_filled, + size: 40, + color: Theme.of(context).accentColor), + onPressed: () { + audio.playlistLoad(); + // setState(() {}); + }), + ), ), ], ), @@ -286,6 +307,7 @@ class _DismissibleContainerState extends State { var audio = Provider.of(context, listen: false); return AnimatedContainer( duration: Duration(milliseconds: 300), + alignment: Alignment.center, height: _delete ? 0 : 95.0, child: _delete ? Container( diff --git a/lib/local_storage/sqflite_localpodcast.dart b/lib/local_storage/sqflite_localpodcast.dart index 7a07ba6..dfc240d 100644 --- a/lib/local_storage/sqflite_localpodcast.dart +++ b/lib/local_storage/sqflite_localpodcast.dart @@ -195,12 +195,12 @@ class DBHelper { return result; } - Future> getPlayHistory() async { + Future> getPlayHistory(int top) async { var dbClient = await database; List list = await dbClient.rawQuery( """SELECT title, enclosure_url, seconds, seek_value, add_date FROM PlayHistory - ORDER BY add_date DESC - """); + ORDER BY add_date DESC LIMIT ? + """,[top]); List playHistory = []; list.forEach((record) { playHistory.add(PlayHistory(record['title'], record['enclosure_url'], diff --git a/lib/podcasts/podcastdetail.dart b/lib/podcasts/podcastdetail.dart index 70ca6f3..2e9f4e7 100644 --- a/lib/podcasts/podcastdetail.dart +++ b/lib/podcasts/podcastdetail.dart @@ -173,7 +173,7 @@ class _PodcastDetailState extends State { void initState() { super.initState(); _loadMore = false; - _top = 33; + _top = 99; _controller = ScrollController(); } diff --git a/lib/settings/history.dart b/lib/settings/history.dart index f5c6a02..c29fd2f 100644 --- a/lib/settings/history.dart +++ b/lib/settings/history.dart @@ -13,16 +13,26 @@ class PlayedHistory extends StatefulWidget { class _PlayedHistoryState extends State with SingleTickerProviderStateMixin { - Future> getPlayHistory() async { + Future> getPlayHistory(int top) async { DBHelper dbHelper = DBHelper(); List playHistory; - playHistory = await dbHelper.getPlayHistory(); + playHistory = await dbHelper.getPlayHistory(top); await Future.forEach(playHistory, (playHistory) async { await playHistory.getEpisode(); }); return playHistory; } + _loadMoreData() async { + // await Future.delayed(Duration(seconds: 3)); + if (mounted) + setState(() { + _top = _top + 100; + }); + } + + int _top = 100; + Future> getSubHistory() async { DBHelper dbHelper = DBHelper(); return await dbHelper.getSubHistory(); @@ -126,94 +136,109 @@ class _PlayedHistoryState extends State }, body: TabBarView(controller: _controller, children: [ FutureBuilder>( - future: getPlayHistory(), + future: getPlayHistory(_top), builder: (context, snapshot) { double _width = MediaQuery.of(context).size.width; return snapshot.hasData - ? ListView.builder( - shrinkWrap: true, - scrollDirection: Axis.vertical, - itemCount: snapshot.data.length, - itemBuilder: (BuildContext context, int index) { - return Container( - color: Theme.of(context).scaffoldBackgroundColor, - child: Column( - children: [ - ListTile( - title: Column( - mainAxisAlignment: - MainAxisAlignment.start, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - DateFormat.yMd().add_jm().format( - snapshot.data[index].playdate), - style: TextStyle( - color: const Color(0xff67727d), - fontSize: 15, - fontStyle: FontStyle.italic), - ), - Text( - snapshot.data[index].title, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ], - ), - subtitle: Container( - width: _width, - child: Row( - children: [ - Icon( - Icons.timelapse, - color: Colors.grey[400], - ), - Container( - height: 2, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.grey[400], - width: 2.0))), - width: _width * - snapshot.data[index] - .seekValue < - (_width - 120) - ? _width * - snapshot - .data[index].seekValue - : _width - 120, - ), - Padding( - padding: EdgeInsets.symmetric( - horizontal: 2), - ), - Container( - width: 50, - alignment: Alignment.center, - decoration: BoxDecoration( - color: Theme.of(context) - .accentColor, - borderRadius: BorderRadius.all( - Radius.circular(10))), - padding: EdgeInsets.all(2), - child: Text( - _stringForSeconds( - snapshot.data[index].seconds), + ? NotificationListener( + onNotification: (ScrollNotification scrollInfo) { + if (scrollInfo.metrics.pixels == + scrollInfo.metrics.maxScrollExtent && + snapshot.data.length == _top) + _loadMoreData(); + return true; + }, + child: ListView.builder( + //shrinkWrap: true, + scrollDirection: Axis.vertical, + itemCount: snapshot.data.length, + itemBuilder: (BuildContext context, int index) { + return Container( + color: + Theme.of(context).scaffoldBackgroundColor, + child: Column( + children: [ + ListTile( + title: Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + DateFormat.yMd().add_jm().format( + snapshot + .data[index].playdate), style: TextStyle( - color: Colors.white), + color: + const Color(0xff67727d), + fontSize: 15, + fontStyle: FontStyle.italic), ), + Text( + snapshot.data[index].title, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], + ), + subtitle: Container( + width: _width, + child: Row( + children: [ + Icon( + Icons.timelapse, + color: Colors.grey[400], + ), + Container( + height: 2, + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Colors + .grey[400], + width: 2.0))), + width: _width * + snapshot.data[index] + .seekValue < + (_width - 120) + ? _width * + snapshot.data[index] + .seekValue + : _width - 120, + ), + Padding( + padding: EdgeInsets.symmetric( + horizontal: 2), + ), + Container( + width: 50, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Theme.of(context) + .accentColor, + borderRadius: + BorderRadius.all( + Radius.circular( + 10))), + padding: EdgeInsets.all(2), + child: Text( + _stringForSeconds(snapshot + .data[index].seconds), + style: TextStyle( + color: Colors.white), + ), + ), + ], ), - ], + ), ), - ), + // Divider(height: 2), + ], ), - // Divider(height: 2), - ], - ), - ); - }) + ); + }), + ) : Center( child: CircularProgressIndicator(), ); diff --git a/lib/settings/licenses.dart b/lib/settings/licenses.dart index c1fd878..3ca19ab 100644 --- a/lib/settings/licenses.dart +++ b/lib/settings/licenses.dart @@ -41,5 +41,8 @@ List plugins = [ Libries('audio_service', mit, 'https://pub.dev/packages/audio_service'), Libries('just_audio', apacheLicense, 'https://pub.dev/packages/just_audio'), Libries('line_icons', gpl, 'https://pub.dev/packages/line_icons'), - Libries('flutter_file_dialog', bsd, 'https://pub.dev/packages/flutter_file_dialog') + Libries('flutter_file_dialog', bsd, 'https://pub.dev/packages/flutter_file_dialog'), + Libries('flutter_linkify', mit, 'https://pub.dev/packages/flutter_linkify'), + Libries('extended_nested_scroll_view', mit, 'https://pub.dev/packages/extended_nested_scroll_view'), + Libries('connectivity', bsd, 'https://pub.dev/packages/connectivity'), ]; \ No newline at end of file diff --git a/lib/settings/settting.dart b/lib/settings/settting.dart index aa6d69a..d23a302 100644 --- a/lib/settings/settting.dart +++ b/lib/settings/settting.dart @@ -195,7 +195,7 @@ class Settings extends StatelessWidget { EdgeInsets.symmetric(horizontal: 25.0), leading: Icon(LineIcons.map_signs_solid), title: Text('Changelog'), - subtitle: Text('List of chagnes'), + subtitle: Text('List of changes'), ), Divider(height: 2), ListTile( @@ -213,7 +213,7 @@ class Settings extends StatelessWidget { Divider(height: 2), ListTile( onTap: () => _launchUrl( - 'mailto:?subject=Tsacdop Feedback'), + 'mailto:?subject=Tsacdop Feedback'), contentPadding: EdgeInsets.symmetric(horizontal: 25.0), leading: Icon(LineIcons.bug_solid), diff --git a/lib/settings/storage.dart b/lib/settings/storage.dart index 6d49118..e47464c 100644 --- a/lib/settings/storage.dart +++ b/lib/settings/storage.dart @@ -58,7 +58,7 @@ class StorageSetting extends StatelessWidget { EdgeInsets.only(left: 80.0, right: 25), title: Text('Ask before using cellular data'), subtitle: Text( - 'Ask to confirem when using cellular data to download episodes.'), + 'Ask to confirm when using cellular data to download episodes.'), trailing: Selector( selector: (_, settings) => settings.downloadUsingData, diff --git a/lib/util/context_extension.dart b/lib/util/context_extension.dart index 106489e..11a8eee 100644 --- a/lib/util/context_extension.dart +++ b/lib/util/context_extension.dart @@ -8,4 +8,5 @@ extension ContextExtension on BuildContext{ Brightness get brightness => Theme.of(this).brightness; double get width => MediaQuery.of(this).size.width; double get height => MediaQuery.of(this).size.width; + TextTheme get textTheme => Theme.of(this).textTheme; } \ No newline at end of file diff --git a/lib/util/day_night_switch.dart b/lib/util/day_night_switch.dart index a2a956c..87939b5 100644 --- a/lib/util/day_night_switch.dart +++ b/lib/util/day_night_switch.dart @@ -1,4 +1,7 @@ //Fork from https://github.com/divyanshub024/day_night_switch +//Copyright https://github.com/divyanshub024 +//Apache License 2.0 https://github.com/divyanshub024/day_night_switch/blob/master/LICENSE + import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; diff --git a/lib/util/episodegrid.dart b/lib/util/episodegrid.dart index 699e456..0ca7492 100644 --- a/lib/util/episodegrid.dart +++ b/lib/util/episodegrid.dart @@ -104,7 +104,7 @@ class EpisodeGrid extends StatelessWidget { const EdgeInsets.only(top: 5.0, bottom: 5.0, left: 15.0, right: 15.0), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - childAspectRatio: 1.0, + childAspectRatio: 1, crossAxisCount: 3, mainAxisSpacing: 6.0, crossAxisSpacing: 6.0, @@ -213,7 +213,7 @@ class EpisodeGrid extends StatelessWidget { child: Text( episodes[index].title, style: TextStyle( - fontSize: _width / 32, + // fontSize: _width / 32, ), maxLines: 4, overflow: TextOverflow.fade, diff --git a/lib/webfeed/README.md b/lib/webfeed/README.md index 4ccfb3c..ea9e518 100644 --- a/lib/webfeed/README.md +++ b/lib/webfeed/README.md @@ -1 +1,3 @@ -Forked from https://github.com/witochandra/webfeed \ No newline at end of file +Forked from https://github.com/witochandra/webfeed +Copyright https://github.com/witochandra ALL RIGHT RESERVED +Mit License https://github.com/witochandra/webfeed/blob/master/LICENSE \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 9408d38..cad52a9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: An easy-use podacasts player. # 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.5 +version: 0.1.6 environment: sdk: ">=2.6.0 <3.0.0" @@ -56,7 +56,6 @@ dev_dependencies: just_audio: git: url: https://github.com/stonega/just_audio.git - rxdart: ^0.23.1 line_icons: git: url: https://github.com/galonsos/line_icons.git