using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reactive; using System.Reactive.Linq; using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input.Platform; using DesertPaintCodex.Models; using DesertPaintCodex.Services; using ReactiveUI; namespace DesertPaintCodex.ViewModels { public class MainWindowViewModel : ViewModelBase { private string _statusText = string.Empty; public string StatusText { get => _statusText; private set => this.RaiseAndSetIfChanged(ref _statusText, value); } private static readonly List ZipFileExtensions = new() {"zip"}; private static readonly FileDialogFilter ZipFileFilter = new() {Extensions = ZipFileExtensions, Name = "Zip"}; private static readonly List ZipFileFilters = new() {ZipFileFilter}; private static readonly List TxtFileExtensions = new() {"txt"}; private static readonly FileDialogFilter TxtFileFilter = new() {Extensions = TxtFileExtensions, Name = "Text"}; private static readonly List TxtFileFilters = new() {TxtFileFilter}; private static readonly List NoFileFilters = new(); public MainWindowViewModel() { if (!ProfileManager.HasProfileLoaded && ProfileManager.HasProfiles()) { ProfileManager.LoadProfile(ProfileManager.GetProfileList()[0]); } Debug.Assert(ProfileManager.HasProfileLoaded); PaletteService.Initialize(); ReactionTestService.Initialize(); ShowAboutDialog = new Interaction(); ShowScreenSettingsDialog = new Interaction(); StatusText = "USER PROFILE: " + ProfileManager.CurrentProfile?.Name; Exit = ReactiveCommand.Create(() => { }); } public async void ManageProfiles() { if (Application.Current is not App app) return; if (await ValidateSafeExit()) { ProfileManager.UnloadProfile(); app.ReturnToWelcome(); } } public async void ImportProfile() { string? fileName = await GetLoadFileName("Open Zipped Profile", ZipFileFilters); if (string.IsNullOrEmpty(fileName)) return; try { ProfileManager.CurrentProfile?.Import(fileName); } catch (Exception e) { Debug.WriteLine("ImportProfile threw exception " + e); await ShowMessageBox("Import Failed", "Your file could not be imported. It must be a zip file containing a Desert Paint Codex profile.", "OK"); } ProfileManager.ReloadProfile(); if (Application.Current is not App app) return; app.RefreshMainWindow(); } public async void ExportProfile() { string? fileName = await GetSaveFileName("Save Zipped Profile", ZipFileFilters); if (string.IsNullOrEmpty(fileName)) return; try { ProfileManager.CurrentProfile?.Export(fileName); } catch (Exception e) { Debug.WriteLine("ExportProfile threw exception " + e); await ShowMessageBox("Export Failed", "Your profile could not be exported. Please ensure that you are providing a valid filename for the zip file that we are creating.", "OK"); } } public async void ExportForPP(object f) { string? fileName = await GetSaveFileName("Save Practical Paint File", TxtFileFilters, "reactions.txt"); if (string.IsNullOrEmpty(fileName)) return; try { ProfileManager.CurrentProfile?.SaveToPP(fileName); } catch (Exception e) { Debug.WriteLine("ExportForPP threw exception " + e); await ShowMessageBox("Export Failed", "Please ensure that you have provided a valid file path for your reactions file.", "OK"); } } public async void ImportFromPP() { string? fileName = await GetLoadFileName("Import Reactions File", TxtFileFilters, "reactions.txt"); if (string.IsNullOrEmpty(fileName)) return; try { ProfileManager.CurrentProfile?.ImportFromPP(fileName); } catch (Exception e) { Debug.WriteLine("ImportFromPP threw exception " + e); await ShowMessageBox("Import Failed", "Your file could not be imported. It must be a valid Practical Paint reactions.txt file.", "OK"); } ProfileManager.ReloadProfile(); if (Application.Current is not App app) return; app.RefreshMainWindow(); } public static async void ExportPaintRecipes() { string? fileName = await GetSaveFileName("Export Paint Recipes", NoFileFilters); if (!string.IsNullOrEmpty(fileName)) { ProfileManager.CurrentProfile?.ExportWikiRecipes(fileName); } } public static async void ExportRibbonRecipes() { string? fileName = await GetSaveFileName("Export Ribbon Recipes", NoFileFilters); if (!string.IsNullOrEmpty(fileName)) { ProfileManager.CurrentProfile?.ExportWikiRibbons(fileName); } } public static async void CopyPaintRecipes() { StringWriter writer = new(); ProfileManager.CurrentProfile?.ExportWikiRecipes(writer); IClipboard clipboard = Application.Current.Clipboard; await writer.FlushAsync(); await clipboard.SetTextAsync(writer.ToString()); writer.Close(); } public static async void CopyRibbonRecipes() { StringWriter writer = new(); ProfileManager.CurrentProfile?.ExportWikiRibbons(writer); IClipboard clipboard = Application.Current.Clipboard; await writer.FlushAsync(); await clipboard.SetTextAsync(writer.ToString()); writer.Close(); } public async Task ShowScreenSettings() { await ShowScreenSettingsDialog.Handle(new ScreenSettingsViewModel()); } public async Task ShowAbout() { await ShowAboutDialog.Handle(new AboutViewModel()); } public async Task ValidateSafeExit() { // TODO: Determine if there's unsaved stuff we need to deal with. // return await ShowYesNoBox("Leaving so Soon?", "[A potential reason not to quit goes here]"); await Task.Delay(1); // Stub to prevent warnings. return true; } private static async Task GetLoadFileName(string title, List filters, string? fileName = null) { if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return null; // TODO: Figure out why the file filters aren't working. OpenFileDialog dialog = new() { Title = title, Filters = filters, InitialFileName = fileName, AllowMultiple = false }; string[] files = await dialog.ShowAsync(desktop.MainWindow); return files.Length > 0 ? files[0] : null; } private static async Task GetSaveFileName(string title, List filters, string? fileName = null) { if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return null; // TODO: Figure out why the file filters aren't working. SaveFileDialog dialog = new() { Title = title, Filters = filters, InitialFileName = fileName }; return await dialog.ShowAsync(desktop.MainWindow); } public Interaction ShowAboutDialog { get; } public Interaction ShowScreenSettingsDialog { get; } public ReactiveCommand Exit { get; } } }