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
This commit is contained in:
Jake Fink 2021-10-28 12:52:41 -04:00 committed by GitHub
parent 397250368a
commit 83fd6736f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 72 additions and 11 deletions

View File

@ -98,5 +98,15 @@ namespace Bit.Droid.Services
Console.WriteLine(".NET Fallback Language/Locale:" + netLanguage + " (application-specific)"); Console.WriteLine(".NET Fallback Language/Locale:" + netLanguage + " (application-specific)");
return netLanguage; return netLanguage;
} }
public string GetLocaleShortDate(DateTime? date)
{
return date?.ToShortDateString() ?? string.Empty;
}
public string GetLocaleShortTime(DateTime? time)
{
return time?.ToShortTimeString() ?? string.Empty;
}
} }
} }

View File

@ -1,9 +1,22 @@
using System.Globalization; using System;
using System.Globalization;
namespace Bit.App.Abstractions namespace Bit.App.Abstractions
{ {
public interface ILocalizeService public interface ILocalizeService
{ {
CultureInfo GetCurrentCultureInfo(); CultureInfo GetCurrentCultureInfo();
/// <summary>
/// Format date using device locale.
/// Needed for iOS as it provides locales unsupported in .Net
/// </summary>
string GetLocaleShortDate(DateTime? date);
/// <summary>
/// Format time using device locale.
/// Needed for iOS as it provides locales unsupported in .Net
/// </summary>
string GetLocaleShortTime(DateTime? time);
} }
} }

View File

@ -17,7 +17,6 @@
<ContentPage.Resources> <ContentPage.Resources>
<ResourceDictionary> <ResourceDictionary>
<u:DateTimeConverter x:Key="dateTime" />
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" <ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Name="_closeItem" x:Key="closeItem" /> x:Name="_closeItem" x:Key="closeItem" />
<StackLayout <StackLayout

View File

@ -26,6 +26,7 @@ namespace Bit.App.Pages
private readonly ISyncService _syncService; private readonly ISyncService _syncService;
private readonly IBiometricService _biometricService; private readonly IBiometricService _biometricService;
private readonly IPolicyService _policyService; private readonly IPolicyService _policyService;
private readonly ILocalizeService _localizeService;
private const int CustomVaultTimeoutValue = -100; private const int CustomVaultTimeoutValue = -100;
@ -72,6 +73,7 @@ namespace Bit.App.Pages
_syncService = ServiceContainer.Resolve<ISyncService>("syncService"); _syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService"); _biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService"); _policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
GroupedItems = new ExtendedObservableCollection<SettingsPageListGroup>(); GroupedItems = new ExtendedObservableCollection<SettingsPageListGroup>();
PageTitle = AppResources.Settings; PageTitle = AppResources.Settings;
@ -86,8 +88,9 @@ namespace Bit.App.Pages
if (lastSync != null) if (lastSync != null)
{ {
lastSync = lastSync.Value.ToLocalTime(); lastSync = lastSync.Value.ToLocalTime();
_lastSyncDate = string.Format("{0} {1}", lastSync.Value.ToShortDateString(), _lastSyncDate = string.Format("{0} {1}",
lastSync.Value.ToShortTimeString()); _localizeService.GetLocaleShortDate(lastSync.Value),
_localizeService.GetLocaleShortTime(lastSync.Value));
} }
if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout)) if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout))

View File

@ -14,6 +14,7 @@ namespace Bit.App.Pages
private readonly IPlatformUtilsService _platformUtilsService; private readonly IPlatformUtilsService _platformUtilsService;
private readonly IStorageService _storageService; private readonly IStorageService _storageService;
private readonly ISyncService _syncService; private readonly ISyncService _syncService;
private readonly ILocalizeService _localizeService;
private string _lastSync = "--"; private string _lastSync = "--";
private bool _inited; private bool _inited;
@ -25,6 +26,7 @@ namespace Bit.App.Pages
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService"); _platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService"); _storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService"); _syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
PageTitle = AppResources.Sync; PageTitle = AppResources.Sync;
} }
@ -68,7 +70,9 @@ namespace Bit.App.Pages
if (last != null) if (last != null)
{ {
var localDate = last.Value.ToLocalTime(); 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 else
{ {

View File

@ -17,7 +17,6 @@
<ContentPage.Resources> <ContentPage.Resources>
<ResourceDictionary> <ResourceDictionary>
<u:DateTimeConverter x:Key="dateTime" />
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" <ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Name="_closeItem" x:Key="closeItem" /> x:Name="_closeItem" x:Key="closeItem" />
<StackLayout <StackLayout

View File

@ -25,6 +25,7 @@ namespace Bit.App.Pages
private readonly IMessagingService _messagingService; private readonly IMessagingService _messagingService;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly IPasswordRepromptService _passwordRepromptService; private readonly IPasswordRepromptService _passwordRepromptService;
private readonly ILocalizeService _localizeService;
private CipherView _cipher; private CipherView _cipher;
private List<ViewPageFieldViewModel> _fields; private List<ViewPageFieldViewModel> _fields;
private bool _canAccessPremium; private bool _canAccessPremium;
@ -52,6 +53,7 @@ namespace Bit.App.Pages
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService"); _messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_eventService = ServiceContainer.Resolve<IEventService>("eventService"); _eventService = ServiceContainer.Resolve<IEventService>("eventService");
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService"); _passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
CopyCommand = new Command<string>((id) => CopyAsync(id, null)); CopyCommand = new Command<string>((id) => CopyAsync(id, null));
CopyUriCommand = new Command<LoginUriView>(CopyUri); CopyUriCommand = new Command<LoginUriView>(CopyUri);
CopyFieldCommand = new Command<FieldView>(CopyField); CopyFieldCommand = new Command<FieldView>(CopyField);
@ -152,8 +154,8 @@ namespace Bit.App.Pages
fs.Spans.Add(new Span fs.Spans.Add(new Span
{ {
Text = string.Format(" {0} {1}", Text = string.Format(" {0} {1}",
Cipher.RevisionDate.ToLocalTime().ToShortDateString(), _localizeService.GetLocaleShortDate(Cipher.RevisionDate.ToLocalTime()),
Cipher.RevisionDate.ToLocalTime().ToShortTimeString()) _localizeService.GetLocaleShortTime(Cipher.RevisionDate.ToLocalTime()))
}); });
return fs; return fs;
} }
@ -171,8 +173,8 @@ namespace Bit.App.Pages
fs.Spans.Add(new Span fs.Spans.Add(new Span
{ {
Text = string.Format(" {0} {1}", Text = string.Format(" {0} {1}",
Cipher.PasswordRevisionDisplayDate?.ToLocalTime().ToShortDateString(), _localizeService.GetLocaleShortDate(Cipher.PasswordRevisionDisplayDate?.ToLocalTime()),
Cipher.PasswordRevisionDisplayDate?.ToLocalTime().ToShortTimeString()) _localizeService.GetLocaleShortTime(Cipher.PasswordRevisionDisplayDate?.ToLocalTime()))
}); });
return fs; return fs;
} }

View File

@ -1,10 +1,19 @@
using System; using System;
using Bit.App.Abstractions;
using Bit.Core.Utilities;
using Xamarin.Forms; using Xamarin.Forms;
namespace Bit.App.Utilities namespace Bit.App.Utilities
{ {
public class DateTimeConverter : IValueConverter public class DateTimeConverter : IValueConverter
{ {
private readonly ILocalizeService _localizeService;
public DateTimeConverter()
{
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
}
public object Convert(object value, Type targetType, object parameter, public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture) System.Globalization.CultureInfo culture)
{ {
@ -17,7 +26,9 @@ namespace Bit.App.Utilities
return string.Empty; return string.Empty;
} }
var d = ((DateTime)value).ToLocalTime(); 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, public object ConvertBack(object value, Type targetType, object parameter,

View File

@ -100,5 +100,25 @@ namespace Bit.iOS.Core.Services
Console.WriteLine(".NET Fallback Language/Locale:" + netLanguage + " (application-specific)"); Console.WriteLine(".NET Fallback Language/Locale:" + netLanguage + " (application-specific)");
return netLanguage; 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);
}
}
} }
} }