Auto download

This commit is contained in:
stonegate 2020-06-13 01:56:13 +08:00
parent e69a2dbc00
commit 0b20c24984
12 changed files with 169 additions and 71 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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';

View File

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

View File

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