import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:intl/intl.dart'; import 'package:shared_preferences/src/shared_preferences_legacy.dart'; import 'package:simplecloudnotifier/state/globals.dart'; enum AppSettingsDateFormat { ISO(displayStr: 'ISO (yyyy-MM-dd)', key: 'ISO'), German(displayStr: 'German (dd.MM.yyyy)', key: 'German'), US(displayStr: 'US (MM/dd/yyyy)', key: 'US'); const AppSettingsDateFormat({required this.displayStr, required this.key}); final String displayStr; final String key; @override toString() => displayStr; DateFormat dateFormat() { switch (this) { case AppSettingsDateFormat.ISO: return DateFormat('yyyy-MM-dd HH:mm'); case AppSettingsDateFormat.German: return DateFormat('dd.MM.yyyy HH:mm'); case AppSettingsDateFormat.US: return DateFormat('MM/dd/yyyy HH:mm'); } } static AppSettingsDateFormat? parse(String? string) { if (string == null) return null; return values.firstWhere((e) => e.key == string, orElse: null); } } class AppSettings extends ChangeNotifier { bool groupNotifications = true; int messagePageSize = 128; bool devMode = false; bool showDebugButton = false; bool backgroundRefreshMessageListOnPop = false; bool alwaysBackgroundRefreshMessageListOnLifecycleResume = true; AppSettingsDateFormat dateFormat = AppSettingsDateFormat.ISO; int messagePreviewLength = 3; AppNotificationSettings notification0 = AppNotificationSettings(); AppNotificationSettings notification1 = AppNotificationSettings(); AppNotificationSettings notification2 = AppNotificationSettings(); static AppSettings? _singleton = AppSettings._internal(); factory AppSettings() { return _singleton ?? (_singleton = AppSettings._internal()); } AppSettings._internal() { load(); } void reset() { groupNotifications = true; messagePageSize = 128; devMode = false; showDebugButton = false; backgroundRefreshMessageListOnPop = false; alwaysBackgroundRefreshMessageListOnLifecycleResume = true; dateFormat = AppSettingsDateFormat.ISO; messagePreviewLength = 3; notification0 = AppNotificationSettings(); notification1 = AppNotificationSettings(); notification2 = AppNotificationSettings(); notifyListeners(); } void load() { groupNotifications = Globals().sharedPrefs.getBool('settings.groupNotifications') ?? groupNotifications; messagePageSize = Globals().sharedPrefs.getInt('settings.messagePageSize') ?? messagePageSize; devMode = Globals().sharedPrefs.getBool('settings.devMode') ?? devMode; showDebugButton = Globals().sharedPrefs.getBool('settings.showDebugButton') ?? showDebugButton; backgroundRefreshMessageListOnPop = Globals().sharedPrefs.getBool('settings.backgroundRefreshMessageListOnPop') ?? backgroundRefreshMessageListOnPop; alwaysBackgroundRefreshMessageListOnLifecycleResume = Globals().sharedPrefs.getBool('settings.alwaysBackgroundRefreshMessageListOnLifecycleResume') ?? alwaysBackgroundRefreshMessageListOnLifecycleResume; dateFormat = AppSettingsDateFormat.parse(Globals().sharedPrefs.getString('settings.dateFormat')) ?? dateFormat; messagePreviewLength = Globals().sharedPrefs.getInt('settings.messagePreviewLength') ?? messagePreviewLength; notification0 = AppNotificationSettings.load(Globals().sharedPrefs, 'settings.notification0'); notification1 = AppNotificationSettings.load(Globals().sharedPrefs, 'settings.notification1'); notification2 = AppNotificationSettings.load(Globals().sharedPrefs, 'settings.notification2'); } Future save() async { await Globals().sharedPrefs.setBool('settings.groupNotifications', groupNotifications); await Globals().sharedPrefs.setInt('settings.messagePageSize', messagePageSize); await Globals().sharedPrefs.setBool('settings.devMode', devMode); await Globals().sharedPrefs.setBool('settings.showDebugButton', showDebugButton); await Globals().sharedPrefs.setBool('settings.backgroundRefreshMessageListOnPop', backgroundRefreshMessageListOnPop); await Globals().sharedPrefs.setBool('settings.alwaysBackgroundRefreshMessageListOnLifecycleResume', alwaysBackgroundRefreshMessageListOnLifecycleResume); await Globals().sharedPrefs.setString('settings.dateFormat', dateFormat.key); await Globals().sharedPrefs.setInt('settings.messagePreviewLength', messagePreviewLength); await notification0.save(Globals().sharedPrefs, 'settings.notification0'); await notification1.save(Globals().sharedPrefs, 'settings.notification1'); await notification2.save(Globals().sharedPrefs, 'settings.notification2'); } void update(void Function(AppSettings p) fn) { fn(this); save(); notifyListeners(); } void updateNotification(int prio, AppNotificationSettings Function(AppNotificationSettings p) fn) { if (prio == 0) { notification0 = fn(notification0); } else if (prio == 1) { notification1 = fn(notification1); } else if (prio == 2) { notification2 = fn(notification2); } save(); notifyListeners(); } AppNotificationSettings getNotificationSettings(int? prio) { if (prio != null && prio == 0) { return notification0; } else if (prio != null && prio == 1) { return notification1; } else if (prio != null && prio == 2) { return notification2; } else { return AppNotificationSettings(); } } } class AppNotificationSettings { // Immutable AppNotificationSettings({ this.enableLights = false, this.enableVibration = true, this.playSound = true, this.sound = null, this.silent = false, this.timeoutAfter = null, }); final bool enableLights; final bool enableVibration; final bool playSound; final String? sound; final bool silent; final int? timeoutAfter; Future save(SharedPreferences sharedPrefs, String prefix) async { await Globals().sharedPrefs.setBool('${prefix}.enableLights', enableLights); await Globals().sharedPrefs.setBool('${prefix}.enableVibration', enableVibration); await Globals().sharedPrefs.setBool('${prefix}.playSound', playSound); await Globals().sharedPrefs.setString('${prefix}.sound', _encode(sound)); await Globals().sharedPrefs.setBool('${prefix}.silent', silent); await Globals().sharedPrefs.setString('${prefix}.timeoutAfter', _encode(timeoutAfter)); } UriAndroidNotificationSound? soundURI() { return (sound != null) ? UriAndroidNotificationSound(sound!) : null; } AppNotificationSettings withEnableLights(bool v) => AppNotificationSettings(enableLights: v, enableVibration: enableVibration, playSound: playSound, sound: sound, silent: silent, timeoutAfter: timeoutAfter); AppNotificationSettings withEnableVibration(bool v) => AppNotificationSettings(enableLights: enableLights, enableVibration: v, playSound: playSound, sound: sound, silent: silent, timeoutAfter: timeoutAfter); AppNotificationSettings withPlaySound(bool v) => AppNotificationSettings(enableLights: enableLights, enableVibration: enableVibration, playSound: v, sound: sound, silent: silent, timeoutAfter: timeoutAfter); AppNotificationSettings withSound(String? v) => AppNotificationSettings(enableLights: enableLights, enableVibration: enableVibration, playSound: playSound, sound: v, silent: silent, timeoutAfter: timeoutAfter); AppNotificationSettings withSilent(bool v) => AppNotificationSettings(enableLights: enableLights, enableVibration: enableVibration, playSound: playSound, sound: sound, silent: v, timeoutAfter: timeoutAfter); AppNotificationSettings withTimeoutAfter(int? v) => AppNotificationSettings(enableLights: enableLights, enableVibration: enableVibration, playSound: playSound, sound: sound, silent: silent, timeoutAfter: v); static AppNotificationSettings load(SharedPreferences prefs, String prefix) { final def = AppNotificationSettings(); final enableLights = prefs.getBool('${prefix}.enableLights') ?? def.enableLights; final enableVibration = prefs.getBool('${prefix}.enableVibration') ?? def.enableVibration; final playSound = prefs.getBool('${prefix}.playSound') ?? def.playSound; final sound = _decode(prefs.getString('${prefix}.sound'), def.sound); final silent = prefs.getBool('${prefix}.silent') ?? def.silent; final timeoutAfter = _decode(prefs.getString('${prefix}.timeoutAfter'), def.timeoutAfter); return AppNotificationSettings( enableLights: enableLights, enableVibration: enableVibration, playSound: playSound, sound: sound, silent: silent, timeoutAfter: timeoutAfter, ); } } String _encode(T v) { return JsonEncoder().convert(v); } T _decode(String? v, T fallback) { if (v == null) return fallback; try { return JsonDecoder().convert(v) as T; } catch (_) { return fallback; } }