taskeep-app/app/widgets/widget-task-handler.tsx
2025-07-30 14:10:23 +02:00

138 lines
5.2 KiB
TypeScript

import * as Notifications from 'expo-notifications';
import React from 'react';
import type { WidgetTaskHandlerProps } from 'react-native-android-widget';
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 { throttle } from '../../utils/throttle';
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[] = [];
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: 'Task Reminder',
body: `${category?.icon} "${task.title}" is due! ⌛`,
data: { taskId: task.id },
},
trigger: null
});
}
}
return { newTasks: tasks, newCategories: categories };
}
const throttledCheckTaskAndNotify = throttle(CheckTaskAndNotify, 1000); // Throttle to prevent too frequent calls
setInterval(async () => {
const { newTasks, newCategories } = await throttledCheckTaskAndNotify();
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 * 30); // Check every 30 minutes
export async function widgetTaskHandler(props: WidgetTaskHandlerProps) {
async function updateAndRenderWidget() {
const { newTasks, newCategories } = await throttledCheckTaskAndNotify();
tasks = newTasks;
categories = newCategories;
console.log("Throttled task check and notify executed IN");
console.log("New tasks:", newTasks);
console.log("New categories:", newCategories);
props.renderWidget(<HelloWidget tasks={tasks} categories={categories} />);
}
switch (props.widgetAction) {
case 'WIDGET_ADDED':
case 'WIDGET_UPDATE':
case 'WIDGET_RESIZED':
// Not needed for now
updateAndRenderWidget();
break;
case 'WIDGET_DELETED':
// Not needed for now
break;
case 'WIDGET_CLICK':
switch (props.clickAction) {
case 'REFRESH':
await updateAndRenderWidget();
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();
}
}
break;
default:
break;
}
}
}