mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
* [PM-2658] Settings Reorganization Init (#2697) * PM-2658 Started settings reorganization (settings main + vault + about) * PM-2658 Added settings controls based on templates and implemented OtherSettingsPage * PM-2658 Fix format * [PM-3512] Settings Appearance (#2703) * PM-3512 Implemented new Appearance Settings * PM-3512 Fix format * [PM-3510] Implement Account Security Settings view (#2714) * PM-3510 Implemented Security settings view * PM-3510 Fix format * PM-3510 Added empty placeholder to pending login requests and also improved a11y on security settings view. * PM-3511 Implemented autofill settings view (#2735) * [PM-3695] Add Connect to Watch to Other settings (#2736) * PM-3511 Implemented autofill settings view * PM-3695 Add Connect to watch setting to other settings view * [PM-3693] Clear old Settings approach (#2737) * PM-3511 Implemented autofill settings view * PM-3693 Remove old Settings approach * PM-3845 Fix default dark theme description verbiage (#2759) * PM-3839 Fix allow screen capture and submit crash logs to init their state when the page appears (#2760) * PM-3834 Fix dialogs strings on settings (#2758) * [PM-3834] Fix import items link (#2782) * PM-3834 Fix import items link * PM-3834 Fix import items link, removed old link. * [PM-4092] Fix vault timeout policies on new Settings (#2796) * PM-4092 Fix vault timeout policy on settings for disabling controls and reset timeout when surpassing maximum * PM-4092 Removed testing hardcoding of policy data
125 lines
4.3 KiB
C#
125 lines
4.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Bit.App.Abstractions;
|
|
using Bit.App.Resources;
|
|
using Bit.Core.Abstractions;
|
|
using Bit.Core.Utilities;
|
|
using Xamarin.CommunityToolkit.ObjectModel;
|
|
using Xamarin.Essentials;
|
|
|
|
namespace Bit.App.Pages
|
|
{
|
|
public class PickerViewModel<TKey> : ExtendedViewModel
|
|
{
|
|
const string SELECTED_CHARACTER = "✓";
|
|
|
|
private readonly IDeviceActionService _deviceActionService;
|
|
private readonly ILogger _logger;
|
|
private readonly Func<TKey, Task<bool>> _onSelectionChangingAsync;
|
|
private readonly string _title;
|
|
|
|
public Dictionary<TKey, string> _items;
|
|
private TKey _selectedKey;
|
|
private TKey _defaultSelectedKeyIfFailsToFind;
|
|
private Func<TKey, Task> _afterSelectionChangedAsync;
|
|
|
|
public PickerViewModel(IDeviceActionService deviceActionService,
|
|
ILogger logger,
|
|
Func<TKey, Task<bool>> onSelectionChangingAsync,
|
|
string title,
|
|
Func<object, bool> canExecuteSelectOptionCommand = null,
|
|
Action<Exception> onSelectOptionCommandException = null)
|
|
{
|
|
_deviceActionService = deviceActionService;
|
|
_logger = logger;
|
|
_onSelectionChangingAsync = onSelectionChangingAsync;
|
|
_title = title;
|
|
|
|
SelectOptionCommand = new AsyncCommand(SelectOptionAsync, canExecuteSelectOptionCommand, onSelectOptionCommandException, allowsMultipleExecutions: false);
|
|
}
|
|
|
|
public AsyncCommand SelectOptionCommand { get; }
|
|
|
|
public TKey SelectedKey => _selectedKey;
|
|
|
|
public string SelectedValue
|
|
{
|
|
get
|
|
{
|
|
if (_items.TryGetValue(_selectedKey, out var option))
|
|
{
|
|
return option;
|
|
}
|
|
|
|
_selectedKey = _defaultSelectedKeyIfFailsToFind;
|
|
return _items[_selectedKey];
|
|
}
|
|
}
|
|
|
|
public void Init(Dictionary<TKey, string> items, TKey currentSelectedKey, TKey defaultSelectedKeyIfFailsToFind, bool logIfKeyNotFound = true)
|
|
{
|
|
_items = items;
|
|
_defaultSelectedKeyIfFailsToFind = defaultSelectedKeyIfFailsToFind;
|
|
|
|
Select(currentSelectedKey, logIfKeyNotFound);
|
|
}
|
|
|
|
public void Select(TKey key, bool logIfKeyNotFound = true)
|
|
{
|
|
if (!_items.ContainsKey(key))
|
|
{
|
|
if (logIfKeyNotFound)
|
|
{
|
|
_logger.Error($"There is no {_title} options for key: {key}");
|
|
}
|
|
key = _defaultSelectedKeyIfFailsToFind;
|
|
}
|
|
|
|
_selectedKey = key;
|
|
|
|
MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(SelectedValue)));
|
|
}
|
|
|
|
private async Task SelectOptionAsync()
|
|
{
|
|
var selection = await _deviceActionService.DisplayActionSheetAsync(_title,
|
|
AppResources.Cancel,
|
|
null,
|
|
_items.Select(o => CreateSelectableOption(o.Value, EqualityComparer<TKey>.Default.Equals(o.Key, _selectedKey)))
|
|
.ToArray()
|
|
);
|
|
|
|
if (selection == null || selection == AppResources.Cancel)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var sanitizedSelection = selection.Replace($"{SELECTED_CHARACTER} ", string.Empty);
|
|
var optionKey = _items.First(o => o.Value == sanitizedSelection).Key;
|
|
|
|
if (EqualityComparer<TKey>.Default.Equals(optionKey, _selectedKey)
|
|
||
|
|
!await _onSelectionChangingAsync(optionKey))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_selectedKey = optionKey;
|
|
TriggerPropertyChanged(nameof(SelectedValue));
|
|
|
|
if (_afterSelectionChangedAsync != null)
|
|
{
|
|
await _afterSelectionChangedAsync(_selectedKey);
|
|
}
|
|
}
|
|
|
|
public void SetAfterSelectionChanged(Func<TKey, Task> afterSelectionChangedAsync) => _afterSelectionChangedAsync = afterSelectionChangedAsync;
|
|
|
|
private string CreateSelectableOption(string option, bool selected) => selected ? ToSelectedOption(option) : option;
|
|
|
|
private string ToSelectedOption(string option) => $"{SELECTED_CHARACTER} {option}";
|
|
}
|
|
}
|