Continue working on main menu screen and refactor

New method for storing information on report data; rework and migrate settings to version 2; Add new options to ConfirmViewModel; rework some class hierarchy (may change more later)
This commit is contained in:
2026-03-30 20:12:34 +09:00
parent 8be518e81c
commit a9674a3f45
9 changed files with 247 additions and 73 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ public partial class App : Application, ITopLevelGrabber
public TopLevel GetTopLevel()
{
return _topLevel;
return _topLevel!;
}
public void AboutOnClick(object? sender, EventArgs args)
+2 -26
View File
@@ -9,47 +9,23 @@ using MayShow.Helpers;
namespace MayShow.Models;
class PDFReport : ChangeNotifier
class PDFReport : PDFReportInfo
{
private string _baseFolder;
private string _title;
private List<ReportFile> _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<ReportFile> Files
{
get => _files;
set { _files = value; NotifyPropertyChanged(); }
}
public DateTime LastSaved
{
get => _lastSaved;
set { _lastSaved = value; NotifyPropertyChanged(); }
}
public DateTime? LastGenerated
{
get => _lastGenerated;
@@ -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);
}
}
}
+49 -5
View File
@@ -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<string, string> _workingFolderToInternalFolderName;
private Dictionary<string, string> _workingFolderToInternalFolderName; // obsolete
private List<PDFReportInfo> _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<PDFReportInfo> 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<PDFReportInfo>();
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<Settings>(json, jsonContext.Settings) ?? new Settings();
return UpgradeSettings(JsonSerializer.Deserialize<Settings>(json, jsonContext.Settings) ?? new Settings());
}
public static async Task<Settings> 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<Settings>(fileStream, jsonContext.Settings) ?? new Settings();
return output;
return UpgradeSettings(output);
}
}
@@ -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);
@@ -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<PDFReport>(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<ReportFile>(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;
@@ -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<string> _savedReports;
private ObservableCollection<PDFReportInfo> _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<PDFReportInfo>(_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<string> SavedReports
public ObservableCollection<PDFReportInfo> 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<PDFReportInfo>(_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
}
}
}
+9 -4
View File
@@ -20,16 +20,21 @@
MaxWidth="350"
Text="{Binding Message}"/>
<StackPanel Orientation="Horizontal"
Spacing="12"
Spacing="16"
HorizontalAlignment="Right"
Margin="4">
<Button Command="{Binding Decline}"
Content="{Binding DeclineTitle}"
HorizontalAlignment="Right"/>
<Button Command="{Binding Confirm}"
Classes="accent"
Content="{Binding ConfirmTitle}"
HorizontalAlignment="Right"/>
Classes.accent="{Binding ConfirmButtonIsAccent}"
Classes.Danger="{Binding ConfirmButtonIsDanger}"
HorizontalAlignment="Right">
<TextBlock>
<Run Text="{Binding ConfirmTitleIcon}"
FontFamily="{StaticResource FontAwesomeSolid}" /> <Run Text="{Binding ConfirmTitle}"/>
</TextBlock>
</Button>
</StackPanel>
</StackPanel>
</UserControl>
@@ -26,7 +26,7 @@
HorizontalAlignment="Center"
Grid.Column="1"
Grid.Row="1" />
<Label Content="Start New Project"
<Label Content="Start New Report"
HorizontalAlignment="Left"
FontSize="18"
FontWeight="Bold"
@@ -38,7 +38,7 @@
Margin="0,8,0,0"
Grid.Column="1"
Grid.Row="3">
<TextBox Watermark="Report Title"
<TextBox Watermark="Feb 2024 Report"
Classes="clearButton"
Text="{Binding CreatingReportTitle}"
VerticalAlignment="Stretch"
@@ -54,14 +54,14 @@
FontFamily="{StaticResource FontAwesomeSolid}" /> Create and Start Report</TextBlock>
</Button>
</Grid>
<Label Content="Load Existing Project"
<Label Content="Load Existing Report"
FontSize="18"
FontWeight="Bold"
HorizontalAlignment="Left"
Margin="0,16,0,0"
Grid.Column="1"
Grid.Row="4"/>
<ScrollViewer Margin="0,8,0,8"
<ScrollViewer Margin="0,8,0,32"
Grid.Column="1"
Grid.Row="5"
VerticalScrollBarVisibility="Visible"
@@ -69,10 +69,38 @@
HorizontalScrollBarVisibility="Disabled">
<ItemsControl ItemsSource="{Binding SavedReports}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<!-- TODO: buttons to load, delete reports -->
<DataTemplate x:DataType="models:PDFReportInfo">
<StackPanel Orientation="Vertical"
Margin="12,4,4,8"
Spacing="4">
<TextBlock Text="{Binding Title}" />
<!-- <TextBlock Text="{Binding BaseFolder}"
Foreground="Gray"
TextWrapping="Wrap" /> -->
<TextBlock Foreground="Gray"
TextWrapping="Wrap">
Last saved on: <Run Text="{Binding LastSaved, StringFormat='{}{0:yyyy-MM-dd}'}"/>
</TextBlock>
<StackPanel Orientation="Horizontal"
Spacing="8">
<Button Command="{Binding $parent[UserControl].((vm:StartNewChooseReportViewModel)DataContext).LoadExistingReport}"
CommandParameter="{Binding}"
Classes="accent"
Grid.Column="1">
<TextBlock>
<Run Text="&#xf56f;"
FontFamily="{StaticResource FontAwesomeSolid}" /> Load Report</TextBlock>
</Button>
<Button Command="{Binding $parent[UserControl].((vm:StartNewChooseReportViewModel)DataContext).DeleteExistingReport}"
CommandParameter="{Binding}"
Classes="Danger"
Grid.Column="1">
<TextBlock>
<Run Text="&#xf1f8;"
FontFamily="{StaticResource FontAwesomeSolid}" /> Delete Report</TextBlock>
</Button>
</StackPanel>
<Rectangle Fill="Gray" Height="2" HorizontalAlignment="Stretch" Margin="0,8,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>