Files @ 7ef39aaa6e6b
Branch filter:

Location: ATITD-Tools/Desert-Paint-Codex/ViewModels/MainWindowViewModel.cs - annotation

Jason Maltzen
Bump version to 1.11.0 for Tale 11
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
40eaee10ae56
a5faa82faf6a
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
867b2b613117
867b2b613117
867b2b613117
867b2b613117
867b2b613117
867b2b613117
867b2b613117
867b2b613117
867b2b613117
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
a5faa82faf6a
a5faa82faf6a
a5faa82faf6a
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
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<string> ZipFileExtensions = new() {"zip"};
        private static readonly FileDialogFilter ZipFileFilter = new() {Extensions = ZipFileExtensions, Name = "Zip"};
        private static readonly List<FileDialogFilter> ZipFileFilters = new() {ZipFileFilter};

        private static readonly List<string> TxtFileExtensions = new() {"txt"};
        private static readonly FileDialogFilter TxtFileFilter = new() {Extensions = TxtFileExtensions, Name = "Text"};
        private static readonly List<FileDialogFilter> TxtFileFilters = new() {TxtFileFilter};
        
        private static readonly List<FileDialogFilter> 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<AboutViewModel, Unit>();
            ShowScreenSettingsDialog = new Interaction<ScreenSettingsViewModel, Unit>();
            
            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 ExportPaintMixRecipes()
        {
            string? fileName = await GetSaveFileName("Export paint_mix recipes", NoFileFilters, "paint_recipes.txt");
            if (!string.IsNullOrEmpty(fileName))
            {
                ProfileManager.CurrentProfile?.ExportPaintMixRecipes(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<bool> 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<string?> GetLoadFileName(string title, List<FileDialogFilter> 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<string?> GetSaveFileName(string title, List<FileDialogFilter> 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<AboutViewModel, Unit> ShowAboutDialog { get; }
        public Interaction<ScreenSettingsViewModel, Unit> ShowScreenSettingsDialog { get; }

        public ReactiveCommand<Unit, Unit> Exit { get; }
    }
}