public SetupAssistedProgressViewModel(FlutnetSetupInArg setupArguments, IScreen screen = null) : base("setup_assisted_progress", screen) { Title = "Configuration in progress"; Button1Visible = false; Button2Visible = false; Button3Visible = false; // Create the command that calls Flutnet CLI RunDiagnostic = ReactiveCommand.CreateFromTask(async ct => { CommandLineCallResult callResult = await CommandLineTools.Call <FlutnetSetupOutArg>(setupArguments, ct); // 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. SetupResult overallResult = null; FlutnetSetupOutArg setupResult = null; if (callResult.Canceled) { // Jump to finish page and notify the user that the operation has been canceled. overallResult = new SetupResult { OperationCanceled = true }; } else if (callResult.Failed) { // Jump to finish page and notify the user that an unexpected error occured. overallResult = new SetupResult { OperationFailed = true }; } else { FlutnetSetupOutArg result = (FlutnetSetupOutArg)callResult.CommandResult; if (!result.Success) { // Jump to finish page and notify the user that an unexpected error occured. overallResult = new SetupResult { OperationFailed = true }; } else { //setupResult = result; overallResult = new SetupResult { OperationResult = setupResult }; } } if (overallResult != null) { await HostScreen.Router.Navigate.Execute(new SetupFinishViewModel(overallResult, this, HostScreen)); } else { //await HostScreen.Router.Navigate.Execute(new SetupCheckFlutterErrorViewModel(checkResult, HostScreen)); } }); RunDiagnostic.IsExecuting.ToProperty(this, x => x.IsInProgress, out _isInProgress); RunDiagnostic.IsExecuting.BindTo(this, x => x.IsBusy); // Execute the command when the View is activated this.WhenActivated(disposables => { RunDiagnostic.Execute(Unit.Default).Subscribe().DisposeWith(disposables); }); }
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..."; }
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 AboutViewModel(IScreen hostScreen) : base("about", hostScreen) { Title = "About"; Description = ""; IsDescriptionVisible = false; OpenFlutnetWebsite = ReactiveCommand.Create(() => Launcher.OpenURL(FlutnetHome)); ContactFlutnetInfo = ReactiveCommand.Create(() => Launcher.MailTo("*****@*****.**")); ContactFlutnetSupport = ReactiveCommand.Create(() => Launcher.MailTo("*****@*****.**")); DownloadNewVersion = ReactiveCommand.Create(() => Launcher.OpenURL(_newVersionUrl)); // Create the command that calls Flutnet CLI // for contacting the server and checking for updates CheckForUpdates = ReactiveCommand.CreateFromTask(async ct => { CommandLineCallResult callResult = await CommandLineTools.Call <UpdateCheckInArg, UpdateCheckOutArg>(ct); // 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 || callResult.Failed) { IsNewVersionAvailable = false; FlutnetVersionMessage = "An unexpected error occured, please retry."; } else { UpdateCheckOutArg result = (UpdateCheckOutArg)callResult.CommandResult; if (!result.Success) { IsNewVersionAvailable = false; FlutnetVersionMessage = result.ErrorMessage; } else if (result.UpToDate) { IsNewVersionAvailable = false; FlutnetVersionMessage = "Your software is up to date."; } else { IsNewVersionAvailable = true; FlutnetVersionMessage = $"A new version of Flutnet ({result.NewVersion}) is available."; _newVersionUrl = result.DownloadUrl; } } }); CheckForUpdates.IsExecuting.ToProperty(this, x => x.IsCheckingForUpdates, out _isCheckingForUpdates); CheckForUpdates.IsExecuting.BindTo(this, x => x.IsBusy); this.WhenAnyValue(t => t.CheckForUpdatesAtStartup).Skip(1).Subscribe(value => { AppSettings.Default.Preferences.CheckForUpdatesAtStartup = value; AppSettings.Default.Preferences.Save(); }); // Load user preferences when the view is activated this.WhenActivated((Action <IDisposable> disposables) => { AppSettings.Default.Preferences.Reload(); CheckForUpdatesAtStartup = AppSettings.Default.Preferences.CheckForUpdatesAtStartup; CurrentFlutnetVersion = Assembly.GetExecutingAssembly().GetProductVersion(); }); }