taskeep-app/app/widgets/widget-task-handler.tsx

142 lines
5.3 KiB
TypeScript

import { throttle } from '@/utils/throttle';
import * as Notifications from 'expo-notifications';
import React from 'react';
import type { WidgetTaskHandlerProps } from 'react-native-android-widget';
import i18n from '../../i18n';
import { Category, CategoryQuery } from '../../models/category';
import { Task, TaskQuery } from '../../models/task';
import { CategoryRepository } from '../../repositories/CategoryRepository';
import { TaskRepository } from '../../repositories/TaskRepository';
import { SQLiteDataService } from '../../services/data/sqliteDataService';
import { HelloWidget } from './hello';
const taskRepository = new TaskRepository(new SQLiteDataService<Task>(TaskQuery));
const categoryRepository = new CategoryRepository(new SQLiteDataService<Category>(CategoryQuery));
let tasks: Task[] = [];
let categories: Category[] = [];
let resizeInterval = -1;
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false,
shouldShowBanner: false,
shouldShowList: true,
}),
});
let notify_channels: Notifications.NotificationChannel[] = [];
let notify_notification: Notifications.Notification | undefined = undefined;
let notify_listener: Notifications.EventSubscription | null = null;
let notify_responseListener: Notifications.EventSubscription | null = null;
Notifications.getNotificationChannelsAsync().then((channels) => {
if (channels.length === 0) {
Notifications.setNotificationChannelAsync('default', {
name: 'Default Channel',
importance: Notifications.AndroidImportance.HIGH,
sound: 'default',
vibrationPattern: [0, 250, 250, 250],
}).then((channel) => {
if (channel) notify_channels = [channel];
});
}
notify_channels = channels;
});
notify_listener = Notifications.addNotificationReceivedListener(notification => {
notify_notification = notification;
});
notify_responseListener = Notifications.addNotificationResponseReceivedListener(response => { });
const CheckTaskAndNotify = async (): Promise<{ newTasks: Task[], newCategories: Category[] }> => {
const tasks = await taskRepository.findAll();
const categories = await categoryRepository.findAll();
const expiredTasks = tasks.filter(task => {
const expirationDate = task.lastDone! + (task.daysToRedo! * 24 * 60 * 60 * 1000); // Convert days to milliseconds
return expirationDate < Date.now();
});
if (expiredTasks.length > 0) {
for (const task of expiredTasks) {
const category = categories.find(cat => cat.id === task.category);
await Notifications.scheduleNotificationAsync({
identifier: `task-due-${task.id}`,
content: {
title: i18n.t("task_reminder_title"),
body: `${category?.icon} "${task.title}" ${i18n.t("is_due")}`,
data: { taskId: task.id },
},
trigger: null
});
}
}
return { newTasks: tasks, newCategories: categories };
}
setInterval(async () => {
const { newTasks, newCategories } = await CheckTaskAndNotify();
console.log("Throttled task check and notify executed OUT");
console.log("New tasks:", newTasks);
console.log("New categories:", newCategories);
tasks = newTasks;
categories = newCategories;
}, 1000 * 60); // Check every minute
let lastRender = 0;
export async function widgetTaskHandler(props: WidgetTaskHandlerProps) {
const throttledDraw = throttle(props.renderWidget, 1000);
async function updateAndRenderWidget(force = false) {
console.log("Updating widget with tasks and categories");
const { newTasks, newCategories } = await CheckTaskAndNotify();
throttledDraw(<HelloWidget tasks={newTasks} categories={newCategories} />);
if (lastRender > Date.now() - 1000 || force) {
lastRender = Date.now();
console.log("Rendering widget");
props.renderWidget(<HelloWidget tasks={newTasks} categories={newCategories} />);
}
}
switch (props.widgetAction) {
case 'WIDGET_ADDED':
case 'WIDGET_UPDATE':
case 'WIDGET_RESIZED':
updateAndRenderWidget();
break;
case 'WIDGET_DELETED':
// Not needed for now
break;
case 'WIDGET_CLICK':
switch (props.clickAction) {
case 'REFRESH':
await updateAndRenderWidget(true);
break;
case 'UPDATE_TASK':
if (props.clickActionData && props.clickActionData.id) {
const taskId = props.clickActionData.id;
const task = await taskRepository.findById(parseInt(taskId.toString()));
if (task) {
task.lastDone = Math.floor(Date.now() / 1000 / 60 / 60 / 24); // Set last done to today
await taskRepository.update(parseInt(taskId.toString()), { ...task, lastDone: new Date().getTime() });
await updateAndRenderWidget(true);
}
}
break;
default:
break;
}
}
}