Fixed bug => save history error.
This commit is contained in:
parent
fda2c2266c
commit
017e15b129
|
@ -521,7 +521,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||
),
|
||||
],
|
||||
),
|
||||
child: PlaylistButton()),
|
||||
child: _PlaylistButton()),
|
||||
],
|
||||
),
|
||||
Container(height: 2, color: context.primaryColor),
|
||||
|
@ -536,19 +536,15 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
class PlaylistButton extends StatefulWidget {
|
||||
PlaylistButton({Key key}) : super(key: key);
|
||||
class _PlaylistButton extends StatefulWidget {
|
||||
_PlaylistButton({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
PlaylistButtonState createState() => PlaylistButtonState();
|
||||
__PlaylistButtonState createState() => __PlaylistButtonState();
|
||||
}
|
||||
|
||||
class PlaylistButtonState extends State<PlaylistButton> {
|
||||
class __PlaylistButtonState extends State<_PlaylistButton> {
|
||||
bool _loadPlay;
|
||||
static String _stringForSeconds(int seconds) {
|
||||
if (seconds == null) return null;
|
||||
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
_getPlaylist() async {
|
||||
await Provider.of<AudioPlayerNotifier>(context, listen: false)
|
||||
|
@ -567,7 +563,7 @@ class PlaylistButtonState extends State<PlaylistButton> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
var audio = context.watch<AudioPlayerNotifier>();
|
||||
final s = context.s;
|
||||
return MyPopupMenuButton<int>(
|
||||
shape: RoundedRectangleBorder(
|
||||
|
@ -639,7 +635,7 @@ class PlaylistButtonState extends State<PlaylistButton> {
|
|||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
_stringForSeconds(data.item3 ~/ 1000),
|
||||
(data.item3 ~/ 1000).toTime,
|
||||
// style:
|
||||
// TextStyle(color: Colors.white)
|
||||
),
|
||||
|
@ -654,7 +650,7 @@ class PlaylistButtonState extends State<PlaylistButton> {
|
|||
),
|
||||
),
|
||||
Divider(
|
||||
height: 2,
|
||||
height: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -677,6 +673,9 @@ class PlaylistButtonState extends State<PlaylistButton> {
|
|||
),
|
||||
),
|
||||
),
|
||||
PopupMenuDivider(
|
||||
height: 1,
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 2,
|
||||
child: Container(
|
||||
|
@ -692,6 +691,9 @@ class PlaylistButtonState extends State<PlaylistButton> {
|
|||
),
|
||||
),
|
||||
),
|
||||
PopupMenuDivider(
|
||||
height: 1,
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
if (value == 0) {
|
||||
|
@ -757,14 +759,14 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
await Future.delayed(Duration(seconds: 3));
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_top = _top + 33;
|
||||
_top = _top + 30;
|
||||
_loadMore = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Episodes loaded first time.
|
||||
int _top = 99;
|
||||
int _top = 90;
|
||||
|
||||
/// Load more episodes when scroll to bottom.
|
||||
bool _loadMore;
|
||||
|
@ -822,7 +824,9 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
if (scrollInfo.metrics.pixels ==
|
||||
scrollInfo.metrics.maxScrollExtent &&
|
||||
snapshot.data.length == _top) {
|
||||
_loadMoreEpisode();
|
||||
if (!_loadMore) {
|
||||
_loadMoreEpisode();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
@ -1060,13 +1064,13 @@ class _MyFavoriteState extends State<_MyFavorite>
|
|||
await Future.delayed(Duration(seconds: 3));
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_top = _top + 33;
|
||||
_top = _top + 30;
|
||||
_loadMore = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int _top = 99;
|
||||
int _top = 90;
|
||||
bool _loadMore;
|
||||
Layout _layout;
|
||||
int _sortBy;
|
||||
|
@ -1110,7 +1114,9 @@ class _MyFavoriteState extends State<_MyFavorite>
|
|||
if (scrollInfo.metrics.pixels ==
|
||||
scrollInfo.metrics.maxScrollExtent &&
|
||||
snapshot.data.length == _top) {
|
||||
_loadMoreEpisode();
|
||||
if (!_loadMore) {
|
||||
_loadMoreEpisode();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
@ -515,6 +513,9 @@ class _HistoryList extends StatefulWidget {
|
|||
|
||||
class __HistoryListState extends State<_HistoryList> {
|
||||
var dbHelper = DBHelper();
|
||||
bool _loadMore = false;
|
||||
Future _getData;
|
||||
|
||||
Future<List<PlayHistory>> getPlayRecords(int top) async {
|
||||
List<PlayHistory> playHistory;
|
||||
playHistory = await dbHelper.getPlayRecords(top);
|
||||
|
@ -527,208 +528,237 @@ class __HistoryListState extends State<_HistoryList> {
|
|||
_loadMoreData() async {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_top = _top + 20;
|
||||
_loadMore = true;
|
||||
});
|
||||
}
|
||||
await Future.delayed(Duration(milliseconds: 500));
|
||||
_top = _top + 20;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_getData = getPlayRecords(_top);
|
||||
_loadMore = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int _top = 20;
|
||||
int _top;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_top = 20;
|
||||
_getData = getPlayRecords(_top);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = context.s;
|
||||
final audio = context.watch<AudioPlayerNotifier>();
|
||||
return FutureBuilder<List<PlayHistory>>(
|
||||
future: getPlayRecords(_top),
|
||||
future: _getData,
|
||||
builder: (context, snapshot) {
|
||||
return snapshot.hasData
|
||||
? NotificationListener<ScrollNotification>(
|
||||
onNotification: (scrollInfo) {
|
||||
if (scrollInfo.metrics.pixels ==
|
||||
scrollInfo.metrics.maxScrollExtent &&
|
||||
snapshot.data.length == _top) _loadMoreData();
|
||||
snapshot.data.length == _top) {
|
||||
if (!_loadMore) {
|
||||
_loadMoreData();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: snapshot.data.length,
|
||||
itemCount: snapshot.data.length + 1,
|
||||
itemBuilder: (context, index) {
|
||||
final seekValue = snapshot.data[index].seekValue;
|
||||
final seconds = snapshot.data[index].seconds;
|
||||
final date = snapshot
|
||||
.data[index].playdate.millisecondsSinceEpoch;
|
||||
final episode = snapshot.data[index].episode;
|
||||
var c =
|
||||
(Theme.of(context).brightness == Brightness.light)
|
||||
? episode.primaryColor.colorizedark()
|
||||
: episode.primaryColor.colorizeLight();
|
||||
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,
|
||||
if (index == snapshot.data.length) {
|
||||
return SizedBox(
|
||||
height: 2,
|
||||
child: _loadMore
|
||||
? LinearProgressIndicator()
|
||||
: Center());
|
||||
} else {
|
||||
final seekValue = snapshot.data[index].seekValue;
|
||||
final seconds = snapshot.data[index].seconds;
|
||||
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
|
||||
.symmetric(
|
||||
horizontal: 20),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.all(
|
||||
Radius
|
||||
.circular(
|
||||
20.0)),
|
||||
color: context
|
||||
.accentColor,
|
||||
),
|
||||
child: Text(
|
||||
seconds.toTime,
|
||||
style: TextStyle(
|
||||
color:
|
||||
Colors.white),
|
||||
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
|
||||
.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)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}),
|
||||
)
|
||||
: Center(
|
||||
child: SizedBox(
|
||||
height: 25,
|
||||
width: 25,
|
||||
child: CircularProgressIndicator()),
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
)),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -235,30 +235,27 @@ class DBHelper {
|
|||
[_milliseconds, 1, id]);
|
||||
}
|
||||
|
||||
Future<int> saveHistory(PlayHistory history) async {
|
||||
Future<void> saveHistory(PlayHistory history) async {
|
||||
var dbClient = await database;
|
||||
var _milliseconds = DateTime.now().millisecondsSinceEpoch;
|
||||
final milliseconds = DateTime.now().millisecondsSinceEpoch;
|
||||
var recent = await getPlayHistory(1);
|
||||
if (recent.length == 1) {
|
||||
if (recent.first.url == history.url) {
|
||||
await dbClient.rawDelete("DELETE FROM PlayHistory WHERE add_date = ?",
|
||||
[recent.first.playdate.millisecondsSinceEpoch]);
|
||||
}
|
||||
if (recent.isNotEmpty && recent.first.url == history.url) {
|
||||
await dbClient.rawDelete("DELETE FROM PlayHistory WHERE add_date = ?",
|
||||
[recent.first.playdate.millisecondsSinceEpoch]);
|
||||
}
|
||||
var result = await dbClient.transaction((txn) async {
|
||||
await dbClient.transaction((txn) async {
|
||||
return await txn.rawInsert(
|
||||
"""REPLACE INTO PlayHistory (title, enclosure_url, seconds, seek_value, add_date, listen_time)
|
||||
"""INSERT INTO PlayHistory (title, enclosure_url, seconds, seek_value, add_date, listen_time)
|
||||
VALUES (?, ?, ?, ?, ?, ?) """,
|
||||
[
|
||||
history.title,
|
||||
history.url,
|
||||
history.seconds,
|
||||
history.seekValue,
|
||||
_milliseconds,
|
||||
milliseconds,
|
||||
history.seekValue > 0.95 ? 1 : 0
|
||||
]);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<List<PlayHistory>> getPlayHistory(int top) async {
|
||||
|
|
|
@ -267,7 +267,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
await lastWorkStorage.saveInt(0);
|
||||
}
|
||||
|
||||
playlistLoad() async {
|
||||
Future<void> playlistLoad() async {
|
||||
await _queue.getPlaylist();
|
||||
_backgroundAudioDuration = 0;
|
||||
_backgroundAudioPosition = 0;
|
||||
|
@ -442,11 +442,13 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
await dbHelper.saveHistory(history);
|
||||
}
|
||||
if (event is Map && event['playerRunning'] == false) {
|
||||
_playerRunning = false;
|
||||
notifyListeners();
|
||||
final history = PlayHistory(_episode.title, _episode.enclosureUrl,
|
||||
_lastPostion ~/ 1000, _seekSliderValue);
|
||||
await dbHelper.saveHistory(history);
|
||||
if (_playerRunning) {
|
||||
_playerRunning = false;
|
||||
notifyListeners();
|
||||
final history = PlayHistory(_episode.title, _episode.enclosureUrl,
|
||||
_lastPostion ~/ 1000, _seekSliderValue);
|
||||
await dbHelper.saveHistory(history);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue