Minor change
This commit is contained in:
parent
93ed9d3513
commit
6086db0f8c
|
@ -173,8 +173,8 @@ For help getting started with Flutter, view our
|
|||
[English]: https://img.shields.io/badge/dynamic/json?style=for-the-badge&color=%2323CCC6&label=English&query=%24.languages%5B3%5D.reviewedProgress&url=https%3A%2F%2Fapi.localizely.com%2Fv1%2Fprojects%2Fbde4e9bd-4cb2-449b-9de2-18f231ddb47d%2Fstatus&suffix=%
|
||||
[Chinese Simplified]: https://img.shields.io/badge/dynamic/json?style=for-the-badge&color=%2323CCC6&label=Chinese%20Simplified&query=%24.languages%5B2%5D.reviewedProgress&url=https%3A%2F%2Fapi.localizely.com%2Fv1%2Fprojects%2Fbde4e9bd-4cb2-449b-9de2-18f231ddb47d%2Fstatus&suffix=%
|
||||
[French]: https://img.shields.io/badge/dynamic/json?style=for-the-badge&color=%2323CCC6&label=French(ppp)&query=%24.languages%5B5%5D.reviewedProgress&url=https%3A%2F%2Fapi.localizely.com%2Fv1%2Fprojects%2Fbde4e9bd-4cb2-449b-9de2-18f231ddb47d%2Fstatus&suffix=%
|
||||
[Spanish]: https://img.shields.io/badge/dynamic/json?style=for-the-badge&color=%2323CCC6&label=Spanish(Joel)&query=%24.languages%5B8%5D.reviewedProgress&url=https%3A%2F%2Fapi.localizely.com%2Fv1%2Fprojects%2Fbde4e9bd-4cb2-449b-9de2-18f231ddb47d%2Fstatus&suffix=%
|
||||
[Portuguese]: https://img.shields.io/badge/dynamic/json?style=for-the-badge&color=%2323CCC6&label=portuguese(Bruno)&query=%24.languages%5B10%5D.reviewedProgress&url=https%3A%2F%2Fapi.localizely.com%2Fv1%2Fprojects%2Fbde4e9bd-4cb2-449b-9de2-18f231ddb47d%2Fstatus&suffix=%
|
||||
[Spanish]: https://img.shields.io/badge/dynamic/json?style=for-the-badge&color=%2323CCC6&label=Spanish(Joel)&query=%24.languages%5B7%5D.reviewedProgress&url=https%3A%2F%2Fapi.localizely.com%2Fv1%2Fprojects%2Fbde4e9bd-4cb2-449b-9de2-18f231ddb47d%2Fstatus&suffix=%
|
||||
[Portuguese]: https://img.shields.io/badge/dynamic/json?style=for-the-badge&color=%2323CCC6&label=portuguese(Bruno)&query=%24.languages%5B9%5D.reviewedProgress&url=https%3A%2F%2Fapi.localizely.com%2Fv1%2Fprojects%2Fbde4e9bd-4cb2-449b-9de2-18f231ddb47d%2Fstatus&suffix=%
|
||||
[localizely - website]: https://localizely.com/
|
||||
[google play - icon]: https://img.shields.io/badge/google-playStore-%2323CCC6
|
||||
[google play]: https://play.google.com/store/apps/details?id=com.stonegate.tsacdop
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'package:line_icons/line_icons.dart';
|
|||
import '../util/custom_widget.dart';
|
||||
import '../util/extension_helper.dart';
|
||||
|
||||
const String version = '0.4.17';
|
||||
const String version = '0.4.18';
|
||||
|
||||
class AboutApp extends StatelessWidget {
|
||||
Widget _listItem(
|
||||
|
|
|
@ -526,12 +526,13 @@ class _PlaylistButton extends StatefulWidget {
|
|||
class __PlaylistButtonState extends State<_PlaylistButton> {
|
||||
bool _loadPlay;
|
||||
|
||||
_getPlaylist() async {
|
||||
await Provider.of<AudioPlayerNotifier>(context, listen: false)
|
||||
.loadPlaylist();
|
||||
setState(() {
|
||||
_loadPlay = true;
|
||||
});
|
||||
Future<void> _getPlaylist() async {
|
||||
await context.read<AudioPlayerNotifier>().loadPlaylist();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loadPlay = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -545,157 +546,158 @@ class __PlaylistButtonState extends State<_PlaylistButton> {
|
|||
Widget build(BuildContext context) {
|
||||
var audio = context.watch<AudioPlayerNotifier>();
|
||||
final s = context.s;
|
||||
return MyPopupMenuButton<int>(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||
elevation: 1,
|
||||
icon: Icon(Icons.playlist_play),
|
||||
tooltip: s.menu,
|
||||
itemBuilder: (context) => [
|
||||
MyPopupMenuItem(
|
||||
height: 50,
|
||||
value: 1,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Theme.of(context).accentColor,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.0),
|
||||
topRight: Radius.circular(10.0)),
|
||||
),
|
||||
child: Selector<AudioPlayerNotifier, Tuple3<bool, Playlist, int>>(
|
||||
selector: (_, audio) =>
|
||||
Tuple3(audio.playerRunning, audio.queue, audio.lastPositin),
|
||||
builder: (_, data, __) => !_loadPlay
|
||||
? Container(
|
||||
height: 8.0,
|
||||
)
|
||||
: data.item1 || data.item2.playlist.length == 0
|
||||
? Container(
|
||||
height: 8.0,
|
||||
)
|
||||
: InkWell(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.0),
|
||||
topRight: Radius.circular(10.0)),
|
||||
onTap: () {
|
||||
audio.playlistLoad();
|
||||
Navigator.pop<int>(context);
|
||||
},
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 5),
|
||||
),
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundImage: data
|
||||
.item2.playlist.first.avatarImage),
|
||||
Container(
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.black12),
|
||||
child: Icon(
|
||||
Icons.play_arrow,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 2),
|
||||
),
|
||||
Container(
|
||||
height: 70,
|
||||
width: 140,
|
||||
child: Column(
|
||||
return Material(
|
||||
child: MyPopupMenuButton<int>(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||
elevation: 1,
|
||||
icon: Icon(Icons.playlist_play),
|
||||
tooltip: s.menu,
|
||||
itemBuilder: (context) => [
|
||||
MyPopupMenuItem(
|
||||
height: 50,
|
||||
value: 1,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.0),
|
||||
topRight: Radius.circular(10.0)),
|
||||
),
|
||||
child: Selector<AudioPlayerNotifier, Tuple3<bool, Playlist, int>>(
|
||||
selector: (_, audio) =>
|
||||
Tuple3(audio.playerRunning, audio.queue, audio.lastPositin),
|
||||
builder: (_, data, __) => !_loadPlay
|
||||
? SizedBox(
|
||||
height: 8.0,
|
||||
)
|
||||
: data.item1 || data.item2.playlist.length == 0
|
||||
? SizedBox(
|
||||
height: 8.0,
|
||||
)
|
||||
: InkWell(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.0),
|
||||
topRight: Radius.circular(10.0)),
|
||||
onTap: () {
|
||||
audio.playlistLoad();
|
||||
Navigator.pop<int>(context);
|
||||
},
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 5),
|
||||
),
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
(data.item3 ~/ 1000).toTime,
|
||||
// style:
|
||||
// TextStyle(color: Colors.white)
|
||||
),
|
||||
Text(
|
||||
data.item2.playlist.first.title,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.fade,
|
||||
// style: TextStyle(color: Colors.white),
|
||||
CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundImage: data
|
||||
.item2.playlist.first.avatarImage),
|
||||
Container(
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.black12),
|
||||
child: Icon(
|
||||
Icons.play_arrow,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
height: 1,
|
||||
),
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 2),
|
||||
),
|
||||
Container(
|
||||
height: 70,
|
||||
width: 140,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
(data.item3 ~/ 1000).toTime,
|
||||
// style:
|
||||
// TextStyle(color: Colors.white)
|
||||
),
|
||||
Text(
|
||||
data.item2.playlist.first.title,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.fade,
|
||||
// style: TextStyle(color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
height: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(Icons.playlist_play),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 5.0),
|
||||
),
|
||||
Text(s.homeMenuPlaylist),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuDivider(
|
||||
height: 1,
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 2,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(Icons.history),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5.0),
|
||||
),
|
||||
Text(s.settingsHistory),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuDivider(
|
||||
height: 1,
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
if (value == 0) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PlaylistPage(
|
||||
initPage: InitPage.playlist,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (value == 2) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PlaylistPage(
|
||||
initPage: InitPage.history,
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(Icons.playlist_play),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 5.0),
|
||||
),
|
||||
Text(s.homeMenuPlaylist),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
PopupMenuDivider(
|
||||
height: 1,
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 2,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(Icons.history),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5.0),
|
||||
),
|
||||
Text(s.settingsHistory),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuDivider(
|
||||
height: 1,
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
if (value == 0) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PlaylistPage(
|
||||
initPage: InitPage.playlist,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (value == 2) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PlaylistPage(
|
||||
initPage: InitPage.history,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -707,6 +709,19 @@ class _RecentUpdate extends StatefulWidget {
|
|||
|
||||
class _RecentUpdateState extends State<_RecentUpdate>
|
||||
with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin {
|
||||
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
|
||||
GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
Future _updateRssItem() async {
|
||||
final refreshWorker = context.read<RefreshWorker>();
|
||||
refreshWorker.start(_group);
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Refresh started',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<EpisodeBrief>> _getRssItem(int top, List<String> group,
|
||||
{bool hideListened}) async {
|
||||
var storage = KeyValueStorage(recentLayoutKey);
|
||||
|
@ -718,7 +733,7 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
}
|
||||
var dbHelper = DBHelper();
|
||||
List<EpisodeBrief> episodes;
|
||||
if (group.first == 'All') {
|
||||
if (group.isEmpty) {
|
||||
episodes =
|
||||
await dbHelper.getRecentRssItem(top, hideListened: _hideListened);
|
||||
} else {
|
||||
|
@ -731,7 +746,7 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
Future<int> _getUpdateCounts(List<String> group) async {
|
||||
var dbHelper = DBHelper();
|
||||
var episodes = <EpisodeBrief>[];
|
||||
if (group.first == 'All') {
|
||||
if (group.isEmpty) {
|
||||
episodes = await dbHelper.getRecentNewRssItem();
|
||||
} else {
|
||||
episodes = await dbHelper.getGroupNewRssItem(group);
|
||||
|
@ -768,7 +783,7 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
super.initState();
|
||||
_loadMore = false;
|
||||
_groupName = 'All';
|
||||
_group = ['All'];
|
||||
_group = [];
|
||||
_scroll = false;
|
||||
}
|
||||
|
||||
|
@ -820,24 +835,28 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
}
|
||||
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:
|
||||
child: RefreshIndicator(
|
||||
key: _refreshIndicatorKey,
|
||||
color: context.accentColor,
|
||||
onRefresh: () async {
|
||||
await _updateRssItem();
|
||||
},
|
||||
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) =>
|
||||
PopupMenuButton<String>(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
|
@ -903,7 +922,7 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
if (value == 'All') {
|
||||
setState(() {
|
||||
_groupName = 'All';
|
||||
_group = ['All'];
|
||||
_group = [];
|
||||
});
|
||||
} else {
|
||||
for (var group
|
||||
|
@ -923,129 +942,128 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
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: 15,
|
||||
width: 20,
|
||||
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: 15,
|
||||
width: 20,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter:
|
||||
AddToPlaylistPainter(
|
||||
context
|
||||
.textColor,
|
||||
context
|
||||
.textColor,
|
||||
))),
|
||||
onPressed:
|
||||
() {}),
|
||||
);
|
||||
}),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
tooltip:
|
||||
s.hideListenedSetting,
|
||||
icon: SizedBox(
|
||||
width: 30,
|
||||
height: 15,
|
||||
child: HideListened(
|
||||
hideListened:
|
||||
_hideListened ??
|
||||
false,
|
||||
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:
|
||||
15,
|
||||
width: 20,
|
||||
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: 15,
|
||||
width: 20,
|
||||
child: CustomPaint(
|
||||
painter: AddToPlaylistPainter(
|
||||
context
|
||||
.textColor,
|
||||
context
|
||||
.textColor,
|
||||
))),
|
||||
onPressed: () {}),
|
||||
);
|
||||
}),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
tooltip:
|
||||
s.hideListenedSetting,
|
||||
icon: SizedBox(
|
||||
width: 30,
|
||||
height: 15,
|
||||
child: HideListened(
|
||||
hideListened:
|
||||
_hideListened ??
|
||||
false,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() =>
|
||||
_hideListened =
|
||||
!_hideListened);
|
||||
},
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() =>
|
||||
_hideListened =
|
||||
!_hideListened);
|
||||
},
|
||||
),
|
||||
),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: LayoutButton(
|
||||
layout: _layout,
|
||||
onPressed: (layout) =>
|
||||
setState(() {
|
||||
_layout = layout;
|
||||
}),
|
||||
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,
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
]))
|
||||
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();
|
||||
},
|
||||
);
|
||||
|
|
|
@ -361,11 +361,8 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
|||
alignment: Alignment.centerLeft,
|
||||
color: context.scaffoldBackgroundColor,
|
||||
child: TabBar(
|
||||
labelPadding: EdgeInsets.only(
|
||||
top: 5.0,
|
||||
bottom: 10.0,
|
||||
left: 6.0,
|
||||
right: 6.0),
|
||||
labelPadding:
|
||||
EdgeInsets.fromLTRB(6.0, 5.0, 6.0, 10.0),
|
||||
indicator: CircleTabIndicator(
|
||||
color: context.accentColor, radius: 3),
|
||||
isScrollable: true,
|
||||
|
@ -439,17 +436,30 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
|||
.podcasts
|
||||
.map<Widget>((podcastLocal) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? Theme.of(context).primaryColor
|
||||
: Colors.black12),
|
||||
margin: EdgeInsets.symmetric(horizontal: 5.0),
|
||||
key: ObjectKey(podcastLocal.title),
|
||||
child: PodcastPreview(
|
||||
podcastLocal: podcastLocal,
|
||||
),
|
||||
);
|
||||
decoration: BoxDecoration(
|
||||
color: context.brightness ==
|
||||
Brightness.light
|
||||
? context.primaryColor
|
||||
: Colors.black12),
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 5.0),
|
||||
key: ObjectKey(podcastLocal.title),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
SlideLeftRoute(
|
||||
page: PodcastDetail(
|
||||
podcastLocal: podcastLocal,
|
||||
)),
|
||||
);
|
||||
},
|
||||
child: PodcastPreview(
|
||||
podcastLocal: podcastLocal,
|
||||
),
|
||||
)));
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
|
@ -513,27 +523,11 @@ class PodcastPreview extends StatelessWidget {
|
|||
Expanded(
|
||||
flex: 1,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Selector<AudioPlayerNotifier, bool>(
|
||||
selector: (_, audio) => audio.playerRunning,
|
||||
builder: (_, playerRunning, __) => IconButton(
|
||||
icon: Icon(Icons.arrow_forward),
|
||||
tooltip: context.s.homeGroupsSeeAll,
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
SlideLeftRoute(
|
||||
page: PodcastDetail(
|
||||
podcastLocal: podcastLocal,
|
||||
)),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Icon(Icons.arrow_forward),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'package:file_picker/file_picker.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:line_icons/line_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
|
@ -26,7 +25,6 @@ class PopupMenu extends StatefulWidget {
|
|||
class _PopupMenuState extends State<PopupMenu> {
|
||||
Future<String> _getRefreshDate(BuildContext context) async {
|
||||
int refreshDate;
|
||||
final s = context.s;
|
||||
var refreshstorage = KeyValueStorage('refreshdate');
|
||||
var i = await refreshstorage.getInt();
|
||||
if (i == 0) {
|
||||
|
@ -36,20 +34,21 @@ class _PopupMenuState extends State<PopupMenu> {
|
|||
} else {
|
||||
refreshDate = i;
|
||||
}
|
||||
var date = DateTime.fromMillisecondsSinceEpoch(refreshDate);
|
||||
var difference = DateTime.now().difference(date);
|
||||
if (difference.inSeconds < 60) {
|
||||
return s.secondsAgo(difference.inSeconds);
|
||||
} else if (difference.inMinutes < 60) {
|
||||
return s.minsAgo(difference.inMinutes);
|
||||
} else if (difference.inHours < 24) {
|
||||
return s.hoursAgo(difference.inHours);
|
||||
} else if (difference.inDays < 7) {
|
||||
return s.daysAgo(difference.inDays);
|
||||
} else {
|
||||
return DateFormat.yMMMd()
|
||||
.format(DateTime.fromMillisecondsSinceEpoch(refreshDate));
|
||||
}
|
||||
return refreshDate.toDate(context);
|
||||
// var date = DateTime.fromMillisecondsSinceEpoch(refreshDate);
|
||||
// var difference = DateTime.now().difference(date);
|
||||
// if (difference.inSeconds < 60) {
|
||||
// return s.secondsAgo(difference.inSeconds);
|
||||
// } else if (difference.inMinutes < 60) {
|
||||
// return s.minsAgo(difference.inMinutes);
|
||||
// } else if (difference.inHours < 24) {
|
||||
// return s.hoursAgo(difference.inHours);
|
||||
// } else if (difference.inDays < 7) {
|
||||
// return s.daysAgo(difference.inDays);
|
||||
// } else {
|
||||
// return DateFormat.yMMMd()
|
||||
// .format(DateTime.fromMillisecondsSinceEpoch(refreshDate));
|
||||
// }
|
||||
}
|
||||
|
||||
void _saveOmpl(String path) async {
|
||||
|
@ -198,8 +197,7 @@ class _PopupMenuState extends State<PopupMenu> {
|
|||
} else if (value == 2) {
|
||||
_getFilePath();
|
||||
} else if (value == 1) {
|
||||
//_refreshAll();
|
||||
refreshWorker.start();
|
||||
refreshWorker.start([]);
|
||||
} else if (value == 3) {
|
||||
// setting.theme != 2 ? setting.setTheme(2) : setting.setTheme(1);
|
||||
} else if (value == 4) {
|
||||
|
|
|
@ -69,7 +69,7 @@ class _PlaylistPageState extends State<PlaylistPage> {
|
|||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
child: Scaffold(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
backgroundColor: context.primaryColor,
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: context.accentColor.withAlpha(70),
|
||||
|
@ -264,9 +264,12 @@ class _PlaylistPageState extends State<PlaylistPage> {
|
|||
),
|
||||
),
|
||||
Expanded(
|
||||
child: AnimatedSwitcher(
|
||||
duration: Duration(milliseconds: 300),
|
||||
child: _loadList)),
|
||||
child: Container(
|
||||
color: context.primaryColor,
|
||||
child: AnimatedSwitcher(
|
||||
duration: Duration(milliseconds: 300),
|
||||
child: _loadList),
|
||||
)),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
@ -586,171 +589,192 @@ class __HistoryListState extends State<_HistoryList> {
|
|||
final date = snapshot
|
||||
.data[index].playdate.millisecondsSinceEpoch;
|
||||
final episode = snapshot.data[index].episode;
|
||||
final c = episode.backgroudColor(context);
|
||||
return SizedBox(
|
||||
height: 90.0,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: ListTile(
|
||||
contentPadding:
|
||||
EdgeInsets.fromLTRB(24, 8, 20, 8),
|
||||
onTap: () => audio.episodeLoad(episode),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: c.withOpacity(0.5),
|
||||
backgroundImage: episode.avatarImage),
|
||||
title: Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: Text(
|
||||
snapshot.data[index].title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
subtitle: Container(
|
||||
height: 35,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
if (seekValue < 0.9)
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(
|
||||
vertical: 5.0),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
audio.episodeLoad(episode,
|
||||
startPosition:
|
||||
(seconds * 1000)
|
||||
.toInt());
|
||||
},
|
||||
child: Stack(children: [
|
||||
ShaderMask(
|
||||
shaderCallback:
|
||||
(bounds) {
|
||||
return LinearGradient(
|
||||
begin: Alignment
|
||||
.centerLeft,
|
||||
colors: <Color>[
|
||||
Colors.cyan[600]
|
||||
.withOpacity(
|
||||
0.8),
|
||||
Colors.white70
|
||||
],
|
||||
stops: [
|
||||
seekValue,
|
||||
seekValue
|
||||
],
|
||||
tileMode:
|
||||
TileMode.mirror,
|
||||
).createShader(
|
||||
bounds);
|
||||
},
|
||||
child: Container(
|
||||
height: 25,
|
||||
alignment:
|
||||
Alignment.center,
|
||||
padding: EdgeInsets
|
||||
final c = episode?.backgroudColor(context);
|
||||
return episode == null
|
||||
? Center()
|
||||
: SizedBox(
|
||||
height: 90.0,
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.fromLTRB(
|
||||
24, 8, 20, 8),
|
||||
onTap: () =>
|
||||
audio.episodeLoad(episode),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
c?.withOpacity(0.5),
|
||||
backgroundImage:
|
||||
episode.avatarImage),
|
||||
title: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 5.0),
|
||||
child: Text(
|
||||
snapshot.data[index].title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
subtitle: Container(
|
||||
height: 35,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
if (seekValue < 0.9)
|
||||
Padding(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
horizontal:
|
||||
20),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.all(
|
||||
Radius.circular(
|
||||
20.0)),
|
||||
color: context
|
||||
.accentColor,
|
||||
),
|
||||
child: Text(
|
||||
seconds.toTime,
|
||||
style: TextStyle(
|
||||
color: Colors
|
||||
.white),
|
||||
),
|
||||
vertical: 5.0),
|
||||
child: Material(
|
||||
color:
|
||||
Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
audio.episodeLoad(
|
||||
episode,
|
||||
startPosition:
|
||||
(seconds *
|
||||
1000)
|
||||
.toInt());
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
ShaderMask(
|
||||
shaderCallback:
|
||||
(bounds) {
|
||||
return LinearGradient(
|
||||
begin: Alignment
|
||||
.centerLeft,
|
||||
colors: <
|
||||
Color>[
|
||||
Colors
|
||||
.cyan[600]
|
||||
.withOpacity(0.8),
|
||||
Colors
|
||||
.white70
|
||||
],
|
||||
stops: [
|
||||
seekValue,
|
||||
seekValue
|
||||
],
|
||||
tileMode:
|
||||
TileMode
|
||||
.mirror,
|
||||
).createShader(
|
||||
bounds);
|
||||
},
|
||||
child:
|
||||
Container(
|
||||
height: 25,
|
||||
alignment:
|
||||
Alignment
|
||||
.center,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal:
|
||||
20),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.all(
|
||||
Radius.circular(20.0)),
|
||||
color: context
|
||||
.accentColor,
|
||||
),
|
||||
child: Text(
|
||||
seconds
|
||||
.toTime,
|
||||
style: TextStyle(
|
||||
color:
|
||||
Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
SizedBox(
|
||||
child: Selector<
|
||||
AudioPlayerNotifier,
|
||||
Tuple2<
|
||||
List<EpisodeBrief>,
|
||||
bool>>(
|
||||
selector: (_, audio) =>
|
||||
Tuple2(
|
||||
audio.queue
|
||||
.playlist,
|
||||
audio
|
||||
.queueUpdate),
|
||||
builder: (_, data, __) {
|
||||
return data.item1
|
||||
.contains(
|
||||
episode)
|
||||
? IconButton(
|
||||
icon: Icon(
|
||||
Icons
|
||||
.playlist_add_check,
|
||||
color: context
|
||||
.accentColor),
|
||||
onPressed:
|
||||
() async {
|
||||
audio.delFromPlaylist(
|
||||
episode);
|
||||
Fluttertoast
|
||||
.showToast(
|
||||
msg: s
|
||||
.toastRemovePlaylist,
|
||||
gravity:
|
||||
ToastGravity
|
||||
.BOTTOM,
|
||||
);
|
||||
})
|
||||
: IconButton(
|
||||
icon: Icon(
|
||||
Icons
|
||||
.playlist_add,
|
||||
color: Colors
|
||||
.grey[
|
||||
700]),
|
||||
onPressed:
|
||||
() async {
|
||||
audio.addToPlaylist(
|
||||
episode);
|
||||
Fluttertoast
|
||||
.showToast(
|
||||
msg: s
|
||||
.toastAddPlaylist,
|
||||
gravity:
|
||||
ToastGravity
|
||||
.BOTTOM,
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
child: Selector<
|
||||
AudioPlayerNotifier,
|
||||
Tuple2<List<EpisodeBrief>,
|
||||
bool>>(
|
||||
selector: (_, audio) => Tuple2(
|
||||
audio.queue.playlist,
|
||||
audio.queueUpdate),
|
||||
builder: (_, data, __) {
|
||||
return data.item1
|
||||
.contains(episode)
|
||||
? IconButton(
|
||||
icon: Icon(
|
||||
Icons
|
||||
.playlist_add_check,
|
||||
color: context
|
||||
.accentColor),
|
||||
onPressed: () async {
|
||||
audio
|
||||
.delFromPlaylist(
|
||||
episode);
|
||||
Fluttertoast
|
||||
.showToast(
|
||||
msg: s
|
||||
.toastRemovePlaylist,
|
||||
gravity:
|
||||
ToastGravity
|
||||
.BOTTOM,
|
||||
);
|
||||
})
|
||||
: IconButton(
|
||||
icon: Icon(
|
||||
Icons
|
||||
.playlist_add,
|
||||
color: Colors
|
||||
.grey[700]),
|
||||
onPressed: () async {
|
||||
audio.addToPlaylist(
|
||||
episode);
|
||||
Fluttertoast
|
||||
.showToast(
|
||||
msg: s
|
||||
.toastAddPlaylist,
|
||||
gravity:
|
||||
ToastGravity
|
||||
.BOTTOM,
|
||||
);
|
||||
});
|
||||
},
|
||||
Spacer(),
|
||||
Text(
|
||||
date.toDate(context),
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Text(
|
||||
date.toDate(context),
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(height: 1)
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(height: 1)
|
||||
],
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
|
|
@ -38,7 +38,8 @@ class DBHelper {
|
|||
description TEXT, add_date INTEGER, imagePath TEXT, provider TEXT, link TEXT,
|
||||
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, skip_seconds_end INTEGER DEFAULT 0)""");
|
||||
auto_download INTEGER DEFAULT 0, skip_seconds_end INTEGER DEFAULT 0,
|
||||
never_update INTEGER DEFAULT 0)""");
|
||||
await db
|
||||
.execute("""CREATE TABLE Episodes(id INTEGER PRIMARY KEY,title TEXT,
|
||||
enclosure_url TEXT UNIQUE, enclosure_length INTEGER, pubDate TEXT,
|
||||
|
@ -62,27 +63,41 @@ class DBHelper {
|
|||
"ALTER TABLE PodcastLocal ADD auto_download INTEGER DEFAULT 0");
|
||||
await db.execute(
|
||||
"ALTER TABLE PodcastLocal ADD skip_seconds_end INTEGER DEFAULT 0 ");
|
||||
await db.execute(
|
||||
"ALTER TABLE PodcastLocal ADD never_update INTEGER DEFAULT 0 ");
|
||||
} else if (oldVersion == 2) {
|
||||
await db.execute(
|
||||
"ALTER TABLE PodcastLocal ADD auto_download INTEGER DEFAULT 0");
|
||||
await db.execute(
|
||||
"ALTER TABLE PodcastLocal ADD skip_seconds_end INTEGER DEFAULT 0 ");
|
||||
await db.execute(
|
||||
"ALTER TABLE PodcastLocal ADD never_update INTEGER DEFAULT 0 ");
|
||||
} else if (oldVersion == 3) {
|
||||
await db.execute(
|
||||
"ALTER TABLE PodcastLocal ADD skip_seconds_end INTEGER DEFAULT 0 ");
|
||||
"ALTER TABLE PodcastLocal ADD skip_seconds_end INTEGER DEFAULT 0");
|
||||
await db.execute(
|
||||
"ALTER TABLE PodcastLocal ADD never_update INTEGER DEFAULT 0 ");
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<PodcastLocal>> getPodcastLocal(List<String> podcasts) async {
|
||||
Future<List<PodcastLocal>> getPodcastLocal(List<String> podcasts,
|
||||
{bool updateOnly = false}) async {
|
||||
var dbClient = await database;
|
||||
var podcastLocal = <PodcastLocal>[];
|
||||
|
||||
for (var s in podcasts) {
|
||||
List<Map> list;
|
||||
list = await dbClient.rawQuery(
|
||||
"""SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath , provider,
|
||||
if (updateOnly) {
|
||||
list = await dbClient.rawQuery(
|
||||
"""SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath , provider,
|
||||
link ,update_count, episode_count FROM PodcastLocal WHERE id = ? AND
|
||||
never_update = 0""", [s]);
|
||||
} else {
|
||||
list = await dbClient.rawQuery(
|
||||
"""SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath , provider,
|
||||
link ,update_count, episode_count FROM PodcastLocal WHERE id = ?""",
|
||||
[s]);
|
||||
[s]);
|
||||
}
|
||||
if (list.length > 0) {
|
||||
podcastLocal.add(PodcastLocal(
|
||||
list.first['title'],
|
||||
|
@ -101,10 +116,21 @@ class DBHelper {
|
|||
return podcastLocal;
|
||||
}
|
||||
|
||||
Future<List<PodcastLocal>> getPodcastLocalAll() async {
|
||||
Future<List<PodcastLocal>> getPodcastLocalAll(
|
||||
{bool updateOnly = false}) async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
'SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath, provider, link FROM PodcastLocal ORDER BY add_date DESC');
|
||||
|
||||
List<Map> list;
|
||||
if (updateOnly) {
|
||||
list = await dbClient.rawQuery(
|
||||
"""SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath,
|
||||
provider, link FROM PodcastLocal WHERE never_update = 0 ORDER BY
|
||||
add_date DESC""");
|
||||
} else {
|
||||
list = await dbClient.rawQuery(
|
||||
"""SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath,
|
||||
provider, link FROM PodcastLocal ORDER BY add_date DESC""");
|
||||
}
|
||||
|
||||
var podcastLocal = <PodcastLocal>[];
|
||||
|
||||
|
@ -131,6 +157,21 @@ class DBHelper {
|
|||
return 0;
|
||||
}
|
||||
|
||||
Future<bool> getNeverUpdate(String id) async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient
|
||||
.rawQuery('SELECT never_update FROM PodcastLocal WHERE id = ?', [id]);
|
||||
if (list.isNotEmpty) return list.first['never_update'] == 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<int> saveNeverUpdate(String id, {bool boo}) async {
|
||||
var dbClient = await database;
|
||||
return await dbClient.rawUpdate(
|
||||
"UPDATE PodcastLocal SET never_update = ? WHERE id = ?",
|
||||
[boo ? 1 : 0, id]);
|
||||
}
|
||||
|
||||
Future<int> getPodcastUpdateCounts(String id) async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
|
|
|
@ -58,6 +58,11 @@ class _PodcastSettingState extends State<PodcastSetting> {
|
|||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _setNeverUpdate(bool boo) async {
|
||||
await _dbHelper.saveNeverUpdate(widget.podcastLocal.id, boo: boo);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _saveSkipSecondsStart(int seconds) async {
|
||||
await _dbHelper.saveSkipSecondsStart(widget.podcastLocal.id, seconds);
|
||||
}
|
||||
|
@ -70,6 +75,10 @@ class _PodcastSettingState extends State<PodcastSetting> {
|
|||
return await _dbHelper.getAutoDownload(id);
|
||||
}
|
||||
|
||||
Future<bool> _getNeverUpdate(String id) async {
|
||||
return await _dbHelper.getNeverUpdate(id);
|
||||
}
|
||||
|
||||
Future<int> _getSkipSecondStart(String id) async {
|
||||
return await _dbHelper.getSkipSecondsStart(id);
|
||||
}
|
||||
|
@ -217,6 +226,21 @@ class _PodcastSettingState extends State<PodcastSetting> {
|
|||
),
|
||||
);
|
||||
}),
|
||||
FutureBuilder<bool>(
|
||||
future: _getNeverUpdate(widget.podcastLocal.id),
|
||||
initialData: false,
|
||||
builder: (context, snapshot) {
|
||||
return ListTile(
|
||||
onTap: () => _setNeverUpdate(!snapshot.data),
|
||||
leading: Icon(Icons.lock),
|
||||
title: Text('Never update'),
|
||||
trailing: Transform.scale(
|
||||
scale: 0.9,
|
||||
child:
|
||||
Switch(value: snapshot.data, onChanged: _setNeverUpdate),
|
||||
),
|
||||
);
|
||||
}),
|
||||
FutureBuilder<int>(
|
||||
future: _getSkipSecondStart(widget.podcastLocal.id),
|
||||
initialData: 0,
|
||||
|
@ -246,42 +270,42 @@ class _PodcastSettingState extends State<PodcastSetting> {
|
|||
},
|
||||
onConfirm: () async {
|
||||
await _saveSkipSecondsStart(_secondsStart);
|
||||
setState(() => _showStartTimePicker = false);
|
||||
if (mounted) 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,
|
||||
),
|
||||
// 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) {
|
||||
|
@ -419,7 +443,6 @@ class _TimePicker extends StatelessWidget {
|
|||
children: [
|
||||
SizedBox(height: 10),
|
||||
DurationPicker(
|
||||
key: key,
|
||||
onChange: onChange,
|
||||
),
|
||||
Row(
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
|||
import 'dart:developer' as developer;
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:device_info/device_info.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -9,6 +10,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:line_icons/line_icons.dart';
|
||||
import 'package:confetti/confetti.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
@ -299,23 +301,37 @@ class _DataBackupState extends State<DataBackup> {
|
|||
final loginInfo = snapshot.data;
|
||||
if (loginInfo.isNotEmpty) {
|
||||
return ListTile(
|
||||
contentPadding:
|
||||
const EdgeInsets.only(left: 70.0, right: 20),
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 70.0, right: 20, top: 10, bottom: 10),
|
||||
onTap: _syncNow,
|
||||
title: Text(s.syncNow),
|
||||
trailing: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => _GpodderInfo()));
|
||||
},
|
||||
icon: Icon(LineIcons.info_circle_solid),
|
||||
),
|
||||
subtitle: FutureBuilder<List<int>>(
|
||||
future: _getSyncStatus(),
|
||||
initialData: [0, 0],
|
||||
builder: (context, snapshot) {
|
||||
final dateTime = snapshot.data[0];
|
||||
final status = snapshot.data[1];
|
||||
return Wrap(
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${s.lastUpdate}: ${dateTime.toDate(context)}'),
|
||||
SizedBox(width: 8),
|
||||
Text('${s.status}: '),
|
||||
_syncStauts(status),
|
||||
Row(
|
||||
children: [
|
||||
Text('${s.status}: '),
|
||||
_syncStauts(status),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
|
@ -323,6 +339,7 @@ class _DataBackupState extends State<DataBackup> {
|
|||
}
|
||||
return Center();
|
||||
}),
|
||||
|
||||
// ListTile(
|
||||
// onTap: () async {
|
||||
// final subscribeWorker = context.read<GroupList>();
|
||||
|
@ -402,7 +419,7 @@ class _DataBackupState extends State<DataBackup> {
|
|||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
Divider(height: 1),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
|
@ -568,13 +585,21 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
|||
var _username = '';
|
||||
var _password = '';
|
||||
LoginStatus _loginStatus;
|
||||
ConfettiController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_loginStatus = LoginStatus.none;
|
||||
_controller = ConfettiController(duration: Duration(seconds: 3));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
final GlobalKey<FormFieldState<String>> _passwordFieldKey =
|
||||
GlobalKey<FormFieldState<String>>();
|
||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||
|
@ -601,6 +626,7 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
|||
if (mounted) {
|
||||
setState(() {
|
||||
_loginStatus = LoginStatus.complete;
|
||||
_controller.play();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -635,9 +661,11 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
|||
var rssLink = rssExp.stringMatch(rss.xmlUrl);
|
||||
if (rssLink != null) {
|
||||
final dbHelper = DBHelper();
|
||||
final exist = dbHelper.checkPodcast(rssLink);
|
||||
final exist = await dbHelper.checkPodcast(rssLink);
|
||||
if (exist == '') {
|
||||
var item = SubscribeItem(rssLink, rss.text, group: 'Home');
|
||||
var item = SubscribeItem(
|
||||
rssLink, rss.text == '' ? rssLink : rss.text,
|
||||
group: 'Home');
|
||||
await subscribeWorker.setSubscribeItem(item, syncGpodder: false);
|
||||
await Future.delayed(Duration(milliseconds: 200));
|
||||
}
|
||||
|
@ -757,14 +785,37 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
|||
_loginStatus == LoginStatus.complete
|
||||
? SliverList(
|
||||
delegate: SliverChildListDelegate([
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(40.0, 50, 40, 100),
|
||||
child: Text(
|
||||
s.gpodderLoginDes,
|
||||
textAlign: TextAlign.center,
|
||||
style:
|
||||
context.textTheme.subtitle1.copyWith(height: 2),
|
||||
),
|
||||
Stack(
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.fromLTRB(40.0, 50, 40, 100),
|
||||
child: Text(
|
||||
s.gpodderLoginDes,
|
||||
textAlign: TextAlign.center,
|
||||
style: context.textTheme.subtitle1
|
||||
.copyWith(height: 2),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: ConfettiWidget(
|
||||
confettiController: _controller,
|
||||
blastDirectionality:
|
||||
BlastDirectionality.explosive,
|
||||
emissionFrequency: 0.05,
|
||||
maximumSize: Size(20, 10),
|
||||
shouldLoop: false,
|
||||
colors: const [
|
||||
Colors.green,
|
||||
Colors.blue,
|
||||
Colors.pink,
|
||||
Colors.orange,
|
||||
Colors.purple
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Center(
|
||||
child: OutlineButton(
|
||||
|
@ -773,7 +824,7 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
|||
},
|
||||
highlightedBorderColor: context.accentColor,
|
||||
child: Text(s.back)),
|
||||
)
|
||||
),
|
||||
]),
|
||||
)
|
||||
: Form(
|
||||
|
@ -922,3 +973,152 @@ class _PasswordFieldState extends State<PasswordField> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _GpodderInfo extends StatefulWidget {
|
||||
_GpodderInfo({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
__GpodderInfoState createState() => __GpodderInfoState();
|
||||
}
|
||||
|
||||
class __GpodderInfoState extends State<_GpodderInfo> {
|
||||
final _gpodder = Gpodder();
|
||||
var _syncing = false;
|
||||
|
||||
Future<List<String>> _getLoginInfo() async {
|
||||
final storage = KeyValueStorage(gpodderApiKey);
|
||||
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||
final deviceInfo = await storage.getStringList();
|
||||
deviceInfo.add("Tsacdop on ${androidInfo.model}");
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
Future<void> _fullSync() async {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_syncing = true;
|
||||
});
|
||||
}
|
||||
final uploadStatus = await _gpodder.uploadSubscriptions();
|
||||
if (uploadStatus == 200) {
|
||||
var subscribeWorker = context.read<GroupList>();
|
||||
var rssExp = RegExp(r'^(https?):\/\/(.*)');
|
||||
final opml = await _gpodder.getAllPodcast();
|
||||
if (opml != '') {
|
||||
Map<String, List<OmplOutline>> data = PodcastsBackup.parseOMPL(opml);
|
||||
for (var entry in data.entries) {
|
||||
var list = entry.value.reversed;
|
||||
for (var rss in list) {
|
||||
var rssLink = rssExp.stringMatch(rss.xmlUrl);
|
||||
if (rssLink != null) {
|
||||
final dbHelper = DBHelper();
|
||||
final exist = await dbHelper.checkPodcast(rssLink);
|
||||
if (exist == '') {
|
||||
var item = SubscribeItem(
|
||||
rssLink, rss.text == '' ? rssLink : rss.text,
|
||||
group: 'Home');
|
||||
await subscribeWorker.setSubscribeItem(item,
|
||||
syncGpodder: false);
|
||||
await Future.delayed(Duration(milliseconds: 200));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//await _syncNow();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_syncing = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = context.s;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
),
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
brightness: Brightness.dark,
|
||||
iconTheme: IconThemeData(
|
||||
color: Colors.white,
|
||||
),
|
||||
elevation: 0,
|
||||
backgroundColor: context.accentColor,
|
||||
expandedHeight: 200,
|
||||
flexibleSpace: Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
color: context.accentColor,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
minRadius: 50,
|
||||
backgroundColor: context.primaryColor.withOpacity(0.3),
|
||||
child: SizedBox(
|
||||
height: 80,
|
||||
width: 80,
|
||||
child: Image.asset('assets/gpodder.png')),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(s.intergateWith('gpodder.net'),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate([
|
||||
FutureBuilder<List<String>>(
|
||||
future: _getLoginInfo(),
|
||||
initialData: [],
|
||||
builder: (context, snapshot) {
|
||||
final deviceId =
|
||||
snapshot.data.isNotEmpty ? snapshot.data[1] : '';
|
||||
final deviceName =
|
||||
snapshot.data.isNotEmpty ? snapshot.data[3] : '';
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text('Divice id'),
|
||||
subtitle: Text(deviceId),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('Divice name'),
|
||||
subtitle: Text(deviceName),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
ListTile(
|
||||
onTap: _fullSync,
|
||||
// contentPadding:
|
||||
// const EdgeInsets.only(left: 70.0, right: 20),
|
||||
title: Text('Full sync'),
|
||||
subtitle: Text('If sync have error')),
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
volumeGainStorage.saveInt(volumeGain);
|
||||
}
|
||||
|
||||
Future _initAudioData() async {
|
||||
Future<void> _initAudioData() async {
|
||||
var index = await playerHeightStorage.getInt(defaultValue: 0);
|
||||
_playerHeight = PlayerHeight.values[index];
|
||||
_currentSpeed = await speedStorage.getDoubel(defaultValue: 1.0);
|
||||
|
@ -250,8 +250,6 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
void addListener(VoidCallback listener) {
|
||||
super.addListener(listener);
|
||||
_initAudioData();
|
||||
// _queueUpdate = false;
|
||||
// _getAutoSleepTimer();
|
||||
AudioService.connect();
|
||||
var running = AudioService.running;
|
||||
if (running) {}
|
||||
|
@ -265,7 +263,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
if (_lastPostion > 0 && _queue.playlist.length > 0) {
|
||||
final episode = _queue.playlist.first;
|
||||
final duration = episode.duration * 1000;
|
||||
final seekValue = duration != 0 ? _lastPostion / duration : 1;
|
||||
final seekValue = duration != 0 ? _lastPostion / duration : 1.0;
|
||||
final history = PlayHistory(
|
||||
episode.title, episode.enclosureUrl, _lastPostion ~/ 1000, seekValue);
|
||||
await dbHelper.saveHistory(history);
|
||||
|
@ -319,7 +317,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
}
|
||||
}
|
||||
|
||||
_startAudioService(int position, String url) async {
|
||||
Future<void> _startAudioService(int position, String url) async {
|
||||
_stopOnComplete = false;
|
||||
_sleepTimerMode = SleepTimerMode.undefined;
|
||||
_switchValue = 0;
|
||||
|
@ -439,27 +437,26 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
});
|
||||
|
||||
AudioService.customEventStream.distinct().listen((event) async {
|
||||
if (event is String && _episode.title == event) {
|
||||
if (event is String &&
|
||||
_queue.playlist.isNotEmpty &&
|
||||
_queue.playlist.first.title == event) {
|
||||
_queue.delFromPlaylist(_episode);
|
||||
_lastPostion = 0;
|
||||
notifyListeners();
|
||||
await positionStorage.saveInt(_lastPostion);
|
||||
if (_lastPostion == 0) {
|
||||
final history = PlayHistory(_episode.title, _episode.enclosureUrl,
|
||||
_backgroundAudioPosition ~/ 1000, _seekSliderValue);
|
||||
await dbHelper.saveHistory(history);
|
||||
}
|
||||
if (event is Map && event['playerRunning'] == false && _playerRunning) {
|
||||
_playerRunning = false;
|
||||
notifyListeners();
|
||||
if (_lastPostion > 0) {
|
||||
final history = PlayHistory(_episode.title, _episode.enclosureUrl,
|
||||
_backgroundAudioPosition ~/ 1000, _seekSliderValue);
|
||||
_lastPostion ~/ 1000, _seekSliderValue);
|
||||
await dbHelper.saveHistory(history);
|
||||
}
|
||||
}
|
||||
if (event is Map && event['playerRunning'] == false) {
|
||||
if (_playerRunning) {
|
||||
_playerRunning = false;
|
||||
notifyListeners();
|
||||
if (_lastPostion > 0) {
|
||||
final history = PlayHistory(_episode.title, _episode.enclosureUrl,
|
||||
_lastPostion ~/ 1000, _seekSliderValue);
|
||||
await dbHelper.saveHistory(history);
|
||||
}
|
||||
}
|
||||
_episode = null;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -531,7 +528,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
|
||||
Future<void> addNewEpisode(List<String> group) async {
|
||||
var newEpisodes = <EpisodeBrief>[];
|
||||
if (group.first == 'All') {
|
||||
if (group.isEmpty) {
|
||||
newEpisodes = await dbHelper.getRecentNewRssItem();
|
||||
} else {
|
||||
newEpisodes = await dbHelper.getGroupNewRssItem(group);
|
||||
|
@ -541,14 +538,14 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
await addToPlaylist(episode);
|
||||
}
|
||||
}
|
||||
if (group.first == 'All') {
|
||||
if (group.isEmpty) {
|
||||
await dbHelper.removeAllNewMark();
|
||||
} else {
|
||||
await dbHelper.removeGroupNewMark(group);
|
||||
}
|
||||
}
|
||||
|
||||
updateMediaItem(EpisodeBrief episode) async {
|
||||
Future<void> updateMediaItem(EpisodeBrief episode) async {
|
||||
if (episode.enclosureUrl == episode.mediaId) {
|
||||
var index = _queue.playlist
|
||||
.indexWhere((item) => item.enclosureUrl == episode.enclosureUrl);
|
||||
|
@ -867,7 +864,8 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||
await AudioServiceBackground.setQueue(_queue);
|
||||
if (_queue.length == 0 || _stopAtEnd) {
|
||||
_skipState = null;
|
||||
onStop();
|
||||
await Future.delayed(Duration(milliseconds: 200));
|
||||
await onStop();
|
||||
} else {
|
||||
await AudioServiceBackground.setQueue(_queue);
|
||||
await AudioServiceBackground.setMediaItem(mediaItem);
|
||||
|
@ -878,13 +876,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||
mediaItem.copyWith(duration: duration));
|
||||
}
|
||||
_skipState = null;
|
||||
// Resume playback if we were playing
|
||||
// if (_playing) {
|
||||
//onPlay();
|
||||
_playFromStart();
|
||||
// } else {
|
||||
// _setState(state: BasicPlaybackState.paused);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -922,10 +914,11 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||
_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']));
|
||||
_audioPlayer
|
||||
.seek(Duration(seconds: mediaItem.extras['skipSecondsStart']));
|
||||
// await _audioPlayer.setClip(
|
||||
// start: Duration(seconds: mediaItem.extras['skipSecondsStart']),
|
||||
// );
|
||||
}
|
||||
if (_audioPlayer.playbackEvent.state != AudioPlaybackState.connecting ||
|
||||
_audioPlayer.playbackEvent.state != AudioPlaybackState.none) {
|
||||
|
|
|
@ -152,14 +152,14 @@ class SubscribeItem {
|
|||
///Podcast group, default Home.
|
||||
String group;
|
||||
|
||||
///sync to gpodder
|
||||
bool syncWithGpodder;
|
||||
SubscribeItem(this.url, this.title,
|
||||
{this.subscribeState = SubscribeState.none,
|
||||
this.id = '',
|
||||
this.imgUrl = '',
|
||||
this.group = '',
|
||||
this.syncWithGpodder = true});
|
||||
SubscribeItem(
|
||||
this.url,
|
||||
this.title, {
|
||||
this.subscribeState = SubscribeState.none,
|
||||
this.id = '',
|
||||
this.imgUrl = '',
|
||||
this.group = '',
|
||||
});
|
||||
}
|
||||
|
||||
class GroupList extends ChangeNotifier {
|
||||
|
@ -219,7 +219,7 @@ class GroupList extends ChangeNotifier {
|
|||
}
|
||||
|
||||
Future _start() async {
|
||||
if (_created == false) {
|
||||
if (!_created) {
|
||||
await _createIsolate();
|
||||
_created = true;
|
||||
listen();
|
||||
|
@ -229,7 +229,6 @@ class GroupList extends ChangeNotifier {
|
|||
_subscribeItem.title,
|
||||
_subscribeItem.imgUrl,
|
||||
_subscribeItem.group,
|
||||
_subscribeItem.syncWithGpodder
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -250,7 +249,6 @@ class GroupList extends ChangeNotifier {
|
|||
_subscribeItem.title,
|
||||
_subscribeItem.imgUrl,
|
||||
_subscribeItem.group,
|
||||
_subscribeItem.syncWithGpodder
|
||||
]);
|
||||
} else if (message is List) {
|
||||
_setCurrentSubscribeItem(SubscribeItem(
|
||||
|
@ -717,7 +715,7 @@ Future<void> subIsolateEntryPoint(SendPort sendPort) async {
|
|||
subReceivePort.distinct().listen((message) {
|
||||
if (message is List<dynamic>) {
|
||||
items.add(SubscribeItem(message[0], message[1],
|
||||
imgUrl: message[2], group: message[3], syncWithGpodder: message[4]));
|
||||
imgUrl: message[2], group: message[3]));
|
||||
if (!_running) {
|
||||
_subscribe(items.first);
|
||||
_running = true;
|
||||
|
|
|
@ -34,8 +34,12 @@ class RefreshWorker extends ChangeNotifier {
|
|||
refreshIsolateEntryPoint, receivePort.sendPort);
|
||||
}
|
||||
|
||||
void _listen() {
|
||||
void _listen(List<String> podcasts) {
|
||||
receivePort.distinct().listen((message) {
|
||||
if (message is SendPort) {
|
||||
refreshSendPort = message;
|
||||
refreshSendPort.send(podcasts);
|
||||
}
|
||||
if (message is List) {
|
||||
_currentRefreshItem =
|
||||
RefreshItem(message[0], RefreshState.values[message[1]]);
|
||||
|
@ -51,11 +55,11 @@ class RefreshWorker extends ChangeNotifier {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> start() async {
|
||||
Future<void> start(List<String> podcasts) async {
|
||||
if (!_created) {
|
||||
_complete = false;
|
||||
_createIsolate();
|
||||
_listen();
|
||||
await _createIsolate();
|
||||
_listen(podcasts);
|
||||
_created = true;
|
||||
}
|
||||
}
|
||||
|
@ -68,14 +72,30 @@ class RefreshWorker extends ChangeNotifier {
|
|||
}
|
||||
|
||||
Future<void> refreshIsolateEntryPoint(SendPort sendPort) async {
|
||||
var refreshstorage = KeyValueStorage(refreshdateKey);
|
||||
await refreshstorage.saveInt(DateTime.now().millisecondsSinceEpoch);
|
||||
var dbHelper = DBHelper();
|
||||
var podcastList = await dbHelper.getPodcastLocalAll();
|
||||
for (var podcastLocal in podcastList) {
|
||||
sendPort.send([podcastLocal.title, 1]);
|
||||
var updateCount = await dbHelper.updatePodcastRss(podcastLocal);
|
||||
developer.log('Refresh ${podcastLocal.title}$updateCount');
|
||||
var refreshReceivePort = ReceivePort();
|
||||
sendPort.send(refreshReceivePort.sendPort);
|
||||
var _dbHelper = DBHelper();
|
||||
|
||||
Future<void> _refreshAll(List<String> podcasts) async {
|
||||
var podcastList;
|
||||
if (podcasts.isEmpty) {
|
||||
var refreshstorage = KeyValueStorage(refreshdateKey);
|
||||
await refreshstorage.saveInt(DateTime.now().millisecondsSinceEpoch);
|
||||
podcastList = await _dbHelper.getPodcastLocalAll(updateOnly: true);
|
||||
} else {
|
||||
podcastList = await _dbHelper.getPodcastLocal(podcasts, updateOnly: true);
|
||||
}
|
||||
for (var podcastLocal in podcastList) {
|
||||
sendPort.send([podcastLocal.title, 1]);
|
||||
var updateCount = await _dbHelper.updatePodcastRss(podcastLocal);
|
||||
developer.log('Refresh ${podcastLocal.title}$updateCount');
|
||||
}
|
||||
sendPort.send("done");
|
||||
}
|
||||
sendPort.send("done");
|
||||
|
||||
refreshReceivePort.distinct().listen((message) {
|
||||
if (message is List<dynamic>) {
|
||||
_refreshAll(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ void callbackDispatcher() {
|
|||
if (Platform.isAndroid) {
|
||||
Workmanager.executeTask((task, inputData) async {
|
||||
var dbHelper = DBHelper();
|
||||
var podcastList = await dbHelper.getPodcastLocalAll();
|
||||
var podcastList = await dbHelper.getPodcastLocalAll(updateOnly: false);
|
||||
//lastWork is a indicator for if the app was opened since last backgroundwork
|
||||
//if the app wes opend,then the old marked new episode would be marked not new.
|
||||
var lastWorkStorage = KeyValueStorage(lastWorkKey);
|
||||
|
|
19
pubspec.yaml
19
pubspec.yaml
|
@ -1,7 +1,7 @@
|
|||
name: tsacdop
|
||||
description: An open source podacasts player.
|
||||
|
||||
version: 0.4.17+34
|
||||
version: 0.4.18+35
|
||||
|
||||
environment:
|
||||
sdk: ">=2.6.0 <3.0.0"
|
||||
|
@ -15,7 +15,8 @@ dependencies:
|
|||
audio_session: ^0.0.7
|
||||
cached_network_image: ^2.3.2+1
|
||||
color_thief_flutter: ^1.0.2
|
||||
cookie_jar: ^1.0.0
|
||||
confetti: ^0.5.4+1
|
||||
cookie_jar: ^1.0.1
|
||||
cupertino_icons: ^1.0.0
|
||||
connectivity: ^0.4.9
|
||||
device_info: ^0.4.2+7
|
||||
|
@ -25,7 +26,7 @@ dependencies:
|
|||
effective_dart: ^1.2.4
|
||||
equatable: ^1.2.5
|
||||
feature_discovery: ^0.10.0
|
||||
file_picker: ^2.0.0
|
||||
file_picker: ^2.0.1+2
|
||||
flutter_html: ^0.11.1
|
||||
flutter_downloader: ^1.5.0
|
||||
fluttertoast: ^4.0.0
|
||||
|
@ -36,18 +37,18 @@ dependencies:
|
|||
fl_chart: ^0.11.1
|
||||
marquee: ^1.3.1
|
||||
google_fonts: ^1.1.0
|
||||
image: ^2.1.14
|
||||
image: ^2.1.17
|
||||
intl: ^0.16.1
|
||||
json_serializable: ^3.4.1
|
||||
json_annotation: ^3.0.1
|
||||
path_provider: ^1.6.16
|
||||
json_serializable: ^3.5.0
|
||||
json_annotation: ^3.1.0
|
||||
path_provider: ^1.6.18
|
||||
permission_handler: ^5.0.1
|
||||
provider: ^4.3.2
|
||||
rxdart: ^0.24.1
|
||||
sqflite: ^1.3.1
|
||||
shared_preferences: ^0.5.10
|
||||
shared_preferences: ^0.5.12
|
||||
tuple: ^1.0.3
|
||||
url_launcher: ^5.6.0
|
||||
url_launcher: ^5.7.1
|
||||
uuid: ^2.2.2
|
||||
xml: ^4.2.0
|
||||
workmanager: ^0.2.3
|
||||
|
|
Loading…
Reference in New Issue