public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel) { ClearSensitiveData(true); ToggleSensitiveKeysCommand = ReactiveCommand.Create(() => { try { if (ShowSensitiveKeys) { ClearSensitiveData(true); } else { var secret = PasswordHelper.GetMasterExtKey(KeyManager, Password, out string isCompatibilityPasswordUsed); Password = ""; if (isCompatibilityPasswordUsed != null) { NotificationHelpers.Warning(PasswordHelper.CompatibilityPasswordWarnMessage); } string master = secret.GetWif(Global.Network).ToWif(); string account = secret.Derive(KeyManager.AccountKeyPath).GetWif(Global.Network).ToWif(); string masterZ = secret.ToZPrv(Global.Network); string accountZ = secret.Derive(KeyManager.AccountKeyPath).ToZPrv(Global.Network); SetSensitiveData(master, account, masterZ, accountZ); } } catch (Exception ex) { NotificationHelpers.Error(ex.ToTypeMessageString()); } }); }
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Interlocked.Exchange(ref _disableClipboard, 0); Transactions = new ObservableCollection <TransactionViewModel>(); RewriteTable(); Global.WalletService.NewBlockProcessed += WalletService_NewBlockProcessed; Global.WalletService.Coins.CollectionChanged += Coins_CollectionChanged; Global.WalletService.CoinSpentOrSpenderConfirmed += WalletService_CoinSpent; this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction => { if (Interlocked.Read(ref _disableClipboard) == 0) { if (transaction != null) { await Application.Current.Clipboard.SetTextAsync(transaction.TransactionId); ClipboardNotificationVisible = true; ClipboardNotificationOpacity = 1; Dispatcher.UIThread.Post(async() => { await Task.Delay(1000); ClipboardNotificationOpacity = 0; }); } } else { Interlocked.Exchange(ref _disableClipboard, 0); } }); }
public CoinJoinTabViewModel(WalletViewModel walletViewModel) : base("CoinJoin", walletViewModel) { Password = ""; var onCoinsSetModified = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged)) .ObserveOn(RxApp.MainThreadScheduler); var globalCoins = Global.WalletService.Coins.CreateDerivedCollection(c => new CoinViewModel(c), null, (first, second) => second.Amount.CompareTo(first.Amount), signalReset: onCoinsSetModified, RxApp.MainThreadScheduler); globalCoins.ChangeTrackingEnabled = true; var available = globalCoins.CreateDerivedCollection(c => c, c => c.Confirmed && !c.SpentOrCoinJoinInProgress); var queued = globalCoins.CreateDerivedCollection(c => c, c => c.CoinJoinInProgress); var registrableRound = Global.ChaumianClient.State.GetRegistrableRoundOrDefault(); UpdateRequiredBtcLabel(registrableRound, available, queued); if (registrableRound != default) { CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString(); } else { CoordinatorFeePercent = "0.003"; } if (!(registrableRound?.State?.Denomination is null) && registrableRound.State.Denomination != Money.Zero) { AvailableCoinsList = new CoinListViewModel(available, RequiredBTC, PreSelectMaxAnonSetExcludingCondition); }
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Disposables = new CompositeDisposable(); Transactions = new ObservableCollection <TransactionViewModel>(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed RewriteTableAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed var coinsChanged = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged)); var newBlockProcessed = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.NewBlockProcessed)); var coinSpent = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.CoinSpentOrSpenderConfirmed)); coinsChanged .Merge(newBlockProcessed) .Merge(coinSpent) .Throttle(TimeSpan.FromSeconds(5)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed RewriteTableAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed }).DisposeWith(Disposables); this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(transaction => transaction?.CopyToClipboard()).DisposeWith(Disposables); SortCommand = ReactiveCommand.Create(() => RefreshOrdering()).DisposeWith(Disposables); DateSortDirection = SortOrder.Decreasing; }
public WalletActionViewModel(string title, WalletViewModel walletViewModel) : base(title) { Disposables = new CompositeDisposable(); Wallet = walletViewModel; DoItCommand = ReactiveCommand.Create(DisplayActionTab).DisposeWith(Disposables); }
public ReceiveTabViewModel(WalletViewModel walletViewModel) : base("Receive", walletViewModel) { Global = Locator.Current.GetService <Global>(); LabelSuggestion = new SuggestLabelViewModel(); _addresses = new ObservableCollection <AddressViewModel>(); LabelSuggestion.Label = ""; InitializeAddresses(); GenerateCommand = ReactiveCommand.Create(() => { var label = new SmartLabel(LabelSuggestion.Label); LabelSuggestion.Label = label; if (label.IsEmpty) { NotificationHelpers.Warning("Observers are required."); return; } AvaloniaThreadingExtensions.PostLogException(Dispatcher.UIThread, () => { var newKey = KeyManager.GetNextReceiveKey(label, out bool minGapLimitIncreased); if (minGapLimitIncreased) { int minGapLimit = KeyManager.MinGapLimit.Value; int prevMinGapLimit = minGapLimit - 1; NotificationHelpers.Warning($"{nameof(KeyManager.MinGapLimit)} increased from {prevMinGapLimit} to {minGapLimit}."); } var newAddress = new AddressViewModel(newKey, KeyManager); Addresses.Insert(0, newAddress); SelectedAddress = newAddress; LabelSuggestion.Label = ""; }); }); this.WhenAnyValue(x => x.SelectedAddress) .Subscribe(async address => { if (Global.UiConfig?.Autocopy is false || address is null) { return; } await address.TryCopyToClipboardAsync(); }); Observable .Merge(GenerateCommand.ThrownExceptions) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => { Logger.LogError(ex); NotificationHelpers.Error(ex.ToUserFriendlyString()); }); }
public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel) { ClearSensitiveData(true); SetWarningMessage(""); this.WhenAnyValue(x => x.Password).Subscribe(x => { try { if (x.NotNullAndNotEmpty()) { char lastChar = x.Last(); if (lastChar == '\r' || lastChar == '\n') // If the last character is cr or lf then act like it'd be a sign to do the job. { Password = x.TrimEnd('\r', '\n'); } } } catch (Exception ex) { Logging.Logger.LogTrace(ex); } }); ToggleSensitiveKeysCommand = ReactiveCommand.Create(() => { try { if (ShowSensitiveKeys) { ClearSensitiveData(true); } else { var secret = PasswordHelper.GetMasterExtKey(KeyManager, Password, out string isCompatibilityPasswordUsed); Password = ""; if (isCompatibilityPasswordUsed != null) { SetWarningMessage(PasswordHelper.CompatibilityPasswordWarnMessage); } string master = secret.GetWif(Global.Network).ToWif(); string account = secret.Derive(KeyManager.AccountKeyPath).GetWif(Global.Network).ToWif(); string masterZ = secret.ToZPrv(Global.Network); string accountZ = secret.Derive(KeyManager.AccountKeyPath).ToZPrv(Global.Network); SetSensitiveData(master, account, masterZ, accountZ); } } catch (Exception ex) { SetWarningMessage(ex.ToTypeMessageString()); } }); }
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Transactions = new ObservableCollection <TransactionViewModel>(); SortCommand = ReactiveCommand.Create(RefreshOrdering); DateSortDirection = SortOrder.Decreasing; _isItemSelected = this .WhenAnyValue(x => x.SelectedTransaction) .Select(x => x is { })
internal void OpenWallet(string walletName) { if (_wallets.Any(x => x.Title == walletName)) { return; } WalletViewModel walletViewModel = new WalletViewModel(walletName); _wallets.Add(walletViewModel); }
internal void OpenWallet(string walletName, bool receiveDominant) { if (_wallets.Any(x => x.Title == walletName)) { return; } WalletViewModel walletViewModel = new WalletViewModel(walletName, receiveDominant); _wallets.Add(walletViewModel); }
public SendTabViewModel(WalletViewModel walletViewModel) : base("Send", walletViewModel) { CoinList = new CoinListViewModel(Global.WalletService.Coins); BuildTransactionButtonText = BuildTransactionButtonTextString; this.WhenAnyValue(x => x.Amount).Subscribe(_ => { if (!_ignoreAmountChanges) { IsMax = false; } }); BuildTransactionCommand = ReactiveCommand.Create(async() => { IsBusy = true; try { await Task.Delay(5000); //CoinList.SelectedCoins //IsMax = use all selected coins. // backend stuff here. } catch { } finally { IsBusy = false; } }, this.WhenAny(x => x.IsMax, x => x.Amount, x => x.Address, x => x.IsBusy, (isMax, amount, address, busy) => (isMax.Value || !string.IsNullOrWhiteSpace(amount.Value) && !string.IsNullOrWhiteSpace(Address) && !IsBusy))); MaxCommand = ReactiveCommand.Create(() => { SetMax(); }); this.WhenAnyValue(x => x.IsBusy).Subscribe(busy => { if (busy) { BuildTransactionButtonText = BuildingTransactionButtonTextString; } else { BuildTransactionButtonText = BuildTransactionButtonTextString; } }); }
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Disposables = new CompositeDisposable(); Interlocked.Exchange(ref _disableClipboard, 0); Transactions = new ObservableCollection <TransactionViewModel>(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed RewriteTableAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed var coinsChanged = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged)); var newBlockProcessed = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.NewBlockProcessed)); var coinSpent = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.CoinSpentOrSpenderConfirmed)); coinsChanged .Merge(newBlockProcessed) .Merge(coinSpent) .Throttle(TimeSpan.FromSeconds(5)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed RewriteTableAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed }).DisposeWith(Disposables); this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction => { if (Interlocked.Read(ref _disableClipboard) == 0) { if (!(transaction is null)) { await Application.Current.Clipboard.SetTextAsync(transaction.TransactionId); ClipboardNotificationVisible = true; ClipboardNotificationOpacity = 1; Dispatcher.UIThread.Post(async() => { await Task.Delay(1000); ClipboardNotificationOpacity = 0; }); } } else { Interlocked.Exchange(ref _disableClipboard, 0); } }).DisposeWith(Disposables); SortCommand = ReactiveCommand.Create(() => RefreshOrdering()).DisposeWith(Disposables); DateSortDirection = SortOrder.Decreasing; }
public ReceiveTabViewModel(WalletViewModel walletViewModel) : base("Receive", walletViewModel) { _labelSuggestion = new SuggestLabelViewModel(Global); _addresses = new ObservableCollection <AddressViewModel>(); _labelSuggestion.Label = ""; InitializeAddresses(); GenerateCommand = ReactiveCommand.Create(() => { var label = new SmartLabel(_labelSuggestion.Label); _labelSuggestion.Label = label; if (label.IsEmpty) { NotificationHelpers.Warning("Label is required."); return; } Dispatcher.UIThread.PostLogException(() => { HdPubKey newKey = Global.WalletService.GetReceiveKey(_labelSuggestion.Label, Addresses.Select(x => x.Model).Take(7)); // Never touch the first 7 keys. AddressViewModel found = Addresses.FirstOrDefault(x => x.Model == newKey); if (found != default) { Addresses.Remove(found); } var newAddress = new AddressViewModel(newKey, Global); Addresses.Insert(0, newAddress); SelectedAddress = newAddress; _labelSuggestion.Label = ""; }); }); this.WhenAnyValue(x => x.SelectedAddress).Subscribe(async address => { if (Global.UiConfig?.Autocopy is false || address is null) { return; } await address.TryCopyToClipboardAsync(); }); var isCoinListItemSelected = this.WhenAnyValue(x => x.SelectedAddress).Select(coin => coin is { });
public ReceiveTabViewModel(WalletViewModel walletViewModel) : base("Receive", walletViewModel) { _addresses = new ObservableCollection <AddressViewModel>(); Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(o => { InitializeAddresses(); }); InitializeAddresses(); GenerateCommand = ReactiveCommand.Create(() => { HdPubKey newKey = Global.WalletService.GetReceiveKey(Label); AddressViewModel found = Addresses.FirstOrDefault(x => x.Model == newKey); if (found != default) { Addresses.Remove(found); } var newAddress = new AddressViewModel(newKey); Addresses.Insert(0, newAddress); SelectedAddress = newAddress; Label = string.Empty; }, this.WhenAnyValue(x => x.Label, label => !string.IsNullOrWhiteSpace(label))); this.WhenAnyValue(x => x.SelectedAddress).Subscribe(async address => { if (address != null) { await Application.Current.Clipboard.SetTextAsync(address.Address); ClipboardNotificationVisible = true; ClipboardNotificationOpacity = 1; Dispatcher.UIThread.Post(async() => { await Task.Delay(1000); ClipboardNotificationOpacity = 0; }); } }); }
public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel) { Disposables = new CompositeDisposable(); ClearSensitiveData(true); _warningMessage = ""; Closing = new CancellationTokenSource().DisposeWith(Disposables); this.WhenAnyValue(x => x.Password).Subscribe(x => { try { if (x.NotNullAndNotEmpty()) { char lastChar = x.Last(); if (lastChar == '\r' || lastChar == '\n') // If the last character is cr or lf then act like it'd be a sign to do the job. { Password = x.TrimEnd('\r', '\n'); } } } catch (Exception ex) { Logging.Logger.LogTrace(ex); } }).DisposeWith(Disposables); ShowSensitiveKeysCommand = ReactiveCommand.Create(() => { try { Password = Guard.Correct(Password); var secret = KeyManager.GetMasterExtKey(Password); Password = ""; string master = secret.GetWif(Global.Network).ToWif(); string masterPub = secret.Neuter().GetWif(Global.Network).ToWif(); string account = secret.Derive(KeyManager.AccountKeyPath).GetWif(Global.Network).ToWif(); string masterY = secret.ToZPrv(Global.Network); string masterPubY = secret.Neuter().ToZpub(Global.Network); string accountY = secret.Derive(KeyManager.AccountKeyPath).ToZPrv(Global.Network); SetSensitiveData(master, masterPub, account, masterY, masterPubY, accountY); } catch (Exception ex) { SetWarningMessage(ex.ToTypeMessageString()); } }).DisposeWith(Disposables); }
public ReceiveTabViewModel(WalletViewModel walletViewModel) : base("Receive", walletViewModel) { _labelSuggestion = new SuggestLabelViewModel(Global); _addresses = new ObservableCollection <AddressViewModel>(); _labelSuggestion.Label = ""; InitializeAddresses(); GenerateCommand = ReactiveCommand.Create(() => { var label = new SmartLabel(_labelSuggestion.Label); _labelSuggestion.Label = label; if (label.IsEmpty) { NotificationHelpers.Warning("Label is required."); return; } AvaloniaThreadingExtensions.PostLogException(Dispatcher.UIThread, () => { var newKey = KeyManager.GetNextReceiveKey(label, out bool minGapLimitIncreased); if (minGapLimitIncreased) { int minGapLimit = KeyManager.MinGapLimit.Value; int prevMinGapLimit = minGapLimit - 1; NotificationHelpers.Warning($"{nameof(KeyManager.MinGapLimit)} increased from {prevMinGapLimit} to {minGapLimit}."); } var newAddress = new AddressViewModel(newKey, Global); Addresses.Insert(0, newAddress); SelectedAddress = newAddress; _labelSuggestion.Label = ""; }); }); this.WhenAnyValue(x => x.SelectedAddress).Subscribe(async address => { if (Global.UiConfig?.Autocopy is false || address is null) { return; } await address.TryCopyToClipboardAsync(); }); var isCoinListItemSelected = this.WhenAnyValue(x => x.SelectedAddress).Select(coin => coin is { });
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Transactions = new ObservableCollection <TransactionViewModel>(); SortCommand = ReactiveCommand.Create(RefreshOrdering); DateSortDirection = SortOrder.Decreasing; SortCommand.ThrownExceptions .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => { NotificationHelpers.Error(ex.ToTypeMessageString()); Logger.LogWarning(ex); }); _ = TryRewriteTableAsync(); }
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Interlocked.Exchange(ref _disableClipboard, 0); Transactions = new ObservableCollection <TransactionViewModel>(); RewriteTable(); var coinsChanged = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged)); var newBlockProcessed = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.NewBlockProcessed)); var coinSpent = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.CoinSpentOrSpenderConfirmed)); coinsChanged .Merge(newBlockProcessed) .Merge(coinSpent) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(o => { RewriteTable(); }); this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction => { if (Interlocked.Read(ref _disableClipboard) == 0) { if (!(transaction is null)) { await Application.Current.Clipboard.SetTextAsync(transaction.TransactionId); ClipboardNotificationVisible = true; ClipboardNotificationOpacity = 1; Dispatcher.UIThread.Post(async() => { await Task.Delay(1000); ClipboardNotificationOpacity = 0; }); } } else { Interlocked.Exchange(ref _disableClipboard, 0); } }); DateSortDirection = SortOrder.Decreasing; }
public CoinJoinTabViewModel(WalletViewModel walletViewModel) : base("CoinJoin", walletViewModel) { Password = ""; var onCoinsSetModified = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged)) .ObserveOn(RxApp.MainThreadScheduler); var globalCoins = Global.WalletService.Coins.CreateDerivedCollection(c => new CoinViewModel(c), null, (first, second) => second.Amount.CompareTo(first.Amount), signalReset: onCoinsSetModified, RxApp.MainThreadScheduler); globalCoins.ChangeTrackingEnabled = true; var available = globalCoins.CreateDerivedCollection(c => c, c => c.Confirmed && !c.SpentOrCoinJoinInProcess); var queued = globalCoins.CreateDerivedCollection(c => c, c => c.CoinJoinInProgress); AvailableCoinsList = new CoinListViewModel(available); QueuedCoinsList = new CoinListViewModel(queued); EnqueueCommand = ReactiveCommand.Create(async() => { var selectedCoins = AvailableCoinsList.Coins.Where(c => c.IsSelected).ToList(); foreach (var coin in selectedCoins) { coin.IsSelected = false; } await Global.ChaumianClient.QueueCoinsToMixAsync(Password, selectedCoins.Select(c => c.Model).ToArray()); }); DequeueCommand = ReactiveCommand.Create(async() => { var selectedCoins = QueuedCoinsList.Coins.Where(c => c.IsSelected).ToList(); foreach (var coin in selectedCoins) { coin.IsSelected = false; } await Global.ChaumianClient.DequeueCoinsFromMixAsync(selectedCoins.Select(c => c.Model).ToArray()); }); }
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Global = Locator.Current.GetService <Global>(); Transactions = new ObservableCollection <TransactionViewModel>(); SortCommand = ReactiveCommand.Create(RefreshOrdering); DateSortDirection = SortOrder.Decreasing; SortCommand.ThrownExceptions .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => { Logger.LogError(ex); NotificationHelpers.Error(ex.ToUserFriendlyString()); }); _ = TryRewriteTableAsync(); }
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Transactions = new ObservableCollection <TransactionViewModel>(); RewriteTableAsync().GetAwaiter(); this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction => { if (Global.UiConfig.Autocopy is false || transaction is null) { return; } await transaction.TryCopyTxIdToClipboardAsync(); }); SortCommand = ReactiveCommand.Create(() => RefreshOrdering()); DateSortDirection = SortOrder.Decreasing; }
public CoinJoinTabViewModel(WalletViewModel walletViewModel) : base("CoinJoin", walletViewModel) { Password = ""; var registrableRound = Global.ChaumianClient.State.GetRegistrableRoundOrDefault(); UpdateRequiredBtcLabel(registrableRound); if (registrableRound != default) { CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString(); } else { CoordinatorFeePercent = "0.003"; } if (!(registrableRound?.State?.Denomination is null) && registrableRound.State.Denomination != Money.Zero) { CoinsList = new CoinListViewModel(RequiredBTC, PreSelectMaxAnonSetExcludingCondition); }
public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel) { Global = Locator.Current.GetService <Global>(); ClearSensitiveData(true); ToggleSensitiveKeysCommand = ReactiveCommand.Create(() => { if (ShowSensitiveKeys) { ClearSensitiveData(true); } else { var secret = PasswordHelper.GetMasterExtKey(KeyManager, Password, out string isCompatibilityPasswordUsed); Password = ""; if (isCompatibilityPasswordUsed != null) { NotificationHelpers.Warning(PasswordHelper.CompatibilityPasswordWarnMessage); } string master = secret.GetWif(Global.Network).ToWif(); string account = secret.Derive(KeyManager.AccountKeyPath).GetWif(Global.Network).ToWif(); string masterZ = secret.ToZPrv(Global.Network); string accountZ = secret.Derive(KeyManager.AccountKeyPath).ToZPrv(Global.Network); SetSensitiveData(master, account, masterZ, accountZ); } }); ToggleSensitiveKeysCommand.ThrownExceptions .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => { Logging.Logger.LogError(ex); NotificationHelpers.Error(ex.ToUserFriendlyString()); }); }
public CoinJoinTabViewModel(WalletViewModel walletViewModel) : base("CoinJoin", walletViewModel) { Password = ""; TargetPrivacy = ShieldLevelHelper.GetTargetPrivacy(Global.Config.MixUntilAnonymitySet); var registrableRound = Global.ChaumianClient.State.GetRegistrableRoundOrDefault(); UpdateRequiredBtcLabel(registrableRound); if (registrableRound != default) { CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString(); } else { CoordinatorFeePercent = "0.003"; } if (!(registrableRound?.State?.Denomination is null) && registrableRound.State.Denomination != Money.Zero) { CoinsList = new CoinListViewModel(); }
public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel) { Disposables = new CompositeDisposable(); _password = ""; _secret = ""; _warningMessage = ""; Closing = new CancellationTokenSource().DisposeWith(Disposables); this.WhenAnyValue(x => x.Password).Subscribe(x => { if (x.NotNullAndNotEmpty()) { char lastChar = x.Last(); if (lastChar == '\r' || lastChar == '\n') // If the last character is cr or lf then act like it'd be a sign to do the job. { Password = x.TrimEnd('\r', '\n'); } } }).DisposeWith(Disposables); ShowMasterKeyCommand = ReactiveCommand.Create(() => { try { Password = Guard.Correct(Password); var secret = KeyManager.GetExtKey(Password); Password = ""; SetSecret(secret.GetWif(Global.Network).ToWif()); } catch (Exception ex) { SetWarningMessage(ex.ToTypeMessageString()); } }).DisposeWith(Disposables); }
public HistoryTabViewModel(WalletViewModel walletViewModel) : base("History", walletViewModel) { Transactions = new ObservableCollection <TransactionViewModel>(); this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction => { if (Global.UiConfig?.Autocopy is false || transaction is null) { return; } await transaction.TryCopyTxIdToClipboardAsync(); }); SortCommand = ReactiveCommand.Create(RefreshOrdering); SortCommand.ThrownExceptions .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => Logger.LogError(ex)); DateSortDirection = SortOrder.Decreasing; _ = TryRewriteTableAsync(); }
public WalletActionViewModel(string title, WalletViewModel walletViewModel) : base(title) { Wallet = walletViewModel; DoItCommand = ReactiveCommand.Create(DisplayActionTab); }
public CoinJoinTabViewModel(WalletViewModel walletViewModel) : base("CoinJoin", walletViewModel) { Password = ""; TimeLeftTillRoundTimeout = TimeSpan.Zero; CoinsList = new CoinListViewModel(Global, CoinListContainerType.CoinJoinTabViewModel); Observable.FromEventPattern(CoinsList, nameof(CoinsList.DequeueCoinsPressed)).Subscribe(_ => OnCoinsListDequeueCoinsPressedAsync()); AmountQueued = Money.Zero; // Global.ChaumianClient.State.SumAllQueuedCoinAmounts(); EnqueueCommand = ReactiveCommand.CreateFromTask(async() => await DoEnqueueAsync(CoinsList.Coins.Where(c => c.IsSelected))); DequeueCommand = ReactiveCommand.CreateFromTask(async() => await DoDequeueAsync(CoinsList.Coins.Where(c => c.IsSelected))); PrivacySomeCommand = ReactiveCommand.Create(() => TargetPrivacy = TargetPrivacy.Some); PrivacyFineCommand = ReactiveCommand.Create(() => TargetPrivacy = TargetPrivacy.Fine); PrivacyStrongCommand = ReactiveCommand.Create(() => TargetPrivacy = TargetPrivacy.Strong); TargetButtonCommand = ReactiveCommand.CreateFromTask(async() => { switch (TargetPrivacy) { case TargetPrivacy.None: TargetPrivacy = TargetPrivacy.Some; break; case TargetPrivacy.Some: TargetPrivacy = TargetPrivacy.Fine; break; case TargetPrivacy.Fine: TargetPrivacy = TargetPrivacy.Strong; break; case TargetPrivacy.Strong: TargetPrivacy = TargetPrivacy.Some; break; } Global.Config.MixUntilAnonymitySet = CoinJoinUntilAnonymitySet; await Global.Config.ToFileAsync(); }); this.WhenAnyValue(x => x.Password).Subscribe(async x => { try { if (x.NotNullAndNotEmpty()) { char lastChar = x.Last(); if (lastChar == '\r' || lastChar == '\n') // If the last character is cr or lf then act like it'd be a sign to do the job. { Password = x.TrimEnd('\r', '\n'); await DoEnqueueAsync(CoinsList.Coins.Where(c => c.IsSelected)); } } } catch (Exception ex) { Logger.LogTrace(ex); } }); this.WhenAnyValue(x => x.IsEnqueueBusy) .Select(x => x ? EnqueuingButtonTextString : EnqueueButtonTextString) .Subscribe(text => EnqueueButtonText = text); this.WhenAnyValue(x => x.IsDequeueBusy) .Select(x => x ? DequeuingButtonTextString : DequeueButtonTextString) .Subscribe(text => DequeueButtonText = text); this.WhenAnyValue(x => x.TargetPrivacy).Subscribe(target => { CoinJoinUntilAnonymitySet = Global.Config.GetTargetLevel(target); }); this.WhenAnyValue(x => x.RoundTimesout) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { TimeSpan left = x - DateTimeOffset.UtcNow; TimeLeftTillRoundTimeout = left > TimeSpan.Zero ? left : TimeSpan.Zero; // Make sure cannot be less than zero. }); }
public SendTabViewModel(WalletViewModel walletViewModel) : base("Send", walletViewModel) { Label = ""; var onCoinsSetModified = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged)) .ObserveOn(RxApp.MainThreadScheduler); var globalCoins = Global.WalletService.Coins.CreateDerivedCollection(c => new CoinViewModel(c), null, (first, second) => second.Amount.CompareTo(first.Amount), signalReset: onCoinsSetModified, RxApp.MainThreadScheduler); globalCoins.ChangeTrackingEnabled = true; var filteredCoins = globalCoins.CreateDerivedCollection(c => c, c => !c.SpentOrCoinJoinInProgress); CoinList = new CoinListViewModel(filteredCoins); BuildTransactionButtonText = BuildTransactionButtonTextString; ResetMax(); this.WhenAnyValue(x => x.Amount).Subscribe(amount => { if (!IgnoreAmountChanges) { IsMax = false; // Correct amount Regex digitsOnly = new Regex(@"[^\d,.]"); string betterAmount = digitsOnly.Replace(amount, ""); // Make it digits , and . only. betterAmount = betterAmount.Replace(',', '.'); int countBetterAmount = betterAmount.Count(x => x == '.'); if (countBetterAmount > 1) // Don't enable typing two dots. { var index = betterAmount.IndexOf('.', betterAmount.IndexOf('.') + 1); if (index > 0) { betterAmount = betterAmount.Substring(0, index); } } var dotIndex = betterAmount.IndexOf('.'); if (betterAmount.Length - dotIndex > 8) // Enable max 8 decimals. { betterAmount = betterAmount.Substring(0, dotIndex + 1 + 8); } if (betterAmount != amount) { Dispatcher.UIThread.Post(() => { Amount = betterAmount; }); } } }); BuildTransactionCommand = ReactiveCommand.Create(async() => { IsBusy = true; try { Password = Guard.Correct(Password); if (!IsMax && string.IsNullOrWhiteSpace(Label)) { SetWarningMessage("Label is required."); return; } var selectedCoins = CoinList.Coins.Where(cvm => cvm.IsSelected).Select(cvm => new TxoRef(cvm.Model.TransactionId, cvm.Model.Index)).ToList(); if (!selectedCoins.Any()) { SetWarningMessage("No coins are selected to spend."); return; } BitcoinAddress address; try { address = BitcoinAddress.Create(Address.Trim(), Global.Network); } catch (FormatException) { SetWarningMessage("Invalid address."); return; } var script = address.ScriptPubKey; var amount = Money.Zero; if (!IsMax) { amount = Money.Parse(Amount); if (amount == Money.Zero) { SetWarningMessage($"Invalid amount."); return; } } var label = Label.Trim(',', ' ').Trim(); var operation = new WalletService.Operation(script, amount, label); var result = await Task.Run(async() => await Global.WalletService.BuildTransactionAsync(Password, new[] { operation }, Fee, allowUnconfirmed: true, allowedInputs: selectedCoins)); await Task.Run(async() => await Global.WalletService.SendTransactionAsync(result.Transaction)); ResetMax(); Address = ""; Label = ""; Password = ""; SetSuccessMessage("Transaction is successfully sent!"); } catch (InsufficientBalanceException ex) { Money needed = ex.Minimum - ex.Actual; SetWarningMessage($"Not enough coins selected. You need an estimated {needed.ToString(false, true)} BTC more to make this transaction."); } catch (Exception ex) { SetWarningMessage(ex.ToTypeMessageString()); } finally { IsBusy = false; } }, this.WhenAny(x => x.IsMax, x => x.Amount, x => x.Address, x => x.IsBusy, (isMax, amount, address, busy) => ((isMax.Value || !string.IsNullOrWhiteSpace(amount.Value)) && !string.IsNullOrWhiteSpace(Address) && !IsBusy))); MaxCommand = ReactiveCommand.Create(() => { SetMax(); }); this.WhenAnyValue(x => x.IsBusy).Subscribe(busy => { if (busy) { BuildTransactionButtonText = BuildingTransactionButtonTextString; } else { BuildTransactionButtonText = BuildTransactionButtonTextString; } }); this.WhenAnyValue(x => x.Password).Subscribe(x => { if (x.NotNullAndNotEmpty()) { char lastChar = x.Last(); if (lastChar == '\r' || lastChar == '\n') // If the last character is cr or lf then act like it'd be a sign to do the job. { Password = x.TrimEnd('\r', '\n'); } } }); this.WhenAnyValue(x => x.Label).Subscribe(x => UpdateSuggestions(x)); this.WhenAnyValue(x => x.CaretIndex).Subscribe(_ => { if (Label == null) { return; } if (CaretIndex != Label.Length) { CaretIndex = Label.Length; } }); _suggestions = new ObservableCollection <SuggestionViewModel>(); }
public ReceiveTabViewModel(WalletViewModel walletViewModel) : base("Receive", walletViewModel) { _addresses = new ObservableCollection <AddressViewModel>(); Label = ""; InitializeAddresses(); GenerateCommand = ReactiveCommand.Create(() => { var label = new SmartLabel(Label); Label = label.ToString(); if (label.IsEmpty) { LabelRequiredNotificationVisible = true; LabelRequiredNotificationOpacity = 1; Dispatcher.UIThread.PostLogException(async() => { await Task.Delay(TimeSpan.FromSeconds(4)); LabelRequiredNotificationOpacity = 0; }); return; } Dispatcher.UIThread.PostLogException(() => { HdPubKey newKey = Global.WalletService.GetReceiveKey(new SmartLabel(Label), Addresses.Select(x => x.Model).Take(7)); // Never touch the first 7 keys. AddressViewModel found = Addresses.FirstOrDefault(x => x.Model == newKey); if (found != default) { Addresses.Remove(found); } var newAddress = new AddressViewModel(newKey, Global); Addresses.Insert(0, newAddress); SelectedAddress = newAddress; Label = ""; }); }); this.WhenAnyValue(x => x.Label).Subscribe(UpdateSuggestions); this.WhenAnyValue(x => x.SelectedAddress).Subscribe(async address => { if (Global.UiConfig?.Autocopy is false || address is null) { return; } await address.TryCopyToClipboardAsync(); }); var isCoinListItemSelected = this.WhenAnyValue(x => x.SelectedAddress).Select(coin => coin != null); CopyAddress = ReactiveCommand.CreateFromTask(async() => { if (SelectedAddress is null) { return; } await SelectedAddress.TryCopyToClipboardAsync(); }, isCoinListItemSelected); CopyLabel = ReactiveCommand.CreateFromTask(async() => { try { await Application.Current.Clipboard.SetTextAsync(SelectedAddress.Label ?? string.Empty); } catch (Exception) { } }, isCoinListItemSelected); ToggleQrCode = ReactiveCommand.Create(() => { try { SelectedAddress.IsExpanded = !SelectedAddress.IsExpanded; } catch (Exception) { } }, isCoinListItemSelected); #pragma warning disable IDE0053 // Use expression body for lambda expressions ChangeLabelCommand = ReactiveCommand.Create(() => { SelectedAddress.InEditMode = true; }); #pragma warning restore IDE0053 // Use expression body for lambda expressions DisplayAddressOnHwCommand = ReactiveCommand.CreateFromTask(async() => { var client = new HwiClient(Global.Network); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); try { await client.DisplayAddressAsync(KeyManager.MasterFingerprint.Value, SelectedAddress.Model.FullKeyPath, cts.Token); } catch (HwiException) { await PinPadViewModel.UnlockAsync(Global); await client.DisplayAddressAsync(KeyManager.MasterFingerprint.Value, SelectedAddress.Model.FullKeyPath, cts.Token); } }); _suggestions = new ObservableCollection <SuggestionViewModel>(); }