mirror of
https://github.com/bitwarden/mobile
synced 2025-12-10 05:13:31 +00:00
account list status enhancements
This commit is contained in:
@@ -283,13 +283,14 @@ namespace Bit.App
|
|||||||
{
|
{
|
||||||
await SetMainPageAsync();
|
await SetMainPageAsync();
|
||||||
}
|
}
|
||||||
|
await Task.Delay(50);
|
||||||
UpdateTheme();
|
UpdateTheme();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetMainPageAsync()
|
private async Task SetMainPageAsync()
|
||||||
{
|
{
|
||||||
await _stateService.RefreshAccountViews();
|
await _stateService.RefreshAccountViewsAsync();
|
||||||
var authed = await _stateService.IsAuthenticatedAsync();
|
var authed = await _stateService.IsAuthenticatedAsync();
|
||||||
if (authed)
|
if (authed)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
Padding="0">
|
Padding="0">
|
||||||
|
|
||||||
<StackLayout
|
<StackLayout
|
||||||
x:Name="_accountListView"
|
x:Name="_accountListContainer"
|
||||||
VerticalOptions="StartAndExpand"
|
VerticalOptions="StartAndExpand"
|
||||||
HorizontalOptions="FillAndExpand"
|
HorizontalOptions="FillAndExpand"
|
||||||
BackgroundColor="{DynamicResource BackgroundColor}"
|
BackgroundColor="{DynamicResource BackgroundColor}"
|
||||||
@@ -87,6 +87,7 @@
|
|||||||
xct:ShadowEffect.Radius="10"
|
xct:ShadowEffect.Radius="10"
|
||||||
xct:ShadowEffect.OffsetY="3">
|
xct:ShadowEffect.OffsetY="3">
|
||||||
<ListView
|
<ListView
|
||||||
|
x:Name="_accountListView"
|
||||||
ItemsSource="{Binding AccountViews}"
|
ItemsSource="{Binding AccountViews}"
|
||||||
ItemSelected="AccountRow_Selected"
|
ItemSelected="AccountRow_Selected"
|
||||||
BackgroundColor="Transparent"
|
BackgroundColor="Transparent"
|
||||||
|
|||||||
@@ -142,17 +142,18 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
if (_accountListOverlay.IsVisible)
|
if (_accountListOverlay.IsVisible)
|
||||||
{
|
{
|
||||||
await ShowAccountListAsync(false, _accountListView, _accountListOverlay);
|
await ShowAccountListAsync(false, _accountListContainer, _accountListOverlay);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await ShowAccountListAsync(true, _accountListView, _accountListOverlay);
|
await RefreshAccountViewsAsync(_accountListView);
|
||||||
|
await ShowAccountListAsync(true, _accountListContainer, _accountListOverlay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void AccountRow_Selected(object sender, SelectedItemChangedEventArgs e)
|
private async void AccountRow_Selected(object sender, SelectedItemChangedEventArgs e)
|
||||||
{
|
{
|
||||||
await AccountRowSelectedAsync(sender, e, _accountListView, _accountListOverlay, null, true);
|
await AccountRowSelectedAsync(sender, e, _accountListContainer, _accountListOverlay, null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,7 @@
|
|||||||
Padding="0">
|
Padding="0">
|
||||||
|
|
||||||
<StackLayout
|
<StackLayout
|
||||||
x:Name="_accountListView"
|
x:Name="_accountListContainer"
|
||||||
VerticalOptions="StartAndExpand"
|
VerticalOptions="StartAndExpand"
|
||||||
HorizontalOptions="FillAndExpand"
|
HorizontalOptions="FillAndExpand"
|
||||||
BackgroundColor="{DynamicResource BackgroundColor}"
|
BackgroundColor="{DynamicResource BackgroundColor}"
|
||||||
@@ -181,6 +181,7 @@
|
|||||||
xct:ShadowEffect.Radius="10"
|
xct:ShadowEffect.Radius="10"
|
||||||
xct:ShadowEffect.OffsetY="3">
|
xct:ShadowEffect.OffsetY="3">
|
||||||
<ListView
|
<ListView
|
||||||
|
x:Name="_accountListView"
|
||||||
ItemsSource="{Binding AccountViews}"
|
ItemsSource="{Binding AccountViews}"
|
||||||
ItemSelected="AccountRow_Selected"
|
ItemSelected="AccountRow_Selected"
|
||||||
BackgroundColor="Transparent"
|
BackgroundColor="Transparent"
|
||||||
|
|||||||
@@ -159,17 +159,18 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
if (_accountListOverlay.IsVisible)
|
if (_accountListOverlay.IsVisible)
|
||||||
{
|
{
|
||||||
await ShowAccountListAsync(false, _accountListView, _accountListOverlay);
|
await ShowAccountListAsync(false, _accountListContainer, _accountListOverlay);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await ShowAccountListAsync(true, _accountListView, _accountListOverlay);
|
await RefreshAccountViewsAsync(_accountListView);
|
||||||
|
await ShowAccountListAsync(true, _accountListContainer, _accountListOverlay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void AccountRow_Selected(object sender, SelectedItemChangedEventArgs e)
|
private async void AccountRow_Selected(object sender, SelectedItemChangedEventArgs e)
|
||||||
{
|
{
|
||||||
await AccountRowSelectedAsync(sender, e, _accountListView, _accountListOverlay, null, true);
|
await AccountRowSelectedAsync(sender, e, _accountListContainer, _accountListOverlay, null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@
|
|||||||
Padding="0">
|
Padding="0">
|
||||||
|
|
||||||
<StackLayout
|
<StackLayout
|
||||||
x:Name="_accountListView"
|
x:Name="_accountListContainer"
|
||||||
VerticalOptions="StartAndExpand"
|
VerticalOptions="StartAndExpand"
|
||||||
HorizontalOptions="FillAndExpand"
|
HorizontalOptions="FillAndExpand"
|
||||||
BackgroundColor="{DynamicResource BackgroundColor}"
|
BackgroundColor="{DynamicResource BackgroundColor}"
|
||||||
@@ -130,6 +130,7 @@
|
|||||||
xct:ShadowEffect.Radius="10"
|
xct:ShadowEffect.Radius="10"
|
||||||
xct:ShadowEffect.OffsetY="3">
|
xct:ShadowEffect.OffsetY="3">
|
||||||
<ListView
|
<ListView
|
||||||
|
x:Name="_accountListView"
|
||||||
ItemsSource="{Binding AccountViews}"
|
ItemsSource="{Binding AccountViews}"
|
||||||
ItemSelected="AccountRow_Selected"
|
ItemSelected="AccountRow_Selected"
|
||||||
BackgroundColor="Transparent"
|
BackgroundColor="Transparent"
|
||||||
|
|||||||
@@ -141,17 +141,18 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
if (_accountListOverlay.IsVisible)
|
if (_accountListOverlay.IsVisible)
|
||||||
{
|
{
|
||||||
await ShowAccountListAsync(false, _accountListView, _accountListOverlay);
|
await ShowAccountListAsync(false, _accountListContainer, _accountListOverlay);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await ShowAccountListAsync(true, _accountListView, _accountListOverlay);
|
await RefreshAccountViewsAsync(_accountListView);
|
||||||
|
await ShowAccountListAsync(true, _accountListContainer, _accountListOverlay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void AccountRow_Selected(object sender, SelectedItemChangedEventArgs e)
|
private async void AccountRow_Selected(object sender, SelectedItemChangedEventArgs e)
|
||||||
{
|
{
|
||||||
await AccountRowSelectedAsync(sender, e, _accountListView, _accountListOverlay, null, true);
|
await AccountRowSelectedAsync(sender, e, _accountListContainer, _accountListOverlay, null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Bit.Core.Enums;
|
|||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Xamarin.Forms.PlatformConfiguration;
|
using Xamarin.Forms.PlatformConfiguration;
|
||||||
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
||||||
using Page = Xamarin.Forms.Page;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -39,12 +38,6 @@ namespace Bit.App.Pages
|
|||||||
await SaveActivity();
|
await SaveActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ShowAccountSwitcherAsync()
|
|
||||||
{
|
|
||||||
return await _stateService.HasMultipleAccountsAsync()
|
|
||||||
|| await _stateService.IsAuthenticatedAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoOnce(Action action = null, int milliseconds = 1000)
|
public bool DoOnce(Action action = null, int milliseconds = 1000)
|
||||||
{
|
{
|
||||||
if (LastPageAction.HasValue && (DateTime.UtcNow - LastPageAction.Value).TotalMilliseconds < milliseconds)
|
if (LastPageAction.HasValue && (DateTime.UtcNow - LastPageAction.Value).TotalMilliseconds < milliseconds)
|
||||||
@@ -115,23 +108,33 @@ namespace Bit.App.Pages
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task<bool> ShowAccountSwitcherAsync()
|
||||||
|
{
|
||||||
|
return await _stateService.HasMultipleAccountsAsync()
|
||||||
|
|| await _stateService.IsAuthenticatedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task RefreshAccountViewsAsync(Xamarin.Forms.ListView accountListView)
|
||||||
|
{
|
||||||
|
await _stateService.RefreshAccountViewsAsync();
|
||||||
|
// Property change trigger on account listview is yielding inconsistent results, using a hammer instead
|
||||||
|
accountListView.ItemsSource = null;
|
||||||
|
accountListView.ItemsSource = _stateService.AccountViews;
|
||||||
|
}
|
||||||
protected async Task<AvatarImageSource> GetAvatarImageSourceAsync(bool useCurrentActiveAccount = true)
|
protected async Task<AvatarImageSource> GetAvatarImageSourceAsync(bool useCurrentActiveAccount = true)
|
||||||
{
|
{
|
||||||
return new AvatarImageSource(useCurrentActiveAccount ? await _stateService.GetEmailAsync() : null);
|
return new AvatarImageSource(useCurrentActiveAccount ? await _stateService.GetEmailAsync() : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task ShowAccountListAsync(bool isVisible, View listView, View overlay, View fab = null)
|
protected async Task ShowAccountListAsync(bool isVisible, View listContainer, View overlay, View fab = null)
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(async () =>
|
Device.BeginInvokeOnMainThread(async () =>
|
||||||
{
|
{
|
||||||
// Not all animations are awaited. This is intentional to allow multiple simultaneous animations.
|
// Not all animations are awaited. This is intentional to allow multiple simultaneous animations.
|
||||||
if (isVisible)
|
if (isVisible)
|
||||||
{
|
{
|
||||||
// Update account views to reflect current state
|
|
||||||
await _stateService.RefreshAccountViews();
|
|
||||||
|
|
||||||
// start listView in default (off-screen) position
|
// start listView in default (off-screen) position
|
||||||
await listView.TranslateTo(0, listView.Height * -1, 0);
|
await listContainer.TranslateTo(0, listContainer.Height * -1, 0);
|
||||||
|
|
||||||
// set overlay opacity to zero before making visible and start fade-in
|
// set overlay opacity to zero before making visible and start fade-in
|
||||||
overlay.Opacity = 0;
|
overlay.Opacity = 0;
|
||||||
@@ -145,7 +148,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
// slide account list into view
|
// slide account list into view
|
||||||
await listView.TranslateTo(0, 0, 200, Easing.SinOut);
|
await listContainer.TranslateTo(0, 0, 200, Easing.SinOut);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -159,7 +162,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
// slide account list out of view
|
// slide account list out of view
|
||||||
await listView.TranslateTo(0, listView.Height * -1, 200, Easing.SinIn);
|
await listContainer.TranslateTo(0, listContainer.Height * -1, 200, Easing.SinIn);
|
||||||
|
|
||||||
// remove overlay
|
// remove overlay
|
||||||
overlay.IsVisible = false;
|
overlay.IsVisible = false;
|
||||||
@@ -167,7 +170,7 @@ namespace Bit.App.Pages
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task AccountRowSelectedAsync(object sender, SelectedItemChangedEventArgs e, View listView,
|
protected async Task AccountRowSelectedAsync(object sender, SelectedItemChangedEventArgs e, View listContainer,
|
||||||
View overlay, View fab = null, bool? allowActiveAccountSelection = false)
|
View overlay, View fab = null, bool? allowActiveAccountSelection = false)
|
||||||
{
|
{
|
||||||
if (!DoOnce())
|
if (!DoOnce())
|
||||||
@@ -181,7 +184,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
((Xamarin.Forms.ListView)sender).SelectedItem = null;
|
((Xamarin.Forms.ListView)sender).SelectedItem = null;
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
await ShowAccountListAsync(false, listView, overlay, fab);
|
await ShowAccountListAsync(false, listContainer, overlay, fab);
|
||||||
|
|
||||||
if (item.AccountView.IsAccount)
|
if (item.AccountView.IsAccount)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -172,7 +172,7 @@
|
|||||||
Padding="0">
|
Padding="0">
|
||||||
|
|
||||||
<StackLayout
|
<StackLayout
|
||||||
x:Name="_accountListView"
|
x:Name="_accountListContainer"
|
||||||
VerticalOptions="StartAndExpand"
|
VerticalOptions="StartAndExpand"
|
||||||
HorizontalOptions="FillAndExpand"
|
HorizontalOptions="FillAndExpand"
|
||||||
BackgroundColor="{DynamicResource BackgroundColor}"
|
BackgroundColor="{DynamicResource BackgroundColor}"
|
||||||
@@ -180,6 +180,7 @@
|
|||||||
xct:ShadowEffect.Radius="10"
|
xct:ShadowEffect.Radius="10"
|
||||||
xct:ShadowEffect.OffsetY="3">
|
xct:ShadowEffect.OffsetY="3">
|
||||||
<ListView
|
<ListView
|
||||||
|
x:Name="_accountListView"
|
||||||
ItemsSource="{Binding AccountViews}"
|
ItemsSource="{Binding AccountViews}"
|
||||||
ItemSelected="AccountRow_Selected"
|
ItemSelected="AccountRow_Selected"
|
||||||
BackgroundColor="Transparent"
|
BackgroundColor="Transparent"
|
||||||
|
|||||||
@@ -298,17 +298,18 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
if (_accountListOverlay.IsVisible)
|
if (_accountListOverlay.IsVisible)
|
||||||
{
|
{
|
||||||
await ShowAccountListAsync(false, _accountListView, _accountListOverlay, _fab);
|
await ShowAccountListAsync(false, _accountListContainer, _accountListOverlay, _fab);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await ShowAccountListAsync(true, _accountListView, _accountListOverlay, _fab);
|
await RefreshAccountViewsAsync(_accountListView);
|
||||||
|
await ShowAccountListAsync(true, _accountListContainer, _accountListOverlay, _fab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void AccountRow_Selected(object sender, SelectedItemChangedEventArgs e)
|
private async void AccountRow_Selected(object sender, SelectedItemChangedEventArgs e)
|
||||||
{
|
{
|
||||||
await AccountRowSelectedAsync(sender, e, _accountListView, _accountListOverlay, _fab);
|
await AccountRowSelectedAsync(sender, e, _accountListContainer, _accountListOverlay, _fab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace Bit.Core.Abstractions
|
|||||||
Task SetActiveUserAsync(string userId);
|
Task SetActiveUserAsync(string userId);
|
||||||
Task<bool> IsAuthenticatedAsync(string userId = null);
|
Task<bool> IsAuthenticatedAsync(string userId = null);
|
||||||
Task<bool> HasMultipleAccountsAsync();
|
Task<bool> HasMultipleAccountsAsync();
|
||||||
Task RefreshAccountViews();
|
Task RefreshAccountViewsAsync();
|
||||||
Task AddAccountAsync(Account account);
|
Task AddAccountAsync(Account account);
|
||||||
Task ClearAsync(string userId);
|
Task ClearAsync(string userId);
|
||||||
Task<EnvironmentUrlData> GetPreAuthEnvironmentUrlsAsync();
|
Task<EnvironmentUrlData> GetPreAuthEnvironmentUrlsAsync();
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ namespace Bit.Core.Services
|
|||||||
return _state.Accounts?.Count > 1;
|
return _state.Accounts?.Count > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RefreshAccountViews()
|
public async Task RefreshAccountViewsAsync()
|
||||||
{
|
{
|
||||||
await CheckStateAsync();
|
await CheckStateAsync();
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
await ScaffoldNewAccountAsync(account);
|
await ScaffoldNewAccountAsync(account);
|
||||||
await SetActiveUserAsync(account.Profile.UserId);
|
await SetActiveUserAsync(account.Profile.UserId);
|
||||||
await RefreshAccountViews();
|
await RefreshAccountViewsAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ClearAsync(string userId)
|
public async Task ClearAsync(string userId)
|
||||||
|
|||||||
Reference in New Issue
Block a user