Fixed bug => save history error.

This commit is contained in:
stonegate 2020-08-16 16:05:04 +08:00
parent fda2c2266c
commit 017e15b129
4 changed files with 236 additions and 201 deletions

View File

@ -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;
},

View File

@ -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,
)),
);
});
}

View File

@ -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 {

View File

@ -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);
}
}
});