Improve gpodder sync.

This commit is contained in:
stonegate 2020-09-24 15:27:52 +08:00
parent d15f1c7b89
commit 93ed9d3513
9 changed files with 301 additions and 265 deletions

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -191,15 +191,6 @@ class AboutApp extends StatelessWidget {
'https://github.com/stonega'), 'https://github.com/stonega'),
_listItem(context, 'Medium', LineIcons.medium, _listItem(context, 'Medium', LineIcons.medium,
'https://medium.com/@stonegate'), 'https://medium.com/@stonegate'),
Padding(
padding: EdgeInsets.fromLTRB(20, 10, 20, 10),
child: Text(
'I need to pay for podcast search API and '
'always get headache without caffeine.',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey[500]),
),
),
Center( Center(
child: SizedBox( child: SizedBox(
width: 200, width: 200,
@ -221,7 +212,6 @@ class AboutApp extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Text('Buy me a coffee', Text('Buy me a coffee',
style: TextStyle( style: TextStyle(
color: context.accentColor,
fontWeight: FontWeight.bold)), fontWeight: FontWeight.bold)),
SizedBox(width: 10), SizedBox(width: 10),
Image( Image(
@ -236,6 +226,15 @@ class AboutApp extends StatelessWidget {
), ),
), ),
), ),
Padding(
padding: EdgeInsets.fromLTRB(20, 10, 20, 10),
child: Text(
'I need to pay for podcast search API and '
'always get headache without caffeine.',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey[500]),
),
),
], ],
), ),
), ),

View File

@ -390,7 +390,6 @@ class __TopPodcastListState extends State<_TopPodcastList> {
() { () {
_loading = true; _loading = true;
_page++; _page++;
print(_page);
_searchFuture = _getTopPodcasts( _searchFuture = _getTopPodcasts(
genre: widget.genre, page: _page); genre: widget.genre, page: _page);
}, },

View File

@ -194,7 +194,6 @@ class Gpodder {
final timeStamp = changes['timestamp']; final timeStamp = changes['timestamp'];
final addList = changes['add'].cast<String>(); final addList = changes['add'].cast<String>();
final removeList = changes['remove'].cast<String>(); final removeList = changes['remove'].cast<String>();
print(removeList);
await _storage.saveStringList([username, deviceId, timeStamp.toString()]); await _storage.saveStringList([username, deviceId, timeStamp.toString()]);
await _remoteAddStorage.addList(addList); await _remoteAddStorage.addList(addList);
await _remoteRemoveStorage.addList(removeList); await _remoteRemoveStorage.addList(removeList);

View File

@ -12,8 +12,6 @@ import 'package:line_icons/line_icons.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tsacdop/util/custom_widget.dart';
import 'package:tuple/tuple.dart';
import 'package:wc_flutter_share/wc_flutter_share.dart'; import 'package:wc_flutter_share/wc_flutter_share.dart';
import '../local_storage/key_value_storage.dart'; import '../local_storage/key_value_storage.dart';
@ -23,6 +21,7 @@ import '../service/opml_build.dart';
import '../state/podcast_group.dart'; import '../state/podcast_group.dart';
import '../state/setting_state.dart'; import '../state/setting_state.dart';
import '../type/settings_backup.dart'; import '../type/settings_backup.dart';
import '../util/custom_widget.dart';
import '../util/extension_helper.dart'; import '../util/extension_helper.dart';
class DataBackup extends StatefulWidget { class DataBackup extends StatefulWidget {
@ -151,9 +150,11 @@ class _DataBackupState extends State<DataBackup> {
} }
Future<void> _syncNow() async { Future<void> _syncNow() async {
setState(() { if (mounted) {
_syncing = true; setState(() {
}); _syncing = true;
});
}
final gpodder = Gpodder(); final gpodder = Gpodder();
final status = await gpodder.getChanges(); final status = await gpodder.getChanges();
@ -169,10 +170,12 @@ class _DataBackupState extends State<DataBackup> {
} }
} }
Future<Tuple2<int, int>> _getSyncStatus() async { Future<List<int>> _getSyncStatus() async {
final syncDateTime = await KeyValueStorage(gpodderSyncDateTimeKey).getInt(); var dateTimeStorage = KeyValueStorage(gpodderSyncDateTimeKey);
final statusIndex = await KeyValueStorage(gpodderSyncStatusKey).getInt(); var statusStorage = KeyValueStorage(gpodderSyncStatusKey);
return Tuple2(syncDateTime, statusIndex); final syncDateTime = await dateTimeStorage.getInt();
final statusIndex = await statusStorage.getInt();
return [syncDateTime, statusIndex];
} }
@override @override
@ -186,228 +189,167 @@ class _DataBackupState extends State<DataBackup> {
Theme.of(context).accentColorBrightness, Theme.of(context).accentColorBrightness,
), ),
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
elevation: 0, elevation: 0,
title: Text(s.settingsBackup), title: Text(s.settingsBackup),
backgroundColor: context.primaryColor, backgroundColor: context.primaryColor,
), ),
body: Column( body: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: EdgeInsets.all(10.0), padding: EdgeInsets.all(10.0),
), ),
FutureBuilder<List<String>>( FutureBuilder<List<String>>(
future: _getLoginInfo(), future: _getLoginInfo(),
initialData: [], initialData: [],
builder: (context, snapshot) { builder: (context, snapshot) {
final loginInfo = snapshot.data; final loginInfo = snapshot.data;
return Container( return Container(
height: 160, height: 160,
width: double.infinity, width: double.infinity,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Stack( Stack(
children: [ children: [
Hero( Hero(
tag: 'gpodder.net', tag: 'gpodder.net',
child: CircleAvatar( child: CircleAvatar(
minRadius: 40, minRadius: 40,
backgroundColor: context.primaryColor, backgroundColor: context.primaryColor,
child: SizedBox( child: SizedBox(
height: 60, height: 60,
width: 60, width: 60,
child: Image.asset('assets/gpodder.png')), child: Image.asset('assets/gpodder.png')),
),
), ),
if (_syncing)
Positioned(
left: context.width / 2 - 40,
child: SizedBox(
height: 80,
width: 80,
child: CircularProgressIndicator(
strokeWidth: 1,
),
),
),
if (_syncing)
Positioned(
bottom: 39,
left: context.width / 2 - 12,
child: _OpenEye()),
if (_syncing)
Positioned(
bottom: 39,
left: context.width / 2 + 3,
child: _OpenEye()),
],
),
Text(
loginInfo.isEmpty
? s.intergateWith('gpodder.net')
: s.loggedInAs(loginInfo.first),
style: TextStyle(color: Colors.purple[700])),
ButtonTheme(
height: 32,
child: OutlineButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
side: BorderSide(color: Colors.purple[700])),
highlightedBorderColor: Colors.purple[700],
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
LineIcons.user,
color: Colors.purple[700],
size: context.textTheme.headline6.fontSize,
),
SizedBox(width: 10),
Text(loginInfo.isEmpty ? s.login : s.logout,
style:
TextStyle(color: Colors.purple[700])),
],
),
onPressed: () {
if (loginInfo.isEmpty) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => _LoginGpodder(),
fullscreenDialog: true));
} else {
_logout();
}
},
), ),
), if (_syncing)
], Positioned(
), left: context.width / 2 - 40,
); child: SizedBox(
}), height: 80,
FutureBuilder<List<String>>( width: 80,
future: _getLoginInfo(), child: CircularProgressIndicator(
initialData: [], strokeWidth: 1,
builder: (context, snapshot) { ),
final loginInfo = snapshot.data; ),
if (loginInfo.isNotEmpty) {
return ListTile(
contentPadding:
const EdgeInsets.only(left: 70.0, right: 20),
onTap: _syncNow,
title: Text(s.syncNow),
subtitle: FutureBuilder<Tuple2<int, int>>(
future: _getSyncStatus(),
initialData: Tuple2(0, 0),
builder: (context, snapshot) {
final dateTime = snapshot.data.item1;
final status = snapshot.data.item2;
return Wrap(
children: [
Text(
'${s.lastUpdate}: ${dateTime.toDate(context)}'),
SizedBox(width: 8),
Text('${s.status}: '),
_syncStauts(status),
],
);
}),
);
}
return Center();
}),
Divider(height: 1),
Container(
height: 30.0,
padding: EdgeInsets.fromLTRB(70, 0, 70, 0),
alignment: Alignment.centerLeft,
child: Text(s.subscribe,
style: context.textTheme.bodyText1
.copyWith(color: context.accentColor)),
),
Padding(
padding:
EdgeInsets.only(left: 70.0, right: 20, top: 10, bottom: 10),
child: Text(s.subscribeExportDes),
),
Padding(
padding: EdgeInsets.only(left: 70.0, right: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
ButtonTheme(
height: 32,
child: OutlineButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
side: BorderSide(color: Colors.green[700])),
highlightedBorderColor: Colors.green[700],
child: Row(
children: [
Icon(
LineIcons.save,
color: Colors.green[700],
size: context.textTheme.headline6.fontSize,
), ),
SizedBox(width: 10), if (_syncing)
Text(s.save, Positioned(
style: TextStyle(color: Colors.green[700])), bottom: 39,
], left: context.width / 2 - 12,
child: _OpenEye()),
if (_syncing)
Positioned(
bottom: 39,
left: context.width / 2 + 3,
child: _OpenEye()),
],
),
Text(
loginInfo.isEmpty
? s.intergateWith('gpodder.net')
: s.loggedInAs(loginInfo.first),
style: TextStyle(color: Colors.purple[700])),
ButtonTheme(
height: 32,
child: OutlineButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
side: BorderSide(color: Colors.purple[700])),
highlightedBorderColor: Colors.purple[700],
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
LineIcons.user,
color: Colors.purple[700],
size: context.textTheme.headline6.fontSize,
),
SizedBox(width: 10),
Text(loginInfo.isEmpty ? s.login : s.logout,
style:
TextStyle(color: Colors.purple[700])),
],
),
onPressed: () {
if (loginInfo.isEmpty) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => _LoginGpodder(),
fullscreenDialog: true));
} else {
_logout();
}
},
), ),
onPressed: () async { ),
var file = await _exportOmpl(context); ],
await _saveFile(file);
}),
), ),
SizedBox(width: 10), );
ButtonTheme( }),
height: 32, FutureBuilder<List<String>>(
child: OutlineButton( future: _getLoginInfo(),
shape: RoundedRectangleBorder( initialData: [],
borderRadius: BorderRadius.circular(100.0), builder: (context, snapshot) {
side: BorderSide(color: Colors.blue[700])), final loginInfo = snapshot.data;
highlightedBorderColor: Colors.blue[700], if (loginInfo.isNotEmpty) {
child: Row( return ListTile(
children: [ contentPadding:
Icon( const EdgeInsets.only(left: 70.0, right: 20),
Icons.share, onTap: _syncNow,
size: context.textTheme.headline6.fontSize, title: Text(s.syncNow),
color: Colors.blue[700], subtitle: FutureBuilder<List<int>>(
), future: _getSyncStatus(),
SizedBox(width: 10), initialData: [0, 0],
Text(s.share, builder: (context, snapshot) {
style: TextStyle(color: Colors.blue[700])), final dateTime = snapshot.data[0];
], final status = snapshot.data[1];
), return Wrap(
onPressed: () async { children: [
var file = await _exportOmpl(context); Text(
await _shareFile(file); '${s.lastUpdate}: ${dateTime.toDate(context)}'),
SizedBox(width: 8),
Text('${s.status}: '),
_syncStauts(status),
],
);
}), }),
) );
], }
), return Center();
), }),
Divider(), // ListTile(
Container( // onTap: () async {
height: 30.0, // final subscribeWorker = context.read<GroupList>();
padding: EdgeInsets.symmetric(horizontal: 70), // await subscribeWorker.cancelWork();
alignment: Alignment.centerLeft, // subscribeWorker.setWorkManager();
child: Text(s.settings, // },
style: context.textTheme.bodyText1 // title: Text('reset'),
.copyWith(color: Theme.of(context).accentColor)), // ),
), Divider(height: 1),
Padding( Container(
padding: height: 30.0,
EdgeInsets.only(left: 70.0, right: 20, top: 10, bottom: 10), padding: EdgeInsets.fromLTRB(70, 0, 70, 0),
child: Text(s.settingsExportDes), alignment: Alignment.centerLeft,
), child: Text(s.subscribe,
Padding( style: context.textTheme.bodyText1
padding: EdgeInsets.only(left: 70.0, right: 10), .copyWith(color: context.accentColor)),
child: Wrap(children: [ ),
Padding(
padding:
EdgeInsets.only(left: 70.0, right: 20, top: 10, bottom: 10),
child: Text(s.subscribeExportDes),
),
Padding(
padding: EdgeInsets.only(left: 70.0, right: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
ButtonTheme( ButtonTheme(
height: 32, height: 32,
child: OutlineButton( child: OutlineButton(
@ -416,7 +358,6 @@ class _DataBackupState extends State<DataBackup> {
side: BorderSide(color: Colors.green[700])), side: BorderSide(color: Colors.green[700])),
highlightedBorderColor: Colors.green[700], highlightedBorderColor: Colors.green[700],
child: Row( child: Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( Icon(
LineIcons.save, LineIcons.save,
@ -429,7 +370,7 @@ class _DataBackupState extends State<DataBackup> {
], ],
), ),
onPressed: () async { onPressed: () async {
var file = await _exportSetting(context); var file = await _exportOmpl(context);
await _saveFile(file); await _saveFile(file);
}), }),
), ),
@ -442,7 +383,6 @@ class _DataBackupState extends State<DataBackup> {
side: BorderSide(color: Colors.blue[700])), side: BorderSide(color: Colors.blue[700])),
highlightedBorderColor: Colors.blue[700], highlightedBorderColor: Colors.blue[700],
child: Row( child: Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( Icon(
Icons.share, Icons.share,
@ -455,41 +395,113 @@ class _DataBackupState extends State<DataBackup> {
], ],
), ),
onPressed: () async { onPressed: () async {
var file = await _exportSetting(context); var file = await _exportOmpl(context);
await _shareFile(file); await _shareFile(file);
}), }),
), )
SizedBox(width: 10), ],
ButtonTheme( ),
height: 32, ),
child: OutlineButton( Divider(),
highlightedBorderColor: Colors.red[700], Container(
height: 30.0,
padding: EdgeInsets.symmetric(horizontal: 70),
alignment: Alignment.centerLeft,
child: Text(s.settings,
style: context.textTheme.bodyText1
.copyWith(color: Theme.of(context).accentColor)),
),
Padding(
padding:
EdgeInsets.only(left: 70.0, right: 20, top: 10, bottom: 10),
child: Text(s.settingsExportDes),
),
Padding(
padding: EdgeInsets.only(left: 70.0, right: 10),
child: Wrap(children: [
ButtonTheme(
height: 32,
child: OutlineButton(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0), borderRadius: BorderRadius.circular(100.0),
side: BorderSide(color: Colors.red[700])), side: BorderSide(color: Colors.green[700])),
highlightedBorderColor: Colors.green[700],
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( Icon(
LineIcons.paperclip_solid, LineIcons.save,
color: Colors.green[700],
size: context.textTheme.headline6.fontSize, size: context.textTheme.headline6.fontSize,
color: Colors.red[700],
), ),
SizedBox(width: 10), SizedBox(width: 10),
Text(s.import, Text(s.save,
style: TextStyle(color: Colors.red[700])), style: TextStyle(color: Colors.green[700])),
], ],
), ),
onPressed: () { onPressed: () async {
_getFilePath(context); var file = await _exportSetting(context);
}, await _saveFile(file);
}),
),
SizedBox(width: 10),
ButtonTheme(
height: 32,
child: OutlineButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
side: BorderSide(color: Colors.blue[700])),
highlightedBorderColor: Colors.blue[700],
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.share,
size: context.textTheme.headline6.fontSize,
color: Colors.blue[700],
),
SizedBox(width: 10),
Text(s.share,
style: TextStyle(color: Colors.blue[700])),
],
),
onPressed: () async {
var file = await _exportSetting(context);
await _shareFile(file);
}),
),
SizedBox(width: 10),
ButtonTheme(
height: 32,
child: OutlineButton(
highlightedBorderColor: Colors.red[700],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
side: BorderSide(color: Colors.red[700])),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
LineIcons.paperclip_solid,
size: context.textTheme.headline6.fontSize,
color: Colors.red[700],
),
SizedBox(width: 10),
Text(s.import,
style: TextStyle(color: Colors.red[700])),
],
), ),
onPressed: () {
_getFilePath(context);
},
), ),
]), ),
), ]),
Divider(height: 1) ),
], Divider(height: 1)
)), ],
),
),
); );
} }
} }
@ -634,7 +646,7 @@ class __LoginGpodderState extends State<_LoginGpodder> {
} }
} }
await subscribeWorker.cancelWork(); await subscribeWorker.cancelWork();
subscribeWorker.setWorkManager(4); subscribeWorker.setWorkManager();
} }
String _validateName(String value) { String _validateName(String value) {
@ -750,6 +762,8 @@ class __LoginGpodderState extends State<_LoginGpodder> {
child: Text( child: Text(
s.gpodderLoginDes, s.gpodderLoginDes,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style:
context.textTheme.subtitle1.copyWith(height: 2),
), ),
), ),
Center( Center(

View File

@ -107,7 +107,7 @@ class _LanguagesSettingState extends State<LanguagesSetting> {
), ),
Divider(height: 1), Divider(height: 1),
ListTile( ListTile(
title: Text('português'), title: Text('Português'),
onTap: () => _setLocale(Locale('pt')), onTap: () => _setLocale(Locale('pt')),
contentPadding: const EdgeInsets.only(left: 20, right: 20), contentPadding: const EdgeInsets.only(left: 20, right: 20),
trailing: Radio<Locale>( trailing: Radio<Locale>(

View File

@ -30,6 +30,7 @@ void callbackDispatcher() {
final status = await gpodder.getChanges(); final status = await gpodder.getChanges();
if (status == 200) { if (status == 200) {
await gpodder.updateChange(); await gpodder.updateChange();
developer.log('Gpodder sync successfully');
} }
return Future.value(true); return Future.value(true);
}); });
@ -310,14 +311,14 @@ class GroupList extends ChangeNotifier {
} }
} }
void setWorkManager(int hour) { void setWorkManager() {
Workmanager.initialize( Workmanager.initialize(
callbackDispatcher, callbackDispatcher,
isInDebugMode: false, isInDebugMode: false,
); );
Workmanager.registerPeriodicTask("2", "gpodder_sync", Workmanager.registerPeriodicTask("2", "gpodder_sync",
frequency: Duration(hours: hour), frequency: Duration(hours: 4),
initialDelay: Duration(seconds: 10), initialDelay: Duration(seconds: 1),
constraints: Constraints( constraints: Constraints(
networkType: NetworkType.connected, networkType: NetworkType.connected,
)); ));