public CoinViewModel(CoinListViewModel owner, SmartCoin model) { Global = Locator.Current.GetService <Global>(); Model = model; Owner = owner; InCoinJoinContainer = owner.CoinListContainerType == CoinListContainerType.CoinJoinTabViewModel; RefreshSmartCoinStatus(); Disposables = new CompositeDisposable(); _coinJoinInProgress = Model .WhenAnyValue(x => x.CoinJoinInProgress) .ToProperty(this, x => x.CoinJoinInProgress, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _unspent = Model .WhenAnyValue(x => x.Unspent) .ToProperty(this, x => x.Unspent, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _confirmed = Model .WhenAnyValue(x => x.Confirmed) .ToProperty(this, x => x.Confirmed, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _cluster = Model .WhenAnyValue(x => x.Clusters, x => x.Clusters.Labels) .Select(x => x.Item2.ToString()) .ToProperty(this, x => x.Clusters, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _unavailable = Model .WhenAnyValue(x => x.Unavailable) .ToProperty(this, x => x.Unavailable, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); this.WhenAnyValue(x => x.Status) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => this.RaisePropertyChanged(nameof(ToolTip))); Observable .Merge(Model.WhenAnyValue(x => x.IsBanned, x => x.SpentAccordingToBackend, x => x.Confirmed, x => x.CoinJoinInProgress).Select(_ => Unit.Default)) .Merge(Observable.FromEventPattern(Global.ChaumianClient, nameof(Global.ChaumianClient.StateUpdated)).Select(_ => Unit.Default)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => RefreshSmartCoinStatus()) .DisposeWith(Disposables); Global.BitcoinStore.SmartHeaderChain .WhenAnyValue(x => x.TipHeight).Select(_ => Unit.Default) .Merge(Model.WhenAnyValue(x => x.Height).Select(_ => Unit.Default)) .Throttle(TimeSpan.FromSeconds(0.1)) // DO NOT TAKE THIS THROTTLE OUT, OTHERWISE SYNCING WITH COINS IN THE WALLET WILL STACKOVERFLOW! .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => this.RaisePropertyChanged(nameof(Confirmations))) .DisposeWith(Disposables); Global.UiConfig .WhenAnyValue(x => x.LurkingWifeMode) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { this.RaisePropertyChanged(nameof(AmountBtc)); this.RaisePropertyChanged(nameof(Clusters)); }).DisposeWith(Disposables); DequeueCoin = ReactiveCommand.Create(() => Owner.PressDequeue(Model), this.WhenAnyValue(x => x.CoinJoinInProgress)); _expandMenuCaption = this .WhenAnyValue(x => x.IsExpanded) .Select(x => (x ? "Hide " : "Show ") + "Details") .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.ExpandMenuCaption) .DisposeWith(Disposables); ToggleDetails = ReactiveCommand.Create(() => IsExpanded = !IsExpanded); ToggleDetails.ThrownExceptions .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => { NotificationHelpers.Error(ex.ToTypeMessageString()); Logging.Logger.LogWarning(ex); }); DequeueCoin.ThrownExceptions .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => Logging.Logger.LogError(ex)); // Don't notify about it. Dequeue failure (and success) is notified by other mechanism. }
public CoinViewModel(Wallet wallet, CoinListViewModel owner, SmartCoin model) { Global = Locator.Current.GetService <Global>(); Model = model; Wallet = wallet; Owner = owner; RefreshSmartCoinStatus(); Disposables = new CompositeDisposable(); _coinJoinInProgress = Model .WhenAnyValue(x => x.CoinJoinInProgress) .ToProperty(this, x => x.CoinJoinInProgress, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _unspent = Model .WhenAnyValue(x => x.Unspent) .ToProperty(this, x => x.Unspent, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _confirmed = Model .WhenAnyValue(x => x.Confirmed) .ToProperty(this, x => x.Confirmed, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _cluster = Model .WhenAnyValue(x => x.Clusters, x => x.Clusters.Labels) .Select(x => x.Item2.ToString()) .ToProperty(this, x => x.Clusters, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _unavailable = Model .WhenAnyValue(x => x.Unavailable) .ToProperty(this, x => x.Unavailable, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); this.WhenAnyValue(x => x.Status) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => this.RaisePropertyChanged(nameof(ToolTip))); Observable .Merge(Model.WhenAnyValue(x => x.IsBanned, x => x.SpentAccordingToBackend, x => x.Confirmed, x => x.CoinJoinInProgress).Select(_ => Unit.Default)) .Merge(Observable.FromEventPattern(Wallet.ChaumianClient, nameof(Wallet.ChaumianClient.StateUpdated)).Select(_ => Unit.Default)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => RefreshSmartCoinStatus()) .DisposeWith(Disposables); Global.BitcoinStore.SmartHeaderChain .WhenAnyValue(x => x.TipHeight).Select(_ => Unit.Default) .Merge(Model.WhenAnyValue(x => x.Height).Select(_ => Unit.Default)) .Throttle(TimeSpan.FromSeconds(0.1)) // DO NOT TAKE THIS THROTTLE OUT, OTHERWISE SYNCING WITH COINS IN THE WALLET WILL STACKOVERFLOW! .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => this.RaisePropertyChanged(nameof(Confirmations))) .DisposeWith(Disposables); Global.UiConfig .WhenAnyValue(x => x.LurkingWifeMode) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { this.RaisePropertyChanged(nameof(AmountBtc)); this.RaisePropertyChanged(nameof(Clusters)); }).DisposeWith(Disposables); DequeueCoin = ReactiveCommand.Create(() => Owner.PressDequeue(Model), this.WhenAnyValue(x => x.CoinJoinInProgress)); OpenCoinInfo = ReactiveCommand.Create(() => { var shell = IoC.Get <IShell>(); var coinInfo = shell.Documents?.OfType <CoinInfoTabViewModel>()?.FirstOrDefault(x => x.Coin?.Model == Model); if (coinInfo is null) { coinInfo = new CoinInfoTabViewModel(this); shell.AddDocument(coinInfo); } shell.Select(coinInfo); }); CopyClusters = ReactiveCommand.CreateFromTask(async() => await Application.Current.Clipboard.SetTextAsync(Clusters)); Observable .Merge(DequeueCoin.ThrownExceptions) // Don't notify about it. Dequeue failure (and success) is notified by other mechanism. .Merge(OpenCoinInfo.ThrownExceptions) .Merge(CopyClusters.ThrownExceptions) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => Logger.LogError(ex)); }