diff --git a/src/MayShow.Shared/App.axaml.cs b/src/MayShow.Shared/App.axaml.cs index 57374c9..e5b46a8 100644 --- a/src/MayShow.Shared/App.axaml.cs +++ b/src/MayShow.Shared/App.axaml.cs @@ -39,7 +39,7 @@ public partial class App : Application, ITopLevelGrabber public TopLevel GetTopLevel() { - return _topLevel; + return _topLevel!; } public void AboutOnClick(object? sender, EventArgs args) diff --git a/src/MayShow.Shared/Models/PDFReport.cs b/src/MayShow.Shared/Models/PDFReport.cs index 3b0b769..501c060 100644 --- a/src/MayShow.Shared/Models/PDFReport.cs +++ b/src/MayShow.Shared/Models/PDFReport.cs @@ -9,47 +9,23 @@ using MayShow.Helpers; namespace MayShow.Models; -class PDFReport : ChangeNotifier +class PDFReport : PDFReportInfo { - private string _baseFolder; - private string _title; private List _files; - private DateTime _lastSaved; private DateTime? _lastGenerated; - public PDFReport() + public PDFReport() : base() { - _baseFolder = ""; - _title = ""; _files = []; - _lastSaved = DateTime.Now; _lastGenerated = null; } - public string BaseFolder - { - get => _baseFolder; - set { _baseFolder = value; NotifyPropertyChanged(); } - } - - public string Title - { - get => _title; - set { _title = value; NotifyPropertyChanged(); } - } - public List Files { get => _files; set { _files = value; NotifyPropertyChanged(); } } - public DateTime LastSaved - { - get => _lastSaved; - set { _lastSaved = value; NotifyPropertyChanged(); } - } - public DateTime? LastGenerated { get => _lastGenerated; diff --git a/src/MayShow.Shared/Models/PDFReportInfo.cs b/src/MayShow.Shared/Models/PDFReportInfo.cs new file mode 100644 index 0000000..9cacd0a --- /dev/null +++ b/src/MayShow.Shared/Models/PDFReportInfo.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using MayShow.Helpers; +using MayShows.Helpers; + +namespace MayShow.Models; + +class PDFReportInfo : ChangeNotifier +{ + private string? _baseFolder; // might be null + private string _uuid; + private string _title; + private DateTime? _lastSaved; + + public PDFReportInfo() : base() + { + _baseFolder = null; + _uuid = Guid.NewGuid().ToString(); + _title = ""; + _lastSaved = null; + } + + public string? BaseFolder + { + get => _baseFolder; + set { _baseFolder = value; NotifyPropertyChanged(); } + } + + public string UUID + { + get => _uuid; + set { _uuid = value; NotifyPropertyChanged(); } + } + + public string Title + { + get => _title; + set { _title = value; NotifyPropertyChanged(); } + } + + public DateTime? LastSaved + { + get => _lastSaved; + set { _lastSaved = value; NotifyPropertyChanged(); } + } + + public void ResetUUID() + { + UUID = Guid.NewGuid().ToString(); + } + + public void DeleteInternalFolderFromDisk() + { + var path = Path.Combine(Utilities.GetInternalDataPath(), UUID); + if (Directory.Exists(path) && path != Utilities.GetInternalDataPath()) + { + Directory.Delete(path, true); + } + } +} \ No newline at end of file diff --git a/src/MayShow.Shared/Models/Settings.cs b/src/MayShow.Shared/Models/Settings.cs index c1b7002..3356fa6 100644 --- a/src/MayShow.Shared/Models/Settings.cs +++ b/src/MayShow.Shared/Models/Settings.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; @@ -18,10 +19,11 @@ class Settings : ChangeNotifier private string _outputPdfDir; private decimal _imageResizeThreshold; private bool _saveReportJsonDataInInternalDir; - private Dictionary _workingFolderToInternalFolderName; + private Dictionary _workingFolderToInternalFolderName; // obsolete + private List _allReportInfo; public int _settingsVersion; - public Settings() + public Settings() : base() { _lastUsedPath = ""; _useDocnetPDFImageRendering = true; @@ -30,7 +32,8 @@ class Settings : ChangeNotifier _imageResizeThreshold = 1.5m; _saveReportJsonDataInInternalDir = false; _workingFolderToInternalFolderName = []; - _settingsVersion = 1; + _allReportInfo = []; + _settingsVersion = 2; } public Settings(Settings other) @@ -43,6 +46,7 @@ class Settings : ChangeNotifier _saveReportJsonDataInInternalDir = other.SaveReportJsonDataInInternalDir; _workingFolderToInternalFolderName = other.WorkingFolderToInternalFolderName; _settingsVersion = other.SettingsVersion; + _allReportInfo = other.AllReportInfo; } [JsonInclude] @@ -95,6 +99,13 @@ class Settings : ChangeNotifier set { _workingFolderToInternalFolderName = value; NotifyPropertyChanged(); } } + [JsonInclude] + public List AllReportInfo + { + get => _allReportInfo; + set { _allReportInfo = value; NotifyPropertyChanged(); } + } + [JsonInclude] public int SettingsVersion { @@ -135,6 +146,39 @@ class Settings : ChangeNotifier return json; } + private static Settings UpgradeSettings(Settings settings) + { + if (settings.SettingsVersion == 1) + { + // update settings + var internalPath = Utilities.GetInternalDataPath(); + var list = new List(); + foreach (var data in settings.WorkingFolderToInternalFolderName) + { + var uuid = data.Value; + var path = Path.Combine(internalPath, uuid, Constants.ReportSavedDataFileName); + var json = File.ReadAllText(path); + var jsonContext = new SourceGenerationContext(Utilities.GetSerializerOptions()); + var report = File.Exists(path) ? JsonSerializer.Deserialize(json, jsonContext.PDFReport) : null; + var reportTitle = report?.Title ?? ""; + var lastSaved = report?.LastSaved; + var reportInfo = new PDFReportInfo() + { + Title = reportTitle, + UUID = uuid, + LastSaved = lastSaved, + BaseFolder = data.Key, + }; + list.Add(reportInfo); + } + settings.AllReportInfo = list.OrderBy(x => x.Title).ToList(); + settings.WorkingFolderToInternalFolderName = []; // clear this list; it is no longer used + settings.SettingsVersion = 2; + // TODO: finish using new array for everything, make sure we save data, etc. + } + return settings; + } + public static Settings LoadSettings() { var path = GetSettingsPath(); @@ -144,7 +188,7 @@ class Settings : ChangeNotifier } var json = File.ReadAllText(GetSettingsPath()); var jsonContext = new SourceGenerationContext(Utilities.GetSerializerOptions()); - return JsonSerializer.Deserialize(json, jsonContext.Settings) ?? new Settings(); + return UpgradeSettings(JsonSerializer.Deserialize(json, jsonContext.Settings) ?? new Settings()); } public static async Task LoadSettingsAsync() @@ -152,6 +196,6 @@ class Settings : ChangeNotifier using FileStream fileStream = File.OpenRead(GetSettingsPath()); var jsonContext = new SourceGenerationContext(Utilities.GetSerializerOptions()); var output = await JsonSerializer.DeserializeAsync(fileStream, jsonContext.Settings) ?? new Settings(); - return output; + return UpgradeSettings(output); } } \ No newline at end of file diff --git a/src/MayShow.Shared/ViewModels/ConfirmViewModel.cs b/src/MayShow.Shared/ViewModels/ConfirmViewModel.cs index 54b05a4..994b40d 100644 --- a/src/MayShow.Shared/ViewModels/ConfirmViewModel.cs +++ b/src/MayShow.Shared/ViewModels/ConfirmViewModel.cs @@ -5,12 +5,14 @@ using MayShow.Helpers; namespace MayShow.ViewModels; -class ConfirmViewModel +class ConfirmViewModel : ChangeNotifier { private string _title; private string _message; private string _confirmTitle; private string _declineTitle; + private bool _confirmButtonUsesDangerStyle; + private string _confirmButtonIcon; public ConfirmViewModel(string title, string message, string confirmTitle = "Yes", string declineTitle = "No") { @@ -18,6 +20,8 @@ class ConfirmViewModel _message = message; _confirmTitle = confirmTitle; _declineTitle = declineTitle; + _confirmButtonUsesDangerStyle = false; + _confirmButtonIcon = ""; } public string Title @@ -40,6 +44,35 @@ class ConfirmViewModel get => _declineTitle; } + public bool ConfirmButtonIsAccent + { + get => !_confirmButtonUsesDangerStyle; + } + + public bool ConfirmButtonIsDanger + { + get => _confirmButtonUsesDangerStyle; + } + + public bool ConfirmButtonUsesDangerStyle + { + set + { + _confirmButtonUsesDangerStyle = value; + NotifyPropertyChanged(nameof(ConfirmButtonIsAccent)); + NotifyPropertyChanged(nameof(ConfirmButtonIsDanger)); + } + } + + public string ConfirmTitleIcon + { + get => _confirmButtonIcon; + set + { + _confirmButtonIcon = value; NotifyPropertyChanged(); + } + } + public void Confirm() { DialogHost.Close("DialogHost", true); diff --git a/src/MayShow.Shared/ViewModels/CreatePDFReportViewModel.cs b/src/MayShow.Shared/ViewModels/CreatePDFReportViewModel.cs index d538b6e..440dbd7 100644 --- a/src/MayShow.Shared/ViewModels/CreatePDFReportViewModel.cs +++ b/src/MayShow.Shared/ViewModels/CreatePDFReportViewModel.cs @@ -253,13 +253,13 @@ class CreatePDFReportViewModel : BaseViewModel, IFontResolver, ICanCheckShutdown // load prior report var json = File.ReadAllText(reportFilePath); var jsonContext = new SourceGenerationContext(Utilities.GetSerializerOptions()); - var report = JsonSerializer.Deserialize(json, jsonContext.PDFReport); + var report = JsonSerializer.Deserialize(json, jsonContext.PDFReport); if (report != null && report.Files.Count > 0) { Console.WriteLine("Loading prior report data at {0}", reportFilePath); ReportFiles = new ObservableCollection(report.Files); ReportTitle = report.Title; - WorkingFolder = report.BaseFolder; + WorkingFolder = report.BaseFolder ?? ""; _lastGeneratedTime = report.LastGenerated ?? null; LogInfo("Reloaded report last saved at {0}", report.LastSaved); successfullyLoadedPriorReport = true; diff --git a/src/MayShow.Shared/ViewModels/StartNewChooseReportViewModel.cs b/src/MayShow.Shared/ViewModels/StartNewChooseReportViewModel.cs index ce3c663..3e271c4 100644 --- a/src/MayShow.Shared/ViewModels/StartNewChooseReportViewModel.cs +++ b/src/MayShow.Shared/ViewModels/StartNewChooseReportViewModel.cs @@ -1,43 +1,30 @@ #nullable enable -using System; using System.Collections.ObjectModel; -using System.Globalization; using System.IO; using System.Linq; -using System.Threading.Tasks; -using Avalonia.Platform.Storage; -using Avalonia.Themes.Fluent; using DialogHostAvalonia; -using ImageMagick; -using MigraDoc.DocumentObjectModel; -using MigraDoc.Rendering; -using PdfSharp.Fonts; -using PdfSharp.Pdf.IO; -using PdfSharp.Snippets.Font; using MayShow.Interfaces; using MayShow.Models; using MayShow.Helpers; +using MayShows.Helpers; namespace MayShow.ViewModels; class StartNewChooseReportViewModel : BaseViewModel { private string _creatingReportTitle; - private ObservableCollection _savedReports; + private ObservableCollection _savedReports; + private Settings _settings; public StartNewChooseReportViewModel(IChangeViewModel viewModelChanger) : base(viewModelChanger) { _creatingReportTitle = ""; - // TODO: load existing reports - _savedReports = []; - for (var i = 1; i <= 100; i++) - { - _savedReports.Add("Report " + i); - } + _settings = Settings.LoadSettings(); + _savedReports = new ObservableCollection(_settings.AllReportInfo.OrderBy(x => x.Title)); } - public string Version + public static string Version { get => Constants.AppVersion; } @@ -48,30 +35,66 @@ class StartNewChooseReportViewModel : BaseViewModel set { _creatingReportTitle = value; NotifyPropertyChanged(); } } - public ObservableCollection SavedReports + public ObservableCollection SavedReports { get => _savedReports; set { _savedReports = value; NotifyPropertyChanged(); } } - public void StartReport() + public async void StartReport() { - // TODO: make sure there is a folder and everything set up for this report + var reportInfo = new PDFReportInfo() + { + Title = CreatingReportTitle, + }; + _settings.AllReportInfo.Add(reportInfo); + // ... this sort is slow, technically, but we're not going to have millions of items here, so... + SavedReports = new ObservableCollection(_settings.AllReportInfo.OrderBy(x => x.Title)); + await _settings.SaveSettingsAsync(); + // create folder for report data + var path = Path.Combine(Utilities.GetInternalDataPath(), reportInfo.UUID); + while (Directory.Exists(path)) + { + reportInfo.ResetUUID(); + path = Path.Combine(Utilities.GetInternalDataPath(), reportInfo.UUID); + } + Directory.CreateDirectory(path); + // now update UI ViewModelChanger.PushViewModel(new CreatePDFReportViewModel(ViewModelChanger) { ReportTitle = CreatingReportTitle }); CreatingReportTitle = ""; // when user comes back they can start another new report - // TODO: add to existing reports list } - public void LoadExistingReport() + + public void LoadExistingReport(object info) => LoadExistingReportImpl((PDFReportInfo) info); + public void LoadExistingReportImpl(PDFReportInfo reportInfo) { // TODO: load data and send to create PDF report view model } - public void DeleteExistingReport() + public void DeleteExistingReport(object info) => DeleteExistingReportImpl((PDFReportInfo) info); + public async void DeleteExistingReportImpl(PDFReportInfo reportInfo) { - // TODO: warn user, delete if they want to proceed + var message = string.IsNullOrWhiteSpace(reportInfo.BaseFolder) + ? "Are you sure you want to delete this report and its associated data? It will be gone forever!" + : "Are you sure you want to delete information about this report? It will be gone forever!"; + var result = await DialogHost.Show(new ConfirmViewModel( + "Warning!", + message, + "Delete Report", + "Cancel") + { + ConfirmButtonUsesDangerStyle = true, + ConfirmTitleIcon = "\uf1f8;" + }); + if (result != null && (bool)result) + { + SavedReports.Remove(reportInfo); + _settings.AllReportInfo.Remove(reportInfo); + reportInfo.DeleteInternalFolderFromDisk(); // delete internal data if available + await _settings.SaveSettingsAsync(); // update saved items list + } } } \ No newline at end of file diff --git a/src/MayShow.Shared/Views/ConfirmView.axaml b/src/MayShow.Shared/Views/ConfirmView.axaml index 94125fd..0a4a43c 100644 --- a/src/MayShow.Shared/Views/ConfirmView.axaml +++ b/src/MayShow.Shared/Views/ConfirmView.axaml @@ -20,16 +20,21 @@ MaxWidth="350" Text="{Binding Message}"/> diff --git a/src/MayShow.Shared/Views/StartNewChooseReport.axaml b/src/MayShow.Shared/Views/StartNewChooseReport.axaml index 950d649..dbb9329 100644 --- a/src/MayShow.Shared/Views/StartNewChooseReport.axaml +++ b/src/MayShow.Shared/Views/StartNewChooseReport.axaml @@ -26,7 +26,7 @@ HorizontalAlignment="Center" Grid.Column="1" Grid.Row="1" /> -