fixing version issue

This commit is contained in:
Azmat-7860
2026-10-04 23:19:49 +05:30
parent 0d7785b242
commit 15387ee4e5
11 changed files with 780 additions and 3 deletions
@@ -0,0 +1,383 @@
import 'dart:async';
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
import 'package:base_project/core/providers/locale_provider.dart';
import 'package:base_project/core/providers/timezone_provider.dart';
import 'package:base_project/l10n/app_localizations.dart';
import 'package:base_project/resources/app_colors.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
/// Time Zone Settings card, themed for base_project.
/// - Live ticking preview in the SELECTED zone (see time here / there).
/// - Current zone dropdown + common-zone quick chips.
/// - Date format / 12-24h / week-start prefs, persisted locally.
/// - Theming: surfaces + text from Theme colorScheme (dark-mode safe),
/// header/preview gradients from DynamicThemeProvider (logo-derived),
/// radii/spacing from UIConstants, inputs/buttons/chips from AppTheme.
/// - Multilingual: every label via AppLocalizations (EN/HI).
class TimezoneSettingsCard extends StatefulWidget {
const TimezoneSettingsCard({super.key});
@override
State<TimezoneSettingsCard> createState() => _TimezoneSettingsCardState();
}
class _TimezoneSettingsCardState extends State<TimezoneSettingsCard> {
Timer? _ticker;
@override
void initState() {
super.initState();
_ticker = Timer.periodic(const Duration(seconds: 1), (_) {
if (mounted) setState(() {});
});
}
@override
void dispose() {
_ticker?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final strings = AppLocalizations.of(context)!;
final localeCode = context.watch<LocaleProvider>().locale.languageCode;
// Listen to prefs so preview + chips update instantly on selection.
final tzPrefs = context.watch<TimezoneProvider>();
final colorScheme = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
final gradients =
context.watch<DynamicThemeProvider>().getGradientColors();
final gradStart =
gradients.isNotEmpty ? gradients.first : AppColors.primary;
final gradEnd =
gradients.length > 1 ? gradients.last : AppColors.primary2;
final now = tzPrefs.nowInZone();
final timePattern = tzPrefs.is24h ? 'HH:mm:ss' : 'hh:mm:ss a';
final timeStr = DateFormat(timePattern, localeCode).format(now);
final dateLine =
DateFormat('EEEE, MMMM d, yyyy', localeCode).format(now);
final offset = tzPrefs.offsetLabel(now);
final city = TimezoneProvider.cityOf(tzPrefs.zoneId);
final onGradient = Colors.white;
return Card(
margin: EdgeInsets.zero,
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header
Container(
padding: const EdgeInsets.fromLTRB(UIConstants.spacing16,
UIConstants.spacing14, UIConstants.spacing16, UIConstants.spacing14),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [gradStart, gradEnd],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(UIConstants.spacing8),
decoration: BoxDecoration(
color: onGradient.withValues(alpha: 0.2),
borderRadius:
BorderRadius.circular(UIConstants.radius12),
),
child: Icon(Icons.public,
color: onGradient, size: UIConstants.iconSizeMedium),
),
const SizedBox(width: UIConstants.spacing12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(strings.timeZoneSettings,
style: textTheme.titleMedium?.copyWith(
color: onGradient,
fontWeight: FontWeight.w700)),
const SizedBox(height: 2),
Text(strings.timeZoneSubtitle,
style: textTheme.bodySmall
?.copyWith(color: onGradient.withValues(alpha: 0.85))),
],
),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: UIConstants.spacing12,
vertical: UIConstants.spacing4),
decoration: BoxDecoration(
color: onGradient.withValues(alpha: 0.2),
borderRadius:
BorderRadius.circular(UIConstants.radiusFull),
),
child: Text('UTC',
style: TextStyle(
color: onGradient,
fontSize: 11,
fontWeight: FontWeight.w600)),
),
],
),
),
Padding(
padding: const EdgeInsets.all(UIConstants.spacing16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Live preview
Container(
padding: const EdgeInsets.all(UIConstants.spacing16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
gradStart.withValues(alpha: 0.9),
gradEnd.withValues(alpha: 0.9)
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
borderRadius:
BorderRadius.circular(UIConstants.radius16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('◷ ${strings.livePreview}',
style: TextStyle(
color: onGradient.withValues(alpha: 0.8),
fontSize: 11,
letterSpacing: 1.2)),
const SizedBox(height: UIConstants.spacing8),
Text(timeStr,
style: TextStyle(
color: onGradient,
fontSize: 38,
fontWeight: FontWeight.w800,
letterSpacing: 1)),
const SizedBox(height: 2),
Text(dateLine,
style: TextStyle(
color: onGradient.withValues(alpha: 0.9),
fontSize: 13)),
const SizedBox(height: UIConstants.spacing12),
Wrap(
spacing: UIConstants.spacing8,
runSpacing: UIConstants.spacing8,
children: [
_miniChip('◉ $city', onGradient),
_miniChip(offset, onGradient),
_miniChip(tzPrefs.datePattern, onGradient),
_miniChip(
tzPrefs.is24h
? strings.hour24
: strings.hour12,
onGradient),
],
),
],
),
),
const SizedBox(height: UIConstants.spacing16),
_sectionLabel(strings.currentTimeZone, colorScheme),
const SizedBox(height: UIConstants.spacing8),
DropdownButtonFormField<String>(
key: ValueKey('zone_${tzPrefs.zoneId}'),
initialValue: tzPrefs.zoneId,
items: TimezoneProvider.commonZoneIds
.map((id) => DropdownMenuItem(
value: id,
child: Text(tzPrefs.displayLabel(id),
style: textTheme.bodyMedium)))
.toList(),
onChanged: (v) {
if (v != null) tzPrefs.setZone(v);
},
),
const SizedBox(height: UIConstants.spacing16),
_sectionLabel(strings.commonTimeZones, colorScheme),
const SizedBox(height: UIConstants.spacing8),
Wrap(
spacing: UIConstants.spacing8,
runSpacing: UIConstants.spacing8,
children: TimezoneProvider.commonZoneIds.map((id) {
return ChoiceChip(
label: Text(TimezoneProvider.cityOf(id)),
selected: id == tzPrefs.zoneId,
onSelected: (_) => tzPrefs.setZone(id),
);
}).toList(),
),
const SizedBox(height: UIConstants.spacing16),
LayoutBuilder(builder: (context, constraints) {
final narrow = constraints.maxWidth < 520;
final fields = [
_labelled(strings.dateFormat,
DropdownButtonFormField<String>(
key: ValueKey('pat_${tzPrefs.datePattern}'),
initialValue: tzPrefs.datePattern,
items: TimezoneProvider.datePatterns
.map((p) => DropdownMenuItem(
value: p,
child: Text(p,
style: textTheme.bodyMedium)))
.toList(),
onChanged: (v) {
if (v != null) tzPrefs.setDatePattern(v);
},
)),
_labelled(
strings.timeFormat,
SegmentedButton<bool>(
segments: [
ButtonSegment(
value: false,
label: Text(strings.hour12)),
ButtonSegment(
value: true,
label: Text(strings.hour24)),
],
selected: {tzPrefs.is24h},
onSelectionChanged: (s) =>
tzPrefs.setIs24h(s.first),
)),
_labelled(strings.firstDayOfWeek,
DropdownButtonFormField<String>(
key: ValueKey('ws_${tzPrefs.weekStart}'),
initialValue: tzPrefs.weekStart,
items: TimezoneProvider.weekDays
.map((d) => DropdownMenuItem(
value: d,
child: Text(
_localizedWeekday(d, localeCode),
style: textTheme.bodyMedium)))
.toList(),
onChanged: (v) {
if (v != null) tzPrefs.setWeekStart(v);
},
)),
];
if (narrow) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
fields[0],
const SizedBox(height: UIConstants.spacing12),
fields[1],
const SizedBox(height: UIConstants.spacing12),
fields[2],
],
);
}
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: fields[0]),
const SizedBox(width: UIConstants.spacing8),
Expanded(child: fields[1]),
const SizedBox(width: UIConstants.spacing8),
Expanded(child: fields[2]),
],
);
}),
const SizedBox(height: UIConstants.spacing16),
Row(
children: [
Icon(Icons.info_outline,
size: UIConstants.iconSizeSmall,
color: colorScheme.onSurfaceVariant),
const SizedBox(width: UIConstants.spacing8),
Expanded(
child: Text(strings.storedInUtcNote,
style: textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant)),
),
],
),
const SizedBox(height: UIConstants.spacing12),
Align(
alignment: Alignment.centerRight,
child: ElevatedButton.icon(
onPressed: () async {
await tzPrefs.save();
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text(strings.preferencesSaved)),
);
}
},
icon: const Icon(Icons.save_outlined, size: 16),
label: Text(strings.savePreferences),
),
),
],
),
),
],
),
);
}
Widget _sectionLabel(String label, ColorScheme colorScheme) {
return Text('◉ $label',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w700,
letterSpacing: 0.6,
color: colorScheme.onSurfaceVariant));
}
Widget _miniChip(String text, Color onGradient) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: UIConstants.spacing12,
vertical: UIConstants.spacing4),
decoration: BoxDecoration(
color: onGradient.withValues(alpha: 0.18),
borderRadius: BorderRadius.circular(UIConstants.radiusFull),
),
child: Text(text, style: TextStyle(color: onGradient, fontSize: 11)),
);
}
Widget _labelled(String label, Widget child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Builder(builder: (context) {
final colorScheme = Theme.of(context).colorScheme;
return Text(label,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w700,
letterSpacing: 0.6,
color: colorScheme.onSurfaceVariant));
}),
const SizedBox(height: UIConstants.spacing8),
child,
],
);
}
/// Weekday names localized via intl for the current locale; values
/// stay canonical English for storage.
String _localizedWeekday(String canonical, String localeCode) {
// 2026-10-05 is a Monday; add index to get each weekday name.
final base = DateTime(2026, 10, 5);
final idx = TimezoneProvider.weekDays.indexOf(canonical);
if (idx < 0) return canonical;
return DateFormat('EEEE', localeCode)
.format(base.add(Duration(days: idx)));
}
}