mirror of
https://github.com/stonega/tsacdop
synced 2025-02-18 04:20:37 +01:00
Minor change.
This commit is contained in:
parent
be00383966
commit
5a32511ac9
@ -422,19 +422,19 @@ class __MenuBarState extends State<_MenuBar> {
|
||||
return await dbHelper.isListened(episode.enclosureUrl);
|
||||
}
|
||||
|
||||
_saveLiked(String url) async {
|
||||
Future<void> _saveLiked(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.setLiked(url);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
_setUnliked(String url) async {
|
||||
Future<void> _setUnliked(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.setUniked(url);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
_markListened(EpisodeBrief episode) async {
|
||||
Future<void> _markListened(EpisodeBrief episode) async {
|
||||
var dbHelper = DBHelper();
|
||||
//var marked = await dbHelper.checkMarked(episode);
|
||||
//if (!marked) {
|
||||
@ -444,7 +444,7 @@ class __MenuBarState extends State<_MenuBar> {
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
_markNotListened(String url) async {
|
||||
Future<void> _markNotListened(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.markNotListened(url);
|
||||
if (mounted) setState(() {});
|
||||
@ -554,8 +554,9 @@ class __MenuBarState extends State<_MenuBar> {
|
||||
selector: (_, audio) =>
|
||||
Tuple2(audio.queue.playlist, audio.queueUpdate),
|
||||
builder: (_, data, __) {
|
||||
return (data.item1.contains(widget.episodeItem) &&
|
||||
!widget.hide)
|
||||
final inPlaylist =
|
||||
data.item1.contains(widget.episodeItem);
|
||||
return inPlaylist
|
||||
? _buttonOnMenu(
|
||||
child: Icon(Icons.playlist_add_check,
|
||||
color: context.accentColor),
|
||||
@ -673,7 +674,7 @@ class _ShowNote extends StatelessWidget {
|
||||
const _ShowNote({this.episode, Key key}) : super(key: key);
|
||||
|
||||
int _getTimeStamp(String url) {
|
||||
final time = url.substring(7);
|
||||
final time = url.substring(3).trim();
|
||||
final data = time.split(':');
|
||||
var seconds;
|
||||
if (data.length == 3) {
|
||||
@ -726,7 +727,7 @@ class _ShowNote extends StatelessWidget {
|
||||
? Selector<AudioPlayerNotifier, EpisodeBrief>(
|
||||
selector: (_, audio) => audio.episode,
|
||||
builder: (_, data, __) {
|
||||
if (data == episode) {
|
||||
if (data == episode && !description.contains('#t=')) {
|
||||
final linkList = linkify(description,
|
||||
options: LinkifyOptions(humanize: false),
|
||||
linkifiers: [TimeStampLinkifier()]);
|
||||
@ -734,7 +735,7 @@ class _ShowNote extends StatelessWidget {
|
||||
if (element is TimeStampElement) {
|
||||
final time = element.timeStamp;
|
||||
description = description.replaceFirst(time,
|
||||
'<a rel="nofollow" href = "skipto:$time">$time</a>');
|
||||
'<a rel="nofollow" href = "#t=$time">$time</a>');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -751,9 +752,11 @@ class _ShowNote extends StatelessWidget {
|
||||
color: context.accentColor,
|
||||
textBaseline: TextBaseline.ideographic),
|
||||
onLinkTap: (url) {
|
||||
if (url.substring(0, 6) == 'skipto') {
|
||||
if (url.substring(0, 3) == '#t=') {
|
||||
final seconds = _getTimeStamp(url);
|
||||
audio.seekTo(seconds * 1000);
|
||||
if (data == episode) {
|
||||
audio.seekTo(seconds * 1000);
|
||||
}
|
||||
} else {
|
||||
url.launchUrl;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import '../local_storage/sqflite_localpodcast.dart';
|
||||
import '../state/audio_state.dart';
|
||||
import '../state/download_state.dart';
|
||||
import '../state/podcast_group.dart';
|
||||
import '../state/refresh_podcast.dart';
|
||||
import '../state/setting_state.dart';
|
||||
import '../type/episodebrief.dart';
|
||||
import '../type/playlist.dart';
|
||||
@ -790,253 +791,259 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
||||
super.build(context);
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
final s = context.s;
|
||||
return Selector<GroupList, bool>(
|
||||
selector: (_, worker) => worker.created,
|
||||
builder: (context, created, child) {
|
||||
return FutureBuilder<List<EpisodeBrief>>(
|
||||
future: _getRssItem(_top, _group),
|
||||
builder: (context, snapshot) {
|
||||
return (snapshot.hasData)
|
||||
? snapshot.data.length == 0
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 150),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Icon(LineIcons.cloud_download_alt_solid,
|
||||
size: 80, color: Colors.grey[500]),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10)),
|
||||
Text(
|
||||
s.noEpisodeRecent,
|
||||
style: TextStyle(color: Colors.grey[500]),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: NotificationListener<ScrollNotification>(
|
||||
onNotification: (scrollInfo) {
|
||||
if (scrollInfo is ScrollStartNotification &&
|
||||
mounted &&
|
||||
!_scroll) {
|
||||
setState(() => _scroll = true);
|
||||
}
|
||||
if (scrollInfo.metrics.pixels ==
|
||||
scrollInfo.metrics.maxScrollExtent &&
|
||||
snapshot.data.length == _top) {
|
||||
if (!_loadMore) {
|
||||
_loadMoreEpisode();
|
||||
return Selector<RefreshWorker, bool>(
|
||||
selector: (_, worker) => worker.complete,
|
||||
builder: (_, complete, __) => Selector<GroupList, bool>(
|
||||
selector: (_, worker) => worker.created,
|
||||
builder: (context, created, child) {
|
||||
return FutureBuilder<List<EpisodeBrief>>(
|
||||
future: _getRssItem(_top, _group),
|
||||
builder: (context, snapshot) {
|
||||
return (snapshot.hasData)
|
||||
? snapshot.data.length == 0
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 150),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Icon(LineIcons.cloud_download_alt_solid,
|
||||
size: 80, color: Colors.grey[500]),
|
||||
Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 10)),
|
||||
Text(
|
||||
s.noEpisodeRecent,
|
||||
style: TextStyle(color: Colors.grey[500]),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: NotificationListener<ScrollNotification>(
|
||||
onNotification: (scrollInfo) {
|
||||
if (scrollInfo is ScrollStartNotification &&
|
||||
mounted &&
|
||||
!_scroll) {
|
||||
setState(() => _scroll = true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
child: CustomScrollView(
|
||||
key: PageStorageKey<String>('update'),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: <Widget>[
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 40,
|
||||
color: context.primaryColor,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Consumer<GroupList>(
|
||||
builder:
|
||||
(context, groupList, child) =>
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: PopupMenuButton<String>(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(
|
||||
Radius.circular(
|
||||
10))),
|
||||
elevation: 1,
|
||||
tooltip: s.groupFilter,
|
||||
child: Container(
|
||||
padding:
|
||||
EdgeInsets.symmetric(
|
||||
horizontal: 20),
|
||||
height: 50,
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(_groupName ==
|
||||
'All'
|
||||
? s.all
|
||||
: _groupName),
|
||||
Padding(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
horizontal:
|
||||
5),
|
||||
),
|
||||
Icon(
|
||||
LineIcons
|
||||
.filter_solid,
|
||||
size: 18,
|
||||
)
|
||||
],
|
||||
)),
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
child: Row(children: [
|
||||
Text(s.all),
|
||||
Spacer(),
|
||||
if (_groupName ==
|
||||
'All')
|
||||
DotIndicator()
|
||||
]),
|
||||
value: 'All')
|
||||
]..addAll(groupList.groups
|
||||
.map<
|
||||
PopupMenuEntry<
|
||||
String>>(
|
||||
(e) => PopupMenuItem(
|
||||
value: e.name,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(e.name),
|
||||
Spacer(),
|
||||
if (e.name ==
|
||||
_groupName)
|
||||
DotIndicator()
|
||||
],
|
||||
)))
|
||||
.toList()),
|
||||
onSelected: (value) {
|
||||
if (value == 'All') {
|
||||
setState(() {
|
||||
_groupName = 'All';
|
||||
_group = ['All'];
|
||||
});
|
||||
} else {
|
||||
for (var group
|
||||
in groupList.groups) {
|
||||
if (group.name ==
|
||||
value) {
|
||||
setState(() {
|
||||
_groupName = value;
|
||||
_group = group
|
||||
.podcastList;
|
||||
});
|
||||
if (scrollInfo.metrics.pixels ==
|
||||
scrollInfo.metrics.maxScrollExtent &&
|
||||
snapshot.data.length == _top) {
|
||||
if (!_loadMore) {
|
||||
_loadMoreEpisode();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
child: CustomScrollView(
|
||||
key: PageStorageKey<String>('update'),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: <Widget>[
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 40,
|
||||
color: context.primaryColor,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Consumer<GroupList>(
|
||||
builder: (context, groupList,
|
||||
child) =>
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child:
|
||||
PopupMenuButton<String>(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(
|
||||
Radius.circular(
|
||||
10))),
|
||||
elevation: 1,
|
||||
tooltip: s.groupFilter,
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
horizontal: 20),
|
||||
height: 50,
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(_groupName ==
|
||||
'All'
|
||||
? s.all
|
||||
: _groupName),
|
||||
Padding(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
horizontal:
|
||||
5),
|
||||
),
|
||||
Icon(
|
||||
LineIcons
|
||||
.filter_solid,
|
||||
size: 18,
|
||||
)
|
||||
],
|
||||
)),
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
child: Row(children: [
|
||||
Text(s.all),
|
||||
Spacer(),
|
||||
if (_groupName ==
|
||||
'All')
|
||||
DotIndicator()
|
||||
]),
|
||||
value: 'All')
|
||||
]..addAll(groupList.groups
|
||||
.map<
|
||||
PopupMenuEntry<
|
||||
String>>((e) =>
|
||||
PopupMenuItem(
|
||||
value: e.name,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
e.name),
|
||||
Spacer(),
|
||||
if (e.name ==
|
||||
_groupName)
|
||||
DotIndicator()
|
||||
],
|
||||
)))
|
||||
.toList()),
|
||||
onSelected: (value) {
|
||||
if (value == 'All') {
|
||||
setState(() {
|
||||
_groupName = 'All';
|
||||
_group = ['All'];
|
||||
});
|
||||
} else {
|
||||
for (var group
|
||||
in groupList
|
||||
.groups) {
|
||||
if (group.name ==
|
||||
value) {
|
||||
setState(() {
|
||||
_groupName =
|
||||
value;
|
||||
_group = group
|
||||
.podcastList;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
FutureBuilder<int>(
|
||||
future:
|
||||
_getUpdateCounts(_group),
|
||||
initialData: 0,
|
||||
builder: (context, snapshot) {
|
||||
return snapshot.data != 0
|
||||
? Material(
|
||||
color: Colors
|
||||
.transparent,
|
||||
child: IconButton(
|
||||
tooltip: s
|
||||
.addNewEpisodeTooltip,
|
||||
icon: SizedBox(
|
||||
height: 16,
|
||||
width: 21,
|
||||
child: CustomPaint(
|
||||
painter: AddToPlaylistPainter(
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color,
|
||||
Colors
|
||||
.red))),
|
||||
onPressed:
|
||||
() async {
|
||||
await audio
|
||||
.addNewEpisode(
|
||||
_group);
|
||||
if (mounted) {
|
||||
setState(
|
||||
() {});
|
||||
}
|
||||
Fluttertoast
|
||||
.showToast(
|
||||
msg: _groupName ==
|
||||
'All'
|
||||
? s.addNewEpisodeAll(
|
||||
snapshot
|
||||
.data)
|
||||
: s.addEpisodeGroup(
|
||||
_groupName,
|
||||
snapshot
|
||||
.data),
|
||||
gravity:
|
||||
ToastGravity
|
||||
.BOTTOM,
|
||||
);
|
||||
}),
|
||||
)
|
||||
: Material(
|
||||
color: Colors
|
||||
.transparent,
|
||||
child: IconButton(
|
||||
tooltip: s
|
||||
.addNewEpisodeTooltip,
|
||||
icon: SizedBox(
|
||||
height: 16,
|
||||
width: 21,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter:
|
||||
AddToPlaylistPainter(
|
||||
context
|
||||
.textColor,
|
||||
context
|
||||
.textColor,
|
||||
))),
|
||||
onPressed: () {}),
|
||||
);
|
||||
}),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: LayoutButton(
|
||||
layout: _layout,
|
||||
onPressed: (layout) =>
|
||||
setState(() {
|
||||
_layout = layout;
|
||||
}),
|
||||
Spacer(),
|
||||
FutureBuilder<int>(
|
||||
future:
|
||||
_getUpdateCounts(_group),
|
||||
initialData: 0,
|
||||
builder: (context, snapshot) {
|
||||
return snapshot.data != 0
|
||||
? Material(
|
||||
color: Colors
|
||||
.transparent,
|
||||
child: IconButton(
|
||||
tooltip: s
|
||||
.addNewEpisodeTooltip,
|
||||
icon: SizedBox(
|
||||
height: 16,
|
||||
width: 21,
|
||||
child: CustomPaint(
|
||||
painter: AddToPlaylistPainter(
|
||||
context
|
||||
.textTheme.bodyText1.color,
|
||||
Colors
|
||||
.red))),
|
||||
onPressed:
|
||||
() async {
|
||||
await audio
|
||||
.addNewEpisode(
|
||||
_group);
|
||||
if (mounted) {
|
||||
setState(
|
||||
() {});
|
||||
}
|
||||
Fluttertoast
|
||||
.showToast(
|
||||
msg: _groupName ==
|
||||
'All'
|
||||
? s.addNewEpisodeAll(snapshot
|
||||
.data)
|
||||
: s.addEpisodeGroup(
|
||||
_groupName,
|
||||
snapshot.data),
|
||||
gravity:
|
||||
ToastGravity
|
||||
.BOTTOM,
|
||||
);
|
||||
}),
|
||||
)
|
||||
: Material(
|
||||
color: Colors
|
||||
.transparent,
|
||||
child: IconButton(
|
||||
tooltip: s
|
||||
.addNewEpisodeTooltip,
|
||||
icon: SizedBox(
|
||||
height: 16,
|
||||
width: 21,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter:
|
||||
AddToPlaylistPainter(
|
||||
context
|
||||
.textColor,
|
||||
context
|
||||
.textColor,
|
||||
))),
|
||||
onPressed:
|
||||
() {}),
|
||||
);
|
||||
}),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: LayoutButton(
|
||||
layout: _layout,
|
||||
onPressed: (layout) =>
|
||||
setState(() {
|
||||
_layout = layout;
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
EpisodeGrid(
|
||||
episodes: snapshot.data,
|
||||
layout: _layout,
|
||||
initNum: _scroll ? 0 : 12,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return _loadMore
|
||||
? Container(
|
||||
height: 2,
|
||||
child: LinearProgressIndicator())
|
||||
: Center();
|
||||
},
|
||||
childCount: 1,
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
]))
|
||||
: Center();
|
||||
},
|
||||
);
|
||||
});
|
||||
EpisodeGrid(
|
||||
episodes: snapshot.data,
|
||||
layout: _layout,
|
||||
initNum: _scroll ? 0 : 12,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return _loadMore
|
||||
? Container(
|
||||
height: 2,
|
||||
child:
|
||||
LinearProgressIndicator())
|
||||
: Center();
|
||||
},
|
||||
childCount: 1,
|
||||
),
|
||||
),
|
||||
]))
|
||||
: Center();
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -48,7 +49,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||
super.initState();
|
||||
_groupIndex = 0;
|
||||
_controller =
|
||||
AnimationController(vsync: this, duration: Duration(milliseconds: 125))
|
||||
AnimationController(vsync: this, duration: Duration(milliseconds: 150))
|
||||
..addListener(() {
|
||||
if (mounted) setState(() {});
|
||||
})
|
||||
@ -64,7 +65,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<int> getPodcastUpdateCounts(String id) async {
|
||||
Future<int> _getPodcastUpdateCounts(String id) async {
|
||||
var dbHelper = DBHelper();
|
||||
return await dbHelper.getPodcastUpdateCounts(id);
|
||||
}
|
||||
@ -79,7 +80,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var _width = MediaQuery.of(context).size.width;
|
||||
var width = MediaQuery.of(context).size.width;
|
||||
final s = context.s;
|
||||
return Selector<GroupList, Tuple3<List<PodcastGroup>, bool, bool>>(
|
||||
selector: (_, groupList) =>
|
||||
@ -90,11 +91,11 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||
var isLoading = data.item3;
|
||||
return isLoading
|
||||
? Container(
|
||||
height: (_width - 20) / 3 + 140,
|
||||
height: (width - 20) / 3 + 140,
|
||||
)
|
||||
: groups[_groupIndex].podcastList.length == 0
|
||||
? Container(
|
||||
height: (_width - 20) / 3 + 140,
|
||||
height: (width - 20) / 3 + 140,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -195,7 +196,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||
],
|
||||
)),
|
||||
Container(
|
||||
height: (_width - 20) / 3 + 40,
|
||||
height: (width - 20) / 3 + 40,
|
||||
color: context.primaryColor,
|
||||
margin: EdgeInsets.symmetric(horizontal: 15),
|
||||
child: Center(
|
||||
@ -334,7 +335,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||
),
|
||||
Container(
|
||||
height: 70,
|
||||
width: _width,
|
||||
width: width,
|
||||
alignment: Alignment.centerLeft,
|
||||
color: context.scaffoldBackgroundColor,
|
||||
child: TabBar(
|
||||
@ -358,49 +359,41 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||
_slideTween
|
||||
.animate(_controller)
|
||||
.value),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(25.0)),
|
||||
child: LimitedBox(
|
||||
maxHeight: 50,
|
||||
maxWidth: 50,
|
||||
child: CircleAvatar(
|
||||
backgroundColor:
|
||||
color.withOpacity(0.5),
|
||||
backgroundImage:
|
||||
podcastLocal.avatarImage,
|
||||
child: FutureBuilder<int>(
|
||||
future:
|
||||
getPodcastUpdateCounts(
|
||||
podcastLocal.id),
|
||||
initialData: 0,
|
||||
builder: (context, snapshot) {
|
||||
return snapshot.data > 0
|
||||
? Align(
|
||||
child: LimitedBox(
|
||||
maxHeight: 50,
|
||||
maxWidth: 50,
|
||||
child: CircleAvatar(
|
||||
backgroundColor:
|
||||
color.withOpacity(0.5),
|
||||
backgroundImage:
|
||||
podcastLocal.avatarImage,
|
||||
child: FutureBuilder<int>(
|
||||
future: _getPodcastUpdateCounts(
|
||||
podcastLocal.id),
|
||||
initialData: 0,
|
||||
builder: (context, snapshot) {
|
||||
return snapshot.data > 0
|
||||
? Align(
|
||||
alignment: Alignment
|
||||
.bottomRight,
|
||||
child: Container(
|
||||
alignment: Alignment
|
||||
.bottomCenter,
|
||||
child: Container(
|
||||
alignment:
|
||||
Alignment
|
||||
.center,
|
||||
height: 10,
|
||||
width: 40,
|
||||
color: Colors
|
||||
.black54,
|
||||
child: Text('New',
|
||||
style: TextStyle(
|
||||
color: Colors
|
||||
.red,
|
||||
fontSize:
|
||||
8,
|
||||
fontStyle:
|
||||
FontStyle
|
||||
.italic)),
|
||||
),
|
||||
)
|
||||
: Center();
|
||||
}),
|
||||
),
|
||||
.center,
|
||||
height: 10,
|
||||
width: 10,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Colors.red,
|
||||
border: Border.all(
|
||||
color: context
|
||||
.primaryColor,
|
||||
width: 2),
|
||||
shape: BoxShape
|
||||
.circle),
|
||||
),
|
||||
)
|
||||
: Center();
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -412,10 +405,10 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: (_width - 20) / 3 + 40,
|
||||
margin: EdgeInsets.only(left: 10, right: 10),
|
||||
height: (width - 20) / 3 + 40,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
color: context.scaffoldBackgroundColor,
|
||||
),
|
||||
child: ScrollConfiguration(
|
||||
behavior: NoGrowBehavior(),
|
||||
@ -474,8 +467,8 @@ class PodcastPreview extends StatelessWidget {
|
||||
episodes: snapshot.data,
|
||||
podcastLocal: podcastLocal,
|
||||
)
|
||||
: Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -492,12 +485,12 @@ class PodcastPreview extends StatelessWidget {
|
||||
flex: 4,
|
||||
child: Text(podcastLocal.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.visible,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: c)),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
@ -510,10 +503,6 @@ class PodcastPreview extends StatelessWidget {
|
||||
Navigator.push(
|
||||
context,
|
||||
SlideLeftRoute(
|
||||
// transitionPage: PodcastDetail(
|
||||
// podcastLocal: podcastLocal,
|
||||
// hide: playerRunning,
|
||||
// ),
|
||||
page: PodcastDetail(
|
||||
podcastLocal: podcastLocal,
|
||||
)),
|
||||
@ -536,7 +525,7 @@ class ShowEpisode extends StatelessWidget {
|
||||
final List<EpisodeBrief> episodes;
|
||||
final PodcastLocal podcastLocal;
|
||||
ShowEpisode({Key key, this.episodes, this.podcastLocal}) : super(key: key);
|
||||
String _stringForSeconds(double seconds) {
|
||||
String stringForSeconds(double seconds) {
|
||||
if (seconds == null) return null;
|
||||
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
|
||||
}
|
||||
@ -928,11 +917,9 @@ class ShowEpisode extends StatelessWidget {
|
||||
? Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
_stringForSeconds(
|
||||
episodes[index]
|
||||
.duration
|
||||
.toDouble())
|
||||
.toString(),
|
||||
episodes[index]
|
||||
.duration
|
||||
.toTime,
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
// color: _c,
|
||||
@ -981,7 +968,7 @@ class ShowEpisode extends StatelessWidget {
|
||||
);
|
||||
}));
|
||||
},
|
||||
childCount: (episodes.length > 2) ? 2 : episodes.length,
|
||||
childCount: math.min(episodes.length, 2),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -538,12 +538,14 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||
}
|
||||
|
||||
updateMediaItem(EpisodeBrief episode) async {
|
||||
var index = _queue.playlist
|
||||
.indexWhere((item) => item.enclosureUrl == episode.enclosureUrl);
|
||||
if (index > 0) {
|
||||
var episodeNew = await dbHelper.getRssItemWithUrl(episode.enclosureUrl);
|
||||
await delFromPlaylist(episode);
|
||||
await addToPlaylistAt(episodeNew, index);
|
||||
if (episode.enclosureUrl == episode.mediaId) {
|
||||
var index = _queue.playlist
|
||||
.indexWhere((item) => item.enclosureUrl == episode.enclosureUrl);
|
||||
if (index > 0) {
|
||||
var episodeNew = await dbHelper.getRssItemWithUrl(episode.enclosureUrl);
|
||||
await delFromPlaylist(episode);
|
||||
await addToPlaylistAt(episodeNew, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -818,7 +820,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||
// Resume playback if we were playing
|
||||
// if (_playing) {
|
||||
//onPlay();
|
||||
playFromStart();
|
||||
_playFromStart();
|
||||
// } else {
|
||||
// _setState(state: BasicPlaybackState.paused);
|
||||
// }
|
||||
@ -842,7 +844,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||
await AudioServiceBackground.setMediaItem(
|
||||
mediaItem.copyWith(duration: duration));
|
||||
}
|
||||
playFromStart();
|
||||
_playFromStart();
|
||||
} else {
|
||||
_playing = true;
|
||||
if (_audioPlayer.playbackEvent.state != AudioPlaybackState.connecting ||
|
||||
@ -853,7 +855,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||
}
|
||||
}
|
||||
|
||||
playFromStart() async {
|
||||
_playFromStart() async {
|
||||
_playing = true;
|
||||
if (_audioPlayer.playbackEvent.state != AudioPlaybackState.connecting ||
|
||||
_audioPlayer.playbackEvent.state != AudioPlaybackState.none) {
|
||||
@ -940,7 +942,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||
var duration = await _audioPlayer.durationFuture ?? Duration.zero;
|
||||
AudioServiceBackground.setMediaItem(
|
||||
mediaItem.copyWith(duration: duration));
|
||||
playFromStart();
|
||||
_playFromStart();
|
||||
//onPlay();
|
||||
} else {
|
||||
_queue.insert(index, mediaItem);
|
||||
|
@ -7,26 +7,14 @@ import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import '../local_storage/key_value_storage.dart';
|
||||
import '../local_storage/sqflite_localpodcast.dart';
|
||||
import '../type/episode_task.dart';
|
||||
import '../type/episodebrief.dart';
|
||||
|
||||
class EpisodeTask {
|
||||
final String taskId;
|
||||
int progress;
|
||||
DownloadTaskStatus status;
|
||||
final EpisodeBrief episode;
|
||||
EpisodeTask(
|
||||
this.episode,
|
||||
this.taskId, {
|
||||
this.progress = 0,
|
||||
this.status = DownloadTaskStatus.undefined,
|
||||
});
|
||||
}
|
||||
|
||||
void downloadCallback(String id, DownloadTaskStatus status, int progress) {
|
||||
developer.log('Homepage callback task in $id status ($status) $progress');
|
||||
final send = IsolateNameServer.lookupPortByName('downloader_send_port');
|
||||
@ -170,6 +158,14 @@ class DownloadState extends ChangeNotifier {
|
||||
taskId: task.taskId, shouldDeleteContent: true);
|
||||
await dbHelper.delDownloaded(episode.enclosureUrl);
|
||||
} else {
|
||||
if (episode.enclosureUrl == episode.mediaId) {
|
||||
var filePath =
|
||||
'file://${path.join(task.savedDir, Uri.encodeComponent(task.filename))}';
|
||||
var fileStat =
|
||||
await File(path.join(task.savedDir, task.filename)).stat();
|
||||
await dbHelper.saveMediaId(
|
||||
episode.enclosureUrl, filePath, task.taskId, fileStat.size);
|
||||
}
|
||||
_episodeTasks.add(EpisodeTask(episode, task.taskId,
|
||||
progress: task.progress, status: task.status));
|
||||
}
|
||||
@ -286,17 +282,19 @@ class DownloadState extends ChangeNotifier {
|
||||
|
||||
Future pauseTask(EpisodeBrief episode) async {
|
||||
var task = episodeToTask(episode);
|
||||
await FlutterDownloader.pause(taskId: task.taskId);
|
||||
if (task.progress > 0) {
|
||||
await FlutterDownloader.pause(taskId: task.taskId);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future resumeTask(EpisodeBrief episode) async {
|
||||
var task = episodeToTask(episode);
|
||||
var newTaskId = await FlutterDownloader.resume(taskId: task.taskId);
|
||||
await FlutterDownloader.remove(taskId: task.taskId);
|
||||
var index = _episodeTasks.indexOf(task);
|
||||
_removeTask(episode);
|
||||
FlutterDownloader.remove(taskId: task.taskId);
|
||||
var dbHelper = DBHelper();
|
||||
_episodeTasks.insert(index, EpisodeTask(episode, newTaskId));
|
||||
_episodeTasks[index] = task.copyWith(taskId: newTaskId);
|
||||
notifyListeners();
|
||||
await dbHelper.saveDownloaded(episode.enclosureUrl, newTaskId);
|
||||
}
|
||||
|
||||
@ -305,9 +303,8 @@ class DownloadState extends ChangeNotifier {
|
||||
var newTaskId = await FlutterDownloader.retry(taskId: task.taskId);
|
||||
await FlutterDownloader.remove(taskId: task.taskId);
|
||||
var index = _episodeTasks.indexOf(task);
|
||||
_removeTask(episode);
|
||||
var dbHelper = DBHelper();
|
||||
_episodeTasks.insert(index, EpisodeTask(episode, newTaskId));
|
||||
_episodeTasks[index] = task.copyWith(taskId: newTaskId);
|
||||
notifyListeners();
|
||||
await dbHelper.saveDownloaded(episode.enclosureUrl, newTaskId);
|
||||
}
|
||||
|
||||
|
25
lib/type/episode_task.dart
Normal file
25
lib/type/episode_task.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
import 'episodebrief.dart';
|
||||
|
||||
class EpisodeTask extends Equatable {
|
||||
final String taskId;
|
||||
final EpisodeBrief episode;
|
||||
int progress;
|
||||
DownloadTaskStatus status;
|
||||
EpisodeTask(
|
||||
this.episode,
|
||||
this.taskId, {
|
||||
this.progress = 0,
|
||||
this.status = DownloadTaskStatus.undefined,
|
||||
});
|
||||
|
||||
EpisodeTask copyWith({String taskId}) {
|
||||
return EpisodeTask(episode, taskId ?? this.taskId,
|
||||
progress: progress, status: status);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => [taskId];
|
||||
}
|
@ -947,10 +947,10 @@ class DownloadPainter extends CustomPainter {
|
||||
var center = Offset(size.width / 2, size.height / 2);
|
||||
if (pauseProgress == 0) {
|
||||
canvas.drawLine(
|
||||
Offset(width / 2, 2), Offset(width / 2, height * 4 / 5), _paint);
|
||||
canvas.drawLine(Offset(width / 5, height / 2),
|
||||
Offset(width / 2, 4), Offset(width / 2, height * 4 / 5), _paint);
|
||||
canvas.drawLine(Offset(width / 4, height / 2),
|
||||
Offset(width / 2, height * 4 / 5), _paint);
|
||||
canvas.drawLine(Offset(width * 4 / 5, height / 2),
|
||||
canvas.drawLine(Offset(width * 3 / 4, height / 2),
|
||||
Offset(width / 2, height * 4 / 5), _paint);
|
||||
}
|
||||
|
||||
@ -972,13 +972,15 @@ class DownloadPainter extends CustomPainter {
|
||||
if (pauseProgress > 0) {
|
||||
canvas.drawLine(
|
||||
Offset(width / 5 + height * 3 * pauseProgress / 20,
|
||||
height / 2 - height * 3 * pauseProgress / 10),
|
||||
Offset(width / 2 - height * 3 * pauseProgress / 20, height * 4 / 5),
|
||||
height / 2 - height * pauseProgress / 5),
|
||||
Offset(width / 2 - height * 3 * pauseProgress / 20,
|
||||
height * 4 / 5 - height * pauseProgress / 10),
|
||||
_paint);
|
||||
canvas.drawLine(
|
||||
Offset(width * 4 / 5 - height * 3 * pauseProgress / 20,
|
||||
height / 2 - height * 3 * pauseProgress / 10),
|
||||
Offset(width / 2 + height * 3 * pauseProgress / 20, height * 4 / 5),
|
||||
height / 2 - height * pauseProgress / 5),
|
||||
Offset(width / 2 + height * 3 * pauseProgress / 20,
|
||||
height * 4 / 5 - height * pauseProgress / 10),
|
||||
_paint);
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ class EpisodeGrid extends StatelessWidget {
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.done_all,
|
||||
Icons.arrow_downward,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user