ViewModel validation methods take IErrorList and dont need to know about ErrorDescriptors.
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
@@ -469,6 +469,6 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
base.OnDeselected();
}
- public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public void ValidatePassword(IErrorList errors) => PasswordHelper.ValidatePassword(errors, Password);
}
}

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendControlViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/SendControlViewModel.cs
@@ -873,54 +873,67 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
&& userFee > 0;
}
- public ErrorDescriptors ValidateUserFeeText()
+ public void ValidateUserFeeText(IErrorList errors)
{
- return TryParseUserFee(out _)
- ? ErrorDescriptors.Empty
- : new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Error, "Invalid fee."));
+ if (!TryParseUserFee(out _))
+ {
+ errors.Add(ErrorSeverity.Error, "Invalid fee.");
+ }
}
- public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public void ValidatePassword(IErrorList errors) => PasswordHelper.ValidatePassword(errors, Password);
+
+ public void ValidateActiveAddress(IErrorList errors)
+ {
+ if (string.IsNullOrWhiteSpace(Address))
+ {
+ return;
+ }
- public void ValidateActiveAddress(AddErrorDelegate addError)
+ if (!string.IsNullOrWhiteSpace(CustomChangeAddress))
{
if (Address == CustomChangeAddress)
{
- addError(ErrorSeverity.Error, "The active address and the change address cannot be the same.");
+ errors.Add(ErrorSeverity.Error, "The active address and the change address cannot be the same.");
+ }
+ }
+
+ if (AddressStringParser.TryParseBitcoinAddress(Address, Global.Network, out _))
+ {
return;
}
- if (!AddressStringParser.TryParseBitcoinAddress(Address, Global.Network, out _) ||
- !AddressStringParser.TryParseBitcoinUrl(Address, Global.Network, out _))
+ if (AddressStringParser.TryParseBitcoinUrl(Address, Global.Network, out _))
{
- addError(ErrorSeverity.Error, "Invalid address.");
return;
}
+
+ errors.Add(ErrorSeverity.Error, "Invalid address.");
}
- public ErrorDescriptors ValidateCustomChangeAddress()
+ public void ValidateCustomChangeAddress(IErrorList errors)
{
if (string.IsNullOrWhiteSpace(CustomChangeAddress))
{
- return ErrorDescriptors.Empty;
+ return;
}
if (IsMax)
{
- return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Error, "Spending whole coins does not generate change."));
+ errors.Add(ErrorSeverity.Error, "Spending whole coins does not generate change.");
}
if (Address == CustomChangeAddress)
{
- return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Error, "The active address and the change address cannot be the same."));
+ errors.Add(ErrorSeverity.Error, "The active address and the change address cannot be the same.");
}
if (AddressStringParser.TryParseBitcoinAddress(CustomChangeAddress, Global.Network, out _))
{
- return ErrorDescriptors.Empty;
+ return;
}
- return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Error, "Invalid change address."));
+ errors.Add(ErrorSeverity.Error, "Invalid change address.");
}
public override void OnOpen(CompositeDisposable disposables)

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/WalletInfoViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/WalletInfoViewModel.cs
@@ -119,7 +119,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
set => this.RaiseAndSetIfChanged(ref _extendedAccountZprv, value);
}
- public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public void ValidatePassword(IErrorList errors) => PasswordHelper.ValidatePassword(errors, Password);
private void ClearSensitiveData(bool passwordToo)
{

MODIFY
WalletWasabi.Gui/Tabs/SettingsViewModel.cs
WalletWasabi.Gui/Tabs/SettingsViewModel.cs
@@ -330,13 +330,8 @@ namespace WalletWasabi.Gui.Tabs
return;
}
- var isValid =
- !ValidatePrivacyLevel(SomePrivacyLevel, whiteSpaceOk: false).HasErrors
- && !ValidatePrivacyLevel(FinePrivacyLevel, whiteSpaceOk: false).HasErrors
- && !ValidatePrivacyLevel(StrongPrivacyLevel, whiteSpaceOk: false).HasErrors
- && !ValidateDustThreshold(DustThreshold, whiteSpaceOk: false).HasErrors
- && !ValidateEndPoint(TorSocks5EndPoint, Constants.DefaultTorSocksPort, whiteSpaceOk: false).HasErrors
- && !ValidateEndPoint(BitcoinP2pEndPoint, network.DefaultPort, whiteSpaceOk: false).HasErrors;
+ Validate();
+ var isValid = !HasErrors;
if (!isValid)
{
@@ -387,72 +382,60 @@ namespace WalletWasabi.Gui.Tabs
#region Validation
- public ErrorDescriptors ValidateSomePrivacyLevel()
- => ValidatePrivacyLevel(SomePrivacyLevel, whiteSpaceOk: true);
+ public void ValidateSomePrivacyLevel(IErrorList errors)
+ => ValidatePrivacyLevel(errors, SomePrivacyLevel, whiteSpaceOk: true);
- public ErrorDescriptors ValidateFinePrivacyLevel()
- => ValidatePrivacyLevel(FinePrivacyLevel, whiteSpaceOk: true);
+ public void ValidateFinePrivacyLevel(IErrorList errors)
+ => ValidatePrivacyLevel(errors, FinePrivacyLevel, whiteSpaceOk: true);
- public ErrorDescriptors ValidateStrongPrivacyLevel()
- => ValidatePrivacyLevel(StrongPrivacyLevel, whiteSpaceOk: true);
+ public void ValidateStrongPrivacyLevel(IErrorList errors)
+ => ValidatePrivacyLevel(errors, StrongPrivacyLevel, whiteSpaceOk: true);
- public ErrorDescriptors ValidateDustThreshold()
- => ValidateDustThreshold(DustThreshold, whiteSpaceOk: true);
+ public void ValidateDustThreshold(IErrorList errors)
+ => ValidateDustThreshold(errors, DustThreshold, whiteSpaceOk: true);
- public ErrorDescriptors ValidateTorSocks5EndPoint()
- => ValidateEndPoint(TorSocks5EndPoint, Constants.DefaultTorSocksPort, whiteSpaceOk: true);
+ public void ValidateTorSocks5EndPoint(IErrorList errors)
+ => ValidateEndPoint(errors, TorSocks5EndPoint, Constants.DefaultTorSocksPort, whiteSpaceOk: true);
- public ErrorDescriptors ValidateBitcoinP2pEndPoint()
- => ValidateEndPoint(BitcoinP2pEndPoint, Network.DefaultPort, whiteSpaceOk: true);
+ public void ValidateBitcoinP2pEndPoint(IErrorList errors)
+ => ValidateEndPoint(errors, BitcoinP2pEndPoint, Network.DefaultPort, whiteSpaceOk: true);
- public ErrorDescriptors ValidatePrivacyLevel(string value, bool whiteSpaceOk)
+ public void ValidatePrivacyLevel(IErrorList errors, string value, bool whiteSpaceOk)
{
- if (whiteSpaceOk && string.IsNullOrWhiteSpace(value))
+ if (!whiteSpaceOk || !string.IsNullOrWhiteSpace(value))
{
- return ErrorDescriptors.Empty;
- }
-
- if (uint.TryParse(value, out _))
+ if (!uint.TryParse(value, out _))
{
- return ErrorDescriptors.Empty;
+ errors.Add(ErrorSeverity.Error, "Invalid privacy level.");
+ }
}
-
- return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Error, "Invalid privacy level."));
}
- public ErrorDescriptors ValidateDustThreshold(string dustThreshold, bool whiteSpaceOk)
+ public void ValidateDustThreshold(IErrorList errors, string dustThreshold, bool whiteSpaceOk)
{
- if (whiteSpaceOk && string.IsNullOrWhiteSpace(dustThreshold))
+ if (!whiteSpaceOk || !string.IsNullOrWhiteSpace(dustThreshold))
{
- return ErrorDescriptors.Empty;
- }
-
if (!string.IsNullOrEmpty(dustThreshold) && dustThreshold.Contains(',', StringComparison.InvariantCultureIgnoreCase))
{
- return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Error, "Use decimal point instead of comma."));
+ errors.Add(ErrorSeverity.Error, "Use decimal point instead of comma.");
}
- if (decimal.TryParse(dustThreshold, out var dust) && dust >= 0)
+ if (!decimal.TryParse(dustThreshold, out var dust) || dust < 0)
{
- return ErrorDescriptors.Empty;
+ errors.Add(ErrorSeverity.Error, "Invalid dust threshold.");
+ }
}
-
- return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Error, "Invalid dust threshold."));
}
- public ErrorDescriptors ValidateEndPoint(string endPoint, int defaultPort, bool whiteSpaceOk)
+ public void ValidateEndPoint(IErrorList errors, string endPoint, int defaultPort, bool whiteSpaceOk)
{
- if (whiteSpaceOk && string.IsNullOrWhiteSpace(endPoint))
+ if (!whiteSpaceOk || !string.IsNullOrWhiteSpace(endPoint))
{
- return ErrorDescriptors.Empty;
- }
-
- if (EndPointParser.TryParse(endPoint, defaultPort, out _))
+ if (!EndPointParser.TryParse(endPoint, defaultPort, out _))
{
- return ErrorDescriptors.Empty;
+ errors.Add(ErrorSeverity.Error, "Invalid endpoint.");
+ }
}
-
- return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Error, "Invalid endpoint."));
}
#endregion Validation

MODIFY
WalletWasabi.Gui/Tabs/WalletManager/GenerateWallets/GenerateWalletViewModel.cs
WalletWasabi.Gui/Tabs/WalletManager/GenerateWallets/GenerateWalletViewModel.cs
@@ -26,9 +26,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager.GenerateWallets
Global = Locator.Current.GetService<Global>();
Owner = owner;
- IObservable<bool> canGenerate = this.WhenAnyValue(x => x.Password).Select(pw => !ValidatePassword().HasErrors);
-
- NextCommand = ReactiveCommand.Create(DoNextCommand, canGenerate);
+ NextCommand = ReactiveCommand.Create(DoNextCommand, this.WhenAnyValue(x=>x.HasErrors).Select(x=> !x));
NextCommand.ThrownExceptions
.ObserveOn(RxApp.TaskpoolScheduler)
@@ -70,23 +68,19 @@ namespace WalletWasabi.Gui.Tabs.WalletManager.GenerateWallets
}
}
- public ErrorDescriptors ValidatePassword()
+ public void ValidatePassword(IErrorList errors)
{
string password = Password;
- var errors = new ErrorDescriptors();
-
if (PasswordHelper.IsTrimable(password, out _))
{
- errors.Add(new ErrorDescriptor(ErrorSeverity.Error, "Leading and trailing white spaces are not allowed!"));
+ errors.Add(ErrorSeverity.Error, "Leading and trailing white spaces are not allowed!");
}
if (PasswordHelper.IsTooLong(password, out _))
{
- errors.Add(new ErrorDescriptor(ErrorSeverity.Error, PasswordHelper.PasswordTooLongMessage));
+ errors.Add(ErrorSeverity.Error, PasswordHelper.PasswordTooLongMessage);
}
-
- return errors;
}
public override void OnCategorySelected()

MODIFY
WalletWasabi.Gui/Tabs/WalletManager/LoadWallets/LoadWalletViewModel.cs
WalletWasabi.Gui/Tabs/WalletManager/LoadWallets/LoadWalletViewModel.cs
@@ -132,7 +132,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager.LoadWallets
private ReplaySubject<Unit> ResortTrigger { get; } = new ReplaySubject<Unit>();
private CompositeDisposable Disposables { get; } = new CompositeDisposable();
- public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public void ValidatePassword(IErrorList errors) => PasswordHelper.ValidatePassword(errors, Password);
public override void OnCategorySelected()
{

MODIFY
WalletWasabi.Gui/Tabs/WalletManager/RecoverWallets/RecoverWalletViewModel.cs
WalletWasabi.Gui/Tabs/WalletManager/RecoverWallets/RecoverWalletViewModel.cs
@@ -109,7 +109,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager.RecoverWallets
private Global Global { get; }
private Wallets.WalletManager WalletManager { get; }
- public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public void ValidatePassword(IErrorList errors) => PasswordHelper.ValidatePassword(errors, Password);
[ValidateMethod(nameof(ValidatePassword))]
public string Password

MODIFY
WalletWasabi/Helpers/PasswordHelper.cs
WalletWasabi/Helpers/PasswordHelper.cs
@@ -152,21 +152,17 @@ namespace WalletWasabi.Helpers
throw resultException; // Throw the last exception - Invalid password.
}
- public static ErrorDescriptors ValidatePassword(string password)
+ public static void ValidatePassword(IErrorList errors, string password)
{
- var errors = new ErrorDescriptors();
-
if (IsTrimable(password, out _))
{
- errors.Add(new ErrorDescriptor(ErrorSeverity.Warning, TrimWarnMessage));
+ errors.Add(ErrorSeverity.Warning, TrimWarnMessage);
}
if (IsTooLong(password, out _))
{
- errors.Add(new ErrorDescriptor(ErrorSeverity.Error, PasswordTooLongMessage));
+ errors.Add(ErrorSeverity.Error, PasswordTooLongMessage);
}
-
- return errors;
}
}
}

ViewModel validation methods take IErrorList and dont need to know about ErrorDescriptors.