import 'dart:developer' as developer; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:image/image.dart' as img; import 'package:webfeed/webfeed.dart'; import '../local_storage/sqflite_localpodcast.dart'; import '../type/play_histroy.dart'; import '../type/podcastlocal.dart'; import '../util/custom_widget.dart'; import '../util/duraiton_picker.dart'; import '../util/extension_helper.dart'; import '../util/general_dialog.dart'; enum MarkStatus { start, complete, none } enum RefreshCoverStatus { start, complete, error, none } class PodcastSetting extends StatefulWidget { const PodcastSetting({this.podcastLocal, Key key}) : super(key: key); final PodcastLocal podcastLocal; @override _PodcastSettingState createState() => _PodcastSettingState(); } class _PodcastSettingState extends State { MarkStatus _markStatus = MarkStatus.none; RefreshCoverStatus _coverStatus = RefreshCoverStatus.none; int _seconds = 0; Future _setAutoDownload(bool boo) async { var permission = await _checkPermmison(); if (permission) { var dbHelper = DBHelper(); await dbHelper.saveAutoDownload(widget.podcastLocal.id, boo: boo); } if (mounted) setState(() {}); } Future _saveSkipSeconds(int seconds) async { var dbHelper = DBHelper(); await dbHelper.saveSkipSeconds(widget.podcastLocal.id, seconds); } Future _markListened(String podcastId) async { setState(() { _markStatus = MarkStatus.start; }); var dbHelper = DBHelper(); var episodes = await dbHelper.getRssItem(podcastId, -1, reverse: true); for (var episode in episodes) { var marked = await dbHelper.checkMarked(episode); if (!marked) { final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1); await dbHelper.saveHistory(history); if (mounted) { setState(() { _markStatus = MarkStatus.complete; }); } } } } void _confirmMarkListened(BuildContext context) => generalDialog( context, title: Text(context.s.markConfirm), content: Text(context.s.markConfirmContent), actions: [ FlatButton( onPressed: () { Navigator.of(context).pop(); }, child: Text( context.s.cancel, style: TextStyle(color: Colors.grey[600]), ), ), FlatButton( onPressed: () async { Navigator.of(context).pop(); await _markListened(widget.podcastLocal.id); }, child: Text( context.s.confirm, style: TextStyle(color: context.accentColor), ), ) ], ); Future _refreshArtWork() async { setState(() => _coverStatus = RefreshCoverStatus.start); var options = BaseOptions( connectTimeout: 30000, receiveTimeout: 90000, ); var dio = Dio(options); String imageUrl; try { var response = await dio.get(widget.podcastLocal.rssUrl); try { var p = RssFeed.parse(response.data); imageUrl = p.itunes.image.href ?? p.image.url; } catch (e) { developer.log(e.toString()); if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error); } } catch (e) { developer.log(e.toString()); if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error); } if (imageUrl != null && imageUrl.contains('http') && (imageUrl != widget.podcastLocal.imageUrl || !File(widget.podcastLocal.imageUrl).existsSync())) { try { img.Image thumbnail; var imageResponse = await dio.get>(imageUrl, options: Options( responseType: ResponseType.bytes, )); var image = img.decodeImage(imageResponse.data); thumbnail = img.copyResize(image, width: 300); if (thumbnail != null) { var dir = await getApplicationDocumentsDirectory(); File("${dir.path}/${widget.podcastLocal.id}.png") ..writeAsBytesSync(img.encodePng(thumbnail)); if (mounted) { setState(() => _coverStatus = RefreshCoverStatus.complete); } } } catch (e) { developer.log(e.toString()); if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error); } } else if (_coverStatus == RefreshCoverStatus.start && mounted) { setState(() => _coverStatus = RefreshCoverStatus.complete); } } Future _checkPermmison() async { var permission = await Permission.storage.status; if (permission != PermissionStatus.granted) { var permissions = await [Permission.storage].request(); if (permissions[Permission.storage] == PermissionStatus.granted) { return true; } else { return false; } } else { return true; } } Future _getAutoDownload(String id) async { var dbHelper = DBHelper(); return await dbHelper.getAutoDownload(id); } Future _getSkipSecond(String id) async { var dbHelper = DBHelper(); var seconds = await dbHelper.getSkipSeconds(id); return seconds; } Widget _getRefreshStatusIcon(RefreshCoverStatus status) { switch (status) { case RefreshCoverStatus.none: return Center(); break; case RefreshCoverStatus.start: return CircularProgressIndicator(strokeWidth: 2); break; case RefreshCoverStatus.complete: return Icon(Icons.done); break; case RefreshCoverStatus.error: return Icon(Icons.refresh, color: Colors.red); break; default: return Center(); } } @override Widget build(BuildContext context) { final s = context.s; return Column( mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ FutureBuilder( future: _getAutoDownload(widget.podcastLocal.id), initialData: false, builder: (context, snapshot) { return ListTile( onTap: () => _setAutoDownload(!snapshot.data), leading: SizedBox( height: 18, width: 18, child: CustomPaint( painter: DownloadPainter( color: context.brightness == Brightness.light ? Colors.grey[600] : Colors.white, fraction: 0, progressColor: context.accentColor, ), ), ), title: Text(s.autoDownload), trailing: Transform.scale( scale: 0.9, child: Switch( value: snapshot.data, onChanged: _setAutoDownload), ), ); }), Divider(height: 1), FutureBuilder( future: _getSkipSecond(widget.podcastLocal.id), initialData: 0, builder: (context, snapshot) => ListTile( onTap: () { generalDialog( context, title: Text(s.skipSecondsAtStart, maxLines: 2), content: DurationPicker( duration: Duration(seconds: snapshot.data), onChange: (value) => _seconds = value.inSeconds, ), actions: [ FlatButton( onPressed: () { Navigator.of(context).pop(); _seconds = 0; }, child: Text( s.cancel, style: TextStyle(color: Colors.grey[600]), ), ), FlatButton( onPressed: () { Navigator.of(context).pop(); _saveSkipSeconds(_seconds); }, child: Text( s.confirm, style: TextStyle(color: context.accentColor), ), ) ], ).then((value) => setState(() {})); }, leading: Icon(Icons.fast_forward), title: Text(s.skipSecondsAtStart), trailing: Padding( padding: const EdgeInsets.only(right: 10.0), child: Text(snapshot.data.toTime), ), ), ), Divider(height: 1), ListTile( onTap: () { if (_markStatus != MarkStatus.start) { _confirmMarkListened(context); } }, title: Text(s.menuMarkAllListened), leading: SizedBox( height: 20, width: 20, child: CustomPaint( painter: ListenedAllPainter( context.brightness == Brightness.light ? Colors.grey[600] : Colors.white, stroke: 2), ), ), trailing: Padding( padding: const EdgeInsets.only(right: 10.0), child: SizedBox( height: 20, width: 20, child: _markStatus == MarkStatus.none ? Center() : _markStatus == MarkStatus.start ? CircularProgressIndicator(strokeWidth: 2) : Icon(Icons.done)), )), Divider(height: 1), ListTile( onTap: () { if (_coverStatus != RefreshCoverStatus.start) { _refreshArtWork(); } }, title: Text(s.refreshArtwork), leading: Icon(Icons.refresh), trailing: Padding( padding: const EdgeInsets.only(right: 15.0), child: SizedBox( height: 20, width: 20, child: _getRefreshStatusIcon(_coverStatus)))), Divider(height: 1), ]); } }