138 lines
5.2 KiB
TypeScript
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;
|
|
}
|
|
}
|
|
} |