Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more parameters to the settings page #1538

Merged
merged 10 commits into from
Jun 11, 2019
117 changes: 77 additions & 40 deletions WalletWasabi.Gui/Tabs/SettingsView.xaml
Original file line number Diff line number Diff line change
@@ -1,54 +1,91 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:controls="clr-namespace:WalletWasabi.Gui.Controls;assembly=WalletWasabi.Gui">
<ScrollViewer>
<StackPanel Margin="30" Spacing="10">
<Grid Classes="content">
<StackPanel Orientation="Vertical" Spacing="30">
<StackPanel IsVisible="{Binding IsModified}" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="Heads Up!" FontWeight="Bold" Classes="warningMessage" Margin="0 0 3 0" />
<TextBlock Classes="warningMessage">Changes will be applied after restarting the application.</TextBlock>
</StackPanel>

<controls:GroupBox Title="Bitcoin" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Margin="0 10">
<TextBlock>Network</TextBlock>
<DropDown Items="{Binding Networks}" SelectedItem="{Binding Network}" />
<StackPanel Margin="30" Spacing="10">
<Grid Classes="content">
<StackPanel Orientation="Vertical" Spacing="30">
<StackPanel IsVisible="{Binding IsModified}" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="Heads Up!" FontWeight="Bold" Classes="warningMessage" Margin="0 0 3 0" />
<TextBlock Classes="warningMessage">Changes will be applied after restarting the application.</TextBlock>
</StackPanel>
</controls:GroupBox>

<controls:GroupBox Title="Tor" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Orientation="Vertical">
<StackPanel Margin="0 10" Orientation="Horizontal">
<ToggleButton IsChecked="{Binding UseTor}" Content="{Binding UseTorText}" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center">Tor can be turned off for debugging.</TextBlock>
<controls:GroupBox Title="Bitcoin" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Orientation="Vertical" Spacing="5">
<StackPanel Margin="0 10" Spacing="5">
<TextBlock>Network</TextBlock>
<DropDown Items="{Binding Networks}" SelectedItem="{Binding Network}" />
</StackPanel>
</StackPanel>
<StackPanel Margin="0 10">
<TextBlock>Host</TextBlock>
<TextBox Text="{Binding TorHost}" />
</controls:GroupBox>

<controls:GroupBox Title="Tor" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Orientation="Vertical" Spacing="5">
<StackPanel Margin="0 10" Orientation="Horizontal" Spacing="5">
<ToggleButton IsChecked="{Binding UseTor}" Content="{Binding UseTorText}" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center">Tor can be turned off for debugging.</TextBlock>
</StackPanel>
<StackPanel Margin="0 10" Spacing="5">
<TextBlock>Host</TextBlock>
<TextBox Text="{Binding TorHost}" />
</StackPanel>
<StackPanel Spacing="5">
<TextBlock>Port</TextBlock>
<TextBox Text="{Binding TorPort}" />
</StackPanel>
</StackPanel>
<StackPanel>
<TextBlock>Port</TextBlock>
<TextBox Text="{Binding TorPort}" />
</controls:GroupBox>

<controls:GroupBox Title="UI" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Orientation="Vertical" Spacing="5">
<StackPanel Margin="0 10" Orientation="Horizontal" Spacing="5">
<ToggleButton IsChecked="{Binding Autocopy}" Content="{Binding AutocopyText}" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center">Autocopy on Receive and History wallet tabs.</TextBlock>
</StackPanel>
<StackPanel Margin="0 10" Orientation="Horizontal" Spacing="5">
<ToggleButton IsChecked="{Binding LurkingWifeMode}" Content="{Binding LurkingWifeModeText}" Margin="0 0 10 0" Command="{Binding LurkingWifeModeCommand}" />
<TextBlock VerticalAlignment="Center">Lurking Wife Mode hides sensitive content.</TextBlock>
</StackPanel>
</StackPanel>
</StackPanel>
</controls:GroupBox>
</controls:GroupBox>

<controls:GroupBox Title="UI" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Spacing="10" Orientation="Vertical">
<StackPanel Margin="0 10" Orientation="Horizontal">
<ToggleButton IsChecked="{Binding Autocopy}" Content="{Binding AutocopyText}" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center">Autocopy on Receive and History wallet tabs.</TextBlock>
<controls:GroupBox Title="Anonymity" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Orientation="Vertical" Spacing="5">
<Grid Margin="0 10" ColumnDefinitions="30, *">
<DrawingPresenter Height="24" Width="24" Grid.Column="0"
Margin="0 0 10 10"
VerticalAlignment="Center" HorizontalAlignment="Center"
Drawing="{DynamicResource PrivacySome}" />
<TextBox Text="{Binding SomePrivacyLevel}" Grid.Column="1" />
</Grid>
<Grid Margin="0 10" ColumnDefinitions="30, *">
<DrawingPresenter Height="24" Width="24" Grid.Column="0"
Margin="0 0 10 10"
VerticalAlignment="Center" HorizontalAlignment="Center"
Drawing="{DynamicResource PrivacyFine}" />
<TextBox Text="{Binding FinePrivacyLevel}" Grid.Column="1" />
</Grid>
<Grid Margin="0 10" ColumnDefinitions="30, *">
<DrawingPresenter Height="24" Width="24" Grid.Column="0"
Margin="0 0 10 10"
VerticalAlignment="Center" HorizontalAlignment="Center"
Drawing="{DynamicResource PrivacyStrong}" />
<TextBox Text="{Binding StrongPrivacyLevel}" Grid.Column="1" />
</Grid>
</StackPanel>
<StackPanel Margin="0 10" Orientation="Horizontal">
<ToggleButton IsChecked="{Binding LurkingWifeMode}" Content="{Binding LurkingWifeModeText}" Margin="0 0 10 0" Command="{Binding LurkingWifeModeCommand}" />
<TextBlock VerticalAlignment="Center">Lurking Wife Mode hides sensitive content.</TextBlock>
</controls:GroupBox>

<controls:GroupBox Title="Other settings" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Orientation="Vertical" Spacing="5">
<StackPanel Margin="0 10" Spacing="5">
<TextBlock ToolTip.Tip="Under the dust threshold coins aren't appearing in the coin lists.">Dust Threshold (BTC)</TextBlock>
<TextBox Text="{Binding DustThreshold}" />
</StackPanel>
</StackPanel>
</StackPanel>
</controls:GroupBox>
</controls:GroupBox>

<Button Content="Open Config File" Command="{Binding OpenConfigFileCommand}" />
</StackPanel>
</Grid>
</StackPanel>
<Button Content="Open Config File" Command="{Binding OpenConfigFileCommand}" />
</StackPanel>
</Grid>
</StackPanel>
</ScrollViewer>
</UserControl>
115 changes: 111 additions & 4 deletions WalletWasabi.Gui/Tabs/SettingsViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Avalonia.Threading;
using NBitcoin;
using ReactiveUI;
using System;
using System.Collections.Generic;
Expand All @@ -7,6 +8,8 @@
using System.Net.Sockets;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text.RegularExpressions;
using WalletWasabi.Gui.ViewModels;
using WalletWasabi.Gui.ViewModels.Validation;

Expand All @@ -25,6 +28,11 @@ internal class SettingsViewModel : WasabiDocumentTabViewModel
private string _useTorText;
private bool _isModified;

private string _somePrivacyLevel;
private string _finePrivacyLevel;
private string _strongPrivacyLevel;
private string _dustThreshold;

public ReactiveCommand<Unit, Unit> OpenConfigFileCommand { get; }
public ReactiveCommand<Unit, Unit> LurkingWifeModeCommand { get; }

Expand All @@ -33,7 +41,14 @@ public SettingsViewModel() : base("Settings")
var config = new Config(Global.Config.FilePath);
Autocopy = Global.UiConfig?.Autocopy is true;

this.WhenAnyValue(x => x.Network, x => x.TorHost, x => x.TorPort, x => x.UseTor).Subscribe(x => Save());
this.WhenAnyValue(x => x.Network,
x => x.TorHost, x => x.TorPort, x => x.UseTor)
.Subscribe(x => Save());

this.WhenAnyValue(
x => x.SomePrivacyLevel, x => x.FinePrivacyLevel, x => x.StrongPrivacyLevel,
x => x.DustThreshold)
.Subscribe(x => Save());

this.WhenAnyValue(x => x.Autocopy).Subscribe(x =>
{
Expand All @@ -60,6 +75,12 @@ public SettingsViewModel() : base("Settings")
TorPort = config.TorSocks5Port.ToString();
UseTor = config.UseTor.Value;

SomePrivacyLevel = config.PrivacyLevelSome.ToString();
FinePrivacyLevel = config.PrivacyLevelFine.ToString();
StrongPrivacyLevel = config.PrivacyLevelStrong.ToString();

DustThreshold = config.DustThreshold.ToString();

IsModified = await Global.Config.CheckFileChangeAsync();
});

Expand Down Expand Up @@ -155,6 +176,34 @@ public string UseTorText
set => this.RaiseAndSetIfChanged(ref _useTorText, value);
}

[ValidateMethod(nameof(ValidateSomePrivacyLevel))]
public string SomePrivacyLevel
{
get => _somePrivacyLevel;
set => this.RaiseAndSetIfChanged(ref _somePrivacyLevel, value);
}

[ValidateMethod(nameof(ValidateFinePrivacyLevel))]
public string FinePrivacyLevel
{
get => _finePrivacyLevel;
set => this.RaiseAndSetIfChanged(ref _finePrivacyLevel, value);
}

[ValidateMethod(nameof(ValidateStrongPrivacyLevel))]
public string StrongPrivacyLevel
{
get => _strongPrivacyLevel;
set => this.RaiseAndSetIfChanged(ref _strongPrivacyLevel, value);
}

[ValidateMethod(nameof(ValidateDustThreshold))]
public string DustThreshold
{
get => _dustThreshold;
set => this.RaiseAndSetIfChanged(ref _dustThreshold, value);
}

public bool LurkingWifeMode => Global.UiConfig.LurkingWifeMode is true;

public string LurkingWifeModeText => Global.UiConfig.LurkingWifeMode is true ? "On" : "Off";
Expand All @@ -168,7 +217,11 @@ private void Save()
return;
}

if (string.IsNullOrWhiteSpace(Network))
if (string.IsNullOrWhiteSpace(Network)
|| string.IsNullOrWhiteSpace(SomePrivacyLevel)
|| string.IsNullOrWhiteSpace(FinePrivacyLevel)
|| string.IsNullOrWhiteSpace(StrongPrivacyLevel)
|| string.IsNullOrWhiteSpace(DustThreshold))
{
return;
}
Expand All @@ -183,13 +236,28 @@ private void Save()
var torHost = TorHost;
var torSocks5Port = int.TryParse(TorPort, out var port) ? (int?)port : null;
var useTor = UseTor;

if (config.Network != network || config.TorHost != torHost || config.TorSocks5Port != torSocks5Port || config.UseTor != useTor)
var somePrivacyLevel = int.TryParse(SomePrivacyLevel, out int level) ? (int?)level : null;
var finePrivacyLevel = int.TryParse(FinePrivacyLevel, out level) ? (int?)level : null;
var strongPrivacyLevel = int.TryParse(StrongPrivacyLevel, out level) ? (int?)level : null;
var dustThreshold = decimal.TryParse(DustThreshold, out var threshold) ? (decimal?)threshold : null;

if (config.Network != network
|| config.TorHost != torHost
|| config.TorSocks5Port != torSocks5Port
|| config.UseTor != useTor
|| config.PrivacyLevelSome != somePrivacyLevel
|| config.PrivacyLevelFine != finePrivacyLevel
|| config.PrivacyLevelStrong != strongPrivacyLevel
|| config.DustThreshold.ToUnit(MoneyUnit.BTC) != dustThreshold)
{
config.Network = network;
config.TorHost = torHost;
config.TorSocks5Port = torSocks5Port;
config.UseTor = useTor;
config.PrivacyLevelSome = somePrivacyLevel;
config.PrivacyLevelFine = finePrivacyLevel;
config.PrivacyLevelStrong = strongPrivacyLevel;
config.DustThreshold = Money.Coins(dustThreshold.Value);

await config.ToFileAsync();

Expand Down Expand Up @@ -238,6 +306,45 @@ public string ValidateTorPort()
return "Invalid port.";
}

public string ValidateSomePrivacyLevel()
=> ValidatePrivacyLevel(SomePrivacyLevel);

public string ValidateFinePrivacyLevel()
=> ValidatePrivacyLevel(FinePrivacyLevel);

public string ValidateStrongPrivacyLevel()
=> ValidatePrivacyLevel(StrongPrivacyLevel);

public string ValidatePrivacyLevel(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}

if (uint.TryParse(value, out _))
{
return string.Empty;
}

return "Invalid privacy level.";
}

public string ValidateDustThreshold()
{
if (string.IsNullOrWhiteSpace(DustThreshold))
{
return string.Empty;
}

if (decimal.TryParse(DustThreshold, out _))
{
return string.Empty;
}

return "Invalid dust amount.";
}

private void OpenConfigFile()
{
IoHelpers.OpenFileInTextEditor(Global.Config.FilePath);
Expand Down