Meldingen-hardening: verwerp-optie bij sluiten, classificatie-gate, presentatietimer #7
2 changed files with 47 additions and 16 deletions
|
|
@ -783,6 +783,7 @@ const _dutchSourceStrings = {
|
||||||
'Verwijderen': 'Delete',
|
'Verwijderen': 'Delete',
|
||||||
'Herstellen': 'Restore',
|
'Herstellen': 'Restore',
|
||||||
'Opslaan en sluiten': 'Save and close',
|
'Opslaan en sluiten': 'Save and close',
|
||||||
|
'Niet opslaan': "Don't save",
|
||||||
'Niet-opgeslagen werk herstellen?': 'Restore unsaved work?',
|
'Niet-opgeslagen werk herstellen?': 'Restore unsaved work?',
|
||||||
'Niet-opgeslagen wijzigingen': 'Unsaved changes',
|
'Niet-opgeslagen wijzigingen': 'Unsaved changes',
|
||||||
'Er is een presentatie met niet-opgeslagen wijzigingen gevonden van een vorige sessie:':
|
'Er is een presentatie met niet-opgeslagen wijzigingen gevonden van een vorige sessie:':
|
||||||
|
|
@ -1161,6 +1162,7 @@ const _dutchSourceStrings = {
|
||||||
'Verwijderen': 'Elimina',
|
'Verwijderen': 'Elimina',
|
||||||
'Herstellen': 'Ripristina',
|
'Herstellen': 'Ripristina',
|
||||||
'Opslaan en sluiten': 'Salva e chiudi',
|
'Opslaan en sluiten': 'Salva e chiudi',
|
||||||
|
'Niet opslaan': 'Non salvare',
|
||||||
'Importeren via URL': 'Importa da URL',
|
'Importeren via URL': 'Importa da URL',
|
||||||
'Ophalen': 'Recupera',
|
'Ophalen': 'Recupera',
|
||||||
'Titelpagina': 'Slide titolo',
|
'Titelpagina': 'Slide titolo',
|
||||||
|
|
@ -1372,6 +1374,7 @@ const _dutchSourceStrings = {
|
||||||
'Verwijderen': 'Löschen',
|
'Verwijderen': 'Löschen',
|
||||||
'Herstellen': 'Wiederherstellen',
|
'Herstellen': 'Wiederherstellen',
|
||||||
'Opslaan en sluiten': 'Speichern und schließen',
|
'Opslaan en sluiten': 'Speichern und schließen',
|
||||||
|
'Niet opslaan': 'Nicht speichern',
|
||||||
'Importeren via URL': 'Von URL importieren',
|
'Importeren via URL': 'Von URL importieren',
|
||||||
'Ophalen': 'Abrufen',
|
'Ophalen': 'Abrufen',
|
||||||
'Titelpagina': 'Titelfolie',
|
'Titelpagina': 'Titelfolie',
|
||||||
|
|
@ -1584,6 +1587,7 @@ const _dutchSourceStrings = {
|
||||||
'Verwijderen': 'Supprimer',
|
'Verwijderen': 'Supprimer',
|
||||||
'Herstellen': 'Restaurer',
|
'Herstellen': 'Restaurer',
|
||||||
'Opslaan en sluiten': 'Enregistrer et fermer',
|
'Opslaan en sluiten': 'Enregistrer et fermer',
|
||||||
|
'Niet opslaan': 'Ne pas enregistrer',
|
||||||
'Importeren via URL': 'Importer depuis une URL',
|
'Importeren via URL': 'Importer depuis une URL',
|
||||||
'Ophalen': 'Récupérer',
|
'Ophalen': 'Récupérer',
|
||||||
'Titelpagina': 'Diapositive de titre',
|
'Titelpagina': 'Diapositive de titre',
|
||||||
|
|
@ -1795,6 +1799,7 @@ const _dutchSourceStrings = {
|
||||||
'Verwijderen': 'Eliminar',
|
'Verwijderen': 'Eliminar',
|
||||||
'Herstellen': 'Restaurar',
|
'Herstellen': 'Restaurar',
|
||||||
'Opslaan en sluiten': 'Guardar y cerrar',
|
'Opslaan en sluiten': 'Guardar y cerrar',
|
||||||
|
'Niet opslaan': 'No guardar',
|
||||||
'Importeren via URL': 'Importar desde URL',
|
'Importeren via URL': 'Importar desde URL',
|
||||||
'Ophalen': 'Obtener',
|
'Ophalen': 'Obtener',
|
||||||
'Titelpagina': 'Diapositiva de título',
|
'Titelpagina': 'Diapositiva de título',
|
||||||
|
|
@ -2007,6 +2012,7 @@ const _dutchSourceStrings = {
|
||||||
'Verwijderen': 'Fuortsmite',
|
'Verwijderen': 'Fuortsmite',
|
||||||
'Herstellen': 'Weromsette',
|
'Herstellen': 'Weromsette',
|
||||||
'Opslaan en sluiten': 'Bewarje en slute',
|
'Opslaan en sluiten': 'Bewarje en slute',
|
||||||
|
'Niet opslaan': 'Net bewarje',
|
||||||
'Importeren via URL': 'Ymportearje fan URL',
|
'Importeren via URL': 'Ymportearje fan URL',
|
||||||
'Ophalen': 'Ophelje',
|
'Ophalen': 'Ophelje',
|
||||||
'Titelpagina': 'Titelslide',
|
'Titelpagina': 'Titelslide',
|
||||||
|
|
@ -2219,6 +2225,7 @@ const _dutchSourceStrings = {
|
||||||
'Verwijderen': 'Kita',
|
'Verwijderen': 'Kita',
|
||||||
'Herstellen': 'Restorá',
|
'Herstellen': 'Restorá',
|
||||||
'Opslaan en sluiten': 'Warda i sera',
|
'Opslaan en sluiten': 'Warda i sera',
|
||||||
|
'Niet opslaan': 'No warda',
|
||||||
'Importeren via URL': 'Importá for di URL',
|
'Importeren via URL': 'Importá for di URL',
|
||||||
'Ophalen': 'Tuma',
|
'Ophalen': 'Tuma',
|
||||||
'Titelpagina': 'Slide di título',
|
'Titelpagina': 'Slide di título',
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ part 'shell/welcome_screen.dart';
|
||||||
part 'shell/status_bar.dart';
|
part 'shell/status_bar.dart';
|
||||||
part 'shell/shell_overlays.dart';
|
part 'shell/shell_overlays.dart';
|
||||||
|
|
||||||
|
/// Keuze uit de "niet-opgeslagen wijzigingen"-dialoog bij het sluiten.
|
||||||
|
enum _CloseChoice { cancel, discard, save }
|
||||||
|
|
||||||
class AppShell extends ConsumerStatefulWidget {
|
class AppShell extends ConsumerStatefulWidget {
|
||||||
const AppShell({super.key});
|
const AppShell({super.key});
|
||||||
|
|
||||||
|
|
@ -128,14 +131,21 @@ class _AppShellState extends ConsumerState<AppShell> with WindowListener {
|
||||||
@override
|
@override
|
||||||
void onWindowClose() async {
|
void onWindowClose() async {
|
||||||
if (ref.read(tabsProvider).anyDirty) {
|
if (ref.read(tabsProvider).anyDirty) {
|
||||||
final shouldSave = await _confirmSaveBeforeClose(
|
final choice = await _confirmSaveBeforeClose(
|
||||||
context.l10n.d(
|
context.l10n.d(
|
||||||
'Er zijn presentaties met niet-opgeslagen wijzigingen. Sla ze op voordat de app sluit.',
|
'Er zijn presentaties met niet-opgeslagen wijzigingen. Sla ze op voordat de app sluit.',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!shouldSave) return;
|
switch (choice) {
|
||||||
|
case _CloseChoice.cancel:
|
||||||
|
return;
|
||||||
|
case _CloseChoice.discard:
|
||||||
|
// Wijzigingen verwerpen: herstelbestanden weg, niets opslaan.
|
||||||
|
await _destroy();
|
||||||
|
case _CloseChoice.save:
|
||||||
final saved = await _saveAllDirtyTabs();
|
final saved = await _saveAllDirtyTabs();
|
||||||
if (saved) await _destroy();
|
if (saved) await _destroy();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
await _destroy();
|
await _destroy();
|
||||||
}
|
}
|
||||||
|
|
@ -147,9 +157,9 @@ class _AppShellState extends ConsumerState<AppShell> with WindowListener {
|
||||||
await windowManager.destroy();
|
await windowManager.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _confirmSaveBeforeClose(String message) async {
|
Future<_CloseChoice> _confirmSaveBeforeClose(String message) async {
|
||||||
if (!mounted) return false;
|
if (!mounted) return _CloseChoice.cancel;
|
||||||
return await showDialog<bool>(
|
return await showDialog<_CloseChoice>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (ctx) {
|
builder: (ctx) {
|
||||||
|
|
@ -159,18 +169,25 @@ class _AppShellState extends ConsumerState<AppShell> with WindowListener {
|
||||||
content: Text(message),
|
content: Text(message),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(ctx, false),
|
onPressed: () => Navigator.pop(ctx, _CloseChoice.cancel),
|
||||||
child: Text(l10n.t('cancel')),
|
child: Text(l10n.t('cancel')),
|
||||||
),
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx, _CloseChoice.discard),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor: Theme.of(ctx).colorScheme.error,
|
||||||
|
),
|
||||||
|
child: Text(l10n.d('Niet opslaan')),
|
||||||
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () => Navigator.pop(ctx, true),
|
onPressed: () => Navigator.pop(ctx, _CloseChoice.save),
|
||||||
child: Text(l10n.d('Opslaan en sluiten')),
|
child: Text(l10n.d('Opslaan en sluiten')),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
) ??
|
) ??
|
||||||
false;
|
_CloseChoice.cancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _saveAllDirtyTabs() async {
|
Future<bool> _saveAllDirtyTabs() async {
|
||||||
|
|
@ -186,17 +203,24 @@ class _AppShellState extends ConsumerState<AppShell> with WindowListener {
|
||||||
Future<void> _onCloseTab(int index) async {
|
Future<void> _onCloseTab(int index) async {
|
||||||
final tab = ref.read(tabsProvider).tabs[index];
|
final tab = ref.read(tabsProvider).tabs[index];
|
||||||
if (tab.isDirty) {
|
if (tab.isDirty) {
|
||||||
final shouldSave = await _confirmSaveBeforeClose(
|
final choice = await _confirmSaveBeforeClose(
|
||||||
context.l10n.d(
|
context.l10n.d(
|
||||||
'Deze presentatie heeft niet-opgeslagen wijzigingen. Sla de presentatie op voordat het tabblad sluit.',
|
'Deze presentatie heeft niet-opgeslagen wijzigingen. Sla de presentatie op voordat het tabblad sluit.',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!shouldSave) return;
|
switch (choice) {
|
||||||
|
case _CloseChoice.cancel:
|
||||||
|
return;
|
||||||
|
case _CloseChoice.discard:
|
||||||
|
// Wijzigingen verwerpen: closeTab() ruimt ook het herstelbestand op.
|
||||||
|
break;
|
||||||
|
case _CloseChoice.save:
|
||||||
final saved = await tab.deckNotifier.save(
|
final saved = await tab.deckNotifier.save(
|
||||||
initialDirectory: ref.read(settingsProvider).homeDirectory,
|
initialDirectory: ref.read(settingsProvider).homeDirectory,
|
||||||
);
|
);
|
||||||
if (!saved) return;
|
if (!saved) return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ref.read(tabsProvider.notifier).closeTab(index);
|
ref.read(tabsProvider.notifier).closeTab(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue