From cfbbea59e9a687a7d5bcc1da1d70acf85e1a45cf Mon Sep 17 00:00:00 2001
From: mp-bw <59324545+mp-bw@users.noreply.github.com>
Date: Tue, 19 Apr 2022 20:38:17 -0400
Subject: [PATCH] account switching in autofill UI (Android) (#1882)
---
src/App/App.xaml.cs | 17 ++++++-
src/App/Pages/Vault/AutofillCiphersPage.xaml | 25 +++++++++-
.../Pages/Vault/AutofillCiphersPage.xaml.cs | 48 +++++++++++++++++--
.../Vault/AutofillCiphersPageViewModel.cs | 26 ++++++++--
4 files changed, 106 insertions(+), 10 deletions(-)
diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs
index f51974df2..8391cbf4b 100644
--- a/src/App/App.xaml.cs
+++ b/src/App/App.xaml.cs
@@ -208,7 +208,10 @@ namespace Bit.App
{
await _stateService.SetLastActiveTimeAsync(_deviceActionService.GetActiveTime());
}
- SetTabsPageFromAutofill(isLocked);
+ if (!SetTabsPageFromAutofill(isLocked))
+ {
+ ClearAutofillUri();
+ }
await SleptAsync();
}
}
@@ -365,7 +368,15 @@ namespace Bit.App
}
}
- private void SetTabsPageFromAutofill(bool isLocked)
+ private void ClearAutofillUri()
+ {
+ if (Device.RuntimePlatform == Device.Android && !string.IsNullOrWhiteSpace(Options.Uri))
+ {
+ Options.Uri = null;
+ }
+ }
+
+ private bool SetTabsPageFromAutofill(bool isLocked)
{
if (Device.RuntimePlatform == Device.Android && !string.IsNullOrWhiteSpace(Options.Uri) &&
!Options.FromAutofillFramework)
@@ -385,7 +396,9 @@ namespace Bit.App
}
});
});
+ return true;
}
+ return false;
}
private void Prime()
diff --git a/src/App/Pages/Vault/AutofillCiphersPage.xaml b/src/App/Pages/Vault/AutofillCiphersPage.xaml
index 5bb8b4004..4a99f7b0e 100644
--- a/src/App/Pages/Vault/AutofillCiphersPage.xaml
+++ b/src/App/Pages/Vault/AutofillCiphersPage.xaml
@@ -15,7 +15,18 @@
-
+
+
@@ -58,7 +69,7 @@
VerticalOptions="CenterAndExpand"
Padding="20, 0"
Spacing="20"
- IsVisible="{Binding ShowList, Converter={StaticResource inverseBool}}">
+ IsVisible="{Binding ShowNoData}">
@@ -88,6 +99,8 @@
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0, 0, 1, 1">
+
+
+
+
diff --git a/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs b/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs
index 69d04cda5..3c680aa05 100644
--- a/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs
+++ b/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs
@@ -1,5 +1,4 @@
using Bit.App.Models;
-using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
@@ -15,7 +14,8 @@ namespace Bit.App.Pages
public partial class AutofillCiphersPage : BaseContentPage
{
private readonly AppOptions _appOptions;
- private readonly IPlatformUtilsService _platformUtilsService;
+ private readonly IBroadcasterService _broadcasterService;
+ private readonly ISyncService _syncService;
private readonly IVaultTimeoutService _vaultTimeoutService;
private AutofillCiphersPageViewModel _vm;
@@ -24,17 +24,23 @@ namespace Bit.App.Pages
{
_appOptions = appOptions;
InitializeComponent();
+ SetActivityIndicator(_mainContent);
_vm = BindingContext as AutofillCiphersPageViewModel;
_vm.Page = this;
_vm.Init(appOptions);
- _platformUtilsService = ServiceContainer.Resolve("platformUtilsService");
+ _broadcasterService = ServiceContainer.Resolve("broadcasterService");
+ _syncService = ServiceContainer.Resolve("syncService");
_vaultTimeoutService = ServiceContainer.Resolve("vaultTimeoutService");
}
protected async override void OnAppearing()
{
base.OnAppearing();
+ if (_syncService.SyncInProgress)
+ {
+ IsBusy = true;
+ }
if (!await AppHelpers.IsVaultTimeoutImmediateAsync())
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
@@ -43,6 +49,30 @@ namespace Bit.App.Pages
{
return;
}
+
+ _accountAvatar?.OnAppearing();
+ _vm.AvatarImageSource = await GetAvatarImageSourceAsync();
+
+ _broadcasterService.Subscribe(nameof(AutofillCiphersPage), async (message) =>
+ {
+ if (message.Command == "syncStarted")
+ {
+ Device.BeginInvokeOnMainThread(() => IsBusy = true);
+ }
+ else if (message.Command == "syncCompleted")
+ {
+ await Task.Delay(500);
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ IsBusy = false;
+ if (_vm.LoadedOnce)
+ {
+ var task = _vm.LoadAsync();
+ }
+ });
+ }
+ });
+
await LoadOnAppearedAsync(_mainLayout, false, async () =>
{
try
@@ -59,6 +89,11 @@ namespace Bit.App.Pages
protected override bool OnBackButtonPressed()
{
+ if (_accountListOverlay.IsVisible)
+ {
+ _accountListOverlay.HideAsync().FireAndForget();
+ return true;
+ }
if (Device.RuntimePlatform == Device.Android)
{
_appOptions.Uri = null;
@@ -66,6 +101,13 @@ namespace Bit.App.Pages
return base.OnBackButtonPressed();
}
+ protected override void OnDisappearing()
+ {
+ base.OnDisappearing();
+ IsBusy = false;
+ _accountAvatar?.OnDisappearing();
+ }
+
private async void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ExtendedCollectionView)sender).SelectedItem = null;
diff --git a/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs b/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs
index 360b5d225..77e0dea0a 100644
--- a/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs
+++ b/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.CommunityToolkit.ObjectModel;
+using Bit.App.Controls;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -23,8 +24,10 @@ namespace Bit.App.Pages
private readonly ICipherService _cipherService;
private readonly IStateService _stateService;
private readonly IPasswordRepromptService _passwordRepromptService;
+ private readonly IMessagingService _messagingService;
+ private readonly ILogger _logger;
- private AppOptions _appOptions;
+ private bool _showNoData;
private bool _showList;
private string _noDataText;
private bool _websiteIconsEnabled;
@@ -36,15 +39,30 @@ namespace Bit.App.Pages
_deviceActionService = ServiceContainer.Resolve("deviceActionService");
_stateService = ServiceContainer.Resolve("stateService");
_passwordRepromptService = ServiceContainer.Resolve("passwordRepromptService");
+ _messagingService = ServiceContainer.Resolve("messagingService");
+ _logger = ServiceContainer.Resolve("logger");
GroupedItems = new ObservableRangeCollection();
CipherOptionsCommand = new Command(CipherOptionsAsync);
+
+ AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger)
+ {
+ AllowAddAccountRow = false
+ };
}
public string Name { get; set; }
public string Uri { get; set; }
public Command CipherOptionsCommand { get; set; }
+ public bool LoadedOnce { get; set; }
public ObservableRangeCollection GroupedItems { get; set; }
+ public AccountSwitchingOverlayViewModel AccountSwitchingOverlayViewModel { get; }
+
+ public bool ShowNoData
+ {
+ get => _showNoData;
+ set => SetProperty(ref _showNoData, value);
+ }
public bool ShowList
{
@@ -65,7 +83,6 @@ namespace Bit.App.Pages
public void Init(AppOptions appOptions)
{
- _appOptions = appOptions;
Uri = appOptions?.Uri;
string name = null;
if (Uri?.StartsWith(Constants.AndroidAppProtocol) ?? false)
@@ -87,8 +104,10 @@ namespace Bit.App.Pages
public async Task LoadAsync()
{
- WebsiteIconsEnabled = !(await _stateService.GetDisableFaviconAsync()).GetValueOrDefault();
+ LoadedOnce = true;
ShowList = false;
+ ShowNoData = false;
+ WebsiteIconsEnabled = !(await _stateService.GetDisableFaviconAsync()).GetValueOrDefault();
var groupedItems = new List();
var ciphers = await _cipherService.GetAllDecryptedByUrlAsync(Uri, null);
var matching = ciphers.Item1?.Select(c => new GroupingsPageListItem { Cipher = c }).ToList();
@@ -150,6 +169,7 @@ namespace Bit.App.Pages
}
}
ShowList = groupedItems.Any();
+ ShowNoData = !ShowList;
}
public async Task SelectCipherAsync(CipherView cipher, bool fuzzy)