polish logic more and add function to disallow mistakes
ADD
WalletWasabi.Fluent/Behaviors/FocusBehavior.cs
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Avalonia.Xaml.Interactivity;
+using System;
+using System.Reactive.Disposables;
+
+namespace WalletWasabi.Fluent.Behaviors
+{
+ public class FocusBehavior : Behavior<Control>
+ {
+ // ReSharper disable once MemberCanBePrivate.Global
+ public static readonly StyledProperty<bool> IsFocusedProperty =
+ AvaloniaProperty.Register<FocusBehavior, bool>(nameof(IsFocused), defaultBindingMode: BindingMode.TwoWay);
+
+ private CompositeDisposable Disposables { get; } = new CompositeDisposable();
+
+ public bool IsFocused
+ {
+ get => GetValue(IsFocusedProperty);
+ set => SetValue(IsFocusedProperty, value);
+ }
+
+ protected override void OnAttached()
+ {
+ base.OnAttached();
+
+ if (AssociatedObject is null)
+ {
+ return;
+ }
+
+ AssociatedObject.AttachedToLogicalTree += (sender, e) =>
+ Disposables.Add(this.GetObservable(IsFocusedProperty)
+ .Subscribe(focused =>
+ {
+ if (focused)
+ {
+ AssociatedObject.Focus();
+ }
+ }));
+ }
+
+ protected override void OnDetaching()
+ {
+ base.OnDetaching();
+
+ Disposables?.Dispose();
+ }
+ }
+}

MODIFY
WalletWasabi.Fluent/Behaviors/SplitViewAutoBehavior.cs
WalletWasabi.Fluent/Behaviors/SplitViewAutoBehavior.cs
@@ -58,6 +58,11 @@ namespace WalletWasabi.Fluent.Behaviors
private void OnCollapseOnClickAction()
{
+ if (AssociatedObject is null)
+ {
+ return;
+ }
+
if (AssociatedObject.Bounds.Width <= CollapseThreshold && AssociatedObject.IsPaneOpen)
{
AssociatedObject.IsPaneOpen = false;
@@ -66,6 +71,11 @@ namespace WalletWasabi.Fluent.Behaviors
private void OnToggleAction()
{
+ if (AssociatedObject is null)
+ {
+ return;
+ }
+
if (AssociatedObject.Bounds.Width > CollapseThreshold)
{
_sidebarWasForceClosed = AssociatedObject.IsPaneOpen;

MODIFY
WalletWasabi.Fluent/Behaviors/TagBoxAutoCompleteBoxBehavior.cs
WalletWasabi.Fluent/Behaviors/TagBoxAutoCompleteBoxBehavior.cs
@@ -2,9 +2,14 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Xaml.Interactivity;
using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.Input;
+using Avalonia.Interactivity;
using Avalonia.Threading;
using ReactiveUI;
@@ -12,12 +17,24 @@ namespace WalletWasabi.Fluent.Behaviors
{
public class TagBoxAutoCompleteBoxBehavior : Behavior<AutoCompleteBox>
{
+ public static readonly StyledProperty<IEnumerable<string>> SuggestionsProperty =
+ AvaloniaProperty.Register<SplitViewAutoBehavior, IEnumerable<string>>(nameof(Suggestions));
+
public static readonly StyledProperty<Action<string>> CommitTextActionProperty =
AvaloniaProperty.Register<SplitViewAutoBehavior, Action<string>>(nameof(CommitTextAction));
public static readonly StyledProperty<Action> BackspaceAndEmptyTextActionProperty =
AvaloniaProperty.Register<SplitViewAutoBehavior, Action>(nameof(BackspaceAndEmptyTextAction));
+ private IDisposable _disposable;
+ private bool _disableEntry;
+
+ public IEnumerable<string> Suggestions
+ {
+ get => GetValue(SuggestionsProperty);
+ set => SetValue(SuggestionsProperty, value);
+ }
+
public Action<string> CommitTextAction
{
get => GetValue(CommitTextActionProperty);
@@ -32,9 +49,18 @@ namespace WalletWasabi.Fluent.Behaviors
protected override void OnAttached()
{
+ if (AssociatedObject is null)
+ {
+ return;
+ }
+
AssociatedObject.KeyUp += OnKeyUp;
AssociatedObject.TextChanged += OnTextChanged;
AssociatedObject.DropDownClosed += OnDropDownClosed;
+ _disposable =
+ AssociatedObject.AddDisposableHandler(InputElement.TextInputEvent, OnTextInput,
+ RoutingStrategies.Tunnel);
+
Dispatcher.UIThread.InvokeAsync(() =>
{
@@ -46,6 +72,31 @@ namespace WalletWasabi.Fluent.Behaviors
base.OnAttached();
}
+ private void OnTextInput(object? sender, TextInputEventArgs e)
+ {
+ _disableEntry = false;
+ var k = sender as AutoCompleteBox;
+
+ if (k is null)
+ {
+ return;
+ }
+ //
+ // var ki = k.SearchText ?? "";
+ // var kv = k.Text ?? "";
+ //
+ // if (Math.Abs(ki.Length - kv.Length) == 1)
+ // {
+ // ki = kv.Substring(0, ki.Length + 1);
+ // }
+
+ if (!Suggestions.Any(x => x.StartsWith(k.SearchText ?? "", true, CultureInfo.CurrentCulture)))
+ {
+ e.Handled = true;
+ _disableEntry = true;
+ }
+ }
+
private void OnDropDownClosed(object? sender, EventArgs e)
{
var currentText = AssociatedObject?.Text ?? "";
@@ -56,47 +107,79 @@ namespace WalletWasabi.Fluent.Behaviors
return;
}
- if (selItem is null || selItem.Length == 0) return;
+ if (selItem is null || selItem.Length == 0 || currentText != selItem) return;
- CommitTextAction?.Invoke(AssociatedObject?.Text?.Trim() ?? "");
+ CommitTextAction?.Invoke(currentText.Trim());
AssociatedObject?.ClearValue(AutoCompleteBox.SelectedItemProperty);
- Dispatcher.UIThread.Post(() =>
- {
- AssociatedObject?.ClearValue(AutoCompleteBox.TextProperty);
- });
+ Dispatcher.UIThread.Post(() => { AssociatedObject?.ClearValue(AutoCompleteBox.TextProperty); });
}
private void OnTextChanged(object? sender, EventArgs e)
{
- var currentText = AssociatedObject?.Text ?? "";
+ if (AssociatedObject is null)
+ {
+ return;
+ }
+
+ var currentText = AssociatedObject.Text ?? "";
+ var currentTextTrimmed = currentText.Trim();
- if (currentText.Length >= 1 && !string.IsNullOrEmpty(currentText.Trim()) && currentText.EndsWith(' '))
+ if (currentText.Length < 1 || string.IsNullOrEmpty(currentTextTrimmed) || !currentText.EndsWith(' ') ||
+ !Suggestions.Any(x => x.Equals(currentTextTrimmed,
+ StringComparison.InvariantCultureIgnoreCase)))
{
- CommitTextAction?.Invoke(AssociatedObject?.Text?.Trim() ?? "");
- Dispatcher.UIThread.Post(() => { AssociatedObject?.ClearValue(AutoCompleteBox.TextProperty); });
+ return;
}
+
+ CommitTextAction?.Invoke(currentTextTrimmed);
+ Dispatcher.UIThread.Post(() => { AssociatedObject?.ClearValue(AutoCompleteBox.TextProperty); });
}
+
private void OnKeyUp(object? sender, KeyEventArgs e)
{
- if (e.Key == Key.Back && (AssociatedObject?.Text?.Length == 0 || AssociatedObject?.Text is null))
+ if (AssociatedObject is null)
{
- BackspaceAndEmptyTextAction?.Invoke();
+ return;
}
- else if (e.Key == Key.Enter && !string.IsNullOrEmpty(AssociatedObject?.Text?.Trim() ?? ""))
+
+ var str = AssociatedObject?.Text ?? "";
+ var strTrimmed = str.Trim();
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
+ switch (e.Key)
{
- CommitTextAction?.Invoke(AssociatedObject?.Text?.Trim() ?? "");
+ case Key.Back when string.IsNullOrEmpty(str):
+ BackspaceAndEmptyTextAction?.Invoke();
+ break;
+ case Key.Enter when !string.IsNullOrEmpty(strTrimmed):
+
+ if (!Suggestions.Any(x => x.Equals(strTrimmed,StringComparison.InvariantCultureIgnoreCase)))
+ {
+ break;
+ }
+
+ CommitTextAction?.Invoke(strTrimmed);
Dispatcher.UIThread.Post(() => { AssociatedObject?.ClearValue(AutoCompleteBox.TextProperty); });
+ break;
}
}
protected override void OnDetaching()
{
+ if (AssociatedObject is null)
+ {
+ return;
+ }
+
base.OnDetaching();
+
AssociatedObject.DropDownClosed -= OnDropDownClosed;
AssociatedObject.KeyUp -= OnKeyUp;
AssociatedObject.TextChanged -= OnTextChanged;
+
+ _disposable?.Dispose();
}
}
}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/Views/RecoveryPageView.axaml
WalletWasabi.Fluent/Views/RecoveryPageView.axaml
<Panel Margin="25 0 25 20">
<Button Classes="invisible" Margin="0 35 0 0" Command="{Binding GoBackCommand}" DockPanel.Dock="Left"
HorizontalAlignment="Left" VerticalAlignment="Top">
- <PathIcon Data="{StaticResource arrow_left_regular}" />
+ <PathIcon Data="{DynamicResource arrow_left_regular}" />
</Button>
<c:ContentArea Title="Enter recovery words" Caption="Type in your 12 recovery words and click continue"
- Margin="44 0 44 0">
+ Margin="44 0">
<Grid RowDefinitions="Auto,30,Auto" VerticalAlignment="Top" >
<TextBlock Classes="h7 bold" Text="Type in your recovery words here:"/>
<c:TagBox Grid.Row="2"

MODIFY
WalletWasabi.Fluent/Views/TagsBox/TagInputView.xaml
WalletWasabi.Fluent/Views/TagsBox/TagInputView.xaml
<AutoCompleteBox x:DataType="vm:TagInputViewModel" IsTextCompletionEnabled="True" Items="{CompiledBinding Suggestions}">
<i:Interaction.Behaviors>
<behaviors:TagBoxAutoCompleteBoxBehavior
+ Suggestions="{CompiledBinding Suggestions}"
CommitTextAction="{CompiledBinding CommitTextAction}"
BackspaceAndEmptyTextAction="{CompiledBinding BackspaceAndEmptyTextAction}" />
</i:Interaction.Behaviors>

MODIFY
WalletWasabi.Fluent/Views/TagsBox/TagView.xaml
WalletWasabi.Fluent/Views/TagsBox/TagView.xaml
<Border BorderBrush="{DynamicResource TagBoxControlForeground}"
BorderThickness="1"
CornerRadius="4"
- Margin="4,0"
+ Margin="4"
VerticalAlignment="Center">
<TextBlock x:DataType="vm:TagViewModel"
Text="{CompiledBinding Tag}"

polish logic more and add function to disallow mistakes