import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:timezone/timezone.dart' as tz; /// Single source of truth for time-zone display prefs (v1: local-only). /// Mirrors LocaleProvider: ChangeNotifier + SharedPreferences + notifyListeners. /// Backend sync (AppUser.multitime) is a later phase; for now prefs stay on-device /// so the settings card in the screenshot works standalone + multilingual. class TimezoneProvider with ChangeNotifier { static const _zoneKey = 'app_timezone_id'; static const _patternKey = 'app_date_pattern'; static const _is24hKey = 'app_time_24h'; static const _weekStartKey = 'app_week_start'; /// Curated quick-pick list matching the settings mock. static const commonZoneIds = [ 'Asia/Kolkata', 'Asia/Dubai', 'Asia/Singapore', 'Asia/Kuala_Lumpur', 'Asia/Hong_Kong', 'Asia/Shanghai', 'Asia/Taipei', 'Asia/Tokyo', 'Asia/Seoul', 'Asia/Bangkok', 'Asia/Jakarta', 'Asia/Manila', 'Asia/Karachi', 'Europe/London', 'Europe/Paris', 'Europe/Berlin', 'America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles', 'America/Toronto', 'Australia/Sydney', 'UTC', ]; static const datePatterns = ['dd-MM-yyyy', 'MM-dd-yyyy', 'yyyy-MM-dd']; static const weekDays = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', ]; String _zoneId = 'Asia/Kolkata'; String get zoneId => _zoneId; String _datePattern = 'dd-MM-yyyy'; String get datePattern => _datePattern; bool _is24h = true; bool get is24h => _is24h; String _weekStart = 'Monday'; String get weekStart => _weekStart; bool _ready = false; bool get ready => _ready; /// Short city label: 'Asia/Kolkata' -> 'Kolkata', 'UTC' -> 'UTC'. static String cityOf(String id) { if (id == 'UTC') return 'UTC'; final parts = id.split('/'); final raw = parts.isNotEmpty ? parts.last : id; return raw.replaceAll('_', ' '); } Future init() async { final prefs = await SharedPreferences.getInstance(); final z = prefs.getString(_zoneKey); if (z != null && z.isNotEmpty) _zoneId = z; final p = prefs.getString(_patternKey); if (p != null && datePatterns.contains(p)) _datePattern = p; final h = prefs.getBool(_is24hKey); if (h != null) _is24h = h; final w = prefs.getString(_weekStartKey); if (w != null && weekDays.contains(w)) _weekStart = w; _ready = true; notifyListeners(); } Future setZone(String id) async { _zoneId = id; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_zoneKey, id); notifyListeners(); } Future setDatePattern(String p) async { if (!datePatterns.contains(p)) return; _datePattern = p; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_patternKey, p); notifyListeners(); } Future setIs24h(bool v) async { _is24h = v; final prefs = await SharedPreferences.getInstance(); await prefs.setBool(_is24hKey, v); notifyListeners(); } Future setWeekStart(String d) async { if (!weekDays.contains(d)) return; _weekStart = d; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_weekStartKey, d); notifyListeners(); } /// Explicit save (button in the mock). Values are already persisted on /// change; this re-persists + notifies so callers can show a snackbar. Future save() async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_zoneKey, _zoneId); await prefs.setString(_patternKey, _datePattern); await prefs.setBool(_is24hKey, _is24h); await prefs.setString(_weekStartKey, _weekStart); notifyListeners(); } tz.Location get location { try { return tz.getLocation(_zoneId); } catch (_) { return tz.getLocation('UTC'); } } tz.TZDateTime nowInZone() { try { return tz.TZDateTime.now(location); } catch (_) { return tz.TZDateTime.now(tz.getLocation('UTC')); } } /// e.g. 'GMT+5:30', 'GMT-4:00', 'GMT'. DST-aware via timezone DB. String offsetLabel([tz.TZDateTime? at]) { try { final dt = at ?? nowInZone(); final offset = dt.timeZoneOffset; if (offset == Duration.zero) return 'GMT'; final sign = offset.isNegative ? '-' : '+'; final abs = offset.abs(); final h = abs.inHours.toString(); final m = (abs.inMinutes % 60).toString().padLeft(2, '0'); return 'GMT$sign$h:$m'; } catch (_) { return ''; } } /// 'Kolkata (GMT+5:30)' style label for dropdown rows. String displayLabel(String id) { try { final loc = tz.getLocation(id); final now = tz.TZDateTime.now(loc); final offset = now.timeZoneOffset; final sign = offset.isNegative ? '-' : '+'; final abs = offset.abs(); final off = offset == Duration.zero ? 'GMT' : 'GMT$sign${abs.inHours}:${(abs.inMinutes % 60).toString().padLeft(2, '0')}'; return '${cityOf(id)} ($off)'; } catch (_) { return cityOf(id); } } }