Compare commits

..

52 Commits

Author SHA1 Message Date
Elias Fierke
4cfbcd0ab4 [feat:] added Country implementation for country code editing (unused) 2026-01-01 14:45:57 +01:00
Elias Fierke
b82473ada2 [chore:] PdfBuilder.cs skips empty addresses 2025-12-21 11:43:41 +01:00
Elias Fierke
1cba67253a [chore:] selectable pdf file path for label creation 2025-12-21 11:32:38 +01:00
Elias Fierke
63c1559110 [chore:] added "Postfach" to address creation 2025-12-21 11:25:48 +01:00
Elias Fierke
b670ba11fa [chore:] sender address usage in PdfBuilder.cs 2025-12-15 10:17:10 +01:00
Elias Fierke
1ad57543d1 [chore:] sender address editing 2025-12-15 10:04:33 +01:00
Elias Fierke
6cd4ea2df6 [chore:] added sender address field 2025-12-15 10:01:07 +01:00
Elias Fierke
30e42afe35 [chore:] rearrangend some result window features for debugging purposes (unfinal) 2025-12-14 14:33:55 +01:00
Elias Fierke
70e127b2f0 [init:] Initialized PDF Creation 2025-12-14 14:33:25 +01:00
Elias Fierke
7c73170b46 [chore:] implemented label generation button handler 2025-12-14 14:33:07 +01:00
Elias Fierke
290f69e976 [chore:] the IDE wanted to add some spaces 2025-12-14 14:32:45 +01:00
Elias Fierke
6ce08d7d4a [gui:] added a few tabs that will be used later 2025-12-14 14:32:02 +01:00
Elias Fierke
86df6f6a63 [file:] imported PdfSharp 2025-12-14 14:31:33 +01:00
Elias Fierke
eae0568ae0 [feat:] added KasPersonError.GetString() 2025-12-14 14:31:20 +01:00
Elias Fierke
4ebd6bc407 [fix:] fixed some logical errors in address creation 2025-12-14 14:30:53 +01:00
Elias Fierke
2c22306fef [fix:] plz check was bad 2025-12-14 14:30:33 +01:00
Elias Fierke
174223ba9e [fix:] Address Creation used an empty address instead of the one from the address set 2025-12-14 14:30:07 +01:00
Elias Fierke
8e5709c215 [feat:] initial fully implemented address creation 2025-12-07 13:30:52 +01:00
Elias Fierke
b70bd5e324 [struc:] moved KasPersonError-Instance from addressset to KasPerson-Instance 2025-12-07 13:30:25 +01:00
8c56717b9c [fix:] plz's and pplz's CAN be alphanumeric 2025-11-27 14:48:24 +01:00
7cd02456bc [init:] AddressCreator with first string address alternative 2025-11-27 14:47:48 +01:00
88bbc9644c [chore:] applied improved set naming 2025-11-17 13:28:40 +01:00
743c3aacd1 [chore:] added basic name-generation-function for address-sets 2025-11-17 13:14:26 +01:00
ac8362d9ba [feat:] added unprocessed-item-to-new-set-Option to address-combining 2025-11-17 13:13:30 +01:00
0c11cb2819 [chore:] added "-new"-part to names of AddressSets if the name already exists (will be improved further) 2025-11-11 11:16:06 +01:00
f057226a5f [fix:] bad refsid creation on address-patch-import 2025-11-11 10:50:36 +01:00
Elias Fierke
a70948599f [fix:] fixed new customer issue (new customer creation was terrible) 2025-11-04 14:43:11 +01:00
Elias Fierke
fb671e3526 [docs:] removed unrelated comment from another document which provided the template 2025-11-04 14:20:47 +01:00
Elias Fierke
a2af60a808 [chore:] implemented symmetric difference (combiner) and its usage 2025-10-23 20:49:19 +02:00
Elias Fierke
34c4dd8df1 [init:] initialized logof client documentation (tex) 2025-10-23 16:49:54 +02:00
Elias Fierke
bed0ebaf16 [chore:] implemented intersection (combiner) and its usage 2025-10-23 16:43:23 +02:00
Elias Fierke
d0ecfda404 [chore:] implemented union (combiner) and its usage 2025-10-23 13:54:48 +02:00
Elias Fierke
f28ac1a4b9 [chore:] implemented difference (combiner) and its usage 2025-10-23 13:32:26 +02:00
Elias Fierke
09bbdfdfde [feat:] added address-getter 2025-10-23 13:31:31 +02:00
Elias Fierke
6efafb7cc2 [init:] initialized new combine-functions 2025-10-23 10:40:25 +02:00
Elias Fierke
f93d9aada8 [fix:] refsid creation for non-refsid address-sets 2025-10-23 10:40:01 +02:00
Elias Fierke
f27adffe41 [chore:] added loading.mp4 to project resources 2025-10-23 10:39:27 +02:00
Elias Fierke
48b0500bfe [chore:] initial splash preparation, which will not be used for now 2025-10-23 10:39:04 +02:00
Elias Fierke
c6da9ac416 [file:] some ui layout for a not-shown window yeah 2025-10-23 10:38:32 +02:00
Elias Fierke
d02d5199c3 [file:] added new window for splash screen 2025-10-09 11:22:17 +02:00
Elias Fierke
b4430ae424 [file:] added loading animation 2025-10-09 11:19:15 +02:00
Elias Fierke
52c028cc8a [chore:] added link to git 2025-10-09 10:26:28 +02:00
Elias Fierke
af8a74c2c3 [chore:] added ID to addres-sets (yes, there was no -_-) 2025-10-09 10:22:22 +02:00
Elias Fierke
63d430dd72 [chore:] combine split into four possible variants of merging 2025-10-09 10:21:42 +02:00
Elias Fierke
c4663e489e [fix:] changed Shwo to Show 👍 2025-10-09 10:19:27 +02:00
Elias Fierke
f3ec633c53 [file:] deleted /obj 2025-10-09 08:58:39 +02:00
Elias Fierke
6d3ea7fd2d [fix:] added /obj/* to .gitignore 2025-10-09 08:53:58 +02:00
Elias Fierke
fc69c8cd6d [fix:] added /obj/ to .gitignore 2025-10-09 08:53:18 +02:00
Elias Fierke
69e9b84812 [fix:] forgot to use the separator in last commit 2025-10-09 08:51:25 +02:00
Elias Fierke
c7740a48dc stuff 2025-10-09 08:40:24 +02:00
Elias Fierke
3cf1fb3012 [chore:] remove unused code for now 2025-10-09 08:40:09 +02:00
Elias Fierke
316c9511d3 [chore:] added CSV-Separator Settings.cs 2025-10-09 08:39:49 +02:00
35 changed files with 2553 additions and 2635 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/obj/*

View File

@@ -12,3 +12,4 @@
/dataSources/ /dataSources/
/dataSources.local.xml /dataSources.local.xml
/obj /obj
/obj/*

View File

@@ -32,7 +32,7 @@ public class DataImport
return (false, null); return (false, null);
} }
var imported = new KasAddressList(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath)); var imported = new KasAddressList(KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath)));
while (!reader.EndOfStream) while (!reader.EndOfStream)
{ {
@@ -61,10 +61,10 @@ public class DataImport
parts[7], parts[7],
parts[8], parts[8],
parts[9], parts[9],
ParseInt(parts[10]), parts[10],
parts[11], parts[11],
parts[12], parts[12],
ParseInt(parts[13]), parts[13],
parts[14], parts[14],
parts[15], parts[15],
parts[16], parts[16],
@@ -108,7 +108,7 @@ public class DataImport
var headers = headerLine.Split(separator).Select(h => h.Trim()).ToArray(); var headers = headerLine.Split(separator).Select(h => h.Trim()).ToArray();
var imported = new KasAddressList(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath)); var imported = new KasAddressList(KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath)));
var patchType = typeof(AddressPatch); var patchType = typeof(AddressPatch);
var binding = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; var binding = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase;
@@ -134,7 +134,6 @@ public class DataImport
{ {
var fieldName = hasProp.Name.Substring(4); var fieldName = hasProp.Name.Substring(4);
if (fieldName == "refsid") refsid_existing = true;
var hasObj = hasProp.GetValue(patch); var hasObj = hasProp.GetValue(patch);
var has = hasObj is bool b && b; var has = hasObj is bool b && b;
@@ -178,8 +177,8 @@ public class DataImport
return fieldValues.TryGetValue(name, out var v) ? v : ""; return fieldValues.TryGetValue(name, out var v) ? v : "";
} }
var new_refsid = 0; var new_refsid = last_refsid;
if (!refsid_existing) if (!patch.has_refsid)
new_refsid = GenerateNewRefsid(); new_refsid = GenerateNewRefsid();
else else
new_refsid = ParseInt(GetField("refsid")); new_refsid = ParseInt(GetField("refsid"));
@@ -197,10 +196,10 @@ public class DataImport
GetField("anredzus"), GetField("anredzus"),
GetField("strasse"), GetField("strasse"),
GetField("strasse2"), GetField("strasse2"),
ParseInt(GetField("plz")), GetField("plz"),
GetField("ort"), GetField("ort"),
GetField("land"), GetField("land"),
ParseInt(GetField("pplz")), GetField("pplz"),
GetField("postfach"), GetField("postfach"),
GetField("name1"), GetField("name1"),
GetField("name2"), GetField("name2"),
@@ -227,7 +226,19 @@ public class DataImport
int GenerateNewRefsid() int GenerateNewRefsid()
{ {
last_refsid++;
int biggest = last_refsid;
foreach (var set in Settings._instance.addressSets.addresses)
{
foreach (var address in set.KasPersons)
{
if (biggest < address.refsid)
{
biggest = address.refsid+1;
}
}
}
last_refsid = biggest+1;
return last_refsid; return last_refsid;
} }
} }

View File

@@ -3,27 +3,63 @@ using System.Collections.Generic;
namespace Logof_Client; namespace Logof_Client;
public class KasAddressList public class KasAddressList //Address-Set
{ {
//public List<KasPersonError> errors = new();
public List<KasPerson> KasPersons; public List<KasPerson> KasPersons;
public KasAddressList(string name) public KasAddressList(string name)
{ {
KasPersons = new List<KasPerson>(); KasPersons = new List<KasPerson>();
Name = name; Name = name;
foreach (var set in Settings._instance.addressSets.addresses)
if (Name == set.Name)
Name = name + "-new";
var highest = 0;
foreach (var k in Settings._instance.addressSets.addresses)
if (highest <= k.ID)
highest = k.ID + 1;
ID = highest;
} }
public string Name { get; set; } = "Neues Address-Set"; public string Name { get; set; } = "Neues Address-Set";
public int owner_id { get; set; } public int owner_id { get; set; }
public int ID { get; }
public void SetOwner(int owner_id) public void SetOwner(int owner_id)
{ {
this.owner_id = owner_id; this.owner_id = owner_id;
} }
public static string GenerateName(string basic_type, bool? is_rest = false)
{
if (is_rest == true)
return basic_type + " - " + DateTime.Now.ToShortDateString() + " - Rest";
return basic_type + " - " + DateTime.Now.ToShortDateString();
}
// public void UpdateErrorList(List<KasPersonError> errorList)
// {
// //errors.Clear();
// // foreach (KasPersonError err in errorList)
// // {
// //
// // }
// //foreach (var error in errorList) errors.Add(new KasPersonError(error));
// }
public static int GetIDByAddressSetListItem(string listItemName)
{
var id = listItemName.Split(" - ")[0];
return int.Parse(id);
}
} }
public class KasPerson public class KasPerson
{ {
public KasPersonError PersonError = null;
public KasPerson() public KasPerson()
{ {
refsid = 0; refsid = 0;
@@ -36,10 +72,10 @@ public class KasPerson
anredzus = ""; anredzus = "";
strasse = ""; strasse = "";
strasse2 = ""; strasse2 = "";
plz = 0; plz = "";
ort = ""; ort = "";
land = ""; land = "";
pplz = 0; pplz = "";
postfach = ""; postfach = "";
name1 = ""; name1 = "";
name2 = ""; name2 = "";
@@ -62,10 +98,10 @@ public class KasPerson
string anredzus, string anredzus,
string strasse, string strasse,
string strasse2, string strasse2,
int plz, string plz,
string ort, string ort,
string land, string land,
int pplz, string pplz,
string postfach, string postfach,
string name1, string name1,
string name2, string name2,
@@ -113,10 +149,10 @@ public class KasPerson
public string anredzus { get; set; } public string anredzus { get; set; }
public string strasse { get; set; } public string strasse { get; set; }
public string strasse2 { get; set; } public string strasse2 { get; set; }
public int plz { get; set; } public string plz { get; set; }
public string ort { get; set; } public string ort { get; set; }
public string land { get; set; } public string land { get; set; }
public int pplz { get; set; } public string pplz { get; set; }
public string postfach { get; set; } public string postfach { get; set; }
public string name1 { get; set; } public string name1 { get; set; }
public string name2 { get; set; } public string name2 { get; set; }
@@ -131,35 +167,24 @@ public class KasPerson
public class KasPersonError public class KasPersonError
{ {
public KasPersonError((int, List<AddressCheck.ErrorTypes>, List<AddressCheck.WarningTypes>) single_result) public KasPersonError((List<AddressCheck.ErrorTypes>, List<AddressCheck.WarningTypes>) single_result)
{
refsid = single_result.Item1;
try
{
foreach (var err in single_result.Item2) errors += err + ", ";
errors = errors.Trim();
errors = errors.TrimEnd(',');
}
catch
{ {
//refsid = single_result.Item1;
errors = single_result.Item1;
warnings = single_result.Item2;
} }
try //public int refsid { get; set; }
{ public List<AddressCheck.ErrorTypes> errors { get; set; } = new();
if (single_result.Item3 != null) public List<AddressCheck.WarningTypes> warnings { get; set; } = new();
{
foreach (var err in single_result.Item3) warnings += err + ", ";
warnings = warnings.Trim();
warnings = warnings.TrimEnd(',');
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public int refsid { get; set; } public string GetString()
public string errors { get; set; } = ""; {
public string warnings { get; set; } = ""; var output = "";
foreach (var error in errors) output += error + ", ";
foreach (var warning in warnings) output += warning + ", ";
return output;
}
} }

View File

@@ -21,5 +21,21 @@
</PackageReference> </PackageReference>
<PackageReference Include="Lucide.Avalonia" Version="0.1.35"/> <PackageReference Include="Lucide.Avalonia" Version="0.1.35"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.4"/> <PackageReference Include="Newtonsoft.Json" Version="13.0.4"/>
<PackageReference Include="PdfSharp" Version="6.1.1"/>
</ItemGroup>
<ItemGroup>
<None Remove="assets\icon.ico"/>
<AvaloniaResource Include="assets\icon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</AvaloniaResource>
<None Remove="assets\calc_man.png"/>
<AvaloniaResource Include="assets\calc_man.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</AvaloniaResource>
<None Remove="assets\loading.mp4"/>
<AvaloniaResource Include="assets\loading.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</AvaloniaResource>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -3,6 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
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"
MinWidth="1000" MinHeight="600" IsVisible="False"
x:Class="Logof_Client.MainWindow" WindowState="Maximized" Icon="assets/icon.ico" x:Class="Logof_Client.MainWindow" WindowState="Maximized" Icon="assets/icon.ico"
Title="Logof Client"> Title="Logof Client">
<Border> <Border>
@@ -15,7 +16,7 @@
</MenuItem> </MenuItem>
<MenuItem Header="Hilfe"> <MenuItem Header="Hilfe">
<MenuItem Header="Onlinehilfe" x:Name="MnuHelp" Click="MnuHelp_OnClick" /> <MenuItem Header="Onlinehilfe" x:Name="MnuHelp" Click="MnuHelp_OnClick" />
<MenuItem Header="Github" x:Name="MnuGithub" Click="MnuGithub_OnClick" /> <MenuItem Header="Git" x:Name="MnuGit" Click="MnuGit_OnClick" />
<MenuItem Header="Über" x:Name="MnuAbout" Click="MnuAbout_OnClick" /> <MenuItem Header="Über" x:Name="MnuAbout" Click="MnuAbout_OnClick" />
</MenuItem> </MenuItem>
</Menu> </Menu>
@@ -134,6 +135,7 @@
</StackPanel> </StackPanel>
</Button> </Button>
<Button HorizontalAlignment="Stretch" IsEnabled="False" <Button HorizontalAlignment="Stretch" IsEnabled="False"
Click="BtnGenerateLabels_OnClick"
HorizontalContentAlignment="Center" x:Name="BtnGenerateLabels" HorizontalContentAlignment="Center" x:Name="BtnGenerateLabels"
Margin="0,0,0,10"> Margin="0,0,0,10">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@@ -145,9 +147,80 @@
</Button> </Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
<Grid Grid.Row="2" Margin="20"> <Grid Grid.Row="2" Margin="20" IsVisible="True" x:Name="GrdCalcMan">
<Image Source="assets/calc_man.png" VerticalAlignment="Center" HorizontalAlignment="Center" /> <Image Source="assets/calc_man.png" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid> </Grid>
<Grid Grid.Row="2" Margin="20" IsVisible="False" x:Name="GrdCombineTypes">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10"
Margin="5,0,0,0">
<Button HorizontalAlignment="Stretch" MinWidth="240"
HorizontalContentAlignment="Center" x:Name="BtnCombineUnion"
Click="BtnCombineUnion_OnClick"
Margin="0,0,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="SquaresUnite" Width="36" Height="36" />
<Label Content="Vereinigung" VerticalContentAlignment="Center"
FontSize="15"
FontWeight="Bold" />
</StackPanel>
<Label FontSize="9"
Content="Fügt Elemente beider Mengen in eine Menge zusammen" />
</StackPanel>
</Button>
<Button HorizontalAlignment="Stretch" MinWidth="240"
HorizontalContentAlignment="Center" x:Name="BtnCombineIntersect"
Click="BtnCombineIntersection_OnClick"
Margin="0,0,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="SquaresIntersect" Width="36" Height="36" />
<Label Content="Schnittmenge" VerticalContentAlignment="Center"
FontSize="15"
FontWeight="Bold" />
</StackPanel>
<Label FontSize="9"
Content="Überträgt nur doppelte Elemente in die neue Menge" />
</StackPanel>
</Button>
<Button HorizontalAlignment="Stretch" MinWidth="240"
HorizontalContentAlignment="Center" x:Name="BtnCombineDifference"
Click="BtnCombineDifference_OnClick"
Margin="0,0,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="SquaresSubtract" Width="36" Height="36" />
<Label Content="Differenz" VerticalContentAlignment="Center"
FontSize="15"
FontWeight="Bold" />
</StackPanel>
<Label FontSize="9"
Content="Elemente der ersten Menge ohne Elemente der zweiten Menge" />
</StackPanel>
</Button>
<Button HorizontalAlignment="Stretch" MinWidth="240"
HorizontalContentAlignment="Center" x:Name="BtnCombineSymmetric"
Click="BtnCombineSymmetricDifference_OnClick"
Margin="0,0,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="SquaresExclude" Width="36" Height="36" />
<Label Content="Symmetrische Differenz"
VerticalContentAlignment="Center"
FontSize="15"
FontWeight="Bold" />
</StackPanel>
<Label FontSize="9" Content="Nur Elemente, die NICHT doppelt sind" />
</StackPanel>
</Button>
</StackPanel>
<CheckBox HorizontalAlignment="Center" x:Name="CbMergeExportUnmerged" IsChecked="False">Speichere Unverarbeitete in neuem Verteiler</CheckBox>
</StackPanel>
</Grid>
</Grid> </Grid>
</TabItem> </TabItem>
<TabItem IsEnabled="False"> <TabItem IsEnabled="False">
@@ -174,6 +247,14 @@
</StackPanel> </StackPanel>
</TabItem.Header> </TabItem.Header>
</TabItem> </TabItem>
<TabItem IsEnabled="False">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="LibraryBig" Width="32" Height="32" Size="32" />
<Label FontSize="20" Content="Wiki" VerticalContentAlignment="Center" />
</StackPanel>
</TabItem.Header>
</TabItem>
<TabItem IsEnabled="True"> <TabItem IsEnabled="True">
<TabItem.Header> <TabItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@@ -248,6 +329,20 @@
TextChanged="TbSettingsCustomerDescription_OnTextChanged" TextChanged="TbSettingsCustomerDescription_OnTextChanged"
x:Name="TbSettingsCustomerDescription" /> x:Name="TbSettingsCustomerDescription" />
</Grid> </Grid>
<Grid ColumnDefinitions="150,*">
<Label Content="Absenderadresse" />
<TextBox Grid.Column="1" Watermark="Absenderadresse"
HorizontalAlignment="Stretch"
TextChanged="TbSettingsCustomerSenderAddress_OnTextChanged"
x:Name="TbSettingsCustomerSenderAddress" />
</Grid>
<Grid ColumnDefinitions="150,*">
<Label Content="CSV-Trennzeichen" />
<TextBox Grid.Column="1" Watermark=","
HorizontalAlignment="Stretch"
TextChanged="TbSettingsCustomerCsvSeparator_OnTextChanged"
x:Name="TbSettingsCustomerCsvSeparator" />
</Grid>
<Grid ColumnDefinitions="150,*"> <Grid ColumnDefinitions="150,*">
<Label Content="Address-Patch-Info" /> <Label Content="Address-Patch-Info" />
<TextBlock Grid.Column="1" <TextBlock Grid.Column="1"
@@ -283,6 +378,87 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
</TabItem> </TabItem>
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="Globe" Width="16" Height="16" Size="16" />
<Label FontSize="16" Content="Länder" VerticalContentAlignment="Center" />
</StackPanel>
</TabItem.Header>
<Grid ColumnDefinitions="*,*">
<Grid Grid.Column="0" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox x:Name="CountryList" Grid.Row="0"
SelectionChanged="CountryList_OnSelectionChanged" />
<Grid Grid.Row="1" ColumnDefinitions="*,250" Margin="0,5,0,0">
<TextBox x:Name="TbSettingsNewCountry" />
<Button Grid.Column="1" x:Name="BtnSettingsNewCountry"
HorizontalAlignment="Stretch" Click="BtnSettingsNewCountry_OnClick"
HorizontalContentAlignment="Center" Content="+ Hinzufügen"
Margin="5,0,0,0" />
</Grid>
</Grid>
<Grid Grid.Column="1" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid ColumnDefinitions="300,*" Margin="0,0,0,5">
<TextBlock Text="Name:" VerticalAlignment="Center" />
<TextBox Grid.Column="1" x:Name="TbSettingsCountryName"
TextChanged="TbSettingsCountryName_OnTextChanged" />
</Grid>
<Grid ColumnDefinitions="300,*" Margin="0,0,0,5" Grid.Row="1">
<TextBlock Text="Übersetzung:" VerticalAlignment="Center" />
<TextBox Grid.Column="1" x:Name="TbSettingsCountryTranslation"
TextChanged="TbSettingsCountryTranslation_OnTextChanged" />
</Grid>
<Grid Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox x:Name="LbSettingsAlternatives" Grid.Row="0" SelectionMode="Multiple" />
<Grid Grid.Row="1" ColumnDefinitions="*,200" Margin="0,5,0,0">
<TextBox x:Name="TbSettingsNewCountryAlternative"
Watermark="Kürzel/Alternative" />
<Button Grid.Column="1" x:Name="BtnSettingsNewCountryAlternative"
Content="+ Hinzufügen" Margin="5 0 0 0"
HorizontalContentAlignment="Center"
Click="BtnSettingsNewCountryAlternative_OnClick"
HorizontalAlignment="Stretch" />
</Grid>
<Button x:Name="BtnSettingsRemoveSelectedAlternatives" Grid.Row="2"
Content="Ausgewählte Entfernen" Background="#99963434"
HorizontalContentAlignment="Center"
HorizontalAlignment="Stretch"
Click="BtnSettingsRemoveSelectedAlternatives_OnClick"
Margin="0,5,0,0" />
<Button Grid.Row="3"
Content="Land Entfernen" Background="#99963434"
HorizontalContentAlignment="Center" x:Name="BtnSettingsRemoveCountry"
HorizontalAlignment="Stretch" Click="BtnSettingsRemoveCountry_OnClick"
Margin="0,5,0,0" />
</Grid>
</Grid>
</Grid>
</TabItem>
</TabControl> </TabControl>
</TabItem> </TabItem>
</TabControl> </TabControl>

View File

@@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@@ -11,18 +11,31 @@ namespace Logof_Client;
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
public static MainWindow _instance; public static MainWindow _instance;
private Country _selectedCountry;
private bool _suppressCountryRefresh = false;
public Uri filePath; public Uri filePath;
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
//Hide();
var s = new StartupWindow();
//s.Show();
_instance = this; _instance = this;
WindowState = WindowState.Maximized; WindowState = WindowState.Maximized;
Global.Load(); Global.Load();
Settings.Load(); Settings.Load();
RefreshCountryView();
//Thread.Sleep(3000);
//Show();
} }
private async void StartAddressCheck(KasAddressList addresses) private async void StartAddressCheck(int addresSetID)
{ {
//var addresses = DataImport.ImportKasAddressList(path); // Ihr Code hier //var addresses = DataImport.ImportKasAddressList(path); // Ihr Code hier
@@ -31,13 +44,18 @@ public partial class MainWindow : Window
progressWindow.Show(_instance); progressWindow.Show(_instance);
var processor = new AddressCheck(progressWindow); var processor = new AddressCheck(progressWindow);
var result = await processor.Perform(addresses); var result = await processor.Perform(addresSetID);
// foreach (var item in result)
// {
// }
progressWindow.Close(); progressWindow.Close();
new ResultWindow(result, addresses).Show(); new ResultWindow(result, addresSetID).Show();
//await MessageBox.Show(_instance, $"{result.Count} Einträge fehlerhaft.", "Fertig"); //await MessageBox.Show(_instance, $"{result.Count} Einträge fehlerhaft.", "Fertig");
} }
@@ -69,19 +87,25 @@ public partial class MainWindow : Window
throw new NotImplementedException(); throw new NotImplementedException();
} }
private void MnuSettings_OnClick(object? sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
private void MnuHelp_OnClick(object? sender, RoutedEventArgs e) private void MnuHelp_OnClick(object? sender, RoutedEventArgs e)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
private void MnuGithub_OnClick(object? sender, RoutedEventArgs e) private void MnuGit_OnClick(object? sender, RoutedEventArgs e)
{ {
throw new NotImplementedException(); try
{
Process.Start(new ProcessStartInfo
{
FileName = "https://git.mypapercloud.de/fierke/logofclient",
UseShellExecute = true // Wichtig für Plattformübergreifendes Öffnen
});
}
catch (Exception ex)
{
Console.WriteLine($"Fehler beim Öffnen des Links: {ex.Message}");
}
} }
private async void BtnChooseFile_OnClick(object? sender, RoutedEventArgs e) private async void BtnChooseFile_OnClick(object? sender, RoutedEventArgs e)
@@ -108,18 +132,19 @@ public partial class MainWindow : Window
private void BtnCheck_OnClick(object? sender, RoutedEventArgs e) private void BtnCheck_OnClick(object? sender, RoutedEventArgs e)
{ {
MakeCalcManVisible();
if (LstCustomerAdressSets.SelectedIndex == -1) if (LstCustomerAdressSets.SelectedIndex == -1)
{ {
MessageBox.Show(null, "Bitte zunächst ein Adress-Set auswählen", "Kein Adress-Set ausgewählt"); MessageBox.Show(null, "Bitte zunächst ein Adress-Set auswählen", "Kein Adress-Set ausgewählt");
return; return;
} }
var set = new KasAddressList(""); //var set = new KasAddressList("");
foreach (var adset in Settings._instance.addressSets.addresses) //foreach (var adset in Settings._instance.addressSets.addresses)
if (adset.Name == LstCustomerAdressSets.SelectedItem.ToString()) //if (adset.ID == KasAddressList.GetIDByAddressSetListItem(LstCustomerAdressSets.SelectedItem.ToString()))
set = adset; StartAddressCheck(KasAddressList.GetIDByAddressSetListItem(LstCustomerAdressSets.SelectedItem.ToString()));
StartAddressCheck(set);
// var result = DataImport.ImportKasAddressList(filePath); // var result = DataImport.ImportKasAddressList(filePath);
// if (result.Item1) // if (result.Item1)
// { // {
@@ -135,17 +160,19 @@ public partial class MainWindow : Window
private void BtnCombine_OnClick(object? sender, RoutedEventArgs e) private void BtnCombine_OnClick(object? sender, RoutedEventArgs e)
{ {
if (filePath == null) GrdCalcMan.IsVisible = false;
{ GrdCombineTypes.IsVisible = true;
MessageBox.Show(null, "Bitte zunächst eine Datei auswählen", "Datei fehlt");
return;
} }
StartCombine(filePath); private void MakeCalcManVisible()
{
GrdCalcMan.IsVisible = true;
GrdCombineTypes.IsVisible = false;
} }
private async void StartCombine(Uri path) private async void StartCombine(Uri path)
{ {
MakeCalcManVisible();
var addresses = DataImport.ImportKasAddressList(path); var addresses = DataImport.ImportKasAddressList(path);
var progressWindow = new ProgressWindow(); var progressWindow = new ProgressWindow();
var address_list = new List<KasAddressList> { addresses.Item2 }; var address_list = new List<KasAddressList> { addresses.Item2 };
@@ -174,14 +201,14 @@ public partial class MainWindow : Window
progressWindow.Show(_instance); progressWindow.Show(_instance);
var processor = new CombineAddresses(progressWindow); var processor = new CombineAddresses(progressWindow);
var result = await processor.Perform(address_list); //var result = await processor.Perform(address_list);
progressWindow.Close(); progressWindow.Close();
File.WriteAllText(OpenSettingsSaveAsDialog().Result, //File.WriteAllText(OpenSettingsSaveAsDialog().Result,
new CsvBuilder( //new CsvBuilder(
"refsid,anrede,titel,vorname,adel,name,namezus,anredzus,strasse,strasse2,plz,ort,land,pplz,postfach,name1,name2,name3,name4,name5,funktion,funktion2,abteilung,funktionad,lastupdate", //"refsid,anrede,titel,vorname,adel,name,namezus,anredzus,strasse,strasse2,plz,ort,land,pplz,postfach,name1,name2,name3,name4,name5,funktion,funktion2,abteilung,funktionad,lastupdate",
result).BuildKas()); //result).BuildKas());
} }
private async Task<string> OpenSettingsSaveAsDialog() private async Task<string> OpenSettingsSaveAsDialog()
@@ -212,24 +239,58 @@ public partial class MainWindow : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
//Logger.Log("Saving file not successfull: " + ex.Message, Logger.LogType.Error); //Logger.Log("Saving file not successful: " + ex.Message, Logger.LogType.Error);
await MessageBox.Show(this, ex.Message, "Fehler beim Speichern der Datei"); await MessageBox.Show(this, ex.Message, "Fehler beim Speichern der Datei");
return null; return null;
} }
} }
private async void StartCombine(List<KasAddressList> address_lists, int owner_id, string type)
{
var progressWindow = new ProgressWindow();
progressWindow.Show(_instance);
var processor = new CombineAddresses(progressWindow);
var result = await processor.Perform(address_lists, type, CbMergeExportUnmerged.IsChecked);
if (result.Item1 != null)
result.Item1.owner_id = owner_id;
if (result.Item2 != null)
result.Item2.owner_id = owner_id;
if (result.Item1 != null)
Settings._instance.addressSets.addresses.Add(result.Item1);
if (result.Item2 != null)
Settings._instance.addressSets.addresses.Add(result.Item2);
Settings.Save();
progressWindow.Close();
//new ResultWindow(result, addresSetID).Show();
}
private void BtnSettingsAddCustomer_OnClick(object? sender, RoutedEventArgs e) private void BtnSettingsAddCustomer_OnClick(object? sender, RoutedEventArgs e)
{ {
Settings._instance.customers.customers.Add(new Customer()); Settings._instance.customers.customers.Add(new Customer());
TbSettingsCustomerDescription.Text = ""; TbSettingsCustomerDescription.Text = "";
TbSettingsCustomerName.Text = ""; TbSettingsCustomerName.Text = "";
TbSettingsCustomerPatchInfo.Text = ""; TbSettingsCustomerPatchInfo.Text = "";
//Settings.Save();
//RefreshCustomerItems(); Settings.Save();
RefreshCustomerItems();
try
{
LstSettingsCustomers.SelectedIndex = LstSettingsCustomers.Items.Count - 1;
}
catch
{
}
} }
private void TbSettingsCustomerName_OnTextChanged(object? sender, TextChangedEventArgs e) private void TbSettingsCustomerName_OnTextChanged(object? sender, TextChangedEventArgs e)
{ {
if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return;
foreach (var customer in Settings._instance.customers.customers) foreach (var customer in Settings._instance.customers.customers)
if (customer.ID == Settings._instance.customers.current) if (customer.ID == Settings._instance.customers.current)
customer.name = TbSettingsCustomerName.Text; customer.name = TbSettingsCustomerName.Text;
@@ -247,6 +308,8 @@ public partial class MainWindow : Window
{ {
TbSettingsCustomerDescription.Text = customer.description; TbSettingsCustomerDescription.Text = customer.description;
TbSettingsCustomerName.Text = customer.name; TbSettingsCustomerName.Text = customer.name;
TbSettingsCustomerSenderAddress.Text = customer.sender_address;
TbSettingsCustomerCsvSeparator.Text = customer.separator.ToString();
if (customer.patch != null) if (customer.patch != null)
TbSettingsCustomerPatchInfo.Text = customer.patch.ToString(); TbSettingsCustomerPatchInfo.Text = customer.patch.ToString();
else else
@@ -254,7 +317,7 @@ public partial class MainWindow : Window
} }
} }
public void RefreshCustomerItems() public void RefreshCustomerItems(int index = 0)
{ {
if (LstCustomers.Items.Count > 0) if (LstCustomers.Items.Count > 0)
LstCustomers.SelectedIndex = -1; LstCustomers.SelectedIndex = -1;
@@ -273,10 +336,19 @@ public partial class MainWindow : Window
LstCustomers.Items.Add(customer.ID + " - " + customer.name); LstCustomers.Items.Add(customer.ID + " - " + customer.name);
LstSettingsCustomers.Items.Add(customer.ID + " - " + customer.name); LstSettingsCustomers.Items.Add(customer.ID + " - " + customer.name);
} }
try
{
LstSettingsCustomers.SelectedIndex = index;
}
catch
{
}
} }
private void TbSettingsCustomerDescription_OnTextChanged(object? sender, TextChangedEventArgs e) private void TbSettingsCustomerDescription_OnTextChanged(object? sender, TextChangedEventArgs e)
{ {
if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return;
foreach (var customer in Settings._instance.customers.customers) foreach (var customer in Settings._instance.customers.customers)
if (customer.ID == Settings._instance.customers.current) if (customer.ID == Settings._instance.customers.current)
customer.description = TbSettingsCustomerDescription.Text; customer.description = TbSettingsCustomerDescription.Text;
@@ -286,11 +358,12 @@ public partial class MainWindow : Window
private void BtnSettingsSaveCustomerData_OnClick(object? sender, RoutedEventArgs e) private void BtnSettingsSaveCustomerData_OnClick(object? sender, RoutedEventArgs e)
{ {
Settings.Save(); Settings.Save();
RefreshCustomerItems(); RefreshCustomerItems(LstSettingsCustomers.SelectedIndex);
} }
private void LstCustomers_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) private void LstCustomers_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{ {
MakeCalcManVisible();
if (LstCustomers.SelectedItems == null || LstCustomers.SelectedIndex == -1) return; if (LstCustomers.SelectedItems == null || LstCustomers.SelectedIndex == -1) return;
var customer_id = int.Parse(LstCustomers.SelectedItem.ToString().Split(" - ")[0]); var customer_id = int.Parse(LstCustomers.SelectedItem.ToString().Split(" - ")[0]);
RefreshAddressSetListItems(customer_id); RefreshAddressSetListItems(customer_id);
@@ -298,6 +371,7 @@ public partial class MainWindow : Window
private async void BtnCustomerAddressSetImport_OnClick(object? sender, RoutedEventArgs e) private async void BtnCustomerAddressSetImport_OnClick(object? sender, RoutedEventArgs e)
{ {
MakeCalcManVisible();
var opts = new FilePickerOpenOptions(); var opts = new FilePickerOpenOptions();
opts.Title = "Address-Set importieren..."; opts.Title = "Address-Set importieren...";
opts.AllowMultiple = false; opts.AllowMultiple = false;
@@ -320,7 +394,7 @@ public partial class MainWindow : Window
{ {
if (customer.patch == null) if (customer.patch == null)
{ {
var got = DataImport.ImportKasAddressList(selected_path); var got = DataImport.ImportKasAddressList(selected_path, null, customer.separator);
if (!got.Item1) if (!got.Item1)
{ {
Console.WriteLine("Error while importing. Please try another file."); Console.WriteLine("Error while importing. Please try another file.");
@@ -336,7 +410,7 @@ public partial class MainWindow : Window
} }
else else
{ {
var got = DataImport.ImportKasAddressList(selected_path, customer.patch); var got = DataImport.ImportKasAddressList(selected_path, customer.patch, customer.separator);
if (!got.Item1) if (!got.Item1)
{ {
Console.WriteLine("Error while importing. Please try another file."); Console.WriteLine("Error while importing. Please try another file.");
@@ -358,22 +432,29 @@ public partial class MainWindow : Window
public void RefreshAddressSetListItems(int customer_id) public void RefreshAddressSetListItems(int customer_id)
{ {
BtnCheck.IsEnabled = false;
BtnCombine.IsEnabled = false;
BtnGenerateLabels.IsEnabled = false;
BtnRepair.IsEnabled = false;
BtnShorten.IsEnabled = false;
if (LstCustomers.SelectedIndex < 0) return; if (LstCustomers.SelectedIndex < 0) return;
LstCustomerAdressSets.SelectedItems = null; LstCustomerAdressSets.SelectedItems = null;
LstCustomerAdressSets.Items.Clear(); LstCustomerAdressSets.Items.Clear();
foreach (var k in Settings._instance.addressSets.addresses) foreach (var k in Settings._instance.addressSets.addresses)
foreach (var customer in Settings._instance.customers.customers) foreach (var customer in Settings._instance.customers.customers)
if (customer.ID == k.owner_id && customer.ID == customer_id) if (customer.ID == k.owner_id && customer.ID == customer_id)
LstCustomerAdressSets.Items.Add(k.Name); LstCustomerAdressSets.Items.Add(k.ID + " - " + k.Name + "(" + k.KasPersons.Count + " Einträge)");
} }
private void LstCustomerAdressSets_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) private void LstCustomerAdressSets_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{ {
MakeCalcManVisible();
if (LstCustomerAdressSets.SelectedItems == null || LstCustomerAdressSets.SelectedIndex == -1) if (LstCustomerAdressSets.SelectedItems == null || LstCustomerAdressSets.SelectedIndex == -1)
{ {
BtnCheck.IsEnabled = false; BtnCheck.IsEnabled = false;
BtnCombine.IsEnabled = false; BtnCombine.IsEnabled = false;
BtnGenerateLabels.IsEnabled = false; BtnGenerateLabels.IsEnabled = false;
BtnRepair.IsEnabled = false; BtnRepair.IsEnabled = false;
BtnShorten.IsEnabled = false; BtnShorten.IsEnabled = false;
@@ -382,8 +463,8 @@ public partial class MainWindow : Window
{ {
BtnCheck.IsEnabled = true; BtnCheck.IsEnabled = true;
BtnCombine.IsEnabled = true; BtnCombine.IsEnabled = true;
BtnGenerateLabels.IsEnabled = true;
// BtnGenerateLabels.IsEnabled = true;
// BtnRepair.IsEnabled = true; // BtnRepair.IsEnabled = true;
// BtnShorten.IsEnabled = true; // BtnShorten.IsEnabled = true;
} }
@@ -417,4 +498,225 @@ public partial class MainWindow : Window
Settings.Save(); Settings.Save();
} }
private void TbSettingsCustomerCsvSeparator_OnTextChanged(object? sender, TextChangedEventArgs e)
{
if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return;
var sep = !string.IsNullOrEmpty(TbSettingsCustomerCsvSeparator.Text)
? TbSettingsCustomerCsvSeparator.Text
: ",";
foreach (var customer in Settings._instance.customers.customers)
if (customer.ID == Settings._instance.customers.current)
try
{
customer.separator = Convert.ToChar(sep);
}
catch (FormatException ex)
{
MessageBox.Show(this, "Error while converting: " + ex.Message, "Could not parse");
}
catch (Exception ex)
{
MessageBox.Show(this, "Unknown Error: " + ex.Message, "Error");
}
}
private void BtnCombineDifference_OnClick(object? sender, RoutedEventArgs e)
{
var list = new List<KasAddressList>();
foreach (var item in LstCustomerAdressSets.SelectedItems)
list.Add(Settings._instance.addressSets.GetAddressSetByID(
Convert.ToInt32(item.ToString().Split(" - ")[0])));
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "difference");
}
private void BtnCombineUnion_OnClick(object? sender, RoutedEventArgs e)
{
var list = new List<KasAddressList>();
foreach (var item in LstCustomerAdressSets.SelectedItems)
list.Add(Settings._instance.addressSets.GetAddressSetByID(
Convert.ToInt32(item.ToString().Split(" - ")[0])));
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "union");
}
private void BtnCombineIntersection_OnClick(object? sender, RoutedEventArgs e)
{
var list = new List<KasAddressList>();
foreach (var item in LstCustomerAdressSets.SelectedItems)
list.Add(Settings._instance.addressSets.GetAddressSetByID(
Convert.ToInt32(item.ToString().Split(" - ")[0])));
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "intersection");
}
private void BtnCombineSymmetricDifference_OnClick(object? sender, RoutedEventArgs e)
{
var list = new List<KasAddressList>();
foreach (var item in LstCustomerAdressSets.SelectedItems)
list.Add(Settings._instance.addressSets.GetAddressSetByID(
Convert.ToInt32(item.ToString().Split(" - ")[0])));
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "symdiff");
}
private async void BtnGenerateLabels_OnClick(object? sender, RoutedEventArgs e)
{
var saveDialog = new SaveFileDialog
{
DefaultExtension = "pdf",
Filters = { new FileDialogFilter { Name = "PDF-Dateien", Extensions = { "pdf" } } }
};
var filePath = await saveDialog.ShowAsync(this);
if (!string.IsNullOrEmpty(filePath))
{
var builder = new PdfBuilder();
builder.CreateAddressLabelPdfFromAddressSetWithPlaceholder(
Convert.ToInt32(LstCustomerAdressSets.SelectedItems[0].ToString().Split(" - ")[0]),
"Company Logo/Info",
filePath
);
//return true;
}
}
private void TbSettingsCustomerSenderAddress_OnTextChanged(object? sender, TextChangedEventArgs e)
{
if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return;
foreach (var customer in Settings._instance.customers.customers)
if (customer.ID == Settings._instance.customers.current)
customer.sender_address = TbSettingsCustomerSenderAddress.Text;
}
// Country Section
private void BtnSettingsRemoveCountry_OnClick(object? sender, RoutedEventArgs e)
{
if (_selectedCountry != null)
{
Global._instance.countries.Remove(_selectedCountry);
_selectedCountry = null;
}
RefreshCountryView();
}
public void RefreshCountryView()
{
if (_suppressCountryRefresh) return;
try
{
_suppressCountryRefresh = true;
Global.Save();
var alt_index = LbSettingsAlternatives.SelectedIndex;
var country_index = CountryList.SelectedIndex;
LbSettingsAlternatives.Items.Clear();
try
{
CountryList.Items.Clear();
}
catch
{
}
foreach (var c in Global._instance.countries) CountryList.Items.Add(c.name);
try
{
CountryList.SelectedIndex = country_index;
}
catch
{
}
try
{
_selectedCountry = Country.GetByName(CountryList.SelectedItems[0].ToString());
}
catch
{
_selectedCountry = null;
}
if (_selectedCountry == null) return;
//Console.WriteLine("Refreshing alternatives...");
foreach (var a in _selectedCountry.alternatives)
{
LbSettingsAlternatives.Items.Add(a);
//Console.WriteLine(a);
}
TbSettingsCountryName.Text = _selectedCountry.name;
TbSettingsCountryTranslation.Text = _selectedCountry.translation;
try
{
LbSettingsAlternatives.SelectedIndex = alt_index;
}
catch
{
}
}
finally
{
_suppressCountryRefresh = false;
}
}
private void BtnSettingsRemoveSelectedAlternatives_OnClick(object? sender, RoutedEventArgs e)
{
foreach (var selected in LbSettingsAlternatives.SelectedItems)
try
{
_selectedCountry.alternatives.Remove(selected.ToString());
}
catch
{
Console.WriteLine("Error while removing country alternative");
}
RefreshCountryView();
}
private void BtnSettingsNewCountryAlternative_OnClick(object? sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(TbSettingsNewCountryAlternative.Text)) return;
_selectedCountry.alternatives.Add(TbSettingsNewCountryAlternative.Text.Trim());
RefreshCountryView();
}
private void TbSettingsCountryTranslation_OnTextChanged(object? sender, TextChangedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(TbSettingsCountryTranslation.Text))
{
_selectedCountry.translation = TbSettingsCountryTranslation.Text.Trim();
RefreshCountryView();
}
}
private void TbSettingsCountryName_OnTextChanged(object? sender, TextChangedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(TbSettingsCountryName.Text))
{
_selectedCountry.name = TbSettingsCountryName.Text.Trim();
RefreshCountryView();
}
}
private void BtnSettingsNewCountry_OnClick(object? sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(TbSettingsNewCountry.Text)) return;
Global._instance.countries.Add(new Country(TbSettingsNewCountry.Text));
RefreshCountryView();
}
private void CountryList_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
_selectedCountry = Country.GetByName(CountryList.SelectedItems[0].ToString());
RefreshCountryView();
}
} }

View File

@@ -15,10 +15,12 @@
<!-- <Button x:Name="BtnUpdateFilter" Content="Aktualisieren" HorizontalAlignment="Stretch" --> <!-- <Button x:Name="BtnUpdateFilter" Content="Aktualisieren" HorizontalAlignment="Stretch" -->
<!-- VerticalAlignment="Bottom" Margin="10,0,10,10" Click="BtnUpdateFilter_OnClick" /> --> <!-- VerticalAlignment="Bottom" Margin="10,0,10,10" Click="BtnUpdateFilter_OnClick" /> -->
<Button Content="Ausgewählte Anzeigen" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" <Button Content="Ausgewählte Anzeigen" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
x:Name="BtnShwoSelected" Click="BtnShwoSelected_OnClick" x:Name="BtnShowSelected" Click="BtnShowSelected_OnClick"
Margin="10,10,10,10" /> Margin="10,10,10,10" />
</Grid> </Grid>
<DataGrid x:Name="DgResult" Grid.Column="1" AutoGenerateColumns="True" /> <ScrollViewer Grid.Column="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="StkResults" Orientation="Vertical" Margin="10" />
</ScrollViewer>
</Grid> </Grid>
</Window> </Window>

View File

@@ -1,9 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Media;
namespace Logof_Client; namespace Logof_Client;
@@ -11,25 +13,61 @@ public partial class ResultWindow : Window
{ {
public List<CheckBox> errortypecheckboxes = new(); public List<CheckBox> errortypecheckboxes = new();
public KasAddressList ur_addresses = new("Ergebnis_" + DateTime.Now.ToString("ddMMyy_HHmmss")); public KasAddressList ur_addresses = new("Ergebnis_" + DateTime.Now.ToString("ddMMyy_HHmmss"));
public List<(int, List<AddressCheck.ErrorTypes>, List<AddressCheck.WarningTypes>)> ur_result; public List<KasPerson> ur_result;
public List<CheckBox> warningtypecheckboxes = new(); public List<CheckBox> warningtypecheckboxes = new();
public ResultWindow(List<(int, List<AddressCheck.ErrorTypes>, List<AddressCheck.WarningTypes>)> result, public ResultWindow(List<KasPerson> result,
KasAddressList ur_addresses) int addressSetID)
{ {
InitializeComponent(); InitializeComponent();
ur_result = result; ur_result = result;
this.ur_addresses = ur_addresses; ur_addresses = ur_addresses;
Load(result); Load(result);
//ViewSingle(200552426); //ViewSingle(200552426);
} }
private void GenerateView(List<(int, List<AddressCheck.ErrorTypes>, List<AddressCheck.WarningTypes>)> result) private void GenerateView(List<KasPerson> result)
{ {
var errors = new List<KasPersonError>(); // Filter to only show persons with errors
foreach (var single_result in result) errors.Add(new KasPersonError(single_result)); var result_with_errors = result.Where(p => p.PersonError != null).ToList();
LblResultCount.Content = $"{errors.Count}/{ur_result.Count} Ergebnisse"; LblResultCount.Content = $"{result_with_errors.Count}/{ur_result.Count} Ergebnisse";
DgResult.ItemsSource = errors;
StkResults.Children.Clear();
foreach (var person in result_with_errors) StkResults.Children.Add(CreatePersonGrid(person));
}
private Grid CreatePersonGrid(KasPerson person)
{
var grid = new Grid
{
ColumnDefinitions = ColumnDefinitions.Parse("100,*,100,*,100,*"),
RowDefinitions = RowDefinitions.Parse("Auto"),
Margin = new Thickness(0, 5, 0, 5),
Background = new SolidColorBrush(Color.Parse("#F0F0F0"))
};
// Refsid
grid.Children.Add(new TextBlock
{
Text = "refsid: ",
FontWeight = FontWeight.Bold, Margin = new Thickness(5)
});
grid.Children.Add(new TextBlock { Text = person.refsid.ToString(), Margin = new Thickness(5) });
Grid.SetColumn(grid.Children[1], 1);
// PLZ
grid.Children.Add(new TextBlock { Text = "plz:", FontWeight = FontWeight.Bold, Margin = new Thickness(5) });
Grid.SetColumn(grid.Children[2], 2);
grid.Children.Add(new TextBlock { Text = person.plz, Margin = new Thickness(5) });
Grid.SetColumn(grid.Children[3], 3);
// PPLZ
grid.Children.Add(new TextBlock { Text = "errors:", FontWeight = FontWeight.Bold, Margin = new Thickness(5) });
Grid.SetColumn(grid.Children[4], 4);
grid.Children.Add(new TextBlock { Text = person.PersonError.GetString(), Margin = new Thickness(5) });
Grid.SetColumn(grid.Children[5], 5);
return grid;
} }
private void ViewSingle(int refsid) private void ViewSingle(int refsid)
@@ -62,18 +100,20 @@ public partial class ResultWindow : Window
} }
} }
private void Load(List<(int, List<AddressCheck.ErrorTypes>, List<AddressCheck.WarningTypes>)> result) private void Load(List<KasPerson> result)
{ {
var knownErrors = new List<AddressCheck.ErrorTypes>(); var knownErrors = new List<AddressCheck.ErrorTypes>();
var knownWarnings = new List<AddressCheck.WarningTypes>(); var knownWarnings = new List<AddressCheck.WarningTypes>();
foreach (var single_result in result) foreach (var person in result)
{ {
foreach (var errtyp in single_result.Item2) if (person.PersonError == null) continue;
foreach (var errtyp in person.PersonError.errors)
if (!knownErrors.Contains(errtyp)) if (!knownErrors.Contains(errtyp))
knownErrors.Add(errtyp); knownErrors.Add(errtyp);
foreach (var wartyp in single_result.Item3) foreach (var wartyp in person.PersonError.warnings)
if (!knownWarnings.Contains(wartyp)) if (!knownWarnings.Contains(wartyp))
knownWarnings.Add(wartyp); knownWarnings.Add(wartyp);
} }
@@ -108,49 +148,75 @@ public partial class ResultWindow : Window
private void UpdateFilter() private void UpdateFilter()
{ {
var temp_result = new List<(int, List<AddressCheck.ErrorTypes>, List<AddressCheck.WarningTypes>)>(); var temp_result = new List<KasPerson>();
var checked_types = new List<AddressCheck.ErrorTypes>();
var checked_types_war = new List<AddressCheck.WarningTypes>(); var checkedErrors = new HashSet<AddressCheck.ErrorTypes>();
var checkedWarnings = new HashSet<AddressCheck.WarningTypes>();
// safer parsing: use TryParse and trim the Content string
foreach (var cb in errortypecheckboxes) foreach (var cb in errortypecheckboxes)
if (cb.IsChecked == true) if (cb.IsChecked == true)
checked_types.Add( {
(AddressCheck.ErrorTypes)Enum.Parse(typeof(AddressCheck.ErrorTypes), cb.Content.ToString())); var s = cb.Content?.ToString()?.Trim();
if (!string.IsNullOrEmpty(s) &&
Enum.TryParse<AddressCheck.ErrorTypes>(s, true, out var et))
checkedErrors.Add(et);
}
foreach (var cb in warningtypecheckboxes) foreach (var cb in warningtypecheckboxes)
if (cb.IsChecked == true) if (cb.IsChecked == true)
checked_types_war.Add(
(AddressCheck.WarningTypes)Enum.Parse(typeof(AddressCheck.WarningTypes), cb.Content.ToString()));
foreach (var sres in ur_result)
{ {
foreach (var err in sres.Item2) var s = cb.Content?.ToString()?.Trim();
if (checked_types.Contains(err) && !temp_result.Contains(sres)) if (!string.IsNullOrEmpty(s) &&
temp_result.Add(sres); Enum.TryParse<AddressCheck.WarningTypes>(s, true, out var wt))
checkedWarnings.Add(wt);
foreach (var war in sres.Item3)
if (checked_types_war.Contains(war) && !temp_result.Contains(sres))
temp_result.Add(sres);
} }
// If no checkboxes are selected, show all persons with errors (default behavior)
var errors = new List<KasPersonError>(); if (checkedErrors.Count == 0 && checkedWarnings.Count == 0)
foreach (var single_result in temp_result) errors.Add(new KasPersonError(single_result)); temp_result = ur_result.Where(p => p.PersonError != null).ToList();
else
LblResultCount.Content = $"{errors.Count}/{ur_result.Count} Ergebnisse"; foreach (var person in ur_result)
DgResult.ItemsSource = errors;
}
private void BtnShwoSelected_OnClick(object? sender, RoutedEventArgs e)
{ {
foreach (var selected in DgResult.SelectedItems) if (person.PersonError == null) continue;
try
var personErrors = person.PersonError.errors ?? Enumerable.Empty<AddressCheck.ErrorTypes>();
var personWarnings = person.PersonError.warnings ?? Enumerable.Empty<AddressCheck.WarningTypes>();
var matchesError = false;
var matchesWarning = false;
// only test errors if the user selected error-types
if (checkedErrors.Count > 0)
matchesError = personErrors.Any(err => checkedErrors.Contains(err));
// only test warnings if the user selected warning-types
if (checkedWarnings.Count > 0)
matchesWarning = personWarnings.Any(war => checkedWarnings.Contains(war));
// If at least one category matches (OR across categories), include person
if ((matchesError || matchesWarning) && !temp_result.Contains(person))
temp_result.Add(person);
}
LblResultCount.Content = $"{temp_result.Count}/{ur_result.Count} Ergebnisse";
StkResults.Children.Clear();
foreach (var person in temp_result) StkResults.Children.Add(CreatePersonGrid(person));
}
private void BtnShowSelected_OnClick(object? sender, RoutedEventArgs e)
{ {
var _asKas = (KasPersonError)selected; // foreach (var selected in DgResult.SelectedItems)
ViewSingle(_asKas.refsid); // try
} // {
catch (Exception ex) // var _asKas = (KasPerson)selected;
{ // ViewSingle(_asKas.refsid);
Console.WriteLine(ex.Message); // }
} // catch (Exception ex)
// {
// Console.WriteLine(ex.Message);
// }
} }
} }

View File

@@ -62,6 +62,7 @@ public class Global
} }
public string config_path { get; set; } = ""; public string config_path { get; set; } = "";
public List<Country> countries { get; set; } = new();
public static void Save() public static void Save()
{ {
@@ -74,6 +75,7 @@ public class Global
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "logofclient", Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "logofclient",
"global.config"), json); "global.config"), json);
} }
public static void Load() public static void Load()
{ {
// if (!File.Exists(Path.Combine( // if (!File.Exists(Path.Combine(
@@ -120,9 +122,12 @@ public class Customer
public string name { get; set; } = ""; public string name { get; set; } = "";
public string description { get; set; } = ""; public string description { get; set; } = "";
public string sender_address { get; set; } = "";
public AddressPatch patch { get; set; } public AddressPatch patch { get; set; }
public char separator { get; set; } = ',';
public int ID { get; } public int ID { get; }
public static int GetIDByCustomerListItem(string item_content) public static int GetIDByCustomerListItem(string item_content)
{ {
var id = item_content.Split(" - ")[0]; var id = item_content.Split(" - ")[0];
@@ -133,4 +138,47 @@ public class Customer
public class AddressSets public class AddressSets
{ {
public List<KasAddressList> addresses = new(); public List<KasAddressList> addresses = new();
public KasAddressList GetAddressSetByID(int ID)
{
foreach (var i in addresses)
if (i.ID == ID)
return i;
return null;
}
}
public class Country
{
public Country(string name, string translation, List<string> alternatives)
{
this.name = name;
this.translation = translation;
this.alternatives = alternatives;
}
public Country(string name)
{
this.name = name;
translation = "";
alternatives = new List<string>();
}
public Country()
{
}
public string? name { get; set; }
public string translation { get; set; }
public List<string> alternatives { get; set; }
public static Country GetByName(string name)
{
foreach (var country in Global._instance.countries)
if (country.name == name)
return country;
return null;
}
} }

12
StartupWindow.axaml Normal file
View File

@@ -0,0 +1,12 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" Width="400" MinWidth="400" MaxWidth="400" d:DesignHeight="400"
Height="400" MinHeight="400" MaxHeight="400" Icon="assets/icon.ico" SystemDecorations="None"
x:Class="Logof_Client.StartupWindow" Title="Verarbeitung läuft...">
<Grid>
<Label Content="Hello, World!" />
<ProgressBar x:Name="PbLoading" Minimum="0" Maximum="100" />
</Grid>
</Window>

13
StartupWindow.axaml.cs Normal file
View File

@@ -0,0 +1,13 @@
using Avalonia.Controls;
namespace Logof_Client;
public partial class StartupWindow : Window
{
public StartupWindow()
{
InitializeComponent();
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Threading; using Avalonia.Threading;
@@ -9,10 +10,8 @@ public class AddressCheck
{ {
public enum ErrorTypes public enum ErrorTypes
{ {
PlzTooShort, PlzNotUsable,
PlzTooLong, PPlzNotUsable,
PPlzTooShort,
PPlzTooLong,
MayBeSameAddress, MayBeSameAddress,
NoPLZorPPLZ NoPLZorPPLZ
} }
@@ -37,15 +36,26 @@ public class AddressCheck
_progress = progressWindow; _progress = progressWindow;
} }
public async Task<List<(int, List<ErrorTypes>, List<WarningTypes>)>> Perform(KasAddressList addresses) public async Task<List<KasPerson>> Perform(int id)
{ {
var failed_refsids = new List<(int, List<ErrorTypes>, List<WarningTypes>)>(); // Find the index of the address set with the given id
var total = addresses.KasPersons.Count; var adset_index = -1;
for (var i = 0; i < Settings._instance.addressSets.addresses.Count; i++)
if (Settings._instance.addressSets.addresses[i].ID == id)
{
adset_index = i;
break;
}
if (adset_index == -1) return new List<KasPerson>();
var adset = Settings._instance.addressSets.addresses[adset_index];
var total = adset.KasPersons.Count;
var current = 0; var current = 0;
await Task.Run(async () => await Task.Run(async () =>
{ {
foreach (var person in addresses.KasPersons) foreach (var person in adset.KasPersons)
{ {
var errors = new List<ErrorTypes>(); var errors = new List<ErrorTypes>();
var warnings = new List<WarningTypes>(); var warnings = new List<WarningTypes>();
@@ -54,52 +64,63 @@ public class AddressCheck
var address_component_count = 2; // cause anrede and name are first var address_component_count = 2; // cause anrede and name are first
// PLZ-Prüfung // PLZ-Prüfung
if (person.plz == 0 || person.plz == null) if (person.plz == "" || person.plz == null)
{ {
hasFaults = true; hasFaults = true;
warnings.Add(WarningTypes.NoPLZ); warnings.Add(WarningTypes.NoPLZ);
} }
else else
{ {
if ((person.plz < 10000 && string.IsNullOrWhiteSpace(person.land)) || if (!AddressCreator.CheckPLZ(person.plz, person.land))
(person.plz < 10000 && person.land == "GER") ||
(person.plz < 10000 && person.land == "DE"))
{ {
hasFaults = true; hasFaults = true;
errors.Add(ErrorTypes.PlzTooShort); errors.Add(ErrorTypes.PlzNotUsable);
}
else if ((person.plz > 99999 && string.IsNullOrWhiteSpace(person.land)) ||
(person.plz > 99999 && person.land == "GER") ||
(person.plz > 99999 && person.land == "DE"))
{
hasFaults = true;
errors.Add(ErrorTypes.PlzTooLong);
} }
// if ((person.plz < 10000 && string.IsNullOrWhiteSpace(person.land)) ||
// (person.plz < 10000 && person.land == "GER") ||
// (person.plz < 10000 && person.land == "DE"))
// {
// hasFaults = true;
// errors.Add(ErrorTypes.PlzTooShort);
// }
// else if ((person.plz > 99999 && string.IsNullOrWhiteSpace(person.land)) ||
// (person.plz > 99999 && person.land == "GER") ||
// (person.plz > 99999 && person.land == "DE"))
// {
// hasFaults = true;
// errors.Add(ErrorTypes.PlzTooLong);
// }
} }
// PPLZ-Prüfung // PPLZ-Prüfung
if (person.pplz == 0 || person.pplz == null) if (person.pplz == "" || person.pplz == null)
{ {
hasFaults = true; hasFaults = true;
warnings.Add(WarningTypes.NoPPLZ); warnings.Add(WarningTypes.NoPPLZ);
} }
else else
{ {
if ((person.pplz < 10000 && string.IsNullOrWhiteSpace(person.land)) || if (!AddressCreator.CheckPLZ(person.pplz, person.land))
(person.pplz < 10000 && person.land == "GER") ||
(person.pplz < 10000 && person.land == "DE"))
{ {
hasFaults = true; hasFaults = true;
errors.Add(ErrorTypes.PPlzTooShort); errors.Add(ErrorTypes.PPlzNotUsable);
}
else if ((person.pplz > 99999 && string.IsNullOrWhiteSpace(person.land)) ||
(person.pplz > 99999 && person.land == "GER") ||
(person.pplz > 99999 && person.land == "DE"))
{
hasFaults = true;
errors.Add(ErrorTypes.PPlzTooLong);
} }
// if ((person.pplz < 10000 && string.IsNullOrWhiteSpace(person.land)) ||
// (person.pplz < 10000 && person.land == "GER") ||
// (person.pplz < 10000 && person.land == "DE"))
// {
// hasFaults = true;
// errors.Add(ErrorTypes.PPlzTooShort);
// }
// else if ((person.pplz > 99999 && string.IsNullOrWhiteSpace(person.land)) ||
// (person.pplz > 99999 && person.land == "GER") ||
// (person.pplz > 99999 && person.land == "DE"))
// {
// hasFaults = true;
// errors.Add(ErrorTypes.PPlzTooLong);
// }
} }
if (warnings.Contains(WarningTypes.NoPLZ) && warnings.Contains(WarningTypes.NoPPLZ)) if (warnings.Contains(WarningTypes.NoPLZ) && warnings.Contains(WarningTypes.NoPPLZ))
@@ -173,9 +194,9 @@ public class AddressCheck
if (!string.IsNullOrWhiteSpace(person.abteilung)) address_component_count++; if (!string.IsNullOrWhiteSpace(person.abteilung)) address_component_count++;
// Double-Refsid or DoubleAddresses // Double-Refsid or DoubleAddresses
foreach (var person2 in addresses.KasPersons) foreach (var person2 in adset.KasPersons)
{ {
if (addresses.KasPersons.IndexOf(person) == addresses.KasPersons.IndexOf(person2)) continue; if (adset.KasPersons.IndexOf(person) == adset.KasPersons.IndexOf(person2)) continue;
if (person.refsid == person2.refsid) // trifft auf Patch-Addressen nicht zu if (person.refsid == person2.refsid) // trifft auf Patch-Addressen nicht zu
{ {
@@ -211,9 +232,13 @@ public class AddressCheck
} }
if (hasFaults) if (hasFaults)
lock (failed_refsids) lock (Settings._instance.addressSets.addresses)
{ {
failed_refsids.Add((person.refsid, errors, warnings)); // Directly set PersonError in the address set
var person_index = adset.KasPersons.IndexOf(person);
if (person_index >= 0)
Settings._instance.addressSets.addresses[adset_index].KasPersons[person_index].PersonError =
new KasPersonError((errors, warnings));
} }
// Fortschritt aktualisieren // Fortschritt aktualisieren
@@ -228,6 +253,12 @@ public class AddressCheck
}); });
} }
}); });
return failed_refsids;
Settings.Save();
// Return only the persons with errors from the address set
return Settings._instance.addressSets.addresses[adset_index].KasPersons
.Where(p => p.PersonError != null)
.ToList();
} }
} }

275
Tasks/AddressCreation.cs Normal file
View File

@@ -0,0 +1,275 @@
using System;
using System.Linq;
namespace Logof_Client;
public static class AddressCreator
{
/// <summary>
/// Creates max-seven-lines-long Markdown address-string. Analyzes the KasPerson-Instance to find the best result.
/// </summary>
/// <param name="refsid">KasPerson-ID</param>
/// <returns>A Markdown string with the address that is maximum seven lines long</returns>
public static string? CreateFinalMarkdownString2(int refsid)
{
// Maximum seven lines of information
// find the address
KasPerson? address = null;
var string_address = "";
var address_line_count = 0;
foreach (var set in Settings._instance.addressSets.addresses)
{
var temp = set.KasPersons.FirstOrDefault(obj => obj.refsid == refsid);
if (temp != null)
{
address = temp;
break;
}
}
// no address found
if (address == null) return null;
// let's get started: the name (and anrede), block-line-count: 1
if (!string.IsNullOrEmpty(address.anrede))
{
if (address.anrede == "Herr") string_address += "Herrn";
else string_address += address.anrede;
address_line_count++;
}
if (!string.IsNullOrEmpty(address.name) && !string.IsNullOrEmpty(address.vorname))
{
string_address += " " + address.vorname + " " + address.name;
}
else if (!string.IsNullOrEmpty(address.name))
{
}
else // Anrede but no name? to the trash!
{
string_address = "";
address_line_count = 0;
}
return "Hier könnte eine\nAdresse stehen";
}
//+++ Aufbau +++
//
// Von unten anfangen, max. 7 Zeilen
//
// + Wenn Land nicht Deutschland Abbildung von Land (Fettgedruckt)
//
// Alternative A (wenn PPLZ + Ort ausgefüllt):
// + Abbildung PPLZ + Ort - Ort ggf. Abschneiden, wenn länger als eine Zeile … das längste was ich finden konnte: „Giugliano in Campania-Lago Patra“ (passt exakt auf eine Zeile)
// + Abbildung Postfach wenn leer, dann Straße
// + Abbildung Wenn Anredezusatz nicht leer, Anredezusatz, sonst Anrede + Titel + Vorname + Adel + Name + Namenszusatz in Klammern
// + Abbildung Name 1 + Name 2 + Name 3 + Name 4 + Name 5 + Abteilung (insgesamt max. 7 Zeilen)
//
// ansonsten
//
// + Abbildung PLZ + Ort - Ort ggf. Abschneiden, wenn länger als eine Zeile … das längste was ich finden konnte: „Giugliano in Campania-Lago Patra“ (passt exakt auf eine Zeile)
// + Abbildung Straße wenn Straße leer, dann Postfach
// + Abbildung Wenn Anredezusatz nicht leer, Anredezusatz, sonst Anrede + Titel + Vorname + Adel + Name + Namenszusatz in Klammern
// + Abbildung Name 1 + Name 2 + Name 3 + Name 4 + Name 5 + Abteilung (insgesamt max. 7 Zeilen)
//
// Auswurf Fehler-Datei
//
// + wenn keine PLZ und/oder kein Ort -> Fehler
// + wenn kein Name 1-5 und/oder Name -> Fehler
//
// Auswurf CSV-Datei (Komma/TAB, UTF-8, ISO…)
//
// Auswurf PDF mit normalen Absender
//
// Auswurf PDF mit PvSt.
/// <summary>
/// Creates max-seven-lines-long Markdown address-string. Analyzes the KasPerson-Instance to find the best result.
/// </summary>
/// <param name="refsid">KasPerson-ID</param>
/// <returns>A Markdown string with the address that is maximum seven lines long</returns>
public static string? CreateFinalMarkdownString(int refsid)
{
// Maximum seven lines of information
// find the address
KasPerson? address = null;
var string_address = "";
var address_line_count = 0;
foreach (var set in Settings._instance.addressSets.addresses)
{
var temp = set.KasPersons.FirstOrDefault(obj => obj.refsid == refsid);
if (temp != null)
{
address = temp;
break;
}
}
// no address found
if (address == null) return null;
// let's get started: we start from the bottom
// if the country is not germany, set it
// LAND: GER oder DE
if (address.land.ToLower().Trim() != "germany" && address.land.ToLower().Trim() != "ger" &&
address.land.ToLower().Trim() != "" && address.land.ToLower().Trim() != "de" &&
address.land.ToLower().Trim() != "deutschland")
{
string_address = "\n**" + address.land.Trim() + "**"; // Needs to be bold
address_line_count++;
}
// Alternative A: pplz valid and city existing
if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.pplz, address.land))
{
string_address = address.pplz + " " + address.ort + string_address;
address_line_count++;
if (!string.IsNullOrWhiteSpace(address.postfach))
{
string_address = "Postfach " + address.postfach.Trim() + "\n" + string_address;
address_line_count++;
}
else if (!string.IsNullOrWhiteSpace(address.strasse.Trim()))
{
string_address = address.strasse.Trim() + "\n" + string_address;
address_line_count++;
}
var nameline = CreateNameLine(address.anredzus, address.anrede, address.titel, address.vorname,
address.adel, address.name, address.namezus);
if (!string.IsNullOrWhiteSpace(nameline))
{
string_address = nameline + string_address;
address_line_count++;
}
// REIHENFOLGE
var nameattribs = new[]
{ address.name1, address.name2, address.name3, address.name4, address.name5, address.abteilung };
var names = "";
for (var i = 0; i < nameattribs.Length; i++)
try
{
if (address_line_count >= 7) break;
if (!string.IsNullOrWhiteSpace(nameattribs[i]))
{
names += "\n" + nameattribs[i];
address_line_count++;
}
}
catch
{
Console.WriteLine("ERROR 15821");
}
string_address = names + "\n" + string_address;
} // Alternative B: plz valid and city existing
else if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.plz, address.land))
{
string_address = address.plz + " " + address.ort + "\n" + string_address;
address_line_count++;
if (!string.IsNullOrWhiteSpace(address.strasse))
{
string_address = address.strasse.Trim() + "\n" + string_address;
address_line_count++;
}
else if (!string.IsNullOrWhiteSpace(address.postfach.Trim()))
{
string_address = "Postfach " + address.postfach.Trim() + "\n" + string_address;
address_line_count++;
}
var nameline = CreateNameLine(address.anredzus, address.anrede, address.titel, address.vorname,
address.adel, address.name, address.namezus);
if (!string.IsNullOrWhiteSpace(nameline))
{
string_address = nameline + string_address;
address_line_count++;
}
var nameattribs = new[]
{ address.name1, address.name2, address.name3, address.name4, address.name5, address.abteilung };
var names = "";
for (var i = 0; i < nameattribs.Length; i++)
try
{
if (address_line_count >= 7) break;
if (!string.IsNullOrWhiteSpace(nameattribs[i]))
{
names += "\n" + nameattribs[i];
address_line_count++;
}
}
catch
{
Console.WriteLine("ERROR 15821");
}
string_address = names + "\n" + string_address;
} // Error-Handling?
return string_address;
return "Hier könnte eine\nAdresse stehen";
}
public static string CreateNameLine(string anredezus, string anrede, string titel, string vorname, string adel,
string name, string namezus)
{
if (!string.IsNullOrWhiteSpace(anredezus))
return string.Join(" ",
new[] { anredezus, titel, vorname, adel, name }
.Where(s => !string.IsNullOrWhiteSpace(s))
)
+ (string.IsNullOrWhiteSpace(namezus) ? "" : $" ({namezus.Trim()})")
+ "\n";
// else
return string.Join(" ",
new[] { anrede, titel, vorname, adel, name }
.Where(s => !string.IsNullOrWhiteSpace(s))
)
+ (string.IsNullOrWhiteSpace(namezus) ? "" : $" ({namezus.Trim()})")
+ "\n";
}
/// <summary>
/// Returns true if a plz (or pplz) is valid
/// </summary>
/// <param name="plz">the plz itself</param>
/// <param name="land">country, to check the plz</param>
/// <returns>true or faslse, depending on result :+1:</returns>
public static bool CheckPLZ(string plz, string land)
{
if (string.IsNullOrWhiteSpace(plz)) return false;
var trimmedPlz = plz.Trim();
var trimmedLand = land.ToLower().Trim();
// Check if it's a German country code
var isGermany = trimmedLand == "germany" || trimmedLand == "ger" || trimmedLand == "de" ||
trimmedLand == "deutschland" || trimmedLand == "";
if (isGermany)
// For Germany (including empty land), accept numeric postal codes with 5 digits
try
{
var iplz = Convert.ToInt32(trimmedPlz);
if (trimmedPlz.Length == 5) return true;
return false;
}
catch
{
return false;
}
// For non-German countries, accept any non-empty postal code
return true;
}
}

View File

@@ -9,15 +9,15 @@ public class AddressRepair(ProgressWindow progressWindow)
public KasAddressList Perform(KasAddressList all_addresses, public KasAddressList Perform(KasAddressList all_addresses,
List<(int, List<AddressCheck.ErrorTypes>)> failed_addresses) List<(int, List<AddressCheck.ErrorTypes>)> failed_addresses)
{ {
foreach (var k in all_addresses.KasPersons) // foreach (var k in all_addresses.KasPersons)
foreach (var p in failed_addresses) // foreach (var p in failed_addresses)
{ // {
if (k.refsid != p.Item1) continue; // if (k.refsid != p.Item1) continue;
//
if (p.Item2.Contains(AddressCheck.ErrorTypes.DoubledRefsid)) // if (p.Item1.Contains(AddressCheck.WarningTypes.DoubledRefsid))
{ // {
} // }
} // }
return null; return null;
} }

View File

@@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Threading; using Avalonia.Threading;
@@ -14,82 +16,336 @@ public class CombineAddresses
_progress = progressWindow; _progress = progressWindow;
} }
public async Task<KasAddressList> Perform(List<KasAddressList> address_lists) public async Task<(KasAddressList,KasAddressList)> Perform(List<KasAddressList> address_lists, string type, bool? exportUnused)
{ {
KasAddressList result = new("Ergebnis_" + DateTime.Now.ToString("ddMMyy_HHmmss")); var res = await Task.Run(async () =>
await Task.Run(async () =>
{ {
for (var i = 0; i < address_lists.Count; i++) if (type == "difference") return Difference(address_lists, exportUnused);
if (i == 0) if (type == "union") return Union(address_lists, exportUnused);
lock (result) if (type == "intersection") return Intersection(address_lists, exportUnused);
if (type == "symdiff") return SymmetricDifference(address_lists, exportUnused);
return null;
});
return res.Result;
// KasAddressList result = new("Ergebnis_" + DateTime.Now.ToString("ddMMyy_HHmmss"));
// await Task.Run(async () =>
// {
// for (var i = 0; i < address_lists.Count; i++)
// if (i == 0)
// lock (result)
// {
// result = address_lists[i];
// }
// else
// lock (result)
// {
// result = Merge(result, address_lists[i], i + 1, address_lists.Count).Result;
// }
// });
// return result;
return (null,null);
}
/// <summary>
/// Returns true if the addresses are the same.
/// </summary>
/// <param name="first">First address to compare</param>
/// <param name="second">Second address to compare</param>
/// <param name="only_refsid">If true, only a refsid-check will be done</param>
/// <returns></returns>
public bool CompareAddresses(KasPerson first, KasPerson second, bool only_refsid = false)
{ {
result = address_lists[i]; if (first.refsid == second.refsid) return true;
if (!only_refsid)
if (first.name == second.name &&
first.anrede == second.anrede &&
first.anredzus == second.anredzus &&
first.namezus == second.namezus &&
first.titel == second.titel &&
first.adel == second.adel &&
first.strasse == second.strasse &&
first.strasse2 == second.strasse2 &&
first.vorname == second.vorname &&
first.ort == second.ort &&
first.land == second.land &&
first.plz == second.plz &&
first.pplz == second.pplz &&
first.funktion == second.funktion &&
first.funktion2 == second.funktion2 &&
first.funktionad == second.funktionad &&
first.abteilung == second.abteilung &&
first.postfach == second.postfach &&
first.name1 == second.name1 &&
first.name2 == second.name2 &&
first.name3 == second.name3 &&
first.name4 == second.name4 &&
first.name5 == second.name5)
return true;
return false;
}
public async Task<(KasAddressList,KasAddressList)> Difference(List<KasAddressList> address_lists, bool? return_unused,
Progress? progress = null)
{
if (address_lists == null || address_lists.Count == 0)
return (new KasAddressList(KasAddressList.GenerateName("difference")),null);
progress ??= new Progress
{
TotalPersons = address_lists.Sum(l => l.KasPersons.Count),
ComparedPersons = 0
};
// Vereinigung aller Listen außer der ersten
var restUnion = new List<KasPerson>();
for (var i = 1; i < address_lists.Count; i++)
restUnion.AddRange(address_lists[i].KasPersons);
var result = new KasAddressList(KasAddressList.GenerateName("difference"));
var second_result = new KasAddressList(KasAddressList.GenerateName("difference_rest"));
foreach (var person in address_lists[0].KasPersons)
{
var isDouble = restUnion.Any(p => CompareAddresses(person, p));
if (!isDouble)
result.KasPersons.Add(person);
else
second_result.KasPersons.Add(person);
progress.Increment();
if (progress.LogAction == null) continue;
var logMessage =
$"Person mit refsid {person.refsid} verglichen mit {restUnion.Count} Personen des Restes.";
await Dispatcher.UIThread.InvokeAsync(() => progress.LogAction?.Invoke(logMessage));
}
if(return_unused == true) return (result,second_result);
else return (result, null);
}
public async Task<(KasAddressList,KasAddressList)> Union(List<KasAddressList> address_lists, bool? return_unused, Progress progress = null)
{
var result = new KasAddressList(KasAddressList.GenerateName("union"));
var second_result = new KasAddressList(KasAddressList.GenerateName("union_rest"));
if (address_lists == null || address_lists.Count == 0)
return (result,null);
var total = address_lists.Sum(l => l.KasPersons.Count);
var processed = 0;
foreach (var list in address_lists)
foreach (var person in list.KasPersons)
{
if (!result.KasPersons.Any(existing => CompareAddresses(existing, person)))
result.KasPersons.Add(person);
else
second_result.KasPersons.Add(person);
processed++;
var percent = processed / (double)total * 100;
var logMessage =
$"{percent:F1}%: Person mit {person.refsid} hinzugefügt (aktuell {result.KasPersons.Count} Einträge)";
if (progress == null) continue;
if (Dispatcher.UIThread.CheckAccess())
progress.LogAction?.Invoke(logMessage);
else
Dispatcher.UIThread.Post(() => progress.LogAction?.Invoke(logMessage));
}
if(return_unused == true) return (result,second_result);
else return (result, null);
}
public async Task<KasAddressList> MoveDuplicatesToNew()
{
return null;
}
public async Task<(KasAddressList,KasAddressList)> Intersection(List<KasAddressList> address_lists, bool? return_unused, Progress progress = null)
{
var result = new KasAddressList(KasAddressList.GenerateName("intersection"));
var second_result = new KasAddressList(KasAddressList.GenerateName("intersection_rest"));
if (address_lists == null || address_lists.Count == 0)
return (result,null);
// Nur die erste Liste als Ausgangspunkt verwenden
var baseList = address_lists[0];
var otherLists = address_lists.Skip(1).ToList();
var total = baseList.KasPersons.Count;
var processed = 0;
foreach (var person in baseList.KasPersons)
{
// Prüfen, ob Person in *allen* anderen Listen vorkommt
var isInAll = otherLists.All(list =>
list.KasPersons.Any(existing => CompareAddresses(existing, person)));
if (isInAll)
result.KasPersons.Add(person);
else
second_result.KasPersons.Add(person);
processed++;
var percent = processed / (double)total * 100;
var logMessage =
$"{percent:F1}%: Person mit {person.refsid} geprüft {(isInAll ? "in allen enthalten" : "nicht überall vorhanden")}";
// Sicher und nicht blockierend loggen
if (progress != null)
{
if (Dispatcher.UIThread.CheckAccess())
progress.LogAction?.Invoke(logMessage);
else
Dispatcher.UIThread.Post(() => progress.LogAction?.Invoke(logMessage));
}
}
if(return_unused == true) return (result,second_result);
else return (result, null);
}
public async Task<(KasAddressList,KasAddressList)> SymmetricDifference(List<KasAddressList> address_lists, bool? return_unused, Progress progress = null)
{
var result = new KasAddressList(KasAddressList.GenerateName("symmetric_difference"));
var second_result = new KasAddressList(KasAddressList.GenerateName("symmetric_rest"));
if (address_lists == null || address_lists.Count == 0)
return (result, null);
var total = address_lists.Sum(l => l.KasPersons.Count);
var processed = 0;
// Wir sammeln alle Personen + zählen, wie oft sie vorkommen
var allPersons = new List<(KasPerson person, int count)>();
foreach (var list in address_lists)
foreach (var person in list.KasPersons)
{
// Prüfen, ob schon vorhanden
var existing = allPersons.FirstOrDefault(p => CompareAddresses(p.person, person));
if (existing.person != null)
{
// Falls schon drin → Vorkommen erhöhen
var index = allPersons.IndexOf(existing);
allPersons[index] = (existing.person, existing.count + 1);
} }
else else
lock (result)
{ {
result = Merge(result, address_lists[i], i + 1, address_lists.Count).Result; // Neu hinzufügen
} allPersons.Add((person, 1));
});
return result;
} }
private async Task<KasAddressList> Merge(KasAddressList first, KasAddressList second, int num, int total) processed++;
{ var percent = processed / (double)total * 100;
foreach (var sec in second.KasPersons) var logMessage =
{ $"{percent:F1}%: Person mit {person.refsid} verarbeitet (Zwischengröße {allPersons.Count})";
var is_new = true;
foreach (var fi in first.KasPersons)
{
if (fi.refsid == sec.refsid)
{
is_new = false;
break;
}
if (fi.name == sec.name && if (progress != null)
fi.anrede == sec.anrede &&
fi.anredzus == sec.anredzus &&
fi.namezus == sec.namezus &&
fi.titel == sec.titel &&
fi.adel == sec.adel &&
fi.strasse == sec.strasse &&
fi.strasse2 == sec.strasse2 &&
fi.vorname == sec.vorname &&
fi.ort == sec.ort &&
fi.land == sec.land &&
fi.plz == sec.plz &&
fi.pplz == sec.pplz &&
fi.funktion == sec.funktion &&
fi.funktion2 == sec.funktion2 &&
fi.funktionad == sec.funktionad &&
fi.abteilung == sec.abteilung &&
fi.postfach == sec.postfach &&
fi.name1 == sec.name1 &&
fi.name2 == sec.name2 &&
fi.name3 == sec.name3 &&
fi.name4 == sec.name4 &&
fi.name5 == sec.name5)
{ {
is_new = false; if (Dispatcher.UIThread.CheckAccess())
break; progress.LogAction?.Invoke(logMessage);
}
}
if (is_new) first.KasPersons.Add(sec);
var subperc = second.KasPersons.IndexOf(sec) / second.KasPersons.Count;
var percent = (num + (double)subperc) / total * 100;
await Dispatcher.UIThread.InvokeAsync(() =>
{
if (is_new)
_progress.AddToLog($"Person mit refsid {sec.refsid} ergänzt");
else else
_progress.AddToLog($"Person mit refsid {sec.refsid} bereits vorhanden"); Dispatcher.UIThread.Post(() => progress.LogAction?.Invoke(logMessage));
}
_progress.ChangePercentage(percent);
});
} }
return first; // Nur diejenigen übernehmen, die *genau einmal* vorkamen
foreach (var (person, count) in allPersons)
if (count == 1)
result.KasPersons.Add(person);
else
second_result.KasPersons.Add(person);
if(return_unused == true) return (result,second_result);
else return (result, null);
}
// private async Task<KasAddressList> Merge(KasAddressList first, KasAddressList second, int num, int total)
// {
// foreach (var sec in second.KasPersons)
// {
// var is_new = true;
// foreach (var fi in first.KasPersons)
// {
// if (fi.refsid == sec.refsid)
// {
// is_new = false;
// break;
// }
//
// if (fi.name == sec.name &&
// fi.anrede == sec.anrede &&
// fi.anredzus == sec.anredzus &&
// fi.namezus == sec.namezus &&
// fi.titel == sec.titel &&
// fi.adel == sec.adel &&
// fi.strasse == sec.strasse &&
// fi.strasse2 == sec.strasse2 &&
// fi.vorname == sec.vorname &&
// fi.ort == sec.ort &&
// fi.land == sec.land &&
// fi.plz == sec.plz &&
// fi.pplz == sec.pplz &&
// fi.funktion == sec.funktion &&
// fi.funktion2 == sec.funktion2 &&
// fi.funktionad == sec.funktionad &&
// fi.abteilung == sec.abteilung &&
// fi.postfach == sec.postfach &&
// fi.name1 == sec.name1 &&
// fi.name2 == sec.name2 &&
// fi.name3 == sec.name3 &&
// fi.name4 == sec.name4 &&
// fi.name5 == sec.name5)
// {
// is_new = false;
// break;
// }
// }
//
// if (is_new) first.KasPersons.Add(sec);
// var subperc = second.KasPersons.IndexOf(sec) / second.KasPersons.Count;
// var percent = (num + (double)subperc) / total * 100;
// await Dispatcher.UIThread.InvokeAsync(() =>
// {
// if (is_new)
// _progress.AddToLog($"Person mit refsid {sec.refsid} ergänzt");
// else
// _progress.AddToLog($"Person mit refsid {sec.refsid} bereits vorhanden");
//
// _progress.ChangePercentage(percent);
// });
// }
//
// return first;
// }
}
public class Progress
{
public int TotalPersons { get; set; } // Gesamtzahl der zu prüfenden Personen
public int ComparedPersons { get; set; } // Schon verglichene Personen
public double Percentage => TotalPersons == 0 ? 0 : (double)ComparedPersons / TotalPersons * 100;
public Action<string>? LogAction { get; set; } // z.B. Dispatcher-UI-Callback
public void Increment()
{
var comparedPersons = ComparedPersons;
Interlocked.Increment(ref comparedPersons);
} }
} }

391
Tasks/PdfBuilder.cs Normal file
View File

@@ -0,0 +1,391 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
namespace Logof_Client;
public class PdfBuilder
{
// Table layout
private const int CellsPerRow = 3;
private const int CellsPerPage = 21; // 3 columns × 7 rows
private readonly XFont _boldFont = new("Arial", 9, XFontStyleEx.Bold);
private readonly double _cellHeight = 42.43; // mm
private readonly double _cellPaddingBottom = 5; // mm
// Padding inside cells
private readonly double _cellPaddingLeft = 5; // mm
private readonly double _cellPaddingTop = 5; // mm
// Cell dimensions (in mm)
private readonly double _cellWidth = 70; // mm
// Font settings
private readonly double _fontSize = 9;
private readonly double _marginBottom = 1; // mm
// Paper and layout settings
private readonly double _marginLeft = 0; // mm
private readonly double _marginRight = 0; // mm
private readonly double _marginTop = 0; // mm
private readonly XFont _regularFont = new("Arial", 9, XFontStyleEx.Regular);
private readonly XFont _smallFont = new("Arial", 6, XFontStyleEx.Regular);
/// <summary>
/// Creates a PDF document with address stickers from an AddressSet in a 3×7 grid layout on A4 pages.
/// </summary>
/// <param name="addressSetId">The ID of the AddressSet to use</param>
/// <param name="outputPath">Path where the PDF should be saved</param>
public void CreateAddressLabelPdfFromAddressSet(int addressSetId, string outputPath)
{
// Find the AddressSet by ID
var addressSet = Settings._instance.addressSets.GetAddressSetByID(addressSetId);
if (addressSet == null)
throw new ArgumentException($"AddressSet with ID {addressSetId} not found");
if (addressSet.KasPersons == null || addressSet.KasPersons.Count == 0)
throw new ArgumentException($"AddressSet with ID {addressSetId} contains no addresses");
// Generate markdown addresses from all KasPersons in the set
//var addresses = new string?[addressSet.KasPersons.Count];
var addresses = new List<string>();
// find customer (owner) to include sender_address
string senderLine = null;
try
{
var owner = Settings._instance.customers.customers.FirstOrDefault(c => c.ID == addressSet.owner_id);
if (owner != null && !string.IsNullOrWhiteSpace(owner.sender_address))
// ensure single line and wrap in a small-font tag
senderLine = "<font6>" + owner.sender_address.Replace("\n", " ").Trim() + "</font6>\n";
}
catch
{
senderLine = null;
}
for (var i = 0; i < addressSet.KasPersons.Count; i++)
{
var addr = AddressCreator.CreateFinalMarkdownString(addressSet.KasPersons[i].refsid);
if (string.IsNullOrWhiteSpace(addr.Trim())) continue;
if (!string.IsNullOrEmpty(senderLine))
addresses.Add(senderLine + addr);
else
addresses.Add(addr);
}
CreateAddressLabelPdf(addresses, outputPath);
}
/// <summary>
/// Creates a PDF document with address stickers from an AddressSet with a placeholder in the first cell.
/// </summary>
/// <param name="addressSetId">The ID of the AddressSet to use</param>
/// <param name="placeholderText">Text for the first cell (top-left)</param>
/// <param name="outputPath">Path where the PDF should be saved</param>
public void CreateAddressLabelPdfFromAddressSetWithPlaceholder(int addressSetId, string placeholderText,
string outputPath)
{
// Find the AddressSet by ID
var addressSet = Settings._instance.addressSets.GetAddressSetByID(addressSetId);
if (addressSet == null)
throw new ArgumentException($"AddressSet with ID {addressSetId} not found");
if (addressSet.KasPersons == null || addressSet.KasPersons.Count == 0)
throw new ArgumentException($"AddressSet with ID {addressSetId} contains no addresses");
// Generate markdown addresses from all KasPersons in the set
//var addresses = new string?[addressSet.KasPersons.Count];
var addresses = new List<string>();
// find customer (owner) to include sender_address
string senderLine = null;
try
{
var owner = Settings._instance.customers.customers.FirstOrDefault(c => c.ID == addressSet.owner_id);
if (owner != null && !string.IsNullOrWhiteSpace(owner.sender_address))
senderLine = "<font6>" + owner.sender_address.Replace("\n", " ").Trim() + "</font6>\n";
}
catch
{
senderLine = null;
}
for (var i = 0; i < addressSet.KasPersons.Count; i++)
{
var addr = AddressCreator.CreateFinalMarkdownString(addressSet.KasPersons[i].refsid);
if (string.IsNullOrWhiteSpace(addr.Trim())) continue;
if (!string.IsNullOrEmpty(senderLine))
addresses.Add(senderLine + (addr ?? ""));
else
addresses.Add(addr);
}
CreateAddressLabelPdfWithPlaceholder(addresses, placeholderText, outputPath);
}
/// <summary>
/// Creates a PDF document with address stickers in a 3×7 grid layout on A4 pages.
/// </summary>
/// <param name="addresses">Array of addresses (from CreateFinalMarkdownString)</param>
/// <param name="outputPath">Path where the PDF should be saved</param>
public void CreateAddressLabelPdf(List<string> addresses, string outputPath)
{
if (addresses == null || addresses.Count == 0)
throw new ArgumentException("Addresses array cannot be null or empty");
var document = new PdfDocument();
var addressIndex = 0;
while (addressIndex < addresses.Count)
{
var page = document.AddPage();
page.Size = PageSize.A4;
using (var gfx = XGraphics.FromPdfPage(page))
{
// Draw the grid and fill cells
DrawPage(gfx, addresses, ref addressIndex);
}
}
// Save the document
document.Save(outputPath);
}
/// <summary>
/// Creates a PDF document with a single placeholder cell for other information.
/// </summary>
/// <param name="addresses">Array of addresses</param>
/// <param name="placeholderText">Text for the first cell (top-left)</param>
/// <param name="outputPath">Path where the PDF should be saved</param>
public void CreateAddressLabelPdfWithPlaceholder(List<string> addresses, string placeholderText, string outputPath)
{
if (addresses == null || addresses.Count == 0)
throw new ArgumentException("Addresses array cannot be null or empty");
var document = new PdfDocument();
var addressIndex = 0;
var isFirstCell = true;
while (addressIndex < addresses.Count || isFirstCell)
{
var page = document.AddPage();
page.Size = PageSize.A4;
using (var gfx = XGraphics.FromPdfPage(page))
{
DrawPageWithPlaceholder(gfx, addresses, ref addressIndex, ref isFirstCell, placeholderText);
}
}
document.Save(outputPath);
}
private void DrawPage(XGraphics gfx, List<string> addresses, ref int addressIndex)
{
var cellCount = 0;
for (var row = 0; row < 7; row++)
{
for (var col = 0; col < 3; col++)
{
if (addressIndex >= addresses.Count) break;
var x = MmToPoints(_marginLeft + col * _cellWidth);
var y = MmToPoints(_marginTop + row * _cellHeight);
DrawCell(gfx, x, y, addresses[addressIndex]);
addressIndex++;
cellCount++;
}
if (addressIndex >= addresses.Count) break;
}
}
private void DrawPageWithPlaceholder(XGraphics gfx, List<string> addresses, ref int addressIndex,
ref bool isFirstCell, string placeholderText)
{
var cellCount = 0;
for (var row = 0; row < 7; row++)
for (var col = 0; col < 3; col++)
{
var x = MmToPoints(_marginLeft + col * _cellWidth);
var y = MmToPoints(_marginTop + row * _cellHeight);
// First cell: placeholder
if (isFirstCell)
{
DrawCell(gfx, x, y, placeholderText);
isFirstCell = false;
}
else if (addressIndex < addresses.Count)
{
DrawCell(gfx, x, y, addresses[addressIndex]);
addressIndex++;
}
else
{
DrawEmptyCell(gfx, x, y);
}
cellCount++;
}
}
private void DrawCell(XGraphics gfx, double x, double y, string? address)
{
var cellWidthPoints = MmToPoints(_cellWidth);
var cellHeightPoints = MmToPoints(_cellHeight);
// Draw cell border
var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints);
gfx.DrawRectangle(XPens.Black, rect);
// Draw address content if available
if (!string.IsNullOrEmpty(address)) DrawMarkdownText(gfx, address, x, y, cellWidthPoints, cellHeightPoints);
}
private void DrawEmptyCell(XGraphics gfx, double x, double y)
{
var cellWidthPoints = MmToPoints(_cellWidth);
var cellHeightPoints = MmToPoints(_cellHeight);
var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints);
gfx.DrawRectangle(XPens.Black, rect);
}
private void DrawMarkdownText(XGraphics gfx, string text, double x, double y, double cellWidth, double cellHeight)
{
var paddingLeftPoints = MmToPoints(_cellPaddingLeft);
var paddingTopPoints = MmToPoints(_cellPaddingTop);
var paddingBottomPoints = MmToPoints(_cellPaddingBottom);
var maxWidth = cellWidth - paddingLeftPoints * 2;
// Split text by newlines and remove empty trailing lines
var rawLines = text.Split(new[] { "\n" }, StringSplitOptions.None);
var lines = rawLines.Where(l => l != null).ToArray();
// Use a conservative line height in points
var lineHeight = _regularFont.Size * 1.2;
// Calculate total height of the text block
var totalHeight = lines.Length * lineHeight;
// Start drawing from the top of the cell (align addresses to top)
var startY = y + paddingTopPoints;
var currentY = startY;
foreach (var line in lines)
{
// Stop if we've reached the top boundary
if (currentY + lineHeight > y + cellHeight - paddingBottomPoints + 0.001)
break;
// Parse and draw the line with markdown support
DrawLineWithMarkdown(gfx, line, x + paddingLeftPoints, currentY, maxWidth);
currentY += lineHeight;
}
}
private void DrawLineWithMarkdown(XGraphics gfx, string line, double x, double y, double maxWidth)
{
var currentX = x;
var i = 0;
while (i < line.Length)
{
// Check for small-font tag <font6> ... </font6>
if (i <= line.Length - 7 && line.Substring(i, 7) == "<font6>")
{
var endTag = line.IndexOf("</font6>", i + 7, StringComparison.Ordinal);
if (endTag != -1)
{
var inner = line.Substring(i + 7, endTag - (i + 7));
if (!string.IsNullOrEmpty(inner))
{
gfx.DrawString(inner, _smallFont, XBrushes.Black,
new XRect(currentX, y, maxWidth - (currentX - x), _smallFont.Size * 1.2),
XStringFormats.TopLeft);
var measuredSmall = gfx.MeasureString(inner, _smallFont);
currentX += measuredSmall.Width;
}
i = endTag + 8; // move past </font6>
continue;
}
}
// Check for bold marker (**)
if (i < line.Length - 1 && line[i] == '*' && line[i + 1] == '*')
{
// Find closing **
var endIndex = line.IndexOf("**", i + 2, StringComparison.Ordinal);
if (endIndex != -1)
{
var boldText = line.Substring(i + 2, endIndex - (i + 2));
// Draw bold text and measure width accurately
gfx.DrawString(boldText, _boldFont, XBrushes.Black,
new XRect(currentX, y, maxWidth - (currentX - x), _boldFont.Size * 1.2),
XStringFormats.TopLeft);
var measured = gfx.MeasureString(boldText, _boldFont);
currentX += measured.Width;
i = endIndex + 2;
continue;
}
}
// Regular text until next ** or end of line
var nextBoldIndex = line.IndexOf("**", i, StringComparison.Ordinal);
var textEnd = nextBoldIndex == -1 ? line.Length : nextBoldIndex;
var regularText = line.Substring(i, textEnd - i);
if (!string.IsNullOrEmpty(regularText))
{
gfx.DrawString(regularText, _regularFont, XBrushes.Black,
new XRect(currentX, y, maxWidth - (currentX - x), _regularFont.Size * 1.2), XStringFormats.TopLeft);
var measured = gfx.MeasureString(regularText, _regularFont);
currentX += measured.Width;
}
i = textEnd;
}
}
/// <summary>
/// Converts millimeters to points (1 mm = 2.834645669 points)
/// </summary>
private double MmToPoints(double mm)
{
return mm * 2.834645669;
}
// Configuration methods to allow customization
/// <summary>
/// Sets the cell dimensions in millimeters
/// </summary>
public void SetCellDimensions(double width, double height)
{
if (width <= 0 || height <= 0)
throw new ArgumentException("Cell dimensions must be positive");
}
/// <summary>
/// Sets the page margins in millimeters
/// </summary>
public void SetMargins(double left, double top, double right, double bottom)
{
if (left < 0 || top < 0 || right < 0 || bottom < 0)
throw new ArgumentException("Margins cannot be negative");
}
}

BIN
assets/loading.mp4 Normal file

Binary file not shown.

157
docs/logof_client_docs.tex Normal file
View File

@@ -0,0 +1,157 @@
\documentclass[a4paper]{article}
\usepackage{graphicx}
\usepackage[left=3cm,right=3cm,top=3cm, bottom=3cm]{geometry}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage[headsepline, footsepline]{scrlayer-scrpage}
\usepackage{enumerate}
\usepackage{dsfont}
\usepackage[]{mathtools}
\usepackage[]{mathbbol}
\usepackage{multicol}
\usepackage{enumitem}
\usepackage[hidelinks]{hyperref}
\usepackage[]{circuitikz}
\usepackage{tcolorbox} % Für schöne Boxen
\usetikzlibrary{circuits.logic.IEC}
\usepackage{tikz}
\usepackage{tkz-graph}
\usepackage{listings}
\usepackage{xcolor}
\setlist{itemsep=0.3em, topsep=0.5em, parsep=0pt}
\newcommand{\bpf}[1]{%
\par\vspace{0.8\baselineskip}% Abstand vor der Überschrift
\noindent\textbf{#1}% Fettgedruckte Überschrift
\par\vspace{0.3\baselineskip}% Abstand nach der Überschrift
}
\renewcommand{\contentsname}{Inhaltsverzeichnis}
\renewcommand{\figurename}{Grafik}
\renewcommand{\partname}{Teil}
\renewcommand{\epsilon}{\varepsilon}
\definecolor{darkgrey}{HTML}{232327}
% Zählerdefinition mit AUTOMATISCHEM SUBSECTION-RESET
\newcounter{commoncounter}[subsection]
\renewcommand{\thecommoncounter}{\thesubsection.\arabic{commoncounter}}
% Zähler direkt bei Dokumentstart initialisieren
\AtBeginDocument{\setcounter{commoncounter}{0}}
% BOX-DEFINITIONEN mit korrigierter Zählerlogik
\newtcolorbox{definitionbox}[1][]{
before title={\refstepcounter{commoncounter}}, % KRITISCH: vor dem Titel!
title={Definition \thecommoncounter: #1},
colback=white,
colframe=white!75!darkgrey,
fonttitle=\bfseries,
boxrule=0.6mm,
coltitle=black,
rounded corners,
before skip=10pt,
after skip=10pt
}
\newtcolorbox{examplebox}[1][]{
before title={\refstepcounter{commoncounter}}, % KRITISCH: vor dem Titel!
title={Beispiel \thecommoncounter: #1},
colback=white,
colframe=white!75!orange,
fonttitle=\bfseries,
boxrule=0.6mm,
coltitle=black,
rounded corners,
before skip=10pt,
after skip=10pt
}
\newtcolorbox{satzbox}[1][]{
before title={\refstepcounter{commoncounter}}, % KRITISCH: vor dem Titel!
title={Satz \thecommoncounter: #1},
colback=white,
colframe=white!75!blue,
fonttitle=\bfseries,
boxrule=0.6mm,
coltitle=black,
rounded corners,
before skip=10pt,
after skip=10pt
}
\definecolor{codegreen}{rgb}{0,0.6,0}
\definecolor{codeblue}{rgb}{0,0,0.8}
\definecolor{codered}{rgb}{0.8,0,0}
\definecolor{lightgray}{rgb}{0.95,0.95,0.95}
\lstdefinestyle{CSharpStyle}{
language=Python,
basicstyle=\ttfamily\small, % Monospace-Schrift
keywordstyle=\color{blue}\bfseries, % Schlüsselwörter fett und blau
stringstyle=\color{red}, % Strings rot
commentstyle=\color{codegreen}, % Kommentare grün
backgroundcolor=\color{lightgray}, % Hintergrundfarbe
numbers=left, % Zeilennummern links
numbersep=10px, % Abstand zwischen Zeilennummern und Code
numberstyle=\color{gray}\texttt,
stepnumber=1, % Zeilennummerierung Schrittweite 1
frame=single, % Rahmen um den Code
tabsize=4, % Tabulatorgröße
breaklines=true, % Zeilenumbruch aktivieren
captionpos=none,
showstringspaces=false,
xleftmargin=15pt, % Linker Rand für den Code (verschiebt alles nach rechts)
}
% Umgebung für Listings mit Titel und Zähler
\newenvironment{codeexample}[1][]{
\refstepcounter{commoncounter} % Zähler erhöhen
\lstset{
style=CSharpStyle,
caption={Listing \thecommoncounter: #1}, % Titel mit Zähler
label={listing:\thecommoncounter}
}
}{}
\setlength{\parindent}{0pt}
\title{\includegraphics[width=0.3\textwidth]{../assets/icon.png}\vspace{15pt}\\Logof Client\\
Handbuch}
\author{Elias Fierke}
\pagestyle{scrheadings}
\date{Oktober 2025}
\begin{document}
\ohead{Oktober 2025}
\ofoot{Seite {\pagemark} von \pageref{LastPage}}
\ihead{Logof Client Handbuch}
\maketitle
\tableofcontents
\newpage
\part{Einführung}
\newpage
\part{Installation}
\newpage
\part{Adress-Verwaltung}
\label{LastPage}
\end{document}

View File

@@ -1,4 +0,0 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0")]

View File

@@ -1 +0,0 @@
2bf0329c81e2f3ff97db5a7094fe15e6e531951b18bd3b2cd78b8ead3da7d4f6

Binary file not shown.

View File

@@ -1,22 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Logof Client")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+081a705d2dba93801d5b5b2a9e3fdd48ca22a4a9")]
[assembly: System.Reflection.AssemblyProductAttribute("Logof Client")]
[assembly: System.Reflection.AssemblyTitleAttribute("Logof Client")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Von der MSBuild WriteCodeFragment-Klasse generiert.

View File

@@ -1 +0,0 @@
9f6fed80f7fee5ed32df831b4e1e94a71401c93cdd66f2736d976877317c192f

View File

@@ -1,37 +0,0 @@
is_global = true
build_property.AvaloniaNameGeneratorIsEnabled = true
build_property.AvaloniaNameGeneratorBehavior = InitializeComponent
build_property.AvaloniaNameGeneratorDefaultFieldModifier = internal
build_property.AvaloniaNameGeneratorFilterByPath = *
build_property.AvaloniaNameGeneratorFilterByNamespace = *
build_property.AvaloniaNameGeneratorViewFileNamingStrategy = NamespaceAndClassName
build_property.AvaloniaNameGeneratorAttachDevTools = true
build_property.TargetFramework = net9.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = Logof_Client
build_property.ProjectDir = /home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.EffectiveAnalysisLevelStyle = 9.0
build_property.EnableCodeStyleSeverity =
[/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/App.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
[/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/MainWindow.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
[/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/MessageBox.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
[/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/ProgressWindow.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
[/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/ResultWindow.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml

View File

@@ -1,102 +0,0 @@
{
"format": 1,
"restore": {
"/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/Logof Client.csproj": {}
},
"projects": {
"/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/Logof Client.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/Logof Client.csproj",
"projectName": "Logof Client",
"projectPath": "/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/Logof Client.csproj",
"packagesPath": "/home/fierke/.nuget/packages/",
"outputPath": "/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/obj/",
"projectStyle": "PackageReference",
"configFilePaths": [
"/home/fierke/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net9.0"
],
"sources": {
"/usr/lib64/dotnet/library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net9.0": {
"targetAlias": "net9.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.100"
},
"frameworks": {
"net9.0": {
"targetAlias": "net9.0",
"dependencies": {
"Avalonia": {
"target": "Package",
"version": "[11.3.2, )"
},
"Avalonia.Controls.DataGrid": {
"target": "Package",
"version": "[11.3.2, )"
},
"Avalonia.Desktop": {
"target": "Package",
"version": "[11.3.2, )"
},
"Avalonia.Diagnostics": {
"target": "Package",
"version": "[11.3.2, )"
},
"Avalonia.Fonts.Inter": {
"target": "Package",
"version": "[11.3.2, )"
},
"Avalonia.Themes.Fluent": {
"target": "Package",
"version": "[11.3.2, )"
},
"Lucide.Avalonia": {
"target": "Package",
"version": "[0.1.35, )"
},
"Newtonsoft.Json": {
"target": "Package",
"version": "[13.0.4, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/9.0.110/PortableRuntimeIdentifierGraph.json"
}
}
}
}
}

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/home/fierke/.nuget/packages/</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/home/fierke/.nuget/packages/</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="/home/fierke/.nuget/packages/" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)skiasharp.nativeassets.webassembly/2.88.9/buildTransitive/netstandard1.0/SkiaSharp.NativeAssets.WebAssembly.props" Condition="Exists('$(NuGetPackageRoot)skiasharp.nativeassets.webassembly/2.88.9/buildTransitive/netstandard1.0/SkiaSharp.NativeAssets.WebAssembly.props')" />
<Import Project="$(NuGetPackageRoot)avalonia/11.3.2/buildTransitive/Avalonia.props" Condition="Exists('$(NuGetPackageRoot)avalonia/11.3.2/buildTransitive/Avalonia.props')" />
<Import Project="$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly/8.3.1.1/buildTransitive/netstandard1.0/HarfBuzzSharp.NativeAssets.WebAssembly.props" Condition="Exists('$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly/8.3.1.1/buildTransitive/netstandard1.0/HarfBuzzSharp.NativeAssets.WebAssembly.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgAvalonia_BuildServices Condition=" '$(PkgAvalonia_BuildServices)' == '' ">/home/fierke/.nuget/packages/avalonia.buildservices/0.0.31</PkgAvalonia_BuildServices>
<PkgAvalonia Condition=" '$(PkgAvalonia)' == '' ">/home/fierke/.nuget/packages/avalonia/11.3.2</PkgAvalonia>
</PropertyGroup>
</Project>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)skiasharp.nativeassets.webassembly/2.88.9/buildTransitive/netstandard1.0/SkiaSharp.NativeAssets.WebAssembly.targets" Condition="Exists('$(NuGetPackageRoot)skiasharp.nativeassets.webassembly/2.88.9/buildTransitive/netstandard1.0/SkiaSharp.NativeAssets.WebAssembly.targets')" />
<Import Project="$(NuGetPackageRoot)avalonia.buildservices/0.0.31/buildTransitive/Avalonia.BuildServices.targets" Condition="Exists('$(NuGetPackageRoot)avalonia.buildservices/0.0.31/buildTransitive/Avalonia.BuildServices.targets')" />
<Import Project="$(NuGetPackageRoot)avalonia/11.3.2/buildTransitive/Avalonia.targets" Condition="Exists('$(NuGetPackageRoot)avalonia/11.3.2/buildTransitive/Avalonia.targets')" />
<Import Project="$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly/8.3.1.1/buildTransitive/netstandard1.0/HarfBuzzSharp.NativeAssets.WebAssembly.targets" Condition="Exists('$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly/8.3.1.1/buildTransitive/netstandard1.0/HarfBuzzSharp.NativeAssets.WebAssembly.targets')" />
</ImportGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +0,0 @@
{
"version": 2,
"dgSpecHash": "x3mQGRaWoaU=",
"success": true,
"projectFilePath": "/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/Logof Client.csproj",
"expectedPackageFiles": [
"/home/fierke/.nuget/packages/avalonia/11.3.2/avalonia.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.angle.windows.natives/2.1.25547.20250602/avalonia.angle.windows.natives.2.1.25547.20250602.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.buildservices/0.0.31/avalonia.buildservices.0.0.31.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.controls.colorpicker/11.3.2/avalonia.controls.colorpicker.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.controls.datagrid/11.3.2/avalonia.controls.datagrid.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.desktop/11.3.2/avalonia.desktop.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.diagnostics/11.3.2/avalonia.diagnostics.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.fonts.inter/11.3.2/avalonia.fonts.inter.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.freedesktop/11.3.2/avalonia.freedesktop.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.native/11.3.2/avalonia.native.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.remote.protocol/11.3.2/avalonia.remote.protocol.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.skia/11.3.2/avalonia.skia.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.themes.fluent/11.3.2/avalonia.themes.fluent.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.themes.simple/11.3.2/avalonia.themes.simple.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.win32/11.3.2/avalonia.win32.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/avalonia.x11/11.3.2/avalonia.x11.11.3.2.nupkg.sha512",
"/home/fierke/.nuget/packages/harfbuzzsharp/8.3.1.1/harfbuzzsharp.8.3.1.1.nupkg.sha512",
"/home/fierke/.nuget/packages/harfbuzzsharp.nativeassets.linux/8.3.1.1/harfbuzzsharp.nativeassets.linux.8.3.1.1.nupkg.sha512",
"/home/fierke/.nuget/packages/harfbuzzsharp.nativeassets.macos/8.3.1.1/harfbuzzsharp.nativeassets.macos.8.3.1.1.nupkg.sha512",
"/home/fierke/.nuget/packages/harfbuzzsharp.nativeassets.webassembly/8.3.1.1/harfbuzzsharp.nativeassets.webassembly.8.3.1.1.nupkg.sha512",
"/home/fierke/.nuget/packages/harfbuzzsharp.nativeassets.win32/8.3.1.1/harfbuzzsharp.nativeassets.win32.8.3.1.1.nupkg.sha512",
"/home/fierke/.nuget/packages/lucide.avalonia/0.1.35/lucide.avalonia.0.1.35.nupkg.sha512",
"/home/fierke/.nuget/packages/microcom.runtime/0.11.0/microcom.runtime.0.11.0.nupkg.sha512",
"/home/fierke/.nuget/packages/newtonsoft.json/13.0.4/newtonsoft.json.13.0.4.nupkg.sha512",
"/home/fierke/.nuget/packages/skiasharp/2.88.9/skiasharp.2.88.9.nupkg.sha512",
"/home/fierke/.nuget/packages/skiasharp.nativeassets.linux/2.88.9/skiasharp.nativeassets.linux.2.88.9.nupkg.sha512",
"/home/fierke/.nuget/packages/skiasharp.nativeassets.macos/2.88.9/skiasharp.nativeassets.macos.2.88.9.nupkg.sha512",
"/home/fierke/.nuget/packages/skiasharp.nativeassets.webassembly/2.88.9/skiasharp.nativeassets.webassembly.2.88.9.nupkg.sha512",
"/home/fierke/.nuget/packages/skiasharp.nativeassets.win32/2.88.9/skiasharp.nativeassets.win32.2.88.9.nupkg.sha512",
"/home/fierke/.nuget/packages/system.io.pipelines/8.0.0/system.io.pipelines.8.0.0.nupkg.sha512",
"/home/fierke/.nuget/packages/tmds.dbus.protocol/0.21.2/tmds.dbus.protocol.0.21.2.nupkg.sha512"
],
"logs": []
}

View File

@@ -1 +0,0 @@
"restore":{"projectUniqueName":"/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/Logof Client.csproj","projectName":"Logof Client","projectPath":"/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/Logof Client.csproj","outputPath":"/home/fierke/Nextcloud/Documents/source/repos/logofclient/Logof Client/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net9.0"],"sources":{"/usr/lib64/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net9.0":{"targetAlias":"net9.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"direct"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net9.0":{"targetAlias":"net9.0","dependencies":{"Avalonia":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Controls.DataGrid":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Desktop":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Diagnostics":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Fonts.Inter":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Themes.Fluent":{"target":"Package","version":"[11.3.2, )"},"Lucide.Avalonia":{"target":"Package","version":"[0.1.35, )"},"Newtonsoft.Json":{"target":"Package","version":"[13.0.4, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/lib64/dotnet/sdk/9.0.110/PortableRuntimeIdentifierGraph.json"}}

View File

@@ -1 +0,0 @@
17593251314500016

View File

@@ -1 +0,0 @@
17595787829208916