1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-16 00:03:22 +00:00

got the countdown working

This commit is contained in:
Jacob Fink
2022-03-04 16:44:22 -05:00
parent 3ac2580742
commit 0b626cedc7
7 changed files with 442 additions and 60 deletions

View File

@@ -3,35 +3,92 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.AuthenticatorViewCell" x:Class="Bit.App.Controls.AuthenticatorViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls" xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities" xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:ff="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms" xmlns:ff="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore" xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
StyleClass="list-row, list-row-platform" StyleClass="list-row, list-row-platform"
RowSpacing="0" RowSpacing="0"
ColumnSpacing="0" ColumnSpacing="0"
x:DataType="controls:AuthenticatorViewCellViewModel"> x:DataType="pages:AuthenticatorPageListItem">
<Grid.Resources>
<u:IconGlyphConverter x:Key="iconGlyphConverter"/>
<u:IconImageConverter x:Key="iconImageConverter"/>
<u:InverseBoolConverter x:Key="inverseBool" />
<u:StringHasValueConverter x:Key="stringHasValueConverter" />
</Grid.Resources>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="60" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label <controls:IconLabel
Text="Figma" Grid.Column="0"
StyleClass="box-label" HorizontalOptions="Center"
Grid.Row="0" VerticalOptions="Center"
Grid.Column="0" /> StyleClass="list-icon, list-icon-platform"
<controls:MonoLabel IsVisible="{Binding ShowIconImage, Converter={StaticResource inverseBool}}"
Text="{Binding TotpCodeFormatted, Mode=OneWay}" Text="{Binding Cipher, Converter={StaticResource iconGlyphConverter}}"
StyleClass="box-value" AutomationProperties.IsInAccessibleTree="False" />
Grid.Row="1"
Grid.Column="0" /> <ff:CachedImage
Grid.Column="0"
BitmapOptimizations="True"
ErrorPlaceholder="login.png"
LoadingPlaceholder="login.png"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="22"
HeightRequest="22"
IsVisible="{Binding ShowIconImage}"
Source="{Binding IconImageSource, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="False" />
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center" Padding="0, 7">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<controls:MonoLabel
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="0"
Grid.ColumnSpan="3"
StyleClass="list-title, list-title-platform"
Text="{Binding TotpCodeFormatted, Mode=OneWay}" />
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Cipher.Name}" />
<controls:IconLabel
Grid.Column="1"
Grid.Row="1"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="{Binding Source={x:Static core:BitwardenIcons.Collection}}"
IsVisible="{Binding Cipher.Shared, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Shared}" />
</Grid>
<Label <Label
Text="{Binding TotpSec, Mode=OneWay}" Text="{Binding TotpSec, Mode=OneWay}"
Style="{DynamicResource textTotp}" Style="{DynamicResource textTotp}"
@@ -50,6 +107,7 @@
Grid.Row="0" Grid.Row="0"
Grid.Column="2" Grid.Column="2"
Grid.RowSpan="2" Grid.RowSpan="2"
Padding="0,0,1,0"
AutomationProperties.IsInAccessibleTree="True" AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n CopyTotp}" /> AutomationProperties.Name="{u:I18n CopyTotp}" />
</controls:ExtendedGrid> </controls:ExtendedGrid>

View File

@@ -1,5 +1,7 @@
using System; using System;
using Bit.App.Utilities;
using Bit.Core.Models.View; using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.Forms; using Xamarin.Forms;
namespace Bit.App.Controls namespace Bit.App.Controls
@@ -7,64 +9,112 @@ namespace Bit.App.Controls
public partial class AuthenticatorViewCell : ExtendedGrid public partial class AuthenticatorViewCell : ExtendedGrid
{ {
public static readonly BindableProperty CipherProperty = BindableProperty.Create( public static readonly BindableProperty CipherProperty = BindableProperty.Create(
nameof(Cipher), typeof(CipherView), typeof(AuthenticatorViewCell), default(CipherView), BindingMode.OneWay); nameof(Cipher), typeof(CipherView), typeof(AuthenticatorViewCell), default(CipherView), BindingMode.TwoWay);
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create( public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(AuthenticatorViewCell)); nameof(WebsiteIconsEnabled), typeof(bool?), typeof(AuthenticatorViewCell));
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create( public static readonly BindableProperty TotpSecProperty = BindableProperty.Create(
nameof(ButtonCommand), typeof(Command<CipherView>), typeof(AuthenticatorViewCell)); nameof(TotpSec), typeof(long), typeof(AuthenticatorViewCell));
//public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
// nameof(ButtonCommand), typeof(Command<CipherView>), typeof(AuthenticatorViewCell));
public AuthenticatorViewCell() public AuthenticatorViewCell()
{ {
InitializeComponent(); InitializeComponent();
} }
public Command CopyCommand { get; set; }
public CipherView Cipher
{
get => GetValue(CipherProperty) as CipherView;
set => SetValue(CipherProperty, value);
}
public bool? WebsiteIconsEnabled public bool? WebsiteIconsEnabled
{ {
get => (bool)GetValue(WebsiteIconsEnabledProperty); get => (bool)GetValue(WebsiteIconsEnabledProperty);
set => SetValue(WebsiteIconsEnabledProperty, value); set => SetValue(WebsiteIconsEnabledProperty, value);
} }
public CipherView Cipher public long TotpSec
{ {
get => GetValue(CipherProperty) as CipherView; get => (long)GetValue(TotpSecProperty);
set => SetValue(CipherProperty, value); set => SetValue(TotpSecProperty, value);
} }
public Command<CipherView> ButtonCommand public bool ShowIconImage
{ {
get => GetValue(ButtonCommandProperty) as Command<CipherView>; get => WebsiteIconsEnabled ?? false
set => SetValue(ButtonCommandProperty, value); && !string.IsNullOrWhiteSpace(Cipher.Login?.Uri)
&& IconImageSource != null;
} }
protected override void OnPropertyChanged(string propertyName = null) private string _iconImageSource = string.Empty;
public string IconImageSource
{ {
base.OnPropertyChanged(propertyName); get
if (propertyName == CipherProperty.PropertyName)
{ {
if (Cipher == null) if (_iconImageSource == string.Empty) // default value since icon source can return null
{ {
return; _iconImageSource = IconImageHelper.GetLoginIconImage(Cipher);
} }
BindingContext = new AuthenticatorViewCellViewModel(Cipher, WebsiteIconsEnabled ?? false); return _iconImageSource;
}
else if (propertyName == WebsiteIconsEnabledProperty.PropertyName)
{
if (Cipher == null)
{
return;
}
((AuthenticatorViewCellViewModel)BindingContext).WebsiteIconsEnabled = WebsiteIconsEnabled ?? false;
} }
} }
private string _totpCodeFormatted = "938 928";
public string TotpCodeFormatted
{
get => _totpCodeFormatted;
set => _totpCodeFormatted = value;
}
//public Command<CipherView> ButtonCommand
//{
// get => GetValue(ButtonCommandProperty) as Command<CipherView>;
// set => SetValue(ButtonCommandProperty, value);
//}
//protected override void OnPropertyChanged(string propertyName = null)
//{
// base.OnPropertyChanged(propertyName);
// if (propertyName == CipherProperty.PropertyName)
// {
// if (Cipher == null)
// {
// return;
// }
// _cipherLabel.Text = Cipher.Name;
// }
// else if (propertyName == WebsiteIconsEnabledProperty.PropertyName)
// {
// if (Cipher == null)
// {
// return;
// }
// ((AuthenticatorViewCellViewModel)BindingContext).WebsiteIconsEnabled = WebsiteIconsEnabled ?? false;
// }
// else if (propertyName == TotpSecProperty.PropertyName)
// {
// if (Cipher == null)
// {
// return;
// }
// ((AuthenticatorViewCellViewModel)BindingContext).UpdateTotpSec(TotpSec);
// }
//}
private void MoreButton_Clicked(object sender, EventArgs e) private void MoreButton_Clicked(object sender, EventArgs e)
{ {
var cipher = ((sender as MiButton)?.BindingContext as AuthenticatorViewCellViewModel)?.Cipher; var cipher = ((sender as MiButton)?.BindingContext as AuthenticatorViewCellViewModel)?.Cipher;
if (cipher != null) if (cipher != null)
{ {
ButtonCommand?.Execute(cipher); //ButtonCommand?.Execute(cipher);
} }
} }
} }

View File

@@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Bit.App.Utilities; using Bit.App.Utilities;
using Bit.Core.Models.View; using Bit.Core.Models.View;
using Bit.Core.Utilities; using Bit.Core.Utilities;
@@ -8,7 +9,7 @@ namespace Bit.App.Controls
public class AuthenticatorViewCellViewModel : ExtendedViewModel public class AuthenticatorViewCellViewModel : ExtendedViewModel
{ {
private CipherView _cipher; private CipherView _cipher;
private string _totpCodeFormatted = "938928"; private string _totpCodeFormatted = "938 928";
private string _totpSec; private string _totpSec;
private bool _websiteIconsEnabled; private bool _websiteIconsEnabled;
private string _iconImageSource = string.Empty; private string _iconImageSource = string.Empty;
@@ -64,6 +65,39 @@ namespace Bit.App.Controls
} }
} }
public void UpdateTotpSec(long totpSec)
{
_totpSec = totpSec.ToString();
}
//private async Task TotpUpdateCodeAsync()
//{
// if (Cipher == null || Cipher.Type != Core.Enums.CipherType.Login || Cipher.Login.Totp == null)
// {
// _totpInterval = null;
// return;
// }
// _totpCode = await _totpService.GetCodeAsync(Cipher.Login.Totp);
// if (_totpCode != null)
// {
// if (_totpCode.Length > 4)
// {
// var half = (int)Math.Floor(_totpCode.Length / 2M);
// TotpCodeFormatted = string.Format("{0} {1}", _totpCode.Substring(0, half),
// _totpCode.Substring(half));
// }
// else
// {
// TotpCodeFormatted = _totpCode;
// }
// }
// else
// {
// TotpCodeFormatted = null;
// _totpInterval = null;
// }
//}
} }
} }

View File

@@ -8,7 +8,8 @@
xmlns:pages="clr-namespace:Bit.App.Pages" xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:controls="clr-namespace:Bit.App.Controls" xmlns:controls="clr-namespace:Bit.App.Controls"
x:DataType="pages:AuthenticatorPageViewModel" x:DataType="pages:AuthenticatorPageViewModel"
Title="{Binding PageTitle}"> Title="{Binding PageTitle}"
x:Name="_page">
<ContentPage.BindingContext> <ContentPage.BindingContext>
<pages:AuthenticatorPageViewModel /> <pages:AuthenticatorPageViewModel />
@@ -40,31 +41,31 @@
AutomationProperties.Name="{u:I18n AddItem}" /> AutomationProperties.Name="{u:I18n AddItem}" />
<DataTemplate x:Key="authenticatorTemplate" <DataTemplate x:Key="authenticatorTemplate"
x:DataType="pages:SendGroupingsPageListItem"> x:DataType="pages:AuthenticatorPageListItem">
<controls:AuthenticatorViewCell /> <controls:AuthenticatorViewCell
Cipher="{Binding Cipher}"
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
TotpSec="{Binding TotpSec}"/>
</DataTemplate> </DataTemplate>
<StackLayout x:Key="mainLayout" x:Name="_mainLayout"> <StackLayout x:Key="mainLayout" x:Name="_mainLayout">
<RefreshView <RefreshView>
IsVisible="{Binding ShowList}"
IsRefreshing="{Binding Refreshing}"
Command="{Binding RefreshCommand}">
<controls:ExtendedCollectionView <controls:ExtendedCollectionView
ItemsSource="{Binding Items}" ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource authenticatorTemplate}"
VerticalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
SelectionMode="Single" SelectionMode="Single"
SelectionChanged="RowSelected" SelectionChanged="RowSelected"
StyleClass="list, list-platform"> StyleClass="list, list-platform">
<controls:ExtendedCollectionView.ItemTemplate>
<DataTemplate x:DataType="pages:AuthenticatorPageListItem">
<controls:AuthenticatorViewCell />
</DataTemplate>
</controls:ExtendedCollectionView.ItemTemplate>
</controls:ExtendedCollectionView> </controls:ExtendedCollectionView>
</RefreshView> </RefreshView>
<StackLayout
IsVisible="{Binding ShowList}">
</StackLayout>
</StackLayout> </StackLayout>
</ResourceDictionary> </ResourceDictionary>
</ContentPage.Resources> </ContentPage.Resources>

View File

@@ -1,5 +1,6 @@
using Bit.App.Resources; using Bit.App.Resources;
using System; using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Utilities; using Bit.Core.Utilities;
@@ -14,6 +15,8 @@ namespace Bit.App.Pages
#region Members #region Members
private readonly IBroadcasterService _broadcasterService; private readonly IBroadcasterService _broadcasterService;
private readonly ISyncService _syncService;
private readonly ICipherService _cipherService;
private AuthenticatorPageViewModel _vm; private AuthenticatorPageViewModel _vm;
private readonly bool _fromTabPage; private readonly bool _fromTabPage;
private readonly Action<string> _selectAction; private readonly Action<string> _selectAction;
@@ -26,6 +29,8 @@ namespace Bit.App.Pages
//_tabsPage = tabsPage; //_tabsPage = tabsPage;
InitializeComponent(); InitializeComponent();
//_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService"); //_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
_vm = BindingContext as AuthenticatorPageViewModel; _vm = BindingContext as AuthenticatorPageViewModel;
//_vm.Page = this; //_vm.Page = this;
//_fromTabPage = fromTabPage; //_fromTabPage = fromTabPage;
@@ -47,7 +52,7 @@ namespace Bit.App.Pages
public async Task InitAsync() public async Task InitAsync()
{ {
await _vm.InitAsync(); await _vm.LoadAsync();
} }
protected async override void OnAppearing() protected async override void OnAppearing()
@@ -67,7 +72,36 @@ namespace Bit.App.Pages
// }); // });
// } // }
//}); //});
await LoadOnAppearedAsync(_mainLayout, false, async () =>
{
if (!_syncService.SyncInProgress || (await _cipherService.GetAllAsync()).Any())
{
try
{
await _vm.LoadAsync();
}
catch (Exception e) when (e.Message.Contains("No key."))
{
await Task.Delay(1000);
await _vm.LoadAsync();
}
}
else
{
await Task.Delay(5000);
if (!_vm.Loaded)
{
await _vm.LoadAsync();
}
}
AdjustToolbar();
//await CheckAddRequest();
}, _mainContent);
} }
private async void Search_Clicked(object sender, EventArgs e) private async void Search_Clicked(object sender, EventArgs e)
@@ -132,6 +166,11 @@ namespace Bit.App.Pages
base.OnDisappearing(); base.OnDisappearing();
//_broadcasterService.Unsubscribe(nameof(GeneratorPage)); //_broadcasterService.Unsubscribe(nameof(GeneratorPage));
} }
private void AdjustToolbar()
{
//_addItem.IsEnabled = !_vm.Deleted;
//_addItem.IconImageSource = _vm.Deleted ? null : "plus.png";
}
} }
} }

View File

@@ -0,0 +1,129 @@
using System;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class AuthenticatorPageListItem : ExtendedViewModel
{
//private string _totpCode;
private readonly ITotpService _totpService;
//public CipherView Cipher { get; set; }
//public CipherType? Type { get; set; }
//public int interval { get; set; }
//public long TotpSec { get; set; }
//private DateTime? _totpInterval = null;
private CipherView _cipher;
private bool _websiteIconsEnabled;
private string _iconImageSource = string.Empty;
public int interval { get; set; }
private string _totpSec;
private string _totpCode;
private string _totpCodeFormatted = "938 928";
public AuthenticatorPageListItem(CipherView cipherView, bool websiteIconsEnabled)
{
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
Cipher = cipherView;
WebsiteIconsEnabled = websiteIconsEnabled;
interval = _totpService.GetTimeInterval(Cipher.Login.Totp);
}
public Command CopyCommand { get; set; }
public CipherView Cipher
{
get => _cipher;
set => SetProperty(ref _cipher, value);
}
public string TotpCodeFormatted
{
get => _totpCodeFormatted;
set => SetProperty(ref _totpCodeFormatted, value);
}
public string TotpSec
{
get => _totpSec;
set => SetProperty(ref _totpSec, value);
}
public bool WebsiteIconsEnabled
{
get => _websiteIconsEnabled;
set => SetProperty(ref _websiteIconsEnabled, value);
}
public bool ShowIconImage
{
get => WebsiteIconsEnabled
&& !string.IsNullOrWhiteSpace(Cipher.Login?.Uri)
&& IconImageSource != null;
}
public string IconImageSource
{
get
{
if (_iconImageSource == string.Empty) // default value since icon source can return null
{
_iconImageSource = IconImageHelper.GetLoginIconImage(Cipher);
}
return _iconImageSource;
}
}
public async Task TotpTickAsync()
{
var epoc = CoreHelpers.EpocUtcNow() / 1000;
var mod = epoc % interval;
var totpSec = interval - mod;
TotpSec = totpSec.ToString();
//TotpLow = totpSec < 7;
if (mod == 0)
{
await TotpUpdateCodeAsync();
}
}
public async Task TotpUpdateCodeAsync()
{
_totpCode = await _totpService.GetCodeAsync(Cipher.Login.Totp);
if (_totpCode != null)
{
if (_totpCode.Length > 4)
{
var half = (int)Math.Floor(_totpCode.Length / 2M);
TotpCodeFormatted = string.Format("{0} {1}", _totpCode.Substring(0, half),
_totpCode.Substring(half));
}
else
{
TotpCodeFormatted = _totpCode;
}
}
else
{
TotpCodeFormatted = null;
}
}
}
}

View File

@@ -1,7 +1,9 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq;
using Bit.App.Resources; using Bit.App.Resources;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Xamarin.Forms; using Xamarin.Forms;
@@ -12,29 +14,35 @@ namespace Bit.App.Pages
#region Members #region Members
private readonly IClipboardService _clipboardService; private readonly IClipboardService _clipboardService;
private bool _showList = true; private readonly ITotpService _totpService;
private bool _refreshing;
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly IVaultTimeoutService _vaultTimeoutService; private readonly IVaultTimeoutService _vaultTimeoutService;
private readonly ICipherService _cipherService;
private bool _showList = true;
private bool _refreshing;
private bool _loaded;
private bool _websiteIconsEnabled = true;
//private long _totpSec;
#endregion #endregion
#region Ctor #region Ctor
public AuthenticatorPageViewModel() public AuthenticatorPageViewModel()
{ {
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
_userService = ServiceContainer.Resolve<IUserService>("userService"); _userService = ServiceContainer.Resolve<IUserService>("userService");
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService"); _vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
PageTitle = AppResources.Authenticator; PageTitle = AppResources.Authenticator;
Items = new ExtendedObservableCollection<AuthenticatorPageListItem>();
} }
#endregion #endregion
#region Methods #region Methods
public async Task InitAsync() { }
public async Task CopyAsync() public async Task CopyAsync()
{ {
//await _clipboardService.CopyTextAsync(Password); //await _clipboardService.CopyTextAsync(Password);
@@ -54,15 +62,61 @@ namespace Bit.App.Pages
return; return;
} }
this.ShowList = true; try
this.Refreshing = false; {
await LoadDataAsync();
}
finally
{
ShowList = true;
Refreshing = false;
}
}
private async Task LoadDataAsync()
{
var _allCiphers = await _cipherService.GetAllDecryptedAsync();
_allCiphers = _allCiphers.Where(c => c.Type == Core.Enums.CipherType.Login && c.Login.Totp != null).ToList();
var filteredCiphers = _allCiphers.Select(c => new AuthenticatorPageListItem(c, WebsiteIconsEnabled)).ToList();
Items.ResetWithRange(filteredCiphers);
foreach (AuthenticatorPageListItem item in Items)
{
item.TotpUpdateCodeAsync();
}
//await TotpUpdateCodeAsync();
// var interval = _totpService.GetTimeInterval(Cipher.Login.Totp);
// await TotpTickAsync(interval);
// _totpInterval = DateTime.UtcNow;
Device.StartTimer(new TimeSpan(0, 0, 1), () =>
{
foreach(AuthenticatorPageListItem item in Items)
{
item.TotpTickAsync();
}
return true;
});
//}
//private async Task TotpTickAsync(int intervalSeconds)
//{
// var epoc = CoreHelpers.EpocUtcNow() / 1000;
// var mod = epoc % intervalSeconds;
// var totpSec = intervalSeconds - mod;
// TotpSec = totpSec.ToString();
// TotpLow = totpSec < 7;
// if (mod == 0)
// {
// await TotpUpdateCodeAsync();
// }
} }
#endregion #endregion
#region Properties #region Properties
public ExtendedObservableCollection<GroupingsPageListGroup> Items { get; set; } public ExtendedObservableCollection<AuthenticatorPageListItem> Items { get; set; }
public Command RefreshCommand { get; set; } public Command RefreshCommand { get; set; }
public bool ShowList public bool ShowList
@@ -77,6 +131,23 @@ namespace Bit.App.Pages
set => SetProperty(ref _refreshing, value); set => SetProperty(ref _refreshing, value);
} }
public bool WebsiteIconsEnabled
{
get => _websiteIconsEnabled;
set => SetProperty(ref _websiteIconsEnabled, value);
}
public bool Loaded
{
get => _loaded;
set => SetProperty(ref _loaded, value);
}
//public long TotpSec
//{
// get => _totpSec;
// set => SetProperty(ref _totpSec, value);
//}
#endregion #endregion
} }
} }