Skip to content

Commit

Permalink
Improve Task Queue
Browse files Browse the repository at this point in the history
  • Loading branch information
Soopyboo32 committed Dec 21, 2024
1 parent ff771fd commit ae482a7
Show file tree
Hide file tree
Showing 11 changed files with 401 additions and 273 deletions.
6 changes: 5 additions & 1 deletion src/screens/library/LibraryScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,10 @@ const LibraryScreen = ({ navigation }: LibraryScreenProps) => {
library[index].id !== 2 &&
ServiceManager.manager.addTask({
name: 'UPDATE_LIBRARY',
data: library[index].id,
data: {
categoryId: library[index].id,
categoryName: library[index].name,
},
}),
},
{
Expand Down Expand Up @@ -289,6 +292,7 @@ const LibraryScreen = ({ navigation }: LibraryScreenProps) => {
) : null}
<LibraryView
categoryId={route.id}
categoryName={route.name}
novels={route.novels}
selectedNovelIds={selectedNovelIds}
setSelectedNovelIds={setSelectedNovelIds}
Expand Down
7 changes: 6 additions & 1 deletion src/screens/library/components/LibraryListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ServiceManager from '@services/ServiceManager';

interface Props {
categoryId: number;
categoryName: string;
novels: LibraryNovelInfo[];
selectedNovelIds: number[];
setSelectedNovelIds: React.Dispatch<React.SetStateAction<number[]>>;
Expand All @@ -24,6 +25,7 @@ interface Props {

export const LibraryView: React.FC<Props> = ({
categoryId,
categoryName,
novels,
selectedNovelIds,
setSelectedNovelIds,
Expand Down Expand Up @@ -62,7 +64,10 @@ export const LibraryView: React.FC<Props> = ({
setRefreshing(true);
ServiceManager.manager.addTask({
name: 'UPDATE_LIBRARY',
data: categoryId,
data: {
categoryId,
categoryName,
},
});
setRefreshing(false);
};
Expand Down
24 changes: 16 additions & 8 deletions src/screens/more/TaskQueueScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ import { showToast } from '../../utils/showToast';
import { getString } from '@strings/translations';
import { Appbar, EmptyView } from '@components';
import { TaskQueueScreenProps } from '@navigators/types';
import ServiceManager, { BackgroundTask } from '@services/ServiceManager';
import ServiceManager, { QueuedBackgroundTask } from '@services/ServiceManager';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useMMKVObject } from 'react-native-mmkv';

const DownloadQueue = ({ navigation }: TaskQueueScreenProps) => {
const theme = useTheme();
const { bottom } = useSafeAreaInsets();
const [taskQueue] = useMMKVObject<BackgroundTask[]>(
const [taskQueue] = useMMKVObject<QueuedBackgroundTask[]>(
ServiceManager.manager.STORE_KEY,
);
const [isRunning, setIsRunning] = useState(ServiceManager.manager.isRunning);
Expand All @@ -34,6 +34,8 @@ const DownloadQueue = ({ navigation }: TaskQueueScreenProps) => {
}
}, [taskQueue]);

//TODO: there should probably be a way to cancel a specific task from this screen

return (
<>
<Appbar
Expand Down Expand Up @@ -71,15 +73,21 @@ const DownloadQueue = ({ navigation }: TaskQueueScreenProps) => {
contentContainerStyle={{ flexGrow: 1, paddingBottom: 100 }}
keyExtractor={(item, index) => 'task_' + index}
data={taskQueue || []}
renderItem={({ item, index }) => (
renderItem={({ item }) => (
<View style={{ padding: 16 }}>
<Text style={{ color: theme.onSurface }}>
{item.name} - {ServiceManager.manager.getTaskDescription(item)}
</Text>
<Text style={{ color: theme.onSurface }}>{item.meta.name}</Text>
{item.meta.progressText ? (
<Text style={{ color: theme.onSurfaceVariant }}>
{item.meta.progressText}
</Text>
) : null}
<ProgressBar
indeterminate={taskQueue && taskQueue.length > 0 && index === 0}
indeterminate={
item.meta.isRunning && item.meta.progress === undefined
}
progress={item.meta.progress}
color={theme.primary}
style={{ marginTop: 8 }}
style={{ marginTop: 8, backgroundColor: theme.surface2 }}
/>
</View>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/screens/updates/UpdatesScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const UpdatesScreen = ({ navigation }: UpdateScreenProps) => {
e.preventDefault();

navigation.navigate('MoreStack', {
screen: 'Downloads',
screen: 'TaskQueue',
});
}
}),
Expand Down
112 changes: 88 additions & 24 deletions src/services/ServiceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ export type BackgroundTask =
}
| {
name: 'UPDATE_LIBRARY';
data?: number;
data?: {
categoryId?: number;
categoryName?: string;
};
}
| { name: 'DRIVE_BACKUP'; data: DriveFile }
| { name: 'DRIVE_RESTORE'; data: DriveFile }
Expand All @@ -37,6 +40,18 @@ export type BackgroundTask =
data: { chapterId: number; novelName: string; chapterName: string };
};

export type BackgroundTaskMetadata = {
name: string;
isRunning: boolean;
progress: number | undefined;
progressText: string | undefined;
};

export type QueuedBackgroundTask = {
task: BackgroundTask;
meta: BackgroundTaskMetadata;
};

export default class ServiceManager {
STORE_KEY = 'APP_SERVICE';
private static instance?: ServiceManager;
Expand Down Expand Up @@ -78,24 +93,48 @@ export default class ServiceManager {
});
}
}
async executeTask(task: BackgroundTask) {
switch (task.name) {
async executeTask(task: QueuedBackgroundTask) {
let setMeta = (
transformer: (meta: BackgroundTaskMetadata) => BackgroundTaskMetadata,
) => {
let taskList = [...this.getTaskList()];
taskList[0] = {
...taskList[0],
meta: transformer(taskList[0].meta),
};

if (taskList[0].meta.isRunning) {
BackgroundService.updateNotification({
taskTitle: taskList[0].meta.name,
taskDesc: taskList[0].meta.progressText,
progressBar: {
indeterminate: taskList[0].meta.progress === undefined,
value: (taskList[0].meta.progress || 0) * 100,
max: 100,
},
});
}

setMMKVObject(this.STORE_KEY, taskList);
};

switch (task.task.name) {
case 'IMPORT_EPUB':
return importEpub(task.data);
return importEpub(task.task.data, setMeta);
case 'UPDATE_LIBRARY':
return updateLibrary(task.data);
return updateLibrary(task.task.data || {}, setMeta);
case 'DRIVE_BACKUP':
return createDriveBackup(task.data);
return createDriveBackup(task.task.data, setMeta);
case 'DRIVE_RESTORE':
return driveRestore(task.data);
return driveRestore(task.task.data, setMeta);
case 'SELF_HOST_BACKUP':
return createSelfHostBackup(task.data);
return createSelfHostBackup(task.task.data, setMeta);
case 'SELF_HOST_RESTORE':
return selfHostRestore(task.data);
return selfHostRestore(task.task.data, setMeta);
case 'MIGRATE_NOVEL':
return migrateNovel(task.data);
return migrateNovel(task.task.data, setMeta);
case 'DOWNLOAD_CHAPTER':
return downloadChapter(task.data);
return downloadChapter(task.task.data, setMeta);
default:
return;
}
Expand All @@ -121,11 +160,11 @@ export default class ServiceManager {
}
try {
await manager.executeTask(currentTask);
doneTasks[currentTask.name] += 1;
doneTasks[currentTask.task.name] += 1;
} catch (error: any) {
await Notifications.scheduleNotificationAsync({
content: {
title: currentTask.name,
title: currentTask.meta.name,
body: error?.message || String(error),
},
trigger: null,
Expand All @@ -148,46 +187,71 @@ export default class ServiceManager {
});
}
}
getTaskDescription(task: BackgroundTask) {
getTaskName(task: BackgroundTask) {
switch (task.name) {
case 'DOWNLOAD_CHAPTER':
return task.data.chapterName;
return (
'Download ' + task.data.novelName + ' - ' + task.data.chapterName
);
case 'IMPORT_EPUB':
return task.data.filename;
return 'Import Epub ' + task.data.filename;
case 'MIGRATE_NOVEL':
return task.data.fromNovel.name;
return 'Migrate Novel ' + task.data.fromNovel.name;
case 'UPDATE_LIBRARY':
if (task.data !== undefined) {
return 'Update Category ' + task.data.categoryName;
}
return 'Update Library';
case 'DRIVE_BACKUP':
return 'Drive Backup';
case 'DRIVE_RESTORE':
return 'Drive Restore';
case 'SELF_HOST_BACKUP':
return 'Self Host Backup';
case 'SELF_HOST_RESTORE':
return 'Self Host Restore';
default:
return task.data?.toString() || 'No data';
return 'Unknown Task';
}
}
getTaskList() {
return getMMKVObject<Array<BackgroundTask>>(this.STORE_KEY) || [];
return getMMKVObject<Array<QueuedBackgroundTask>>(this.STORE_KEY) || [];
}
addTask(tasks: BackgroundTask | BackgroundTask[]) {
const currentTasks = this.getTaskList();
const addableTasks = (Array.isArray(tasks) ? tasks : [tasks]).filter(
task =>
this.isMultiplicableTask(task) ||
!currentTasks.some(_t => _t.name === task.name),
!currentTasks.some(_t => _t.task.name === task.name),
);
if (addableTasks.length) {
setMMKVObject(this.STORE_KEY, currentTasks.concat(addableTasks));
let newTasks: QueuedBackgroundTask[] = addableTasks.map(task => ({
task,
meta: {
name: this.getTaskName(task),
isRunning: false,
progress: undefined,
progressText: undefined,
},
}));

setMMKVObject(this.STORE_KEY, currentTasks.concat(newTasks));
this.start();
}
}
removeTasksByName(name: BackgroundTask['name']) {
const taskList = this.getTaskList();
if (taskList[0]?.name === name) {
if (taskList[0]?.task?.name === name) {
this.pause();
setMMKVObject(
this.STORE_KEY,
taskList.filter(t => t.name !== name),
taskList.filter(t => t.task.name !== name),
);
this.resume();
} else {
setMMKVObject(
this.STORE_KEY,
taskList.filter(t => t.name !== name),
taskList.filter(t => t.task.name !== name),
);
}
}
Expand Down
Loading

0 comments on commit ae482a7

Please sign in to comment.