Remove listened indicator and increase the color difference
Improve download manage page, support fliters
This commit is contained in:
parent
935566b304
commit
f4b56938ae
|
@ -269,14 +269,15 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
padding: EdgeInsets.only(
|
||||
left: 20.0, right: 20, bottom: 10),
|
||||
defaultTextStyle:
|
||||
GoogleFonts.libreBaskerville(
|
||||
// GoogleFonts.libreBaskerville(
|
||||
GoogleFonts.martel(
|
||||
textStyle: TextStyle(
|
||||
height: 1.8,
|
||||
),
|
||||
),
|
||||
data: _description,
|
||||
linkStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
color: context.accentColor,
|
||||
// decoration: TextDecoration.underline,
|
||||
textBaseline: TextBaseline.ideographic),
|
||||
onLinkTap: (url) {
|
||||
|
@ -296,7 +297,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
_launchUrl(link.url);
|
||||
},
|
||||
text: _description,
|
||||
style: GoogleFonts.libreBaskerville(
|
||||
style: GoogleFonts.martel(
|
||||
textStyle: TextStyle(
|
||||
height: 1.8,
|
||||
),
|
||||
|
@ -384,8 +385,6 @@ class MenuBar extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _MenuBarState extends State<MenuBar> {
|
||||
bool _liked = false;
|
||||
|
||||
Future<PlayHistory> getPosition(EpisodeBrief episode) async {
|
||||
var dbHelper = DBHelper();
|
||||
return await dbHelper.getPosition(episode);
|
||||
|
@ -394,17 +393,14 @@ class _MenuBarState extends State<MenuBar> {
|
|||
Future<int> saveLiked(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
int result = await dbHelper.setLiked(url);
|
||||
if (result == 1 && mounted) setState(() => _liked = true);
|
||||
setState(() {});
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<int> setUnliked(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
int result = await dbHelper.setUniked(url);
|
||||
if (result == 1 && mounted)
|
||||
setState(() {
|
||||
_liked = false;
|
||||
});
|
||||
setState(() {});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -418,12 +414,6 @@ class _MenuBarState extends State<MenuBar> {
|
|||
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_liked = false;
|
||||
}
|
||||
|
||||
Widget _buttonOnMenu(Widget widget, VoidCallback onTap) => Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
|
@ -495,7 +485,7 @@ class _MenuBarState extends State<MenuBar> {
|
|||
future: _isLiked(widget.episodeItem),
|
||||
initialData: false,
|
||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||
return (!snapshot.data && !_liked)
|
||||
return (!snapshot.data)
|
||||
? _buttonOnMenu(
|
||||
Icon(
|
||||
Icons.favorite_border,
|
||||
|
@ -508,23 +498,13 @@ class _MenuBarState extends State<MenuBar> {
|
|||
await Future.delayed(Duration(seconds: 2));
|
||||
_overlayEntry?.remove();
|
||||
})
|
||||
: (snapshot.data && !_liked)
|
||||
? _buttonOnMenu(
|
||||
Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
() => setUnliked(
|
||||
widget.episodeItem.enclosureUrl))
|
||||
: _buttonOnMenu(
|
||||
Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
() {
|
||||
setUnliked(widget.episodeItem.enclosureUrl);
|
||||
},
|
||||
);
|
||||
: _buttonOnMenu(
|
||||
Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
() =>
|
||||
setUnliked(widget.episodeItem.enclosureUrl));
|
||||
},
|
||||
),
|
||||
DownloadButton(episode: widget.episodeItem),
|
||||
|
@ -534,7 +514,7 @@ class _MenuBarState extends State<MenuBar> {
|
|||
return data.contains(widget.episodeItem)
|
||||
? _buttonOnMenu(
|
||||
Icon(Icons.playlist_add_check,
|
||||
color: Theme.of(context).accentColor), () {
|
||||
color: context.accentColor), () {
|
||||
audio.delFromPlaylist(widget.episodeItem);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Removed from playlist',
|
||||
|
|
|
@ -376,14 +376,10 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
|||
}
|
||||
}
|
||||
|
||||
class PodcastPreview extends StatefulWidget {
|
||||
class PodcastPreview extends StatelessWidget {
|
||||
final PodcastLocal podcastLocal;
|
||||
PodcastPreview({this.podcastLocal, Key key}) : super(key: key);
|
||||
@override
|
||||
_PodcastPreviewState createState() => _PodcastPreviewState();
|
||||
}
|
||||
|
||||
class _PodcastPreviewState extends State<PodcastPreview> {
|
||||
Future<List<EpisodeBrief>> _getRssItemTop(PodcastLocal podcastLocal) async {
|
||||
var dbHelper = DBHelper();
|
||||
List<EpisodeBrief> episodes = await dbHelper.getRssItemTop(podcastLocal.id);
|
||||
|
@ -393,8 +389,8 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color _c = (Theme.of(context).brightness == Brightness.light)
|
||||
? widget.podcastLocal.primaryColor.colorizedark()
|
||||
: widget.podcastLocal.primaryColor.colorizeLight();
|
||||
? podcastLocal.primaryColor.colorizedark()
|
||||
: podcastLocal.primaryColor.colorizeLight();
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
|
@ -402,7 +398,7 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
selector: (_, worker) => worker.created,
|
||||
builder: (context, created, child) {
|
||||
return FutureBuilder<List<EpisodeBrief>>(
|
||||
future: _getRssItemTop(widget.podcastLocal),
|
||||
future: _getRssItemTop(podcastLocal),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
print(snapshot.error);
|
||||
|
@ -411,7 +407,7 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
return (snapshot.hasData)
|
||||
? ShowEpisode(
|
||||
episodes: snapshot.data,
|
||||
podcastLocal: widget.podcastLocal,
|
||||
podcastLocal: podcastLocal,
|
||||
)
|
||||
: Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
|
@ -429,7 +425,7 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Text(widget.podcastLocal.title,
|
||||
child: Text(podcastLocal.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.visible,
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: _c)),
|
||||
|
@ -450,11 +446,11 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
context,
|
||||
SlideLeftHideRoute(
|
||||
transitionPage: PodcastDetail(
|
||||
podcastLocal: widget.podcastLocal,
|
||||
podcastLocal: podcastLocal,
|
||||
hide: playerRunning,
|
||||
),
|
||||
page: PodcastDetail(
|
||||
podcastLocal: widget.podcastLocal,
|
||||
podcastLocal: podcastLocal,
|
||||
)),
|
||||
);
|
||||
},
|
||||
|
@ -606,7 +602,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
isListened > 0.95
|
||||
isListened > 0
|
||||
? Text('Listened',
|
||||
style: TextStyle(
|
||||
color: context.textColor.withOpacity(0.5)))
|
||||
|
@ -671,7 +667,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
}
|
||||
break;
|
||||
case 3:
|
||||
if (isListened < 0.95) {
|
||||
if (isListened < 1) {
|
||||
await _markListened(episode);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
|
|
|
@ -24,6 +24,7 @@ const String favLayoutKey = 'favLayoutKey';
|
|||
const String downloadLayoutKey = 'downloadLayoutKey';
|
||||
const String autoDownloadNetworkKey = 'autoDownloadNetwork';
|
||||
const String episodePopupMenuKey = 'episodePopupMenuKey';
|
||||
const String autoDeleteKey = 'autoDeleteKey';
|
||||
|
||||
class KeyValueStorage {
|
||||
final String key;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'dart:async';
|
||||
import 'package:path/path.dart';
|
||||
|
@ -272,9 +274,7 @@ class DBHelper {
|
|||
var dbClient = await database;
|
||||
int i = 0;
|
||||
List<Map> list =
|
||||
await dbClient.rawQuery("""SELECT listen_time FROM PlayHistory
|
||||
WHERE enclosure_url = ?
|
||||
""", [url]);
|
||||
await dbClient.rawQuery("SELECT listen_time FROM PlayHistory WHERE enclosure_url = ?", [url]);
|
||||
if (list.length == 0)
|
||||
return 0;
|
||||
else {
|
||||
|
@ -708,35 +708,35 @@ class DBHelper {
|
|||
return episodes;
|
||||
}
|
||||
|
||||
Future<EpisodeBrief> getRssItemDownload(String url) async {
|
||||
var dbClient = await database;
|
||||
EpisodeBrief episode;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.primaryColor, E.media_id, E.is_new, P.skip_seconds
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
where E.enclosure_url = ? ORDER BY E.milliseconds DESC LIMIT 3""",
|
||||
[url]);
|
||||
//Future<EpisodeBrief> getRssItemDownload(String url) async {
|
||||
// var dbClient = await database;
|
||||
// EpisodeBrief episode;
|
||||
// List<Map> list = await dbClient.rawQuery(
|
||||
// """SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
// E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
// E.downloaded, P.primaryColor, E.media_id, E.is_new, P.skip_seconds
|
||||
// FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
// where E.enclosure_url = ? ORDER BY E.milliseconds DESC LIMIT 3""",
|
||||
// [url]);
|
||||
|
||||
if (list != null)
|
||||
episode = EpisodeBrief(
|
||||
list.first['title'],
|
||||
list.first['enclosure_url'],
|
||||
list.first['enclosure_length'],
|
||||
list.first['milliseconds'],
|
||||
list.first['feed_title'],
|
||||
list.first['primaryColor'],
|
||||
list.first['liked'],
|
||||
list.first['downloaded'],
|
||||
list.first['duration'],
|
||||
list.first['explicit'],
|
||||
list.first['imagePath'],
|
||||
list.first['media_id'],
|
||||
list.first['is_new'],
|
||||
list.first['skip_seconds']);
|
||||
return episode;
|
||||
}
|
||||
// if (list != null)
|
||||
// episode = EpisodeBrief(
|
||||
// list.first['title'],
|
||||
// list.first['enclosure_url'],
|
||||
// list.first['enclosure_length'],
|
||||
// list.first['milliseconds'],
|
||||
// list.first['feed_title'],
|
||||
// list.first['primaryColor'],
|
||||
// list.first['liked'],
|
||||
// list.first['downloaded'],
|
||||
// list.first['duration'],
|
||||
// list.first['explicit'],
|
||||
// list.first['imagePath'],
|
||||
// list.first['media_id'],
|
||||
// list.first['is_new'],
|
||||
// list.first['skip_seconds']);
|
||||
// return episode;
|
||||
//}
|
||||
|
||||
Future<List<EpisodeBrief>> getRecentRssItem(int top) async {
|
||||
var dbClient = await database;
|
||||
|
@ -835,8 +835,8 @@ class DBHelper {
|
|||
// var dbClient = await database;
|
||||
// List<EpisodeBrief> episodes = [];
|
||||
// List<Map> list = await dbClient.rawQuery(
|
||||
// """SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
// E.milliseconds, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
// """SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
// E.milliseconds, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
// E.downloaded, P.imagePath, P.primaryColor, E.media_id, E.is_new, P.skip_seconds
|
||||
// FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
// WHERE is_new = 1 AND downloaded != 'ND' AND P.id = ?ORDER BY E.milliseconds DESC """,
|
||||
|
@ -861,6 +861,105 @@ class DBHelper {
|
|||
// }
|
||||
// return episodes;
|
||||
//}
|
||||
Future<List<EpisodeBrief>> getOutdatedEpisode(int days) async {
|
||||
var dbClient = await database;
|
||||
List<EpisodeBrief> episodes = [];
|
||||
if (days > 0) {
|
||||
int deadline =
|
||||
DateTime.now().subtract(Duration(days: days)).millisecondsSinceEpoch;
|
||||
List<Map> list = await dbClient
|
||||
.rawQuery("""SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
E.milliseconds, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imagePath, P.primaryColor, E.media_id, E.is_new, P.skip_seconds
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
WHERE E.download_date < ? AND E.enclosure_url != E.media_id
|
||||
ORDER BY E.milliseconds DESC""", [deadline]);
|
||||
for (int x = 0; x < list.length; x++) {
|
||||
episodes.add(EpisodeBrief(
|
||||
list[x]['title'],
|
||||
list[x]['enclosure_url'],
|
||||
list[x]['enclosure_length'],
|
||||
list[x]['milliseconds'],
|
||||
list[x]['feed_title'],
|
||||
list[x]['primaryColor'],
|
||||
list[x]['liked'],
|
||||
list[x]['downloaded'],
|
||||
list[x]['duration'],
|
||||
list[x]['explicit'],
|
||||
list[x]['imagePath'],
|
||||
list[x]['media_id'],
|
||||
list[x]['is_new'],
|
||||
list[x]['skip_seconds']));
|
||||
}
|
||||
}
|
||||
return episodes;
|
||||
}
|
||||
|
||||
Future<List<EpisodeBrief>> getDownloadedEpisode(int mode) async {
|
||||
var dbClient = await database;
|
||||
List<EpisodeBrief> episodes = [];
|
||||
List<Map> list;
|
||||
if (mode == 0)
|
||||
list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.download_date,
|
||||
E.milliseconds, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imagePath, P.primaryColor, E.media_id, E.is_new, P.skip_seconds
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
WHERE E.enclosure_url != E.media_id
|
||||
ORDER BY E.download_date DESC""",
|
||||
);
|
||||
else if (mode == 1)
|
||||
list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.download_date,
|
||||
E.milliseconds, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imagePath, P.primaryColor, E.media_id, E.is_new, P.skip_seconds
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
WHERE E.enclosure_url != E.media_id
|
||||
ORDER BY E.download_date ASC""",
|
||||
);
|
||||
else if (mode == 2)
|
||||
list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.download_date,
|
||||
E.milliseconds, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imagePath, P.primaryColor, E.media_id, E.is_new, P.skip_seconds
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
WHERE E.enclosure_url != E.media_id
|
||||
ORDER BY E.enclosure_length DESC""",
|
||||
);
|
||||
|
||||
for (int x = 0; x < list.length; x++) {
|
||||
int size;
|
||||
if (list[x]['enclosure_length'] == null ||
|
||||
list[x]['enclosure_length'] == 0) {
|
||||
String uri = list[x]['media_id'];
|
||||
FileStat fileStat = await File(uri.substring(6)).stat();
|
||||
size = fileStat.size;
|
||||
await dbClient.rawUpdate(
|
||||
"UPDATE Episodes SET enclosure_length = ?, WHERE media_id = ?",
|
||||
[size, uri]);
|
||||
} else
|
||||
size = list[x]['enclosure_length'];
|
||||
episodes.add(
|
||||
EpisodeBrief(
|
||||
list[x]['title'],
|
||||
list[x]['enclosure_url'],
|
||||
size,
|
||||
list[x]['milliseconds'],
|
||||
list[x]['feed_title'],
|
||||
list[x]['primaryColor'],
|
||||
list[x]['liked'],
|
||||
list[x]['downloaded'],
|
||||
list[x]['duration'],
|
||||
list[x]['explicit'],
|
||||
list[x]['imagePath'],
|
||||
list[x]['media_id'],
|
||||
list[x]['is_new'],
|
||||
list[x]['skip_seconds'],
|
||||
downloadDate: list[x]['download_date']),
|
||||
);
|
||||
}
|
||||
return episodes;
|
||||
}
|
||||
|
||||
Future<int> removeAllNewMark() async {
|
||||
var dbClient = await database;
|
||||
|
@ -995,9 +1094,9 @@ class DBHelper {
|
|||
|
||||
Future<bool> isDownloaded(String url) async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient
|
||||
.rawQuery("SELECT downloaded FROM Episodes WHERE enclosure_url = ?", [url]);
|
||||
return list.first['downloaded'] == 'ND' ? false: true;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"SELECT downloaded FROM Episodes WHERE enclosure_url = ?", [url]);
|
||||
return list.first['downloaded'] == 'ND' ? false : true;
|
||||
}
|
||||
|
||||
Future<int> saveDownloaded(String url, String id) async {
|
||||
|
|
|
@ -5,9 +5,12 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:line_icons/line_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import '../type/episodebrief.dart';
|
||||
import '../util/context_extension.dart';
|
||||
import '../state/download_state.dart';
|
||||
import '../local_storage/sqflite_localpodcast.dart';
|
||||
|
||||
class DownloadsManage extends StatefulWidget {
|
||||
|
@ -18,25 +21,23 @@ class DownloadsManage extends StatefulWidget {
|
|||
class _DownloadsManageState extends State<DownloadsManage> {
|
||||
//Downloaded size
|
||||
int _size;
|
||||
int _mode;
|
||||
//Downloaded files
|
||||
int _fileNum;
|
||||
bool _loadEpisodes;
|
||||
bool _clearing;
|
||||
bool _onlyListened;
|
||||
List<EpisodeBrief> _selectedList;
|
||||
List<EpisodeBrief> _episodes = [];
|
||||
|
||||
_getDownloadedRssItem() async {
|
||||
_episodes = [];
|
||||
final tasks = await FlutterDownloader.loadTasksWithRawQuery(
|
||||
query: "SELECT * FROM task WHERE status = 3");
|
||||
Future<List<EpisodeBrief>> _getDownloadedEpisode(int mode) async {
|
||||
List<EpisodeBrief> episodes = [];
|
||||
var dbHelper = DBHelper();
|
||||
await Future.forEach(tasks, (task) async {
|
||||
EpisodeBrief episode = await dbHelper.getRssItemWithUrl(task.url);
|
||||
_episodes.add(episode);
|
||||
});
|
||||
setState(() {
|
||||
_loadEpisodes = true;
|
||||
});
|
||||
episodes = await dbHelper.getDownloadedEpisode(mode);
|
||||
return episodes;
|
||||
}
|
||||
|
||||
Future<int> _isListened(EpisodeBrief episode) async {
|
||||
DBHelper dbHelper = DBHelper();
|
||||
return await dbHelper.isListened(episode.enclosureUrl);
|
||||
}
|
||||
|
||||
_getStorageSize() async {
|
||||
|
@ -58,12 +59,13 @@ class _DownloadsManageState extends State<DownloadsManage> {
|
|||
_delSelectedEpisodes() async {
|
||||
setState(() => _clearing = true);
|
||||
await Future.forEach(_selectedList, (EpisodeBrief episode) async {
|
||||
await FlutterDownloader.remove(
|
||||
taskId: episode.downloaded, shouldDeleteContent: true);
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.delDownloaded(episode.enclosureUrl);
|
||||
setState(() =>
|
||||
_episodes.removeWhere((e) => e.enclosureUrl == episode.enclosureUrl));
|
||||
var downloader = Provider.of<DownloadState>(context, listen: false);
|
||||
await downloader.removeTask(episode);
|
||||
// await FlutterDownloader.remove(
|
||||
// taskId: episode.downloaded, shouldDeleteContent: true);
|
||||
// var dbHelper = DBHelper();
|
||||
// await dbHelper.delDownloaded(episode.enclosureUrl);
|
||||
setState(() {});
|
||||
});
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
setState(() {
|
||||
|
@ -90,10 +92,10 @@ class _DownloadsManageState extends State<DownloadsManage> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
_clearing = false;
|
||||
_loadEpisodes = false;
|
||||
_selectedList = [];
|
||||
_mode = 0;
|
||||
_onlyListened = false;
|
||||
_getStorageSize();
|
||||
_getDownloadedRssItem();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -107,9 +109,8 @@ class _DownloadsManageState extends State<DownloadsManage> {
|
|||
),
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Downloads'),
|
||||
elevation: 0,
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
backgroundColor: context.primaryColor,
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
|
@ -119,125 +120,248 @@ class _DownloadsManageState extends State<DownloadsManage> {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
Container(
|
||||
height: 100.0,
|
||||
padding: EdgeInsets.only(bottom: 20, left: 60),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: 'Total ',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 20,
|
||||
height: 140.0,
|
||||
color: context.primaryColor,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: 'Total ',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 20,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: _fileNum.toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 40,
|
||||
)),
|
||||
),
|
||||
TextSpan(
|
||||
text: _fileNum < 2
|
||||
? ' episode'
|
||||
: ' episodes ',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 20,
|
||||
)),
|
||||
TextSpan(
|
||||
text: (_size ~/ 1000000).toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 50,
|
||||
)),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' Mb',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 20,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: _fileNum.toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 40,
|
||||
)),
|
||||
),
|
||||
TextSpan(
|
||||
text: _fileNum < 2 ? ' episode' : ' episodes ',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 20,
|
||||
)),
|
||||
TextSpan(
|
||||
text: (_size ~/ 1000000).toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 50,
|
||||
)),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' Mb',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 20,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
_loadEpisodes
|
||||
? Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: _episodes.length,
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemBuilder: (context, index) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
onTap: () {
|
||||
if (_selectedList
|
||||
.contains(_episodes[index])) {
|
||||
setState(() => _selectedList
|
||||
.removeWhere((episode) =>
|
||||
episode.enclosureUrl ==
|
||||
_episodes[index]
|
||||
.enclosureUrl));
|
||||
} else {
|
||||
setState(() => _selectedList
|
||||
.add(_episodes[index]));
|
||||
}
|
||||
},
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${_episodes[index].imagePath}")),
|
||||
),
|
||||
title: Text(
|
||||
_episodes[index].title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: _episodes[index]
|
||||
.enclosureLength !=
|
||||
0
|
||||
? Text(((_episodes[index]
|
||||
.enclosureLength) ~/
|
||||
1000000)
|
||||
.toString() +
|
||||
' Mb')
|
||||
: Center(),
|
||||
trailing: Checkbox(
|
||||
value: _selectedList
|
||||
.contains(_episodes[index]),
|
||||
onChanged: (bool boo) {
|
||||
if (boo) {
|
||||
setState(() => _selectedList
|
||||
.add(_episodes[index]));
|
||||
} else {
|
||||
setState(() => _selectedList
|
||||
.removeWhere((episode) =>
|
||||
episode.enclosureUrl ==
|
||||
_episodes[index]
|
||||
.enclosureUrl));
|
||||
}
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
child: Row(
|
||||
children: [
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: PopupMenuButton<int>(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10))),
|
||||
elevation: 1,
|
||||
tooltip: 'Sort By',
|
||||
child: Container(
|
||||
height: 40,
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text('Sory by'),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 5),
|
||||
),
|
||||
Icon(
|
||||
_mode == 0
|
||||
? LineIcons
|
||||
.hourglass_start_solid
|
||||
: _mode == 1
|
||||
? LineIcons
|
||||
.hourglass_half_solid
|
||||
: LineIcons.save,
|
||||
size: 18,
|
||||
)
|
||||
],
|
||||
)),
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
value: 0,
|
||||
child: Text('Newest first'),
|
||||
),
|
||||
Divider(
|
||||
height: 2,
|
||||
PopupMenuItem(
|
||||
value: 1,
|
||||
child: Text('Oldest first'),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 2,
|
||||
child: Text('Size'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
)
|
||||
: CircularProgressIndicator(),
|
||||
onSelected: (value) {
|
||||
if (value == 0)
|
||||
setState(() => _mode = 0);
|
||||
else if (value == 1)
|
||||
setState(() => _mode = 1);
|
||||
else if (value == 2)
|
||||
setState(() => _mode = 2);
|
||||
},
|
||||
),
|
||||
),
|
||||
//Spacer(),
|
||||
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => setState(() {
|
||||
_onlyListened = !_onlyListened;
|
||||
}),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 5),
|
||||
),
|
||||
Text('Listened Only'),
|
||||
Checkbox(
|
||||
value: _onlyListened,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_onlyListened = value;
|
||||
});
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: FutureBuilder<List<EpisodeBrief>>(
|
||||
future: _getDownloadedEpisode(_mode),
|
||||
initialData: [],
|
||||
builder: (context, snapshot) {
|
||||
var _episodes = snapshot.data;
|
||||
return ListView.builder(
|
||||
itemCount: _episodes.length,
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemBuilder: (context, index) {
|
||||
return FutureBuilder(
|
||||
future: _isListened(_episodes[index]),
|
||||
initialData: 0,
|
||||
builder: (context, snapshot) {
|
||||
return (_onlyListened &&
|
||||
snapshot.data > 0)
|
||||
? Center()
|
||||
: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
onTap: () {
|
||||
if (_selectedList.contains(
|
||||
_episodes[index])) {
|
||||
setState(() => _selectedList
|
||||
.removeWhere((episode) =>
|
||||
episode
|
||||
.enclosureUrl ==
|
||||
_episodes[index]
|
||||
.enclosureUrl));
|
||||
} else {
|
||||
setState(() => _selectedList
|
||||
.add(_episodes[index]));
|
||||
}
|
||||
},
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${_episodes[index].imagePath}")),
|
||||
),
|
||||
title: Text(
|
||||
_episodes[index].title,
|
||||
maxLines: 1,
|
||||
overflow:
|
||||
TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: Row(
|
||||
children: [
|
||||
Text(_episodes[index]
|
||||
.downloadDateToString()),
|
||||
SizedBox(width: 20),
|
||||
_episodes[index]
|
||||
.enclosureLength !=
|
||||
0
|
||||
? Text(((_episodes[index]
|
||||
.enclosureLength) ~/
|
||||
1000000)
|
||||
.toString() +
|
||||
' Mb')
|
||||
: SizedBox(
|
||||
width: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
trailing: Checkbox(
|
||||
value: _selectedList.contains(
|
||||
_episodes[index]),
|
||||
onChanged: (bool boo) {
|
||||
if (boo) {
|
||||
setState(() =>
|
||||
_selectedList.add(
|
||||
_episodes[
|
||||
index]));
|
||||
} else {
|
||||
setState(() => _selectedList
|
||||
.removeWhere((episode) =>
|
||||
episode
|
||||
.enclosureUrl ==
|
||||
_episodes[index]
|
||||
.enclosureUrl));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
height: 2,
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
AnimatedPositioned(
|
||||
duration: Duration(milliseconds: 800),
|
||||
curve: Curves.elasticInOut,
|
||||
left: MediaQuery.of(context).size.width / 2 - 50,
|
||||
left: context.width / 2 - 50,
|
||||
bottom: _selectedList.length == 0 ? -100 : 30,
|
||||
child: InkWell(
|
||||
onTap: () => _delSelectedEpisodes(),
|
||||
|
|
|
@ -300,14 +300,13 @@ class _PlayedHistoryState extends State<PlayedHistory>
|
|||
builder: (context, snapshot) {
|
||||
return snapshot.hasData
|
||||
? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
// shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: snapshot.data.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
bool _status = snapshot.data[index].status;
|
||||
return Container(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
padding: const EdgeInsets.symmetric(vertical: 5),
|
||||
color: context.scaffoldBackgroundColor,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
|
|
|
@ -180,7 +180,6 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
|||
text: 'Favorite tab', key: favLayoutKey),
|
||||
_setDefaultGridView(context,
|
||||
text: 'Downlaod tab', key: downloadLayoutKey),
|
||||
Divider(height: 2),
|
||||
]),
|
||||
Divider(height: 2)
|
||||
]),
|
||||
|
|
|
@ -21,7 +21,8 @@ List<Libries> google = [
|
|||
List<Libries> fonts = [
|
||||
Libries('Libre Baskerville', font,
|
||||
"https://fonts.google.com/specimen/Libre+Baskerville"),
|
||||
Libries('Teko', font, "https://fonts.google.com/specimen/Teko")
|
||||
Libries('Teko', font, "https://fonts.google.com/specimen/Teko"),
|
||||
Libries('Martel', font, "https://fonts.google.com/specimen/Martel")
|
||||
];
|
||||
|
||||
List<Libries> plugins = [
|
||||
|
@ -68,5 +69,6 @@ List<Libries> plugins = [
|
|||
Libries('Rxdart', apacheLicense, 'https://pub.dev/packages/rxdart'),
|
||||
Libries('flutter_isolate', mit, 'https://pub.dev/packages/flutter_isolate'),
|
||||
Libries('auto_animated', mit, 'https://pub.dev/packages/auto_animated'),
|
||||
Libries('wc_flutter_share', apacheLicense, 'https://pub.dev/packages/wc_flutter_share')
|
||||
Libries('wc_flutter_share', apacheLicense,
|
||||
'https://pub.dev/packages/wc_flutter_share')
|
||||
];
|
||||
|
|
|
@ -39,6 +39,21 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
|
|||
leading: icon,
|
||||
title: Text(text),
|
||||
subtitle: Text(description),
|
||||
onTap: e == 0
|
||||
? null
|
||||
: () {
|
||||
if (e >= 10) {
|
||||
int index = menu.indexOf(e);
|
||||
menu.remove(e);
|
||||
menu.insert(index, e - 10);
|
||||
_saveEpisodeMene(menu);
|
||||
} else if (e < 10) {
|
||||
int index = menu.indexOf(e);
|
||||
menu.remove(e);
|
||||
menu.insert(index, e + 10);
|
||||
_saveEpisodeMene(menu);
|
||||
}
|
||||
},
|
||||
trailing: Checkbox(
|
||||
value: e < 10,
|
||||
onChanged: e == 0
|
||||
|
@ -131,11 +146,8 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
|
|||
break;
|
||||
case 2:
|
||||
return _popupMenuItem(menu, e,
|
||||
icon: Icon(
|
||||
LineIcons.heart,
|
||||
color: Colors.red,
|
||||
size: 21
|
||||
),
|
||||
icon: Icon(LineIcons.heart,
|
||||
color: Colors.red, size: 21),
|
||||
text: 'Like',
|
||||
description: 'Add episode to favorite');
|
||||
break;
|
||||
|
|
|
@ -179,12 +179,6 @@ class _SettingsState extends State<Settings>
|
|||
leading: Icon(LineIcons.play_circle),
|
||||
title: Text('Play'),
|
||||
subtitle: Text('Playlist and player'),
|
||||
// trailing: Selector<AudioPlayerNotifier, bool>(
|
||||
// selector: (_, audio) => audio.autoPlay,
|
||||
// builder: (_, data, __) => Switch(
|
||||
// value: data,
|
||||
// onChanged: (boo) => audio.autoPlaySwitch = boo),
|
||||
// ),
|
||||
),
|
||||
Divider(height: 2),
|
||||
ListTile(
|
||||
|
|
|
@ -30,11 +30,6 @@ class _StorageSettingState extends State<StorageSetting>
|
|||
setState(() => _value = _animation.value);
|
||||
});
|
||||
_controller.forward();
|
||||
// _controller.addStatusListener((status) {
|
||||
// if (status == AnimationStatus.completed) {
|
||||
// _controller.reset();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +39,22 @@ class _StorageSettingState extends State<StorageSetting>
|
|||
return value != 0;
|
||||
}
|
||||
|
||||
Future<int> _getAutoDeleteDays() async {
|
||||
KeyValueStorage storage = KeyValueStorage(autoDeleteKey);
|
||||
int days = await storage.getInt();
|
||||
if (days == 0) {
|
||||
storage.saveInt(30);
|
||||
return 30;
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
_setAutoDeleteDays(int days) async {
|
||||
KeyValueStorage storage = KeyValueStorage(autoDeleteKey);
|
||||
await storage.saveInt(days);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
_setAudtDownloadNetwork(bool boo) async {
|
||||
KeyValueStorage storage = KeyValueStorage(autoDownloadNetworkKey);
|
||||
await storage.saveInt(boo ? 1 : 0);
|
||||
|
@ -186,10 +197,41 @@ class _StorageSettingState extends State<StorageSetting>
|
|||
subtitle: Text('Manage downloaded audio files'),
|
||||
),
|
||||
Divider(height: 2),
|
||||
FutureBuilder<int>(
|
||||
future: _getAutoDeleteDays(),
|
||||
initialData: 30,
|
||||
builder: (context, snapshot) {
|
||||
return ListTile(
|
||||
contentPadding:
|
||||
EdgeInsets.only(left: 80.0, right: 20),
|
||||
title: Text('Auto delete downloads after'),
|
||||
subtitle: Text('Default 30 days.'),
|
||||
trailing: DropdownButton(
|
||||
hint: snapshot.data == -1
|
||||
? Text('Never')
|
||||
: Text(snapshot.data.toString() + 'days'),
|
||||
underline: Center(),
|
||||
elevation: 1,
|
||||
value: snapshot.data,
|
||||
onChanged: (value) async {
|
||||
await _setAutoDeleteDays(value);
|
||||
},
|
||||
items: <int>[-1, 10, 30]
|
||||
.map<DropdownMenuItem<int>>((e) {
|
||||
return DropdownMenuItem<int>(
|
||||
value: e,
|
||||
child: e == -1
|
||||
? Text('Never')
|
||||
: Text(e.toString() + ' days'));
|
||||
}).toList()),
|
||||
);
|
||||
},
|
||||
),
|
||||
Divider(height: 2),
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 80.0, right: 25),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text('Cache'),
|
||||
title: Text('Audio cache'),
|
||||
subtitle: Text('Audio cache max size'),
|
||||
trailing: Text.rich(TextSpan(
|
||||
text: '${(_value ~/ 100) * 100}',
|
||||
|
|
|
@ -4,10 +4,10 @@ import 'dart:ui';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:tsacdop/local_storage/key_value_storage.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
|
||||
import '../type/episodebrief.dart';
|
||||
|
@ -37,6 +37,10 @@ class DownloadState extends ChangeNotifier {
|
|||
List<EpisodeTask> _episodeTasks = [];
|
||||
List<EpisodeTask> get episodeTasks => _episodeTasks;
|
||||
|
||||
DownloadState() {
|
||||
_autoDelete();
|
||||
}
|
||||
|
||||
@override
|
||||
void addListener(VoidCallback listener) async {
|
||||
_loadTasks();
|
||||
|
@ -55,7 +59,6 @@ class DownloadState extends ChangeNotifier {
|
|||
_episodeTasks.add(EpisodeTask(episode, task.taskId,
|
||||
progress: task.progress, status: task.status));
|
||||
});
|
||||
print(_episodeTasks.length);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
@ -205,4 +208,19 @@ class DownloadState extends ChangeNotifier {
|
|||
_episodeTasks.removeWhere(
|
||||
(element) => element.episode.enclosureUrl == episode.enclosureUrl);
|
||||
}
|
||||
|
||||
_autoDelete() async {
|
||||
print('Start auto delete outdated episodes');
|
||||
KeyValueStorage autoDeleteStorage = KeyValueStorage(autoDeleteKey);
|
||||
int autoDelete = await autoDeleteStorage.getInt();
|
||||
if (autoDelete == 0)
|
||||
await autoDeleteStorage.saveInt(30);
|
||||
else if (autoDelete > 0) {
|
||||
List<EpisodeBrief> episodes =
|
||||
await dbHelper.getOutdatedEpisode(autoDelete);
|
||||
if (episodes.length > 0) {
|
||||
await Future.forEach(episodes, (episode) => delTask(episode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:audio_service/audio_service.dart';
|
|||
|
||||
class EpisodeBrief {
|
||||
final String title;
|
||||
String description;
|
||||
final String description;
|
||||
final int pubDate;
|
||||
final int enclosureLength;
|
||||
final String enclosureUrl;
|
||||
|
@ -17,6 +17,7 @@ class EpisodeBrief {
|
|||
final String mediaId;
|
||||
final int isNew;
|
||||
final int skipSeconds;
|
||||
final int downloadDate;
|
||||
EpisodeBrief(
|
||||
this.title,
|
||||
this.enclosureUrl,
|
||||
|
@ -31,7 +32,10 @@ class EpisodeBrief {
|
|||
this.imagePath,
|
||||
this.mediaId,
|
||||
this.isNew,
|
||||
this.skipSeconds);
|
||||
this.skipSeconds,
|
||||
{this.description = '',
|
||||
this.downloadDate = 0})
|
||||
: assert(enclosureUrl != null);
|
||||
|
||||
String dateToString() {
|
||||
DateTime date = DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true);
|
||||
|
@ -50,6 +54,23 @@ class EpisodeBrief {
|
|||
}
|
||||
}
|
||||
|
||||
String downloadDateToString() {
|
||||
DateTime date = DateTime.fromMillisecondsSinceEpoch(downloadDate);
|
||||
var diffrence = DateTime.now().toUtc().difference(date);
|
||||
if (diffrence.inHours < 1) {
|
||||
return '1 hour ago';
|
||||
} else if (diffrence.inHours < 24) {
|
||||
return '${diffrence.inHours} hours ago';
|
||||
} else if (diffrence.inHours == 24) {
|
||||
return '1 day ago';
|
||||
} else if (diffrence.inDays < 7) {
|
||||
return '${diffrence.inDays} days ago';
|
||||
} else {
|
||||
return DateFormat.yMMMd().format(
|
||||
DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true).toLocal());
|
||||
}
|
||||
}
|
||||
|
||||
MediaItem toMediaItem() {
|
||||
return MediaItem(
|
||||
id: mediaId,
|
||||
|
|
|
@ -3,7 +3,7 @@ class PodcastLocal {
|
|||
final String imageUrl;
|
||||
final String rssUrl;
|
||||
final String author;
|
||||
|
||||
|
||||
final String primaryColor;
|
||||
final String id;
|
||||
final String imagePath;
|
||||
|
@ -13,20 +13,16 @@ class PodcastLocal {
|
|||
final String description;
|
||||
int upateCount;
|
||||
int episodeCount;
|
||||
PodcastLocal(
|
||||
this.title,
|
||||
this.imageUrl,
|
||||
this.rssUrl,
|
||||
this.primaryColor,
|
||||
this.author,
|
||||
this.id,
|
||||
this.imagePath,
|
||||
this.provider,
|
||||
this.link,
|
||||
{
|
||||
this.description ='',
|
||||
this.upateCount = 0,
|
||||
this.episodeCount = 0
|
||||
}
|
||||
);
|
||||
PodcastLocal(this.title, this.imageUrl, this.rssUrl, this.primaryColor,
|
||||
this.author, this.id, this.imagePath, this.provider, this.link,
|
||||
{this.description = '', this.upateCount = 0, this.episodeCount = 0})
|
||||
: assert(rssUrl != null);
|
||||
@override
|
||||
bool operator ==(Object podcastLocal) =>
|
||||
podcastLocal is PodcastLocal &&
|
||||
podcastLocal.rssUrl == rssUrl &&
|
||||
podcastLocal.id == id;
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode + rssUrl.hashCode;
|
||||
}
|
||||
|
|
|
@ -118,36 +118,37 @@ class EpisodeGrid extends StatelessWidget {
|
|||
|
||||
Widget _listenIndicater(BuildContext context,
|
||||
{EpisodeBrief episode, int isListened}) =>
|
||||
Selector<AudioPlayerNotifier, Tuple2<EpisodeBrief, bool>>(
|
||||
selector: (_, audio) => Tuple2(audio.episode, audio.playerRunning),
|
||||
builder: (_, data, __) {
|
||||
return (episode.enclosureUrl == data.item1?.enclosureUrl &&
|
||||
data.item2)
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: WaveLoader(color: context.accentColor))
|
||||
: layout != Layout.three && isListened > 0
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets.symmetric(horizontal: 2),
|
||||
padding: EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: context.accentColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter: ListenedAllPainter(
|
||||
Colors.white,
|
||||
)),
|
||||
)
|
||||
: Center();
|
||||
});
|
||||
Center();
|
||||
// Selector<AudioPlayerNotifier, Tuple2<EpisodeBrief, bool>>(
|
||||
// selector: (_, audio) => Tuple2(audio.episode, audio.playerRunning),
|
||||
// builder: (_, data, __) {
|
||||
// return (episode.enclosureUrl == data.item1?.enclosureUrl &&
|
||||
// data.item2)
|
||||
// ? Container(
|
||||
// height: 20,
|
||||
// width: 20,
|
||||
// margin: EdgeInsets.symmetric(horizontal: 2),
|
||||
// decoration: BoxDecoration(
|
||||
// shape: BoxShape.circle,
|
||||
// ),
|
||||
// child: WaveLoader(color: context.accentColor))
|
||||
// : layout != Layout.three && isListened > 0
|
||||
// ? Container(
|
||||
// height: 20,
|
||||
// width: 20,
|
||||
// margin: EdgeInsets.symmetric(horizontal: 2),
|
||||
// padding: EdgeInsets.all(2),
|
||||
// decoration: BoxDecoration(
|
||||
// color: context.accentColor,
|
||||
// shape: BoxShape.circle,
|
||||
// ),
|
||||
// child: CustomPaint(
|
||||
// painter: ListenedAllPainter(
|
||||
// Colors.white,
|
||||
// )),
|
||||
// )
|
||||
// : Center();
|
||||
// });
|
||||
|
||||
Widget _downloadIndicater(BuildContext context, {EpisodeBrief episode}) =>
|
||||
showDownload || layout != Layout.three
|
||||
|
@ -294,7 +295,7 @@ class EpisodeGrid extends StatelessWidget {
|
|||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
isListened > 0.95
|
||||
isListened > 0
|
||||
? Text('Listened',
|
||||
style: TextStyle(
|
||||
color: context.textColor.withOpacity(0.5)))
|
||||
|
@ -359,7 +360,7 @@ class EpisodeGrid extends StatelessWidget {
|
|||
}
|
||||
break;
|
||||
case 3:
|
||||
if (isListened < 0.95) {
|
||||
if (isListened < 1) {
|
||||
await _markListened(episode);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
|
@ -368,7 +369,6 @@ class EpisodeGrid extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (!isDownload) downloader.startTask(episode);
|
||||
break;
|
||||
|
@ -428,7 +428,7 @@ class EpisodeGrid extends StatelessWidget {
|
|||
BorderRadius.all(Radius.circular(5.0)),
|
||||
color: snapshot.data > 0
|
||||
? context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
? Colors.grey[200]
|
||||
: Color.fromRGBO(40, 40, 40, 1)
|
||||
: context.scaffoldBackgroundColor,
|
||||
boxShadow: [
|
||||
|
@ -488,9 +488,9 @@ class EpisodeGrid extends StatelessWidget {
|
|||
episode: episodes[index],
|
||||
color: _c),
|
||||
Spacer(),
|
||||
_listenIndicater(context,
|
||||
episode: episodes[index],
|
||||
isListened: snapshot.data),
|
||||
// _listenIndicater(context,
|
||||
// episode: episodes[index],
|
||||
// isListened: snapshot.data),
|
||||
_downloadIndicater(context,
|
||||
episode: episodes[index]),
|
||||
_isNewIndicator(episodes[index]),
|
||||
|
|
Loading…
Reference in New Issue