Auto download
This commit is contained in:
parent
e69a2dbc00
commit
0b20c24984
|
@ -42,14 +42,14 @@ class Import extends StatelessWidget {
|
|||
// For safety
|
||||
if (episodes.length < 100)
|
||||
episodes.forEach((episode) {
|
||||
downloader.startTask(episode, showNotification: false);
|
||||
downloader.startTask(episode, showNotification: true);
|
||||
});
|
||||
} else if (result == ConnectivityResult.wifi) {
|
||||
List<EpisodeBrief> episodes = await dbHelper.getNewEpisodes('all');
|
||||
//For safety
|
||||
if (episodes.length < 100)
|
||||
episodes.forEach((episode) {
|
||||
downloader.startTask(episode, showNotification: false);
|
||||
downloader.startTask(episode, showNotification: true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ class Import extends StatelessWidget {
|
|||
case SubscribeState.start:
|
||||
return importColumn("Subscribe ${item.title}", context);
|
||||
case SubscribeState.subscribe:
|
||||
groupList.subscribeNewPodcast(item.id);
|
||||
return importColumn("Fetch data ${item.title}", context);
|
||||
case SubscribeState.fetch:
|
||||
groupList.subscribeNewPodcast(item.id);
|
||||
// groupList.updatePodcast(item.id);
|
||||
return importColumn("Subscribe success ${item.title}", context);
|
||||
case SubscribeState.exist:
|
||||
|
|
|
@ -328,36 +328,28 @@ class _PlayedHistoryState extends State<PlayedHistory>
|
|||
Text(snapshot.data[index].title),
|
||||
],
|
||||
),
|
||||
subtitle: Row(
|
||||
children: <Widget>[
|
||||
_status
|
||||
? Text(DateTime.now()
|
||||
.difference(snapshot
|
||||
.data[index].subDate)
|
||||
.inDays
|
||||
.toString() +
|
||||
' day ago')
|
||||
: Text(snapshot.data[index].delDate
|
||||
.difference(snapshot
|
||||
.data[index].subDate)
|
||||
.inDays
|
||||
.toString() +
|
||||
' day on your device'),
|
||||
Spacer(),
|
||||
!_status
|
||||
? Text(
|
||||
'Removed at ' +
|
||||
DateFormat.yMd()
|
||||
.add_jm()
|
||||
.format(snapshot
|
||||
.data[index]
|
||||
.delDate),
|
||||
style: TextStyle(
|
||||
color: Colors.red),
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
),
|
||||
subtitle: _status
|
||||
? Text(DateTime.now()
|
||||
.difference(snapshot
|
||||
.data[index].subDate)
|
||||
.inDays
|
||||
.toString() +
|
||||
' day ago')
|
||||
: Text(
|
||||
'Removed at ' +
|
||||
DateFormat.yMd()
|
||||
.add_jm()
|
||||
.format(snapshot
|
||||
.data[index].delDate),
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
// Text(snapshot.data[index].delDate
|
||||
// .difference(snapshot
|
||||
// .data[index].subDate)
|
||||
// .inDays
|
||||
// .toString() +
|
||||
// ' day on your device'),
|
||||
|
||||
trailing: !_status
|
||||
? Material(
|
||||
color: Colors.transparent,
|
||||
|
|
|
@ -133,7 +133,7 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
|||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Episode popup menu',
|
||||
style: Theme.of(context)
|
||||
|
@ -156,9 +156,12 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
|||
subtitle: Text('Change the menu when long tap episode'),
|
||||
),
|
||||
Divider(height: 2),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Default grid view',
|
||||
style: Theme.of(context)
|
||||
|
|
|
@ -36,7 +36,7 @@ class PlaySetting extends StatelessWidget {
|
|||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Playlist',
|
||||
style: Theme.of(context)
|
||||
|
|
|
@ -132,7 +132,7 @@ class _SettingsState extends State<Settings>
|
|||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Prefrence',
|
||||
style: Theme.of(context)
|
||||
|
@ -241,7 +241,7 @@ class _SettingsState extends State<Settings>
|
|||
children: <Widget>[
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Info',
|
||||
style: Theme.of(context)
|
||||
|
|
|
@ -105,7 +105,7 @@ class _StorageSettingState extends State<StorageSetting>
|
|||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Network',
|
||||
style: Theme.of(context)
|
||||
|
@ -174,7 +174,7 @@ class _StorageSettingState extends State<StorageSetting>
|
|||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Storage',
|
||||
style: Theme.of(context)
|
||||
|
|
|
@ -40,7 +40,7 @@ class SyncingSetting extends StatelessWidget {
|
|||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Syncing',
|
||||
style: Theme.of(context)
|
||||
|
@ -48,6 +48,9 @@ class SyncingSetting extends StatelessWidget {
|
|||
.bodyText1
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
),
|
||||
ListView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
|
|
|
@ -32,7 +32,7 @@ class ThemeSetting extends StatelessWidget {
|
|||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Interface',
|
||||
style: Theme.of(context)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:ui';
|
||||
|
@ -7,9 +8,9 @@ import 'package:flutter/rendering.dart';
|
|||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:tsacdop/local_storage/key_value_storage.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
|
||||
import '../local_storage/key_value_storage.dart';
|
||||
import '../local_storage/sqflite_localpodcast.dart';
|
||||
import '../type/episodebrief.dart';
|
||||
|
||||
class EpisodeTask {
|
||||
|
@ -32,6 +33,107 @@ void downloadCallback(String id, DownloadTaskStatus status, int progress) {
|
|||
send.send([id, status, progress]);
|
||||
}
|
||||
|
||||
void autoDownloadCallback(String id, DownloadTaskStatus status, int progress) {
|
||||
print('Autodownload callback task in $id status ($status) $progress');
|
||||
final SendPort send =
|
||||
IsolateNameServer.lookupPortByName('auto_downloader_send_port');
|
||||
send.send([id, status, progress]);
|
||||
}
|
||||
|
||||
//For background auto downlaod
|
||||
class AutoDownloader {
|
||||
DBHelper dbHelper = DBHelper();
|
||||
List<EpisodeTask> _episodeTasks = [];
|
||||
Completer _completer = Completer();
|
||||
AutoDownloader() {
|
||||
FlutterDownloader.registerCallback(autoDownloadCallback);
|
||||
}
|
||||
|
||||
bindBackgroundIsolate() {
|
||||
print('start listen');
|
||||
ReceivePort _port = ReceivePort();
|
||||
bool isSuccess = IsolateNameServer.registerPortWithName(
|
||||
_port.sendPort, 'auto_downloader_send_port');
|
||||
if (!isSuccess) {
|
||||
_unbindBackgroundIsolate();
|
||||
//bindBackgroundIsolate();
|
||||
return;
|
||||
}
|
||||
_port.listen((dynamic data) {
|
||||
String id = data[0];
|
||||
DownloadTaskStatus status = data[1];
|
||||
int progress = data[2];
|
||||
_episodeTasks.forEach((episodeTask) {
|
||||
if (episodeTask.taskId == id) {
|
||||
episodeTask.status = status;
|
||||
episodeTask.progress = progress;
|
||||
if (status == DownloadTaskStatus.complete) {
|
||||
_saveMediaId(episodeTask);
|
||||
} else if (status == DownloadTaskStatus.failed) {
|
||||
_episodeTasks.removeWhere((element) =>
|
||||
element.episode.enclosureUrl ==
|
||||
episodeTask.episode.enclosureUrl);
|
||||
if (_episodeTasks.length == 0) _unbindBackgroundIsolate();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _unbindBackgroundIsolate() {
|
||||
IsolateNameServer.removePortNameMapping('auto_downloader_send_port');
|
||||
_completer?.complete();
|
||||
}
|
||||
|
||||
Future _saveMediaId(EpisodeTask episodeTask) async {
|
||||
final completeTask = await FlutterDownloader.loadTasksWithRawQuery(
|
||||
query: "SELECT * FROM task WHERE task_id = '${episodeTask.taskId}'");
|
||||
String filePath = 'file://' +
|
||||
path.join(completeTask.first.savedDir,
|
||||
Uri.encodeComponent(completeTask.first.filename));
|
||||
await dbHelper.saveMediaId(
|
||||
episodeTask.episode.enclosureUrl, filePath, episodeTask.taskId);
|
||||
_episodeTasks.removeWhere((element) =>
|
||||
element.episode.enclosureUrl == episodeTask.episode.enclosureUrl);
|
||||
if (_episodeTasks.length == 0) _unbindBackgroundIsolate();
|
||||
}
|
||||
|
||||
Future startTask(List<EpisodeBrief> episodes,
|
||||
{bool showNotification = true}) async {
|
||||
episodes.forEach((episode) async {
|
||||
final dir = await getExternalStorageDirectory();
|
||||
String localPath = path.join(dir.path, episode.feedTitle);
|
||||
final saveDir = Directory(localPath);
|
||||
bool hasExisted = await saveDir.exists();
|
||||
if (!hasExisted) {
|
||||
saveDir.create();
|
||||
}
|
||||
DateTime now = DateTime.now();
|
||||
String datePlus = now.year.toString() +
|
||||
now.month.toString() +
|
||||
now.day.toString() +
|
||||
now.second.toString();
|
||||
String fileName = episode.title +
|
||||
datePlus +
|
||||
'.' +
|
||||
episode.enclosureUrl.split('/').last.split('.').last;
|
||||
String taskId = await FlutterDownloader.enqueue(
|
||||
fileName: fileName,
|
||||
url: episode.enclosureUrl,
|
||||
savedDir: localPath,
|
||||
showNotification: showNotification,
|
||||
openFileFromNotification: false,
|
||||
);
|
||||
_episodeTasks.add(EpisodeTask(episode, taskId));
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.saveDownloaded(episode.enclosureUrl, taskId);
|
||||
});
|
||||
await _completer.future;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//For download episode inside app
|
||||
class DownloadState extends ChangeNotifier {
|
||||
DBHelper dbHelper = DBHelper();
|
||||
List<EpisodeTask> _episodeTasks = [];
|
||||
|
@ -39,13 +141,13 @@ class DownloadState extends ChangeNotifier {
|
|||
|
||||
DownloadState() {
|
||||
_autoDelete();
|
||||
_bindBackgroundIsolate();
|
||||
FlutterDownloader.registerCallback(downloadCallback);
|
||||
}
|
||||
|
||||
@override
|
||||
void addListener(VoidCallback listener) async {
|
||||
_loadTasks();
|
||||
_bindBackgroundIsolate();
|
||||
FlutterDownloader.registerCallback(downloadCallback);
|
||||
super.addListener(listener);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'dart:collection';
|
||||
import 'dart:core';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tsacdop/local_storage/key_value_storage.dart';
|
||||
|
|
|
@ -76,7 +76,5 @@ Future<void> refreshIsolateEntryPoint(SendPort sendPort) async {
|
|||
int updateCount = await dbHelper.updatePodcastRss(podcastLocal);
|
||||
print('Refresh ' + podcastLocal.title + updateCount.toString());
|
||||
});
|
||||
// KeyValueStorage refreshcountstorage = KeyValueStorage('refreshcount');
|
||||
// await refreshcountstorage.saveInt(i);
|
||||
sendPort.send("done");
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:ui';
|
||||
import 'package:connectivity/connectivity.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:workmanager/workmanager.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
|
||||
import '../local_storage/sqflite_localpodcast.dart';
|
||||
import '../local_storage/key_value_storage.dart';
|
||||
|
@ -20,30 +23,27 @@ void callbackDispatcher() {
|
|||
KeyValueStorage lastWorkStorage = KeyValueStorage(lastWorkKey);
|
||||
int lastWork = await lastWorkStorage.getInt();
|
||||
await Future.forEach<PodcastLocal>(podcastList, (podcastLocal) async {
|
||||
int updateCount =
|
||||
await dbHelper.updatePodcastRss(podcastLocal, removeMark: lastWork);
|
||||
bool autoDownload = await dbHelper.getAutoDownload(podcastLocal.id);
|
||||
if (autoDownload && updateCount > 0) {
|
||||
var result = await Connectivity().checkConnectivity();
|
||||
KeyValueStorage autoDownloadStorage =
|
||||
KeyValueStorage(autoDownloadNetworkKey);
|
||||
int autoDownloadNetwork = await autoDownloadStorage.getInt();
|
||||
if (autoDownloadNetwork == 1) {
|
||||
List<EpisodeBrief> episodes =
|
||||
await dbHelper.getNewEpisodes(podcastLocal.id);
|
||||
episodes.forEach((episode) {
|
||||
DownloadState().startTask(episode, showNotification: true);
|
||||
});
|
||||
} else if (result == ConnectivityResult.wifi) {
|
||||
List<EpisodeBrief> episodes =
|
||||
await dbHelper.getNewEpisodes(podcastLocal.id);
|
||||
episodes.forEach((episode) {
|
||||
DownloadState().startTask(episode, showNotification: true);
|
||||
});
|
||||
}
|
||||
}
|
||||
await dbHelper.updatePodcastRss(podcastLocal, removeMark: lastWork);
|
||||
print('Refresh ' + podcastLocal.title);
|
||||
});
|
||||
await FlutterDownloader.initialize();
|
||||
AutoDownloader downloader = AutoDownloader();
|
||||
downloader.bindBackgroundIsolate();
|
||||
KeyValueStorage autoDownloadStorage =
|
||||
KeyValueStorage(autoDownloadNetworkKey);
|
||||
int autoDownloadNetwork = await autoDownloadStorage.getInt();
|
||||
var result = await Connectivity().checkConnectivity();
|
||||
if (autoDownloadNetwork == 1) {
|
||||
List<EpisodeBrief> episodes = await dbHelper.getNewEpisodes('all');
|
||||
// For safety
|
||||
if (episodes.length < 100 && episodes.length > 0)
|
||||
await downloader.startTask(episodes);
|
||||
} else if (result == ConnectivityResult.wifi) {
|
||||
List<EpisodeBrief> episodes = await dbHelper.getNewEpisodes('all');
|
||||
//For safety
|
||||
if (episodes.length < 100 && episodes.length > 0)
|
||||
await downloader.startTask(episodes);
|
||||
}
|
||||
await lastWorkStorage.saveInt(1);
|
||||
KeyValueStorage refreshstorage = KeyValueStorage(refreshdateKey);
|
||||
await refreshstorage.saveInt(DateTime.now().millisecondsSinceEpoch);
|
||||
|
|
Loading…
Reference in New Issue