/// <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;
 }
Exemple #2
0
 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 }));
        }
Exemple #4
0
 public MessageDetailViewModel(MessageSummary summary, IProfileDataQueryFactory queryFactory)
 {
     _id           = summary.Id;
     _queryFactory = queryFactory;
     Refresh(summary);
 }
Exemple #5
0
        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);
            });
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        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);
        }