tsacdop-podcast-app-android/lib/state/download_state.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 '../type/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);
}
}