195 lines
6.1 KiB
Dart
195 lines
6.1 KiB
Dart
import 'dart:io';
|
|
import 'dart:isolate';
|
|
import 'dart:ui';
|
|
|
|
import 'package:flutter/material.dart';
|
|
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/sqflite_localpodcast.dart';
|
|
|
|
import 'episodebrief.dart';
|
|
|
|
class EpisodeTask {
|
|
final String taskId;
|
|
int progress;
|
|
DownloadTaskStatus status;
|
|
final EpisodeBrief episode;
|
|
EpisodeTask(
|
|
this.episode,
|
|
this.taskId, {
|
|
this.progress = 0,
|
|
this.status = DownloadTaskStatus.undefined,
|
|
});
|
|
}
|
|
|
|
void downloadCallback(String id, DownloadTaskStatus status, int progress) {
|
|
print('Homepage callback task in $id status ($status) $progress');
|
|
final SendPort send =
|
|
IsolateNameServer.lookupPortByName('downloader_send_port');
|
|
send.send([id, status, progress]);
|
|
}
|
|
|
|
class DownloadState extends ChangeNotifier {
|
|
DBHelper dbHelper = DBHelper();
|
|
List<EpisodeTask> _episodeTasks = [];
|
|
List<EpisodeTask> get episodeTasks => _episodeTasks;
|
|
|
|
@override
|
|
void addListener(VoidCallback listener) async {
|
|
_loadTasks();
|
|
_bindBackgroundIsolate();
|
|
FlutterDownloader.registerCallback(downloadCallback);
|
|
super.addListener(listener);
|
|
}
|
|
|
|
_loadTasks() async {
|
|
_episodeTasks = [];
|
|
DBHelper dbHelper = DBHelper();
|
|
var tasks = await FlutterDownloader.loadTasks();
|
|
if (tasks.length != 0)
|
|
await Future.forEach(tasks, (DownloadTask task) async {
|
|
EpisodeBrief episode = await dbHelper.getRssItemWithUrl(task.url);
|
|
_episodeTasks.add(EpisodeTask(episode, task.taskId,
|
|
progress: task.progress, status: task.status));
|
|
});
|
|
print(_episodeTasks.length);
|
|
notifyListeners();
|
|
}
|
|
|
|
void _bindBackgroundIsolate() {
|
|
ReceivePort _port = ReceivePort();
|
|
bool isSuccess = IsolateNameServer.registerPortWithName(
|
|
_port.sendPort, '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).then((value) {
|
|
notifyListeners();
|
|
});
|
|
} else
|
|
notifyListeners();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
Future _saveMediaId(EpisodeTask episodeTask) async {
|
|
episodeTask.status = DownloadTaskStatus.complete;
|
|
final completeTask = await FlutterDownloader.loadTasksWithRawQuery(
|
|
query: "SELECT * FROM task WHERE task_id = '${episodeTask.taskId}'");
|
|
String filePath = 'file://' +
|
|
path.join(completeTask.first.savedDir, completeTask.first.filename);
|
|
dbHelper.saveMediaId(
|
|
episodeTask.episode.enclosureUrl, filePath, episodeTask.taskId);
|
|
EpisodeBrief episode =
|
|
await dbHelper.getRssItemWithUrl(episodeTask.episode.enclosureUrl);
|
|
_removeTask(episodeTask.episode);
|
|
_episodeTasks.add(EpisodeTask(episode, episodeTask.taskId,
|
|
progress: 100, status: DownloadTaskStatus.complete));
|
|
}
|
|
|
|
void _unbindBackgroundIsolate() {
|
|
IsolateNameServer.removePortNameMapping('downloader_send_port');
|
|
}
|
|
|
|
EpisodeTask episodeToTask(EpisodeBrief episode) {
|
|
return _episodeTasks
|
|
.firstWhere((task) => task.episode.enclosureUrl == episode.enclosureUrl,
|
|
orElse: () {
|
|
return EpisodeTask(
|
|
episode,
|
|
'',
|
|
);
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_unbindBackgroundIsolate();
|
|
super.dispose();
|
|
}
|
|
|
|
Future startTask(EpisodeBrief 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();
|
|
}
|
|
String taskId = await FlutterDownloader.enqueue(
|
|
url: episode.enclosureUrl,
|
|
savedDir: localPath,
|
|
showNotification: true,
|
|
openFileFromNotification: false,
|
|
);
|
|
_episodeTasks.add(EpisodeTask(episode, taskId));
|
|
notifyListeners();
|
|
}
|
|
|
|
Future pauseTask(EpisodeBrief episode) async {
|
|
EpisodeTask task = episodeToTask(episode);
|
|
await FlutterDownloader.pause(taskId: task.taskId);
|
|
}
|
|
|
|
Future resumeTask(EpisodeBrief episode) async {
|
|
EpisodeTask task = episodeToTask(episode);
|
|
String newTaskId = await FlutterDownloader.resume(taskId: task.taskId);
|
|
int index = _episodeTasks.indexOf(task);
|
|
_removeTask(episode);
|
|
FlutterDownloader.remove(taskId: task.taskId);
|
|
var dbHelper = DBHelper();
|
|
_episodeTasks.insert(index, EpisodeTask(episode, newTaskId));
|
|
await dbHelper.saveDownloaded(newTaskId, episode.enclosureUrl);
|
|
}
|
|
|
|
Future retryTask(EpisodeBrief episode) async {
|
|
EpisodeTask task = episodeToTask(episode);
|
|
String newTaskId = await FlutterDownloader.retry(taskId: task.taskId);
|
|
await FlutterDownloader.remove(taskId: task.taskId);
|
|
int index = _episodeTasks.indexOf(task);
|
|
_removeTask(episode);
|
|
var dbHelper = DBHelper();
|
|
_episodeTasks.insert(index, EpisodeTask(episode, newTaskId));
|
|
await dbHelper.saveDownloaded(newTaskId, episode.enclosureUrl);
|
|
}
|
|
|
|
Future removeTask(EpisodeBrief episode) async {
|
|
EpisodeTask task = episodeToTask(episode);
|
|
await FlutterDownloader.remove(
|
|
taskId: task.taskId, shouldDeleteContent: false);
|
|
}
|
|
|
|
Future delTask(EpisodeBrief episode) async {
|
|
EpisodeTask task = episodeToTask(episode);
|
|
await FlutterDownloader.remove(
|
|
taskId: task.taskId, shouldDeleteContent: true);
|
|
await dbHelper.delDownloaded(episode.enclosureUrl);
|
|
_episodeTasks.forEach((episodeTask) {
|
|
if (episodeTask.taskId == task.taskId)
|
|
episodeTask.status = DownloadTaskStatus.undefined;
|
|
notifyListeners();
|
|
});
|
|
_removeTask(episode);
|
|
}
|
|
|
|
_removeTask(EpisodeBrief episode) {
|
|
_episodeTasks.removeWhere(
|
|
(element) => element.episode.enclosureUrl == episode.enclosureUrl);
|
|
}
|
|
}
|