diff --git a/lib/class/settingstate.dart b/lib/class/settingstate.dart index b04f0da..8c9f1c1 100644 --- a/lib/class/settingstate.dart +++ b/lib/class/settingstate.dart @@ -1,13 +1,30 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; -//two types podcast update, backhome nedd to back to default grooup. -enum Update {backhome, justupdate} -class SettingState extends ChangeNotifier{ - Update _subscribeupdate; - Update get subscribeupdate => _subscribeupdate; - set subscribeUpdate(Update s){ - _subscribeupdate = s; +import 'package:tsacdop/local_storage/key_value_storage.dart'; + +class SettingState extends ChangeNotifier { + KeyValueStorage storage = KeyValueStorage('themes'); + int _theme; + + int get theme => _theme; + void setTheme(int theme) { + _theme = theme; notifyListeners(); + _saveTheme(theme); + } + + @override + void addListener(VoidCallback listener) { + super.addListener(listener); + _getTheme(); + } + + _getTheme() async { + _theme = await storage.getTheme(); + } + + _saveTheme(theme) async { + await storage.saveTheme(theme); } } - diff --git a/lib/episodes/episodedetail.dart b/lib/episodes/episodedetail.dart index fd0384d..bf3a7d3 100644 --- a/lib/episodes/episodedetail.dart +++ b/lib/episodes/episodedetail.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'dart:math' as math; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -15,8 +16,7 @@ import 'episodedownload.dart'; class EpisodeDetail extends StatefulWidget { final EpisodeBrief episodeItem; final String heroTag; - EpisodeDetail({this.episodeItem, this.heroTag, Key key}) - : super(key: key); + EpisodeDetail({this.episodeItem, this.heroTag, Key key}) : super(key: key); @override _EpisodeDetailState createState() => _EpisodeDetailState(); @@ -53,119 +53,130 @@ class _EpisodeDetailState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.grey[100], - appBar: AppBar( - title: Text(widget.episodeItem.feedTitle), - elevation: 0.0, - centerTitle: true, - backgroundColor: Colors.grey[100], + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarIconBrightness: Theme.of(context).accentColorBrightness, + systemNavigationBarColor: Theme.of(context).primaryColor, + statusBarColor: Theme.of(context).primaryColor, ), - body: Container( - color: Colors.grey[100], - padding: EdgeInsets.all(10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 12.0), - alignment: Alignment.topLeft, - child: Text( - widget.episodeItem.title, - style: Theme.of(context).textTheme.headline5, + child: SafeArea( + child: Scaffold( + backgroundColor: Theme.of(context).primaryColor, + appBar: AppBar( + title: Text(widget.episodeItem.feedTitle), + centerTitle: true, + ), + body: Container( + color: Theme.of(context).primaryColor, + padding: EdgeInsets.all(10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 12.0), + alignment: Alignment.topLeft, + child: Text( + widget.episodeItem.title, + style: Theme.of(context).textTheme.headline5, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 12.0), + height: 30.0, + child: Text( + 'Published ' + + DateFormat.yMMMd().format( + DateTime.fromMillisecondsSinceEpoch( + widget.episodeItem.pubDate)), + style: TextStyle(color: Colors.blue[500])), + ), + Container( + padding: EdgeInsets.all(12.0), + height: 50.0, + child: Row( + children: [ + (widget.episodeItem.explicit == 1) + ? Container( + decoration: BoxDecoration( + color: Colors.red[800], + shape: BoxShape.circle), + height: 25.0, + width: 25.0, + margin: EdgeInsets.only(right: 10.0), + alignment: Alignment.center, + child: Text('E', + style: TextStyle(color: Colors.white))) + : Center(), + Container( + decoration: BoxDecoration( + color: Colors.cyan[300], + borderRadius: + BorderRadius.all(Radius.circular(15.0))), + height: 30.0, + margin: EdgeInsets.only(right: 10.0), + padding: EdgeInsets.symmetric(horizontal: 10.0), + alignment: Alignment.center, + child: Text( + (widget.episodeItem.duration).toString() + + 'mins', + style: textstyle), + ), + Container( + decoration: BoxDecoration( + color: Colors.lightBlue[300], + borderRadius: + BorderRadius.all(Radius.circular(15.0))), + height: 30.0, + margin: EdgeInsets.only(right: 10.0), + padding: EdgeInsets.symmetric(horizontal: 10.0), + alignment: Alignment.center, + child: Text( + ((widget.episodeItem.enclosureLength) ~/ + 1000000) + .toString() + + 'MB', + style: textstyle), + ), + ], + ), + ), + ], + ), + ), + Expanded( + child: Container( + padding: EdgeInsets.only(left: 12.0, right: 12.0, top: 5.0), + child: SingleChildScrollView( + child: _loaddes + ? (widget.episodeItem.description.contains('<')) + ? Html( + data: widget.episodeItem.description, + onLinkTap: (url) { + _launchUrl(url); + }, + useRichText: true, + ) + : Container( + alignment: Alignment.topLeft, + child: Text(widget.episodeItem.description)) + : Center(), ), ), - Container( - alignment: Alignment.centerLeft, - padding: EdgeInsets.symmetric(horizontal: 12.0), - height: 30.0, - child: Text( - 'Published ' + - DateFormat.yMMMd().format( DateTime.fromMillisecondsSinceEpoch(widget.episodeItem.pubDate)), - style: TextStyle(color: Colors.blue[500])), - ), - Container( - padding: EdgeInsets.all(12.0), - height: 50.0, - child: Row( - children: [ - (widget.episodeItem.explicit == 1) - ? Container( - decoration: BoxDecoration( - color: Colors.red[800], - shape: BoxShape.circle), - height: 25.0, - width: 25.0, - margin: EdgeInsets.only(right: 10.0), - alignment: Alignment.center, - child: Text('E', - style: TextStyle(color: Colors.white))) - : Center(), - Container( - decoration: BoxDecoration( - color: Colors.cyan[300], - borderRadius: - BorderRadius.all(Radius.circular(15.0))), - height: 30.0, - margin: EdgeInsets.only(right: 10.0), - padding: EdgeInsets.symmetric(horizontal: 10.0), - alignment: Alignment.center, - child: Text( - (widget.episodeItem.duration).toString() + 'mins', - style: textstyle), - ), - Container( - decoration: BoxDecoration( - color: Colors.lightBlue[300], - borderRadius: - BorderRadius.all(Radius.circular(15.0))), - height: 30.0, - margin: EdgeInsets.only(right: 10.0), - padding: EdgeInsets.symmetric(horizontal: 10.0), - alignment: Alignment.center, - child: Text( - ((widget.episodeItem.enclosureLength) ~/ 1000000) - .toString() + - 'MB', - style: textstyle), - ), - ], - ), - ), - ], - ), - ), - Expanded( - child: Container( - padding: EdgeInsets.only(left: 12.0, right: 12.0, top: 5.0), - child: SingleChildScrollView( - child: _loaddes - ? (widget.episodeItem.description.contains('<')) - ? Html( - data: widget.episodeItem.description, - onLinkTap: (url) { - _launchUrl(url); - }, - useRichText: true, - ) - : Container( - alignment: Alignment.topLeft, - child: Text(widget.episodeItem.description)) - : Center(), ), - ), - ), - MenuBar( - episodeItem: widget.episodeItem, - heroTag: widget.heroTag, + MenuBar( + episodeItem: widget.episodeItem, + heroTag: widget.heroTag, ), - ], + ], + ), + ), ), ), ); @@ -175,8 +186,7 @@ class _EpisodeDetailState extends State { class MenuBar extends StatefulWidget { final EpisodeBrief episodeItem; final String heroTag; - MenuBar({this.episodeItem, this.heroTag, Key key}) - : super(key: key); + MenuBar({this.episodeItem, this.heroTag, Key key}) : super(key: key); @override _MenuBarState createState() => _MenuBarState(); } @@ -224,114 +234,113 @@ class _MenuBarState extends State { @override Widget build(BuildContext context) { final audioplay = Provider.of(context); - return Container( - height: 50.0, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(10.0)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - (widget.episodeItem.title == audioplay.episode?.title && - audioplay.audioState == AudioState.play) - ? ImageRotate( - title: widget.episodeItem.feedTitle, - path: widget.episodeItem.imagePath, - ) - : Hero( - tag: widget.episodeItem.enclosureUrl + widget.heroTag, - child: Container( - padding: EdgeInsets.all(10.0), - child: ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - child: Container( - height: 30.0, - width: 30.0, - color: Colors.white, - child: Image.file(File( - "${widget.episodeItem.imagePath}")), - ), - ), - ), - ), - (_like == 0 && !_liked) - ? _buttonOnMenu( - Icon( - Icons.favorite_border, - color: Colors.grey[700], - ), - () => saveLiked(widget.episodeItem.enclosureUrl)) - : Stack( - alignment: Alignment.center, - children: [ - LoveOpen(), - _buttonOnMenu( - Icon( - Icons.favorite, - color: Colors.red, - ), - () => setUnliked(widget.episodeItem.enclosureUrl)), - ], - ), - DownloadButton(episodeBrief: widget.episodeItem), - _buttonOnMenu(Icon(Icons.playlist_add, color: Colors.grey[700]), - () { - Fluttertoast.showToast( - msg: 'Not support yet', - gravity: ToastGravity.BOTTOM, - ); - /*TODO*/ - }), - Spacer(), - (widget.episodeItem.title != audioplay.episode?.title) - ? Material( - color: Colors.transparent, - child: InkWell( - borderRadius: BorderRadius.only( - topRight: Radius.circular(5.0), - bottomRight: Radius.circular(5.0)), - onTap: () { - audioplay.episodeLoad = widget.episodeItem; - }, + return Container( + height: 50.0, + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: BorderRadius.all(Radius.circular(10.0)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + (widget.episodeItem.title == audioplay.episode?.title && + audioplay.audioState == AudioState.play) + ? ImageRotate( + title: widget.episodeItem.feedTitle, + path: widget.episodeItem.imagePath, + ) + : Hero( + tag: widget.episodeItem.enclosureUrl + widget.heroTag, + child: Container( + padding: EdgeInsets.all(10.0), + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(15.0)), child: Container( - alignment: Alignment.center, - height: 50.0, - padding: EdgeInsets.symmetric(horizontal: 20.0), - child: Row( - children: [ - Text('Play Now', - style: TextStyle( - color: Colors.blue, - fontSize: 15, - fontWeight: FontWeight.bold, - )), - Icon( - Icons.play_arrow, - color: Colors.blue, - ), - ], - ), + height: 30.0, + width: 30.0, + color: Theme.of(context).scaffoldBackgroundColor, + child: + Image.file(File("${widget.episodeItem.imagePath}")), ), ), - ) - : (widget.episodeItem.title == audioplay.episode?.title && - audioplay.audioState == AudioState.play) - ? Container( - padding: EdgeInsets.only(right: 30), - child: SizedBox( - width: 20, height: 15, child: WaveLoader())) - : Container( - padding: EdgeInsets.only(right: 30), - child: SizedBox( - width: 20, - height: 15, - child: LineLoader(), + ), + ), + (_like == 0 && !_liked) + ? _buttonOnMenu( + Icon( + Icons.favorite_border, + color: Colors.grey[700], + ), + () => saveLiked(widget.episodeItem.enclosureUrl)) + : Stack( + alignment: Alignment.center, + children: [ + LoveOpen(), + _buttonOnMenu( + Icon( + Icons.favorite, + color: Colors.red, ), + () => setUnliked(widget.episodeItem.enclosureUrl)), + ], + ), + DownloadButton(episodeBrief: widget.episodeItem), + _buttonOnMenu(Icon(Icons.playlist_add, color: Colors.grey[700]), () { + Fluttertoast.showToast( + msg: 'Not support yet', + gravity: ToastGravity.BOTTOM, + ); + /*TODO*/ + }), + Spacer(), + (widget.episodeItem.title != audioplay.episode?.title) + ? Material( + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.only( + topRight: Radius.circular(5.0), + bottomRight: Radius.circular(5.0)), + onTap: () { + audioplay.episodeLoad = widget.episodeItem; + }, + child: Container( + alignment: Alignment.center, + height: 50.0, + padding: EdgeInsets.symmetric(horizontal: 20.0), + child: Row( + children: [ + Text('Play Now', + style: TextStyle( + color: Theme.of(context).accentColor, + fontSize: 15, + fontWeight: FontWeight.bold, + )), + Icon( + Icons.play_arrow, + color: Theme.of(context).accentColor, + ), + ], ), - ], - ), + ), + ), + ) + : (widget.episodeItem.title == audioplay.episode?.title && + audioplay.audioState == AudioState.play) + ? Container( + padding: EdgeInsets.only(right: 30), + child: + SizedBox(width: 20, height: 15, child: WaveLoader())) + : Container( + padding: EdgeInsets.only(right: 30), + child: SizedBox( + width: 20, + height: 15, + child: LineLoader(), + ), + ), + ], + ), ); } } diff --git a/lib/home/appbar/about.dart b/lib/home/appbar/about.dart index 77b0d21..60b0a37 100644 --- a/lib/home/appbar/about.dart +++ b/lib/home/appbar/about.dart @@ -1,31 +1,37 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; class AboutApp extends StatelessWidget { TextSpan buildTextSpan() { return TextSpan(children: [ - TextSpan(text: 'Tsacdop\n',style: TextStyle(fontSize: 20)), + TextSpan(text: 'Tsacdop\n', style: TextStyle(fontSize: 20)), TextSpan( text: 'Tsacdop is a podcast client developed by flutter, is a simple, easy-use player.\n'), - TextSpan( - text: - 'Github https://github.com/stonga/tsacdop .\n'), + TextSpan(text: 'Github https://github.com/stonga/tsacdop .\n'), ]); } @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.grey[100], - title: Text('Tsacdop'), - centerTitle: true, - elevation: 0, - ), - body: Container( - padding: EdgeInsets.all(20), - alignment: Alignment.topLeft, - child: Text.rich(buildTextSpan()), - )); + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarIconBrightness: Theme.of(context).accentColorBrightness, + systemNavigationBarColor: Theme.of(context).primaryColor, + statusBarColor: Theme.of(context).primaryColor, + ), + child: SafeArea( + child: Scaffold( + appBar: AppBar( + title: Text('Tsacdop'), + centerTitle: true, + ), + body: Container( + padding: EdgeInsets.all(20), + alignment: Alignment.topLeft, + child: Text.rich(buildTextSpan()), + )), + ), + ); } } diff --git a/lib/home/appbar/addpodcast.dart b/lib/home/appbar/addpodcast.dart index b4091fe..ee9603f 100644 --- a/lib/home/appbar/addpodcast.dart +++ b/lib/home/appbar/addpodcast.dart @@ -34,35 +34,35 @@ class _MyHomePageState extends State { Widget build(BuildContext context) { return AnnotatedRegion( value: SystemUiOverlayStyle( - systemNavigationBarColor: Colors.grey[100], - statusBarColor: Colors.green, + statusBarIconBrightness: Theme.of(context).accentColorBrightness, + systemNavigationBarColor: Theme.of(context).primaryColor, + statusBarColor: Theme.of(context).primaryColor, ), - child: Scaffold( - key: _scaffoldKey, - appBar: AppBar( - elevation: 0, - centerTitle: true, - backgroundColor: Colors.grey[100], - brightness: Brightness.light, - leading: IconButton( - tooltip: 'Add', - icon: const Icon(Icons.add_circle_outline), - onPressed: () async { - await showSearch( - context: context, - delegate: _delegate, - ); - }, + child: SafeArea( + child: Scaffold( + key: _scaffoldKey, + appBar: AppBar( + centerTitle: true, + leading: IconButton( + tooltip: 'Add', + icon: const Icon(Icons.add_circle_outline), + onPressed: () async { + await showSearch( + context: context, + delegate: _delegate, + ); + }, + ), + title: Image( + image: AssetImage('assets/text.png'), + height: 30, + ), + actions: [ + PopupMenu(), + ], ), - title: Image( - image: AssetImage('assets/text.png'), - height: 30, - ), - actions: [ - PopupMenu(), - ], + body: Home(), ), - body: Home(), ), ); } @@ -83,6 +83,9 @@ class _MyHomePageDelegate extends SearchDelegate { var searchResult = SearchPodcast.fromJson(searchResultMap); return searchResult.results; } + + @override + ThemeData appBarTheme(BuildContext context) => Theme.of(context); @override Widget buildLeading(BuildContext context) { @@ -327,7 +330,7 @@ class _SearchResultState extends State { ? !_adding ? OutlineButton( child: Text('Subscribe', - style: TextStyle(color: Colors.blue)), + style: TextStyle(color: Theme.of(context).accentColor)), onPressed: () { importOmpl.rssTitle = widget.onlinePodcast.title; savePodcast(widget.onlinePodcast.rss); @@ -351,7 +354,7 @@ class _SearchResultState extends State { ? Container( alignment: Alignment.centerLeft, decoration: BoxDecoration( - color: Colors.grey[300], + color: Theme.of(context).primaryColorDark, borderRadius: BorderRadius.only( topRight: Radius.circular(15.0), bottomLeft: Radius.circular(15.0), diff --git a/lib/home/appbar/importompl.dart b/lib/home/appbar/importompl.dart index 88aad5e..b91f352 100644 --- a/lib/home/appbar/importompl.dart +++ b/lib/home/appbar/importompl.dart @@ -7,7 +7,7 @@ class Import extends StatelessWidget { Widget build(BuildContext context) { return Consumer( builder: (context, importOmpl, _) => Container( - color: Colors.grey[300], + color: Theme.of(context).primaryColorDark, child: importOmpl.importState == ImportState.start ? Column( mainAxisAlignment: MainAxisAlignment.start, diff --git a/lib/home/appbar/popupmenu.dart b/lib/home/appbar/popupmenu.dart index 811c54f..01ae868 100644 --- a/lib/home/appbar/popupmenu.dart +++ b/lib/home/appbar/popupmenu.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:dio/dio.dart'; import 'package:provider/provider.dart'; import 'package:tsacdop/class/podcast_group.dart'; +import 'package:tsacdop/class/settingstate.dart'; import 'package:xml/xml.dart' as xml; import 'package:file_picker/file_picker.dart'; import 'package:flutter/services.dart'; @@ -47,6 +48,7 @@ class PopupMenu extends StatelessWidget { Widget build(BuildContext context) { ImportOmpl importOmpl = Provider.of(context, listen: false); GroupList groupList = Provider.of(context, listen: false); + SettingState setting = Provider.of(context); _refreshAll() async { var dbHelper = DBHelper(); List podcastList = await dbHelper.getPodcastLocalAll(); @@ -113,16 +115,15 @@ class PopupMenu extends StatelessWidget { await Future.delayed(Duration(seconds: 5)); importOmpl.importState = ImportState.stop; } - } - else { + } else { importOmpl.importState = ImportState.error; - Fluttertoast.showToast( - msg: 'Network error, Subscribe failed', - gravity: ToastGravity.TOP, - ); - await Future.delayed(Duration(seconds: 5)); - importOmpl.importState = ImportState.stop; + Fluttertoast.showToast( + msg: 'Network error, Subscribe failed', + gravity: ToastGravity.TOP, + ); + await Future.delayed(Duration(seconds: 5)); + importOmpl.importState = ImportState.stop; } } @@ -144,10 +145,11 @@ class PopupMenu extends StatelessWidget { for (int i = 0; i < total.length; i++) { if (total[i].xmlUrl != null) { importOmpl.rssTitle = total[i].text; - try{await saveOmpl(total[i].xmlUrl);} - catch (e){ - print(e.toString()); - } + try { + await saveOmpl(total[i].xmlUrl); + } catch (e) { + print(e.toString()); + } print(total[i].text); } } @@ -183,17 +185,23 @@ class PopupMenu extends StatelessWidget { ), PopupMenuItem( value: 3, + child: setting.theme != 2 ? Text('Night Mode') : Text('Light Mode'), + ), + PopupMenuItem( + value: 4, child: Text('About'), ), ], onSelected: (value) { - if (value == 3) { + if (value == 4) { Navigator.push( context, MaterialPageRoute(builder: (context) => AboutApp())); } else if (value == 2) { _getFilePath(); } else if (value == 1) { _refreshAll(); + } else if (value == 3) { + setting.theme != 2 ? setting.setTheme(2) : setting.setTheme(1); } }, ); diff --git a/lib/home/audio_player.dart b/lib/home/audio_player.dart index a88c187..b4531d7 100644 --- a/lib/home/audio_player.dart +++ b/lib/home/audio_player.dart @@ -65,9 +65,10 @@ class _PlayerWidgetState extends State { _remoteAudioLoading = true; Provider.of(context, listen: false).audioState = AudioState.load; - if (_backgroundAudioPlaying == true) - { _backgroundAudio?.pause(); - AudioSystem.instance.stopBackgroundDisplay();} + if (_backgroundAudioPlaying == true) { + _backgroundAudio?.pause(); + AudioSystem.instance.stopBackgroundDisplay(); + } _backgroundAudio?.dispose(); _backgroundAudio = Audio.loadFromRemoteUrl(url, onDuration: (double durationSeconds) { @@ -118,9 +119,10 @@ class _PlayerWidgetState extends State { _remoteAudioLoading = true; ByteData audio = getAudio(path); Provider.of(context, listen: false).audioState = AudioState.load; - if (_backgroundAudioPlaying == true) - {_backgroundAudio?.pause(); - AudioSystem.instance.stopBackgroundDisplay();} + if (_backgroundAudioPlaying == true) { + _backgroundAudio?.pause(); + AudioSystem.instance.stopBackgroundDisplay(); + } _backgroundAudio?.dispose(); _backgroundAudio = Audio.loadFromByteData(audio, onDuration: (double durationSeconds) { @@ -192,11 +194,6 @@ class _PlayerWidgetState extends State { setState(() { this.url = url; episode = Provider.of(context).episode; - var color = json.decode(episode?.primaryColor); - (color[0] > 200 && color[1] > 200 && color[2] > 200) - ? _c = Color.fromRGBO( - (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) - : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); _backgroundAudioPlaying = true; _isLoading = true; _getFile(url).then((result) { @@ -270,11 +267,10 @@ class _PlayerWidgetState extends State { 'playnow', likeButtonId, 'ic_stat_play_circle_filled'); Future _setNotification() async { - final Uint8List imageBytes = - File('${episode.imagePath}').readAsBytesSync(); + final Uint8List imageBytes = File('${episode.imagePath}').readAsBytesSync(); AudioSystem.instance.setMetadata(AudioMetadata( title: episode.title, - artist:episode.feedTitle, + artist: episode.feedTitle, album: episode.feedTitle, genre: "Podcast", durationSeconds: _backgroundAudioDurationSeconds, @@ -309,8 +305,7 @@ class _PlayerWidgetState extends State { Provider.of(context, listen: false).audioState = AudioState.play; }); - final Uint8List imageBytes = - File('${episode.imagePath}').readAsBytesSync(); + final Uint8List imageBytes = File('${episode.imagePath}').readAsBytesSync(); AudioSystem.instance.setMetadata(AudioMetadata( title: episode.title, artist: episode.feedTitle, @@ -383,9 +378,9 @@ class _PlayerWidgetState extends State { AudioSystem.instance.setPlaybackState(true, forwardposition); } - Widget _expandedPanel() => Container( + Widget _expandedPanel(BuildContext context) => Container( height: 300, - color: Colors.grey[100], + color: Theme.of(context).primaryColor, padding: EdgeInsets.symmetric(horizontal: 10.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, @@ -459,7 +454,8 @@ class _PlayerWidgetState extends State { color: const Color(0xFFFF0000))) : Text( _remoteAudioLoading ? 'Buffring...' : '', - style: TextStyle(color: Colors.blue), + style: TextStyle( + color: Theme.of(context).accentColor), ), ), ), @@ -474,6 +470,7 @@ class _PlayerWidgetState extends State { height: 100, child: Row( mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, children: [ Material( color: Colors.transparent, @@ -484,7 +481,7 @@ class _PlayerWidgetState extends State { : null, iconSize: 32.0, icon: Icon(Icons.replay_10), - color: Colors.black), + color: Theme.of(context).tabBarTheme.labelColor), ), _backgroundAudioPlaying ? Material( @@ -498,7 +495,8 @@ class _PlayerWidgetState extends State { : null, iconSize: 40.0, icon: Icon(Icons.pause_circle_filled), - color: Colors.black), + color: + Theme.of(context).tabBarTheme.labelColor), ) : Material( color: Colors.transparent, @@ -511,7 +509,8 @@ class _PlayerWidgetState extends State { }, iconSize: 40.0, icon: Icon(Icons.play_circle_filled), - color: Colors.black), + color: + Theme.of(context).tabBarTheme.labelColor), ), Material( color: Colors.transparent, @@ -522,7 +521,7 @@ class _PlayerWidgetState extends State { : null, iconSize: 32.0, icon: Icon(Icons.forward_30), - color: Colors.black), + color: Theme.of(context).tabBarTheme.labelColor), ), ], ), @@ -533,7 +532,7 @@ class _PlayerWidgetState extends State { margin: EdgeInsets.symmetric(vertical: 10.0), padding: EdgeInsets.symmetric(horizontal: 10.0), decoration: BoxDecoration( - color: Colors.white, + color: Theme.of(context).scaffoldBackgroundColor, borderRadius: BorderRadius.all(Radius.circular(10.0)), ), child: Row( @@ -545,12 +544,9 @@ class _PlayerWidgetState extends State { child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(15.0)), child: Container( - height: 30.0, - width: 30.0, - color: Colors.white, - child: Image.file( - File("${episode.imagePath}")) - ), + height: 30.0, + width: 30.0, + child: Image.file(File("${episode.imagePath}"))), ), ), Spacer(), @@ -565,138 +561,158 @@ class _PlayerWidgetState extends State { )) ]), ); - Widget _miniPanel(double width) => Container( - height: 60, - color: Colors.grey[100], - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - height: 2, - child: LinearProgressIndicator( - value: _seekSliderValue, - backgroundColor: Colors.grey[100], - valueColor: AlwaysStoppedAnimation(_c), - )), - Expanded( - child: Container( - padding: EdgeInsets.only(left: 15, right: 10), - alignment: Alignment.center, + Widget _miniPanel(double width, BuildContext context) { + var color = json.decode(episode?.primaryColor); + if (color) { + if (Theme.of(context).brightness == Brightness.light) { + _c = (color[0] > 200 && color[1] > 200 && color[2] > 200) + ? Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : Color.fromRGBO(color[0], color[1], color[2], 1.0); + } else { + _c = (color[0] < 50 && color[1] < 50 && color[2] < 50) + ? Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : Color.fromRGBO(color[0], color[1], color[2], 1.0); + } + } + return Container( + height: 60, + color: Theme.of(context).primaryColor, + child: + Column(mainAxisAlignment: MainAxisAlignment.start, children: [ + SizedBox( + height: 2, + child: LinearProgressIndicator( + value: _seekSliderValue, + backgroundColor: Theme.of(context).primaryColor, + valueColor: AlwaysStoppedAnimation(_c), + )), + Expanded( + child: Container( + padding: EdgeInsets.only(left: 15, right: 10), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + flex: 4, + child: Container( + padding: EdgeInsets.symmetric(vertical: 5), + alignment: Alignment.centerLeft, + child: (episode.title.length > 55) + ? Marquee( + text: episode.title, + style: TextStyle(fontWeight: FontWeight.bold), + scrollAxis: Axis.vertical, + crossAxisAlignment: CrossAxisAlignment.start, + blankSpace: 30.0, + velocity: 50.0, + pauseAfterRound: Duration(seconds: 1), + startPadding: 30.0, + accelerationDuration: Duration(seconds: 1), + accelerationCurve: Curves.linear, + decelerationDuration: Duration(milliseconds: 500), + decelerationCurve: Curves.easeOut, + ) + : Text( + episode.title, + style: TextStyle(fontWeight: FontWeight.bold), + maxLines: 2, + ), + ), + ), + Expanded( + flex: 2, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), + alignment: Alignment.center, + child: _remoteAudioLoading + ? Text( + 'Buffring...', + style: + TextStyle(color: Theme.of(context).accentColor), + ) + : Row( + children: [ + Text( + _stringForSeconds( + _backgroundAudioDurationSeconds - + _backgroundAudioPositionSeconds) ?? + '', + style: TextStyle(color: _c), + ), + Text( + ' Left', + style: TextStyle(color: _c), + ), + ], + ), + ), + ), + Expanded( + flex: 2, child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - flex: 4, - child: Container( - padding: EdgeInsets.symmetric(vertical: 5), - alignment: Alignment.centerLeft, - child: (episode.title.length > 55) - ? Marquee( - text: episode.title, - style: TextStyle(fontWeight: FontWeight.bold), - scrollAxis: Axis.vertical, - crossAxisAlignment: CrossAxisAlignment.start, - blankSpace: 30.0, - velocity: 50.0, - pauseAfterRound: Duration(seconds: 1), - startPadding: 30.0, - accelerationDuration: Duration(seconds: 1), - accelerationCurve: Curves.linear, - decelerationDuration: - Duration(milliseconds: 500), - decelerationCurve: Curves.easeOut, - ) - : Text( - episode.title, - style: TextStyle(fontWeight: FontWeight.bold), - maxLines: 2, - ), - ), - ), - Expanded( - flex: 2, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 10), - alignment: Alignment.center, - child: _remoteAudioLoading - ? Text( - 'Buffring...', - style: TextStyle(color: Colors.blue), - ) - : Row( - children: [ - Text( - _stringForSeconds( - _backgroundAudioDurationSeconds - - _backgroundAudioPositionSeconds) ?? - '', - style: TextStyle(color: _c), - ), - Text( - ' Left', - style: TextStyle(color: _c), - ), - ], - ), - ), - ), - Expanded( - flex: 2, - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _backgroundAudioPlaying - ? Material( - color: Colors.transparent, - child: IconButton( - onPressed: _backgroundAudioPlaying - ? () { - _pauseBackgroundAudio(); - } - : null, - iconSize: 25.0, - icon: Icon(Icons.pause_circle_filled), - color: Colors.black), - ) - : Material( - color: Colors.transparent, - child: IconButton( - onPressed: _backgroundAudioPlaying - ? null - : () { - _resumeBackgroundAudio(); - }, - iconSize: 25.0, - icon: Icon(Icons.play_circle_filled), - color: Colors.black), - ), - Material( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _backgroundAudioPlaying + ? Material( color: Colors.transparent, child: IconButton( onPressed: _backgroundAudioPlaying - ? () => _forwardBackgroundAudio(30) + ? () { + _pauseBackgroundAudio(); + } : null, iconSize: 25.0, - icon: Icon(Icons.forward_30), - color: Colors.black), + icon: Icon(Icons.pause_circle_filled), + color: + Theme.of(context).tabBarTheme.labelColor), + ) + : Material( + color: Colors.transparent, + child: IconButton( + onPressed: _backgroundAudioPlaying + ? null + : () { + _resumeBackgroundAudio(); + }, + iconSize: 25.0, + icon: Icon(Icons.play_circle_filled), + color: + Theme.of(context).tabBarTheme.labelColor), ), - ], - ), + Material( + color: Colors.transparent, + child: IconButton( + onPressed: _backgroundAudioPlaying + ? () => _forwardBackgroundAudio(30) + : null, + iconSize: 25.0, + icon: Icon(Icons.forward_30), + color: Theme.of(context).tabBarTheme.labelColor), ), ], ), ), - ), - ]), - ); + ], + ), + ), + ), + ]), + ); + } + @override Widget build(BuildContext context) { double _width = MediaQuery.of(context).size.width; + return !_isLoading ? Center() : AudioPanel( - miniPanel: _miniPanel(_width), expandedPanel: _expandedPanel()); + miniPanel: _miniPanel(_width, context), + expandedPanel: _expandedPanel(context)); } } diff --git a/lib/home/audiopanel.dart b/lib/home/audiopanel.dart index d7150e5..01e160b 100644 --- a/lib/home/audiopanel.dart +++ b/lib/home/audiopanel.dart @@ -46,7 +46,7 @@ class _AudioPanelState extends State child: GestureDetector( onTap: () => _backToMini(), child: Container( - color: Colors.white.withOpacity(0.5), + color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.5), ), ), ) @@ -64,7 +64,7 @@ class _AudioPanelState extends State : (_animation.value <= minSize) ? minSize : _animation.value, child: _animation.value < minSize + 30 ? Container( - color: Colors.grey[100], + color: Theme.of(context).primaryColor, child: Opacity( opacity: _animation.value > minSize ? (minSize + 30 - _animation.value) / 40 @@ -75,7 +75,7 @@ class _AudioPanelState extends State ), ) : Container( - color: Colors.grey[100], + color: Theme.of(context).primaryColor, child: SingleChildScrollView( child: Opacity( opacity: _animation.value < (maxSize - 50) diff --git a/lib/home/homescroll.dart b/lib/home/homescroll.dart index e32185e..08f7397 100644 --- a/lib/home/homescroll.dart +++ b/lib/home/homescroll.dart @@ -87,9 +87,10 @@ class _ScrollPodcastsState extends State { EdgeInsets.symmetric(horizontal: 15.0), child: Text( groups[_groupIndex].name, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.red[300]), + style: Theme.of(context) + .textTheme + .bodyText1 + .copyWith(color: Colors.red[300]), )), Spacer(), Container( @@ -104,21 +105,24 @@ class _ScrollPodcastsState extends State { ); }, child: Container( - height: 30, - padding: EdgeInsets.all(5.0), - child: Text('See All', - style: TextStyle( - color: Colors.red[300], - fontWeight: FontWeight.bold, - )), - ), + height: 30, + padding: EdgeInsets.all(5.0), + child: Text( + 'See All', + style: Theme.of(context) + .textTheme + .bodyText1 + .copyWith( + color: Theme.of(context) + .accentColor), + )), ), ), ], ), ), Container( - color: Colors.white10, + // color: Colors.white10, height: 70, width: _width, alignment: Alignment.centerLeft, @@ -153,14 +157,15 @@ class _ScrollPodcastsState extends State { height: (_width - 20) / 3 + 40, margin: EdgeInsets.only(left: 10, right: 10), decoration: BoxDecoration( - color: Colors.white, + color: Theme.of(context).scaffoldBackgroundColor, ), child: TabBarView( children: groups[_groupIndex] .podcasts .map((PodcastLocal podcastLocal) { return Container( - decoration: BoxDecoration(color: Colors.grey[100]), + decoration: BoxDecoration( + color: Theme.of(context).primaryColor), margin: EdgeInsets.symmetric(horizontal: 5.0), key: ObjectKey(podcastLocal.title), child: PodcastPreview( @@ -193,18 +198,21 @@ class _PodcastPreviewState extends State { } Color _c; - @override - void initState() { - super.initState(); - var color = json.decode(widget.podcastLocal.primaryColor); - (color[0] > 200 && color[1] > 200 && color[2] > 200) - ? _c = Color.fromRGBO( - (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) - : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); - } @override Widget build(BuildContext context) { + var color = json.decode(widget.podcastLocal.primaryColor); + if (Theme.of(context).brightness == Brightness.light) { + (color[0] > 200 && color[1] > 200 && color[2] > 200) + ? _c = Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + } else { + (color[0] < 50 && color[1] < 50 && color[2] < 50) + ? _c = Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + } return Column( children: [ Expanded( @@ -294,10 +302,18 @@ class ShowEpisode extends StatelessWidget { (BuildContext context, int index) { Color _c; var color = json.decode(podcast[index].primaryColor); - (color[0] > 200 && color[1] > 200 && color[2] > 200) - ? _c = Color.fromRGBO( - (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) - : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + + if (Theme.of(context).brightness == Brightness.light) { + (color[0] > 200 && color[1] > 200 && color[2] > 200) + ? _c = Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + } else { + (color[0] < 50 && color[1] < 50 && color[2] < 50) + ? _c = Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + } return InkWell( onTap: () { Navigator.push( @@ -315,12 +331,12 @@ class ShowEpisode extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(5.0)), color: Theme.of(context).scaffoldBackgroundColor, border: Border.all( - color: Colors.grey[100], + color: Theme.of(context).primaryColor, width: 3.0, ), boxShadow: [ BoxShadow( - color: Colors.grey[100], + color: Theme.of(context).primaryColor, blurRadius: 1.0, spreadRadius: 0.5, ), diff --git a/lib/home/hometab.dart b/lib/home/hometab.dart index 0b92536..66c28ee 100644 --- a/lib/home/hometab.dart +++ b/lib/home/hometab.dart @@ -12,11 +12,16 @@ class MainTab extends StatefulWidget { class _MainTabState extends State with TickerProviderStateMixin { TabController _controller; - Decoration getIndicator() { - return const UnderlineTabIndicator( - borderSide: BorderSide(color: Colors.red, width: 2), - insets: EdgeInsets.only(left:10.0,right: 10.0, top:10.0,) - );} + Decoration getIndicator(BuildContext context) { + return UnderlineTabIndicator( + borderSide: BorderSide(color: Theme.of(context).accentColor, width: 2), + insets: EdgeInsets.only( + left: 10.0, + right: 10.0, + top: 10.0, + )); + } + @override void initState() { super.initState(); @@ -41,17 +46,23 @@ class _MainTabState extends State with TickerProviderStateMixin { alignment: Alignment.centerLeft, child: TabBar( isScrollable: true, - labelPadding: - EdgeInsets.all(10.0), + labelPadding: EdgeInsets.all(10.0), controller: _controller, - labelColor: Colors.red, - unselectedLabelColor: Colors.black, - indicator: getIndicator(), + indicator: getIndicator(context), tabs: [ - Text('Recent Update',style: TextStyle(fontWeight: FontWeight.bold),), - Text('Favorites',style: TextStyle(fontWeight: FontWeight.bold),), - Text('Downloads',style: TextStyle(fontWeight: FontWeight.bold),), - ], + Text( + 'Recent Update', + style: TextStyle(fontWeight: FontWeight.bold), + ), + Text( + 'Favorites', + style: TextStyle(fontWeight: FontWeight.bold), + ), + Text( + 'Downloads', + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], ), ), Expanded( @@ -96,7 +107,13 @@ class _RecentUpdateState extends State { builder: (context, snapshot) { if (snapshot.hasError) print(snapshot.error); return (snapshot.hasData) - ? EpisodeGrid(podcast: snapshot.data, showDownload: false, showFavorite: false, showNumber: false, heroTag: 'recent',) + ? EpisodeGrid( + podcast: snapshot.data, + showDownload: false, + showFavorite: false, + showNumber: false, + heroTag: 'recent', + ) : Center(child: CircularProgressIndicator()); }, ); @@ -111,7 +128,7 @@ class MyFavorite extends StatefulWidget { class _MyFavoriteState extends State { Future> _getLikedRssItem() async { var dbHelper = DBHelper(); - List episodes =await dbHelper.getLikedRssItem(); + List episodes = await dbHelper.getLikedRssItem(); return episodes; } @@ -122,26 +139,31 @@ class _MyFavoriteState extends State { builder: (context, snapshot) { if (snapshot.hasError) print(snapshot.error); return (snapshot.hasData) - ? EpisodeGrid(podcast: snapshot.data, showDownload: false, showFavorite: false, showNumber: false, heroTag: 'favorite',) + ? EpisodeGrid( + podcast: snapshot.data, + showDownload: false, + showFavorite: false, + showNumber: false, + heroTag: 'favorite', + ) : Center(child: CircularProgressIndicator()); }, ); } } - class MyDownload extends StatefulWidget { +class MyDownload extends StatefulWidget { @override _MyDownloadState createState() => _MyDownloadState(); } - class _MyDownloadState extends State { Future> _getDownloadedRssItem() async { var dbHelper = DBHelper(); - List episodes =await dbHelper.getDownloadedRssItem(); + List episodes = await dbHelper.getDownloadedRssItem(); return episodes; } - + @override Widget build(BuildContext context) { return FutureBuilder>( @@ -149,10 +171,15 @@ class _MyDownloadState extends State { builder: (context, snapshot) { if (snapshot.hasError) print(snapshot.error); return (snapshot.hasData) - ? EpisodeGrid(podcast: snapshot.data, showDownload: true, showFavorite: false, showNumber: false, heroTag: 'download',) + ? EpisodeGrid( + podcast: snapshot.data, + showDownload: true, + showFavorite: false, + showNumber: false, + heroTag: 'download', + ) : Center(child: CircularProgressIndicator()); }, ); } } - diff --git a/lib/local_storage/key_value_storage.dart b/lib/local_storage/key_value_storage.dart index 35bdace..cf74521 100644 --- a/lib/local_storage/key_value_storage.dart +++ b/lib/local_storage/key_value_storage.dart @@ -31,4 +31,15 @@ class KeyValueStorage { json.encode( {'groups': groupList.map((group) => group.toJson()).toList()})); } + + Future saveTheme(int setting) async{ + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.setInt(key, setting); + } + + Future getTheme() async{ + SharedPreferences prefs = await SharedPreferences.getInstance(); + if(prefs.getInt(key) == null) await prefs.setInt(key, 0); + return prefs.getInt(key); + } } diff --git a/lib/main.dart b/lib/main.dart index abafe9f..01497cf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,14 +28,35 @@ void main() async { class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - SystemChrome.setSystemUIOverlayStyle( - SystemUiOverlayStyle(statusBarColor: Colors.grey[100])); + var theme = Provider.of(context).theme; return MaterialApp( + themeMode: theme == 0 + ? ThemeMode.system + : theme == 1 ? ThemeMode.dark : ThemeMode.light, debugShowCheckedModeBanner: false, title: 'TsacDop', theme: ThemeData( - primaryColor: Colors.white, + accentColorBrightness: Brightness.dark, + primaryColor: Colors.grey[100], + accentColor: Colors.blue[400], + primaryColorLight: Colors.white, + primaryColorDark: Colors.grey[300], + dialogBackgroundColor: Colors.white, + backgroundColor: Colors.grey[100], + appBarTheme: AppBarTheme( + color: Colors.grey[100], + elevation: 0, + ), + textTheme: TextTheme( + headline1: TextStyle(fontSize: 72.0, fontWeight: FontWeight.bold), + bodyText2: TextStyle(fontSize: 15.0, fontWeight: FontWeight.normal), + ), + tabBarTheme: TabBarTheme( + labelColor: Colors.black, + unselectedLabelColor: Colors.grey[400], + ), ), + darkTheme: ThemeData.dark(), home: MyHomePage(), ); } diff --git a/lib/podcasts/podcastdetail.dart b/lib/podcasts/podcastdetail.dart index 7142e22..bd9d483 100644 --- a/lib/podcasts/podcastdetail.dart +++ b/lib/podcasts/podcastdetail.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'dart:async'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:tsacdop/class/podcastlocal.dart'; @@ -21,48 +22,62 @@ class _PodcastDetailState extends State { Future _updateRssItem(PodcastLocal podcastLocal) async { var dbHelper = DBHelper(); final result = await dbHelper.updatePodcastRss(podcastLocal); - result == 0 ? - Fluttertoast.showToast( - msg: 'No Update', - gravity: ToastGravity.TOP, - ) - : Fluttertoast.showToast( - msg: 'Updated $result Episodes', - gravity: ToastGravity.TOP, - ); - if(mounted) setState(() {}); + result == 0 + ? Fluttertoast.showToast( + msg: 'No Update', + gravity: ToastGravity.TOP, + ) + : Fluttertoast.showToast( + msg: 'Updated $result Episodes', + gravity: ToastGravity.TOP, + ); + if (mounted) setState(() {}); } Future> _getRssItem(PodcastLocal podcastLocal) async { print(podcastLocal.id); var dbHelper = DBHelper(); - List episodes = await - dbHelper.getRssItem(podcastLocal.id); + List episodes = await dbHelper.getRssItem(podcastLocal.id); return episodes; } @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.podcastLocal.title,), - elevation: 0.0, - backgroundColor: Colors.grey[100], - centerTitle: true, + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarIconBrightness: Theme.of(context).accentColorBrightness, + systemNavigationBarColor: Theme.of(context).primaryColor, + statusBarColor: Theme.of(context).primaryColor, + ), + child: SafeArea( + child: Scaffold( + appBar: AppBar( + title: Text( + widget.podcastLocal.title, + ), + centerTitle: true, + ), + body: RefreshIndicator( + key: _refreshIndicatorKey, + color: Colors.blue[500], + onRefresh: () => _updateRssItem(widget.podcastLocal), + child: FutureBuilder>( + future: _getRssItem(widget.podcastLocal), + builder: (context, snapshot) { + if (snapshot.hasError) print(snapshot.error); + return (snapshot.hasData) + ? EpisodeGrid( + podcast: snapshot.data, + showDownload: true, + showFavorite: true, + showNumber: true, + heroTag: 'podcast', + ) + : Center(child: CircularProgressIndicator()); + }, + )), ), - body: RefreshIndicator( - key: _refreshIndicatorKey, - color: Colors.blue[500], - onRefresh: () => _updateRssItem(widget.podcastLocal), - child: FutureBuilder>( - future: _getRssItem(widget.podcastLocal), - builder: (context, snapshot) { - if (snapshot.hasError) print(snapshot.error); - return (snapshot.hasData) - ? EpisodeGrid(podcast: snapshot.data, showDownload: true, showFavorite: true, showNumber: true, heroTag: 'podcast',) - : Center(child: CircularProgressIndicator()); - }, - )), + ), ); } } diff --git a/lib/podcasts/podcastgroup.dart b/lib/podcasts/podcastgroup.dart index 99dcbd2..66dc10a 100644 --- a/lib/podcasts/podcastgroup.dart +++ b/lib/podcasts/podcastgroup.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:tsacdop/class/podcast_group.dart'; @@ -36,14 +37,15 @@ class _PodcastGroupListState extends State { width: _loadSave ? 70 : 0, height: 60, decoration: BoxDecoration( - color: Colors.blue, - shape: BoxShape.circle, - boxShadow: [BoxShadow( - color: Colors.grey[700], - blurRadius: 5, - offset: Offset(1, 1), - ),] - ), + color: Colors.blue, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.grey[700], + blurRadius: 5, + offset: Offset(1, 1), + ), + ]), alignment: Alignment.center, child: Text( 'Save', @@ -68,10 +70,10 @@ class _PodcastGroupListState extends State { Widget build(BuildContext context) { return widget.group.podcastList.length == 0 ? Container( - color: Colors.grey[100], + color: Theme.of(context).primaryColor, ) : Container( - color: Colors.grey[100], + color: Theme.of(context).primaryColor, child: Stack( children: [ ReorderableListView( @@ -89,7 +91,8 @@ class _PodcastGroupListState extends State { children: widget.group.podcasts .map((PodcastLocal podcastLocal) { return Container( - decoration: BoxDecoration(color: Colors.grey[100]), + decoration: + BoxDecoration(color: Theme.of(context).primaryColor), key: ObjectKey(podcastLocal.title), child: PodcastCard( podcastLocal: podcastLocal, @@ -147,10 +150,17 @@ class _PodcastCardState extends State { @override Widget build(BuildContext context) { var color = json.decode(widget.podcastLocal.primaryColor); - (color[0] > 200 && color[1] > 200 && color[2] > 200) - ? _c = Color.fromRGBO( - (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) - : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + if (Theme.of(context).brightness == Brightness.light) { + (color[0] > 200 && color[1] > 200 && color[2] > 200) + ? _c = Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + } else { + (color[0] < 50 && color[1] < 50 && color[2] < 50) + ? _c = Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + } double _width = MediaQuery.of(context).size.width; var _groupList = Provider.of(context); _belongGroups = _groupList.getPodcastGroup(widget.podcastLocal.id); @@ -219,27 +229,35 @@ class _PodcastCardState extends State { onPressed: () { showDialog( context: context, - child: AlertDialog( - elevation: 2.0, - title: Text('Remove confirm'), - content: Text( - '${widget.podcastLocal.title} will be removed from device.'), - actions: [ - FlatButton( - onPressed: () => Navigator.of(context).pop(), - child: Text('CANCEL'), - ), - FlatButton( - onPressed: () { - _groupList.removePodcast(widget.podcastLocal.id); - Navigator.of(context).pop(); - }, - child: Text( - 'CONFIRM', - style: TextStyle(color: Colors.red), + child: AnnotatedRegion( + value: SystemUiOverlayStyle( + systemNavigationBarColor: + Colors.black.withOpacity(0.5), + statusBarColor: Colors.red, + ), + child: AlertDialog( + elevation: 2.0, + title: Text('Remove confirm'), + content: Text( + '${widget.podcastLocal.title} will be removed from device.'), + actions: [ + FlatButton( + onPressed: () => Navigator.of(context).pop(), + child: Text('CANCEL'), ), - ) - ], + FlatButton( + onPressed: () { + _groupList + .removePodcast(widget.podcastLocal.id); + Navigator.of(context).pop(); + }, + child: Text( + 'CONFIRM', + style: TextStyle(color: Colors.red), + ), + ) + ], + ), )); }, ), @@ -251,10 +269,12 @@ class _PodcastCardState extends State { : Container( child: Container( decoration: BoxDecoration( - color: Colors.grey[100], + color: Theme.of(context).primaryColor, border: Border( - bottom: BorderSide(color: Colors.grey[300]), - top: BorderSide(color: Colors.grey[300]))), + bottom: BorderSide( + color: Theme.of(context).primaryColorDark), + top: BorderSide( + color: Theme.of(context).primaryColorDark))), height: 50, child: _addGroup ? Row( diff --git a/lib/podcasts/podcastlist.dart b/lib/podcasts/podcastlist.dart index 69c1dad..fa47174 100644 --- a/lib/podcasts/podcastlist.dart +++ b/lib/podcasts/podcastlist.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'dart:async'; import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:provider/provider.dart'; import 'package:tsacdop/class/podcast_group.dart'; @@ -52,7 +53,6 @@ class _AboutPodcastState extends State { _groupList.removePodcast(widget.podcastLocal.id); Navigator.of(context).pop(); }, - color: Colors.grey[200], textColor: Colors.red, child: Text( 'UNSUBSCRIBE', @@ -83,7 +83,6 @@ class PodcastList extends StatefulWidget { } class _PodcastListState extends State { - Future> getPodcastLocal() async { var dbHelper = DBHelper(); var podcastList = await dbHelper.getPodcastLocalAll(); @@ -93,109 +92,100 @@ class _PodcastListState extends State { @override Widget build(BuildContext context) { double _width = MediaQuery.of(context).size.width; - return Scaffold( - appBar: AppBar( - title: Text('Podcasts'), - centerTitle: true, - backgroundColor: Colors.grey[100], - elevation: 0, + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarIconBrightness: Theme.of(context).accentColorBrightness, + systemNavigationBarColor: Theme.of(context).primaryColor, + statusBarColor: Theme.of(context).primaryColor, ), - body: Container( - color: Colors.grey[100], - child: FutureBuilder>( - future: getPodcastLocal(), - builder: (context, snapshot) { - if (snapshot.hasData) { - return CustomScrollView( - primary: false, - slivers: [ - SliverPadding( - padding: const EdgeInsets.all(10.0), - sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - childAspectRatio: 0.8, - crossAxisCount: 3, - ), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return InkWell( - onTap: () { - Navigator.push( - context, - ScaleRoute( - page: PodcastDetail( - podcastLocal: snapshot.data[index], - )), + child: SafeArea( + child: Scaffold( + appBar: AppBar( + title: Text('Podcasts'), + centerTitle: true, + ), + body: Container( + color: Theme.of(context).primaryColor, + child: FutureBuilder>( + future: getPodcastLocal(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return CustomScrollView( + primary: false, + slivers: [ + SliverPadding( + padding: const EdgeInsets.all(10.0), + sliver: SliverGrid( + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + childAspectRatio: 0.8, + crossAxisCount: 3, + ), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return InkWell( + onTap: () { + Navigator.push( + context, + ScaleRoute( + page: PodcastDetail( + podcastLocal: snapshot.data[index], + )), + ); + }, + onLongPress: () { + showDialog( + context: context, + builder: (BuildContext context) => + AboutPodcast( + podcastLocal: snapshot.data[index]), + ).then((_) => setState(() {})); + }, + child: Container( + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + height: 10.0, + ), + ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(_width / 8)), + child: Container( + height: _width / 4, + width: _width / 4, + child: Image.file(File( + "${snapshot.data[index].imagePath}")), + ), + ), + Container( + padding: EdgeInsets.all(4.0), + child: Text( + snapshot.data[index].title, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyText1, + maxLines: 2, + ), + ), + ], + ), + ), ); }, - onLongPress: () { - showDialog( - context: context, - builder: (BuildContext context) => AboutPodcast( - podcastLocal: snapshot.data[index]), - ).then((_) => setState(() {})); - }, - child: Container( - alignment: Alignment.center, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - height: 10.0, - ), - ClipRRect( - borderRadius: BorderRadius.all( - Radius.circular(_width / 8)), - child: Container( - height: _width / 4, - width: _width / 4, - child: Image.file(File( - "${snapshot.data[index].imagePath}")), - ), - ), - Container( - padding: EdgeInsets.all(4.0), - child: Text( - snapshot.data[index].title, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16.0, - color: Colors.black.withOpacity(0.5), - ), - maxLines: 2, - ), - ), - ], - ), - ), - ); - }, - childCount: snapshot.data.length, + childCount: snapshot.data.length, + ), + ), ), - ), - ), - ], - ); - } - return Text('NoData'); - }, + ], + ); + } + return Text('NoData'); + }, + ), + ), ), ), ); } } - -class Podcast extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.grey[100], - elevation: 0, - centerTitle: true, - title: Text('Podcasts'), - ), - body: Container(child: PodcastList()), - ); - } -} diff --git a/lib/podcasts/podcastmanage.dart b/lib/podcasts/podcastmanage.dart index 181f514..6dcce33 100644 --- a/lib/podcasts/podcastmanage.dart +++ b/lib/podcasts/podcastmanage.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:tsacdop/class/podcast_group.dart'; import 'package:tsacdop/podcasts/podcastgroup.dart'; @@ -26,86 +27,85 @@ class _PodcastManageState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - elevation: 0, - centerTitle: true, - backgroundColor: Colors.grey[100], - title: Text('Groups'), - actions: [ - OrderMenu(), - ], + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarIconBrightness: Theme.of(context).accentColorBrightness, + systemNavigationBarColor: Theme.of(context).primaryColor, + statusBarColor: Theme.of(context).primaryColor, ), - body: Consumer(builder: (_, groupList, __) { - bool _isLoading = groupList.isLoading; - List _groups = groupList.groups; - return _isLoading - ? Center() - : DefaultTabController( - length: _groups.length, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( + child: SafeArea( + child: Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text('Groups'), + actions: [ + IconButton( + onPressed: () => showDialog( + context: context, + builder: (BuildContext context) => AddGroup()), + icon: Icon(Icons.add)), + OrderMenu(), + ], + ), + body: Consumer(builder: (_, groupList, __) { + bool _isLoading = groupList.isLoading; + List _groups = groupList.groups; + return _isLoading + ? Center() + : DefaultTabController( + length: _groups.length, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ - Expanded( - flex: 4, - child: Container( - height: 50, - padding: EdgeInsets.symmetric(horizontal: 10.0), - alignment: Alignment.centerLeft, - child: TabBar( - labelColor: Colors.black, - unselectedLabelColor: Colors.grey[500], - labelPadding: EdgeInsets.all(5.0), - indicator: getIndicator(), - isScrollable: true, - tabs: _groups.map((group) { - return Tab( - child: Container( - height: 30.0, - padding: EdgeInsets.symmetric( - horizontal: 10.0), - alignment: Alignment.center, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.all( - Radius.circular(15)), - ), - child: Text( - group.name, - )), - ); - }).toList(), - ), + Container( + height: 50, + padding: EdgeInsets.symmetric(horizontal: 10.0), + alignment: Alignment.centerLeft, + child: TabBar( + // labelColor: Colors.black, + // unselectedLabelColor: Colors.grey[500], + labelPadding: EdgeInsets.all(5.0), + indicator: getIndicator(), + isScrollable: true, + tabs: _groups.map((group) { + return Tab( + child: Container( + height: 30.0, + padding: + EdgeInsets.symmetric(horizontal: 10.0), + alignment: Alignment.center, + decoration: BoxDecoration( + color: Theme.of(context).brightness == + Brightness.light + ? Theme.of(context).primaryColorDark + : Colors.grey[800], + borderRadius: + BorderRadius.all(Radius.circular(15)), + ), + child: Text( + group.name, + )), + ); + }).toList(), ), ), Expanded( - flex: 1, - child: IconButton( - onPressed: () => showDialog( - context: context, - builder: (BuildContext context) => - AddGroup()), - icon: Icon(Icons.add)), - ), + child: Container( + child: TabBarView( + children: _groups.map((group) { + return Container( + key: ObjectKey(group), + child: PodcastGroupList(group: group)); + }).toList(), + ), + ), + ) ], - ), - Expanded( - child: Container( - child: TabBarView( - children: _groups.map((group) { - return Container( - key: ObjectKey(group), - child: PodcastGroupList(group: group)); - }).toList(), - ), - ), - ) - ], - )); - }), + )); + }), + ), + ), ); } } @@ -166,66 +166,72 @@ class _AddGroupState extends State { Widget build(BuildContext context) { var groupList = Provider.of(context); List list = groupList.groups.map((e) => e.name).toList(); - return AlertDialog( - elevation: 1, - contentPadding: EdgeInsets.symmetric(horizontal: 20), - titlePadding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 20), - actionsPadding: EdgeInsets.all(0), - actions: [ - FlatButton( - onPressed: () => Navigator.of(context).pop(), - child: Text( - 'CANCEL', - style: TextStyle(color: Colors.grey[700]), - ), - ), - FlatButton( - onPressed: () async { - if (list.contains(_newGroup)) { - setState(() => _error = 1); - } else { - groupList.addGroup(PodcastGroup(_newGroup)); - Navigator.of(context).pop(); - } - }, - child: Text('DONE'), - ) - ], - title: Text('Create new group'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - decoration: InputDecoration( - contentPadding: EdgeInsets.symmetric(horizontal: 10), - hintText: 'New Group', - hintStyle: TextStyle(fontSize: 18), - filled: true, - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.white, width: 2.0), - ), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.blue, width: 2.0), - ), + return AnnotatedRegion( + value: SystemUiOverlayStyle( + systemNavigationBarColor: Colors.black.withOpacity(0.5), + statusBarColor: Colors.red, + ), + child: AlertDialog( + elevation: 1, + contentPadding: EdgeInsets.symmetric(horizontal: 20), + titlePadding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 20), + actionsPadding: EdgeInsets.all(0), + actions: [ + FlatButton( + onPressed: () => Navigator.of(context).pop(), + child: Text( + 'CANCEL', + style: TextStyle(color: Colors.grey[600]), ), - cursorRadius: Radius.circular(2), - autofocus: true, - maxLines: 1, - controller: _controller, - onChanged: (value) { - _newGroup = value; + ), + FlatButton( + onPressed: () async { + if (list.contains(_newGroup)) { + setState(() => _error = 1); + } else { + groupList.addGroup(PodcastGroup(_newGroup)); + Navigator.of(context).pop(); + } }, - ), - Container( - alignment: Alignment.centerLeft, - child: (_error == 1) - ? Text( - 'Group existed', - style: TextStyle(color: Colors.red[400]), - ) - : Center(), - ), + child: Text('DONE'), + ) ], + title: Text('Create new group'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(horizontal: 10), + hintText: 'New Group', + hintStyle: TextStyle(fontSize: 18), + filled: true, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.blue, width: 2.0), + ), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.blue, width: 2.0), + ), + ), + cursorRadius: Radius.circular(2), + autofocus: true, + maxLines: 1, + controller: _controller, + onChanged: (value) { + _newGroup = value; + }, + ), + Container( + alignment: Alignment.centerLeft, + child: (_error == 1) + ? Text( + 'Group existed', + style: TextStyle(color: Colors.red[400]), + ) + : Center(), + ), + ], + ), ), ); } diff --git a/lib/util/episodegrid.dart b/lib/util/episodegrid.dart index 87ddf2b..9cc4401 100644 --- a/lib/util/episodegrid.dart +++ b/lib/util/episodegrid.dart @@ -45,10 +45,17 @@ class EpisodeGrid extends StatelessWidget { (BuildContext context, int index) { Color _c; var color = json.decode(podcast[index].primaryColor); - (color[0] > 200 && color[1] > 200 && color[2] > 200) - ? _c = Color.fromRGBO( - (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) - : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + if (Theme.of(context).brightness == Brightness.light) { + (color[0] > 200 && color[1] > 200 && color[2] > 200) + ? _c = Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + } else { + (color[0] < 50 && color[1] < 50 && color[2] < 50) + ? _c = Color.fromRGBO( + (255 - color[0]), 255 - color[1], 255 - color[2], 1.0) + : _c = Color.fromRGBO(color[0], color[1], color[2], 1.0); + } return Material( color: Colors.transparent, child: InkWell( @@ -67,13 +74,16 @@ class EpisodeGrid extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(5.0)), color: Theme.of(context).scaffoldBackgroundColor, border: Border.all( - color: Colors.grey[100], + color: + Theme.of(context).brightness == Brightness.light + ? Theme.of(context).primaryColor + : Theme.of(context).scaffoldBackgroundColor, width: 3.0, ), boxShadow: [ BoxShadow( - color: Colors.grey[100], - blurRadius: 1.0, + color: Theme.of(context).primaryColor, + blurRadius: 0.5, spreadRadius: 0.5, ), ]),