adding multitimezone
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
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<void> 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<void> setZone(String id) async {
|
||||
_zoneId = id;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_zoneKey, id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setDatePattern(String p) async {
|
||||
if (!datePatterns.contains(p)) return;
|
||||
_datePattern = p;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_patternKey, p);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setIs24h(bool v) async {
|
||||
_is24h = v;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool(_is24hKey, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> 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<void> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user