Add new view model for Qr
ADD
WalletWasabi.Fluent/ViewModels/Dialogs/ShowQrCameraDialogViewModel.cs
+using Avalonia.Media.Imaging;
+using NBitcoin;
+using ReactiveUI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reactive.Concurrency;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using WalletWasabi.Fluent.Models;
+using WalletWasabi.Fluent.ViewModels.Dialogs.Base;
+using WalletWasabi.Fluent.Views.Dialogs;
+
+namespace WalletWasabi.Fluent.ViewModels.Dialogs
+{
+ [NavigationMetaData(Title = "QrCamera")]
+ public partial class ShowQrCameraDialogViewModel : DialogViewModelBase<string?>
+ {
+ [AutoNotify] private WriteableBitmap? _qrImage;
+ [AutoNotify] private bool _isQrPanelVisible;
+ [AutoNotify] private bool _isCameraLoadingAnimationVisible;
+
+ private WebcamQrReader _qrReader;
+
+ public ShowQrCameraDialogViewModel(Network network)
+ {
+ _qrReader = new(network);
+ _isQrPanelVisible = false;
+ _isCameraLoadingAnimationVisible = false;
+
+ SetupCancel(enableCancel: true, enableCancelOnEscape: true, enableCancelOnPressed: true);
+
+ Observable.FromEventPattern<WriteableBitmap>(_qrReader, nameof(_qrReader.NewImageArrived))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(args =>
+ {
+ if (IsCameraLoadingAnimationVisible == true)
+ {
+ IsCameraLoadingAnimationVisible = false;
+ }
+
+ if (QrImage == null)
+ {
+ QrImage = args.EventArgs;
+ }
+ else
+ {
+ ShowQrCameraDialogView.QrImage?.InvalidateVisual();
+ }
+ });
+
+ Observable.FromEventPattern<string>(_qrReader, nameof(_qrReader.CorrectAddressFound))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(async args =>
+ {
+ Close(DialogResultKind.Normal, args.EventArgs);
+ await _qrReader.StopScanningAsync();
+ IsQrPanelVisible = false;
+ });
+
+ Observable.FromEventPattern<string>(_qrReader, nameof(_qrReader.InvalidAddressFound))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(args => Close(DialogResultKind.Normal, args.EventArgs));
+
+ Observable.FromEventPattern<Exception>(_qrReader, nameof(_qrReader.ErrorOccured))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(async args =>
+ {
+ IsCameraLoadingAnimationVisible = false;
+ IsQrPanelVisible = false;
+ Close();
+ await _qrReader.StopScanningAsync();
+ await ShowErrorAsync(Title, args.EventArgs.Message, "Something went wrong");
+ });
+ }
+
+ protected override void OnNavigatedFrom(bool isInHistory)
+ {
+ base.OnNavigatedFrom(isInHistory);
+
+ RxApp.MainThreadScheduler.Schedule(async () => await _qrReader.StopScanningAsync());
+ }
+
+ protected override void OnNavigatedTo(bool isInHistory, CompositeDisposable disposables)
+ {
+ base.OnNavigatedTo(isInHistory, disposables);
+ RxApp.MainThreadScheduler.Schedule(async () => await _qrReader.StartScanningAsync());
+ }
+ }
+}

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/SendViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/SendViewModel.cs
@@ -29,6 +29,7 @@ using WalletWasabi.WebClients.PayJoin;
using Constants = WalletWasabi.Helpers.Constants;
using WalletWasabi.Fluent.Helpers;
using WalletWasabi.Fluent.Views.Wallets.Send;
+using WalletWasabi.Fluent.ViewModels.Dialogs;
namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
{
@@ -51,11 +52,7 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
[AutoNotify] private ObservableCollection<string> _labels;
[AutoNotify] private bool _isPayJoin;
[AutoNotify] private string? _payJoinEndPoint;
- [AutoNotify] private WriteableBitmap? _qrImage;
- [AutoNotify] private bool _isQrPanelVisible;
- [AutoNotify] private bool _isCameraLoadingAnimationVisible;
- private WebcamQrReader _qrReader;
private bool _parsingUrl;
public SendViewModel(Wallet wallet)
@@ -64,54 +61,9 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
_wallet = wallet;
_transactionInfo = new TransactionInfo();
_labels = new ObservableCollection<string>();
- _isQrPanelVisible = false;
- _isCameraLoadingAnimationVisible = false;
- _qrReader = new(_wallet.Network);
ExchangeRate = _wallet.Synchronizer.UsdExchangeRate;
PriorLabels = new();
- Observable.FromEventPattern<WriteableBitmap>(_qrReader, nameof(_qrReader.NewImageArrived))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(args =>
- {
- if (IsCameraLoadingAnimationVisible == true)
- {
- IsCameraLoadingAnimationVisible = false;
- }
-
- if (QrImage == null)
- {
- QrImage = args.EventArgs;
- }
- else
- {
- SendView.QrImage?.InvalidateVisual();
- }
- });
-
- Observable.FromEventPattern<string>(_qrReader, nameof(_qrReader.CorrectAddressFound))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(async args =>
- {
- To = args.EventArgs;
- await _qrReader.StopScanningAsync();
- IsQrPanelVisible = false;
- });
-
- Observable.FromEventPattern<string>(_qrReader, nameof(_qrReader.InvalidAddressFound))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(args => To = args.EventArgs);
-
- Observable.FromEventPattern<Exception>(_qrReader, nameof(_qrReader.ErrorOccured))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(async args =>
- {
- IsCameraLoadingAnimationVisible = false;
- IsQrPanelVisible = false;
- await _qrReader.StopScanningAsync();
- await ShowErrorAsync(Title, args.EventArgs.Message, "Something went wrong");
- });
-
this.ValidateProperty(x => x.To, ValidateToField);
this.ValidateProperty(x => x.AmountBtc, ValidateAmount);
@@ -144,11 +96,11 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
AutoPasteCommand = ReactiveCommand.CreateFromTask(async () => await OnAutoPasteAsync());
QRCommand = ReactiveCommand.Create(async () =>
{
- if (!_qrReader.IsRunning)
+ ShowQrCameraDialogViewModel dialog = new(_wallet.Network);
+ var result = await NavigateDialogAsync(dialog);
+ if (!string.IsNullOrWhiteSpace(result.Result))
{
- IsCameraLoadingAnimationVisible = true;
- IsQrPanelVisible = true;
- await _qrReader.StartScanningAsync();
+ To = result.Result;
}
});
@@ -355,19 +307,6 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
base.OnNavigatedTo(inHistory, disposables);
}
- protected override void OnNavigatedFrom(bool isInHistory)
- {
- try
- {
- RxApp.MainThreadScheduler.Schedule(async () => await _qrReader.StopScanningAsync());
- base.OnNavigatedFrom(isInHistory);
- }
- catch (Exception exc)
- {
- Logger.LogError(exc);
- }
- }
-
private void UpdateSuggestedLabels()
{
var enteredLabels = Labels;

ADD
WalletWasabi.Fluent/Views/Dialogs/ShowQrCameraDialogView.axaml
+<UserControl xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:c="using:WalletWasabi.Fluent.Controls"
+ xmlns:dialog="using:WalletWasabi.Fluent.ViewModels.Dialogs"
+ mc:Ignorable="d" d:DesignWidth="428" d:DesignHeight="371"
+ x:DataType="dialog:ShowQrCameraDialogViewModel"
+ x:CompileBindings="True"
+ x:Class="WalletWasabi.Fluent.Views.Dialogs.ShowQrCameraDialogView">
+ <c:ContentArea EnableNext="False"
+ ScrollViewer.VerticalScrollBarVisibility="Disabled">
+ <!-- QR Camera -->
+ <Panel>
+ <c:ProgressRing IsIndeterminate="True" IsVisible="{Binding QrImage,Converter={x:Static ObjectConverters.IsNull}}" />
+ <Image Source="{Binding QrImage}" Width="275" Height="275" IsVisible="{Binding QrImage,Converter={x:Static ObjectConverters.IsNotNull}}" />
+ </Panel>
+ </c:ContentArea>
+</UserControl>

ADD
WalletWasabi.Fluent/Views/Dialogs/ShowQrCameraDialogView.axaml.cs
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace WalletWasabi.Fluent.Views.Dialogs
+{
+ public class ShowQrCameraDialogView : UserControl
+ {
+ // NASTY HACK! DO NOT USE IN PRODUCTION. kiminuo
+ public static volatile Image? QrImage;
+
+ public ShowQrCameraDialogView()
+ {
+ InitializeComponent();
+ QrImage = this.FindControl<Image>("qrImage");
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}

MODIFY
WalletWasabi.Fluent/Views/Wallets/Send/SendView.axaml
WalletWasabi.Fluent/Views/Wallets/Send/SendView.axaml
</TextBox.InnerRightContent>
</TextBox>
</DockPanel>
- <!-- QR Camera -->
- <DockPanel DockPanel.Dock="Top" Margin="0,0,0,6" IsVisible="{Binding IsQrPanelVisible}">
- <Label DockPanel.Dock="Left" Content="_QR Camera:" Target="qrcamera" />
- <Label DockPanel.Dock="Left" IsVisible="{Binding IsCameraLoadingAnimationVisible}" Content="_Loading camera..." Opacity="0.6"></Label>
- <Image Source="{Binding QrImage}" Width="275" Height="275" Name="qrImage" />
- </DockPanel>
<!-- Amount -->
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,10">
<Label DockPanel.Dock="Left" Content="_Amount:" Target="amountTb" />

MODIFY
WalletWasabi.Fluent/Views/Wallets/Send/SendView.axaml.cs
WalletWasabi.Fluent/Views/Wallets/Send/SendView.axaml.cs
@@ -5,13 +5,9 @@ namespace WalletWasabi.Fluent.Views.Wallets.Send
{
public class SendView : UserControl
{
- // NASTY HACK! DO NOT USE IN PRODUCTION. kiminuo
- public static volatile Image? QrImage;
-
public SendView()
{
InitializeComponent();
- QrImage = this.FindControl<Image>("qrImage");
}
private void InitializeComponent()

Add new view model for Qr