diff --git a/.changes/2120-localised-time-format.md b/.changes/2120-localised-time-format.md new file mode 100644 index 000000000000..a0a43a0fb014 --- /dev/null +++ b/.changes/2120-localised-time-format.md @@ -0,0 +1 @@ +- [New] : Time format is now based on the your localised system setting (12 Hour/24 Hour) \ No newline at end of file diff --git a/app/lib/common/utils/language.dart b/app/lib/common/utils/language.dart deleted file mode 100644 index f19070a4a931..000000000000 --- a/app/lib/common/utils/language.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:acter/features/settings/model/language_model.dart'; -import 'package:acter/features/settings/providers/settings_providers.dart'; -import 'package:acter_flutter_sdk/acter_flutter_sdk.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -const languagePrefKey = 'a3.language'; - -Future initLanguage(WidgetRef ref) async { - final prefLanguageCode = await getLanguage(); - final deviceLanguageCode = PlatformDispatcher.instance.locale.languageCode; - final bool isLanguageContain = LanguageModel.allLanguagesList - .where((element) => element.languageCode == deviceLanguageCode) - .toList() - .isNotEmpty; - - if (prefLanguageCode != null) { - ref.read(languageProvider.notifier).update( - (state) => prefLanguageCode, - ); - } else if (isLanguageContain) { - ref.read(languageProvider.notifier).update((state) => deviceLanguageCode); - } -} - -Future setLanguage(String languageCode) async { - final prefInstance = await sharedPrefs(); - await prefInstance.setString(languagePrefKey, languageCode); -} - -Future getLanguage() async { - final prefInstance = await sharedPrefs(); - return prefInstance.getString(languagePrefKey); -} diff --git a/app/lib/common/utils/utils.dart b/app/lib/common/utils/utils.dart index 3572c8023378..093d7f56da54 100644 --- a/app/lib/common/utils/utils.dart +++ b/app/lib/common/utils/utils.dart @@ -105,26 +105,30 @@ String formatDate(CalendarEvent e) { String formatTime(CalendarEvent e) { final start = toDartDatetime(e.utcStart()).toLocal(); final end = toDartDatetime(e.utcEnd()).toLocal(); - return '${Jiffy.parseFromDateTime(start).jm} - ${Jiffy.parseFromDateTime(end).jm}'; + return '${DateFormat.jm().format(start)} - ${DateFormat.jm().format(end)}'; } String getMonthFromDate(UtcDateTime utcDateTime) { final localDateTime = toDartDatetime(utcDateTime).toLocal(); - final month = DateFormat('MMM').format(localDateTime); + final month = DateFormat.MMM().format(localDateTime); return month; } String getDayFromDate(UtcDateTime utcDateTime) { final localDateTime = toDartDatetime(utcDateTime).toLocal(); - final day = DateFormat('dd').format(localDateTime); + final day = DateFormat.d().format(localDateTime); return day; } -String jiffyTime(int timeInterval) { +String getTimeFromDate(BuildContext context, UtcDateTime utcDateTime) { + final localDateTime = toDartDatetime(utcDateTime).toLocal(); + return DateFormat.jm().format(localDateTime); +} + +String jiffyTime(BuildContext context, int timeInterval) { final jiffyTime = Jiffy.parseFromMillisecondsSinceEpoch(timeInterval); final now = Jiffy.now().startOf(Unit.day); if (now.isSame(jiffyTime, unit: Unit.day)) { - // (00:00 AM/PM) return jiffyTime.jm; } else { final yesterday = now.subtract(days: 1); diff --git a/app/lib/common/widgets/chat/convo_card.dart b/app/lib/common/widgets/chat/convo_card.dart index 0d1ff8574646..92451a0b201a 100644 --- a/app/lib/common/widgets/chat/convo_card.dart +++ b/app/lib/common/widgets/chat/convo_card.dart @@ -431,7 +431,7 @@ class _TrailingWidget extends ConsumerWidget { } return Text( - jiffyTime(eventItem.originServerTs()), + jiffyTime(context, eventItem.originServerTs()), style: Theme.of(context).textTheme.labelMedium, ); } diff --git a/app/lib/features/events/pages/event_details_page.dart b/app/lib/features/events/pages/event_details_page.dart index 4aef0d60e57f..4a1e843ba1ee 100644 --- a/app/lib/features/events/pages/event_details_page.dart +++ b/app/lib/features/events/pages/event_details_page.dart @@ -275,10 +275,7 @@ class _EventDetailPageConsumerState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.start, children: [ // Date and Month - EventDateWidget( - calendarEvent: calendarEvent, - size: 80, - ), + EventDateWidget(calendarEvent: calendarEvent), // Title, Space, User counts, comments counts and like counts Expanded( child: Column( @@ -498,12 +495,8 @@ class _EventDetailPageConsumerState extends ConsumerState { Jiffy.parseFromDateTime(toDartDatetime(ev.utcStart()).toLocal()) .endOf(Unit.hour) .fromNow(); - final startDate = - Jiffy.parseFromDateTime(toDartDatetime(ev.utcStart()).toLocal()) - .format(pattern: 'EEE, MMM dd, yyyy AT hh:mm'); - final endDate = - Jiffy.parseFromDateTime(toDartDatetime(ev.utcEnd()).toLocal()) - .format(pattern: 'EEE, MMM dd, yyyy AT hh:mm'); + + String eventDateTime = '${formatDate(ev)} (${formatTime(ev)})'; String eventTimingTitle = switch (getEventType(ev)) { EventFilters.ongoing => '${L10n.of(context).eventStarted} $agoTime', @@ -518,10 +511,14 @@ class _EventDetailPageConsumerState extends ConsumerState { child: Column( children: [ ListTile( - leading: const Icon(Atlas.calendar_dots), + leading: const Icon(Atlas.clock_time), title: Text(eventTimingTitle), onTap: canChangeDate ? () => showChangeDateSheet(ev) : null, - subtitle: Text('$startDate - $endDate'), + ), + ListTile( + leading: const Icon(Atlas.calendar_dots), + title: Text(eventDateTime), + onTap: canChangeDate ? () => showChangeDateSheet(ev) : null, ), ListTile( leading: const Icon(Atlas.accounts_group_people), diff --git a/app/lib/features/events/widgets/event_date_widget.dart b/app/lib/features/events/widgets/event_date_widget.dart index bdc1c4e2e9e4..92cd3ad0b51d 100644 --- a/app/lib/features/events/widgets/event_date_widget.dart +++ b/app/lib/features/events/widgets/event_date_widget.dart @@ -6,13 +6,8 @@ import 'package:flutter/material.dart'; class EventDateWidget extends StatelessWidget { final CalendarEvent calendarEvent; - final double size; - const EventDateWidget({ - super.key, - required this.calendarEvent, - this.size = 70, - }); + const EventDateWidget({super.key, required this.calendarEvent}); @override Widget build(BuildContext context) { @@ -22,19 +17,27 @@ class EventDateWidget extends StatelessWidget { Widget _buildEventDate(BuildContext context) { final day = getDayFromDate(calendarEvent.utcStart()); final month = getMonthFromDate(calendarEvent.utcStart()); + final startTime = getTimeFromDate(context, calendarEvent.utcStart()); return Card( color: getColorBasedOnEventType(context), child: Container( - height: size, - width: size, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text(month), - Text(day, style: Theme.of(context).textTheme.titleLarge), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(month, style: Theme.of(context).textTheme.titleSmall), + const SizedBox(width: 4), + Text(day, style: Theme.of(context).textTheme.titleSmall), + ], + ), + Text(startTime, style: Theme.of(context).textTheme.labelMedium), ], ), ), diff --git a/app/lib/features/settings/pages/language_select_page.dart b/app/lib/features/settings/pages/language_select_page.dart index 5dffe3da7500..a3a10b7dc644 100644 --- a/app/lib/features/settings/pages/language_select_page.dart +++ b/app/lib/features/settings/pages/language_select_page.dart @@ -1,4 +1,3 @@ -import 'package:acter/common/utils/language.dart'; import 'package:acter/common/utils/utils.dart'; import 'package:acter/common/widgets/with_sidebar.dart'; import 'package:acter/features/settings/model/language_model.dart'; @@ -45,12 +44,11 @@ class LanguageSelectPage extends ConsumerWidget { return Card( child: RadioListTile( value: language.languageCode, - groupValue: ref.watch(languageProvider), + groupValue: ref.watch(localeProvider), title: Text(language.languageName), onChanged: (value) async { if (value != null) { - await setLanguage(value); - ref.read(languageProvider.notifier).update((state) => value); + await ref.read(localeProvider.notifier).setLanguage(value); } }, ), diff --git a/app/lib/features/settings/providers/notifiers/locale_notifier.dart b/app/lib/features/settings/providers/notifiers/locale_notifier.dart new file mode 100644 index 000000000000..b57a94e81ff5 --- /dev/null +++ b/app/lib/features/settings/providers/notifiers/locale_notifier.dart @@ -0,0 +1,38 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:acter/features/settings/model/language_model.dart'; +import 'package:acter_flutter_sdk/acter_flutter_sdk.dart'; +import 'package:flutter/foundation.dart'; +import 'package:intl/intl.dart'; + +class LocaleNotifier extends StateNotifier { + LocaleNotifier() : super('en'); + + static const languagePrefKey = 'a3.language'; + + Future initLanguage() async { + final prefInstance = await sharedPrefs(); + final prefLanguageCode = prefInstance.getString(languagePrefKey); + final deviceLanguageCode = PlatformDispatcher.instance.locale.languageCode; + final bool isLanguageContain = LanguageModel.allLanguagesList + .where((element) => element.languageCode == deviceLanguageCode) + .toList() + .isNotEmpty; + + if (prefLanguageCode != null) { + _localSet(prefLanguageCode); + } else if (isLanguageContain) { + _localSet(deviceLanguageCode); + } + } + + Future setLanguage(String languageCode) async { + final prefInstance = await sharedPrefs(); + await prefInstance.setString(languagePrefKey, languageCode); + _localSet(languageCode); + } + + void _localSet(String languageCode) { + state = languageCode; + Intl.defaultLocale = languageCode; + } +} diff --git a/app/lib/features/settings/providers/settings_providers.dart b/app/lib/features/settings/providers/settings_providers.dart index 1d4918e83922..d40504ff38b9 100644 --- a/app/lib/features/settings/providers/settings_providers.dart +++ b/app/lib/features/settings/providers/settings_providers.dart @@ -6,6 +6,7 @@ import 'package:acter/common/utils/main.dart'; import 'package:acter/common/utils/utils.dart'; import 'package:acter/features/home/providers/client_providers.dart'; import 'package:acter/features/settings/providers/notifiers/labs_features.dart'; +import 'package:acter/features/settings/providers/notifiers/locale_notifier.dart'; import 'package:acter_flutter_sdk/acter_flutter_sdk.dart'; import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -38,7 +39,8 @@ final featuresProvider = ); }); -final languageProvider = StateProvider((ref) => 'en'); +final localeProvider = + StateNotifierProvider((ref) => LocaleNotifier()); final ignoredUsersProvider = FutureProvider>((ref) async { final account = ref.watch(accountProvider); @@ -85,7 +87,10 @@ final asyncIsActiveProvider = // helper Future updateFeatureState( - WidgetRef ref, LabsFeature f, bool value,) async { + WidgetRef ref, + LabsFeature f, + bool value, +) async { await ref.read(featuresProvider.notifier).setActive(f, value); return ref.read(featuresProvider).isActive(f); } diff --git a/app/lib/main.dart b/app/lib/main.dart index fb2b2eb89357..b77b7274be8c 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -8,7 +8,6 @@ import 'package:acter/common/themes/acter_theme.dart'; import 'package:acter/common/tutorial_dialogs/bottom_navigation_tutorials/bottom_navigation_tutorials.dart'; import 'package:acter/common/tutorial_dialogs/space_overview_tutorials/create_or_join_space_tutorials.dart'; import 'package:acter/common/tutorial_dialogs/space_overview_tutorials/space_overview_tutorials.dart'; -import 'package:acter/common/utils/language.dart'; import 'package:acter/common/utils/logging.dart'; import 'package:acter/common/utils/main.dart'; import 'package:acter/config/setup.dart'; @@ -20,12 +19,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/date_symbol_data_local.dart'; import 'package:video_player_media_kit/video_player_media_kit.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:acter/config/env.g.dart'; void main(List args) async { configSetup(); + + //THIS IS TO MANAGE DATE AND TIME FORMATING BASED ON THE LOCAL + await initializeDateFormatting(); + if (args.isNotEmpty) { await cliMain(args); } else { @@ -98,7 +102,7 @@ class _ActerState extends ConsumerState with WidgetsBindingObserver { @override void initState() { super.initState(); - initLanguage(ref); + ref.read(localeProvider.notifier).initLanguage(); WidgetsBinding.instance.addObserver(this); } @@ -115,7 +119,7 @@ class _ActerState extends ConsumerState with WidgetsBindingObserver { @override Widget build(BuildContext context) { - final language = ref.watch(languageProvider); + final language = ref.watch(localeProvider); // all toast msgs will appear at bottom final builder = EasyLoading.init();