Пример #1
0
        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.Acceptable)
                {
                    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), default(string?))),
                needBuild: true)
                              .DisposeWith(this);
        }
Пример #2
0
        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)
                       .Select(_ =>
                {
                    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;
            })
            .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),
                metaPath,
                (nickname, shortDesc, desc, visibility, versioning, meta) => (nickname, shortDesc, desc, visibility, versioning, 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
                    },
                                          Formatting.Indented,
                                          Execution.Constants.JsonSettings));
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, "Error writing out meta");
                }
            })
            .DisposeWith(this);
        }