Implement checkmark and focus on the finish button after seed phrase verification
MODIFY
WalletWasabi.Fluent/Behaviors/FocusNextItemBehavior.cs
WalletWasabi.Fluent/Behaviors/FocusNextItemBehavior.cs
@@ -46,5 +46,6 @@ namespace WalletWasabi.Fluent.Behaviors
})
.DisposeWith(disposables);
}
+
}
}
\ No newline at end of file

ADD
WalletWasabi.Fluent/Behaviors/FocusNextTargetViaBoolean.cs
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.LogicalTree;
+using ReactiveUI;
+using System;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+
+namespace WalletWasabi.Fluent.Behaviors
+{
+ public class FocusNextTargetViaBoolean : DisposingBehavior<Control>
+ {
+ public static readonly StyledProperty<bool> FocusOnTargetProperty =
+ AvaloniaProperty.Register<FocusNextItemBehavior, bool>(nameof(FocusOnTarget), true);
+
+ public bool FocusOnTarget
+ {
+ get => GetValue(FocusOnTargetProperty);
+ set => SetValue(FocusOnTargetProperty, value);
+ }
+
+ public static readonly StyledProperty<Control> TargetControlProperty =
+ AvaloniaProperty.Register<FocusNextItemBehavior, Control>(nameof(TargetControl));
+
+ [ResolveByName]
+ public Control TargetControl
+ {
+ get => GetValue(TargetControlProperty);
+ set => SetValue(TargetControlProperty, value);
+ }
+
+ protected override void OnAttached(CompositeDisposable disposables)
+ {
+ this.WhenAnyValue(x => x.FocusOnTarget)
+ .Where(x => x)
+ .Subscribe(_ => TargetControl?.Focus())
+ .DisposeWith(disposables);
+ }
+ }
+}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/Styles/Styles.xaml
WalletWasabi.Fluent/Styles/Styles.xaml
<Setter Property="Background" Value="{DynamicResource InvisibleButtonBackgroundColor}" />
</Style>
+ <!--Obscured Button-->
+ <Style Selector="Button.obscured">
+ <Setter Property="Transitions">
+ <Transitions>
+ <DoubleTransition Property="Opacity" Easing="{StaticResource FluentDefaultEasing}" Duration="0.215" />
+ </Transitions>
+ </Setter>
+ </Style>
+ <Style Selector="Button.obscured:not(:pointerover)">
+ <Setter Property="Opacity" Value="0.5" />
+ </Style>
+ <Style Selector="Button.obscured:pointerover">
+ <Setter Property="Opacity" Value="1" />
+ </Style>
+
<!--Invisible button style-->
<Style Selector="Button.invisible">
<Setter Property="VerticalAlignment" Value="Stretch" />
<ItemsControl Items="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
- <TextBlock Text="{Binding Message}" Foreground="{Binding Severity, Converter={StaticResource ErrorSeverityColorConverter}}" TextWrapping="Wrap" />
+ <TextBlock Text="{Binding Message}"
+ Foreground="{Binding Severity, Converter={StaticResource ErrorSeverityColorConverter}}"
+ TextWrapping="Wrap" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
MinWidth="{TemplateBinding MinWidth}"
- MinHeight="{TemplateBinding MinHeight}">
- </Border>
+ MinHeight="{TemplateBinding MinHeight}" />
<Border
Margin="{TemplateBinding BorderThickness}">
<Grid ColumnDefinitions="Auto,*,Auto">
<ContentPresenter Grid.Column="0" Grid.ColumnSpan="1" Content="{TemplateBinding InnerLeftContent}" />
- <DockPanel x:Name="PART_InnerDockPanel" Grid.Column="1" Grid.ColumnSpan="1" Margin="{TemplateBinding Padding}">
+ <DockPanel x:Name="PART_InnerDockPanel" Grid.Column="1" Grid.ColumnSpan="1"
+ Margin="{TemplateBinding Padding}">
<TextBlock Name="PART_FloatingWatermark"
Foreground="{DynamicResource SystemAccentColor}"
FontSize="{TemplateBinding FontSize}"
Text="{TemplateBinding Watermark}"
DockPanel.Dock="Top" />
- <ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
+ <ScrollViewer
+ HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<Panel>
<TextBlock Name="PART_Watermark"

MODIFY
WalletWasabi.Fluent/ViewModels/RecoverWallet/RecoverWalletViewModel.cs
WalletWasabi.Fluent/ViewModels/RecoverWallet/RecoverWalletViewModel.cs
@@ -20,6 +20,7 @@ namespace WalletWasabi.Fluent.ViewModels.RecoverWallet
public class RecoverWalletViewModel : RoutableViewModel
{
private readonly ObservableAsPropertyHelper<Mnemonic?> _currentMnemonic;
+ private readonly ObservableAsPropertyHelper<bool> _finishCommandCanExecute;
private string? _selectedTag;
private IEnumerable<string>? _suggestions;
@@ -58,13 +59,12 @@ namespace WalletWasabi.Fluent.ViewModels.RecoverWallet
}
});
- var finishCommandCanExecute = this.WhenAnyValue(
+ _finishCommandCanExecute = this.WhenAnyValue(
x => x.CurrentMnemonics,
x => x.AccountKeyPath,
x => x.MinGapLimit,
delegate
{
- // This will fire validations before return canExecute value.
this.RaisePropertyChanged(nameof(CurrentMnemonics));
this.RaisePropertyChanged(nameof(AccountKeyPath));
this.RaisePropertyChanged(nameof(MinGapLimit));
@@ -72,6 +72,10 @@ namespace WalletWasabi.Fluent.ViewModels.RecoverWallet
return CurrentMnemonics is { } && (CurrentMnemonics?.IsValidChecksum ?? false) &&
!Validations.Any;
})
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .ToProperty(this, x => x.FinishCommandCanExecute);
+
+ var finishCommandCanExecute = this.WhenAnyValue(x => x.FinishCommandCanExecute)
.ObserveOn(RxApp.MainThreadScheduler);
FinishCommand = ReactiveCommand.CreateFromTask(
@@ -156,6 +160,8 @@ namespace WalletWasabi.Fluent.ViewModels.RecoverWallet
set => this.RaiseAndSetIfChanged(ref _selectedTag, value);
}
+ public bool FinishCommandCanExecute => _finishCommandCanExecute.Value;
+
private Mnemonic? CurrentMnemonics => _currentMnemonic.Value;
private void ValidateMnemonics(IValidationErrors errors)

MODIFY
WalletWasabi.Fluent/Views/RecoverWallet/RecoverWalletView.axaml
WalletWasabi.Fluent/Views/RecoverWallet/RecoverWalletView.axaml
<c:ContentArea Title="Enter recovery words" Caption="Type in your 12 recovery words and click Continue."
Margin="44 0">
<StackPanel>
- <Label Content="_Type in your recovery words here:" Target="seedTagsBox" />
+ <DockPanel>
+ <PathIcon Name="IconCheckmark" Classes="checkMark" Margin="15 42 0 0" VerticalAlignment="Top"
+ DockPanel.Dock="Right"
+ Opacity="{Binding FinishCommandCanExecute}" />
+ <Label Content="_Type in your recovery words here:" Target="seedTagsBox" DockPanel.Dock="Top" />
<c:TagsBox x:Name="seedTagsBox"
+ DockPanel.Dock="Top"
ItemCountLimit="12"
RestrictInputToSuggestions="True"
Items="{Binding Mnemonics}"
SelectedTag="{Binding SelectedTag}">
<i:Interaction.Behaviors>
<behaviors:FocusOnAttachedBehavior />
+ <behaviors:FocusNextTargetViaBoolean TargetControl="BtFinished"
+ FocusOnTarget="{Binding FinishCommandCanExecute}" />
</i:Interaction.Behaviors>
</c:TagsBox>
- <Button HorizontalAlignment="Left" Classes="plain" Margin="0,20,0,0" Command="{Binding AdvancedRecoveryOptionsDialogCommand}">
+ </DockPanel>
+
+ <StackPanel HorizontalAlignment="Right" Margin="0,20,0,0" Orientation="Horizontal">
+ <Button Classes="plain obscured"
+ Command="{Binding AdvancedRecoveryOptionsDialogCommand}">
<StackPanel Orientation="Horizontal" Spacing="20">
<PathIcon Data="{StaticResource options_regular}" />
<TextBlock Text="Advanced Recovery Options..." />
</StackPanel>
</Button>
+ <Panel Margin="15,0,0,0" Width="{Binding #IconCheckmark.Bounds.Width}" Height="1" />
+ </StackPanel>
</StackPanel>
</c:ContentArea>
<Button Content="Cancel" Command="{Binding CancelCommand}" Classes="invisible" HorizontalAlignment="Left"
VerticalAlignment="Bottom" />
- <Button Content="Restore" Command="{Binding FinishCommand}" Classes="action" HorizontalAlignment="Right"
+
+ <Button Name="BtFinished" Content="Restore" Command="{Binding FinishCommand}" Classes="action"
+ HorizontalAlignment="Right"
VerticalAlignment="Bottom" />
</Panel>
</UserControl>
\ No newline at end of file

Implement checkmark and focus on the finish button after seed phrase verification