Start major rework for DataGrid display
For editing of file properties, etc.
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<FluentTheme />
|
<FluentTheme />
|
||||||
<StyleInclude Source="avares://AvaloniaProgressRing/Styles/ProgressRing.xaml"/>
|
<StyleInclude Source="avares://AvaloniaProgressRing/Styles/ProgressRing.xaml"/>
|
||||||
|
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
|
||||||
</Application.Styles>
|
</Application.Styles>
|
||||||
<Application.DataTemplates>
|
<Application.DataTemplates>
|
||||||
<DataTemplate DataType="{x:Type viewModels:MainViewModel}">
|
<DataTemplate DataType="{x:Type viewModels:MainViewModel}">
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<AvaloniaVersion>11.3.12</AvaloniaVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
+4
-4
@@ -7,9 +7,9 @@
|
|||||||
Title="Receipt PDF Builder"
|
Title="Receipt PDF Builder"
|
||||||
xmlns:vm="clr-namespace:ReceiptPDFBuilder.ViewModels"
|
xmlns:vm="clr-namespace:ReceiptPDFBuilder.ViewModels"
|
||||||
x:DataType="vm:MainWindowViewModel"
|
x:DataType="vm:MainWindowViewModel"
|
||||||
Width="500"
|
Width="800"
|
||||||
MinWidth="300"
|
MinWidth="400"
|
||||||
Height="350"
|
Height="600"
|
||||||
MinHeight="300">
|
MinHeight="400">
|
||||||
<ContentControl Content="{Binding CurrentViewModel}"/>
|
<ContentControl Content="{Binding CurrentViewModel}"/>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using ReceiptPDFBuilder.Helpers;
|
||||||
|
|
||||||
|
namespace ReceiptPDFBuilder.Models;
|
||||||
|
|
||||||
|
class ReportFile : ChangeNotifier
|
||||||
|
{
|
||||||
|
private string _title;
|
||||||
|
private DateOnly _date;
|
||||||
|
private DateTime _dateTime;
|
||||||
|
private DateTimeOffset _dto;
|
||||||
|
private string _notes;
|
||||||
|
private string _filePath;
|
||||||
|
|
||||||
|
public ReportFile()
|
||||||
|
{
|
||||||
|
_title = "";
|
||||||
|
_date = DateOnly.FromDateTime(DateTime.Now);
|
||||||
|
_notes = "";
|
||||||
|
_filePath = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get => _title;
|
||||||
|
set { _title = value; NotifyPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateOnly Date
|
||||||
|
{
|
||||||
|
get => _date;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_date = value;
|
||||||
|
DateTime = value.ToDateTime(TimeOnly.MinValue);
|
||||||
|
DTO = new DateTimeOffset(value.ToDateTime(TimeOnly.MinValue));
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime DateTime
|
||||||
|
{
|
||||||
|
get => _dateTime;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_dateTime = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTimeOffset DTO
|
||||||
|
{
|
||||||
|
get => _dto;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_dto = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Notes
|
||||||
|
{
|
||||||
|
get => _notes;
|
||||||
|
set { _notes = value; NotifyPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FilePath
|
||||||
|
{
|
||||||
|
get => _filePath;
|
||||||
|
set { _filePath = value; NotifyPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FileName
|
||||||
|
{
|
||||||
|
get => Path.GetFileName(_filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,17 +34,17 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="11.3.10" />
|
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.10" />
|
<PackageReference Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.10" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="$(AvaloniaVersion)" />
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.10" />
|
<PackageReference Include="Avalonia.Fonts.Inter" Version="$(AvaloniaVersion)" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<PackageReference Include="Avalonia.Controls.DataGrid" Version="$(AvaloniaVersion)" />
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.10">
|
<PackageReference Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)">
|
||||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="PDFsharp-MigraDoc" Version="6.2.3" />
|
<PackageReference Include="PDFsharp-MigraDoc" Version="6.2.3" />
|
||||||
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="14.10.1" />
|
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="14.10.2" />
|
||||||
<PackageReference Include="Deadpikle.AvaloniaProgressRing" Version="0.10.11-preview20251127001" />
|
<PackageReference Include="Deadpikle.AvaloniaProgressRing" Version="0.10.11-preview20251127001" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+91
-18
@@ -1,4 +1,7 @@
|
|||||||
|
#nullable enable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -10,6 +13,7 @@ using PdfSharp.Fonts;
|
|||||||
using PdfSharp.Pdf.IO;
|
using PdfSharp.Pdf.IO;
|
||||||
using PdfSharp.Snippets.Font;
|
using PdfSharp.Snippets.Font;
|
||||||
using ReceiptPDFBuilder.Interfaces;
|
using ReceiptPDFBuilder.Interfaces;
|
||||||
|
using ReceiptPDFBuilder.Models;
|
||||||
|
|
||||||
namespace ReceiptPDFBuilder.ViewModels;
|
namespace ReceiptPDFBuilder.ViewModels;
|
||||||
|
|
||||||
@@ -18,12 +22,17 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
private string _baseDir;
|
private string _baseDir;
|
||||||
private bool _isCreatingPDF;
|
private bool _isCreatingPDF;
|
||||||
private string _createPDFLog;
|
private string _createPDFLog;
|
||||||
|
private string _workingFolder;
|
||||||
|
|
||||||
|
private ObservableCollection<ReportFile> _reportFiles;
|
||||||
|
|
||||||
public MainViewModel(IChangeViewModel viewModelChanger) : base(viewModelChanger)
|
public MainViewModel(IChangeViewModel viewModelChanger) : base(viewModelChanger)
|
||||||
{
|
{
|
||||||
_baseDir = Path.GetDirectoryName(Environment.ProcessPath) ?? "";
|
_baseDir = Path.GetDirectoryName(Environment.ProcessPath) ?? "";
|
||||||
_isCreatingPDF = false;
|
_isCreatingPDF = false;
|
||||||
_createPDFLog = "Ready to create PDF!";
|
_createPDFLog = "Ready to create PDF! Choose a folder to begin...";
|
||||||
|
_reportFiles = new ObservableCollection<ReportFile>();
|
||||||
|
_workingFolder = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCreatingPDF
|
public bool IsCreatingPDF
|
||||||
@@ -38,10 +47,17 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
set { _createPDFLog = value; NotifyPropertyChanged(); }
|
set { _createPDFLog = value; NotifyPropertyChanged(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogInfo(string log)
|
public ObservableCollection<ReportFile> ReportFiles
|
||||||
{
|
{
|
||||||
Console.WriteLine(log);
|
get => _reportFiles;
|
||||||
CreatePDFLog += Environment.NewLine + log;
|
set { _reportFiles = value; NotifyPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LogInfo(string message, params object[]? arguments)
|
||||||
|
{
|
||||||
|
var timestamp = string.Format("[{0:s}]", DateTime.Now);
|
||||||
|
Console.WriteLine(timestamp + " " + message, arguments);
|
||||||
|
CreatePDFLog += Environment.NewLine + string.Format(message, arguments ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void ChooseFolder()
|
public async void ChooseFolder()
|
||||||
@@ -60,23 +76,23 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
LogInfo("Chosen folder: " + folder.Path.LocalPath);
|
LogInfo("Chosen folder: " + folder.Path.LocalPath);
|
||||||
if (Directory.Exists(folder.Path.LocalPath))
|
if (Directory.Exists(folder.Path.LocalPath))
|
||||||
{
|
{
|
||||||
try
|
_workingFolder = folder.Path.LocalPath;
|
||||||
|
// TODO: Scan folder for saved info from previous reports and reload if needed
|
||||||
|
// Scan folder for files and display in DataGrid
|
||||||
|
var filePaths = Directory.GetFiles(_workingFolder);
|
||||||
|
filePaths.Sort();
|
||||||
|
foreach (var filePath in filePaths)
|
||||||
{
|
{
|
||||||
await Task.Run(() => CreatePDF(folder.Path.LocalPath));
|
if (!filePath.Contains(".DS_Store"))
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
LogInfo("PDF process failed! Reason: " + e.Message);
|
|
||||||
if (e.StackTrace != null)
|
|
||||||
{
|
{
|
||||||
LogInfo(e.StackTrace);
|
// TODO: if date in file name, pull out that date instead
|
||||||
}
|
ReportFiles.Add(new ReportFile()
|
||||||
if (e.InnerException != null)
|
|
||||||
{
|
|
||||||
LogInfo("Inner exception: " + e.InnerException.Message);
|
|
||||||
if (e.InnerException.StackTrace != null)
|
|
||||||
{
|
{
|
||||||
LogInfo(e.InnerException.StackTrace);
|
Title = Path.GetFileName(filePath),
|
||||||
}
|
Date = DateOnly.FromDateTime(File.GetCreationTime(filePath)),
|
||||||
|
Notes = "",
|
||||||
|
FilePath = filePath
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,6 +100,63 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void MoveItemUp(ReportFile file)
|
||||||
|
{
|
||||||
|
var idx = ReportFiles.IndexOf(file);
|
||||||
|
Console.WriteLine("{0} at idx {1}", file.Title, idx);
|
||||||
|
if (idx != 0)
|
||||||
|
{
|
||||||
|
// .Move() is not observed -_-
|
||||||
|
// https://github.com/AvaloniaUI/Avalonia.Controls.DataGrid/issues/74
|
||||||
|
// ReportFiles.Move(idx, idx - 1);
|
||||||
|
// So, remove and insert.
|
||||||
|
ReportFiles.RemoveAt(idx);
|
||||||
|
ReportFiles.Insert(idx - 1, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MoveItemDown(ReportFile file)
|
||||||
|
{
|
||||||
|
var idx = ReportFiles.IndexOf(file);
|
||||||
|
if (idx != ReportFiles.Count - 1)
|
||||||
|
{
|
||||||
|
ReportFiles.RemoveAt(idx);
|
||||||
|
ReportFiles.Insert(idx + 1, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveFile(ReportFile file)
|
||||||
|
{
|
||||||
|
var idx = ReportFiles.IndexOf(file);
|
||||||
|
if (idx != -1)
|
||||||
|
{
|
||||||
|
ReportFiles.RemoveAt(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void BuildPDF()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Run(() => CreatePDF(_workingFolder));
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
LogInfo("PDF process failed! Reason: " + e.Message);
|
||||||
|
if (e.StackTrace != null)
|
||||||
|
{
|
||||||
|
LogInfo(e.StackTrace);
|
||||||
|
}
|
||||||
|
if (e.InnerException != null)
|
||||||
|
{
|
||||||
|
LogInfo("Inner exception: " + e.InnerException.Message);
|
||||||
|
if (e.InnerException.StackTrace != null)
|
||||||
|
{
|
||||||
|
LogInfo(e.InnerException.StackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public byte[]? GetFont(string faceName)
|
public byte[]? GetFont(string faceName)
|
||||||
{
|
{
|
||||||
LogInfo(string.Format("Loading font {0}", faceName));
|
LogInfo(string.Format("Loading font {0}", faceName));
|
||||||
|
|||||||
+81
-3
@@ -4,11 +4,12 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="ReceiptPDFBuilder.Views.MainView"
|
x:Class="ReceiptPDFBuilder.Views.MainView"
|
||||||
|
xmlns:models="clr-namespace:ReceiptPDFBuilder.Models"
|
||||||
xmlns:vm="clr-namespace:ReceiptPDFBuilder.ViewModels"
|
xmlns:vm="clr-namespace:ReceiptPDFBuilder.ViewModels"
|
||||||
xmlns:progRing="clr-namespace:AvaloniaProgressRing;assembly=AvaloniaProgressRing"
|
xmlns:progRing="clr-namespace:AvaloniaProgressRing;assembly=AvaloniaProgressRing"
|
||||||
x:DataType="vm:MainViewModel">
|
x:DataType="vm:MainViewModel">
|
||||||
<Grid ColumnDefinitions="Auto, *"
|
<Grid ColumnDefinitions="Auto, *"
|
||||||
RowDefinitions="Auto, *">
|
RowDefinitions="Auto, Auto, *, *">
|
||||||
<Label Content="Easy Receipt Folder -> PDF Builder"
|
<Label Content="Easy Receipt Folder -> PDF Builder"
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
@@ -33,9 +34,86 @@
|
|||||||
Foreground="LightBlue"
|
Foreground="LightBlue"
|
||||||
Margin="10,20,0,0"/>
|
Margin="10,20,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ScrollViewer Grid.Column="1"
|
<DataGrid x:Name="FilesGrid"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Margin="2"
|
||||||
|
ItemsSource="{Binding ReportFiles, Mode=TwoWay}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
IsReadOnly="False"
|
||||||
|
GridLinesVisibility="All"
|
||||||
|
CanUserReorderColumns="False"
|
||||||
|
CanUserResizeColumns="True"
|
||||||
|
CanUserSortColumns="False"
|
||||||
|
BorderThickness="1"
|
||||||
|
VerticalScrollBarVisibility="Visible"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
ScrollViewer.AllowAutoHide="False"
|
||||||
|
BorderBrush="Gray">
|
||||||
|
<DataGrid.Styles>
|
||||||
|
<Style Selector="TextBlock">
|
||||||
|
<Setter Property="TextWrapping" Value="NoWrap" />
|
||||||
|
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="TextBox">
|
||||||
|
<Setter Property="TextWrapping" Value="NoWrap" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.Styles>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Title"
|
||||||
|
Binding="{Binding Title}"
|
||||||
|
Width="*"/>
|
||||||
|
<DataGridTemplateColumn Header="Receipt Date"
|
||||||
|
IsReadOnly="False"
|
||||||
|
Width="*">
|
||||||
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Date}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataGridTemplateColumn.CellEditingTemplate>
|
||||||
|
<DataTemplate DataType="models:ReportFile">
|
||||||
|
<!-- <DatePicker DayFormat="ddd dd"
|
||||||
|
SelectedDate="{Binding DateTime}"/> -->
|
||||||
|
<Calendar SelectionMode="SingleDate"
|
||||||
|
SelectedDate="{Binding DateTime}"
|
||||||
|
DisplayDate="{Binding DateTime}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellEditingTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
|
<DataGridTextColumn Header="File Name"
|
||||||
|
Binding="{Binding FileName}"
|
||||||
|
IsReadOnly="True"
|
||||||
|
Width="*" />
|
||||||
|
<DataGridTemplateColumn Header=""
|
||||||
|
IsReadOnly="True"
|
||||||
|
Width="*">
|
||||||
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Button Content="Up"
|
||||||
|
Command="{Binding $parent[DataGrid].((vm:MainViewModel)DataContext).MoveItemUp}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
IsEnabled="True"/>
|
||||||
|
<Button Content="Down"
|
||||||
|
Command="{Binding $parent[DataGrid].((vm:MainViewModel)DataContext).MoveItemDown}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
IsEnabled="True"/>
|
||||||
|
<Button Content="Byebye"
|
||||||
|
Command="{Binding $parent[DataGrid].((vm:MainViewModel)DataContext).RemoveFile}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
IsEnabled="True"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
<ScrollViewer Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
Margin="2"
|
Margin="2"
|
||||||
Grid.Row="1"
|
Grid.Row="3"
|
||||||
x:Name="LogScrollView">
|
x:Name="LogScrollView">
|
||||||
<SelectableTextBlock Text="{Binding CreatePDFLog}"
|
<SelectableTextBlock Text="{Binding CreatePDFLog}"
|
||||||
Margin="2"
|
Margin="2"
|
||||||
|
|||||||
Reference in New Issue
Block a user