WIP: Add iOS version #10
@@ -39,7 +39,7 @@ public partial class App : Application, ITopLevelGrabber
|
||||
|
||||
public TopLevel GetTopLevel()
|
||||
{
|
||||
return _topLevel;
|
||||
return _topLevel!;
|
||||
}
|
||||
|
||||
public void AboutOnClick(object? sender, EventArgs args)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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=""
|
||||
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=""
|
||||
FontFamily="{StaticResource FontAwesomeSolid}" /> Delete Report</TextBlock>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<Rectangle Fill="Gray" Height="2" HorizontalAlignment="Stretch" Margin="0,8,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
|
||||
Reference in New Issue
Block a user