fix: ask before deleting an event, a task or a calendar feed

This commit is contained in:
Linus Rath
2026-10-15 02:51:54 +02:00
parent 90170ea0e7
commit 0460da51e5
4 changed files with 47 additions and 7 deletions
+1
View File
@@ -128,6 +128,7 @@
"add_placeholder": "Aufgabe hinzufügen…",
"add_time": "Uhrzeit hinzufügen",
"clear_due_date": "Fälligkeitsdatum entfernen",
"delete_confirm": "Diese Aufgabe löschen?",
"delete_error": "Aufgabe konnte nicht gelöscht werden",
"not_found": "Diese Aufgabe ist nicht mehr verfügbar.",
"save_error": "Aufgabe konnte nicht gespeichert werden",
+1
View File
@@ -131,6 +131,7 @@
"add_placeholder": "Add a task…",
"add_time": "Add time",
"clear_due_date": "Clear due date",
"delete_confirm": "Delete this task?",
"delete_error": "Failed to delete task",
"not_found": "This task is no longer available.",
"save_error": "Failed to save task",
@@ -1,6 +1,6 @@
import React from 'react';
import {
View, Text, StyleSheet, ScrollView, Pressable, Modal, Animated, Easing, TextInput, ActivityIndicator,
View, Text, StyleSheet, ScrollView, Pressable, Modal, Animated, Easing, TextInput, ActivityIndicator, Alert,
} from 'react-native';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { X, Plus, RefreshCw, Trash2, Rss, AlertTriangle } from 'lucide-react-native';
@@ -279,7 +279,24 @@ export function ICalSubscriptionSheet({ visible, onClose }: Props) {
)}
</Pressable>
<Pressable
onPress={() => { void removeSubscription(sub.id); }}
// Unsubscribing also deletes the calendar and its events.
onPress={() => Alert.alert(
t('calendar.subscription.unsubscribe', 'Unsubscribe'),
t('calendar.subscription.confirm_delete', 'Unsubscribe from "{name}"? The calendar and all its events will be removed.', { name: sub.name }),
[
{ text: t('common.cancel', 'Cancel'), style: 'cancel' },
{
text: t('calendar.subscription.unsubscribe', 'Unsubscribe'),
style: 'destructive',
onPress: () => {
removeSubscription(sub.id).catch((err: unknown) => Alert.alert(
t('calendar.subscription.delete_error', 'Failed to remove subscription'),
err instanceof Error ? err.message : undefined,
));
},
},
],
)}
hitSlop={6}
style={styles.subBtn}
accessibilityRole="button"
+26 -5
View File
@@ -634,15 +634,32 @@ export default function CalendarScreen() {
[t],
);
// A single event is gone for good once deleted; ask first, as the
// recurrence-scope dialog already does for a series.
const confirmDeleteEvent = React.useCallback((event: CalendarEvent) => {
Alert.alert(
t('calendar.detail.delete_confirm', 'Delete this event?'),
event.title || undefined,
[
{ text: t('common.cancel', 'Cancel'), style: 'cancel' },
{
text: t('calendar.recurrence_scope.delete', 'Delete'),
style: 'destructive',
onPress: () => { deleteEvent(event.id).catch(reportError); },
},
],
);
}, [deleteEvent, reportError, t]);
const handleDeleteFromDetail = React.useCallback((event: CalendarEvent) => {
if (isReadOnlyEvent(event)) { setDetailEvent(null); return; }
setDetailEvent(null);
if (isRecurringSeriesMember(event)) {
setPendingAction({ kind: 'delete', event });
} else {
deleteEvent(event.id).catch(reportError);
confirmDeleteEvent(event);
}
}, [deleteEvent, isReadOnlyEvent, reportError]);
}, [confirmDeleteEvent, isReadOnlyEvent]);
// "This and following": end the master at the occurrence and hand back the
// master plus its untouched rules so the caller can start a new series (or
@@ -815,9 +832,9 @@ export default function CalendarScreen() {
setPendingAction({ kind: 'delete', event });
return;
}
await deleteEvent(event.id).catch(reportError);
confirmDeleteEvent(event);
},
[deleteEvent, reportError],
[confirmDeleteEvent],
);
const onRefresh = React.useCallback(() => refresh(), [refresh]);
@@ -838,12 +855,16 @@ export default function CalendarScreen() {
const handleDeleteTask = React.useCallback(
(id: string) => {
deleteTask(id).catch((err: unknown) => {
const run = () => deleteTask(id).catch((err: unknown) => {
Alert.alert(
t('calendar.tasks.delete_error', 'Failed to delete task'),
err instanceof Error ? err.message : undefined,
);
});
Alert.alert(t('calendar.tasks.delete_confirm', 'Delete this task?'), undefined, [
{ text: t('common.cancel', 'Cancel'), style: 'cancel' },
{ text: t('calendar.tasks.delete', 'Delete'), style: 'destructive', onPress: () => { void run(); } },
]);
},
[deleteTask, t],
);