diff --git a/app/(tabs)/settings.tsx b/app/(tabs)/settings.tsx
index beca90c..d9f63af 100644
--- a/app/(tabs)/settings.tsx
+++ b/app/(tabs)/settings.tsx
@@ -2,13 +2,14 @@ import { useState, useEffect, useCallback } from 'react';
import { View, Text, Pressable, useColorScheme, TextInput, ScrollView, Alert, Modal, Platform, Switch, Linking, ActivityIndicator } from 'react-native';
import { KeyboardAvoidingView } from 'react-native-keyboard-controller';
import { useTranslation } from 'react-i18next';
-import { Sun, Moon, Smartphone, Plus, Trash2, Pencil, Bell, CalendarDays, Mail, RefreshCw } from 'lucide-react-native';
+import { Sun, Moon, Smartphone, Plus, Trash2, Pencil, Bell, CalendarDays, LayoutGrid, Mail, RefreshCw } from 'lucide-react-native';
import Constants from 'expo-constants';
import { colors } from '@/src/theme/colors';
import { useSettingsStore } from '@/src/stores/useSettingsStore';
import { getAllTags, createTag, updateTag, deleteTag } from '@/src/db/repository/tags';
import { initCalendar } from '@/src/services/calendar';
+import { syncWidgetData } from '@/src/services/widgetSync';
import i18n from '@/src/i18n';
type ThemeMode = 'light' | 'dark' | 'system';
@@ -23,6 +24,7 @@ export default function SettingsScreen() {
notificationsEnabled, setNotificationsEnabled,
reminderOffset, setReminderOffset,
calendarSyncEnabled, setCalendarSyncEnabled,
+ widgetPeriodWeeks, setWidgetPeriodWeeks,
} = useSettingsStore();
const isDark = (theme === 'system' ? systemScheme : theme) === 'dark';
@@ -299,6 +301,56 @@ export default function SettingsScreen() {
+ {/* Widget Section */}
+
+
+ {t('widget.title')}
+
+
+
+
+
+
+ {t('widget.period')}
+
+
+
+ {[
+ { value: 1, label: t('widget.periodWeek', { count: 1 }) },
+ { value: 2, label: t('widget.periodWeek', { count: 2 }) },
+ { value: 4, label: t('widget.periodWeek', { count: 4 }) },
+ { value: 0, label: t('widget.periodAll') },
+ ].map((opt) => {
+ const isActive = widgetPeriodWeeks === opt.value;
+ return (
+ {
+ setWidgetPeriodWeeks(opt.value);
+ syncWidgetData();
+ }}
+ className={`rounded-full px-3 py-1.5 ${isActive ? 'bg-bleu' : isDark ? 'bg-[#3A3A3A]' : 'bg-[#E5E7EB]'}`}
+ >
+
+ {opt.label}
+
+
+ );
+ })}
+
+
+
+
+
{/* Tags Section */}
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 5ecf688..b8626be 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -138,6 +138,10 @@
"overdue": "Overdue",
"today": "Today",
"tomorrow": "Tomorrow",
- "noDate": "No date"
+ "noDate": "No date",
+ "period": "Display period",
+ "periodWeek_one": "{{count}} week",
+ "periodWeek_other": "{{count}} weeks",
+ "periodAll": "All"
}
}
diff --git a/src/i18n/fr.json b/src/i18n/fr.json
index 738d9e3..f029c31 100644
--- a/src/i18n/fr.json
+++ b/src/i18n/fr.json
@@ -138,6 +138,10 @@
"overdue": "En retard",
"today": "Aujourd'hui",
"tomorrow": "Demain",
- "noDate": "Sans date"
+ "noDate": "Sans date",
+ "period": "Période affichée",
+ "periodWeek_one": "{{count}} semaine",
+ "periodWeek_other": "{{count}} semaines",
+ "periodAll": "Toutes"
}
}
diff --git a/src/services/widgetSync.ts b/src/services/widgetSync.ts
index e60c623..38755dd 100644
--- a/src/services/widgetSync.ts
+++ b/src/services/widgetSync.ts
@@ -34,7 +34,20 @@ export async function syncWidgetData(): Promise {
try {
const now = new Date();
const todayStart = startOfDay(now);
- const twoWeeksEnd = endOfDay(addWeeks(now, 2));
+
+ // Read widget period setting from AsyncStorage (0 = all, N = N weeks ahead)
+ // Coupled with useSettingsStore.ts — key 'simpl-liste-settings', path state.widgetPeriodWeeks
+ let widgetPeriodWeeks = 0;
+ try {
+ const settingsRaw = await AsyncStorage.getItem('simpl-liste-settings');
+ if (settingsRaw) {
+ const settings = JSON.parse(settingsRaw);
+ const stored = settings?.state?.widgetPeriodWeeks;
+ if (typeof stored === 'number') widgetPeriodWeeks = stored;
+ }
+ } catch {
+ // Default to all tasks
+ }
const selectFields = {
id: tasks.id,
@@ -48,19 +61,20 @@ export async function syncWidgetData(): Promise {
subtaskDoneCount: sql`(SELECT COUNT(*) FROM tasks AS sub WHERE sub.parent_id = ${tasks.id} AND sub.completed = 1)`.as('subtask_done_count'),
};
- // Fetch tasks with due date in the next 2 weeks
+ // Fetch upcoming tasks (filtered by period setting, 0 = all future tasks)
+ const upcomingConditions = [
+ eq(tasks.completed, false),
+ isNull(tasks.parentId),
+ gte(tasks.dueDate, todayStart),
+ ];
+ if (widgetPeriodWeeks > 0) {
+ upcomingConditions.push(lte(tasks.dueDate, endOfDay(addWeeks(now, widgetPeriodWeeks))));
+ }
const upcomingTasks = await db
.select(selectFields)
.from(tasks)
.leftJoin(lists, eq(tasks.listId, lists.id))
- .where(
- and(
- eq(tasks.completed, false),
- isNull(tasks.parentId),
- gte(tasks.dueDate, todayStart),
- lte(tasks.dueDate, twoWeeksEnd)
- )
- )
+ .where(and(...upcomingConditions))
.orderBy(asc(tasks.dueDate));
// Fetch overdue tasks
diff --git a/src/stores/useSettingsStore.ts b/src/stores/useSettingsStore.ts
index ee5963d..c9998df 100644
--- a/src/stores/useSettingsStore.ts
+++ b/src/stores/useSettingsStore.ts
@@ -10,11 +10,13 @@ interface SettingsState {
notificationsEnabled: boolean;
reminderOffset: number; // hours before due date (0 = at time)
calendarSyncEnabled: boolean;
+ widgetPeriodWeeks: number; // 0 = all tasks, otherwise number of weeks ahead
setTheme: (theme: ThemeMode) => void;
setLocale: (locale: 'fr' | 'en') => void;
setNotificationsEnabled: (enabled: boolean) => void;
setReminderOffset: (offset: number) => void;
setCalendarSyncEnabled: (enabled: boolean) => void;
+ setWidgetPeriodWeeks: (weeks: number) => void;
}
export const useSettingsStore = create()(
@@ -25,11 +27,13 @@ export const useSettingsStore = create()(
notificationsEnabled: true,
reminderOffset: 0,
calendarSyncEnabled: false,
+ widgetPeriodWeeks: 0,
setTheme: (theme) => set({ theme }),
setLocale: (locale) => set({ locale }),
setNotificationsEnabled: (notificationsEnabled) => set({ notificationsEnabled }),
setReminderOffset: (reminderOffset) => set({ reminderOffset }),
setCalendarSyncEnabled: (calendarSyncEnabled) => set({ calendarSyncEnabled }),
+ setWidgetPeriodWeeks: (widgetPeriodWeeks) => set({ widgetPeriodWeeks }),
}),
{
name: 'simpl-liste-settings',
diff --git a/src/widgets/TaskListWidget.tsx b/src/widgets/TaskListWidget.tsx
index ccfe348..c084192 100644
--- a/src/widgets/TaskListWidget.tsx
+++ b/src/widgets/TaskListWidget.tsx
@@ -380,17 +380,14 @@ function SmallWidget({ tasks, isDark }: { tasks: WidgetTask[]; isDark: boolean }
function ListWidgetContent({
tasks,
- maxItems,
isDark,
expandedTaskIds,
}: {
tasks: WidgetTask[];
- maxItems: number;
isDark: boolean;
expandedTaskIds: Set;
}) {
const c = getColors(isDark);
- const displayTasks = tasks.slice(0, maxItems);
return (
- {/* Task list */}
- {displayTasks.length > 0 ? (
+ {/* Task list — cap at 30 items to avoid Android widget memory limits */}
+ {tasks.length > 0 ? (
- {displayTasks.map((task) => (
+ {tasks.slice(0, 30).map((task) => (
;
}
- const maxItems = widgetName === 'SimplListeLarge' ? 8 : 4;
return (