feat: add setting to require checkbox tap to complete checklist items

This commit is contained in:
2026-05-12 11:36:26 +03:00
parent 448d85834b
commit ef2bc851de
13 changed files with 154 additions and 1 deletions

View File

@@ -361,6 +361,22 @@ class SettingsMessages {
/// ```
String get generalSection => """General""";
/// ```dart
/// "Interface"
/// ```
String get interfaceSection => """Interface""";
/// ```dart
/// "Tap row to complete items"
/// ```
String get tapRowToComplete => """Tap row to complete items""";
/// ```dart
/// "When off, items are only marked complete by tapping the checkbox."
/// ```
String get tapRowToCompleteBody =>
"""When off, items are only marked complete by tapping the checkbox.""";
/// ```dart
/// "Language"
/// ```
@@ -1390,6 +1406,10 @@ Please complete login in your browser.""",
"""about.feedback""": """Feedback & issues""",
"""settings.title""": """App Settings""",
"""settings.generalSection""": """General""",
"""settings.interfaceSection""": """Interface""",
"""settings.tapRowToComplete""": """Tap row to complete items""",
"""settings.tapRowToCompleteBody""":
"""When off, items are only marked complete by tapping the checkbox.""",
"""settings.language""": """Language""",
"""settings.languageNames.system""": """System default""",
"""settings.languageNames.english""": """English""",

View File

@@ -59,6 +59,9 @@ about:
settings:
title: App Settings
generalSection: General
interfaceSection: Interface
tapRowToComplete: Tap row to complete items
tapRowToCompleteBody: "When off, items are only marked complete by tapping the checkbox."
language: Language
languageNames:
system: "System default"

View File

@@ -363,6 +363,22 @@ class SettingsMessagesDe extends SettingsMessages {
/// ```
String get generalSection => """Allgemein""";
/// ```dart
/// "Oberfläche"
/// ```
String get interfaceSection => """Oberfläche""";
/// ```dart
/// "Eintrag durch Tippen der Zeile abhaken"
/// ```
String get tapRowToComplete => """Eintrag durch Tippen der Zeile abhaken""";
/// ```dart
/// "Wenn aus, werden Einträge nur durch Tippen auf das Kontrollkästchen abgehakt."
/// ```
String get tapRowToCompleteBody =>
"""Wenn aus, werden Einträge nur durch Tippen auf das Kontrollkästchen abgehakt.""";
/// ```dart
/// "Sprache"
/// ```
@@ -1403,6 +1419,10 @@ Bitte melde dich in deinem Browser an.""",
"""about.feedback""": """Feedback & Probleme""",
"""settings.title""": """App-Einstellungen""",
"""settings.generalSection""": """Allgemein""",
"""settings.interfaceSection""": """Oberfläche""",
"""settings.tapRowToComplete""": """Eintrag durch Tippen der Zeile abhaken""",
"""settings.tapRowToCompleteBody""":
"""Wenn aus, werden Einträge nur durch Tippen auf das Kontrollkästchen abgehakt.""",
"""settings.language""": """Sprache""",
"""settings.languageNames.system""": """Systemstandard""",
"""settings.languageNames.english""": """English""",

View File

@@ -59,6 +59,9 @@ about:
settings:
title: App-Einstellungen
generalSection: Allgemein
interfaceSection: Oberfläche
tapRowToComplete: Eintrag durch Tippen der Zeile abhaken
tapRowToCompleteBody: "Wenn aus, werden Einträge nur durch Tippen auf das Kontrollkästchen abgehakt."
language: Sprache
languageNames:
system: Systemstandard

View File

@@ -363,6 +363,22 @@ class SettingsMessagesEs extends SettingsMessages {
/// ```
String get generalSection => """General""";
/// ```dart
/// "Interfaz"
/// ```
String get interfaceSection => """Interfaz""";
/// ```dart
/// "Tocar la fila para completar elementos"
/// ```
String get tapRowToComplete => """Tocar la fila para completar elementos""";
/// ```dart
/// "Cuando está desactivado, los elementos solo se marcan como completados al tocar la casilla."
/// ```
String get tapRowToCompleteBody =>
"""Cuando está desactivado, los elementos solo se marcan como completados al tocar la casilla.""";
/// ```dart
/// "Idioma"
/// ```
@@ -1398,6 +1414,10 @@ Por favor, completa el inicio de sesión en tu navegador.""",
"""about.feedback""": """Comentarios y problemas""",
"""settings.title""": """Ajustes de la app""",
"""settings.generalSection""": """General""",
"""settings.interfaceSection""": """Interfaz""",
"""settings.tapRowToComplete""": """Tocar la fila para completar elementos""",
"""settings.tapRowToCompleteBody""":
"""Cuando está desactivado, los elementos solo se marcan como completados al tocar la casilla.""",
"""settings.language""": """Idioma""",
"""settings.languageNames.system""": """Predeterminado del sistema""",
"""settings.languageNames.english""": """English""",

View File

@@ -59,6 +59,9 @@ about:
settings:
title: Ajustes de la app
generalSection: General
interfaceSection: Interfaz
tapRowToComplete: Tocar la fila para completar elementos
tapRowToCompleteBody: "Cuando está desactivado, los elementos solo se marcan como completados al tocar la casilla."
language: Idioma
languageNames:
system: Predeterminado del sistema

View File

@@ -363,6 +363,23 @@ class SettingsMessagesFr extends SettingsMessages {
/// ```
String get generalSection => """Général""";
/// ```dart
/// "Interface"
/// ```
String get interfaceSection => """Interface""";
/// ```dart
/// "Toucher la ligne pour cocher les éléments"
/// ```
String get tapRowToComplete =>
"""Toucher la ligne pour cocher les éléments""";
/// ```dart
/// "Quand désactivé, les éléments ne sont cochés qu'en touchant la case."
/// ```
String get tapRowToCompleteBody =>
"""Quand désactivé, les éléments ne sont cochés qu'en touchant la case.""";
/// ```dart
/// "Langue"
/// ```
@@ -1401,6 +1418,11 @@ Veuillez terminer la connexion dans votre navigateur.""",
"""about.feedback""": """Commentaires & problèmes""",
"""settings.title""": """Réglages de l'app""",
"""settings.generalSection""": """Général""",
"""settings.interfaceSection""": """Interface""",
"""settings.tapRowToComplete""":
"""Toucher la ligne pour cocher les éléments""",
"""settings.tapRowToCompleteBody""":
"""Quand désactivé, les éléments ne sont cochés qu'en touchant la case.""",
"""settings.language""": """Langue""",
"""settings.languageNames.system""": """Par défaut du système""",
"""settings.languageNames.english""": """English""",

View File

@@ -59,6 +59,9 @@ about:
settings:
title: "Réglages de l'app"
generalSection: "Général"
interfaceSection: Interface
tapRowToComplete: Toucher la ligne pour cocher les éléments
tapRowToCompleteBody: "Quand désactivé, les éléments ne sont cochés qu'en touchant la case."
language: Langue
languageNames:
system: "Par défaut du système"

View File

@@ -361,6 +361,22 @@ class SettingsMessagesHe extends SettingsMessages {
/// ```
String get generalSection => """כללי""";
/// ```dart
/// "ממשק"
/// ```
String get interfaceSection => """ממשק""";
/// ```dart
/// "השלם פריטים בלחיצה על השורה"
/// ```
String get tapRowToComplete => """השלם פריטים בלחיצה על השורה""";
/// ```dart
/// "כאשר כבוי, פריטים מסומנים כהושלמו רק בלחיצה על תיבת הסימון."
/// ```
String get tapRowToCompleteBody =>
"""כאשר כבוי, פריטים מסומנים כהושלמו רק בלחיצה על תיבת הסימון.""";
/// ```dart
/// "שפה"
/// ```
@@ -1391,6 +1407,10 @@ Map<String, String> get messagesHeMap => {
"""about.feedback""": """משוב ובעיות""",
"""settings.title""": """הגדרות האפליקציה""",
"""settings.generalSection""": """כללי""",
"""settings.interfaceSection""": """ממשק""",
"""settings.tapRowToComplete""": """השלם פריטים בלחיצה על השורה""",
"""settings.tapRowToCompleteBody""":
"""כאשר כבוי, פריטים מסומנים כהושלמו רק בלחיצה על תיבת הסימון.""",
"""settings.language""": """שפה""",
"""settings.languageNames.system""": """ברירת מחדל (שפת המערכת)""",
"""settings.languageNames.english""": """English""",

View File

@@ -59,6 +59,9 @@ about:
settings:
title: הגדרות האפליקציה
generalSection: כללי
interfaceSection: ממשק
tapRowToComplete: השלם פריטים בלחיצה על השורה
tapRowToCompleteBody: כאשר כבוי, פריטים מסומנים כהושלמו רק בלחיצה על תיבת הסימון.
language: שפה
languageNames:
system: ברירת מחדל (שפת המערכת)

View File

@@ -10,6 +10,7 @@ class PrefsService {
static const _notificationsIntroSeenKey = 'notifications_intro_seen';
static const _localeKey = 'locale';
static const _themeModeKey = 'theme_mode';
static const _checklistTapRowToToggleKey = 'checklist_tap_row_to_toggle';
final _storage = const FlutterSecureStorage();
int? _lastHouseId;
@@ -32,6 +33,9 @@ class PrefsService {
String? _themeMode;
String? get themeMode => _themeMode;
bool _checklistTapRowToToggle = false;
bool get checklistTapRowToToggle => _checklistTapRowToToggle;
Future<void> load() async {
final lastHouse = await _storage.read(key: _lastHouseKey);
if (lastHouse != null) _lastHouseId = int.tryParse(lastHouse);
@@ -50,6 +54,9 @@ class PrefsService {
_locale = await _storage.read(key: _localeKey);
_themeMode = await _storage.read(key: _themeModeKey);
final tapRow = await _storage.read(key: _checklistTapRowToToggleKey);
if (tapRow != null) _checklistTapRowToToggle = tapRow == 'true';
}
Future<void> setLastHouseId(int id) async {
@@ -91,6 +98,14 @@ class PrefsService {
}
}
Future<void> setChecklistTapRowToToggle(bool value) async {
_checklistTapRowToToggle = value;
await _storage.write(
key: _checklistTapRowToToggleKey,
value: value.toString(),
);
}
Future<void> setNotificationsIntroSeen(bool value) async {
_notificationsIntroSeen = value;
await _storage.write(
@@ -106,11 +121,13 @@ class PrefsService {
_notificationsIntroSeen = false;
_locale = null;
_themeMode = null;
_checklistTapRowToToggle = false;
await _storage.delete(key: _lastHouseKey);
await _storage.delete(key: _notificationsEnabledKey);
await _storage.delete(key: _pollIntervalMinutesKey);
await _storage.delete(key: _notificationsIntroSeenKey);
await _storage.delete(key: _localeKey);
await _storage.delete(key: _themeModeKey);
await _storage.delete(key: _checklistTapRowToToggleKey);
}
}

View File

@@ -5,6 +5,7 @@ import 'package:pantry/models/category.dart' as models;
import 'package:pantry/models/checklist.dart';
import 'package:pantry/services/auth_service.dart';
import 'package:pantry/services/checklist_service.dart';
import 'package:pantry/services/prefs_service.dart';
import 'package:pantry/utils/category_icons.dart';
import 'package:pantry/utils/rrule.dart';
import 'package:pantry/widgets/image_preview.dart';
@@ -35,13 +36,14 @@ class ChecklistItemTile extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final dimmed = item.done;
final tapRowToToggle = PrefsService.instance.checklistTapRowToToggle;
return Material(
type: MaterialType.transparency,
child: Opacity(
opacity: dimmed ? 0.5 : 1.0,
child: InkWell(
onTap: () => onToggle(item),
onTap: tapRowToToggle ? () => onToggle(item) : null,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
child: Row(

View File

@@ -19,6 +19,7 @@ class _SettingsViewState extends State<SettingsView> {
late int _pollIntervalMinutes;
late String? _selectedLocale;
late String? _selectedTheme;
late bool _tapRowToComplete;
static const _pollOptions = [15, 30, 60, 120, 360];
@@ -29,6 +30,13 @@ class _SettingsViewState extends State<SettingsView> {
_pollIntervalMinutes = PrefsService.instance.pollIntervalMinutes;
_selectedLocale = PrefsService.instance.locale;
_selectedTheme = PrefsService.instance.themeMode;
_tapRowToComplete = PrefsService.instance.checklistTapRowToToggle;
}
Future<void> _setTapRowToComplete(bool value) async {
await PrefsService.instance.setChecklistTapRowToToggle(value);
if (!mounted) return;
setState(() => _tapRowToComplete = value);
}
// -- Language --
@@ -173,6 +181,15 @@ class _SettingsViewState extends State<SettingsView> {
),
),
// -- Interface --
_SectionHeader(m.settings.interfaceSection),
SwitchListTile(
title: Text(m.settings.tapRowToComplete),
subtitle: Text(m.settings.tapRowToCompleteBody),
value: _tapRowToComplete,
onChanged: _setTapRowToComplete,
),
// -- Notifications --
_SectionHeader(m.settings.notificationsSection),
SwitchListTile(