Beispiel #1
0
        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);
        }