Focus behavior on confirmation
DELETE
WalletWasabi.Fluent/Behaviors/MoveFocusOnDisabledBehavior.cs
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Xaml.Interactivity;
-using System.Reactive.Disposables;
-
-namespace WalletWasabi.Fluent.Behaviors
-{
- public class MoveFocusOnDisabledBehavior : Behavior<Control>
- {
- private CompositeDisposable Disposables { get; } = new CompositeDisposable();
-
- protected override void OnAttached()
- {
- base.OnAttached();
-
- AssociatedObject.PropertyChanged += AssociatedObject_PropertyChanged;
- }
-
- private void AssociatedObject_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
- {
- if (e.Property.Name == "IsEnabled")
- {
-
- }
- }
-
- protected override void OnDetaching()
- {
- base.OnDetaching();
-
- Disposables?.Dispose();
- }
- }
-}

MODIFY
WalletWasabi.Fluent/Models/RecoveryWord.cs
WalletWasabi.Fluent/Models/RecoveryWord.cs
@@ -13,6 +13,7 @@ namespace WalletWasabi.Fluent.Models
{
private string _input;
private bool _isConfirmed;
+ private bool _isFocused;
public RecoveryWord(int index, string word)
{
@@ -34,9 +35,21 @@ namespace WalletWasabi.Fluent.Models
set => this.RaiseAndSetIfChanged(ref _isConfirmed, value);
}
+ public bool IsFocused
+ {
+ get => _isFocused;
+ set => this.RaiseAndSetIfChanged(ref _isFocused, value);
+ }
+
public int Index { get; }
public string Word { get; }
+ public void Reset()
+ {
+ Input = "";
+ IsConfirmed = false;
+ }
+
private void ValidateWord(IValidationErrors errors)
{
if (string.IsNullOrWhiteSpace(Input))

MODIFY
WalletWasabi.Fluent/ViewModels/Dialogs/CreateWallet/ConfirmRecoveryWordsViewModel.cs
WalletWasabi.Fluent/ViewModels/Dialogs/CreateWallet/ConfirmRecoveryWordsViewModel.cs
using ReactiveUI;
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
using System.Linq;
+using System.Reactive.Linq;
+using System.Windows.Input;
using WalletWasabi.Fluent.Models;
using WalletWasabi.Gui.ViewModels;
@@ -12,19 +17,59 @@ namespace WalletWasabi.Fluent.ViewModels.Dialogs.CreateWallet
public ConfirmRecoveryWordsViewModel(IScreen screen, List<RecoveryWord> mnemonicWords)
{
HostScreen = screen;
- ConfirmationWords = new List<RecoveryWord>();
+
+ ConfirmationWords = new ObservableCollection<RecoveryWord>();
+ ConfirmationWords.CollectionChanged += OnConfirmationWordCollectionChanged;
+
+ FinishCommand = ReactiveCommand.Create(() => screen.Router.NavigationStack.Clear());
SetConfirmationWords(mnemonicWords);
}
public string UrlPathSegment { get; }
public IScreen HostScreen { get; }
- public List<RecoveryWord> ConfirmationWords { get; }
+ public ObservableCollection<RecoveryWord> ConfirmationWords { get; }
+ public ICommand FinishCommand { get; }
+
+ private void OnConfirmationWordCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (e.Action == NotifyCollectionChangedAction.Remove)
+ {
+ foreach (RecoveryWord item in e.OldItems)
+ {
+ item.PropertyChanged -= JumpFocus;
+ }
+ }
+ else if (e.Action == NotifyCollectionChangedAction.Add)
+ {
+ foreach (RecoveryWord item in e.NewItems)
+ {
+ item.PropertyChanged += JumpFocus;
+ }
+ }
+ }
+
+ private void JumpFocus(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(RecoveryWord.IsConfirmed))
+ {
+ var nextToFocus = ConfirmationWords.FirstOrDefault(x => x.IsConfirmed == false);
+
+ if (nextToFocus is { })
+ {
+ nextToFocus.IsFocused = true;
+ }
+ else
+ {
+ // Every item is confirmed
+ }
+ }
+ }
private void SetConfirmationWords(List<RecoveryWord> mnemonicWords)
{
var random = new Random();
- var unsortedConfWords = new List<RecoveryWord>();
+ var unsortedConfWords = new ObservableCollection<RecoveryWord>();
for (int i = 0; i < 4; i++)
{
@@ -39,10 +84,14 @@ namespace WalletWasabi.Fluent.ViewModels.Dialogs.CreateWallet
}
}
+ mnemonicWords[index].Reset();
unsortedConfWords.Add(mnemonicWords[index]);
}
- ConfirmationWords.AddRange(unsortedConfWords.OrderBy(x => x.Index));
+ foreach (RecoveryWord item in unsortedConfWords.OrderBy(x => x.Index))
+ {
+ ConfirmationWords.Add(item);
+ }
}
}
}

MODIFY
WalletWasabi.Fluent/Views/Dialogs/CreateWallet/ConfirmRecoveryWordsView.axaml
WalletWasabi.Fluent/Views/Dialogs/CreateWallet/ConfirmRecoveryWordsView.axaml
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
- xmlns:behaviors="clr-namespace:WalletWasabi.Fluent.Behaviors;assembly=WalletWasabi.Fluent"
+ xmlns:behaviors="clr-namespace:WalletWasabi.Gui.Behaviors;assembly=WalletWasabi.Gui"
mc:Ignorable="d"
d:DesignWidth="600" d:DesignHeight="500"
Width="600" Height="500"
<StackPanel Orientation="Horizontal">
<TextBox Watermark="Type the word here..." Text="{Binding Input}" IsEnabled="{Binding !IsConfirmed}" Width="280" FontSize="12">
<i:Interaction.Behaviors>
- <behaviors:MoveFocusOnDisabledBehavior />
+ <behaviors:FocusBehavior IsFocused="{Binding IsFocused}"/>
</i:Interaction.Behaviors>
</TextBox>
<PathIcon Foreground="Green" IsVisible="{Binding IsConfirmed}" Data="{StaticResource checkmark_filled}" VerticalAlignment="Center" Width="12" Height="12" Margin="15 0 0 0"/>
</StackPanel>
<Button Content="Cancel" Command="{Binding CancelCommand}" Classes="invisible" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
- <Button Content="Finish" Command="{Binding ContinueCommand}" Classes="action" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
+ <Button Content="Finish" Command="{Binding FinishCommand}" Classes="action" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
</Panel>
</UserControl>

MODIFY
WalletWasabi.Fluent/Views/SettingsPageView.axaml
WalletWasabi.Fluent/Views/SettingsPageView.axaml
<Button Command="{Binding NextCommand}" Content="Next" />
<Button Command="{Binding OpenDialogCommand}" Content="Open Dialog" />
<Button Command="{Binding ChangeThemeCommand}" Content="Change Theme" />
- <Button Command="{Binding CreateWalletCommand}" Content="Create Wallet" /
+ <Button Command="{Binding CreateWalletCommand}" Content="Create Wallet" />
<TextBox Watermark="Type here..."/>
<TextBox Watermark="Type here... #2"/>
<TextBox Watermark="Type here... #3" Text="{Binding RandomString}"/>

Focus behavior on confirmation