Don't block in constructor
MODIFY
WalletWasabi.Gui/Tabs/LegalIssuesView.xaml
WalletWasabi.Gui/Tabs/LegalIssuesView.xaml
xmlns:controls="clr-namespace:WalletWasabi.Gui.Controls;assembly=WalletWasabi.Gui">
<controls:GroupBox Title="{Binding Title}" BorderThickness="0" Classes="docTabContainer">
<Grid Classes="content" Margin="10">
- <controls:ExtendedTextBox Text="{Binding LegalIssues}" Classes="selectableTextBlock" TextWrapping="Wrap" AcceptsReturn="True" />
+ <controls:ExtendedTextBox Text="{Binding Text}" Classes="selectableTextBlock" TextWrapping="Wrap" AcceptsReturn="True" />
</Grid>
</controls:GroupBox>
</UserControl>

MODIFY
WalletWasabi.Gui/Tabs/LegalIssuesViewModel.cs
WalletWasabi.Gui/Tabs/LegalIssuesViewModel.cs
@@ -6,20 +6,10 @@ using WalletWasabi.Gui.ViewModels;
namespace WalletWasabi.Gui.Tabs
{
- internal class LegalIssuesViewModel : WasabiDocumentTabViewModel
+ public class LegalIssuesViewModel : TextViewModelBase
{
- public string LegalIssues { get; }
-
- public LegalIssuesViewModel(Global global) : base(global, "Legal Issues")
- {
- var target = new Uri("resm:WalletWasabi.Gui.Assets.LegalIssues.txt");
- var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
-
- using (var stream = assetLocator.Open(target))
- using (var reader = new StreamReader(stream))
+ public LegalIssuesViewModel(Global global) : base(global, "Legal Issues", new Uri("resm:WalletWasabi.Gui.Assets.LegalIssues.txt"))
{
- LegalIssues = reader.ReadToEnd();
- }
}
}
}

MODIFY
WalletWasabi.Gui/Tabs/PrivacyPolicyView.xaml
WalletWasabi.Gui/Tabs/PrivacyPolicyView.xaml
xmlns:controls="clr-namespace:WalletWasabi.Gui.Controls;assembly=WalletWasabi.Gui">
<controls:GroupBox Title="{Binding Title}" BorderThickness="0" Classes="docTabContainer">
<Grid Classes="content" Margin="10">
- <controls:ExtendedTextBox Text="{Binding PrivacyPolicy}" Classes="selectableTextBlock" TextWrapping="Wrap" AcceptsReturn="True" />
+ <controls:ExtendedTextBox Text="{Binding Text}" Classes="selectableTextBlock" TextWrapping="Wrap" AcceptsReturn="True" />
</Grid>
</controls:GroupBox>
</UserControl>

MODIFY
WalletWasabi.Gui/Tabs/PrivacyPolicyViewModel.cs
WalletWasabi.Gui/Tabs/PrivacyPolicyViewModel.cs
@@ -6,20 +6,10 @@ using WalletWasabi.Gui.ViewModels;
namespace WalletWasabi.Gui.Tabs
{
- internal class PrivacyPolicyViewModel : WasabiDocumentTabViewModel
+ public class PrivacyPolicyViewModel : TextViewModelBase
{
- public string PrivacyPolicy { get; }
-
- public PrivacyPolicyViewModel(Global global) : base(global, "Privacy Policy")
- {
- var target = new Uri("resm:WalletWasabi.Gui.Assets.PrivacyPolicy.txt");
- var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
-
- using (var stream = assetLocator.Open(target))
- using (var reader = new StreamReader(stream))
+ public PrivacyPolicyViewModel(Global global) : base(global, "Privacy Policy", new Uri("resm:WalletWasabi.Gui.Assets.PrivacyPolicy.txt"))
{
- PrivacyPolicy = reader.ReadToEnd();
- }
}
}
}

MODIFY
WalletWasabi.Gui/Tabs/TermsAndConditionsView.xaml
WalletWasabi.Gui/Tabs/TermsAndConditionsView.xaml
xmlns:controls="clr-namespace:WalletWasabi.Gui.Controls;assembly=WalletWasabi.Gui">
<controls:GroupBox Title="{Binding Title}" BorderThickness="0" Classes="docTabContainer">
<Grid Classes="content" Margin="10">
- <controls:ExtendedTextBox Text="{Binding TermsAndConditions}" Classes="selectableTextBlock" TextWrapping="Wrap" AcceptsReturn="True" />
+ <controls:ExtendedTextBox Text="{Binding Text}" Classes="selectableTextBlock" TextWrapping="Wrap" AcceptsReturn="True" />
</Grid>
</controls:GroupBox>
</UserControl>

MODIFY
WalletWasabi.Gui/Tabs/TermsAndConditionsViewModel.cs
WalletWasabi.Gui/Tabs/TermsAndConditionsViewModel.cs
@@ -3,23 +3,19 @@ using System.IO;
using Avalonia;
using Avalonia.Platform;
using WalletWasabi.Gui.ViewModels;
+using ReactiveUI;
+using System.Threading.Tasks;
+using System.Linq.Expressions;
+using System.Reactive.Linq;
+using System.Reactive.Threading.Tasks;
+using System.Reactive.Disposables;
namespace WalletWasabi.Gui.Tabs
{
- internal class TermsAndConditionsViewModel : WasabiDocumentTabViewModel
+ public class TermsAndConditionsViewModel : TextViewModelBase
{
- public string TermsAndConditions { get; }
-
- public TermsAndConditionsViewModel(Global global) : base(global, "Terms and Conditions")
- {
- var target = new Uri("resm:WalletWasabi.Gui.Assets.TermsAndConditions.txt");
- var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
-
- using (var stream = assetLocator.Open(target))
- using (var reader = new StreamReader(stream))
+ public TermsAndConditionsViewModel(Global global) : base(global, "Terms and Conditions", new Uri("resm:WalletWasabi.Gui.Assets.TermsAndConditions.txt"))
{
- TermsAndConditions = reader.ReadToEnd();
- }
}
}
}

ADD
WalletWasabi.Gui/Tabs/TextViewModelBase.cs
+using Avalonia;
+using Avalonia.Platform;
+using ReactiveUI;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+using System.Reactive.Threading.Tasks;
+using System.Text;
+using System.Threading.Tasks;
+using WalletWasabi.Gui.ViewModels;
+
+namespace WalletWasabi.Gui.Tabs
+{
+ public abstract class TextViewModelBase : WasabiDocumentTabViewModel
+ {
+ protected CompositeDisposable Disposables { get; private set; } = new CompositeDisposable();
+
+ public string _text;
+
+ public TextViewModelBase(Global global, string title, Uri target) : base(global, title)
+ {
+ Text = "";
+
+ LoadDocumentAsync(target)
+ .ToObservable()
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(x => Text = x)
+ .DisposeWith(Disposables);
+ }
+
+ public string Text
+ {
+ get => _text;
+ set => this.RaiseAndSetIfChanged(ref _text, value);
+ }
+
+ private async Task<string> LoadDocumentAsync(Uri target)
+ {
+ var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
+
+ using (var stream = assetLocator.Open(target))
+ using (var reader = new StreamReader(stream))
+ {
+ return await reader.ReadToEndAsync();
+ }
+ }
+
+ public override bool OnClose()
+ {
+ Disposables?.Dispose();
+ Disposables = null;
+ return base.OnClose();
+ }
+ }
+}

Don't block in constructor