/// <summary> /// Constructs in an instance of <see cref="PersistentVirtualizingSource{TEntity, TKey}"/>. /// </summary> /// <param name="queryFactory">The query factory.</param> /// <param name="itemSpecification">The specification specifies how to retrieve the items.</param> /// <param name="indexSpecification">The specification specifies how to get the index of a given item.</param> public PersistentVirtualizingSource( IProfileDataQueryFactory queryFactory, ISpecification <TEntity, TEntity> itemSpecification, Func <TEntity, ISpecification <TEntity, TEntity> > indexSpecification) { _queryFactory = queryFactory; _itemSpecification = itemSpecification; _indexSpecification = indexSpecification; }
private static IObservable <(int UnreadCount, int TotalCount)> CountMessages( IProfileDataQueryFactory queryFactory, string folderId) { return(Observable.Start(() => { using var query = queryFactory.Connect(); var unreadCount = query.MessageSummaries.Count(m => m.FolderId == folderId && !m.IsRead); var totalCount = query.MessageSummaries.Count(m => m.FolderId == folderId); return (UnreadCount: unreadCount, TotalCount: totalCount); }, RxApp.TaskpoolScheduler)); }
public MessageSummaryViewModel(MessageSummary state, MessageListViewModel list, IProfileDataQueryFactory queryFactory) { _detail = new Lazy <MessageDetailViewModel>(() => new MessageDetailViewModel(state, queryFactory)); Id = state.Id; Refresh(state); Archive = ReactiveCommand.CreateFromObservable(() => list.Archive.Execute(new[] { Id })); Delete = ReactiveCommand.CreateFromObservable(() => list.Delete.Execute(new[] { Id })); ToggleFlag = ReactiveCommand.CreateFromObservable(() => { var command = IsFlagged ? list.ClearFlag : list.SetFlag; IsFlagged = !IsFlagged; return(command.Execute(new[] { Id })); }); ToggleFlag.ThrownExceptions .ObserveOn(RxApp.MainThreadScheduler) .Do(_ => IsFlagged = !IsFlagged) .Subscribe() .DisposeWith(_disposables); ToggleRead = ReactiveCommand.CreateFromObservable(() => { var command = IsRead ? list.MarkAsUnread : list.MarkAsRead; IsRead = !IsRead; return(command.Execute(new[] { Id }) .Do(_ => _markingAsReadSubscription.Disposable = null)); }); ToggleRead.ThrownExceptions .ObserveOn(RxApp.MainThreadScheduler) .Do(_ => IsRead = !IsRead) .Subscribe() .DisposeWith(_disposables); Move = ReactiveCommand.CreateFromObservable(() => list.Move.Execute(new[] { Id })); MoveToJunk = ReactiveCommand.CreateFromObservable(() => list.Move.Execute(new[] { Id })); }
public MessageDetailViewModel(MessageSummary summary, IProfileDataQueryFactory queryFactory) { _id = summary.Id; _queryFactory = queryFactory; Refresh(summary); }
public MessageListViewModel(string folderId, FolderType folderType, MailBoxViewModel mailBox, IProfileDataQueryFactory queryFactory, IMailService mailService, ViewModelActivator activator) { var canExecute = this.WhenAnyObservable(x => x.Cache.SelectionChanged) .Select(x => x.IndexCount() > 0) .Publish(); Activator = activator; Archive = ReactiveCommand.Create <IReadOnlyList <string> >(async messageIds => { PrepareMessageIds(ref messageIds); await mailService.MoveMessage(messageIds, FolderType.Archive); }, canExecute); Delete = ReactiveCommand.Create <IReadOnlyList <string> >(async messageIds => { PrepareMessageIds(ref messageIds); if (folderType != FolderType.DeletedItems) { await mailService.MoveMessage(messageIds, FolderType.DeletedItems); } }, canExecute); MarkAsRead = ReactiveCommand.Create <IReadOnlyList <string> >(async messageIds => { PrepareMessageIds(ref messageIds); await mailService.UpdateMessage(messageIds) .Set(m => m.IsRead, true) .ExecuteAsync(); }, canExecute); MarkAsUnread = ReactiveCommand.Create <IReadOnlyList <string> >(async messageIds => { PrepareMessageIds(ref messageIds); await mailService.UpdateMessage(messageIds) .Set(m => m.IsRead, false) .ExecuteAsync(); }, canExecute); SetFlag = ReactiveCommand.Create <IReadOnlyList <string> >(async messageIds => { PrepareMessageIds(ref messageIds); await mailService.UpdateMessage(messageIds) .Set(m => m.IsFlagged, true) .ExecuteAsync(); }, canExecute); ClearFlag = ReactiveCommand.Create <IReadOnlyList <string> >(async messageIds => { PrepareMessageIds(ref messageIds); await mailService.UpdateMessage(messageIds) .Set(m => m.IsFlagged, false) .ExecuteAsync(); }, canExecute); Move = ReactiveCommand.CreateFromTask <IReadOnlyList <string> >(async messageIds => { PrepareMessageIds(ref messageIds); var selectionResult = await mailBox.PromptUserToSelectFolder( messageIds.Count == 1 ? "Move a message" : $"Move {messageIds.Count} messages", "Select another folder to move to:", includeRoot: false, destinationFolder => CanMoveTo(folderId, destinationFolder)); if (!selectionResult.IsCancelled) { await mailService.MoveMessage(messageIds, selectionResult.SelectedFolder.Id); } }, canExecute); MoveToJunk = ReactiveCommand.CreateFromTask <IReadOnlyList <string> >(async messageIds => { PrepareMessageIds(ref messageIds); await mailService.MoveMessage(messageIds, FolderType.Junk); }, canExecute); this.WhenActivated(disposables => { canExecute.Connect() .DisposeWith(disposables); Archive.ThrownExceptions .Do(this.Log().Error) .Subscribe() .DisposeWith(disposables); Delete.ThrownExceptions .Do(this.Log().Error) .Subscribe() .DisposeWith(disposables); SetFlag.ThrownExceptions .Do(this.Log().Error) .Subscribe() .DisposeWith(disposables); ClearFlag.ThrownExceptions .Do(this.Log().Error) .Subscribe() .DisposeWith(disposables); MarkAsRead.ThrownExceptions .Do(this.Log().Error) .Subscribe() .DisposeWith(disposables); MarkAsUnread.ThrownExceptions .Do(this.Log().Error) .Subscribe() .DisposeWith(disposables); Move.ThrownExceptions .Do(this.Log().Error) .Subscribe() .DisposeWith(disposables); MoveToJunk.ThrownExceptions .Do(this.Log().Error) .Subscribe() .DisposeWith(disposables); Observable.CombineLatest( this.WhenAnyValue(x => x.Order), this.WhenAnyValue(x => x.Filter), (order, filter) => (Order: order, Filter: filter)) .DistinctUntilChanged() .Where(x => x.Order != MessageOrder.Sender) .Subscribe(x => { Cache?.Dispose(); Cache = new VirtualizingCache <MessageSummary, MessageSummaryViewModel, string>( new PersistentVirtualizingSource <MessageSummary, string>(queryFactory, GetItemSpecification(folderId, x.Order, x.Filter), GetIndexSpecification(folderId, x.Order, x.Filter)), mailService.MessageChanges .Select(changes => FilterChanges(changes.ForFolder(folderId), x.Filter)), state => new MessageSummaryViewModel(state, this, queryFactory)); }) .DisposeWith(disposables); this.WhenAnyObservable(x => x.Cache.SelectionChanged) .Select(ranges => ranges.Sum(r => r.Length)) .Do(x => SelectionCount = x) .Subscribe() .DisposeWith(disposables); Disposable.Create(() => { Filter = MessageFilter.None; Cache?.Dispose(); Cache = null; IsSelecting = false; SelectionCount = 0; }) .DisposeWith(disposables); }); }
public MailFolderViewModel(Node <MailFolder, string> node, MailBoxViewModel mailBox, IProfileDataQueryFactory queryFactory, IMailService mailService) { Id = node.Item.Id; ParentId = node.Item.ParentId; Name = node.Item.Name; Type = node.Item.Type; IsFavorite = node.Item.IsFavorite; Messages = new MessageListViewModel(node.Item.Id, node.Item.Type, mailBox, queryFactory, mailService, Activator); Synchronize = ReactiveCommand.CreateFromObservable(() => Observable .StartAsync((token) => mailService.SynchronizeMessagesAsync(node.Item.Id, token)) .TakeUntil(CancelSynchronization)); Synchronize.IsExecuting .ToPropertyEx(this, x => x.IsSynchronizing) .DisposeWith(_disposables); Synchronize.ThrownExceptions .Subscribe(ex => this.Log().Error(ex)) .DisposeWith(_disposables); CancelSynchronization = ReactiveCommand.Create(() => { }, Synchronize.IsExecuting); Move = ReactiveCommand.CreateFromTask(async() => { var result = await mailBox.PromptUserToSelectFolder( "Move a folder", "Select another folder to move to:", includeRoot: true, CanMoveTo); this.Log().Debug(result); }); node.Children.Connect() .Transform(n => new MailFolderViewModel(n, mailBox, queryFactory, mailService)) .Sort(SortExpressionComparer <MailFolderViewModel> .Ascending(f => f.Name)) .ObserveOn(RxApp.MainThreadScheduler) .Bind(out _childFolders) .DisposeMany() .Subscribe() .DisposeWith(_disposables); mailService.MessageChanges .Where(changes => changes.AffectsFolder(node.Item.Id)) .SelectMany(_ => CountMessages(queryFactory, node.Item.Id)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { UnreadCount = x.UnreadCount; TotalCount = x.TotalCount; }) .DisposeWith(_disposables); CountMessages(queryFactory, node.Item.Id) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { UnreadCount = x.UnreadCount; TotalCount = x.TotalCount; }) .DisposeWith(_disposables); }
public MailBoxViewModel(IProfileDataQueryFactory queryFactory, IMailService mailService) { _queryFactory = queryFactory; _mailService = mailService; _mailFolderSelectionViewModel = new MailFolderSelectionViewModel(_sourceFolders.AsObservableCache()); var folderChanges = _sourceFolders.Connect(f => f.Type != FolderType.Root) .ObserveOn(RxApp.TaskpoolScheduler) .Sort(SortExpressionComparer <MailFolder> .Ascending(f => f.Type).ThenByAscending(f => f.Name)) .TransformToTree(f => f.ParentId) .Transform(n => new MailFolderViewModel(n, this, queryFactory, mailService)) .DisposeMany() .Publish(); folderChanges .ObserveOn(RxApp.MainThreadScheduler) .Bind(out _allFolders) .Subscribe() .DisposeWith(_disposables); folderChanges .Filter(f => f.IsFavorite) .ObserveOn(RxApp.MainThreadScheduler) .Bind(out _favoriteFolders) .Subscribe() .DisposeWith(_disposables); folderChanges.Connect() .DisposeWith(_disposables); var folderCollection = folderChanges .ToCollection() .Publish(); folderCollection .Select(folders => folders.FirstOrDefault(f => f.Type == FolderType.Inbox)) .ObserveOn(RxApp.MainThreadScheduler) .ToPropertyEx(this, x => x.Inbox) .DisposeWith(_disposables); folderCollection.Connect() .DisposeWith(_disposables); _mailService.FolderChanges .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(changes => { _sourceFolders.Edit(updater => { foreach (var c in changes) { switch (c.State) { case DeltaState.Add: case DeltaState.Update: updater.AddOrUpdate(c.Entity); break; case DeltaState.Remove: updater.RemoveKey(c.Entity.Id); break; } } }); }) .DisposeWith(_disposables); Synchronize = ReactiveCommand.CreateFromTask(_mailService.SynchronizeFoldersAsync); //Synchronize.WithLatestFrom(folderCollection, (_, folders) => folders.Where(f => f.IsFavorite)) // .Subscribe(favoriteFolders => // { // foreach (var f in favoriteFolders) // { // f.Synchronize.Execute().Subscribe(); // } // }) // .DisposeWith(_disposables); Synchronize.ThrownExceptions .Subscribe(ex => this.Log().Error(ex)) .DisposeWith(_disposables); Synchronize.IsExecuting .ToPropertyEx(this, x => x.IsSynchronizing) .DisposeWith(_disposables); }