public CreateFileViewModel(ISessionService applicationService, IAlertDialogFactory alertDialogFactory) { Title = "Create File"; this.WhenAnyValue(x => x.Name).Subscribe(x => CommitMessage = "Created " + x); _canCommit = this.WhenAnyValue(x => x.Name) .Select(x => !string.IsNullOrEmpty(x)) .ToProperty(this, x => x.CanCommit); SaveCommand = ReactiveCommand.CreateAsyncTask( this.WhenAnyValue(x => x.Name).Select(x => !string.IsNullOrEmpty(x)), async _ => { var content = Content ?? string.Empty; var path = Path; if (string.IsNullOrEmpty(Path)) path = "/"; path = System.IO.Path.Combine(path, Name); var request = applicationService.Client.Users[RepositoryOwner].Repositories[RepositoryName].UpdateContentFile(path, CommitMessage, content, null, Branch); await applicationService.Client.ExecuteAsync(request); Dismiss(); }); DismissCommand = ReactiveCommand.CreateAsyncTask(async t => { if (string.IsNullOrEmpty(Name) && string.IsNullOrEmpty(Content)) return true; return await alertDialogFactory.PromptYesNo("Discard File?", "Are you sure you want to discard this file?"); }); DismissCommand.Where(x => x).Subscribe(_ => Dismiss()); }
public AgentAnnotationViewModel(ISharedDataService sharedDataService, MeetingViewModel meeting) : base(sharedDataService, meeting) { _annotations = new ReactiveList<AnnotationViewModel>(); var annotationsChangedObs = _annotations .WhenAnyObservable(p => p.Changed) .Select(p => AreThereAnnotationInTheCurrentPage()); var activeToolObs = Meeting.WhenAnyValue(vm => vm.ActiveTool).Where(t => t != null); var pageChangedObs = activeToolObs .Select(t => t.WhenAnyValue(v => v.CurrentPageNumber, p => AreThereAnnotationInTheCurrentPage())) .Switch(); // Only listen to the most recent sequence of property changes (active tool) var toolChangedObs = activeToolObs.Select(t => AreThereAnnotationInTheCurrentPage()); _containsAnnotationsForCurrentPage = toolChangedObs.Merge(pageChangedObs).Merge(annotationsChangedObs) .ToProperty(this, p => p.ContainsAnnotationsForCurrentPage); AnnotationTools = new AnnotationToolViewModel(this); // when the IsEditing flag changes to false, it means an edit has just completed and we can send // the updates annotations to the client _isEditingSub = this.WhenAnyValue(p => p.IsEditing) .Where(p => !p) .Subscribe(_ => UpdateAnnotationModelAnnotations()); }
public OAuthFlowLoginViewModel( IAccountsRepository accountsRepository, IActionMenuFactory actionMenuService, IAlertDialogFactory alertDialogService) { _accountsRepository = accountsRepository; _alertDialogService = alertDialogService; Title = "Login"; var oauthLogin = ReactiveCommand.Create().WithSubscription(_ => NavigateTo(this.CreateViewModel<OAuthTokenLoginViewModel>())); var canLogin = this.WhenAnyValue(x => x.Code).Select(x => !string.IsNullOrEmpty(x)); var loginCommand = ReactiveCommand.CreateAsyncTask(canLogin,_ => Login(Code)); loginCommand.Subscribe(x => MessageBus.Current.SendMessage(new LogoutMessage())); LoginCommand = loginCommand; ShowLoginOptionsCommand = ReactiveCommand.CreateAsyncTask(sender => { var actionMenu = actionMenuService.Create(); actionMenu.AddButton("Login via Token", oauthLogin); return actionMenu.Show(sender); }); _loginUrl = this.WhenAnyValue(x => x.WebDomain) .IsNotNull() .Select(x => x.TrimEnd('/')) .Select(x => string.Format(x + "/login/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}", ClientId, Uri.EscapeDataString(RedirectUri), Uri.EscapeDataString(string.Join(",", OctokitClientFactory.Scopes)))) .ToProperty(this, x => x.LoginUrl); WebDomain = DefaultWebDomain; }
/// <summary> /// Initializes a new instance of the <see cref="PlaylistViewModel" /> class. /// </summary> /// <param name="playlist">The playlist info.</param> /// <param name="renameRequest"> /// A function that requests the rename of the playlist. Return true, if the rename is /// granted, otherwise false. /// </param> public PlaylistViewModel(Playlist playlist, Func<string, bool> renameRequest) { this.playlist = playlist; this.renameRequest = renameRequest; this.disposable = new CompositeDisposable(); this.entries = playlist .CreateDerivedCollection(entry => new PlaylistEntryViewModel(entry)) .DisposeWith(this.disposable); this.entries.ItemsRemoved.Subscribe(x => x.Dispose()); this.playlist.WhenAnyValue(x => x.CurrentSongIndex).ToUnit() .Merge(this.entries.Changed.ToUnit()) .Subscribe(_ => this.UpdateCurrentSong()) .DisposeWith(this.disposable); IObservable<List<PlaylistEntryViewModel>> remainingSongs = this.entries.Changed .Select(x => Unit.Default) .Merge(this.playlist.WhenAnyValue(x => x.CurrentSongIndex).ToUnit()) .Select(x => this.entries.Reverse().TakeWhile(entry => !entry.IsPlaying).ToList()); this.songsRemaining = remainingSongs .Select(x => x.Count) .ToProperty(this, x => x.SongsRemaining) .DisposeWith(this.disposable); this.timeRemaining = remainingSongs .Select(x => x.Any() ? x.Select(entry => entry.Duration).Aggregate((t1, t2) => t1 + t2) : (TimeSpan?)null) .ToProperty(this, x => x.TimeRemaining) .DisposeWith(this.disposable); this.CurrentPlayingEntry = this.Model.WhenAnyValue(x => x.CurrentSongIndex).Select(x => x == null ? null : this.entries[x.Value]); }
public InsertGistViewModel() { //var client = new GitHubClient() { Username = "******", Password = "******" }; var privateImage = new BitmapImage(new Uri(@"pack://*****:*****@"pack://application:,,,/data/public.png")); _PublicPrivateIcon = this.WhenAny(x => x.IsPrivateGist, x => x.Value) .Select(x => x ? privateImage : publicImage) .ToProperty(this, x => x.PublicPrivateIcon); CreateGist = new ReactiveAsyncCommand(); CreateGist.RegisterAsyncObservable(_ => client.CreateGist(SelectionText, !IsPrivateGist)) .Select(x => x.html_url) .BindTo(this, x => x.LastGistUrl); CopyToClipboard = new ReactiveCommand( this.WhenAny(x => x.LastGistUrl, x => !String.IsNullOrWhiteSpace(x.Value))); CopyToClipboard.Subscribe(_ => Clipboard.SetText(LastGistUrl)); this.WhenAny(x => x.SelectionText, x => x.Value) .Where(_ => LastGistUrl != null) .Subscribe(_ => LastGistUrl = null); }
public void OAPHShouldRethrowErrors() { var input = new Subject<int>(); var sched = new TestScheduler(); var fixture = new ObservableAsPropertyHelper<int>(input, _ => { }, -5, sched); Assert.AreEqual(-5, fixture.Value); (new[] { 1, 2, 3, 4 }).Run(x => input.OnNext(x)); sched.Run(); Assert.AreEqual(4, fixture.Value); input.OnError(new Exception("Die!")); sched.Run(); try { Assert.AreEqual(4, fixture.Value); } catch { return; } Assert.Fail("We should've threw there"); }
public Threshold(IObservable<int> thresholdState) { //this.WhenAny(vm => vm.Good, vm => vm.Bad, vm => vm.OK, (g, b, o) => //{ //}); this.Good = new Range(); this.Bad = new Range(); this.OK = new Range(); var obs = thresholdState.Select(value => { if (value.Between(this.Good.Min, this.Good.Max)) return "Good"; if (value.Between(this.OK.Min, this.ok.Max)) return "OK"; if (value.Between(this.Bad.Min, this.bad.Max)) return "Bad"; return ""; }); this.state = obs.ToProperty(this, vm => vm.State); obs.Subscribe(_ => { Trace.WriteLine(_); }); }
public TreePageViewModel(TreeNode[] nodes) { Nodes = nodes; _details = this.WhenAnyValue(x => x.SelectedNode) .Select(x => x != null ? new ControlDetailsViewModel(x.Control) : null) .ToProperty(this, x => x.Details); }
public MainViewModel() { _multiEngine = this.ObservableToProperty( Engines.Changed.Select(_ => Engines.Count > 1), vm => vm.MultiEngine); _singleEngine = this.ObservableToProperty( Engines.Changed.Select(_ => Engines.Count == 1), vm => vm.SingleEngine); _languages = this.ObservableToProperty( this.ObservableForProperty(vm => vm.SelectedEngine) .Select(_ => SelectedEngine.Value.Languages), vm => vm.Languages); _languages.Subscribe(_ => EnsureLanguage()); Engines.Changed.Subscribe(_ => EnsureEngine()); Observable.Merge( this.ObservableForProperty(vm => vm.DesignTimeMode).IgnoreValues(), this.ObservableForProperty(vm => vm.SelectedEngine).IgnoreValues(), this.ObservableForProperty(vm => vm.SelectedLanguage).IgnoreValues(), this.ObservableForProperty(vm => vm.RazorCode).IgnoreValues()) .ObserveOn(RxApp.DeferredScheduler) .Subscribe(_ => Regenerate()); this.PropertyChanged += MainViewModel_PropertyChanged; }
public SettingsViewModel( IScreen screen, ISettingsProvider settingsProvider, IFolderHelper folderHelper, IAppContext appContext) { HostScreen = screen; BackCommand = new ReactiveAsyncCommand(); BackCommand.RegisterAsyncAction(_ => HostScreen.Router.NavigateBack.Execute(null)); SelectFolder = new ReactiveAsyncCommand(); SelectFolder.RegisterAsyncAction(_ => { var result = folderHelper.SelectFolder(); if (result.Result == true) { UpdateLocation = result.Folder; } }, appContext.DispatcherScheduler); UpdateLocation = settingsProvider.UpdateLocation; _IsError = this.WhenAny(vm => vm.UpdateLocation, vm => vm.Value) .DistinctUntilChanged() .Throttle(TimeSpan.FromMilliseconds(500)) .ObserveOn(appContext.DispatcherScheduler) .Select(text => !IsUrlOrFolder(text)) .Do(error => { if (!error) { settingsProvider.UpdateLocation = UpdateLocation; } }) .ToProperty(this, vm => vm.IsError, setViaReflection: false); }
public MyIssuesViewModel(ISessionService sessionService) : base(sessionService) { _sessionService = sessionService; Title = "My Issues"; Filter = MyIssuesFilterModel.CreateOpenFilter(); _selectedFilter = this.WhenAnyValue(x => x.Filter) .Select(x => { if (x == null || _openFilter.Equals(x)) return 0; return _closedFilter.Equals(x) ? 1 : -1; }) .ToProperty(this, x => x.SelectedFilter); this.WhenAnyValue(x => x.Filter).Skip(1).Subscribe(filter => { InternalItems.Clear(); LoadCommand.ExecuteIfCan(); CustomFilterEnabled = !(filter == _closedFilter || filter == _openFilter); }); GoToFilterCommand = ReactiveCommand.Create(); GoToFilterCommand.Subscribe(_ => { var vm = this.CreateViewModel<MyIssuesFilterViewModel>(); vm.Init(Filter); vm.SaveCommand.Subscribe(filter => Filter = filter); NavigateTo(vm); }); }
public IndexViewModel(IRepository repo) { this.repo = repo; this.refreshCommand = ReactiveCommand.Create(); this.repositoryStatus = this.refreshCommand.Select(u => { return repo.RetrieveStatus(new StatusOptions() { Show = StatusShowOption.IndexAndWorkDir }); }).ToProperty(this, vm => vm.RepositoryStatus); this.statusEntries = this .WhenAny(vm => vm.RepositoryStatus, change => { var status = change.GetValue(); return status.CreateDerivedCollection(s => s, null, null, null, this.refreshCommand); }).ToProperty(this, vm => vm.StatusEntries); var resetSignal = this.WhenAny(vm => vm.StatusEntries, change => { return 0; }); var allEntries = this.WhenAny(vm => vm.StatusEntries, change => change.GetValue()); this.unstagedEntries = allEntries.Select(s => { return s.CreateDerivedCollection(i => i, i => Unstaged(i.State), null, resetSignal); }).ToProperty(this, vm => vm.UnstagedEntries); this.stagedEntries = allEntries.Select(s => { return s.CreateDerivedCollection(i => i, i => Staged(i.State), null, resetSignal); }).ToProperty(this, vm => vm.StagedEntries); }
public ClientAnnotationViewModel(ISharedDataService sharedDataService, MeetingViewModel meeting) : base(sharedDataService, meeting) { // create the client annotations property, a mapped version of the agent's properties based on the screen sizes. _annotationsChangedSub = _clientAnnotations = AnnotationsModel .WhenAnyValue(v => v.Annotations, v => v.Select(p => CreateAnnotationViewModel(p))) .ToProperty(this, v => v.Annotations); }
public VisualTreeViewModel(Control root) { Nodes = VisualTreeNode.Create(root); _details = this.WhenAnyValue(x => x.SelectedNode) .Select(x => x != null ? new ControlDetailsViewModel(x.Control) : null) .ToProperty(this, x => x.Details); }
public CountryViewModel(string name, float population, Task<IBitmap> countryFlag, double longitude, double latitude) : base(name, population, longitude, latitude) { this.countryFlag = countryFlag .ToObservable() .ToProperty(this, x => x.CountryFlag); }
public GistCreationViewModel( IRepositoryHost repositoryHost, ISelectedTextProvider selectedTextProvider, IGistPublishService gistPublishService, IUsageTracker usageTracker) { Title = Resources.CreateGistTitle; apiClient = repositoryHost.ApiClient; this.gistPublishService = gistPublishService; this.usageTracker = usageTracker; FileName = VisualStudio.Services.GetFileNameFromActiveDocument() ?? Resources.DefaultGistFileName; SelectedText = selectedTextProvider.GetSelectedText(); // This class is only instantiated after we are logged into to a github account, so we should be safe to grab the first one here as the defaut. account = repositoryHost.ModelService.GetAccounts() .FirstAsync() .Select(a => a.First()) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, vm => vm.Account); var canCreateGist = this.WhenAny( x => x.FileName, fileName => !String.IsNullOrEmpty(fileName.Value)); CreateGist = ReactiveCommand.CreateAsyncObservable(canCreateGist, OnCreateGist); }
public LoginRouteViewModel(IScreen hostScreen) { HostScreen = hostScreen; var authentication = new Authentication(); var canLogin = this.WhenAny(x => x.LoginName, x => x.Password, (l, p) => !String.IsNullOrWhiteSpace(l.Value) && !String.IsNullOrWhiteSpace(p.Value)); LoginCommand = new ReactiveCommand(canLogin); var loggedIn = LoginCommand.RegisterAsync(_ => Observable.Start(() => { var authenticationResult = authentication.AuthenticateAsync(LoginName, Password). Result; return authenticationResult == AuthenticationResult.Authenticated ? "Přihlášen" : "Nepřihlášen"; })); loggedIn.Subscribe(s => { if (s == "Přihlášen") HostScreen.Router.Navigate.Execute(new PersonListViewModel(HostScreen)); }); message = new ObservableAsPropertyHelper<string>(loggedIn, s => raisePropertyChanged("Message")); }
public SoundCloudSongViewModel(SoundCloudSong model) : base(model) { this.hasThumbnail = this.WhenAnyValue(x => x.Thumbnail) .Select(x => x != null) .ToProperty(this, x => x.HasThumbnail); }
public MainWindowViewModel() { var whenAnyColorChanges = this.WhenAny(x => x.Red, x => x.Green, x => x.Blue, (r, g, b) => Tuple.Create(r.Value, g.Value, b.Value)) .Select(intsToColor); _FinalColor = whenAnyColorChanges .Where(x => x != null) .Select(x => x.Value) .ToProperty(this, x => x.FinalColor); Ok = ReactiveCommand.Create(whenAnyColorChanges.Select(x => x != null)); _Images = this.WhenAny(x => x.FinalColor, x => x.Value) .Throttle(TimeSpan.FromSeconds(0.7), RxApp.MainThreadScheduler) .Do(_ => IsBusy = true) .Select(x => imagesForColor(x)) .Switch() .SelectMany(imageListToImages) .ObserveOn(RxApp.MainThreadScheduler) .Do(_ => IsBusy = false) .ToProperty(this, x => x.Images); _Images.ThrownExceptions.Subscribe(ex => this.Log().WarnException("Can't load images", ex)); }
public YoutubeSongViewModel(YoutubeSong wrapped, Func<string> downloadPathFunc) : base(wrapped) { this.hasThumbnail = this.WhenAnyValue(x => x.Thumbnail) .Select(x => x != null) .ToProperty(this, x => x.HasThumbnail); // Wait for the opening of the context menu to download the YouTube information this.WhenAnyValue(x => x.IsContextMenuOpen) .FirstAsync(x => x) .SelectMany(_ => this.LoadContextMenu().ToObservable()) .Subscribe(); // We have to set a dummy here, so that we can connect the commands this.isDownloading = Observable.Never<bool>().ToProperty(this, x => x.IsDownloading); this.DownloadVideoCommand = ReactiveCommand.CreateAsyncTask(this.WhenAnyValue(x => x.IsDownloading).Select(x => !x), x => this.DownloadVideo((VideoInfo)x, downloadPathFunc())); this.DownloadAudioCommand = ReactiveCommand.CreateAsyncTask(this.WhenAnyValue(x => x.IsDownloading).Select(x => !x), x => this.DownloadAudio((VideoInfo)x, downloadPathFunc())); this.isDownloading = this.DownloadVideoCommand.IsExecuting .CombineLatest(this.DownloadAudioCommand.IsExecuting, (x1, x2) => x1 || x2) .ToProperty(this, x => x.IsDownloading); }
public DevToolsViewModel(IControl root) { _logicalTree = new TreePageViewModel(LogicalTreeNode.Create(root)); _visualTree = new TreePageViewModel(VisualTreeNode.Create(root)); this.WhenAnyValue(x => x.SelectedTab).Subscribe(index => { switch (index) { case 0: Content = _logicalTree; break; case 1: Content = _visualTree; break; } }); _focusedControl = KeyboardDevice.Instance .WhenAnyValue(x => x.FocusedElement) .Select(x => x?.GetType().Name) .ToProperty(this, x => x.FocusedControl); _pointerOverElement = root.GetObservable(TopLevel.PointerOverElementProperty) .Select(x => x?.GetType().Name) .ToProperty(this, x => x.PointerOverElement); }
public MiniMainWindowViewModel(ITrayMainWindowViewModel trayMainWindowViewModel) { TrayViewModel = trayMainWindowViewModel; _taskbarToolTip = this.WhenAnyValue(x => x.DisplayName, x => x.TrayViewModel.Status, trayMainWindowViewModel.FormatTaskbarToolTip) .ToProperty(this, x => x.TaskbarToolTip); OpenPopup = ReactiveCommand.Create(); ShowNotification = ReactiveCommand.CreateAsyncTask(async x => (ITrayNotificationViewModel) x); Deactivate = ReactiveCommand.Create().DefaultSetup("Deactivate"); Deactivate.Subscribe(x => { if (TrayViewModel.MainArea is IWelcomeViewModel) return; Close.Execute(null); }); OpenPopup .Take(1) .Delay(TimeSpan.FromSeconds(20)) .ObserveOnMainThread() .Subscribe(x => TrayViewModel.RemoveUpdatedState()); // TODO: Make this a setting? /* Listen<ApiUserActionStarted>() .ObserveOnMainThread() .InvokeCommand(OpenPopup);*/ Listen<AppStateUpdated>() .Where(x => x.UpdateState == AppUpdateState.Updating) .ObserveOnMainThread() .InvokeCommand(OpenPopup); Listen<ShowTrayNotification>() .Select(x => new TrayNotificationViewModel(x.Subject, x.Text, x.CloseIn, x.Actions)) .ObserveOnMainThread() .InvokeCommand(ShowNotification); }
public TrayMainWindowViewModel(IViewModel mainArea, TrayMainWindowMenu menu, IStatusViewModel status, LoginInfo loginInfo, IWelcomeViewModel welcomeViewModel) { _mainArea = Consts.FirstRun /* || Cheat.Consts.IsTestVersion */ ? welcomeViewModel : mainArea; _menu = menu; _status = status; _loginInfo = loginInfo; welcomeViewModel.Close.Subscribe(x => MainArea = mainArea); _taskbarToolTip = this.WhenAnyValue(x => x.DisplayName, x => x.Status, FormatTaskbarToolTip) .ToProperty(this, x => x.TitleToolTip); _avatarUrl = this.WhenAnyValue<TrayMainWindowViewModel, Uri, AccountInfo>(x => x.LoginInfo.Account, x => new Uri("http:" + AvatarCalc.GetAvatarURL(x))) .ToProperty(this, x => x.AvatarUrl); _installUpdate = ReactiveCommand.CreateAsyncTask( this.WhenAnyValue(x => x.UpdateState, state => state == AppUpdateState.UpdateAvailable), async x => await RequestAsync(new OpenWebLink(ViewType.Update)).ConfigureAwait(false)) .DefaultSetup("InstallUpdate"); _goAccount = ReactiveCommand.CreateAsyncTask( async x => await RequestAsync(new OpenWebLink(ViewType.Profile)).ConfigureAwait(false)) .DefaultSetup("OpenProfile"); _goPremium = ReactiveCommand.CreateAsyncTask( async x => await RequestAsync( new OpenWebLink(_loginInfo.IsPremium ? ViewType.PremiumAccount : ViewType.GoPremium)) .ConfigureAwait(false)) .DefaultSetup("GoPremium"); IViewModel previousMain = null; _switchQueue = ReactiveCommand.CreateAsyncTask( async x => { if (previousMain == null) { previousMain = _mainArea; MainArea = await RequestAsync(new GetQueue()).ConfigureAwait(false); } else { MainArea = previousMain; previousMain = null; } }); status.SwitchQueue = _switchQueue; // TODO.. Listen<LoginChanged>() .Select(x => x.LoginInfo) .ObserveOnMainThread() .BindTo(this, x => x.LoginInfo); // We need to receive these right away.. // toDO: Think about how to make this only on WhenActivated Listen<AppStateUpdated>() .Select(x => x.UpdateState) .ObserveOnMainThread() .BindTo(this, x => x.UpdateState); }
public DownloadVM( IDiversityServiceClient Service, IConnectivityService Connectivity, IFieldDataService Storage, IKeyMappingService Mappings, EventHierarchyLoader HierarchyLoader, [Dispatcher] IScheduler Dispatcher ) { this.Service = Service; this.Connectivity = Connectivity; this.Storage = Storage; this.Mappings = Mappings; this.HierarchyLoader = HierarchyLoader; QueryResult = new ReactiveCollection<Event>(); _IsOnlineAvailable = Connectivity.Status().Select(s => s == ConnectionStatus.Wifi).Do(_ => { this.GetType(); }, ex => { }, () => { }) .ToProperty(this, x => x.IsOnlineAvailable); SearchEvents = new ReactiveAsyncCommand(this.WhenAny(x => x.IsOnlineAvailable, x => x.Value)); SearchEvents.ShowInFlightNotification(Notifications, DiversityResources.Download_SearchingEvents); SearchEvents.ThrownExceptions .ShowServiceErrorNotifications(Notifications) .ShowErrorNotifications(Notifications) .Subscribe(); SearchEvents .RegisterAsyncObservable(query => Service.GetEventsByLocality(query as string ?? string.Empty) .TakeUntil(this.OnDeactivation()) ) .Do(_ => QueryResult.Clear()) .Subscribe(QueryResult.AddRange); CancelDownload = new ReactiveCommand(); DownloadElement = new ReactiveAsyncCommand(this.WhenAny(x => x.IsOnlineAvailable, x => x.Value)); DownloadElement.ThrownExceptions .ShowServiceErrorNotifications(Notifications) .ShowErrorNotifications(Notifications) .Subscribe(); DownloadElement .RegisterAsyncObservable(ev => IfNotDownloadedYet(ev as Event) .Select(HierarchyLoader.downloadAndStoreDependencies) .SelectMany(dl => dl.TakeUntil(CancelDownload)) .Scan(0, (acc, _) => ++acc) .Do(_ElementsDownloadedSubject.OnNext) ); _IsDownloading = DownloadElement.ItemsInflight .Select(x => x > 0) .ToProperty(this, x => x.IsDownloading); this.OnDeactivation() .Subscribe(_ => Messenger.SendMessage(EventMessage.Default, MessageContracts.INIT)); _ElementsDownloadedSubject = new Subject<int>(); _ElementsDownloaded = _ElementsDownloadedSubject.ToProperty(this, x => x.ElementsDownloaded, 0, Dispatcher); }
public SettingsViewModel(IEnumerable<ISettingsTabViewModel> settingsTabs) { var settings = settingsTabs.OrderBy(GetOrder).ToArray(); Settings = new SelectionCollectionHelper<ISettingsTabViewModel>(settings) { SelectedItem = settings.FirstOrDefault() }; _valid = settings.Select(x => x.WhenAnyValue(s => s.IsValid)) .CombineLatest(x => x.All(b => b)) .ToProperty(this, x => x.Valid); }
public ViewModelViewHost() { this.currentView = new SerialDisposable(); this.viewContract = this .WhenAnyObservable(x => x.ViewContractObservable) .ToProperty(this, x => x.ViewContract, scheduler: RxApp.MainThreadScheduler); this.Initialize(); }
public CachingStateVm(CachingState cachingState) { _cachingState = cachingState; var progress = cachingState.Progress; _finalSize = progress.Select(x => x.Total).ToProperty(this, x => x.FinalSize); _cachedSize = progress.Select(x => x.Current).ToProperty(this, x => x.CachedSize); _isFullyCached = progress.Select(x => x.Current != 0UL && x.Current == x.Total).ToProperty(this, x => x.IsFullyCached, false); _isInitialized = this.WhenAny(x => x.FinalSize, ch => ch.Value > 0).ToProperty(this, x => x.IsInitialized, false); }
public DispatchViewModel(IScreen screen, ISession session) { HostScreen = screen; GoBack = HostScreen.Router.NavigateBack; Techs = new ReactiveList<Employee>(); Tickets = new ReactiveList<Ticket>(); var getFreshTechs = new ReactiveCommand(); getFreshTechs.ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ => { Techs.Clear(); session.FetchResults<Employee>() .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => Techs.Add(x)); }); var getFreshTickets = new ReactiveCommand(); getFreshTickets.ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ => { Tickets.Clear(); session.FetchResults<Ticket>() .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => Tickets.Add(x)); }); Refresh = new ReactiveCommand(session.IsWorking.Select(x => !x)); Refresh.Subscribe(_ => { getFreshTechs.Execute(default(object)); getFreshTickets.Execute(default(object)); }); Assign = new ReactiveCommand(Observable.CombineLatest( this.WhenAny( x => x.SelectedEmployee, y => y.SelectedTicket, (x, y) => x.Value != null && y.Value != null), Refresh.CanExecuteObservable, (x, y) => x && y)); Assign.Subscribe(_ => { using (session.ScopedChanges()) { var eventTaker = session.Take<TicketEvent>(); eventTaker.Add(new TicketEvent { Employee = SelectedEmployee, Ticket = SelectedTicket, TicketStatus = TicketStatus.Assigned, Time = DateTime.Now }); } }); _error = session.ThrownExceptions .Select(x => x.Message) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.Error); Refresh.Execute(default(object)); }
public MainWindowViewModel(ILeapMotionService leapMotionService) { this.leapMotionService = leapMotionService; this._fingersDetected = leapMotionService.FingersDetected.ToProperty(this, x => x.FingersDetected); this.Disposables.Add(this._fingersDetected); this._velocity = leapMotionService.SmoothedVelocity.ToProperty(this, x => x.Velocity); this.Disposables.Add(this._velocity); }
protected override void OnInitialize() { base.OnInitialize(); _selectedItem = _mvm.Value.LibraryVM.WhenAnyValue(x => x.SelectedItem.SelectedItem) .OfType<IMod>() .ToProperty(this, x => x.SelectedItem); _isInCollection = this.WhenAny(x => x.SelectedItem, x => x.Value is ToggleableModProxy) .ToProperty(this, x => x.IsInCollection); }
public MainViewModel( ProviderViewModelFactory providerFactory, AuthViewModelFactory authFactory, IProviderStorage storage, IScheduler current, IScheduler main) { _storage = storage; _refresh = ReactiveCommand.CreateFromTask( storage.Refresh, outputScheduler: main); var providers = storage.Read(); providers.Transform(x => providerFactory(x, authFactory(x))) .Sort(SortExpressionComparer <IProviderViewModel> .Descending(x => x.Created)) .ObserveOn(RxApp.MainThreadScheduler) .StartWithEmpty() .Bind(out _providers) .Subscribe(); _isLoading = _refresh .IsExecuting .ToProperty(this, x => x.IsLoading, scheduler: current); _isReady = _refresh .IsExecuting .Skip(1) .Select(executing => !executing) .ToProperty(this, x => x.IsReady, scheduler: current); providers.Where(changes => changes.Any()) .ObserveOn(RxApp.MainThreadScheduler) .OnItemAdded(x => SelectedProvider = Providers.FirstOrDefault()) .OnItemRemoved(x => SelectedProvider = null) .Subscribe(); var canRemove = this .WhenAnyValue(x => x.SelectedProvider) .Select(provider => provider != null); _remove = ReactiveCommand.CreateFromTask( () => storage.Remove(SelectedProvider.Id), canRemove); var canAddProvider = this .WhenAnyValue(x => x.SelectedSupportedType) .Select(type => !string.IsNullOrWhiteSpace(type)); _add = ReactiveCommand.CreateFromTask( () => storage.Add(SelectedSupportedType), canAddProvider); _welcomeScreenVisible = this .WhenAnyValue(x => x.SelectedProvider) .Select(provider => provider == null) .ToProperty(this, x => x.WelcomeScreenVisible); _welcomeScreenCollapsed = this .WhenAnyValue(x => x.WelcomeScreenVisible) .Select(visible => !visible) .ToProperty(this, x => x.WelcomeScreenCollapsed); var canUnSelect = this .WhenAnyValue(x => x.SelectedProvider) .Select(provider => provider != null); _unselect = ReactiveCommand.Create( () => { SelectedProvider = null; }, canUnSelect); Activator = new ViewModelActivator(); this.WhenActivated(disposables => { SelectedSupportedType = SupportedTypes.FirstOrDefault(); _refresh.Execute() .Subscribe() .DisposeWith(disposables); }); }
public VortexCompilerVM(CompilerVM parent) { Parent = parent; GameLocation = new FilePickerVM() { ExistCheckOption = FilePickerVM.CheckOptions.On, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Game Folder Location" }; DownloadsLocation = new FilePickerVM() { ExistCheckOption = FilePickerVM.CheckOptions.On, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Downloads Folder" }; StagingLocation = new FilePickerVM() { ExistCheckOption = FilePickerVM.CheckOptions.On, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Staging Folder" }; // Load custom ModList settings when game type changes _modListSettings = (this).WhenAny(x => x.SelectedGame) .Select(game => { if (game == null) { return(null); } var gameSettings = _settings.ModlistSettings.TryCreate(game.Game); return(new ModlistSettingsEditorVM(gameSettings.ModlistSettings)); }) // Interject and save old while loading new .Pairwise() .Do(pair => { var(previous, current) = pair; previous?.Save(); current?.Init(); }) .Select(x => x.Current) // Save to property .ObserveOnGuiThread() .ToProperty(this, nameof(ModlistSettings)); CanCompile = Observable.CombineLatest( this.WhenAny(x => x.GameLocation.InError), this.WhenAny(x => x.DownloadsLocation.InError), this.WhenAny(x => x.StagingLocation.InError), this.WhenAny(x => x.ModlistSettings) .Select(x => x?.InError ?? Observable.Return(false)) .Switch(), (g, d, s, ml) => !g && !d && !s && !ml) .Publish() .RefCount(); // Load settings _settings = parent.MWVM.Settings.Compiler.VortexCompilation; SelectedGame = _gameOptions.FirstOrDefault(x => x.Game == _settings.LastCompiledGame) ?? _gameOptions[0]; parent.MWVM.Settings.SaveSignal .Subscribe(_ => Unload()) .DisposeWith(CompositeDisposable); // Load custom game settings when game type changes (this).WhenAny(x => x.SelectedGame) .Select(game => _settings.ModlistSettings.TryCreate(game.Game)) .Pairwise() .Subscribe(pair => { // Save old var(previous, current) = pair; if (previous != null) { previous.GameLocation = GameLocation.TargetPath; } // Load new GameLocation.TargetPath = current?.GameLocation; if (string.IsNullOrWhiteSpace(GameLocation.TargetPath)) { SetGameToSteamLocation(); } if (string.IsNullOrWhiteSpace(GameLocation.TargetPath)) { SetGameToGogLocation(); } DownloadsLocation.TargetPath = current?.DownloadLocation; if (string.IsNullOrWhiteSpace(DownloadsLocation.TargetPath)) { DownloadsLocation.TargetPath = VortexCompiler.RetrieveDownloadLocation(SelectedGame.Game); } StagingLocation.TargetPath = current?.StagingLocation; if (string.IsNullOrWhiteSpace(StagingLocation.TargetPath)) { StagingLocation.TargetPath = VortexCompiler.RetrieveStagingLocation(SelectedGame.Game); } }) .DisposeWith(CompositeDisposable); // Find game commands FindGameInSteamCommand = ReactiveCommand.Create(SetGameToSteamLocation); FindGameInGogCommand = ReactiveCommand.Create(SetGameToGogLocation); // Add additional criteria to download/staging folders DownloadsLocation.AdditionalError = this.WhenAny(x => x.DownloadsLocation.TargetPath) .Select(path => path == null ? ErrorResponse.Success : VortexCompiler.IsValidDownloadsFolder(path)); StagingLocation.AdditionalError = this.WhenAny(x => x.StagingLocation.TargetPath) .Select(path => path == null ? ErrorResponse.Success : VortexCompiler.IsValidBaseStagingFolder(path)); }
public CoinViewModel(CoinListViewModel owner, Global global, SmartCoin model) { Model = model; Owner = owner; Global = global; 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 ProviderViewModel( CreateFolderViewModelFactory createFolder, RenameFileViewModelFactory createRename, FileViewModelFactory createFile, IAuthViewModel authViewModel, IFileManager fileManager, IProvider provider, IScheduler current, IScheduler main) { _provider = provider; Folder = createFolder(this); Rename = createRename(this); var canInteract = this .WhenAnyValue( x => x.Folder.IsVisible, x => x.Rename.IsVisible, (folder, rename) => !folder && !rename); _canInteract = canInteract .DistinctUntilChanged() .ToProperty(this, x => x.CanInteract, scheduler: current); _refresh = ReactiveCommand.CreateFromTask( () => provider.Get(CurrentPath), canInteract, main); _files = _refresh .Select(files => files .Select(file => createFile(file, this)) .OrderByDescending(file => file.IsFolder) .ThenBy(file => file.Name) .ToList()) .StartWithEmpty() .Where(files => Files == null || files.Count != Files.Count() || !files.All(x => Files.Any(y => x.Path == y.Path && x.Modified == y.Modified))) .ToProperty(this, x => x.Files, scheduler: current); _isLoading = _refresh .IsExecuting .ToProperty(this, x => x.IsLoading, scheduler: current); _isReady = _refresh .IsExecuting .Select(executing => !executing) .Skip(1) .ToProperty(this, x => x.IsReady, scheduler: current); var canOpenCurrentPath = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && file.IsFolder) .CombineLatest(_refresh.IsExecuting, (folder, busy) => folder && !busy) .CombineLatest(canInteract, (open, interact) => open && interact); _open = ReactiveCommand.Create( () => Path.Combine(CurrentPath, SelectedFile.Name), canOpenCurrentPath, main); var canCurrentPathGoBack = this .WhenAnyValue(x => x.CurrentPath) .Select(path => path.Length > provider.InitialPath.Length) .CombineLatest(_refresh.IsExecuting, (valid, busy) => valid && !busy) .CombineLatest(canInteract, (back, interact) => back && interact); _back = ReactiveCommand.Create( () => Path.GetDirectoryName(CurrentPath), canCurrentPathGoBack, main); _currentPath = _open .Merge(_back) .DistinctUntilChanged() .Log(this, $"Current path changed in {provider.Name}") .ToProperty(this, x => x.CurrentPath, provider.InitialPath, scheduler: current); this.WhenAnyValue(x => x.CurrentPath) .Skip(1) .Select(path => Unit.Default) .InvokeCommand(_refresh); this.WhenAnyValue(x => x.CurrentPath) .Subscribe(path => SelectedFile = null); _isCurrentPathEmpty = this .WhenAnyValue(x => x.Files) .Skip(1) .Where(files => files != null) .Select(files => !files.Any()) .ToProperty(this, x => x.IsCurrentPathEmpty, scheduler: current); _hasErrors = _refresh .ThrownExceptions .Select(exception => true) .Merge(_refresh.Select(x => false)) .ToProperty(this, x => x.HasErrors, scheduler: current); var canUploadToCurrentPath = this .WhenAnyValue(x => x.CurrentPath) .Select(path => path != null) .CombineLatest(_refresh.IsExecuting, (up, loading) => up && !loading) .CombineLatest(canInteract, (upload, interact) => upload && interact); _uploadToCurrentPath = ReactiveCommand.CreateFromObservable( () => Observable .FromAsync(fileManager.OpenRead) .Where(response => response.Name != null && response.Stream != null) .Select(x => _provider.UploadFile(CurrentPath, x.Stream, x.Name)) .SelectMany(task => task.ToObservable()), canUploadToCurrentPath, main); _uploadToCurrentPath.InvokeCommand(_refresh); var canDownloadSelectedFile = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && !file.IsFolder) .CombineLatest(_refresh.IsExecuting, (down, loading) => down && !loading) .CombineLatest(canInteract, (download, interact) => download && interact); _downloadSelectedFile = ReactiveCommand.CreateFromObservable( () => Observable .FromAsync(() => fileManager.OpenWrite(SelectedFile.Name)) .Where(stream => stream != null) .Select(stream => _provider.DownloadFile(SelectedFile.Path, stream)) .SelectMany(task => task.ToObservable()), canDownloadSelectedFile, main); var isAuthEnabled = provider.SupportsDirectAuth || provider.SupportsOAuth; var canLogout = provider .IsAuthorized .Select(loggedIn => loggedIn && isAuthEnabled) .DistinctUntilChanged() .CombineLatest(canInteract, (logout, interact) => logout && interact) .ObserveOn(main); _logout = ReactiveCommand.CreateFromTask(provider.Logout, canLogout); _canLogout = canLogout .ToProperty(this, x => x.CanLogout, scheduler: current); var canDeleteSelection = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && !file.IsFolder) .CombineLatest(_refresh.IsExecuting, (del, loading) => del && !loading) .CombineLatest(canInteract, (delete, interact) => delete && interact); _deleteSelectedFile = ReactiveCommand.CreateFromTask( () => provider.Delete(SelectedFile.Path, SelectedFile.IsFolder), canDeleteSelection); _deleteSelectedFile.InvokeCommand(Refresh); var canUnselectFile = this .WhenAnyValue(x => x.SelectedFile) .Select(selection => selection != null) .CombineLatest(_refresh.IsExecuting, (sel, loading) => sel && !loading) .CombineLatest(canInteract, (unselect, interact) => unselect && interact); _unselectFile = ReactiveCommand.Create( () => { SelectedFile = null; }, canUnselectFile); _uploadToCurrentPath .ThrownExceptions .Merge(_deleteSelectedFile.ThrownExceptions) .Merge(_downloadSelectedFile.ThrownExceptions) .Merge(_refresh.ThrownExceptions) .Log(this, $"Exception occured in provider {provider.Name}") .Subscribe(); Auth = authViewModel; Activator = new ViewModelActivator(); this.WhenActivated(disposable => { this.WhenAnyValue(x => x.Auth.IsAuthenticated) .Where(authenticated => authenticated) .Select(ignore => Unit.Default) .InvokeCommand(_refresh) .DisposeWith(disposable); var interval = TimeSpan.FromSeconds(1); Observable.Timer(interval, interval) .Select(unit => RefreshingIn - 1) .Where(value => value >= 0) .ObserveOn(main) .Subscribe(x => RefreshingIn = x) .DisposeWith(disposable); this.WhenAnyValue(x => x.RefreshingIn) .Skip(1) .Where(refreshing => refreshing == 0) .Log(this, $"Refreshing provider {provider.Name} path {CurrentPath}") .Select(value => Unit.Default) .InvokeCommand(_refresh) .DisposeWith(disposable); const int refreshPeriod = 30; _refresh.Select(results => refreshPeriod) .StartWith(refreshPeriod) .Subscribe(x => RefreshingIn = x) .DisposeWith(disposable); this.WhenAnyValue(x => x.CanInteract) .Skip(1) .Where(interact => interact) .Select(x => Unit.Default) .InvokeCommand(_refresh); }); }
public PullRequestCreationViewModel( IModelServiceFactory modelServiceFactory, IPullRequestService service, INotificationService notifications) { Guard.ArgumentNotNull(modelServiceFactory, nameof(modelServiceFactory)); Guard.ArgumentNotNull(service, nameof(service)); Guard.ArgumentNotNull(notifications, nameof(notifications)); this.service = service; this.modelServiceFactory = modelServiceFactory; this.WhenAnyValue(x => x.Branches) .WhereNotNull() .Where(_ => TargetBranch != null) .Subscribe(x => { if (!x.Any(t => t.Equals(TargetBranch))) { TargetBranch = GitHubRepository.IsFork ? GitHubRepository.Parent.DefaultBranch : GitHubRepository.DefaultBranch; } }); SetupValidators(); var whenAnyValidationResultChanges = this.WhenAny( x => x.TitleValidator.ValidationResult, x => x.BranchValidator.ValidationResult, x => x.IsBusy, (x, y, z) => (x.Value?.IsValid ?? false) && (y.Value?.IsValid ?? false) && !z.Value); this.WhenAny(x => x.BranchValidator.ValidationResult, x => x.GetValue()) .WhereNotNull() .Where(x => !x.IsValid && x.DisplayValidationError) .Subscribe(x => notifications.ShowError(BranchValidator.ValidationResult.Message)); CreatePullRequest = ReactiveCommand.CreateAsyncObservable(whenAnyValidationResultChanges, _ => service .CreatePullRequest(modelService, activeLocalRepo, TargetBranch.Repository, SourceBranch, TargetBranch, PRTitle, Description ?? String.Empty) .Catch <IPullRequestModel, Exception>(ex => { log.Error(ex, "Error creating pull request"); //TODO:Will need a uniform solution to HTTP exception message handling var apiException = ex as ApiValidationException; var error = apiException?.ApiError?.Errors?.FirstOrDefault(); notifications.ShowError(error?.Message ?? ex.Message); return(Observable.Empty <IPullRequestModel>()); })) .OnExecuteCompleted(pr => { notifications.ShowMessage(String.Format(CultureInfo.CurrentCulture, Resources.PRCreatedUpstream, SourceBranch.DisplayName, TargetBranch.Repository.Owner + "/" + TargetBranch.Repository.Name + "#" + pr.Number, TargetBranch.Repository.CloneUrl.ToRepositoryUrl().Append("pull/" + pr.Number))); NavigateTo("/pulls?refresh=true"); Cancel.Execute(null); }); Cancel = ReactiveCommand.Create(); isExecuting = CreatePullRequest.IsExecuting.ToProperty(this, x => x.IsExecuting); this.WhenAnyValue(x => x.Initialized, x => x.GitHubRepository, x => x.IsExecuting) .Select(x => !(x.Item1 && x.Item2 != null && !x.Item3)) .Subscribe(x => IsBusy = x); }
public SolutionPatcherVM(ProfileVM parent, SolutionPatcherSettings?settings = null) : base(parent, settings) { CopyInSettings(settings); SolutionPath.Filters.Add(new CommonFileDialogFilter("Solution", ".sln")); SelectedProjectPath.Filters.Add(new CommonFileDialogFilter("Project", ".csproj")); _DisplayName = Observable.CombineLatest( this.WhenAnyValue(x => x.Nickname), this.WhenAnyValue(x => x.SelectedProjectPath.TargetPath) .StartWith(settings?.ProjectSubpath ?? string.Empty), (nickname, path) => { if (!string.IsNullOrWhiteSpace(nickname)) { return(nickname); } try { var name = Path.GetFileName(Path.GetDirectoryName(path)); if (string.IsNullOrWhiteSpace(name)) { return(string.Empty); } return(name); } catch (Exception) { return(string.Empty); } }) .ToProperty(this, nameof(DisplayName), Nickname); AvailableProjects = SolutionPatcherConfigLogic.AvailableProject( this.WhenAnyValue(x => x.SolutionPath.TargetPath)) .ObserveOnGui() .ToObservableCollection(this); var projPath = SolutionPatcherConfigLogic.ProjectPath( solutionPath: this.WhenAnyValue(x => x.SolutionPath.TargetPath), projectSubpath: this.WhenAnyValue(x => x.ProjectSubpath)); projPath .Subscribe(p => SelectedProjectPath.TargetPath = p) .DisposeWith(this); _State = Observable.CombineLatest( this.WhenAnyValue(x => x.SolutionPath.ErrorState), this.WhenAnyValue(x => x.SelectedProjectPath.ErrorState), this.WhenAnyValue(x => x.Profile.Config.MainVM) .Select(x => x.DotNetSdkInstalled) .Switch(), (sln, proj, dotnet) => { if (sln.Failed) { return(new ConfigurationState(sln)); } if (dotnet == null) { return(new ConfigurationState(ErrorResponse.Fail("No dotnet SDK installed"))); } return(new ConfigurationState(proj)); }) .ToGuiProperty <ConfigurationState>(this, nameof(State), new ConfigurationState(ErrorResponse.Fail("Evaluating")) { IsHaltingError = false }); OpenSolutionCommand = ReactiveCommand.Create( canExecute: this.WhenAnyValue(x => x.SolutionPath.InError) .Select(x => !x), execute: () => { try { Process.Start(new ProcessStartInfo(SolutionPath.TargetPath) { UseShellExecute = true, }); } catch (Exception ex) { Log.Logger.Error(ex, $"Error opening solution: {SolutionPath.TargetPath}"); } }); var metaPath = this.WhenAnyValue(x => x.SelectedProjectPath.TargetPath) .Select(projPath => { try { return(Path.Combine(Path.GetDirectoryName(projPath) !, Constants.MetaFileName)); } catch (Exception) { return(string.Empty); } }) .Replay(1) .RefCount(); // Set up meta file sync metaPath .Select(path => { return(Noggog.ObservableExt.WatchFile(path) .StartWith(Unit.Default) .Throttle(TimeSpan.FromMilliseconds(500), RxApp.MainThreadScheduler) .Select(_ => { if (!File.Exists(path)) { return default; } try { return JsonConvert.DeserializeObject <PatcherCustomization>( File.ReadAllText(path), Execution.Constants.JsonSettings); } catch (Exception ex) { Logger.Error(ex, "Error reading in meta"); } return default(PatcherCustomization?); })); }) .Switch() .DistinctUntilChanged() .ObserveOnGui() .Subscribe(info => { if (info == null) { return; } if (info.Nickname != null) { this.Nickname = info.Nickname; } this.LongDescription = info.LongDescription ?? string.Empty; this.ShortDescription = info.OneLineDescription ?? string.Empty; this.Visibility = info.Visibility; this.Versioning = info.PreferredAutoVersioning; this.RequiredMods.SetTo(info.RequiredMods .SelectWhere(x => TryGet <ModKey> .Create(ModKey.TryFromNameAndExtension(x, out var modKey), modKey)) .Select(m => new ModKeyItemViewModel(m))); }) .DisposeWith(this); Observable.CombineLatest( this.WhenAnyValue(x => x.DisplayName), this.WhenAnyValue(x => x.ShortDescription), this.WhenAnyValue(x => x.LongDescription), this.WhenAnyValue(x => x.Visibility), this.WhenAnyValue(x => x.Versioning), this.RequiredMods .ToObservableChangeSet() .Transform(x => x.ModKey) .AddKey(x => x) .Sort(ModKey.Alphabetical, SortOptimisations.ComparesImmutableValuesOnly, resetThreshold: 0) .QueryWhenChanged() .Select(x => x.Items) .StartWith(Enumerable.Empty <ModKey>()), metaPath, (nickname, shortDesc, desc, visibility, versioning, reqMods, meta) => (nickname, shortDesc, desc, visibility, versioning, reqMods: reqMods.Select(x => x.FileName).OrderBy(x => x).ToArray(), meta)) .DistinctUntilChanged() .Throttle(TimeSpan.FromMilliseconds(200), RxApp.MainThreadScheduler) .Skip(1) .Subscribe(x => { try { if (string.IsNullOrWhiteSpace(x.meta)) { return; } File.WriteAllText(x.meta, JsonConvert.SerializeObject( new PatcherCustomization() { OneLineDescription = x.shortDesc, LongDescription = x.desc, Visibility = x.visibility, Nickname = x.nickname, PreferredAutoVersioning = x.versioning, RequiredMods = x.reqMods }, Formatting.Indented, Execution.Constants.JsonSettings)); } catch (Exception ex) { Logger.Error(ex, "Error writing out meta"); } }) .DisposeWith(this); ReloadAutogeneratedSettingsCommand = ReactiveCommand.Create(() => { }); PatcherSettings = new PatcherSettingsVM( Logger, this, projPath .Merge(ReloadAutogeneratedSettingsCommand.EndingExecution() .WithLatestFrom(projPath, (_, p) => p)) .Select(p => GetResponse <string> .Succeed(p)), needBuild: true) .DisposeWith(this); }
public GitHubPaneViewModel( IViewViewModelFactory viewModelFactory, ISimpleApiClientFactory apiClientFactory, IConnectionManager connectionManager, ITeamExplorerContext teamExplorerContext, IVisualStudioBrowser browser, IUsageTracker usageTracker, INavigationViewModel navigator, ILoggedOutViewModel loggedOut, INotAGitHubRepositoryViewModel notAGitHubRepository, INotAGitRepositoryViewModel notAGitRepository) { Guard.ArgumentNotNull(viewModelFactory, nameof(viewModelFactory)); Guard.ArgumentNotNull(apiClientFactory, nameof(apiClientFactory)); Guard.ArgumentNotNull(connectionManager, nameof(connectionManager)); Guard.ArgumentNotNull(teamExplorerContext, nameof(teamExplorerContext)); Guard.ArgumentNotNull(browser, nameof(browser)); Guard.ArgumentNotNull(usageTracker, nameof(usageTracker)); Guard.ArgumentNotNull(navigator, nameof(navigator)); Guard.ArgumentNotNull(loggedOut, nameof(loggedOut)); Guard.ArgumentNotNull(notAGitHubRepository, nameof(notAGitHubRepository)); Guard.ArgumentNotNull(notAGitRepository, nameof(notAGitRepository)); this.viewModelFactory = viewModelFactory; this.apiClientFactory = apiClientFactory; this.connectionManager = connectionManager; this.teamExplorerContext = teamExplorerContext; this.browser = browser; this.usageTracker = usageTracker; this.navigator = navigator; this.loggedOut = loggedOut; this.notAGitHubRepository = notAGitHubRepository; this.notAGitRepository = notAGitRepository; var contentAndNavigatorContent = Observable.CombineLatest( this.WhenAnyValue(x => x.Content), navigator.WhenAnyValue(x => x.Content), (c, nc) => new { Content = c, NavigatorContent = nc }); contentOverride = contentAndNavigatorContent .SelectMany(x => { if (x.Content == null) { return(Observable.Return(ContentOverride.Spinner)); } else if (x.Content == navigator && x.NavigatorContent != null) { return(x.NavigatorContent.WhenAnyValue( y => y.IsLoading, y => y.Error, (l, e) => { if (l) { return ContentOverride.Spinner; } if (e != null) { return ContentOverride.Error; } else { return ContentOverride.None; } })); } else { return(Observable.Return(ContentOverride.None)); } }) .ToProperty(this, x => x.ContentOverride); // Returns navigator.Content if Content == navigator, otherwise null. var currentPage = contentAndNavigatorContent .Select(x => x.Content == navigator ? x.NavigatorContent : null); title = currentPage .SelectMany(x => x?.WhenAnyValue(y => y.Title) ?? Observable.Return <string>(null)) .Select(x => x ?? "GitHub") .ToProperty(this, x => x.Title); isSearchEnabled = currentPage .Select(x => x is ISearchablePageViewModel) .ToProperty(this, x => x.IsSearchEnabled); refresh = ReactiveCommand.CreateAsyncTask( currentPage.SelectMany(x => x?.WhenAnyValue( y => y.IsLoading, y => y.IsBusy, (loading, busy) => !loading && !busy) ?? Observable.Return(false)), _ => navigator.Content.Refresh()); refresh.ThrownExceptions.Subscribe(); showPullRequests = ReactiveCommand.CreateAsyncTask( this.WhenAny(x => x.Content, x => x.Value == navigator), _ => ShowPullRequests()); openInBrowser = ReactiveCommand.Create(currentPage.Select(x => x is IOpenInBrowser)); openInBrowser.Subscribe(_ => { var url = ((IOpenInBrowser)navigator.Content).WebUrl; if (url != null) { browser.OpenUrl(url); } }); navigator.WhenAnyObservable(x => x.Content.NavigationRequested) .Subscribe(x => NavigateTo(x).Forget()); this.WhenAnyValue(x => x.SearchQuery) .Where(x => navigator.Content is ISearchablePageViewModel) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => ((ISearchablePageViewModel)navigator.Content).SearchQuery = x); }
public ReleaseViewModel(IApplicationService applicationService, IUrlRouterService urlRouterService, IActionMenuFactory actionMenuService) { this.WhenAnyValue(x => x.ReleaseModel) .Select(x => { if (x == null) { return("Release"); } var name = string.IsNullOrEmpty(x.Name) ? x.TagName : x.Name; return(name ?? "Release"); }) .Subscribe(x => Title = x); var shareCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.ReleaseModel).Select(x => x != null)); shareCommand.Subscribe(_ => actionMenuService.ShareUrl(ReleaseModel.HtmlUrl)); var gotoUrlCommand = new Action <string>(x => { var vm = this.CreateViewModel <WebBrowserViewModel>(); vm.Url = x; NavigateTo(vm); }); var gotoGitHubCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.ReleaseModel).Select(x => x != null)); gotoGitHubCommand.Select(_ => ReleaseModel.HtmlUrl).Subscribe(gotoUrlCommand); GoToLinkCommand = ReactiveCommand.Create(); GoToLinkCommand.OfType <string>().Subscribe(x => { var handledViewModel = urlRouterService.Handle(x); if (handledViewModel != null) { NavigateTo(handledViewModel); } else { gotoUrlCommand(x); } }); var canShowMenu = this.WhenAnyValue(x => x.ReleaseModel).Select(x => x != null); ShowMenuCommand = ReactiveCommand.CreateAsyncTask(canShowMenu, _ => { var menu = actionMenuService.Create(Title); menu.AddButton("Share", shareCommand); menu.AddButton("Show in GitHub", gotoGitHubCommand); return(menu.Show()); }); _contentText = this.WhenAnyValue(x => x.ReleaseModel).IsNotNull() .Select(x => x.BodyHtml).ToProperty(this, x => x.ContentText); LoadCommand = ReactiveCommand.CreateAsyncTask(x => this.RequestModel(applicationService.Client.Users[RepositoryOwner].Repositories[RepositoryName].GetRelease(ReleaseId), x as bool?, r => ReleaseModel = r.Data)); }
public SurveyViewModel() { ExecuteTracePull = ReactiveCommand.CreateFromTask <string, List <TraceInfo> >( MaxDataPoint => GetMaxDataFromTrace(MaxDataPoint) ); /* Creating our UI declaratively * * The Properties in this ViewModel are related to each other in different * ways - with other frameworks, it is difficult to describe each relation * succinctly; the code to implement "The UI spinner spins while the search * is live" usually ends up spread out over several event handlers. * * However, with RxUI, we can describe how properties are related in a very * organized clear way. Let's describe the workflow of what the user does in * this application, in the order they do it. */ // We're going to take a Property and turn it into an Observable here - this // Observable will yield a value every time the Search term changes (which in // the XAML, is connected to the TextBox). // // We're going to use the Throttle operator to ignore changes that // happen too quickly, since we don't want to issue a search for each // key pressed! We then pull the Value of the change, then filter // out changes that are identical, as well as strings that are empty. // // Finally, we use RxUI's InvokeCommand operator, which takes the String // and calls the Execute method on the ExecuteSearch Command, after // making sure the Command can be executed via calling CanExecute. this.WhenAnyValue(x => x.TraceNumber) .Throttle(TimeSpan.FromMilliseconds(80), RxApp.MainThreadScheduler) .Select(x => x.ToString()) .DistinctUntilChanged() .Where(x => !String.IsNullOrWhiteSpace(x)) .InvokeCommand(ExecuteTracePull); // How would we describe when to show the spinner in English? We // might say something like, "The spinner's visibility is whether // the search is running". RxUI lets us write these kinds of // statements in code. // // ExecuteSearch has an IObservable<bool> called IsExecuting that // fires every time the command changes execution state. We Select() that into // a Visibility then we will use RxUI's // ToProperty operator, which is a helper to create an // ObservableAsPropertyHelper object. _SpinnerVisibility = ExecuteTracePull.IsExecuting .Select(x => x ? Visibility.Visible : Visibility.Collapsed) .ToProperty(this, x => x.SpinnerVisibility, Visibility.Hidden); // We subscribe to the "ThrownExceptions" property of our ReactiveCommand, // where ReactiveUI pipes any exceptions that are thrown in // "GetSearchResultsFromFlickr" into. See the "Error Handling" section // for more information about this. ExecuteTracePull.ThrownExceptions.Subscribe(ex => { /* Handle errors here */ }); // Here, we're going to actually describe what happens when the Command // gets invoked - we're going to run the GetSearchResultsFromFlickr every // time the Command is executed. // // The important bit here is the return value - an Observable. We're going // to end up here with a Stream of FlickrPhoto Lists: every time someone // calls Execute, we eventually end up with a new list which we then // immediately put into the SearchResults property, that will then // automatically fire INotifyPropertyChanged. _traceResults = ExecuteTracePull.ToProperty(this, x => x.TraceResults, new List <TraceInfo>()); }
public void Initialize(NodesCollection nodes, WasabiSynchronizer synchronizer, UpdateChecker updateChecker) { Nodes = nodes; Synchronizer = synchronizer; HashChain = synchronizer.BitcoinStore.HashChain; UseTor = Global.Config.UseTor.Value; // Don't make it dynamic, because if you change this config settings only next time will it activate. _status = ActiveStatuses.WhenAnyValue(x => x.CurrentStatus) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.Status) .DisposeWith(Disposables); Observable.FromEventPattern <NodeEventArgs>(nodes, nameof(nodes.Added)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { SetPeers(Nodes.Count); }).DisposeWith(Disposables); Observable.FromEventPattern <NodeEventArgs>(nodes, nameof(nodes.Removed)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { SetPeers(Nodes.Count); }).DisposeWith(Disposables); SetPeers(Nodes.Count); Observable.FromEventPattern <bool>(typeof(WalletService), nameof(WalletService.DownloadingBlockChanged)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => DownloadingBlock = x.EventArgs) .DisposeWith(Disposables); Synchronizer.WhenAnyValue(x => x.TorStatus) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(status => { SetTor(status); SetPeers(Nodes.Count); }).DisposeWith(Disposables); Synchronizer.WhenAnyValue(x => x.BackendStatus) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { Backend = Synchronizer.BackendStatus; }).DisposeWith(Disposables); _filtersLeft = HashChain.WhenAnyValue(x => x.HashesLeft) .Throttle(TimeSpan.FromMilliseconds(100)) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.FiltersLeft) .DisposeWith(Disposables); Synchronizer.WhenAnyValue(x => x.UsdExchangeRate) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(usd => { BtcPrice = $"${(long)usd}"; }).DisposeWith(Disposables); Observable.FromEventPattern <bool>(Synchronizer, nameof(Synchronizer.ResponseArrivedIsGenSocksServFail)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(e => { OnResponseArrivedIsGenSocksServFail(e.EventArgs); }).DisposeWith(Disposables); this.WhenAnyValue(x => x.FiltersLeft, x => x.DownloadingBlock) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(tup => { (int filtersLeft, bool downloadingBlock) = tup.ToValueTuple(); if (filtersLeft == 0 && !downloadingBlock) { TryRemoveStatus(StatusBarStatus.Synchronizing); } else { TryAddStatus(StatusBarStatus.Synchronizing); } }); this.WhenAnyValue(x => x.Tor, x => x.Backend, x => x.Peers) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(tup => { (TorStatus tor, BackendStatus backend, int peers) = tup.ToValueTuple(); if (tor == TorStatus.NotRunning || backend != BackendStatus.Connected || peers < 1) { TryAddStatus(StatusBarStatus.Connecting); } else { TryRemoveStatus(StatusBarStatus.Connecting); } }); this.WhenAnyValue(x => x.UpdateStatus) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { if (x == UpdateStatus.Critical) { TryAddStatus(StatusBarStatus.CriticalUpdate); } else { TryRemoveStatus(StatusBarStatus.CriticalUpdate); } if (x == UpdateStatus.Optional) { TryAddStatus(StatusBarStatus.OptionalUpdate); } else { TryRemoveStatus(StatusBarStatus.OptionalUpdate); } }); UpdateCommand = ReactiveCommand.Create(() => { try { IoHelpers.OpenBrowser("https://wasabiwallet.io/#download"); } catch (Exception ex) { Logging.Logger.LogWarning <StatusBarViewModel>(ex); IoC.Get <IShell>().AddOrSelectDocument(() => new AboutViewModel(Global)); } }, this.WhenAnyValue(x => x.UpdateStatus) .ObserveOn(RxApp.MainThreadScheduler) .Select(x => x != UpdateStatus.Latest)); this.RaisePropertyChanged(nameof(UpdateCommand)); // The binding happens after the constructor. So, if the command is not in constructor, then we need this line. updateChecker.Start(TimeSpan.FromMinutes(7), () => { UpdateStatus = UpdateStatus.Critical; return(Task.CompletedTask); }, () => { if (UpdateStatus != UpdateStatus.Critical) { UpdateStatus = UpdateStatus.Optional; } return(Task.CompletedTask); }); }
protected SongSourceViewModel(Library library, CoreSettings coreSettings, Guid accessToken) { if (library == null) { throw new ArgumentNullException("library"); } if (coreSettings == null) { throw new ArgumentNullException("coreSettings"); } this.library = library; this.CoreSettings = coreSettings; this.searchText = String.Empty; this.selectableSongs = Enumerable.Empty <T>(); this.ApplyOrder(SortHelpers.GetOrderByTitle <T>, ref this.titleOrder); IObservable <bool> canAddToPlaylist = this.WhenAnyValue(x => x.SelectedSongs, x => x.Any()) .CombineLatest(this.Library.LocalAccessControl.HasAccess(this.CoreSettings.WhenAnyValue(x => x.LockPlaylist), accessToken), (songsSelected, hasAccess) => songsSelected && hasAccess); this.AddToPlaylistCommand = ReactiveCommand.Create(canAddToPlaylist); this.AddToPlaylistCommand.Subscribe(x => { if (this.IsAdmin) { this.library.AddSongsToPlaylist(this.SelectedSongs.Select(song => song.Model), accessToken); if (x != null) { this.library.MovePlaylistSong(this.library.CurrentPlaylist.Last().Index, (int)x, accessToken); } } else { this.library.AddGuestSongToPlaylist(this.SelectedSongs.Select(song => song.Model).Single(), accessToken); } }); this.SelectionChangedCommand = ReactiveCommand.Create(); this.SelectionChangedCommand.Where(x => x != null) .Select(x => ((IEnumerable)x).Cast <ISongViewModelBase>()) .Subscribe(x => this.SelectedSongs = x); this.isAdmin = this.Library.LocalAccessControl.ObserveAccessPermission(accessToken) .Select(x => x == AccessPermission.Admin) .ToProperty(this, x => x.IsAdmin); // The default play command differs whether we are in party mode or not and depends on // the selected setting in administrator mode and the song source. // // In party mode, it is always "Add To Playlist", in administrator mode we look at the // value that the song source returns this.defaultPlaybackCommand = this.WhenAnyValue(x => x.IsAdmin, isAdmin => !isAdmin || this.DefaultPlaybackAction == DefaultPlaybackAction.AddToPlaylist ? (IReactiveCommand)this.AddToPlaylistCommand : this.PlayNowCommand) .ToProperty(this, x => x.DefaultPlaybackCommand); this.OrderByDurationCommand = ReactiveCommand.Create(); this.OrderByDurationCommand.Subscribe(_ => this.ApplyOrder(SortHelpers.GetOrderByDuration <T>, ref this.durationOrder)); this.OrderByTitleCommand = ReactiveCommand.Create(); this.OrderByTitleCommand.Subscribe(_ => this.ApplyOrder(SortHelpers.GetOrderByTitle <T>, ref this.titleOrder)); }
public ModListGalleryVM(MainWindowVM mainWindowVM) : base(mainWindowVM) { MWVM = mainWindowVM; // load persistent filter settings if (settings.IsPersistent) { GameType = !string.IsNullOrEmpty(settings.Game) ? settings.Game : ALL_GAME_TYPE; ShowNSFW = settings.ShowNSFW; ShowUtilityLists = settings.ShowUtilityLists; OnlyInstalled = settings.OnlyInstalled; Search = settings.Search; } else { GameType = ALL_GAME_TYPE; } // subscribe to save signal MWVM.Settings.SaveSignal .Subscribe(_ => UpdateFiltersSettings()) .DisposeWith(this.CompositeDisposable); ClearFiltersCommand = ReactiveCommand.Create( () => { OnlyInstalled = false; ShowNSFW = false; ShowUtilityLists = false; Search = string.Empty; GameType = ALL_GAME_TYPE; }); this.WhenAny(x => x.OnlyInstalled) .Subscribe(val => { if (val) { GameType = ALL_GAME_TYPE; } }) .DisposeWith(CompositeDisposable); var sourceList = Observable.Return(Unit.Default) .ObserveOn(RxApp.TaskpoolScheduler) .SelectTask(async _ => { try { Error = null; var list = await ModlistMetadata.LoadFromGithub(); Error = ErrorResponse.Success; return(list .AsObservableChangeSet(x => x.DownloadMetadata?.Hash ?? Hash.Empty)); } catch (Exception ex) { Utils.Error(ex); Error = ErrorResponse.Fail(ex); return(Observable.Empty <IChangeSet <ModlistMetadata, Hash> >()); } }) // Unsubscribe and release when not active .FlowSwitch( this.WhenAny(x => x.IsActive), valueWhenOff: Observable.Return(ChangeSet <ModlistMetadata, Hash> .Empty)) .Switch() .RefCount(); _Loaded = sourceList.CollectionCount() .Select(c => c > 0) .ToProperty(this, nameof(Loaded)); // Convert to VM and bind to resulting list sourceList .ObserveOnGuiThread() .Transform(m => new ModListMetadataVM(this, m)) .DisposeMany() // Filter only installed .Filter(this.WhenAny(x => x.OnlyInstalled) .Select <bool, Func <ModListMetadataVM, bool> >(onlyInstalled => (vm) => { if (!onlyInstalled) { return(true); } if (!GameRegistry.Games.TryGetValue(vm.Metadata.Game, out var gameMeta)) { return(false); } return(gameMeta.IsInstalled); })) // Filter on search box .Filter(this.WhenAny(x => x.Search) .Debounce(TimeSpan.FromMilliseconds(150), RxApp.MainThreadScheduler) .Select <string, Func <ModListMetadataVM, bool> >(search => (vm) => { if (string.IsNullOrWhiteSpace(search)) { return(true); } return(vm.Metadata.Title.ContainsCaseInsensitive(search) || vm.Metadata.tags.Any(t => t.ContainsCaseInsensitive(search))); })) .Filter(this.WhenAny(x => x.ShowNSFW) .Select <bool, Func <ModListMetadataVM, bool> >(showNSFW => vm => { if (!vm.Metadata.NSFW) { return(true); } return(vm.Metadata.NSFW && showNSFW); })) .Filter(this.WhenAny(x => x.ShowUtilityLists) .Select <bool, Func <ModListMetadataVM, bool> >(showUtilityLists => vm => showUtilityLists ? vm.Metadata.UtilityList : !vm.Metadata.UtilityList)) // Filter by Game .Filter(this.WhenAny(x => x.GameType) .Debounce(TimeSpan.FromMilliseconds(150), RxApp.MainThreadScheduler) .Select <string, Func <ModListMetadataVM, bool> >(GameType => (vm) => { if (GameType == ALL_GAME_TYPE) { return(true); } if (string.IsNullOrEmpty(GameType)) { return(false); } return(GameType == vm.Metadata.Game.GetDescription <Game>().ToString()); })) .Bind(ModLists) .Subscribe() .DisposeWith(CompositeDisposable); // Extra GC when navigating away, just to immediately clean up modlist metadata this.WhenAny(x => x.IsActive) .Where(x => !x) .Skip(1) .Delay(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler) .Subscribe(_ => { GC.Collect(); }) .DisposeWith(CompositeDisposable); }
public PlaylistViewModel() { this.Activator = new ViewModelActivator(); this.entries = new ReactiveList <PlaylistEntryViewModel>(); this.currentTimeSecondsUserChanged = new Subject <int>(); this.WhenActivated(() => { var disposable = new CompositeDisposable(); this.canModify = NetworkMessenger.Instance.WhenAnyValue(x => x.AccessPermission) .Select(x => x == NetworkAccessPermission.Admin) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.CanModify); this.canModify.DisposeWith(disposable); this.LoadPlaylistCommand = ReactiveCommand.CreateAsyncObservable(_ => NetworkMessenger.Instance.GetCurrentPlaylistAsync().ToObservable() .Timeout(LoadPlaylistCommandTimeout, RxApp.TaskpoolScheduler) .TakeUntil(disposable)); var currentPlaylist = this.LoadPlaylistCommand .FirstAsync() .Concat(NetworkMessenger.Instance.PlaylistChanged.ObserveOn(RxApp.MainThreadScheduler)) .Publish(); currentPlaylist.Connect().DisposeWith(disposable); currentPlaylist.Select(x => x.Songs.Select((song, i) => new PlaylistEntryViewModel(song, x.CurrentIndex < i, x.CurrentIndex.HasValue && i == x.CurrentIndex)).ToList()) .Subscribe(x => { using (this.entries.SuppressChangeNotifications()) { this.entries.Clear(); this.entries.AddRange(x); } }); this.currentSong = this.entries.Changed.Select(x => this.entries.FirstOrDefault(y => y.IsPlaying)) .ToProperty(this, x => x.CurrentSong); this.remainingVotes = NetworkMessenger.Instance.WhenAnyValue(x => x.GuestSystemInfo) .Select(x => x.IsEnabled ? new int?(x.RemainingVotes) : null) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.RemainingVotes) .DisposeWith(disposable); int?remainingVotesConnector = this.RemainingVotes; this.playbackState = currentPlaylist.Select(x => x.PlaybackState) .Merge(NetworkMessenger.Instance.PlaybackStateChanged.ObserveOn(RxApp.MainThreadScheduler)) .ToProperty(this, x => x.PlaybackState) .DisposeWith(disposable); this.currentTimeSeconds = currentPlaylist.Select(x => x.CurrentTime) .Merge(NetworkMessenger.Instance.PlaybackTimeChanged) .Select(x => (int)x.TotalSeconds) .Select(x => Observable.Interval(TimeSpan.FromSeconds(1), RxApp.TaskpoolScheduler) .Where(_ => this.IsPlaying) .StartWith(x) .Select((_, i) => x + i)) .Switch() .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.CurrentTimeSeconds) .DisposeWith(disposable); this.currentTimeSecondsUserChanged .Window(TimeThrottleDuration, TimeThrottleCount, RxApp.TaskpoolScheduler) .Select(x => x.DistinctUntilChanged()) .Select(x => x.Take(1).Concat(x.Skip(1).TakeLast(1))) .Switch() .Select(x => TimeSpan.FromSeconds(x)) .SelectMany(x => NetworkMessenger.Instance.SetCurrentTime(x).ToObservable().SwallowNetworkExceptions()) .Subscribe() .DisposeWith(disposable); this.totalTime = currentPlaylist.Select(x => x.TotalTime) .ToProperty(this, x => x.TotalTime); var canVote = this.WhenAnyValue(x => x.CurrentSong, x => x.RemainingVotes, (currentSong, remainingVotes) => currentSong != null && remainingVotes > 0); this.VoteCommand = ReactiveCommand.CreateAsyncObservable(canVote, _ => NetworkMessenger.Instance.VoteAsync(this.SelectedEntry.Guid).ToObservable().TakeUntil(disposable)); this.canVoteOnSelectedEntry = this.WhenAnyValue(x => x.SelectedEntry).Select(x => x != null && x.IsVoteAble) .CombineLatest(this.WhenAnyValue(x => x.RemainingVotes).Select(x => x.HasValue), (isVoteable, hasVotes) => isVoteable && hasVotes) .ToProperty(this, x => x.CanVoteOnSelectedEntry); var canVoteTemp = this.CanVoteOnSelectedEntry; this.PlayPlaylistSongCommand = ReactiveCommand.CreateAsyncObservable(this.WhenAnyValue(x => x.CanModify), _ => NetworkMessenger.Instance.PlayPlaylistSongAsync(this.SelectedEntry.Guid).ToObservable().TakeUntil(disposable)); var canPlayNextSong = this.entries.Changed.Select(_ => this.entries) .StartWith(this.entries) .Select(x => x.Any(y => y.IsPlaying) && x.FirstOrDefault(y => y.IsPlaying) != x.LastOrDefault()) .CombineLatest(this.WhenAnyValue(x => x.CanModify), (canPlayNext, canModify) => canPlayNext && canModify); this.PlayNextSongCommand = ReactiveCommand.CreateAsyncObservable(canPlayNextSong, _ => NetworkMessenger.Instance.PlayNextSongAsync().ToObservable().TakeUntil(disposable)); var canPlayPreviousSong = this.entries.Changed.Select(_ => this.entries) .StartWith(this.entries) .Select(x => x.Any(y => y.IsPlaying) && x.FirstOrDefault(y => y.IsPlaying) != x.FirstOrDefault()) .CombineLatest(this.WhenAnyValue(x => x.CanModify), (canPlayPrevious, canModify) => canPlayPrevious && canModify); this.PlayPreviousSongCommand = ReactiveCommand.CreateAsyncObservable(canPlayPreviousSong, _ => NetworkMessenger.Instance.PlayPreviousSongAsync().ToObservable().TakeUntil(disposable)); this.isPlaying = this.WhenAnyValue(x => x.PlaybackState) .Select(x => x == NetworkPlaybackState.Playing) .ToProperty(this, x => x.IsPlaying); var canPlayOrPause = this.WhenAnyValue(x => x.PlaybackState) .Select(x => x == NetworkPlaybackState.Playing || x == NetworkPlaybackState.Paused) .CombineLatest(this.WhenAnyValue(x => x.CanModify), (canPlay, canModify) => canPlay && canModify); this.PlayPauseCommand = ReactiveCommand.CreateAsyncObservable(canPlayOrPause, _ => { if (this.IsPlaying) { return(NetworkMessenger.Instance.PauseSongAsync().ToObservable().TakeUntil(disposable)); } return(NetworkMessenger.Instance.ContinueSongAsync().ToObservable().TakeUntil(disposable)); }); this.RemoveSongCommand = ReactiveCommand.CreateAsyncObservable(this.WhenAnyValue(x => x.CanModify), _ => NetworkMessenger.Instance.RemovePlaylistSongAsync(this.SelectedEntry.Guid).ToObservable().TakeUntil(disposable)); this.MoveSongDownCommand = ReactiveCommand.CreateAsyncObservable(this.WhenAnyValue(x => x.CanModify), _ => NetworkMessenger.Instance.MovePlaylistSongDownAsync(this.SelectedEntry.Guid).ToObservable().TakeUntil(disposable)); this.MoveSongUpCommand = ReactiveCommand.CreateAsyncObservable(this.WhenAnyValue(x => x.CanModify), _ => NetworkMessenger.Instance.MovePlaylistSongUpAsync(this.SelectedEntry.Guid).ToObservable().TakeUntil(disposable)); this.ToggleVideoPlayerCommand = ReactiveCommand.CreateAsyncObservable(this.WhenAnyValue(x => x.CanModify), _ => NetworkMessenger.Instance.ToggleVideoPlayer().ToObservable().TakeUntil(disposable)); return(disposable); }); }
public SubordinateViewModel(IMainViewModel mainWindowViewModel) : base(nameof(SubordinateViewModel), mainWindowViewModel) { SetNotification("Loading subordinate data", NotificationType.Refreshing); _mainWindowViewModel = mainWindowViewModel; SearchText = string.Empty; _networkServiceOfPersons ??= Locator.Current.GetService <INetworkService <Person> >(); _networkServiceOfFileData ??= Locator.Current.GetService <INetworkService <FileData> >(); _settingsService ??= Locator.Current.GetService <ISettingsService>(); #region Init Chat service _clientService ??= Locator.Current.GetService <IClientService>(); _clientService.MessageReceived += MessageReceived; #endregion #region Init SelectPersonCommand SelectPersonCommand = ReactiveCommand.CreateFromTask <Person, bool>(SelectPersonExecutedAsync); SelectPersonCommand.ThrownExceptions.Subscribe(exception => { IsPhotoLoading = false; ErrorHandler(nameof(SelectPersonCommand)).Invoke(exception); }); this.WhenAnyValue(x => x.SelectedPerson).InvokeCommand(SelectPersonCommand); #endregion #region Init SearchPersonCommand var canSearch = this.WhenAnyValue(x => x.SearchText, query => !string.IsNullOrWhiteSpace(query)); SearchPersonCommand = ReactiveCommand.CreateFromTask <string, IEnumerable <Person> >( async query => await SearchPersonExecuteAsync(query), canSearch); SearchPersonCommand.IsExecuting.ToProperty(this, x => x.IsSearching, out _isSearching); SearchPersonCommand.ThrownExceptions.Subscribe(ErrorHandler(nameof(SearchPersonCommand))); _searchedPersons = SearchPersonCommand.ToProperty(this, x => x.Persons); this.WhenAnyValue(x => x.SearchText) .Throttle(TimeSpan.FromSeconds(1), RxApp.MainThreadScheduler) .InvokeCommand(SearchPersonCommand); #endregion #region Init ClearSearchPersonCommand var canClearSearch = this.WhenAnyValue(x => x.SearchText, query => !string.IsNullOrWhiteSpace(query) || Persons.Any()); ClearSearchPersonCommand = ReactiveCommand.CreateFromTask <Unit, bool>(ClearSearchPersonsAsync, canClearSearch); ClearSearchPersonCommand.ThrownExceptions.Subscribe(ErrorHandler(nameof(ClearSearchPersonCommand))); #endregion #region Init SendPersonCommand var canSendPerson = this.WhenAnyValue( x => x.IsLoading, x => x.Visitor.Comment, x => x.Visitor.FirstName, x => x.Visitor.Message, x => x.Visitor.MiddleName, x => x.Visitor.Post, x => x.Visitor.SecondName, selector: (isLoading, _, __, ___, ____, _____, ______) => !Visitor.IsNullOrEmpty() && !isLoading); SendVisitorCommand = ReactiveCommand.CreateFromTask <Visitor, bool>(SendVisitorExecuteAsync, canSendPerson); SendVisitorCommand.ThrownExceptions.Subscribe(ErrorHandler(nameof(SendVisitorCommand))); #endregion Initialized += OnSubordinateViewModelInitialized; OnInitialized(); }
public MO2InstallerVM(InstallerVM installerVM) { Parent = installerVM; Location = new FilePickerVM() { ExistCheckOption = FilePickerVM.CheckOptions.Off, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Installation Directory", }; DownloadLocation = new FilePickerVM() { ExistCheckOption = FilePickerVM.CheckOptions.Off, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select a location for MO2 downloads", }; DownloadLocation.AdditionalError = this.WhenAny(x => x.DownloadLocation.TargetPath) .Select(x => Utils.IsDirectoryPathValid(x)); Location.AdditionalError = Observable.CombineLatest( this.WhenAny(x => x.Location.TargetPath), this.WhenAny(x => x.DownloadLocation.TargetPath), resultSelector: (target, download) => (target, download)) .ObserveOn(RxApp.TaskpoolScheduler) .Select(i => MO2Installer.CheckValidInstallPath(i.target, i.download)) .ObserveOnGuiThread(); CanInstall = Observable.CombineLatest( this.WhenAny(x => x.Location.InError), this.WhenAny(x => x.DownloadLocation.InError), installerVM.WhenAny(x => x.ModListLocation.InError), resultSelector: (loc, modlist, download) => { return(!loc && !download && !modlist); }); // Have Installation location updates modify the downloads location if empty this.WhenAny(x => x.Location.TargetPath) .Skip(1) // Don't do it initially .Subscribe(installPath => { if (DownloadLocation.TargetPath == default) { DownloadLocation.TargetPath = installPath.Combine("downloads"); } }) .DisposeWith(CompositeDisposable); // Load settings _CurrentSettings = installerVM.WhenAny(x => x.ModListLocation.TargetPath) .Select(path => path == null ? null : installerVM.MWVM.Settings.Installer.Mo2ModlistSettings.TryCreate(path)) .ToGuiProperty(this, nameof(CurrentSettings)); this.WhenAny(x => x.CurrentSettings) .Pairwise() .Subscribe(settingsPair => { SaveSettings(settingsPair.Previous); if (settingsPair.Current == null) { return; } Location.TargetPath = settingsPair.Current.InstallationLocation; DownloadLocation.TargetPath = settingsPair.Current.DownloadLocation; AutomaticallyOverwrite = settingsPair.Current.AutomaticallyOverrideExistingInstall; }) .DisposeWith(CompositeDisposable); installerVM.MWVM.Settings.SaveSignal .Subscribe(_ => SaveSettings(CurrentSettings)) .DisposeWith(CompositeDisposable); // Hook onto user interventions, and intercept MO2 specific ones for customization this.WhenAny(x => x.ActiveInstallation) .Select(x => x?.LogMessages ?? Observable.Empty <IStatusMessage>()) .Switch() .Subscribe(x => { switch (x) { case ConfirmUpdateOfExistingInstall c: if (AutomaticallyOverwrite) { c.Confirm(); } break; default: break; } }) .DisposeWith(CompositeDisposable); }
public NuGetPackageDetailViewModel() { GetVersions = ReactiveCommand.CreateFromTask <IPackageSearchMetadata, IEnumerable <NuGetVersionViewModel> >(ExecuteGetVersions); _versions = GetVersions.ToProperty(this, x => x.Versions, scheduler: RxApp.MainThreadScheduler); }
public PullRequestViewModel( IApplicationService applicationService, IMarkdownService markdownService, IActionMenuFactory actionMenuService) : base(applicationService, markdownService) { this.WhenAnyValue(x => x.Id) .Subscribe(x => Title = "Pull Request #" + x); _canMerge = this.WhenAnyValue(x => x.PullRequest) .Select(x => x != null && !x.Merged) .ToProperty(this, x => x.CanMerge); var canMergeObservable = this.WhenAnyValue(x => x.PullRequest).Select(x => x != null && !x.Merged && x.Mergeable.HasValue && x.Mergeable.Value); MergeCommand = ReactiveCommand.CreateAsyncTask(canMergeObservable, async t => { var req = new Octokit.MergePullRequest(null); var response = await applicationService.GitHubClient.PullRequest.Merge(RepositoryOwner, RepositoryName, Id, req); if (!response.Merged) { throw new Exception(string.Format("Unable to merge pull request: {0}", response.Message)); } LoadCommand.ExecuteIfCan(); }); // ToggleStateCommand = ReactiveCommand.CreateAsyncTask( // this.WhenAnyValue(x => x.PullRequest).Select(x => x != null), // async t => // { // var newState = PullRequest.State == Octokit.ItemState.Open ? Octokit.ItemState.Closed : Octokit.ItemState.Open; // // try // { // var req = new Octokit.PullRequestUpdate { State = newState }; // PullRequest = await applicationService.GitHubClient.PullRequest.Update(RepositoryOwner, RepositoryName, Id, req); // } // catch (Exception e) // { // throw new Exception("Unable to " + (newState == Octokit.ItemState.Closed ? "close" : "open") + " the item. " + e.Message, e); // } // }); GoToHtmlUrlCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.PullRequest).Select(x => x != null)); GoToHtmlUrlCommand.Select(_ => PullRequest.HtmlUrl).Subscribe(GoToUrlCommand.ExecuteIfCan); GoToCommitsCommand = ReactiveCommand.Create().WithSubscription(_ => { var vm = this.CreateViewModel <PullRequestCommitsViewModel>(); vm.RepositoryOwner = RepositoryOwner; vm.RepositoryName = RepositoryName; vm.PullRequestId = Id; NavigateTo(vm); }); GoToFilesCommand = ReactiveCommand.Create().WithSubscription(_ => { var vm = this.CreateViewModel <PullRequestFilesViewModel>(); vm.RepositoryOwner = RepositoryOwner; vm.RepositoryName = RepositoryName; vm.PullRequestId = Id; NavigateTo(vm); }); ShareCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.PullRequest).Select(x => x != null)); ShareCommand.Subscribe(_ => actionMenuService.ShareUrl(PullRequest.HtmlUrl)); GoToEditCommand = ReactiveCommand.Create().WithSubscription(_ => { var vm = this.CreateViewModel <IssueEditViewModel>(); vm.RepositoryOwner = RepositoryOwner; vm.RepositoryName = RepositoryName; vm.Id = Id; //vm.Issue = Issue; // vm.WhenAnyValue(x => x.Issue).Skip(1).Subscribe(x => Issue = x); NavigateTo(vm); }); ShowMenuCommand = ReactiveCommand.CreateAsyncTask( this.WhenAnyValue(x => x.PullRequest).Select(x => x != null), _ => { var menu = actionMenuService.Create(Title); menu.AddButton("Edit", GoToEditCommand); menu.AddButton(PullRequest.State == Octokit.ItemState.Closed ? "Open" : "Close", ToggleStateCommand); menu.AddButton("Comment", GoToAddCommentCommand); menu.AddButton("Share", ShareCommand); menu.AddButton("Show in GitHub", GoToHtmlUrlCommand); return(menu.Show()); }); }
public async Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection) { modelService = await modelServiceFactory.CreateAsync(connection); activeLocalRepo = repository; SourceBranch = repository.CurrentBranch; var obs = modelService.ApiClient.GetRepository(repository.Owner, repository.Name) .Select(r => new RemoteRepositoryModel(r)) .PublishLast(); disposables.Add(obs.Connect()); var githubObs = obs; githubRepository = githubObs.ToProperty(this, x => x.GitHubRepository); this.WhenAnyValue(x => x.GitHubRepository) .WhereNotNull() .Subscribe(r => { TargetBranch = r.IsFork ? r.Parent.DefaultBranch : r.DefaultBranch; }); githubObs.SelectMany(r => { var b = Observable.Empty <IBranch>(); if (r.IsFork) { b = modelService.GetBranches(r.Parent).Select(x => { return(x); }); } return(b.Concat(modelService.GetBranches(r))); }) .ToList() .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { Branches = x.ToList(); Initialized = true; }); SourceBranch = activeLocalRepo.CurrentBranch; var uniqueCommits = this.WhenAnyValue( x => x.SourceBranch, x => x.TargetBranch) .Where(x => x.Item1 != null && x.Item2 != null) .Select(branches => { var baseBranch = branches.Item1.Name; var compareBranch = branches.Item2.Name; // We only need to get max two commits for what we're trying to achieve here. // If there's no commits we want to block creation of the PR, if there's one commits // we wan't to use its commit message as the PR title/body and finally if there's more // than one we'll use the branch name for the title. return(service.GetMessagesForUniqueCommits(activeLocalRepo, baseBranch, compareBranch, maxCommits: 2) .Catch <IReadOnlyList <CommitMessage>, Exception>(ex => { log.Warning(ex, "Could not load unique commits"); return Observable.Empty <IReadOnlyList <CommitMessage> >(); })); }) .Switch() .ObserveOn(RxApp.MainThreadScheduler) .Replay(1) .RefCount(); Observable.CombineLatest( this.WhenAnyValue(x => x.SourceBranch), uniqueCommits, service.GetPullRequestTemplate(repository).DefaultIfEmpty(string.Empty), (compare, commits, template) => new { compare, commits, template }) .Subscribe(x => { var prTitle = string.Empty; var prDescription = string.Empty; if (x.commits.Count == 1) { prTitle = x.commits[0].Summary; prDescription = x.commits[0].Details; } else { prTitle = x.compare.Name.Humanize(); } if (!string.IsNullOrWhiteSpace(x.template)) { if (!string.IsNullOrEmpty(prDescription)) { prDescription += "\n\n"; } prDescription += x.template; } PRTitle = prTitle; Description = prDescription; }); Initialized = true; }
public CloudViewModel( CloudState state, CreateFolderViewModelFactory createFolderFactory, RenameFileViewModelFactory renameFactory, FileViewModelFactory fileFactory, FolderViewModelFactory folderFactory, IAuthViewModel auth, IFileManager files, ICloud cloud) { _cloud = cloud; Folder = createFolderFactory(this); Rename = renameFactory(this); Auth = auth; var canInteract = this .WhenAnyValue( x => x.Folder.IsVisible, x => x.Rename.IsVisible, (folder, rename) => !folder && !rename); _canInteract = canInteract .ToProperty(this, x => x.CanInteract); var canRefresh = this .WhenAnyValue( x => x.Folder.IsVisible, x => x.Rename.IsVisible, x => x.Auth.IsAuthenticated, (folder, rename, authenticated) => !folder && !rename && authenticated); Refresh = ReactiveCommand.CreateFromTask( () => cloud.GetFiles(CurrentPath), canRefresh); _files = Refresh .Select( items => items .Select(file => fileFactory(file, this)) .OrderByDescending(file => file.IsFolder) .ThenBy(file => file.Name) .ToList()) .Where(items => Files == null || !items.SequenceEqual(Files)) .ToProperty(this, x => x.Files); _isLoading = Refresh .IsExecuting .ToProperty(this, x => x.IsLoading); _isReady = Refresh .IsExecuting .Skip(1) .Select(executing => !executing) .ToProperty(this, x => x.IsReady); var canOpenCurrentPath = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && file.IsFolder) .CombineLatest(Refresh.IsExecuting, canInteract, (folder, busy, ci) => folder && ci && !busy); Open = ReactiveCommand.Create( () => Path.Combine(CurrentPath, SelectedFile.Name), canOpenCurrentPath); var canCurrentPathGoBack = this .WhenAnyValue(x => x.CurrentPath) .Where(path => path != null) .Select(path => path.Length > cloud.InitialPath.Length) .CombineLatest(Refresh.IsExecuting, canInteract, (valid, busy, ci) => valid && ci && !busy); Back = ReactiveCommand.Create( () => Path.GetDirectoryName(CurrentPath), canCurrentPathGoBack); SetPath = ReactiveCommand.Create <string, string>(path => path); _currentPath = Open .Merge(Back) .Merge(SetPath) .Select(path => path ?? cloud.InitialPath) .DistinctUntilChanged() .Log(this, $"Current path changed in {cloud.Name}") .ToProperty(this, x => x.CurrentPath, state.CurrentPath ?? cloud.InitialPath); var getBreadCrumbs = ReactiveCommand.CreateFromTask( () => cloud.GetBreadCrumbs(CurrentPath)); _breadCrumbs = getBreadCrumbs .Where(items => items != null && items.Any()) .Select(items => items.Select(folder => folderFactory(folder, this))) .ToProperty(this, x => x.BreadCrumbs); _showBreadCrumbs = getBreadCrumbs .ThrownExceptions .Select(exception => false) .Merge(getBreadCrumbs.Select(items => items != null && items.Any())) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.ShowBreadCrumbs); _hideBreadCrumbs = this .WhenAnyValue(x => x.ShowBreadCrumbs) .Select(show => !show) .ToProperty(this, x => x.HideBreadCrumbs); this.WhenAnyValue(x => x.CurrentPath, x => x.IsReady) .Where(x => x.Item1 != null && x.Item2) .Select(_ => Unit.Default) .InvokeCommand(getBreadCrumbs); this.WhenAnyValue(x => x.CurrentPath) .Skip(1) .Select(_ => Unit.Default) .InvokeCommand(Refresh); this.WhenAnyValue(x => x.CurrentPath) .Subscribe(_ => SelectedFile = null); _isCurrentPathEmpty = this .WhenAnyValue(x => x.Files) .Skip(1) .Where(items => items != null) .Select(items => !items.Any()) .ToProperty(this, x => x.IsCurrentPathEmpty); _hasErrorMessage = Refresh .ThrownExceptions .Select(exception => true) .ObserveOn(RxApp.MainThreadScheduler) .Merge(Refresh.Select(x => false)) .ToProperty(this, x => x.HasErrorMessage); var canUploadToCurrentPath = this .WhenAnyValue(x => x.CurrentPath) .Select(path => path != null) .CombineLatest(Refresh.IsExecuting, canInteract, (up, loading, can) => up && can && !loading); UploadToCurrentPath = ReactiveCommand.CreateFromObservable( () => Observable .FromAsync(files.OpenRead) .Where(response => response.Name != null && response.Stream != null) .Select(args => _cloud.UploadFile(CurrentPath, args.Stream, args.Name)) .SelectMany(task => task.ToObservable()), canUploadToCurrentPath); UploadToCurrentPath.InvokeCommand(Refresh); var canDownloadSelectedFile = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && !file.IsFolder) .CombineLatest(Refresh.IsExecuting, canInteract, (down, loading, can) => down && !loading && can); DownloadSelectedFile = ReactiveCommand.CreateFromObservable( () => Observable .FromAsync(() => files.OpenWrite(SelectedFile.Name)) .Where(stream => stream != null) .Select(stream => _cloud.DownloadFile(SelectedFile.Path, stream)) .SelectMany(task => task.ToObservable()), canDownloadSelectedFile); var canLogout = cloud .IsAuthorized .DistinctUntilChanged() .Select(loggedIn => loggedIn && ( cloud.SupportsDirectAuth || cloud.SupportsOAuth || cloud.SupportsHostAuth)) .CombineLatest(canInteract, (logout, interact) => logout && interact) .ObserveOn(RxApp.MainThreadScheduler); Logout = ReactiveCommand.CreateFromTask(cloud.Logout, canLogout); _canLogout = canLogout .ToProperty(this, x => x.CanLogout); var canDeleteSelection = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && !file.IsFolder) .CombineLatest(Refresh.IsExecuting, canInteract, (del, loading, ci) => del && !loading && ci); DeleteSelectedFile = ReactiveCommand.CreateFromTask( () => cloud.Delete(SelectedFile.Path, SelectedFile.IsFolder), canDeleteSelection); DeleteSelectedFile.InvokeCommand(Refresh); var canUnselectFile = this .WhenAnyValue(x => x.SelectedFile) .Select(selection => selection != null) .CombineLatest(Refresh.IsExecuting, canInteract, (sel, loading, ci) => sel && !loading && ci); UnselectFile = ReactiveCommand.Create( () => { SelectedFile = null; }, canUnselectFile); UploadToCurrentPath.ThrownExceptions .Merge(DeleteSelectedFile.ThrownExceptions) .Merge(DownloadSelectedFile.ThrownExceptions) .Merge(Refresh.ThrownExceptions) .Merge(getBreadCrumbs.ThrownExceptions) .Log(this, $"Exception occured in provider {cloud.Name}") .Subscribe(); this.WhenAnyValue(x => x.CurrentPath) .Subscribe(path => state.CurrentPath = path); this.WhenAnyValue(x => x.Auth.IsAuthenticated) .Select(authenticated => authenticated ? _cloud.Parameters?.Token : null) .Subscribe(token => state.Token = token); this.WhenAnyValue(x => x.Auth.IsAuthenticated) .Select(authenticated => authenticated ? _cloud.Parameters?.User : null) .Subscribe(user => state.User = user); this.WhenActivated(ActivateAutoRefresh); }
public ItemEditorViewModel( IManualTagEditor tagEdiotr, IItemService itemService, FileVersionListViewModel fileVersionList, INotificationCenterService notificationCenter, ILibraryManagementService libraryManagement, IFileItemLinkService fileItemLinkService, OpenFileCommand openFile, FileToClipboardCommand fileToClipboard, ISettingsService settingsService, IThumbnailManagementService thumbnailManagementService) { this.TagEditor = tagEdiotr; this._itemService = itemService; FileVersionList = fileVersionList; this.notificationCenter = notificationCenter; this.libraryManagement = libraryManagement; this.fileItemLinkService = fileItemLinkService; OpenFile = openFile; FileToClipboard = fileToClipboard; this.thumbnailManagementService = thumbnailManagementService; this.TagEditor.Editmode = true; this.TagEditor.CompletePool = true; this.TagEditor.PermitNewTags = true; this.disposables.Add(_selectedItemIdChanges); this.SelectedItemChanges = this._itemService .GetExtended(this.SelectedItemIdChanges) .TakeUntil(destroy); this.Save = new RelayCommand(_ => _save()); this.CreateThumbnail = new RelayCommand(_ => createThumbnail()); var selectedVersionChanges = this.WhenAnyValue(x => x.SelectedVersion).TakeUntil(destroy); var curLink = this.newLinks.Connect() .ChangeKey(link => link.Version) .WatchValue(selectedVersionChanges, link => link.Version); var curFileFilter = selectedVersionChanges.CombineLatest(SelectedItemChanges, (version, item) => new { version, item }) .Select( x => { return(new Func <VersionedFile, bool>((VersionedFile vFile) => x.version.HasValue && x.item.HasValue && (vFile.Version == x.version.Value) && (vFile.ItemId == x.item.Value.ItemId))); }); var files = this.fileItemLinkService.BuildversionedFiles(newLinks.Connect()); var curFiles = files.Filter(curFileFilter) .Select(x => x.FirstOrDefault(x => x.Reason != ChangeReason.Remove).Current.ToNullable()); this._selectedFiles = curFiles .TakeUntil(destroy) .ToProperty(this, nameof(SelectedFiles)); this._cameraRotationMode = settingsService .WhenAnyValue(x => x.CameraRotationMode) .Select(x => (CameraRotationMode)x) .ToProperty(this, nameof(CameraRotationMode)); _cameraRotationMode.DisposeWith(disposables); DateTime mostRecentRequest = default; curFiles .ObserveOn(RxApp.TaskpoolScheduler) .TakeUntil(destroy) .Select(files => { mostRecentRequest = DateTime.Now; var orderTime = DateTime.Now; if (!files.HasValue || files?.File.AbsolutePath == null) { return(null); } this.MaterialBrush = new SolidColorBrush(Colors.LightGray); var mat = new DiffuseMaterial(this.MaterialBrush); ModelImporter importer = new ModelImporter() { DefaultMaterial = mat }; Model3DGroup model = importer.Load(files.Value.File.AbsolutePath); model.SetMaterial(mat); model.PlaceAtOrigin(); model.Freeze(); return(new { timestamp = mostRecentRequest, model }); }) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { this.ViewportContent = null; if (x == null) { return; } LoadingModel = true; RxApp.MainThreadScheduler.Schedule(x.model, (_, model) => { if (x.timestamp == mostRecentRequest) { this.ViewportContent = model; LoadingModel = false; } return(null); }); }); var linkFilter = selectedVersionChanges.Select(version => new Func <FileItemLink, bool>(link => link.Version == version) ); var selectedLinkChanges = this.newLinks .Connect() .RemoveKey() .Filter(linkFilter) .Select(x => x.FirstOrDefault().Item.Current); this.SelectedItemChanges.Subscribe( LoadItem, ex => this.notificationCenter.OnError(ex)); }
public void SubscribeEvents() { lock (DisposablesLock) { if (Disposables != null) { throw new Exception("Please report to Dan"); } Disposables = new CompositeDisposable(); //TODO defer subscription to when accessed (will be faster in ui.) _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); _unavailable = Model.WhenAnyValue(x => x.Unavailable) .ToProperty(this, x => x.Unavailable, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); this.WhenAnyValue(x => x.Status) .Subscribe(_ => this.RaisePropertyChanged(nameof(ToolTip))); this.WhenAnyValue(x => x.Confirmed, x => x.CoinJoinInProgress, x => x.Confirmations) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => RefreshSmartCoinStatus()); this.WhenAnyValue(x => x.IsSelected) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => _owner.OnCoinIsSelectedChanged(this)); this.WhenAnyValue(x => x.Status) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => _owner.OnCoinStatusChanged()); this.WhenAnyValue(x => x.Unspent) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => _owner.OnCoinUnspentChanged(this)); Model.WhenAnyValue(x => x.IsBanned, x => x.SpentAccordingToBackend) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => RefreshSmartCoinStatus()) .DisposeWith(Disposables); Observable.FromEventPattern( Global.ChaumianClient, nameof(Global.ChaumianClient.StateUpdated)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => RefreshSmartCoinStatus()) .DisposeWith(Disposables); Global.BitcoinStore.HashChain.WhenAnyValue(x => x.ServerTipHeight) .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); } }
public IssueViewModel(IApplicationService applicationService, IActionMenuFactory actionMenuFactory, IMarkdownService markdownService, IGraphicService graphicsService) { _applicationService = applicationService; var issuePresenceObservable = this.WhenAnyValue(x => x.Issue).Select(x => x != null); GoToAssigneesCommand = ReactiveCommand.Create(issuePresenceObservable) .WithSubscription(_ => Assignees.LoadCommand.ExecuteIfCan()); GoToLabelsCommand = ReactiveCommand.Create(issuePresenceObservable) .WithSubscription(_ => Labels.LoadCommand.ExecuteIfCan()); GoToMilestonesCommand = ReactiveCommand.Create(issuePresenceObservable) .WithSubscription(_ => Milestones.LoadCommand.ExecuteIfCan()); this.WhenAnyValue(x => x.Id) .Subscribe(x => Title = "Issue #" + x); _assignedUser = this.WhenAnyValue(x => x.Issue.Assignee) .ToProperty(this, x => x.AssignedUser); _assignedMilestone = this.WhenAnyValue(x => x.Issue.Milestone) .ToProperty(this, x => x.AssignedMilestone); _assignedLabels = this.WhenAnyValue(x => x.Issue.Labels) .ToProperty(this, x => x.AssignedLabels); _markdownDescription = this.WhenAnyValue(x => x.Issue) .Select(x => ((x == null || string.IsNullOrEmpty(x.Body)) ? null : markdownService.Convert(x.Body))) .ToProperty(this, x => x.MarkdownDescription); ShareCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.Issue).Select(x => x != null)); ShareCommand.Subscribe(_ => actionMenuFactory.ShareUrl(Issue.HtmlUrl)); var events = new ReactiveList <IIssueEventItemViewModel>(); Events = events.CreateDerivedCollection(x => x); AddCommentCommand = ReactiveCommand.Create(); AddCommentCommand.Subscribe(_ => { var vm = this.CreateViewModel <IssueCommentViewModel>(); vm.RepositoryOwner = RepositoryOwner; vm.RepositoryName = RepositoryName; vm.Id = Id; vm.SaveCommand.Subscribe(x => events.Add(new IssueCommentItemViewModel(x))); NavigateTo(vm); }); ToggleStateCommand = ReactiveCommand.CreateAsyncTask(issuePresenceObservable, async t => { try { Issue = await applicationService.GitHubClient.Issue.Update(RepositoryOwner, RepositoryName, Id, new Octokit.IssueUpdate { State = (Issue.State == Octokit.ItemState.Open) ? Octokit.ItemState.Closed : Octokit.ItemState.Open }); } catch (Exception e) { var close = (Issue.State == Octokit.ItemState.Open) ? "close" : "open"; throw new Exception("Unable to " + close + " the item. " + e.Message, e); } }); GoToEditCommand = ReactiveCommand.Create(issuePresenceObservable); GoToEditCommand.Subscribe(_ => { var vm = this.CreateViewModel <IssueEditViewModel>(); vm.RepositoryOwner = RepositoryOwner; vm.RepositoryName = RepositoryName; vm.Id = Id; // vm.Issue = Issue; // vm.WhenAnyValue(x => x.Issue).Skip(1).Subscribe(x => Issue = x); NavigateTo(vm); }); Assignees = new IssueAssigneeViewModel( () => applicationService.GitHubClient.Issue.Assignee.GetForRepository(RepositoryOwner, RepositoryName), () => Task.FromResult(Issue), UpdateIssue); Milestones = new IssueMilestonesViewModel( () => applicationService.GitHubClient.Issue.Milestone.GetForRepository(RepositoryOwner, RepositoryName), () => Task.FromResult(Issue), UpdateIssue); Labels = new IssueLabelsViewModel( () => applicationService.GitHubClient.Issue.Labels.GetForRepository(RepositoryOwner, RepositoryName), () => Task.FromResult(Issue), UpdateIssue, graphicsService); LoadCommand = ReactiveCommand.CreateAsyncTask(async t => { var issueRequest = applicationService.GitHubClient.Issue.Get(RepositoryOwner, RepositoryName, Id) .ContinueWith(x => Issue = x.Result, new CancellationToken(), TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.FromCurrentSynchronizationContext()); var eventsRequest = applicationService.GitHubClient.Issue.Events.GetForIssue(RepositoryOwner, RepositoryName, Id); var commentsRequest = applicationService.GitHubClient.Issue.Comment.GetForIssue(RepositoryOwner, RepositoryName, Id); await Task.WhenAll(issueRequest, eventsRequest, commentsRequest); var tempList = new List <IIssueEventItemViewModel>(eventsRequest.Result.Count + commentsRequest.Result.Count); tempList.AddRange(eventsRequest.Result.Select(x => new IssueEventItemViewModel(x))); tempList.AddRange(commentsRequest.Result.Select(x => new IssueCommentItemViewModel(x))); events.Reset(tempList.OrderBy(x => x.CreatedAt)); }); ShowMenuCommand = ReactiveCommand.CreateAsyncTask( this.WhenAnyValue(x => x.Issue).Select(x => x != null), _ => { var menu = actionMenuFactory.Create(Title); menu.AddButton(Issue.State == Octokit.ItemState.Open ? "Close" : "Open", ToggleStateCommand); // // // var editButton = _actionSheet.AddButton("Edit"); // var commentButton = _actionSheet.AddButton("Comment"); // var shareButton = _actionSheet.AddButton("Share"); // var showButton = _actionSheet.AddButton("Show in GitHub"); return(menu.Show()); }); }
public ModListMetadataVM(ModListGalleryVM parent, ModlistMetadata metadata) { _parent = parent; Metadata = metadata; Location = Consts.ModListDownloadFolder.Combine(Metadata.Links.MachineURL + (string)Consts.ModListExtension); ModListTagList = new List <ModListTag>(); Metadata.tags.ForEach(tag => { ModListTagList.Add(new ModListTag(tag)); }); DownloadSizeText = "Download size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfArchives); InstallSizeText = "Installation size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfInstalledFiles); IsBroken = metadata.ValidationSummary.HasFailures; OpenWebsiteCommand = ReactiveCommand.Create(() => Utils.OpenWebsite(new Uri($"https://www.wabbajack.org/modlist/{Metadata.Links.MachineURL}"))); ExecuteCommand = ReactiveCommand.CreateFromObservable <Unit, Unit>( canExecute: this.WhenAny(x => x.IsBroken).Select(x => !x), execute: (unit) => Observable.Return(unit) .WithLatestFrom( this.WhenAny(x => x.Exists), (_, e) => e) // Do any download work on background thread .ObserveOn(RxApp.TaskpoolScheduler) .SelectTask(async(exists) => { if (!exists) { try { var success = await Download(); if (!success) { Error = ErrorResponse.Fail("Download was marked unsuccessful"); return(false); } } catch (Exception ex) { Error = ErrorResponse.Fail(ex); return(false); } // Return an updated check on exists return(Location.Exists); } return(exists); }) .Where(exists => exists) // Do any install page swap over on GUI thread .ObserveOnGuiThread() .Select(_ => { _parent.MWVM.OpenInstaller(Location); // Wait for modlist member to be filled, then open its readme return(_parent.MWVM.Installer.Value.WhenAny(x => x.ModList) .NotNull() .Take(1) .Do(modList => { try { modList.OpenReadme(); } catch (Exception ex) { Utils.Error(ex); } })); }) .Switch() .Unit()); _Exists = Observable.Interval(TimeSpan.FromSeconds(0.5)) .Unit() .StartWith(Unit.Default) .FlowSwitch(_parent.WhenAny(x => x.IsActive)) .Select(_ => { try { return(!metadata.NeedsDownload(Location)); } catch (Exception) { return(true); } }) .ToGuiProperty(this, nameof(Exists)); var imageObs = Observable.Return(Metadata.Links.ImageUri) .DownloadBitmapImage((ex) => Utils.Log($"Error downloading modlist image {Metadata.Title}")); _Image = imageObs .ToGuiProperty(this, nameof(Image)); _LoadingImage = imageObs .Select(x => false) .StartWith(true) .ToGuiProperty(this, nameof(LoadingImage)); }
public NotificationsViewModel(IApplicationService applicationService) { _applicationService = applicationService; var whenNotificationsChange = _notifications.Changed.Select(_ => Unit.Default) .Merge(_notifications.ItemChanged.Select(_ => Unit.Default)); _groupedNotifications = whenNotificationsChange.Select(_ => _notifications.GroupBy(x => x.Repository.FullName) .Select(x => new NotificationGroupViewModel(x.Key, new ReactiveList <NotificationModel>(x), __ => { }))) .ToProperty(this, t => t.GroupedNotifications); LoadCommand = ReactiveCommand.CreateAsyncTask(t => { var req = applicationService.Client.Notifications.GetAll(all: Filter.All, participating: Filter.Participating); return(this.RequestModel(req, t as bool?, response => _notifications.Reset(response.Data))); }); GoToNotificationCommand = ReactiveCommand.Create(); GoToNotificationCommand.OfType <NotificationModel>().Subscribe(GoToNotification); var canReadAll = _notifications.CountChanged.Select(x => x > 0).CombineLatest( this.WhenAnyValue(x => x.ShownIndex).Select(x => x != 2), (x, y) => x & y); ReadAllCommand = ReactiveCommand.CreateAsyncTask(canReadAll, async t => { try { if (!_notifications.Any()) { return; } await applicationService.Client.ExecuteAsync(applicationService.Client.Notifications.MarkAsRead()); _notifications.Clear(); } catch (Exception e) { throw new Exception("Unable to mark all notifications as read. Please try again.", e); } }); ReadRepositoriesCommand = ReactiveCommand.CreateAsyncTask(async t => { try { var repo = t as string; if (repo == null) { return; } var repoId = new RepositoryIdentifier(repo); await applicationService.Client.ExecuteAsync(applicationService.Client.Notifications.MarkRepoAsRead(repoId.Owner, repoId.Name)); _notifications.RemoveAll(_notifications.Where(x => string.Equals(x.Repository.FullName, repo, StringComparison.OrdinalIgnoreCase)).ToList()); } catch (Exception e) { throw new Exception("Unable to mark repositories' notifications as read. Please try again.", e); } }); this.WhenAnyValue(x => x.ShownIndex).Subscribe(x => { switch (x) { case 0: Filter = NotificationsFilterModel.CreateUnreadFilter(); break; case 1: Filter = NotificationsFilterModel.CreateParticipatingFilter(); break; default: Filter = NotificationsFilterModel.CreateAllFilter(); break; } }); this.WhenAnyValue(x => x.Filter).Skip(1).Subscribe(x => LoadCommand.ExecuteIfCan()); }
public SourceTreeViewModel(IApplicationService applicationService) { Branch = "master"; Path = string.Empty; var content = new ReactiveList <ContentModel>(); Content = content.CreateDerivedCollection( x => CreateSourceItemViewModel(x), filter: x => x.Name.ContainsKeyword(SearchKeyword), signalReset: this.WhenAnyValue(x => x.SearchKeyword)); _canAddFile = this.WhenAnyValue(x => x.TrueBranch, y => y.PushAccess) .Select(x => x.Item1 && x.Item2.HasValue && x.Item2.Value) .ToProperty(this, x => x.CanAddFile); this.WhenAnyValue(x => x.Path, y => y.RepositoryName, (x, y) => new { Path = x, Repo = y }) .Subscribe(x => { if (string.IsNullOrEmpty(x.Path)) { Title = string.IsNullOrEmpty(x.Repo) ? "Source" : x.Repo; } else { var split = x.Path.TrimEnd('/').Split('/'); Title = split[split.Length - 1]; } }); GoToAddFileCommand = ReactiveCommand.Create( this.WhenAnyValue(x => x.PushAccess, x => x.TrueBranch) .Select(x => x.Item1.HasValue && x.Item1.Value && x.Item2)) .WithSubscription(_ => { var vm = this.CreateViewModel <CreateFileViewModel>(); vm.RepositoryOwner = RepositoryOwner; vm.RepositoryName = RepositoryName; vm.Branch = Branch; vm.Path = Path; vm.SaveCommand.Subscribe(z => LoadCommand.ExecuteIfCan()); NavigateTo(vm); }); LoadCommand = ReactiveCommand.CreateAsyncTask(async _ => { if (!PushAccess.HasValue) { applicationService.GitHubClient.Repository.Get(RepositoryOwner, RepositoryName) .ToBackground(x => PushAccess = x.Permissions.Push); } var path = Path; if (string.Equals(path, "/", StringComparison.OrdinalIgnoreCase)) { path = string.Empty; } var request = applicationService.Client.Users[RepositoryOwner].Repositories[RepositoryName].GetContent(Path, Branch); var data = new List <ContentModel>(); var response = await applicationService.Client.ExecuteAsync(request); data.AddRange(response.Data); while (response.More != null) { response = await applicationService.Client.ExecuteAsync(response.More); data.AddRange(response.Data); } content.Reset(data.OrderBy(y => y.Type).ThenBy(y => y.Name)); }); }
public RepositoryCloneViewModel( IRepositoryHost repositoryHost, IRepositoryCloneService cloneService, IOperatingSystem operatingSystem, INotificationService notificationService, IUsageTracker usageTracker) { this.repositoryHost = repositoryHost; this.cloneService = cloneService; this.operatingSystem = operatingSystem; this.notificationService = notificationService; this.usageTracker = usageTracker; Title = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title); Repositories = new TrackingCollection <IRepositoryModel>(); repositories.ProcessingDelay = TimeSpan.Zero; repositories.Comparer = OrderedComparer <IRepositoryModel> .OrderBy(x => x.Owner).ThenBy(x => x.Name).Compare; repositories.Filter = FilterRepository; repositories.NewerComparer = OrderedComparer <IRepositoryModel> .OrderByDescending(x => x.UpdatedAt).Compare; filterTextIsEnabled = this.WhenAny(x => x.IsLoading, x => x.Value) .Select(x => !x && repositories.UnfilteredCount > 0) .ToProperty(this, x => x.FilterTextIsEnabled); this.WhenAny(x => x.FilterTextIsEnabled, x => x.IsLoading, x => x.LoadingFailed , (any, loading, failed) => !any.Value && !loading.Value && !failed.Value) .Subscribe(x => NoRepositoriesFound = x); this.WhenAny(x => x.FilterText, x => x.Value) .DistinctUntilChanged(StringComparer.OrdinalIgnoreCase) .Throttle(TimeSpan.FromMilliseconds(100), RxApp.MainThreadScheduler) .Subscribe(_ => repositories.Filter = FilterRepository); var baseRepositoryPath = this.WhenAny( x => x.BaseRepositoryPath, x => x.SelectedRepository, (x, y) => x.Value); BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(baseRepositoryPath) .IfNullOrEmpty(Resources.RepositoryCreationClonePathEmpty) .IfTrue(x => x.Length > 200, Resources.RepositoryCreationClonePathTooLong) .IfContainsInvalidPathChars(Resources.RepositoryCreationClonePathInvalidCharacters) .IfPathNotRooted(Resources.RepositoryCreationClonePathInvalid) .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists); var canCloneObservable = this.WhenAny( x => x.SelectedRepository, x => x.BaseRepositoryPathValidator.ValidationResult.IsValid, (x, y) => x.Value != null && y.Value); canClone = canCloneObservable.ToProperty(this, x => x.CanClone); CloneCommand = ReactiveCommand.CreateAsyncObservable(canCloneObservable, OnCloneRepository); browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog()); this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value) .Subscribe(); BaseRepositoryPath = cloneService.DefaultClonePath; NoRepositoriesFound = true; }
private CommandVM(ReactiveCommand <Unit, Unit> cmd) { Command = cmd; _CanExecute = cmd.CanExecute .ToProperty(this, nameof(CanExecute), initialValue: false); }
public PatchersRunVM(ConfigurationVM parent, ProfileVM profile) { Config = parent; RunningProfile = profile; Patchers.AddOrUpdate(RunningProfile.Patchers.Items .Where(x => x.IsOn) .Select(p => p.ToRunner(this))); PatchersDisplay = Patchers.Connect() .ToObservableCollection(this); if (parent.SelectedPatcher != null && Patchers.TryGetValue(parent.SelectedPatcher.InternalID, out var run)) { SelectedPatcher = run; } BackCommand = ReactiveCommand.Create(() => { parent.SelectedPatcher = SelectedPatcher?.Config; parent.MainVM.ActivePanel = parent; }, canExecute: this.WhenAnyValue(x => x.Running) .Select(running => !running)); CancelCommand = ReactiveCommand.CreateFromTask( execute: Cancel, canExecute: this.WhenAnyValue(x => x.Running)); _reporter.Overall .ObserveOnGui() .Subscribe(ex => { Log.Logger.Error(ex, "Error while running patcher pipeline"); ResultError = ex; }) .DisposeWith(this); _reporter.PrepProblem .Select(data => (data, type: "prepping")) .Merge(_reporter.RunProblem .Select(data => (data, type: "running"))) .ObserveOnGui() .Subscribe(i => { var vm = Patchers.Get(i.data.Key); vm.State = GetResponse <RunState> .Fail(RunState.Error, i.data.Error); SelectedPatcher = vm; Log.Logger .ForContext(nameof(PatcherVM.DisplayName), i.data.Run.Name) .Error(i.data.Error, $"Error while prepping {i.type}"); }) .DisposeWith(this); _reporter.Starting .ObserveOnGui() .Subscribe(i => { var vm = Patchers.Get(i.Key); vm.State = GetResponse <RunState> .Succeed(RunState.Started); Log.Logger .ForContext(nameof(PatcherVM.DisplayName), i.Run.Name) .Information($"Starting"); }) .DisposeWith(this); _reporter.RunSuccessful .ObserveOnGui() .Subscribe(i => { var vm = Patchers.Get(i.Key); vm.State = GetResponse <RunState> .Succeed(RunState.Finished); Log.Logger .ForContext(nameof(PatcherVM.DisplayName), i.Run.Name) .Information("Finished {RunTime}", vm.RunTime); }) .DisposeWith(this); _reporter.Output .Subscribe(s => { Log.Logger .ForContextIfNotNull(nameof(PatcherVM.DisplayName), s.Run?.Name) .Information(s.String); }) .DisposeWith(this); _reporter.Error .Subscribe(s => { Log.Logger .ForContextIfNotNull(nameof(PatcherVM.DisplayName), s.Run?.Name) .Error(s.String); }) .DisposeWith(this); // Clear selected patcher on showing error this.ShowOverallErrorCommand.StartingExecution() .Subscribe(_ => this.SelectedPatcher = null) .DisposeWith(this); _DetailDisplay = Observable.Merge( this.WhenAnyValue(x => x.SelectedPatcher) .Select(i => i as object), this.ShowOverallErrorCommand.EndingExecution() .Select(_ => ResultError == null ? null : new OverallErrorVM(ResultError))) .ToGuiProperty(this, nameof(DetailDisplay)); }
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)); }
public RenameFileViewModel( IProviderViewModel providerViewModel, IProvider provider, IScheduler current, IScheduler main) { _oldName = providerViewModel .WhenAnyValue(x => x.SelectedFile) .Select(file => file?.Name) .ToProperty(this, x => x.OldName, scheduler: current); var canInteract = providerViewModel .WhenAnyValue(x => x.CanInteract); var oldNameValid = this .WhenAnyValue(x => x.OldName) .Select(old => !string.IsNullOrWhiteSpace(old)); var canOpen = this .WhenAnyValue(x => x.IsVisible) .Select(visible => !visible) .CombineLatest(oldNameValid, (visible, old) => visible && old) .CombineLatest(canInteract, (open, interact) => open && interact); _open = ReactiveCommand.Create( () => { IsVisible = true; }, canOpen, main); var canClose = this .WhenAnyValue(x => x.IsVisible) .Select(visible => visible); _close = ReactiveCommand.Create( () => { IsVisible = false; }, canClose, main); var canRename = this .WhenAnyValue(x => x.NewName) .Select(name => !string.IsNullOrWhiteSpace(name)) .CombineLatest(oldNameValid, (old, name) => old && name); _rename = ReactiveCommand.CreateFromTask( () => provider.RenameFile(providerViewModel.SelectedFile.Path, NewName), canRename, main); _isLoading = _rename .IsExecuting .ToProperty(this, x => x.IsLoading, scheduler: current); _hasErrors = _rename .ThrownExceptions .Select(exception => true) .Merge(_close.Select(x => false)) .ToProperty(this, x => x.HasErrors, scheduler: current); _errorMessage = _rename .ThrownExceptions .Select(exception => exception.Message) .Log(this, $"Rename file error occured in {provider.Name} for {OldName}") .Merge(_close.Select(x => string.Empty)) .ToProperty(this, x => x.ErrorMessage, scheduler: current); _rename.InvokeCommand(_close); _close.Subscribe(x => NewName = string.Empty); }