public CreateProjectProgressViewModel(FlutnetAppSettings appSettings, FlutnetProjectSettings projectSettings, NewProjectViewModel screen = null) : base("newprj_progress", screen) { _appSettings = appSettings; _projectSettings = projectSettings; Title = "New Project"; Description = "The project will take some time to generate.\nWait until the procedure finish.\n"; IsDescriptionVisible = false; NextText = "Finish"; BackVisible = false; IsFinishPage = true; OutputLines = new ObservableCollection <string>(); // Observe any changes in the observable collection. // Note that the property has no public setters, so we // assume the collection is mutated by using the Add(), // Delete(), Clear() and other similar methods. OutputLines // Convert the collection to a stream of chunks, // so we have IObservable<IChangeSet<TKey, TValue>> // type also known as the DynamicData monad. .ToObservableChangeSet() // Each time the collection changes, we get // all updated items at once. .ToCollection() // Aggregate all the elements in the collection // into a multi-line string. .Select(lines => string.Join(Environment.NewLine, lines)) // Then, we convert the multi-line string to the // property a multi-line TextBox can bind. .ToProperty(this, x => x.Output, out _output, scheduler: RxApp.MainThreadScheduler); // Create the command that calls Flutnet CLI CreateProject = ReactiveCommand.CreateFromTask(async ct => { NewProjectInArg arguments = BuildCommandLineArg(); CommandLineCallResult callResult = await CommandLineTools.Call <NewProjectOutArg>(arguments, ct, line => { OutputLines.Add(line); }); // This is not the proper way to change property values and raise property change notifications: // we should return a public object and subscribe to the command observable // so that we can use ReactiveUI framework methods such as ToProperty, BindTo etc. if (callResult.Canceled) { IsCanceled = true; } else if (callResult.Failed) { IsFailed = true; } else { OutArg result = callResult.CommandResult; if (!result.Success) { IsFailed = true; } else { IsCompletedSuccessfully = true; } } }); CreateProject.IsExecuting.ToProperty(this, x => x.IsInProgress, out _isInProgress); CreateProject.IsExecuting.BindTo(this, x => x.IsBusy); BrowseProject = ReactiveCommand.Create( execute: () => Launcher.OpenFolder(Path.Combine(projectSettings.Location, projectSettings.SolutionName)), canExecute: this.WhenAnyValue(t => t.IsCompletedSuccessfully)); // Execute the command when the View is activated Activator = new ViewModelActivator(); this.WhenActivated(disposables => { CreateProject.Execute(Unit.Default).Subscribe().DisposeWith(disposables); }); this.WhenAnyValue(t => t.IsInProgress, t => !t).BindTo(this, t => t.NextEnabled); }
public ConfigureProjectViewModel(FlutnetAppSettings appSettings, IScreen screen = null) : base("newprj_project", screen) { _appSettings = appSettings; Title = "New Project"; Description = "Edit project settings: you'll see a preview in the right panel.\nPressing \"Create\" will generate the project folder and all relative files."; IsDescriptionVisible = true; NextText = "Create"; IsFinishPage = false; BrowseLocation = ReactiveCommand.CreateFromTask(BrowseLocationAsync); BrowseLocation.Where(t => !string.IsNullOrEmpty(t)).BindTo(this, t => t.Location); AppSettings.Default.Preferences.Reload(); _location = !string.IsNullOrEmpty(AppSettings.Default.Preferences.LastProjectLocation) ? AppSettings.Default.Preferences.LastProjectLocation : OperatingSystem.DefaultProjectsLocation(); if (appSettings != null) { string projectName = AppNameToProjectName(appSettings.AppName); if (!string.IsNullOrEmpty(projectName)) { _projectName = projectName; } } else { _projectName = DefaultProjectName; _solutionName = DefaultSolutionName; _flutterModuleName = DefaultFlutterModuleName; } this.WhenAnyValue(t => t.ProjectName) .Do(t => { this.RaisePropertyChanged(nameof(SolutionName)); this.RaisePropertyChanged(nameof(FlutterModuleName)); }) .Select(t => ToSafeFilename(t, DefaultAppName)) .ToProperty(this, t => t.OutputProjectName, out _outputProjectName, initialValue: ProjectName); this.WhenAnyValue(t => t.OutputProjectName) .Select(t => $"{t}.Android") .ToProperty(this, t => t.OutputProjectDroidName, out _outputProjectDroidName, initialValue: $"{OutputProjectName}.Android"); this.WhenAnyValue(t => t.OutputProjectName) .Select(t => $"{t}.iOS") .ToProperty(this, t => t.OutputProjectIosName, out _outputProjectIosName, initialValue: $"{OutputProjectName}.iOS"); this.WhenAnyValue(t => t.OutputProjectName) .Select(t => $"{t}.ServiceLibrary") .ToProperty(this, t => t.OutputProjectServiceLibName, out _outputProjectServiceLibName, initialValue: $"{OutputProjectName}.ServiceLibrary"); this.WhenAnyValue(t => t.SolutionName) .Select(t => ToSafeFilename(t, DefaultSolutionName)) .ToProperty(this, t => t.OutputSolutionName, out _outputSolutionName, initialValue: SolutionName ?? DefaultSolutionName); this.WhenAnyValue(t => t.FlutterModuleName) .Select(ToSafeDartPackageName) .ToProperty(this, t => t.OutputFlutterModuleName, out _outputFlutterModuleName, initialValue: FlutterModuleName ?? DefaultFlutterModuleName); this.WhenAnyValue(t => t.OutputFlutterModuleName) .Select(t => $"{t}_bridge") .ToProperty(this, t => t.OutputFlutterPackageName, out _outputFlutterPackageName, initialValue: $"{OutputFlutterModuleName}_bridge"); this.WhenAnyValue( t => t.ProjectName, t => t.SolutionName, t => t.FlutterModuleName, (prj, sln, flutter) => !string.IsNullOrWhiteSpace(prj) && !string.IsNullOrWhiteSpace(sln) && !string.IsNullOrWhiteSpace(flutter)) .BindTo(this, t => t.NextEnabled); BuildProjectTree(); // Command to check if the installed version of Flutter is supported CheckFlutterVersion = ReactiveCommand.CreateFromTask(async ct => { CommandLineCallResult callResult = await CommandLineTools.Call <FlutterInfoInArg, FlutterInfoOutArg>(ct); if (callResult.Canceled || callResult.Failed) { FlutterVersionHasIssues = true; FlutterVersionNotes = "Unable to detect installed Flutter version. Compatibility with Flutnet unknown."; return; } FlutterInfoOutArg result = (FlutterInfoOutArg)callResult.CommandResult; if (!result.Success) { FlutterVersionHasIssues = true; FlutterVersionNotes = "Unable to detect installed Flutter version. Compatibility with Flutnet unknown."; return; } StringBuilder sb = new StringBuilder(); sb.AppendLine($"Installed Flutter version: {result.InstalledVersion}"); switch (result.Compatibility) { case FlutterCompatibility.Supported: FlutterVersionHasIssues = false; break; case FlutterCompatibility.SupportNotGuaranteed: FlutterVersionHasIssues = true; sb.AppendLine("This version is NOT officially compatible with Flutnet and the resulting projects may not work or may exhibit unexpected behaviors."); if (!string.IsNullOrEmpty(result.NextSupportedVersion)) { sb.AppendLine($"We recommend that you update Flutter to the latest supported version ({result.LatestSupportedVersion})."); } else { sb.AppendLine($"The latest supported version is {result.LatestSupportedVersion}."); } break; case FlutterCompatibility.NotSupported: FlutterVersionHasIssues = true; NextEnabled = false; sb.AppendLine("Unfortunately this version is NOT compatible with Flutnet."); sb.AppendLine($"Please update Flutter to the latest supported version ({result.LatestSupportedVersion})."); break; } FlutterVersion = result.InstalledVersion; FlutterVersionNotes = sb.ToString(); }); CheckFlutterVersion.IsExecuting.BindTo(this, x => x.IsBusy); this.WhenAnyValue(t => t.IsBusy).Select(t => !t).BindTo(this, p => p.NextEnabled); FlutterVersionNotes = "Retrieving information about the installed version of Flutter..."; }