public override void OnOpen() { base.OnOpen(); Disposables = Disposables is null ? new CompositeDisposable() : throw new NotSupportedException($"Cannot open {GetType().Name} before closing it."); TargetPrivacy = Global.Config.GetTargetPrivacy(); var registrableRound = Global.WalletService.ChaumianClient.State.GetRegistrableRoundOrDefault(); UpdateRequiredBtcLabel(registrableRound); CoordinatorFeePercent = registrableRound?.State?.CoordinatorFeePercent.ToString() ?? "0.003"; Observable.FromEventPattern(Global.WalletService.ChaumianClient, nameof(Global.WalletService.ChaumianClient.CoinQueued)) .Merge(Observable.FromEventPattern(Global.WalletService.ChaumianClient, nameof(Global.WalletService.ChaumianClient.OnDequeue))) .Merge(Observable.FromEventPattern(Global.WalletService.ChaumianClient, nameof(Global.WalletService.ChaumianClient.StateUpdated))) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => UpdateStates()) .DisposeWith(Disposables); ClientRound mostAdvancedRound = Global.WalletService.ChaumianClient?.State?.GetMostAdvancedRoundOrDefault(); if (mostAdvancedRound != default) { RoundId = mostAdvancedRound.State.RoundId; RoundPhaseState = new RoundPhaseState(mostAdvancedRound.State.Phase, Global.WalletService.ChaumianClient?.State.IsInErrorState ?? false); RoundTimesout = mostAdvancedRound.State.Phase == RoundPhase.InputRegistration ? mostAdvancedRound.State.InputRegistrationTimesout : DateTimeOffset.UtcNow; PeersRegistered = mostAdvancedRound.State.RegisteredPeerCount; PeersNeeded = mostAdvancedRound.State.RequiredPeerCount; } else { RoundId = -1; RoundPhaseState = new RoundPhaseState(RoundPhase.InputRegistration, false); RoundTimesout = DateTimeOffset.UtcNow; PeersRegistered = 0; PeersNeeded = 100; } Global.UiConfig.WhenAnyValue(x => x.LurkingWifeMode).ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ => { this.RaisePropertyChanged(nameof(AmountQueued)); this.RaisePropertyChanged(nameof(IsLurkingWifeMode)); }).DisposeWith(Disposables); Observable.Interval(TimeSpan.FromSeconds(1)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { TimeSpan left = RoundTimesout - DateTimeOffset.UtcNow; TimeLeftTillRoundTimeout = left > TimeSpan.Zero ? left : TimeSpan.Zero; // Make sure cannot be less than zero. }).DisposeWith(Disposables); }
private void UpdateStates() { var chaumianClient = _walletManager.CurrentWallet.ChaumianClient; if (chaumianClient is null) { return; } AmountQueued = chaumianClient.State.SumAllQueuedCoinAmounts(); var registrableRound = chaumianClient.State.GetRegistrableRoundOrDefault(); if (registrableRound != default) { CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString(); UpdateRequiredBtcLabel(registrableRound); } var mostAdvancedRound = chaumianClient.State.GetMostAdvancedRoundOrDefault(); if (mostAdvancedRound != default) { if (!chaumianClient.State.IsInErrorState) { RoundPhaseState = new RoundPhaseState(mostAdvancedRound.State.Phase, false); if (mostAdvancedRound.State?.InputRegistrationTimesout > RoundTimesout && AmountQueued > Money.Zero) { // Seems like this is getting triggered twice. ScheduleConfirmNotification(mostAdvancedRound.State.InputRegistrationTimesout); } RoundTimesout = mostAdvancedRound.State.Phase == RoundPhase.InputRegistration ? mostAdvancedRound.State.InputRegistrationTimesout : DateTimeOffset.UtcNow; } else { RoundPhaseState = new RoundPhaseState(RoundPhaseState.Phase, true); } this.RaisePropertyChanged(nameof(RoundPhaseState)); this.RaisePropertyChanged(nameof(RoundTimesout)); PeersRegistered = mostAdvancedRound.State.RegisteredPeerCount; PeersQueued = mostAdvancedRound.State.QueuedPeerCount; PeersNeeded = mostAdvancedRound.State.RequiredPeerCount; } }
private void UpdateStates() { var chaumianClient = Global?.WalletService?.ChaumianClient; if (chaumianClient is null) { return; } AmountQueued = chaumianClient.State.SumAllQueuedCoinAmounts(); MainWindowViewModel.Instance.CanClose = AmountQueued == Money.Zero; var registrableRound = chaumianClient.State.GetRegistrableRoundOrDefault(); if (registrableRound != default) { CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString(); UpdateRequiredBtcLabel(registrableRound); } var mostAdvancedRound = chaumianClient.State.GetMostAdvancedRoundOrDefault(); if (mostAdvancedRound != default) { RoundId = mostAdvancedRound.State.RoundId; if (!chaumianClient.State.IsInErrorState) { RoundPhaseState = new RoundPhaseState(mostAdvancedRound.State.Phase, false); RoundTimesout = mostAdvancedRound.State.Phase == RoundPhase.InputRegistration ? mostAdvancedRound.State.InputRegistrationTimesout : DateTimeOffset.UtcNow; } else { RoundPhaseState = new RoundPhaseState(RoundPhaseState.Phase, true); } this.RaisePropertyChanged(nameof(RoundPhaseState)); this.RaisePropertyChanged(nameof(RoundTimesout)); PeersRegistered = mostAdvancedRound.State.RegisteredPeerCount; PeersNeeded = mostAdvancedRound.State.RequiredPeerCount; } }
public CoinJoinViewModel(ChaincaseWalletManager walletManager, Config config, INotificationManager notificationManager, SelectCoinsViewModel selectCoinsViewModel) { _walletManager = walletManager; _config = config; _notificationManager = notificationManager; CoinList = selectCoinsViewModel; if (Disposables != null) { throw new Exception("Wallet opened before it was closed."); } Disposables = new CompositeDisposable(); // Infer coordinator fee var registrableRound = _walletManager.CurrentWallet?.ChaumianClient?.State?.GetRegistrableRoundOrDefault(); CoordinatorFeePercent = registrableRound?.State?.CoordinatorFeePercent.ToString() ?? "0.003"; // Select most advanced coin join round ClientRound mostAdvancedRound = _walletManager.CurrentWallet?.ChaumianClient?.State?.GetMostAdvancedRoundOrDefault(); if (mostAdvancedRound != default) { RoundPhaseState = new RoundPhaseState(mostAdvancedRound.State.Phase, _walletManager.CurrentWallet.ChaumianClient?.State.IsInErrorState ?? false); RoundTimesout = mostAdvancedRound.State.Phase == RoundPhase.InputRegistration ? mostAdvancedRound.State.InputRegistrationTimesout : DateTimeOffset.UtcNow; PeersRegistered = mostAdvancedRound.State.RegisteredPeerCount; PeersQueued = mostAdvancedRound.State.QueuedPeerCount; PeersNeeded = mostAdvancedRound.State.RequiredPeerCount; RequiredBTC = mostAdvancedRound.State.CalculateRequiredAmount(); } else { RoundPhaseState = new RoundPhaseState(RoundPhase.InputRegistration, false); RoundTimesout = DateTimeOffset.UtcNow; PeersRegistered = 0; PeersQueued = 0; PeersNeeded = 100; RequiredBTC = Money.Parse("0.01"); } // Set time left in round this.WhenAnyValue(x => x.RoundTimesout) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { TimeLeftTillRoundTimeout = TimeUntilOffset(RoundTimesout); }); Task.Run(async() => { while (_walletManager.CurrentWallet?.ChaumianClient == null) { await Task.Delay(50).ConfigureAwait(false); } // Update view model state on chaumian client state updates Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.CoinQueued)) .Merge(Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.OnDequeue))) .Merge(Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.StateUpdated))) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => UpdateStates()) .DisposeWith(Disposables); // Remove notification on unconfirming status in coin join round Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.OnDequeue)) .Subscribe(pattern => { var e = (DequeueResult)pattern.EventArgs; try { foreach (var success in e.Successful.Where(x => x.Value.Any())) { DequeueReason reason = success.Key; if (reason == DequeueReason.UserRequested) { _notificationManager.RemoveAllPendingNotifications(); } } } catch (Exception ex) { Logger.LogWarning(ex); } }) .DisposeWith(Disposables); }); // Update timeout label Observable.Interval(TimeSpan.FromSeconds(1)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { TimeLeftTillRoundTimeout = TimeUntilOffset(RoundTimesout); }).DisposeWith(Disposables); }
public CoinJoinViewModel(CoinListViewModel coinList) : base(Locator.Current.GetService <IViewStackService>()) { Global = Locator.Current.GetService <Global>(); SetBalance(); notificationManager = Global.NotificationManager; if (Disposables != null) { throw new Exception("Wallet opened before it was closed."); } Disposables = new CompositeDisposable(); CoinList = coinList; Observable .FromEventPattern <SmartCoin>(CoinList, nameof(CoinList.DequeueCoinsPressed)) .Subscribe(async x => await DoDequeueAsync(x.EventArgs)); this.WhenAnyValue(x => x.RoundTimesout) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { TimeSpan left = RoundTimesout - DateTimeOffset.UtcNow; TimeLeftTillRoundTimeout = left > TimeSpan.Zero ? left : TimeSpan.Zero; // Make sure cannot be less than zero. }); AmountQueued = Money.Zero; var registrableRound = Global.Wallet.ChaumianClient.State.GetRegistrableRoundOrDefault(); CoordinatorFeePercent = registrableRound?.State?.CoordinatorFeePercent.ToString() ?? "0.003"; Observable.FromEventPattern(Global.Wallet.ChaumianClient, nameof(Global.Wallet.ChaumianClient.CoinQueued)) .Merge(Observable.FromEventPattern(Global.Wallet.ChaumianClient, nameof(Global.Wallet.ChaumianClient.OnDequeue))) .Merge(Observable.FromEventPattern(Global.Wallet.ChaumianClient, nameof(Global.Wallet.ChaumianClient.StateUpdated))) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => UpdateStates()) .DisposeWith(Disposables); Observable.FromEventPattern(Global.Wallet.ChaumianClient, nameof(Global.Wallet.ChaumianClient.OnDequeue)) .Subscribe(pattern => { var e = (DequeueResult)pattern.EventArgs; try { foreach (var success in e.Successful.Where(x => x.Value.Any())) { DequeueReason reason = success.Key; if (reason == DequeueReason.UserRequested) { notificationManager.RemoveAllPendingNotifications(); } } } catch (Exception ex) { Logger.LogWarning(ex); } }) .DisposeWith(Disposables); ClientRound mostAdvancedRound = Global.Wallet.ChaumianClient?.State?.GetMostAdvancedRoundOrDefault(); if (mostAdvancedRound != default) { RoundPhaseState = new RoundPhaseState(mostAdvancedRound.State.Phase, Global.Wallet.ChaumianClient?.State.IsInErrorState ?? false); RoundTimesout = mostAdvancedRound.State.Phase == RoundPhase.InputRegistration ? mostAdvancedRound.State.InputRegistrationTimesout : DateTimeOffset.UtcNow; PeersRegistered = mostAdvancedRound.State.RegisteredPeerCount; PeersNeeded = mostAdvancedRound.State.RequiredPeerCount; } else { RoundPhaseState = new RoundPhaseState(RoundPhase.InputRegistration, false); RoundTimesout = DateTimeOffset.UtcNow; PeersRegistered = 0; PeersNeeded = 100; } Observable.Interval(TimeSpan.FromSeconds(1)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { TimeSpan left = RoundTimesout - DateTimeOffset.UtcNow; TimeLeftTillRoundTimeout = left > TimeSpan.Zero ? left : TimeSpan.Zero; // Make sure cannot be less than zero. }).DisposeWith(Disposables); CoinJoinCommand = ReactiveCommand.CreateFromTask <string, bool>(DoEnqueueAsync); ExitCoinJoinCommand = ReactiveCommand.CreateFromTask(ExitCoinJoinAsync); var canPromptPassword = this.WhenAnyValue( x => x.CoinList.SelectedAmount, x => x.RequiredBTC, (amnt, rBTC) => { return(!(rBTC is null) && !(amnt is null) && amnt >= rBTC); });
private string FormatPhaseLabel(RoundPhaseState rps) { _phaseStringConverter.TryConvert(rps, typeof(string), null, out var phaseString); return("Phase: " + phaseString); }