mirror of
https://github.com/bitwarden/android.git
synced 2024-12-27 11:28:28 +03:00
PM-3349 PM-3350 Refactored cipher bindings to have a simpler approach reusing a new CipherItemViewModel to avoid unwanted issues in the app
This commit is contained in:
parent
19c393842f
commit
5803635f44
18 changed files with 119 additions and 329 deletions
|
@ -1,68 +1,10 @@
|
||||||
using System;
|
namespace Bit.App.Controls
|
||||||
using Bit.App.Pages;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
{
|
||||||
public partial class AuthenticatorViewCell : ExtendedGrid
|
public partial class AuthenticatorViewCell : ExtendedGrid
|
||||||
{
|
{
|
||||||
public static readonly BindableProperty CipherProperty = BindableProperty.Create(
|
|
||||||
nameof(Cipher), typeof(CipherView), typeof(AuthenticatorViewCell), default(CipherView), BindingMode.TwoWay);
|
|
||||||
|
|
||||||
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
|
|
||||||
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(AuthenticatorViewCell));
|
|
||||||
|
|
||||||
public static readonly BindableProperty TotpSecProperty = BindableProperty.Create(
|
|
||||||
nameof(TotpSec), typeof(long), 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
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(WebsiteIconsEnabledProperty);
|
|
||||||
set => SetValue(WebsiteIconsEnabledProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long TotpSec
|
|
||||||
{
|
|
||||||
get => (long)GetValue(TotpSecProperty);
|
|
||||||
set => SetValue(TotpSecProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowIconImage
|
|
||||||
{
|
|
||||||
get => WebsiteIconsEnabled ?? false
|
|
||||||
&& !string.IsNullOrWhiteSpace(Cipher.Login?.Uri)
|
|
||||||
&& IconImageSource != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string _iconImageSource = string.Empty;
|
|
||||||
public string IconImageSource
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_iconImageSource == string.Empty) // default value since icon source can return null
|
|
||||||
{
|
|
||||||
_iconImageSource = IconImageHelper.GetLoginIconImage(Cipher);
|
|
||||||
}
|
|
||||||
return _iconImageSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||||
x:Class="Bit.App.Controls.CipherViewCell"
|
x:Class="Bit.App.Controls.CipherViewCell"
|
||||||
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.Maui;assembly=FFImageLoading.Compat.Maui"
|
xmlns:ff="clr-namespace:FFImageLoading.Maui;assembly=FFImageLoading.Compat.Maui"
|
||||||
xmlns:core="clr-namespace:Bit.Core"
|
xmlns:core="clr-namespace:Bit.Core"
|
||||||
StyleClass="list-row, list-row-platform"
|
StyleClass="list-row, list-row-platform"
|
||||||
RowSpacing="0"
|
RowSpacing="0"
|
||||||
ColumnSpacing="0"
|
ColumnSpacing="0"
|
||||||
x:DataType="controls:CipherViewCellViewModel"
|
x:DataType="pages:CipherItemViewModel"
|
||||||
AutomationId="CipherCell">
|
AutomationId="CipherCell">
|
||||||
|
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Pages;
|
using Bit.App.Pages;
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
namespace Bit.App.Controls
|
||||||
|
@ -11,12 +10,6 @@ namespace Bit.App.Controls
|
||||||
private const int ICON_COLUMN_DEFAULT_WIDTH = 40;
|
private const int ICON_COLUMN_DEFAULT_WIDTH = 40;
|
||||||
private const int ICON_IMAGE_DEFAULT_WIDTH = 22;
|
private const int ICON_IMAGE_DEFAULT_WIDTH = 22;
|
||||||
|
|
||||||
public static readonly BindableProperty CipherProperty = BindableProperty.Create(
|
|
||||||
nameof(Cipher), typeof(CipherView), typeof(CipherViewCell), default(CipherView), BindingMode.OneWay);
|
|
||||||
|
|
||||||
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
|
|
||||||
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(CipherViewCell));
|
|
||||||
|
|
||||||
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
|
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
|
||||||
nameof(ButtonCommand), typeof(ICommand), typeof(CipherViewCell));
|
nameof(ButtonCommand), typeof(ICommand), typeof(CipherViewCell));
|
||||||
|
|
||||||
|
@ -30,51 +23,17 @@ namespace Bit.App.Controls
|
||||||
_iconImage.HeightRequest = ICON_IMAGE_DEFAULT_WIDTH * fontScale;
|
_iconImage.HeightRequest = ICON_IMAGE_DEFAULT_WIDTH * fontScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool? WebsiteIconsEnabled
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(WebsiteIconsEnabledProperty);
|
|
||||||
set => SetValue(WebsiteIconsEnabledProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CipherView Cipher
|
|
||||||
{
|
|
||||||
get => GetValue(CipherProperty) as CipherView;
|
|
||||||
set => SetValue(CipherProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICommand ButtonCommand
|
public ICommand ButtonCommand
|
||||||
{
|
{
|
||||||
get => GetValue(ButtonCommandProperty) as ICommand;
|
get => GetValue(ButtonCommandProperty) as ICommand;
|
||||||
set => SetValue(ButtonCommandProperty, value);
|
set => SetValue(ButtonCommandProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPropertyChanged(string propertyName = null)
|
|
||||||
{
|
|
||||||
base.OnPropertyChanged(propertyName);
|
|
||||||
|
|
||||||
if (BindingContext is CipherViewCellViewModel cipherViewCellViewModel && propertyName == WebsiteIconsEnabledProperty.PropertyName)
|
|
||||||
{
|
|
||||||
cipherViewCellViewModel.WebsiteIconsEnabled = WebsiteIconsEnabled ?? false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MoreButton_Clicked(object sender, EventArgs e)
|
private void MoreButton_Clicked(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
// WORKAROUND: Added a temporary workaround so that the MoreButton still works in all pages even if it uses GroupingsPageListItem instead of CipherViewCellViewModel.
|
if (BindingContext is CipherItemViewModel cipherItem)
|
||||||
// Ideally this should be fixed so that even Groupings Page uses CipherViewCellViewModel
|
|
||||||
CipherView cipherView = null;
|
|
||||||
if (BindingContext is CipherViewCellViewModel cipherViewCellViewModel)
|
|
||||||
{
|
{
|
||||||
cipherView = cipherViewCellViewModel.Cipher;
|
ButtonCommand?.Execute(cipherItem.Cipher);
|
||||||
}
|
|
||||||
else if (BindingContext is GroupingsPageListItem groupingsPageListItem)
|
|
||||||
{
|
|
||||||
cipherView = groupingsPageListItem.Cipher;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cipherView != null)
|
|
||||||
{
|
|
||||||
ButtonCommand?.Execute(cipherView);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
using System.Globalization;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class CipherViewToCipherViewCellViewModelConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is CipherView cipher)
|
|
||||||
{
|
|
||||||
return new CipherViewCellViewModel(cipher, false);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CipherViewCellViewModel : ExtendedViewModel
|
|
||||||
{
|
|
||||||
private CipherView _cipher;
|
|
||||||
private bool _websiteIconsEnabled;
|
|
||||||
private string _iconImageSource = string.Empty;
|
|
||||||
|
|
||||||
public CipherViewCellViewModel(CipherView cipherView, bool websiteIconsEnabled)
|
|
||||||
{
|
|
||||||
Cipher = cipherView;
|
|
||||||
WebsiteIconsEnabled = websiteIconsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CipherView Cipher
|
|
||||||
{
|
|
||||||
get => _cipher;
|
|
||||||
set => SetProperty(ref _cipher, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool WebsiteIconsEnabled
|
|
||||||
{
|
|
||||||
get => _websiteIconsEnabled;
|
|
||||||
set => SetProperty(ref _websiteIconsEnabled, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowIconImage
|
|
||||||
{
|
|
||||||
get => WebsiteIconsEnabled
|
|
||||||
&& !string.IsNullOrWhiteSpace(Cipher.LaunchUri)
|
|
||||||
&& IconImageSource != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string IconImageSource
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_iconImageSource == string.Empty) // default value since icon source can return null
|
|
||||||
{
|
|
||||||
_iconImageSource = IconImageHelper.GetIconImage(Cipher);
|
|
||||||
}
|
|
||||||
return _iconImageSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +1,11 @@
|
||||||
using System.Collections.Generic;
|
using Bit.App.Models;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Models;
|
|
||||||
using Bit.Core.Resources.Localization;
|
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -48,7 +43,7 @@ namespace Bit.App.Pages
|
||||||
var groupedItems = new List<GroupingsPageListGroup>();
|
var groupedItems = new List<GroupingsPageListGroup>();
|
||||||
var ciphers = await _cipherService.GetAllDecryptedByUrlAsync(Uri, null);
|
var ciphers = await _cipherService.GetAllDecryptedByUrlAsync(Uri, null);
|
||||||
|
|
||||||
var matching = ciphers.Item1?.Select(c => new GroupingsPageListItem { Cipher = c }).ToList();
|
var matching = ciphers.Item1?.Select(c => new CipherItemViewModel(c, WebsiteIconsEnabled)).ToList();
|
||||||
var hasMatching = matching?.Any() ?? false;
|
var hasMatching = matching?.Any() ?? false;
|
||||||
if (matching?.Any() ?? false)
|
if (matching?.Any() ?? false)
|
||||||
{
|
{
|
||||||
|
@ -57,7 +52,7 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
var fuzzy = ciphers.Item2?.Select(c =>
|
var fuzzy = ciphers.Item2?.Select(c =>
|
||||||
new GroupingsPageListItem { Cipher = c, FuzzyAutofill = true }).ToList();
|
new CipherItemViewModel(c, WebsiteIconsEnabled, true)).ToList();
|
||||||
if (fuzzy?.Any() ?? false)
|
if (fuzzy?.Any() ?? false)
|
||||||
{
|
{
|
||||||
groupedItems.Add(
|
groupedItems.Add(
|
||||||
|
@ -70,7 +65,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
protected override async Task SelectCipherAsync(IGroupingsPageListItem item)
|
protected override async Task SelectCipherAsync(IGroupingsPageListItem item)
|
||||||
{
|
{
|
||||||
if (!(item is GroupingsPageListItem listItem) || listItem.Cipher is null)
|
if (!(item is CipherItemViewModel listItem) || listItem.Cipher is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
42
src/Core/Pages/Vault/CipherItemViewModel.cs
Normal file
42
src/Core/Pages/Vault/CipherItemViewModel.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using Bit.App.Utilities;
|
||||||
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.App.Pages
|
||||||
|
{
|
||||||
|
public class CipherItemViewModel : ExtendedViewModel, IGroupingsPageListItem
|
||||||
|
{
|
||||||
|
private readonly bool _websiteIconsEnabled;
|
||||||
|
private string _iconImageSource = string.Empty;
|
||||||
|
|
||||||
|
public CipherItemViewModel(CipherView cipherView, bool websiteIconsEnabled, bool fuzzyAutofill = false)
|
||||||
|
{
|
||||||
|
Cipher = cipherView;
|
||||||
|
_websiteIconsEnabled = websiteIconsEnabled;
|
||||||
|
FuzzyAutofill = fuzzyAutofill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CipherView Cipher { get; }
|
||||||
|
|
||||||
|
public bool FuzzyAutofill { get; }
|
||||||
|
|
||||||
|
public bool ShowIconImage
|
||||||
|
{
|
||||||
|
get => _websiteIconsEnabled
|
||||||
|
&& !string.IsNullOrWhiteSpace(Cipher.LaunchUri)
|
||||||
|
&& IconImageSource != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string IconImageSource
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_iconImageSource == string.Empty) // default value since icon source can return null
|
||||||
|
{
|
||||||
|
_iconImageSource = IconImageHelper.GetIconImage(Cipher);
|
||||||
|
}
|
||||||
|
return _iconImageSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,6 @@
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<u:InverseBoolConverter x:Key="inverseBool" />
|
<u:InverseBoolConverter x:Key="inverseBool" />
|
||||||
<controls:SelectionChangedEventArgsConverter x:Key="SelectionChangedEventArgsConverter" />
|
<controls:SelectionChangedEventArgsConverter x:Key="SelectionChangedEventArgsConverter" />
|
||||||
<controls:CipherViewToCipherViewCellViewModelConverter x:Key="cipherViewToCipherViewCellViewModel" />
|
|
||||||
|
|
||||||
<ToolbarItem
|
<ToolbarItem
|
||||||
x:Name="_closeItem"
|
x:Name="_closeItem"
|
||||||
|
@ -46,9 +45,7 @@
|
||||||
<DataTemplate x:Key="cipherTemplate"
|
<DataTemplate x:Key="cipherTemplate"
|
||||||
x:DataType="pages:GroupingsPageListItem">
|
x:DataType="pages:GroupingsPageListItem">
|
||||||
<controls:CipherViewCell
|
<controls:CipherViewCell
|
||||||
BindingContext="{Binding Cipher, Converter={StaticResource cipherViewToCipherViewCellViewModel}}"
|
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}" />
|
||||||
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}"
|
|
||||||
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}" />
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate
|
<DataTemplate
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
using System;
|
using Bit.App.Abstractions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -37,12 +33,10 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
#if IOS
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
ToolbarItems.Add(_closeItem);
|
ToolbarItems.Add(_closeItem);
|
||||||
ToolbarItems.Add(_addItem);
|
ToolbarItems.Add(_addItem);
|
||||||
}
|
#endif
|
||||||
|
|
||||||
SetActivityIndicator(_mainContent);
|
SetActivityIndicator(_mainContent);
|
||||||
_vm = BindingContext as CipherSelectionPageViewModel;
|
_vm = BindingContext as CipherSelectionPageViewModel;
|
||||||
|
@ -88,12 +82,12 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if (message.Command == "syncStarted")
|
if (message.Command == "syncStarted")
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(() => IsBusy = true);
|
MainThread.BeginInvokeOnMainThread(() => IsBusy = true);
|
||||||
}
|
}
|
||||||
else if (message.Command == "syncCompleted")
|
else if (message.Command == "syncCompleted")
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
IsBusy = false;
|
IsBusy = false;
|
||||||
if (_vm.LoadedOnce)
|
if (_vm.LoadedOnce)
|
||||||
|
@ -130,11 +124,10 @@ namespace Bit.App.Pages
|
||||||
_accountListOverlay.HideAsync().FireAndForget();
|
_accountListOverlay.HideAsync().FireAndForget();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
#if ANDROID
|
||||||
{
|
|
||||||
_appOptions.Uri = null;
|
_appOptions.Uri = null;
|
||||||
}
|
#endif
|
||||||
return base.OnBackButtonPressed();
|
return base.OnBackButtonPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
<ContentPage.Resources>
|
<ContentPage.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<controls:CipherViewToCipherViewCellViewModelConverter x:Key="cipherViewToCipherViewCellViewModel" />
|
|
||||||
|
|
||||||
<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
|
||||||
|
@ -55,7 +53,7 @@
|
||||||
IsVisible="{Binding ShowVaultFilter}"
|
IsVisible="{Binding ShowVaultFilter}"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
HorizontalOptions="FillAndExpand"
|
HorizontalOptions="FillAndExpand"
|
||||||
Margin="0,5,0,0">
|
Margin="{OnPlatform Android='0,5,0,0', iOS='0,15'}">
|
||||||
<Label
|
<Label
|
||||||
Text="{Binding VaultFilterDescription}"
|
Text="{Binding VaultFilterDescription}"
|
||||||
LineBreakMode="TailTruncation"
|
LineBreakMode="TailTruncation"
|
||||||
|
@ -112,10 +110,7 @@
|
||||||
<!--Binding context is not applied if the cell is the direct child, check for context https://github.com/dotnet/maui/issues/9131-->
|
<!--Binding context is not applied if the cell is the direct child, check for context https://github.com/dotnet/maui/issues/9131-->
|
||||||
<Grid>
|
<Grid>
|
||||||
<controls:CipherViewCell
|
<controls:CipherViewCell
|
||||||
BindingContext="{Binding ., Converter={StaticResource cipherViewToCipherViewCellViewModel}}"
|
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}" />
|
||||||
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}"
|
|
||||||
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
|
|
||||||
/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</CollectionView.ItemTemplate>
|
</CollectionView.ItemTemplate>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using Bit.Core.Resources.Localization;
|
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
|
@ -120,9 +120,9 @@ namespace Bit.App.Pages
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.CurrentSelection?.FirstOrDefault() is CipherView cipher)
|
if (e.CurrentSelection?.FirstOrDefault() is CipherItemViewModel cipherIteemVM)
|
||||||
{
|
{
|
||||||
await _vm.SelectCipherAsync(cipher);
|
await _vm.SelectCipherAsync(cipherIteemVM.Cipher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Bit.App.Pages
|
||||||
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
||||||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
||||||
|
|
||||||
Ciphers = new ExtendedObservableCollection<CipherView>();
|
Ciphers = new ExtendedObservableCollection<CipherItemViewModel>();
|
||||||
CipherOptionsCommand = CreateDefaultAsyncRelayCommand<CipherView>(cipher => Utilities.AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
CipherOptionsCommand = CreateDefaultAsyncRelayCommand<CipherView>(cipher => Utilities.AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
@ -53,7 +53,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
public ICommand CipherOptionsCommand { get; }
|
public ICommand CipherOptionsCommand { get; }
|
||||||
public ICommand AddCipherCommand { get; }
|
public ICommand AddCipherCommand { get; }
|
||||||
public ExtendedObservableCollection<CipherView> Ciphers { get; set; }
|
public ExtendedObservableCollection<CipherItemViewModel> Ciphers { get; set; }
|
||||||
public Func<CipherView, bool> Filter { get; set; }
|
public Func<CipherView, bool> Filter { get; set; }
|
||||||
public string AutofillUrl { get; set; }
|
public string AutofillUrl { get; set; }
|
||||||
public bool Deleted { get; set; }
|
public bool Deleted { get; set; }
|
||||||
|
@ -87,12 +87,6 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
public bool ShowAddCipher => ShowNoData && _appOptions?.OtpData != null;
|
public bool ShowAddCipher => ShowNoData && _appOptions?.OtpData != null;
|
||||||
|
|
||||||
public bool WebsiteIconsEnabled
|
|
||||||
{
|
|
||||||
get => _websiteIconsEnabled;
|
|
||||||
set => SetProperty(ref _websiteIconsEnabled, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Prepare(Func<CipherView, bool> filter, bool deleted, AppOptions appOptions)
|
internal void Prepare(Func<CipherView, bool> filter, bool deleted, AppOptions appOptions)
|
||||||
{
|
{
|
||||||
Filter = filter;
|
Filter = filter;
|
||||||
|
@ -105,7 +99,7 @@ namespace Bit.App.Pages
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
await InitVaultFilterAsync(true);
|
await InitVaultFilterAsync(true);
|
||||||
WebsiteIconsEnabled = !(await _stateService.GetDisableFaviconAsync()).GetValueOrDefault();
|
_websiteIconsEnabled = await _stateService.GetDisableFaviconAsync() != true;
|
||||||
PerformSearchIfPopulated();
|
PerformSearchIfPopulated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +151,7 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
MainThread.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
Ciphers.ResetWithRange(ciphers);
|
Ciphers.ResetWithRange(ciphers.Select(c => new CipherItemViewModel(c, _websiteIconsEnabled)).ToList());
|
||||||
ShowNoData = !shouldShowAllWhenEmpty && searchable && Ciphers.Count == 0;
|
ShowNoData = !shouldShowAllWhenEmpty && searchable && Ciphers.Count == 0;
|
||||||
ShowList = (searchable || shouldShowAllWhenEmpty) && !ShowNoData;
|
ShowList = (searchable || shouldShowAllWhenEmpty) && !ShowNoData;
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,8 +32,6 @@
|
||||||
|
|
||||||
<ContentPage.Resources>
|
<ContentPage.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<controls:CipherViewToCipherViewCellViewModelConverter x:Key="cipherViewToCipherViewCellViewModel" />
|
|
||||||
|
|
||||||
<ToolbarItem x:Name="_syncItem" x:Key="syncItem" Text="{u:I18n Sync}"
|
<ToolbarItem x:Name="_syncItem" x:Key="syncItem" Text="{u:I18n Sync}"
|
||||||
Clicked="Sync_Clicked" Order="Secondary" />
|
Clicked="Sync_Clicked" Order="Secondary" />
|
||||||
<ToolbarItem x:Name="_lockItem" x:Key="lockItem" Text="{u:I18n Lock}"
|
<ToolbarItem x:Name="_lockItem" x:Key="lockItem" Text="{u:I18n Lock}"
|
||||||
|
@ -45,19 +43,14 @@
|
||||||
SemanticProperties.Description="{u:I18n AddItem}" />
|
SemanticProperties.Description="{u:I18n AddItem}" />
|
||||||
|
|
||||||
<DataTemplate x:Key="cipherTemplate"
|
<DataTemplate x:Key="cipherTemplate"
|
||||||
x:DataType="pages:GroupingsPageListItem">
|
x:DataType="pages:CipherItemViewModel">
|
||||||
<controls:CipherViewCell
|
<controls:CipherViewCell
|
||||||
BindingContext="{Binding Cipher, Converter={StaticResource cipherViewToCipherViewCellViewModel}}"
|
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}" />
|
||||||
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}"
|
|
||||||
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}" />
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="authenticatorTemplate"
|
<DataTemplate x:Key="authenticatorTemplate"
|
||||||
x:DataType="pages:GroupingsPageTOTPListItem">
|
x:DataType="pages:GroupingsPageTOTPListItem">
|
||||||
<controls:AuthenticatorViewCell
|
<controls:AuthenticatorViewCell />
|
||||||
Cipher="{Binding Cipher}"
|
|
||||||
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
|
|
||||||
TotpSec="{Binding TotpSec}" />
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="groupTemplate"
|
<DataTemplate x:Key="groupTemplate"
|
||||||
|
@ -124,7 +117,7 @@
|
||||||
IsVisible="{Binding ShowVaultFilter}"
|
IsVisible="{Binding ShowVaultFilter}"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
HorizontalOptions="FillAndExpand"
|
HorizontalOptions="FillAndExpand"
|
||||||
Margin="0,5,0,0">
|
Margin="{OnPlatform Android='0,5,0,0', iOS='0,15'}">
|
||||||
<Label
|
<Label
|
||||||
Text="{Binding VaultFilterDescription}"
|
Text="{Binding VaultFilterDescription}"
|
||||||
LineBreakMode="TailTruncation"
|
LineBreakMode="TailTruncation"
|
||||||
|
|
|
@ -215,13 +215,21 @@ namespace Bit.App.Pages
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.CurrentSelection?.FirstOrDefault() is GroupingsPageTOTPListItem totpItem)
|
var selection = e.CurrentSelection?.FirstOrDefault();
|
||||||
|
|
||||||
|
if (selection is GroupingsPageTOTPListItem totpItem)
|
||||||
{
|
{
|
||||||
await _vm.SelectCipherAsync(totpItem.Cipher);
|
await _vm.SelectCipherAsync(totpItem.Cipher);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(e.CurrentSelection?.FirstOrDefault() is GroupingsPageListItem item))
|
if (selection is CipherItemViewModel cipherItemVM)
|
||||||
|
{
|
||||||
|
await _vm.SelectCipherAsync(cipherItemVM.Cipher);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(selection is GroupingsPageListItem item))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -234,10 +242,6 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
await _vm.SelectTotpCodesAsync();
|
await _vm.SelectTotpCodesAsync();
|
||||||
}
|
}
|
||||||
else if (item.Cipher != null)
|
|
||||||
{
|
|
||||||
await _vm.SelectCipherAsync(item.Cipher);
|
|
||||||
}
|
|
||||||
else if (item.Folder != null)
|
else if (item.Folder != null)
|
||||||
{
|
{
|
||||||
await _vm.SelectFolderAsync(item.Folder);
|
await _vm.SelectFolderAsync(item.Folder);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.App.Utilities.Automation;
|
||||||
using Bit.App.Utilities.Automation;
|
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Resources.Localization;
|
||||||
using CollectionView = Bit.Core.Models.View.CollectionView;
|
using CollectionView = Bit.Core.Models.View.CollectionView;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
|
@ -14,10 +14,8 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
public FolderView Folder { get; set; }
|
public FolderView Folder { get; set; }
|
||||||
public CollectionView Collection { get; set; }
|
public CollectionView Collection { get; set; }
|
||||||
public CipherView Cipher { get; set; }
|
|
||||||
public CipherType? Type { get; set; }
|
public CipherType? Type { get; set; }
|
||||||
public string ItemCount { get; set; }
|
public string ItemCount { get; set; }
|
||||||
public bool FuzzyAutofill { get; set; }
|
|
||||||
public bool IsTrash { get; set; }
|
public bool IsTrash { get; set; }
|
||||||
public bool IsTotpCode { get; set; }
|
public bool IsTotpCode { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
using Microsoft.Maui.Controls;
|
namespace Bit.App.Pages
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
{
|
||||||
public class GroupingsPageListItemSelector : DataTemplateSelector
|
public class GroupingsPageListItemSelector : DataTemplateSelector
|
||||||
{
|
{
|
||||||
|
@ -12,19 +9,24 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
|
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
|
||||||
{
|
{
|
||||||
if (item is GroupingsPageHeaderListItem)
|
|
||||||
{
|
|
||||||
return HeaderTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item is GroupingsPageTOTPListItem)
|
if (item is GroupingsPageTOTPListItem)
|
||||||
{
|
{
|
||||||
return AuthenticatorTemplate;
|
return AuthenticatorTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is GroupingsPageListItem listItem)
|
if (item is CipherItemViewModel)
|
||||||
{
|
{
|
||||||
return listItem.Cipher != null ? CipherTemplate : GroupTemplate;
|
return CipherTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is GroupingsPageHeaderListItem)
|
||||||
|
{
|
||||||
|
return HeaderTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is GroupingsPageListItem)
|
||||||
|
{
|
||||||
|
return GroupTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,56 +1,34 @@
|
||||||
using System;
|
using Bit.App.Utilities;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.Core.Resources.Localization;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class GroupingsPageTOTPListItem : ExtendedViewModel, IGroupingsPageListItem
|
public class GroupingsPageTOTPListItem : CipherItemViewModel, IGroupingsPageListItem
|
||||||
{
|
{
|
||||||
private readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
|
|
||||||
private readonly ITotpService _totpService;
|
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
private readonly IClipboardService _clipboardService;
|
private readonly IClipboardService _clipboardService;
|
||||||
private CipherView _cipher;
|
|
||||||
|
|
||||||
private bool _websiteIconsEnabled;
|
|
||||||
private string _iconImageSource = string.Empty;
|
|
||||||
|
|
||||||
private double _progress;
|
private double _progress;
|
||||||
private string _totpSec;
|
private string _totpSec;
|
||||||
private string _totpCodeFormatted;
|
private string _totpCodeFormatted;
|
||||||
private TotpHelper _totpTickHelper;
|
private readonly TotpHelper _totpTickHelper;
|
||||||
|
|
||||||
|
|
||||||
public GroupingsPageTOTPListItem(CipherView cipherView, bool websiteIconsEnabled)
|
public GroupingsPageTOTPListItem(CipherView cipherView, bool websiteIconsEnabled)
|
||||||
|
:base(cipherView, websiteIconsEnabled)
|
||||||
{
|
{
|
||||||
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
_clipboardService = ServiceContainer.Resolve<IClipboardService>();
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
||||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
|
||||||
|
|
||||||
Cipher = cipherView;
|
|
||||||
WebsiteIconsEnabled = websiteIconsEnabled;
|
|
||||||
CopyCommand = CreateDefaultAsyncRelayCommand(CopyToClipboardAsync,
|
CopyCommand = CreateDefaultAsyncRelayCommand(CopyToClipboardAsync,
|
||||||
onException: ex => _logger.Value.Exception(ex),
|
onException: _logger.Value.Exception,
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
_totpTickHelper = new TotpHelper(cipherView);
|
_totpTickHelper = new TotpHelper(cipherView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncRelayCommand CopyCommand { get; set; }
|
public AsyncRelayCommand CopyCommand { get; set; }
|
||||||
|
|
||||||
public CipherView Cipher
|
|
||||||
{
|
|
||||||
get => _cipher;
|
|
||||||
set => SetProperty(ref _cipher, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TotpCodeFormatted
|
public string TotpCodeFormatted
|
||||||
{
|
{
|
||||||
get => _totpCodeFormatted;
|
get => _totpCodeFormatted;
|
||||||
|
@ -72,31 +50,6 @@ namespace Bit.App.Pages
|
||||||
get => _progress;
|
get => _progress;
|
||||||
set => SetProperty(ref _progress, value);
|
set => SetProperty(ref _progress, 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 string TotpCodeFormattedStart => TotpCodeFormatted?.Split(' ')[0];
|
public string TotpCodeFormattedStart => TotpCodeFormatted?.Split(' ')[0];
|
||||||
|
|
||||||
|
@ -105,7 +58,7 @@ namespace Bit.App.Pages
|
||||||
public async Task CopyToClipboardAsync()
|
public async Task CopyToClipboardAsync()
|
||||||
{
|
{
|
||||||
await _clipboardService.CopyTextAsync(TotpCodeFormatted?.Replace(" ", string.Empty));
|
await _clipboardService.CopyTextAsync(TotpCodeFormatted?.Replace(" ", string.Empty));
|
||||||
_platformUtilsService.ShowToast("info", null, string.Format(AppResources.ValueHasBeenCopied, AppResources.VerificationCodeTotp));
|
_platformUtilsService.Value.ShowToast("info", null, string.Format(AppResources.ValueHasBeenCopied, AppResources.VerificationCodeTotp));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task TotpTickAsync()
|
public async Task TotpTickAsync()
|
||||||
|
|
|
@ -25,7 +25,6 @@ namespace Bit.App.Pages
|
||||||
private bool _websiteIconsEnabled;
|
private bool _websiteIconsEnabled;
|
||||||
private bool _syncRefreshing;
|
private bool _syncRefreshing;
|
||||||
private bool _showTotpFilter;
|
private bool _showTotpFilter;
|
||||||
private bool _totpFilterEnable;
|
|
||||||
private string _noDataText;
|
private string _noDataText;
|
||||||
private List<CipherView> _allCiphers;
|
private List<CipherView> _allCiphers;
|
||||||
private Dictionary<string, int> _folderCounts = new Dictionary<string, int>();
|
private Dictionary<string, int> _folderCounts = new Dictionary<string, int>();
|
||||||
|
@ -150,11 +149,6 @@ namespace Bit.App.Pages
|
||||||
get => _showList;
|
get => _showList;
|
||||||
set => SetProperty(ref _showList, value);
|
set => SetProperty(ref _showList, value);
|
||||||
}
|
}
|
||||||
public bool WebsiteIconsEnabled
|
|
||||||
{
|
|
||||||
get => _websiteIconsEnabled;
|
|
||||||
set => SetProperty(ref _websiteIconsEnabled, value);
|
|
||||||
}
|
|
||||||
public bool ShowTotp
|
public bool ShowTotp
|
||||||
{
|
{
|
||||||
get => _showTotpFilter;
|
get => _showTotpFilter;
|
||||||
|
@ -206,7 +200,7 @@ namespace Bit.App.Pages
|
||||||
var groupedItems = new List<GroupingsPageListGroup>();
|
var groupedItems = new List<GroupingsPageListGroup>();
|
||||||
var page = Page as GroupingsPage;
|
var page = Page as GroupingsPage;
|
||||||
|
|
||||||
WebsiteIconsEnabled = !(await _stateService.GetDisableFaviconAsync()).GetValueOrDefault();
|
_websiteIconsEnabled = await _stateService.GetDisableFaviconAsync() != true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadDataAsync();
|
await LoadDataAsync();
|
||||||
|
@ -225,7 +219,7 @@ namespace Bit.App.Pages
|
||||||
var hasFavorites = FavoriteCiphers?.Any() ?? false;
|
var hasFavorites = FavoriteCiphers?.Any() ?? false;
|
||||||
if (hasFavorites)
|
if (hasFavorites)
|
||||||
{
|
{
|
||||||
var favListItems = FavoriteCiphers.Select(c => new GroupingsPageListItem { Cipher = c }).ToList();
|
var favListItems = FavoriteCiphers.Select(c => new CipherItemViewModel(c, _websiteIconsEnabled)).ToList();
|
||||||
groupedItems.Add(new GroupingsPageListGroup(favListItems, AppResources.Favorites,
|
groupedItems.Add(new GroupingsPageListGroup(favListItems, AppResources.Favorites,
|
||||||
favListItems.Count, uppercaseGroupNames, true));
|
favListItems.Count, uppercaseGroupNames, true));
|
||||||
}
|
}
|
||||||
|
@ -282,7 +276,7 @@ namespace Bit.App.Pages
|
||||||
if (ShowNoFolderCipherGroup)
|
if (ShowNoFolderCipherGroup)
|
||||||
{
|
{
|
||||||
var noFolderCiphersListItems = NoFolderCiphers.Select(
|
var noFolderCiphersListItems = NoFolderCiphers.Select(
|
||||||
c => new GroupingsPageListItem { Cipher = c }).ToList();
|
c => new CipherItemViewModel(c, _websiteIconsEnabled)).ToList();
|
||||||
groupedItems.Add(new GroupingsPageListGroup(noFolderCiphersListItems, AppResources.FolderNone,
|
groupedItems.Add(new GroupingsPageListGroup(noFolderCiphersListItems, AppResources.FolderNone,
|
||||||
noFolderCiphersListItems.Count, uppercaseGroupNames, false));
|
noFolderCiphersListItems.Count, uppercaseGroupNames, false));
|
||||||
}
|
}
|
||||||
|
@ -399,7 +393,7 @@ namespace Bit.App.Pages
|
||||||
_totpTickCts?.Cancel();
|
_totpTickCts?.Cancel();
|
||||||
if (ShowTotp)
|
if (ShowTotp)
|
||||||
{
|
{
|
||||||
var ciphersListItems = TOTPCiphers.Select(c => new GroupingsPageTOTPListItem(c, true)).ToList();
|
var ciphersListItems = TOTPCiphers.Select(c => new GroupingsPageTOTPListItem(c, _websiteIconsEnabled)).ToList();
|
||||||
groupedItems.Add(new GroupingsPageListGroup(ciphersListItems, AppResources.Items,
|
groupedItems.Add(new GroupingsPageListGroup(ciphersListItems, AppResources.Items,
|
||||||
ciphersListItems.Count, uppercaseGroupNames, !MainPage && !groupedItems.Any()));
|
ciphersListItems.Count, uppercaseGroupNames, !MainPage && !groupedItems.Any()));
|
||||||
|
|
||||||
|
@ -408,7 +402,7 @@ namespace Bit.App.Pages
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var ciphersListItems = Ciphers.Where(c => c.IsDeleted == Deleted)
|
var ciphersListItems = Ciphers.Where(c => c.IsDeleted == Deleted)
|
||||||
.Select(c => new GroupingsPageListItem { Cipher = c }).ToList();
|
.Select(c => new CipherItemViewModel(c, _websiteIconsEnabled)).ToList();
|
||||||
groupedItems.Add(new GroupingsPageListGroup(ciphersListItems, AppResources.Items,
|
groupedItems.Add(new GroupingsPageListGroup(ciphersListItems, AppResources.Items,
|
||||||
ciphersListItems.Count, uppercaseGroupNames, !MainPage && !groupedItems.Any()));
|
ciphersListItems.Count, uppercaseGroupNames, !MainPage && !groupedItems.Any()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
using System;
|
using Bit.Core.Abstractions;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.Core.Resources.Localization;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -42,7 +36,7 @@ namespace Bit.App.Pages
|
||||||
if (ciphers?.Any() ?? false)
|
if (ciphers?.Any() ?? false)
|
||||||
{
|
{
|
||||||
groupedItems.Add(
|
groupedItems.Add(
|
||||||
new GroupingsPageListGroup(ciphers.Select(c => new GroupingsPageListItem { Cipher = c }).ToList(),
|
new GroupingsPageListGroup(ciphers.Select(c => new CipherItemViewModel(c, WebsiteIconsEnabled)).ToList(),
|
||||||
AppResources.MatchingItems,
|
AppResources.MatchingItems,
|
||||||
ciphers.Count,
|
ciphers.Count,
|
||||||
false,
|
false,
|
||||||
|
@ -54,7 +48,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
protected override async Task SelectCipherAsync(IGroupingsPageListItem item)
|
protected override async Task SelectCipherAsync(IGroupingsPageListItem item)
|
||||||
{
|
{
|
||||||
if (!(item is GroupingsPageListItem listItem) || listItem.Cipher is null)
|
if (!(item is CipherItemViewModel listItem) || listItem.Cipher is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue