1
0
mirror of https://github.com/stonega/tsacdop synced 2025-02-18 04:20:37 +01:00

Update podcast setting menu, add skip seconds at end.

This commit is contained in:
stonegate 2020-09-18 23:01:00 +08:00
parent fb31758f50
commit b271965009
17 changed files with 425 additions and 235 deletions

View File

@ -308,6 +308,7 @@ class MessageLookup extends MessageLookupByLibrary {
"share" : MessageLookupByLibrary.simpleMessage("Share"), "share" : MessageLookupByLibrary.simpleMessage("Share"),
"showNotesFonts" : MessageLookupByLibrary.simpleMessage("Show notes font"), "showNotesFonts" : MessageLookupByLibrary.simpleMessage("Show notes font"),
"size" : MessageLookupByLibrary.simpleMessage("Size"), "size" : MessageLookupByLibrary.simpleMessage("Size"),
"skipSecondsAtEnd" : MessageLookupByLibrary.simpleMessage("Skip seconds at end"),
"skipSecondsAtStart" : MessageLookupByLibrary.simpleMessage("Skip seconds at start"), "skipSecondsAtStart" : MessageLookupByLibrary.simpleMessage("Skip seconds at start"),
"skipSilence" : MessageLookupByLibrary.simpleMessage("Skip silence"), "skipSilence" : MessageLookupByLibrary.simpleMessage("Skip silence"),
"skipToNext" : MessageLookupByLibrary.simpleMessage("Skip to next"), "skipToNext" : MessageLookupByLibrary.simpleMessage("Skip to next"),

View File

@ -308,6 +308,7 @@ class MessageLookup extends MessageLookupByLibrary {
"share" : MessageLookupByLibrary.simpleMessage("Compartir"), "share" : MessageLookupByLibrary.simpleMessage("Compartir"),
"showNotesFonts" : MessageLookupByLibrary.simpleMessage("Show notes font"), "showNotesFonts" : MessageLookupByLibrary.simpleMessage("Show notes font"),
"size" : MessageLookupByLibrary.simpleMessage("Tamaño"), "size" : MessageLookupByLibrary.simpleMessage("Tamaño"),
"skipSecondsAtEnd" : MessageLookupByLibrary.simpleMessage("Skip seconds at end"),
"skipSecondsAtStart" : MessageLookupByLibrary.simpleMessage("Saltar segundos al inicio"), "skipSecondsAtStart" : MessageLookupByLibrary.simpleMessage("Saltar segundos al inicio"),
"skipSilence" : MessageLookupByLibrary.simpleMessage("Saltar silencios"), "skipSilence" : MessageLookupByLibrary.simpleMessage("Saltar silencios"),
"skipToNext" : MessageLookupByLibrary.simpleMessage("Skip to next"), "skipToNext" : MessageLookupByLibrary.simpleMessage("Skip to next"),

View File

@ -308,6 +308,7 @@ class MessageLookup extends MessageLookupByLibrary {
"share" : MessageLookupByLibrary.simpleMessage("Partager"), "share" : MessageLookupByLibrary.simpleMessage("Partager"),
"showNotesFonts" : MessageLookupByLibrary.simpleMessage("Show notes font"), "showNotesFonts" : MessageLookupByLibrary.simpleMessage("Show notes font"),
"size" : MessageLookupByLibrary.simpleMessage("Taille"), "size" : MessageLookupByLibrary.simpleMessage("Taille"),
"skipSecondsAtEnd" : MessageLookupByLibrary.simpleMessage("Skip seconds at end"),
"skipSecondsAtStart" : MessageLookupByLibrary.simpleMessage("Passer les premières secondes du début"), "skipSecondsAtStart" : MessageLookupByLibrary.simpleMessage("Passer les premières secondes du début"),
"skipSilence" : MessageLookupByLibrary.simpleMessage("Skip silence"), "skipSilence" : MessageLookupByLibrary.simpleMessage("Skip silence"),
"skipToNext" : MessageLookupByLibrary.simpleMessage("Skip to next"), "skipToNext" : MessageLookupByLibrary.simpleMessage("Skip to next"),

View File

@ -308,6 +308,7 @@ class MessageLookup extends MessageLookupByLibrary {
"share" : MessageLookupByLibrary.simpleMessage("分享"), "share" : MessageLookupByLibrary.simpleMessage("分享"),
"showNotesFonts" : MessageLookupByLibrary.simpleMessage("节目简介字体"), "showNotesFonts" : MessageLookupByLibrary.simpleMessage("节目简介字体"),
"size" : MessageLookupByLibrary.simpleMessage("大小"), "size" : MessageLookupByLibrary.simpleMessage("大小"),
"skipSecondsAtEnd" : MessageLookupByLibrary.simpleMessage("结束跳过秒数"),
"skipSecondsAtStart" : MessageLookupByLibrary.simpleMessage("开头跳过秒数"), "skipSecondsAtStart" : MessageLookupByLibrary.simpleMessage("开头跳过秒数"),
"skipSilence" : MessageLookupByLibrary.simpleMessage("跳过无声"), "skipSilence" : MessageLookupByLibrary.simpleMessage("跳过无声"),
"skipToNext" : MessageLookupByLibrary.simpleMessage("下一首"), "skipToNext" : MessageLookupByLibrary.simpleMessage("下一首"),

View File

@ -2362,6 +2362,16 @@ class S {
); );
} }
/// `Skip seconds at end`
String get skipSecondsAtEnd {
return Intl.message(
'Skip seconds at end',
name: 'skipSecondsAtEnd',
desc: '',
args: [],
);
}
/// `Skip seconds at start` /// `Skip seconds at start`
String get skipSecondsAtStart { String get skipSecondsAtStart {
return Intl.message( return Intl.message(

View File

@ -535,6 +535,8 @@
"@showNotesFonts": {}, "@showNotesFonts": {},
"size": "Size", "size": "Size",
"@size": {}, "@size": {},
"skipSecondsAtEnd": "Skip seconds at end",
"@skipSecondsAtEnd": {},
"skipSecondsAtStart": "Skip seconds at start", "skipSecondsAtStart": "Skip seconds at start",
"@skipSecondsAtStart": {}, "@skipSecondsAtStart": {},
"skipSilence": "Skip silence", "skipSilence": "Skip silence",

View File

@ -535,6 +535,8 @@
"@showNotesFonts": {}, "@showNotesFonts": {},
"size": "Tamaño", "size": "Tamaño",
"@size": {}, "@size": {},
"skipSecondsAtEnd": "Skip seconds at end",
"@skipSecondsAtEnd": {},
"skipSecondsAtStart": "Saltar segundos al inicio", "skipSecondsAtStart": "Saltar segundos al inicio",
"@skipSecondsAtStart": {}, "@skipSecondsAtStart": {},
"skipSilence": "Saltar silencios", "skipSilence": "Saltar silencios",

View File

@ -535,6 +535,8 @@
"@showNotesFonts": {}, "@showNotesFonts": {},
"size": "Taille", "size": "Taille",
"@size": {}, "@size": {},
"skipSecondsAtEnd": "Skip seconds at end",
"@skipSecondsAtEnd": {},
"skipSecondsAtStart": "Passer les premières secondes du début", "skipSecondsAtStart": "Passer les premières secondes du début",
"@skipSecondsAtStart": {}, "@skipSecondsAtStart": {},
"skipSilence": "Skip silence", "skipSilence": "Skip silence",

View File

@ -535,6 +535,8 @@
"@showNotesFonts": {}, "@showNotesFonts": {},
"size": "大小", "size": "大小",
"@size": {}, "@size": {},
"skipSecondsAtEnd": "结束跳过秒数",
"@skipSecondsAtEnd": {},
"skipSecondsAtStart": "开头跳过秒数", "skipSecondsAtStart": "开头跳过秒数",
"@skipSecondsAtStart": {}, "@skipSecondsAtStart": {},
"skipSilence": "跳过无声", "skipSilence": "跳过无声",

View File

@ -27,7 +27,7 @@ class DBHelper {
var documentsDirectory = await getDatabasesPath(); var documentsDirectory = await getDatabasesPath();
var path = join(documentsDirectory, "podcasts.db"); var path = join(documentsDirectory, "podcasts.db");
var theDb = await openDatabase(path, var theDb = await openDatabase(path,
version: 3, onCreate: _onCreate, onUpgrade: _onUpgrade); version: 4, onCreate: _onCreate, onUpgrade: _onUpgrade);
return theDb; return theDb;
} }
@ -37,14 +37,15 @@ class DBHelper {
imageUrl TEXT,rssUrl TEXT UNIQUE, primaryColor TEXT, author TEXT, imageUrl TEXT,rssUrl TEXT UNIQUE, primaryColor TEXT, author TEXT,
description TEXT, add_date INTEGER, imagePath TEXT, provider TEXT, link TEXT, description TEXT, add_date INTEGER, imagePath TEXT, provider TEXT, link TEXT,
background_image TEXT DEFAULT '', hosts TEXT DEFAULT '',update_count INTEGER DEFAULT 0, background_image TEXT DEFAULT '', hosts TEXT DEFAULT '',update_count INTEGER DEFAULT 0,
episode_count INTEGER DEFAULT 0, skip_seconds INTEGER DEFAULT 0, auto_download INTEGER DEFAULT 0)"""); episode_count INTEGER DEFAULT 0, skip_seconds INTEGER DEFAULT 0,
auto_download INTEGER DEFAULT 0, skip_seconds_end INTEGER DEFAULT 0)""");
await db await db
.execute("""CREATE TABLE Episodes(id INTEGER PRIMARY KEY,title TEXT, .execute("""CREATE TABLE Episodes(id INTEGER PRIMARY KEY,title TEXT,
enclosure_url TEXT UNIQUE, enclosure_length INTEGER, pubDate TEXT, enclosure_url TEXT UNIQUE, enclosure_length INTEGER, pubDate TEXT,
description TEXT, feed_id TEXT, feed_link TEXT, milliseconds INTEGER, description TEXT, feed_id TEXT, feed_link TEXT, milliseconds INTEGER,
duration INTEGER DEFAULT 0, explicit INTEGER DEFAULT 0, liked INTEGER DEFAULT 0, duration INTEGER DEFAULT 0, explicit INTEGER DEFAULT 0, liked INTEGER DEFAULT 0,
liked_date INTEGER DEFAULT 0, downloaded TEXT DEFAULT 'ND', download_date INTEGER DEFAULT 0, media_id TEXT, liked_date INTEGER DEFAULT 0, downloaded TEXT DEFAULT 'ND',
is_new INTEGER DEFAULT 0)"""); download_date INTEGER DEFAULT 0, media_id TEXT, is_new INTEGER DEFAULT 0)""");
await db.execute( await db.execute(
"""CREATE TABLE PlayHistory(id INTEGER PRIMARY KEY, title TEXT, enclosure_url TEXT, """CREATE TABLE PlayHistory(id INTEGER PRIMARY KEY, title TEXT, enclosure_url TEXT,
seconds REAL, seek_value REAL, add_date INTEGER, listen_time INTEGER DEFAULT 0)"""); seconds REAL, seek_value REAL, add_date INTEGER, listen_time INTEGER DEFAULT 0)""");
@ -59,9 +60,16 @@ class DBHelper {
"ALTER TABLE PodcastLocal ADD skip_seconds INTEGER DEFAULT 0 "); "ALTER TABLE PodcastLocal ADD skip_seconds INTEGER DEFAULT 0 ");
await db.execute( await db.execute(
"ALTER TABLE PodcastLocal ADD auto_download INTEGER DEFAULT 0"); "ALTER TABLE PodcastLocal ADD auto_download INTEGER DEFAULT 0");
await db.execute(
"ALTER TABLE PodcastLocal ADD skip_seconds_end INTEGER DEFAULT 0 ");
} else if (oldVersion == 2) { } else if (oldVersion == 2) {
await db.execute( await db.execute(
"ALTER TABLE PodcastLocal ADD auto_download INTEGER DEFAULT 0"); "ALTER TABLE PodcastLocal ADD auto_download INTEGER DEFAULT 0");
await db.execute(
"ALTER TABLE PodcastLocal ADD skip_seconds_end INTEGER DEFAULT 0 ");
} else if (oldVersion == 3) {
await db.execute(
"ALTER TABLE PodcastLocal ADD skip_seconds_end INTEGER DEFAULT 0 ");
} }
} }
@ -130,19 +138,33 @@ class DBHelper {
return list.first['count']; return list.first['count'];
} }
Future<int> getSkipSeconds(String id) async { Future<int> getSkipSecondsStart(String id) async {
var dbClient = await database; var dbClient = await database;
List<Map> list = await dbClient List<Map> list = await dbClient
.rawQuery('SELECT skip_seconds FROM PodcastLocal WHERE id = ?', [id]); .rawQuery('SELECT skip_seconds FROM PodcastLocal WHERE id = ?', [id]);
return list.first['skip_seconds']; return list.first['skip_seconds'];
} }
Future<int> saveSkipSeconds(String id, int seconds) async { Future<int> saveSkipSecondsStart(String id, int seconds) async {
var dbClient = await database; var dbClient = await database;
return await dbClient.rawUpdate( return await dbClient.rawUpdate(
"UPDATE PodcastLocal SET skip_seconds = ? WHERE id = ?", [seconds, id]); "UPDATE PodcastLocal SET skip_seconds = ? WHERE id = ?", [seconds, id]);
} }
Future<int> getSkipSecondsEnd(String id) async {
var dbClient = await database;
List<Map> list = await dbClient.rawQuery(
'SELECT skip_seconds_end FROM PodcastLocal WHERE id = ?', [id]);
return list.first['skip_seconds_end'];
}
Future<int> saveSkipSecondsEnd(String id, int seconds) async {
var dbClient = await database;
return await dbClient.rawUpdate(
"UPDATE PodcastLocal SET skip_seconds_end = ? WHERE id = ?",
[seconds, id]);
}
Future<bool> getAutoDownload(String id) async { Future<bool> getAutoDownload(String id) async {
var dbClient = await database; var dbClient = await database;
List<Map> list = await dbClient List<Map> list = await dbClient
@ -1336,8 +1358,8 @@ class DBHelper {
EpisodeBrief episode; EpisodeBrief episode;
List<Map> list = await dbClient.rawQuery( List<Map> list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.milliseconds, P.imagePath, """SELECT E.title, E.enclosure_url, E.enclosure_length, E.milliseconds, P.imagePath,
P.title as feed_title, E.duration, E.explicit, P.skip_seconds,E.is_new, P.title as feed_title, E.duration, E.explicit, P.skip_seconds, P.skip_seconds_end,
P.primaryColor, E.media_id FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id E.is_new, P.primaryColor, E.media_id FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE E.enclosure_url = ?""", [url]); WHERE E.enclosure_url = ?""", [url]);
if (list.isEmpty) { if (list.isEmpty) {
return null; return null;
@ -1354,7 +1376,8 @@ class DBHelper {
list.first['imagePath'], list.first['imagePath'],
list.first['is_new'], list.first['is_new'],
mediaId: list.first['media_id'], mediaId: list.first['media_id'],
skipSeconds: list.first['skip_seconds']); skipSecondsStart: list.first['skip_seconds'],
skipSecondsEnd: list.first['skip_seconds_end']);
return episode; return episode;
} }
} }
@ -1364,9 +1387,9 @@ class DBHelper {
EpisodeBrief episode; EpisodeBrief episode;
List<Map> list = await dbClient.rawQuery( List<Map> list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.milliseconds, P.imagePath, """SELECT E.title, E.enclosure_url, E.enclosure_length, E.milliseconds, P.imagePath,
P.title as feed_title, E.duration, E.explicit, P.skip_seconds,E.is_new, P.title as feed_title, E.duration, E.explicit, P.skip_seconds, P.skip_seconds_end,
P.primaryColor, E.media_id FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id E.is_new, P.primaryColor, E.media_id FROM Episodes E INNER JOIN
WHERE E.media_id = ?""", [id]); PodcastLocal P ON E.feed_id = P.id WHERE E.media_id = ?""", [id]);
if (list.isEmpty) { if (list.isEmpty) {
return null; return null;
} else { } else {
@ -1382,7 +1405,8 @@ class DBHelper {
list.first['imagePath'], list.first['imagePath'],
list.first['is_new'], list.first['is_new'],
mediaId: list.first['media_id'], mediaId: list.first['media_id'],
skipSeconds: list.first['skip_seconds']); skipSecondsStart: list.first['skip_seconds'],
skipSecondsEnd: list.first['skip_seconds_end']);
return episode; return episode;
} }
} }

View File

@ -354,7 +354,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
case 2: case 2:
generalSheet( generalSheet(
context, context,
title: s.settings, title: widget.podcastLocal.title,
child: PodcastSetting(podcastLocal: widget.podcastLocal), child: PodcastSetting(podcastLocal: widget.podcastLocal),
).then((value) => setState(() {})); ).then((value) => setState(() {}));
break; break;
@ -674,7 +674,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var _color = widget.podcastLocal.primaryColor.colorizedark(); final color = widget.podcastLocal.primaryColor.colorizedark();
final s = context.s; final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
@ -745,7 +745,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
color: Colors.white, color: Colors.white,
), ),
expandedHeight: 150 + context.paddingTop, expandedHeight: 150 + context.paddingTop,
backgroundColor: _color, backgroundColor: color,
floating: true, floating: true,
pinned: true, pinned: true,
flexibleSpace: LayoutBuilder( flexibleSpace: LayoutBuilder(

View File

@ -82,14 +82,14 @@ class __PodcastCardState extends State<_PodcastCard>
Future<int> _getSkipSecond(String id) async { Future<int> _getSkipSecond(String id) async {
var dbHelper = DBHelper(); var dbHelper = DBHelper();
var seconds = await dbHelper.getSkipSeconds(id); var seconds = await dbHelper.getSkipSecondsStart(id);
_skipSeconds = seconds; _skipSeconds = seconds;
return seconds; return seconds;
} }
_saveSkipSeconds(String id, int seconds) async { _saveSkipSeconds(String id, int seconds) async {
var dbHelper = DBHelper(); var dbHelper = DBHelper();
await dbHelper.saveSkipSeconds(id, seconds); await dbHelper.saveSkipSecondsStart(id, seconds);
} }
_setAutoDownload(String id, bool boo) async { _setAutoDownload(String id, bool boo) async {
@ -463,8 +463,7 @@ class __PodcastCardState extends State<_PodcastCard>
), ),
), ),
FlatButton( FlatButton(
splashColor: splashColor: Colors.red.withAlpha(70),
context.accentColor.withAlpha(70),
onPressed: () { onPressed: () {
groupList.removePodcast( groupList.removePodcast(
widget.podcastLocal.id); widget.podcastLocal.id);

View File

@ -3,12 +3,14 @@ import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image/image.dart' as img;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:image/image.dart' as img; import 'package:provider/provider.dart';
import 'package:webfeed/webfeed.dart'; import 'package:webfeed/webfeed.dart';
import '../local_storage/sqflite_localpodcast.dart'; import '../local_storage/sqflite_localpodcast.dart';
import '../state/podcast_group.dart';
import '../type/play_histroy.dart'; import '../type/play_histroy.dart';
import '../type/podcastlocal.dart'; import '../type/podcastlocal.dart';
import '../util/custom_widget.dart'; import '../util/custom_widget.dart';
@ -28,72 +30,73 @@ class PodcastSetting extends StatefulWidget {
} }
class _PodcastSettingState extends State<PodcastSetting> { class _PodcastSettingState extends State<PodcastSetting> {
final _dbHelper = DBHelper();
MarkStatus _markStatus = MarkStatus.none; MarkStatus _markStatus = MarkStatus.none;
RefreshCoverStatus _coverStatus = RefreshCoverStatus.none; RefreshCoverStatus _coverStatus = RefreshCoverStatus.none;
int _seconds = 0; int _secondsStart;
int _secondsEnd;
bool _markConfirm;
bool _removeConfirm;
bool _showStartTimePicker;
bool _showEndTimePicker;
@override
void initState() {
super.initState();
_secondsStart = 0;
_secondsEnd = 0;
_markConfirm = false;
_removeConfirm = false;
_showStartTimePicker = false;
_showEndTimePicker = false;
}
Future<void> _setAutoDownload(bool boo) async { Future<void> _setAutoDownload(bool boo) async {
var permission = await _checkPermmison(); var permission = await _checkPermmison();
if (permission) { if (permission) {
var dbHelper = DBHelper(); await _dbHelper.saveAutoDownload(widget.podcastLocal.id, boo: boo);
await dbHelper.saveAutoDownload(widget.podcastLocal.id, boo: boo);
} }
if (mounted) setState(() {}); if (mounted) setState(() {});
} }
Future<void> _saveSkipSeconds(int seconds) async { Future<void> _saveSkipSecondsStart(int seconds) async {
var dbHelper = DBHelper(); await _dbHelper.saveSkipSecondsStart(widget.podcastLocal.id, seconds);
await dbHelper.saveSkipSeconds(widget.podcastLocal.id, seconds); }
Future<void> _saveSkipSecondsEnd(int seconds) async {
await _dbHelper.saveSkipSecondsEnd(widget.podcastLocal.id, seconds);
}
Future<bool> _getAutoDownload(String id) async {
return await _dbHelper.getAutoDownload(id);
}
Future<int> _getSkipSecondStart(String id) async {
return await _dbHelper.getSkipSecondsStart(id);
}
Future<int> _getSkipSecondEnd(String id) async {
return await _dbHelper.getSkipSecondsEnd(id);
} }
Future<void> _markListened(String podcastId) async { Future<void> _markListened(String podcastId) async {
setState(() { setState(() {
_markStatus = MarkStatus.start; _markStatus = MarkStatus.start;
}); });
var dbHelper = DBHelper(); var episodes = await _dbHelper.getRssItem(podcastId, -1, reverse: true);
var episodes = await dbHelper.getRssItem(podcastId, -1, reverse: true);
for (var episode in episodes) { for (var episode in episodes) {
var marked = await dbHelper.checkMarked(episode); final marked = await _dbHelper.checkMarked(episode);
if (!marked) { if (!marked) {
final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1); final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1);
await dbHelper.saveHistory(history); await _dbHelper.saveHistory(history);
}
}
if (mounted) { if (mounted) {
setState(() { setState(() {
_markStatus = MarkStatus.complete; _markStatus = MarkStatus.complete;
}); });
} }
} }
}
}
void _confirmMarkListened(BuildContext context) => generalDialog(
context,
title: Text(context.s.markConfirm),
content: Text(context.s.markConfirmContent),
actions: <Widget>[
FlatButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
context.s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
),
FlatButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () async {
Navigator.of(context).pop();
await _markListened(widget.podcastLocal.id);
},
child: Text(
context.s.confirm,
style: TextStyle(color: context.accentColor),
),
)
],
);
Future<void> _refreshArtWork() async { Future<void> _refreshArtWork() async {
setState(() => _coverStatus = RefreshCoverStatus.start); setState(() => _coverStatus = RefreshCoverStatus.start);
@ -161,17 +164,6 @@ class _PodcastSettingState extends State<PodcastSetting> {
} }
} }
Future<bool> _getAutoDownload(String id) async {
var dbHelper = DBHelper();
return await dbHelper.getAutoDownload(id);
}
Future<int> _getSkipSecond(String id) async {
var dbHelper = DBHelper();
var seconds = await dbHelper.getSkipSeconds(id);
return seconds;
}
Widget _getRefreshStatusIcon(RefreshCoverStatus status) { Widget _getRefreshStatusIcon(RefreshCoverStatus status) {
switch (status) { switch (status) {
case RefreshCoverStatus.none: case RefreshCoverStatus.none:
@ -194,6 +186,7 @@ class _PodcastSettingState extends State<PodcastSetting> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final s = context.s; final s = context.s;
final groupList = context.watch<GroupList>();
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -205,8 +198,8 @@ class _PodcastSettingState extends State<PodcastSetting> {
return ListTile( return ListTile(
onTap: () => _setAutoDownload(!snapshot.data), onTap: () => _setAutoDownload(!snapshot.data),
leading: SizedBox( leading: SizedBox(
height: 18, height: 22,
width: 18, width: 24,
child: CustomPaint( child: CustomPaint(
painter: DownloadPainter( painter: DownloadPainter(
color: context.brightness == Brightness.light color: context.brightness == Brightness.light
@ -220,49 +213,23 @@ class _PodcastSettingState extends State<PodcastSetting> {
title: Text(s.autoDownload), title: Text(s.autoDownload),
trailing: Transform.scale( trailing: Transform.scale(
scale: 0.9, scale: 0.9,
child: Switch( child:
value: snapshot.data, onChanged: _setAutoDownload), Switch(value: snapshot.data, onChanged: _setAutoDownload),
), ),
); );
}), }),
Divider(height: 1),
FutureBuilder<int>( FutureBuilder<int>(
future: _getSkipSecond(widget.podcastLocal.id), future: _getSkipSecondStart(widget.podcastLocal.id),
initialData: 0, initialData: 0,
builder: (context, snapshot) => ListTile( builder: (context, snapshot) => ListTile(
onTap: () { onTap: () {
generalDialog( _secondsStart = 0;
context, setState(() {
title: Text(s.skipSecondsAtStart, maxLines: 2), _removeConfirm = false;
content: DurationPicker( _markConfirm = false;
duration: Duration(seconds: snapshot.data), _showEndTimePicker = false;
onChange: (value) => _seconds = value.inSeconds, _showStartTimePicker = !_showStartTimePicker;
), });
actions: <Widget>[
FlatButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () {
Navigator.of(context).pop();
_seconds = 0;
},
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
),
FlatButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () {
Navigator.of(context).pop();
_saveSkipSeconds(_seconds);
},
child: Text(
s.confirm,
style: TextStyle(color: context.accentColor),
),
)
],
).then((value) => setState(() {}));
}, },
leading: Icon(Icons.fast_forward), leading: Icon(Icons.fast_forward),
title: Text(s.skipSecondsAtStart), title: Text(s.skipSecondsAtStart),
@ -272,17 +239,80 @@ class _PodcastSettingState extends State<PodcastSetting> {
), ),
), ),
), ),
if (_showStartTimePicker)
_TimePicker(
onCancel: () {
_secondsStart = 0;
setState(() => _showStartTimePicker = false);
},
onConfirm: () async {
await _saveSkipSecondsStart(_secondsStart);
setState(() => _showStartTimePicker = false);
},
onChange: (value) => _secondsStart = value.inSeconds),
FutureBuilder<int>(
future: _getSkipSecondEnd(widget.podcastLocal.id),
initialData: 0,
builder: (context, snapshot) => ListTile(
onTap: () {
_secondsEnd = 0;
setState(() {
_removeConfirm = false;
_markConfirm = false;
_showStartTimePicker = false;
_showEndTimePicker = !_showEndTimePicker;
});
},
leading: Icon(Icons.fast_rewind),
title: Text(s.skipSecondsAtEnd),
trailing: Padding(
padding: const EdgeInsets.only(right: 10.0),
child: Text(snapshot.data.toTime),
),
),
),
if (_showEndTimePicker)
_TimePicker(
onCancel: () {
_secondsEnd = 0;
setState(() => _showEndTimePicker = false);
},
onConfirm: () async {
await _saveSkipSecondsEnd(_secondsEnd);
setState(() => _showEndTimePicker = false);
},
onChange: (value) => _secondsEnd = value.inSeconds,
),
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), Divider(height: 1),
ListTile( ListTile(
onTap: () { onTap: () {
if (_markStatus != MarkStatus.start) { setState(() {
_confirmMarkListened(context); _removeConfirm = false;
} _showStartTimePicker = false;
_showEndTimePicker = false;
_markConfirm = !_markConfirm;
});
}, },
title: Text(s.menuMarkAllListened), title: Text(s.menuMarkAllListened,
style: TextStyle(
color: context.accentColor, fontWeight: FontWeight.bold)),
leading: SizedBox( leading: SizedBox(
height: 20, height: 22,
width: 20, width: 24,
child: CustomPaint( child: CustomPaint(
painter: ListenedAllPainter( painter: ListenedAllPainter(
context.brightness == Brightness.light context.brightness == Brightness.light
@ -302,22 +332,119 @@ class _PodcastSettingState extends State<PodcastSetting> {
? CircularProgressIndicator(strokeWidth: 2) ? CircularProgressIndicator(strokeWidth: 2)
: Icon(Icons.done)), : Icon(Icons.done)),
)), )),
Divider(height: 1), if (_markConfirm)
Container(
width: double.infinity,
color: context.primaryColorDark,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FlatButton(
onPressed: () => setState(() {
_markConfirm = false;
}),
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
)),
FlatButton(
onPressed: () {
if (_markStatus != MarkStatus.start) {
_markListened(widget.podcastLocal.id);
}
setState(() {
_markConfirm = false;
});
},
child: Text(s.confirm,
style: TextStyle(color: context.accentColor))),
],
),
),
ListTile( ListTile(
onTap: () { onTap: () {
if (_coverStatus != RefreshCoverStatus.start) { setState(() {
_refreshArtWork(); _markConfirm = false;
} _showStartTimePicker = false;
_showEndTimePicker = false;
_removeConfirm = !_removeConfirm;
});
}, },
title: Text(s.refreshArtwork), title: Text(s.remove,
leading: Icon(Icons.refresh), style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold)),
trailing: Padding( leading: Icon(Icons.delete, color: Colors.red),
padding: const EdgeInsets.only(right: 15.0), ),
child: SizedBox( if (_removeConfirm)
height: 20, Container(
width: 20, width: double.infinity,
child: _getRefreshStatusIcon(_coverStatus)))), color: context.primaryColorDark,
Divider(height: 1), child: Row(
]); mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FlatButton(
onPressed: () => setState(() {
_removeConfirm = false;
}),
child:
Text(s.cancel, style: TextStyle(color: Colors.grey[600])),
),
FlatButton(
splashColor: Colors.red.withAlpha(70),
onPressed: () {
groupList.removePodcast(widget.podcastLocal.id);
Navigator.of(context).pop();
},
child:
Text(s.confirm, style: TextStyle(color: Colors.red))),
],
),
),
],
);
}
}
class _TimePicker extends StatelessWidget {
const _TimePicker({this.onConfirm, this.onCancel, this.onChange, Key key})
: super(key: key);
final VoidCallback onConfirm;
final VoidCallback onCancel;
final ValueChanged<Duration> onChange;
@override
Widget build(BuildContext context) {
final s = context.s;
return Container(
color: context.primaryColorDark,
child: Column(
children: [
SizedBox(height: 10),
DurationPicker(
key: key,
onChange: onChange,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FlatButton(
onPressed: onCancel,
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
),
FlatButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: onConfirm,
child: Text(
s.confirm,
style: TextStyle(color: context.accentColor),
),
)
],
)
],
),
);
} }
} }

View File

@ -920,6 +920,13 @@ class AudioPlayerTask extends BackgroundAudioTask {
Future<void> _playFromStart() async { Future<void> _playFromStart() async {
_playing = true; _playing = true;
_session.setActive(true); _session.setActive(true);
if (mediaItem.extras['skipSecondsStart'] > 0 ||
mediaItem.extras['skipSecondsEnd'] > 0) {
//_audioPlayer.seek(Duration(seconds: mediaItem.extras['skip']));
_audioPlayer.setClip(
start: Duration(seconds: mediaItem.extras['skipSecondsStart']),
end: Duration(seconds: mediaItem.extras['skipSecondsEnd']));
}
if (_audioPlayer.playbackEvent.state != AudioPlaybackState.connecting || if (_audioPlayer.playbackEvent.state != AudioPlaybackState.connecting ||
_audioPlayer.playbackEvent.state != AudioPlaybackState.none) { _audioPlayer.playbackEvent.state != AudioPlaybackState.none) {
try { try {
@ -928,9 +935,6 @@ class AudioPlayerTask extends BackgroundAudioTask {
_setState(processingState: AudioProcessingState.error); _setState(processingState: AudioProcessingState.error);
} }
} }
if (mediaItem.extras['skip'] > 0) {
_audioPlayer.seek(Duration(seconds: mediaItem.extras['skip']));
}
} }
@override @override

View File

@ -21,7 +21,8 @@ class EpisodeBrief extends Equatable {
final String imagePath; final String imagePath;
final String mediaId; final String mediaId;
final int isNew; final int isNew;
final int skipSeconds; final int skipSecondsStart;
final int skipSecondsEnd;
final int downloadDate; final int downloadDate;
EpisodeBrief( EpisodeBrief(
this.title, this.title,
@ -37,7 +38,8 @@ class EpisodeBrief extends Equatable {
{this.mediaId, {this.mediaId,
this.liked, this.liked,
this.downloaded, this.downloaded,
this.skipSeconds, this.skipSecondsStart,
this.skipSecondsEnd,
this.description = '', this.description = '',
this.downloadDate = 0}) this.downloadDate = 0})
: assert(enclosureUrl != null); : assert(enclosureUrl != null);
@ -50,7 +52,10 @@ class EpisodeBrief extends Equatable {
album: feedTitle, album: feedTitle,
duration: Duration.zero, duration: Duration.zero,
artUri: 'file://$imagePath', artUri: 'file://$imagePath',
extras: {'skip': skipSeconds}); extras: {
'skipSecondsStart': skipSecondsStart,
'skipSecondsEnd': skipSecondsEnd
});
} }
ImageProvider get avatarImage { ImageProvider get avatarImage {
@ -72,7 +77,8 @@ class EpisodeBrief extends Equatable {
primaryColor, duration, explicit, imagePath, isNew, primaryColor, duration, explicit, imagePath, isNew,
mediaId: mediaId ?? this.mediaId, mediaId: mediaId ?? this.mediaId,
downloaded: downloaded, downloaded: downloaded,
skipSeconds: skipSeconds, skipSecondsStart: skipSecondsStart,
skipSecondsEnd: skipSecondsEnd,
description: description, description: description,
downloadDate: downloadDate); downloadDate: downloadDate);

View File

@ -635,24 +635,20 @@ class DurationPicker extends StatelessWidget {
@required this.onChange, @required this.onChange,
this.snapToMins, this.snapToMins,
this.width, this.width,
this.height}); this.height,
Key key})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
width: width ?? _kDurationPickerWidthPortrait / 1.5, width: width ?? _kDurationPickerWidthPortrait / 1.5,
height: height ?? _kDurationPickerHeightPortrait / 1.5, height: height ?? _kDurationPickerHeightPortrait / 1.5,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: _Dial( child: _Dial(
duration: duration, duration: duration,
onChanged: onChange, onChanged: onChange,
snapToMins: snapToMins, snapToMins: snapToMins,
), ),
), );
]));
} }
} }

View File

@ -41,7 +41,10 @@ Future generalSheet(BuildContext context, {Widget child, String title}) async =>
elevation: 2, elevation: 2,
context: context, context: context,
builder: (context) { builder: (context) {
return Column( return SafeArea(
child: SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Padding( Padding(
@ -55,11 +58,20 @@ Future generalSheet(BuildContext context, {Widget child, String title}) async =>
), ),
), ),
Padding( Padding(
padding: EdgeInsets.symmetric(vertical: 6.0), padding: EdgeInsets.only(
child: Text(title, style: context.textTheme.headline6), left: 50, right: 50, top: 6.0, bottom: 15),
child: Text(
title,
style: context.textTheme.headline6,
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.clip,
),
), ),
Divider(height: 1), Divider(height: 1),
child, child,
], ],
),
),
); );
}); });