コード例 #1
0
        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;
                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;
                Search        = string.Empty;
                GameType      = ALL_GAME_TYPE;
            });


            this.WhenAny(x => x.OnlyInstalled)
            .Subscribe(val =>
            {
                if (val)
                {
                    GameType = ALL_GAME_TYPE;
                }
            })
            .DisposeWith(CompositeDisposable);

            var random     = new Random();
            var sourceList = Observable.Return(Unit.Default)
                             .ObserveOn(RxApp.TaskpoolScheduler)
                             .SelectTask(async _ =>
            {
                try
                {
                    Error    = null;
                    var list = await ModlistMetadata.LoadFromGithub();
                    Error    = ErrorResponse.Success;
                    return(list
                           // Sort randomly initially, just to give each list a fair shake
                           .Shuffle(random)
                           .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));
            }))
            .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 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());
            }))
            .Filter(this.WhenAny(x => x.ShowNSFW)
                    .Select <bool, Func <ModListMetadataVM, bool> >(showNSFW => vm =>
            {
                if (!vm.Metadata.NSFW)
                {
                    return(true);
                }
                return(vm.Metadata.NSFW && showNSFW);
            }))
            // Put broken lists at bottom
            .Sort(Comparer <ModListMetadataVM> .Create((a, b) => a.IsBroken.CompareTo(b.IsBroken)))
            .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);
        }
コード例 #2
0
        public ModListMetadataVM(ModListGalleryVM parent, ModlistMetadata metadata)
        {
            _parent            = parent;
            Metadata           = metadata;
            Location           = Path.Combine(Consts.ModListDownloadFolder, Metadata.Links.MachineURL + ExtensionManager.Extension);
            IsBroken           = metadata.ValidationSummary.HasFailures;
            OpenWebsiteCommand = ReactiveCommand.Create(() => Process.Start($"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(File.Exists(Location));
                }
                return(exists);
            })
                .Where(exists => exists)
                // Do any install page swap over on GUI thread
                .ObserveOnGuiThread()
                .Select(_ =>
            {
                _parent.MWVM.OpenInstaller(Path.GetFullPath(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.OpenReadmeWindow();
                    }
                    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));
        }