Added i18n, and time units, v1.1.0

This commit is contained in:
xavis 2025-07-30 18:42:10 +02:00
parent 5e91df4529
commit b588ce2355
13 changed files with 58 additions and 31 deletions

View File

@ -59,4 +59,9 @@ expo.useLegacyPackaging=false
expo.edgeToEdgeEnabled=true expo.edgeToEdgeEnabled=true
android.packagingOptions.pickFirsts=**/libc++_shared.so android.packagingOptions.pickFirsts=**/libc++_shared.so
expo.sqlite.enableFTS=false expo.sqlite.enableFTS=false
expo.sqlite.useSQLCipher=false expo.sqlite.useSQLCipher=false
MYAPP_UPLOAD_STORE_FILE=taskeep.keystore
MYAPP_UPLOAD_STORE_PASSWORD=123?_Tk_?123
MYAPP_UPLOAD_KEY_ALIAS=taskeep
MYAPP_UPLOAD_KEY_PASSWORD=123?_Tk_?123

View File

@ -1,12 +1,13 @@
import { throttle } from '@/utils/throttle';
import * as Notifications from 'expo-notifications'; import * as Notifications from 'expo-notifications';
import React from 'react'; import React from 'react';
import type { WidgetTaskHandlerProps } from 'react-native-android-widget'; import type { WidgetTaskHandlerProps } from 'react-native-android-widget';
import i18n from '../../i18n';
import { Category, CategoryQuery } from '../../models/category'; import { Category, CategoryQuery } from '../../models/category';
import { Task, TaskQuery } from '../../models/task'; import { Task, TaskQuery } from '../../models/task';
import { CategoryRepository } from '../../repositories/CategoryRepository'; import { CategoryRepository } from '../../repositories/CategoryRepository';
import { TaskRepository } from '../../repositories/TaskRepository'; import { TaskRepository } from '../../repositories/TaskRepository';
import { SQLiteDataService } from '../../services/data/sqliteDataService'; import { SQLiteDataService } from '../../services/data/sqliteDataService';
import { throttle } from '../../utils/throttle';
import { HelloWidget } from './hello'; import { HelloWidget } from './hello';
@ -15,6 +16,7 @@ const categoryRepository = new CategoryRepository(new SQLiteDataService<Category
let tasks: Task[] = []; let tasks: Task[] = [];
let categories: Category[] = []; let categories: Category[] = [];
let resizeInterval = -1;
Notifications.setNotificationHandler({ Notifications.setNotificationHandler({
handleNotification: async () => ({ handleNotification: async () => ({
@ -66,8 +68,8 @@ const CheckTaskAndNotify = async (): Promise<{ newTasks: Task[], newCategories:
await Notifications.scheduleNotificationAsync({ await Notifications.scheduleNotificationAsync({
identifier: `task-due-${task.id}`, identifier: `task-due-${task.id}`,
content: { content: {
title: 'Task Reminder', title: i18n.t("task_reminder_title"),
body: `${category?.icon} "${task.title}" is due!`, body: `${category?.icon} "${task.title}" ${i18n.t("is_due")}`,
data: { taskId: task.id }, data: { taskId: task.id },
}, },
trigger: null trigger: null
@ -78,35 +80,37 @@ const CheckTaskAndNotify = async (): Promise<{ newTasks: Task[], newCategories:
return { newTasks: tasks, newCategories: categories }; return { newTasks: tasks, newCategories: categories };
} }
const throttledCheckTaskAndNotify = throttle(CheckTaskAndNotify, 1000); // Throttle to prevent too frequent calls
setInterval(async () => { setInterval(async () => {
const { newTasks, newCategories } = await throttledCheckTaskAndNotify(); const { newTasks, newCategories } = await CheckTaskAndNotify();
console.log("Throttled task check and notify executed OUT"); console.log("Throttled task check and notify executed OUT");
console.log("New tasks:", newTasks); console.log("New tasks:", newTasks);
console.log("New categories:", newCategories); console.log("New categories:", newCategories);
tasks = newTasks; tasks = newTasks;
categories = newCategories; categories = newCategories;
}, 1000 * 60 * 30); // Check every 30 minutes }, 1000 * 60); // Check every minute
let lastRender = 0;
export async function widgetTaskHandler(props: WidgetTaskHandlerProps) { export async function widgetTaskHandler(props: WidgetTaskHandlerProps) {
async function updateAndRenderWidget() { const throttledDraw = throttle(props.renderWidget, 1000);
const { newTasks, newCategories } = await throttledCheckTaskAndNotify();
tasks = newTasks;
categories = newCategories; async function updateAndRenderWidget(force = false) {
console.log("Throttled task check and notify executed IN"); console.log("Updating widget with tasks and categories");
console.log("New tasks:", newTasks); const { newTasks, newCategories } = await CheckTaskAndNotify();
console.log("New categories:", newCategories); throttledDraw(<HelloWidget tasks={newTasks} categories={newCategories} />);
props.renderWidget(<HelloWidget tasks={tasks} categories={categories} />); if (lastRender > Date.now() - 1000 || force) {
lastRender = Date.now();
console.log("Rendering widget");
props.renderWidget(<HelloWidget tasks={newTasks} categories={newCategories} />);
}
} }
switch (props.widgetAction) { switch (props.widgetAction) {
case 'WIDGET_ADDED': case 'WIDGET_ADDED':
case 'WIDGET_UPDATE': case 'WIDGET_UPDATE':
case 'WIDGET_RESIZED': case 'WIDGET_RESIZED':
// Not needed for now
updateAndRenderWidget(); updateAndRenderWidget();
break; break;
@ -117,7 +121,7 @@ export async function widgetTaskHandler(props: WidgetTaskHandlerProps) {
case 'WIDGET_CLICK': case 'WIDGET_CLICK':
switch (props.clickAction) { switch (props.clickAction) {
case 'REFRESH': case 'REFRESH':
await updateAndRenderWidget(); await updateAndRenderWidget(true);
break; break;
case 'UPDATE_TASK': case 'UPDATE_TASK':
if (props.clickActionData && props.clickActionData.id) { if (props.clickActionData && props.clickActionData.id) {
@ -126,7 +130,7 @@ export async function widgetTaskHandler(props: WidgetTaskHandlerProps) {
if (task) { if (task) {
task.lastDone = Math.floor(Date.now() / 1000 / 60 / 60 / 24); // Set last done to today 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 taskRepository.update(parseInt(taskId.toString()), { ...task, lastDone: new Date().getTime() });
await updateAndRenderWidget(); await updateAndRenderWidget(true);
} }
} }
break; break;

View File

@ -5,5 +5,3 @@ import "./i18n.js";
registerWidgetTaskHandler(widgetTaskHandler); registerWidgetTaskHandler(widgetTaskHandler);
console.log(registerWidgetTaskHandler);

View File

@ -61,5 +61,7 @@
"Months": "أشهر", "Months": "أشهر",
"select_icon_and_enter_title": "اختر رمزًا وأدخل عنوانًا", "select_icon_and_enter_title": "اختر رمزًا وأدخل عنوانًا",
"Tasks": "المهام", "Tasks": "المهام",
"Categories": "الفئات" "Categories": "الفئات",
"task_reminder_title": "تذكير بالمهمة",
"is_due": "مستحقة!"
} }

View File

@ -61,5 +61,7 @@
"Months": "Monate", "Months": "Monate",
"select_icon_and_enter_title": "Wählen Sie ein Symbol und geben Sie einen Titel ein", "select_icon_and_enter_title": "Wählen Sie ein Symbol und geben Sie einen Titel ein",
"Tasks": "Aufgaben", "Tasks": "Aufgaben",
"Categories": "Kategorien" "Categories": "Kategorien",
"task_reminder_title": "Aufgabenerinnerung",
"is_due": "ist fällig!"
} }

View File

@ -61,5 +61,7 @@
"Months": "Months", "Months": "Months",
"select_icon_and_enter_title": "Select an icon and enter a title", "select_icon_and_enter_title": "Select an icon and enter a title",
"Tasks": "Tasks", "Tasks": "Tasks",
"Categories": "Categories" "Categories": "Categories",
"task_reminder_title": "Task Reminder",
"is_due": "is due!"
} }

View File

@ -61,5 +61,7 @@
"Months": "Meses", "Months": "Meses",
"select_icon_and_enter_title": "Selecciona un ícono e ingresa un título", "select_icon_and_enter_title": "Selecciona un ícono e ingresa un título",
"Tasks": "Tareas", "Tasks": "Tareas",
"Categories": "Categorías" "Categories": "Categorías",
"task_reminder_title": "Recordatorio de Tarea",
"is_due": "está vencida!"
} }

View File

@ -61,5 +61,7 @@
"Months": "Mois", "Months": "Mois",
"select_icon_and_enter_title": "Sélectionnez une icône et entrez un titre", "select_icon_and_enter_title": "Sélectionnez une icône et entrez un titre",
"Tasks": "Tâches", "Tasks": "Tâches",
"Categories": "Catégories" "Categories": "Catégories",
"task_reminder_title": "Rappel de Tâche",
"is_due": "est due!"
} }

View File

@ -61,5 +61,7 @@
"Months": "Mesi", "Months": "Mesi",
"select_icon_and_enter_title": "Seleziona un'icona e inserisci un titolo", "select_icon_and_enter_title": "Seleziona un'icona e inserisci un titolo",
"Tasks": "Attività", "Tasks": "Attività",
"Categories": "Categorie" "Categories": "Categorie",
"task_reminder_title": "Promemoria Attività",
"is_due": "è scaduta!"
} }

View File

@ -61,5 +61,7 @@
"Months": "月", "Months": "月",
"select_icon_and_enter_title": "アイコンを選択してタイトルを入力", "select_icon_and_enter_title": "アイコンを選択してタイトルを入力",
"Tasks": "タスク", "Tasks": "タスク",
"Categories": "カテゴリ" "Categories": "カテゴリ",
"task_reminder_title": "タスクリマインダー",
"is_due": "期限です!"
} }

View File

@ -61,5 +61,7 @@
"Months": "Meses", "Months": "Meses",
"select_icon_and_enter_title": "Selecione um ícone e insira um título", "select_icon_and_enter_title": "Selecione um ícone e insira um título",
"Tasks": "Tarefas", "Tasks": "Tarefas",
"Categories": "Categorias" "Categories": "Categorias",
"task_reminder_title": "Lembrete de Tarefa",
"is_due": "está vencida!"
} }

View File

@ -61,5 +61,7 @@
"Months": "Месяцы", "Months": "Месяцы",
"select_icon_and_enter_title": "Выберите значок и введите название", "select_icon_and_enter_title": "Выберите значок и введите название",
"Tasks": "Задачи", "Tasks": "Задачи",
"Categories": "Категории" "Categories": "Категории",
"task_reminder_title": "Напоминание о задаче",
"is_due": "просрочено!"
} }

View File

@ -61,5 +61,7 @@
"Months": "月", "Months": "月",
"select_icon_and_enter_title": "选择一个图标并输入标题", "select_icon_and_enter_title": "选择一个图标并输入标题",
"Tasks": "任务", "Tasks": "任务",
"Categories": "类别" "Categories": "类别",
"task_reminder_title": "任务提醒",
"is_due": "已到期!"
} }