192 lines
5.9 KiB
Dart
192 lines
5.9 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);
|
||
|
print(filePath);
|
||
|
dbHelper.saveMediaId(
|
||
|
episodeTask.episode.enclosureUrl, filePath, episodeTask.taskId);
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
}
|