From 83fd6736f6dbb6d1eac39fca02fe72d61e47473d Mon Sep 17 00:00:00 2001 From: Jake Fink Date: Thu, 28 Oct 2021 12:52:41 -0400 Subject: [PATCH] add date and time formatting methods to localize service (#1616) - uses Apple APIs for formatting on iOS - uses .Net APIs for formatting Android - implemented across project - remove unnecesary calls to DateTimeConverter --- src/Android/Services/LocalizeService.cs | 10 ++++++++++ src/App/Abstractions/ILocalizeService.cs | 15 +++++++++++++- src/App/Pages/Send/SendsPage.xaml | 1 - .../SettingsPage/SettingsPageViewModel.cs | 7 +++++-- src/App/Pages/Settings/SyncPageViewModel.cs | 6 +++++- src/App/Pages/Vault/CiphersPage.xaml | 1 - src/App/Pages/Vault/ViewPageViewModel.cs | 10 ++++++---- src/App/Utilities/DateTimeConverter.cs | 13 +++++++++++- src/iOS.Core/Services/LocalizeService.cs | 20 +++++++++++++++++++ 9 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/Android/Services/LocalizeService.cs b/src/Android/Services/LocalizeService.cs index bafcbacd2..ac62a1c7d 100644 --- a/src/Android/Services/LocalizeService.cs +++ b/src/Android/Services/LocalizeService.cs @@ -98,5 +98,15 @@ namespace Bit.Droid.Services Console.WriteLine(".NET Fallback Language/Locale:" + netLanguage + " (application-specific)"); return netLanguage; } + + public string GetLocaleShortDate(DateTime? date) + { + return date?.ToShortDateString() ?? string.Empty; + } + + public string GetLocaleShortTime(DateTime? time) + { + return time?.ToShortTimeString() ?? string.Empty; + } } } \ No newline at end of file diff --git a/src/App/Abstractions/ILocalizeService.cs b/src/App/Abstractions/ILocalizeService.cs index e5d009c4b..09b0fb924 100644 --- a/src/App/Abstractions/ILocalizeService.cs +++ b/src/App/Abstractions/ILocalizeService.cs @@ -1,9 +1,22 @@ -using System.Globalization; +using System; +using System.Globalization; namespace Bit.App.Abstractions { public interface ILocalizeService { CultureInfo GetCurrentCultureInfo(); + + /// + /// Format date using device locale. + /// Needed for iOS as it provides locales unsupported in .Net + /// + string GetLocaleShortDate(DateTime? date); + + /// + /// Format time using device locale. + /// Needed for iOS as it provides locales unsupported in .Net + /// + string GetLocaleShortTime(DateTime? time); } } diff --git a/src/App/Pages/Send/SendsPage.xaml b/src/App/Pages/Send/SendsPage.xaml index 40557f8f4..31f5ddbd5 100644 --- a/src/App/Pages/Send/SendsPage.xaml +++ b/src/App/Pages/Send/SendsPage.xaml @@ -17,7 +17,6 @@ - ("syncService"); _biometricService = ServiceContainer.Resolve("biometricService"); _policyService = ServiceContainer.Resolve("policyService"); + _localizeService = ServiceContainer.Resolve("localizeService"); GroupedItems = new ExtendedObservableCollection(); PageTitle = AppResources.Settings; @@ -86,8 +88,9 @@ namespace Bit.App.Pages if (lastSync != null) { lastSync = lastSync.Value.ToLocalTime(); - _lastSyncDate = string.Format("{0} {1}", lastSync.Value.ToShortDateString(), - lastSync.Value.ToShortTimeString()); + _lastSyncDate = string.Format("{0} {1}", + _localizeService.GetLocaleShortDate(lastSync.Value), + _localizeService.GetLocaleShortTime(lastSync.Value)); } if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout)) diff --git a/src/App/Pages/Settings/SyncPageViewModel.cs b/src/App/Pages/Settings/SyncPageViewModel.cs index c80048741..f0f8674b8 100644 --- a/src/App/Pages/Settings/SyncPageViewModel.cs +++ b/src/App/Pages/Settings/SyncPageViewModel.cs @@ -14,6 +14,7 @@ namespace Bit.App.Pages private readonly IPlatformUtilsService _platformUtilsService; private readonly IStorageService _storageService; private readonly ISyncService _syncService; + private readonly ILocalizeService _localizeService; private string _lastSync = "--"; private bool _inited; @@ -25,6 +26,7 @@ namespace Bit.App.Pages _platformUtilsService = ServiceContainer.Resolve("platformUtilsService"); _storageService = ServiceContainer.Resolve("storageService"); _syncService = ServiceContainer.Resolve("syncService"); + _localizeService = ServiceContainer.Resolve("localizeService"); PageTitle = AppResources.Sync; } @@ -68,7 +70,9 @@ namespace Bit.App.Pages if (last != null) { var localDate = last.Value.ToLocalTime(); - LastSync = string.Format("{0} {1}", localDate.ToShortDateString(), localDate.ToShortTimeString()); + LastSync = string.Format("{0} {1}", + _localizeService.GetLocaleShortDate(localDate), + _localizeService.GetLocaleShortTime(localDate)); } else { diff --git a/src/App/Pages/Vault/CiphersPage.xaml b/src/App/Pages/Vault/CiphersPage.xaml index 2857385b1..bbffc874e 100644 --- a/src/App/Pages/Vault/CiphersPage.xaml +++ b/src/App/Pages/Vault/CiphersPage.xaml @@ -17,7 +17,6 @@ - _fields; private bool _canAccessPremium; @@ -52,6 +53,7 @@ namespace Bit.App.Pages _messagingService = ServiceContainer.Resolve("messagingService"); _eventService = ServiceContainer.Resolve("eventService"); _passwordRepromptService = ServiceContainer.Resolve("passwordRepromptService"); + _localizeService = ServiceContainer.Resolve("localizeService"); CopyCommand = new Command((id) => CopyAsync(id, null)); CopyUriCommand = new Command(CopyUri); CopyFieldCommand = new Command(CopyField); @@ -152,8 +154,8 @@ namespace Bit.App.Pages fs.Spans.Add(new Span { Text = string.Format(" {0} {1}", - Cipher.RevisionDate.ToLocalTime().ToShortDateString(), - Cipher.RevisionDate.ToLocalTime().ToShortTimeString()) + _localizeService.GetLocaleShortDate(Cipher.RevisionDate.ToLocalTime()), + _localizeService.GetLocaleShortTime(Cipher.RevisionDate.ToLocalTime())) }); return fs; } @@ -171,8 +173,8 @@ namespace Bit.App.Pages fs.Spans.Add(new Span { Text = string.Format(" {0} {1}", - Cipher.PasswordRevisionDisplayDate?.ToLocalTime().ToShortDateString(), - Cipher.PasswordRevisionDisplayDate?.ToLocalTime().ToShortTimeString()) + _localizeService.GetLocaleShortDate(Cipher.PasswordRevisionDisplayDate?.ToLocalTime()), + _localizeService.GetLocaleShortTime(Cipher.PasswordRevisionDisplayDate?.ToLocalTime())) }); return fs; } diff --git a/src/App/Utilities/DateTimeConverter.cs b/src/App/Utilities/DateTimeConverter.cs index a73caf4a9..cd8f2cec4 100644 --- a/src/App/Utilities/DateTimeConverter.cs +++ b/src/App/Utilities/DateTimeConverter.cs @@ -1,10 +1,19 @@ using System; +using Bit.App.Abstractions; +using Bit.Core.Utilities; using Xamarin.Forms; namespace Bit.App.Utilities { public class DateTimeConverter : IValueConverter { + private readonly ILocalizeService _localizeService; + + public DateTimeConverter() + { + _localizeService = ServiceContainer.Resolve("localizeService"); + } + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { @@ -17,7 +26,9 @@ namespace Bit.App.Utilities return string.Empty; } var d = ((DateTime)value).ToLocalTime(); - return string.Format("{0} {1}", d.ToShortDateString(), d.ToShortTimeString()); + return string.Format("{0} {1}", + _localizeService.GetLocaleShortDate(d), + _localizeService.GetLocaleShortTime(d)); } public object ConvertBack(object value, Type targetType, object parameter, diff --git a/src/iOS.Core/Services/LocalizeService.cs b/src/iOS.Core/Services/LocalizeService.cs index 21f4a2250..bdafe92d7 100644 --- a/src/iOS.Core/Services/LocalizeService.cs +++ b/src/iOS.Core/Services/LocalizeService.cs @@ -100,5 +100,25 @@ namespace Bit.iOS.Core.Services Console.WriteLine(".NET Fallback Language/Locale:" + netLanguage + " (application-specific)"); return netLanguage; } + + public string GetLocaleShortDate(DateTime? date) + { + using (var df = new NSDateFormatter()) + { + df.Locale = NSLocale.CurrentLocale; + df.DateStyle = NSDateFormatterStyle.Short; + return df.StringFor((NSDate)date); + } + } + + public string GetLocaleShortTime(DateTime? time) + { + using (var df = new NSDateFormatter()) + { + df.Locale = NSLocale.CurrentLocale; + df.TimeStyle = NSDateFormatterStyle.Short; + return df.StringFor((NSDate)time); + } + } } } \ No newline at end of file