From 16ed64dbf42cfa4632d91d4b9fc58406d7a0bf98 Mon Sep 17 00:00:00 2001 From: Elias Fierke Date: Thu, 16 Apr 2026 11:44:10 +0200 Subject: [PATCH 01/15] [chore:] there was a space missing that triggered my monk --- MainWindow.axaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MainWindow.axaml.cs b/MainWindow.axaml.cs index 0f586e1..3abffb3 100644 --- a/MainWindow.axaml.cs +++ b/MainWindow.axaml.cs @@ -593,7 +593,7 @@ public partial class MainWindow : Window foreach (var k in Settings._instance.addressSets.addresses) foreach (var customer in Settings._instance.customers.customers) if (customer.ID == k.owner_id && customer.ID == customer_id) - LstCustomerAdressSets.Items.Add(k.ID + " - " + k.Name + "(" + k.KasPersons.Count + " Einträge)"); + LstCustomerAdressSets.Items.Add(k.ID + " - " + k.Name + " (" + k.KasPersons.Count + " Einträge)"); } private void LstCustomerAdressSets_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) From ac7b23cc2840145f52f4393caaff3a2c6688afe7 Mon Sep 17 00:00:00 2001 From: Elias Fierke Date: Thu, 16 Apr 2026 12:49:10 +0200 Subject: [PATCH 02/15] [fix:] temporarily fixed application crash if no customer is seleceted when starting --- MainWindow.axaml.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/MainWindow.axaml.cs b/MainWindow.axaml.cs index 3abffb3..d927c40 100644 --- a/MainWindow.axaml.cs +++ b/MainWindow.axaml.cs @@ -685,8 +685,15 @@ public partial class MainWindow : Window 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"); + try + { + StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "union"); + } + catch + { + + } + } private void BtnCombineIntersection_OnClick(object? sender, RoutedEventArgs e) From 5ccd4a4e99a24e1299d7eb31fb7683d6319f3da8 Mon Sep 17 00:00:00 2001 From: Elias Fierke Date: Thu, 16 Apr 2026 12:49:45 +0200 Subject: [PATCH 03/15] [fix:] csv-import now recognizes quotation marks --- Tasks/CsvBuilder.cs | 66 ++++++++++++++++++++++++++------------------- Tasks/DataImport.cs | 46 ++++++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/Tasks/CsvBuilder.cs b/Tasks/CsvBuilder.cs index 6365ada..255f190 100644 --- a/Tasks/CsvBuilder.cs +++ b/Tasks/CsvBuilder.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Text; namespace Logof_Client; @@ -30,34 +31,45 @@ public class CsvBuilder result.AppendLine(Header); foreach (var l in KasAddressList.KasPersons) - - result.AppendLine( - l.refsid + Separator + - l.anrede + Separator + - l.titel + Separator + - l.vorname + Separator + - l.adel + Separator + - l.name + Separator + - l.namezus + Separator + - l.anredzus + Separator + - l.strasse + Separator + - l.strasse2 + Separator + - l.plz + Separator + - l.ort + Separator + - l.land + Separator + - l.pplz + Separator + - l.postfach + Separator + - l.name1 + Separator + - l.name2 + Separator + - l.name3 + Separator + - l.name4 + Separator + - l.name5 + Separator + - l.funktion + Separator + - l.funktion2 + Separator + - l.abteilung + Separator + - l.funktionad); + result.AppendLine(string.Join(Separator, new[] + { + EscapeCsvField(l.refsid.ToString()), + EscapeCsvField(l.anrede), + EscapeCsvField(l.titel), + EscapeCsvField(l.vorname), + EscapeCsvField(l.adel), + EscapeCsvField(l.name), + EscapeCsvField(l.namezus), + EscapeCsvField(l.anredzus), + EscapeCsvField(l.strasse), + EscapeCsvField(l.strasse2), + EscapeCsvField(l.plz), + EscapeCsvField(l.ort), + EscapeCsvField(l.land), + EscapeCsvField(l.pplz), + EscapeCsvField(l.postfach), + EscapeCsvField(l.name1), + EscapeCsvField(l.name2), + EscapeCsvField(l.name3), + EscapeCsvField(l.name4), + EscapeCsvField(l.name5), + EscapeCsvField(l.funktion), + EscapeCsvField(l.funktion2), + EscapeCsvField(l.abteilung), + EscapeCsvField(l.funktionad) + })); // weitere Cases return result.ToString(); } -} \ No newline at end of file + + private string EscapeCsvField(string? value) + { + var field = value ?? string.Empty; + var mustQuote = field.Contains(Separator) || field.Contains('"') || field.Contains('\r') || field.Contains('\n'); + if (!mustQuote) + return field; + + return "\"" + field.Replace("\"", "\"\"") + "\""; + } +} diff --git a/Tasks/DataImport.cs b/Tasks/DataImport.cs index e8f6464..d7e5940 100644 --- a/Tasks/DataImport.cs +++ b/Tasks/DataImport.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Text; namespace Logof_Client; @@ -41,7 +42,7 @@ public class DataImport if (string.IsNullOrWhiteSpace(line)) continue; - var parts = line.Split(separator).Select(p => p.Trim()).ToArray(); + var parts = ParseCsvLine(line, separator); if (parts.Length < 24) { @@ -107,7 +108,7 @@ public class DataImport return (false, null); } - var headers = headerLine.Split(separator).Select(h => h.Trim()).ToArray(); + var headers = ParseCsvLine(headerLine, separator); var imported = new KasAddressList(KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath))); @@ -126,7 +127,7 @@ public class DataImport if (string.IsNullOrWhiteSpace(line)) continue; - var parts = line.Split(separator).Select(p => p.Trim()).ToArray(); + var parts = ParseCsvLine(line, separator); var fieldValues = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -241,4 +242,41 @@ public class DataImport { return int.TryParse(input, out var result) ? result : 0; } -} \ No newline at end of file + + private static string[] ParseCsvLine(string line, char separator) + { + var fields = new List(); + var current = new StringBuilder(); + var inQuotes = false; + + for (var i = 0; i < line.Length; i++) + { + var c = line[i]; + + if (c == '"') + { + if (inQuotes && i + 1 < line.Length && line[i + 1] == '"') + { + current.Append('"'); + i++; + continue; + } + + inQuotes = !inQuotes; + continue; + } + + if (c == separator && !inQuotes) + { + fields.Add(current.ToString().Trim()); + current.Clear(); + continue; + } + + current.Append(c); + } + + fields.Add(current.ToString().Trim()); + return fields.ToArray(); + } +} From 9ad378c800ecba549ed518830f5df85d8c4dac15 Mon Sep 17 00:00:00 2001 From: Elias Fierke Date: Thu, 16 Apr 2026 13:29:59 +0200 Subject: [PATCH 04/15] [fix:] temporarily fiex application crash if no customer is selected when start combining (more than union, which was fixed before) --- MainWindow.axaml.cs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/MainWindow.axaml.cs b/MainWindow.axaml.cs index d927c40..31d9dbb 100644 --- a/MainWindow.axaml.cs +++ b/MainWindow.axaml.cs @@ -675,8 +675,14 @@ public partial class MainWindow : Window 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"); + try + { + StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "difference"); + } + catch + { + + } } private void BtnCombineUnion_OnClick(object? sender, RoutedEventArgs e) @@ -702,8 +708,14 @@ public partial class MainWindow : Window 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"); + try + { + StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "intersection"); + } + catch + { + + } } private void BtnCombineSymmetricDifference_OnClick(object? sender, RoutedEventArgs e) From 9777c6b5a27d3ebf4dd218d86e442817e9c4ce5c Mon Sep 17 00:00:00 2001 From: Elias Fierke Date: Wed, 22 Apr 2026 08:09:28 +0200 Subject: [PATCH 05/15] [fix:] naming window showed nothing --- DataStore/DataStructures.cs | 12 ++++++--- MainWindow.axaml.cs | 10 +++---- NamingWindow.axaml.cs | 9 +++---- Tasks/CombineAddresses.cs | 53 ++++++++++--------------------------- Tasks/DataImport.cs | 19 ++++++------- 5 files changed, 41 insertions(+), 62 deletions(-) diff --git a/DataStore/DataStructures.cs b/DataStore/DataStructures.cs index 6c81528..b082d93 100644 --- a/DataStore/DataStructures.cs +++ b/DataStore/DataStructures.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace Logof_Client; @@ -32,11 +33,16 @@ public class KasAddressList //Address-Set this.owner_id = owner_id; } - public static string GenerateName(string basic_type, bool? is_rest = false) + public static async Task GenerateName(string basic_type, bool? is_rest = false) { + string pre = ""; + if (is_rest == true) return basic_type + " - " + DateTime.Now.ToShortDateString() + " - Rest"; - return basic_type + " - " + DateTime.Now.ToShortDateString(); + pre = basic_type + " - " + DateTime.Now.ToShortDateString(); + + var result = await NamingWindow.Show(MainWindow._instance, pre); + return string.IsNullOrWhiteSpace(result) ? pre : result; } // public void UpdateErrorList(List errorList) @@ -206,4 +212,4 @@ public class KasPersonError return output; } -} \ No newline at end of file +} diff --git a/MainWindow.axaml.cs b/MainWindow.axaml.cs index 31d9dbb..1d826de 100644 --- a/MainWindow.axaml.cs +++ b/MainWindow.axaml.cs @@ -194,7 +194,7 @@ public partial class MainWindow : Window private async void StartCombine(Uri path) { MakeCalcManVisible(); - var addresses = DataImport.ImportKasAddressList(path); + var addresses = await DataImport.ImportKasAddressList(path); var progressWindow = new ProgressWindow(); var address_list = new List { addresses.Item2 }; @@ -216,7 +216,7 @@ public partial class MainWindow : Window if (file == null) return; //filePath = file[0].Path; - foreach (var f in file) address_list.Add(DataImport.ImportKasAddressList(f.Path).Item2); + foreach (var f in file) address_list.Add((await DataImport.ImportKasAddressList(f.Path)).Item2); progressWindow.Show(_instance); @@ -542,7 +542,7 @@ public partial class MainWindow : Window { if (customer.patch == null) { - var got = DataImport.ImportKasAddressList(selected_path, null, customer.separator); + var got = await DataImport.ImportKasAddressList(selected_path, null, customer.separator); if (!got.Item1) { Console.WriteLine("Error while importing. Please try another file."); @@ -558,7 +558,7 @@ public partial class MainWindow : Window } else { - var got = DataImport.ImportKasAddressList(selected_path, customer.patch, customer.separator); + var got = await DataImport.ImportKasAddressList(selected_path, customer.patch, customer.separator); if (!got.Item1) { Console.WriteLine("Error while importing. Please try another file."); @@ -933,4 +933,4 @@ public partial class MainWindow : Window MessageBox.Show(this, ex.StackTrace, "Fehler"); } } -} \ No newline at end of file +} diff --git a/NamingWindow.axaml.cs b/NamingWindow.axaml.cs index 12c7bc0..3cf6f34 100644 --- a/NamingWindow.axaml.cs +++ b/NamingWindow.axaml.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using Avalonia.Controls; -using Avalonia.Markup.Xaml; namespace Logof_Client; @@ -9,9 +8,7 @@ public partial class NamingWindow : Window { public NamingWindow() { - AvaloniaXamlLoader.Load(this); - - //InitializeComponent(); + InitializeComponent(); } public static Task Show(Window parent, string input = "", string info = "Bitte geben Sie einen Namen ein:") @@ -54,7 +51,7 @@ public partial class NamingWindow : Window catch (Exception ex) { Console.WriteLine("Error while showing naming window: " + ex.Message); - return null; + return Task.FromResult(null!); } } -} \ No newline at end of file +} diff --git a/Tasks/CombineAddresses.cs b/Tasks/CombineAddresses.cs index 140a6f7..e20a194 100644 --- a/Tasks/CombineAddresses.cs +++ b/Tasks/CombineAddresses.cs @@ -19,36 +19,11 @@ public class CombineAddresses public async Task<(KasAddressList, KasAddressList)> Perform(List address_lists, string type, bool? exportUnused) { - var res = await Task.Run(async () => - { - if (type == "difference") return Difference(address_lists, exportUnused); - if (type == "union") return Union(address_lists, exportUnused); - if (type == "intersection") return Intersection(address_lists, exportUnused); - if (type == "symdiff") return SymmetricDifference(address_lists, exportUnused); + if (type == "difference") return await Difference(address_lists, exportUnused); + if (type == "union") return await Union(address_lists, exportUnused); + if (type == "intersection") return await Intersection(address_lists, exportUnused); + if (type == "symdiff") return await 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); } @@ -97,7 +72,7 @@ public class CombineAddresses Progress? progress = null) { if (address_lists == null || address_lists.Count == 0) - return (new KasAddressList(KasAddressList.GenerateName("difference")), null); + return (new KasAddressList(await KasAddressList.GenerateName("difference")), null); progress ??= new Progress { @@ -109,8 +84,8 @@ public class CombineAddresses var restUnion = new List(); 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")); + var result = new KasAddressList(await KasAddressList.GenerateName("difference")); + var second_result = new KasAddressList(await KasAddressList.GenerateName("difference_rest", false)); foreach (var person in address_lists[0].KasPersons) { @@ -136,8 +111,8 @@ public class CombineAddresses public async Task<(KasAddressList, KasAddressList)> Union(List address_lists, bool? return_unused, Progress progress = null) { - var result = new KasAddressList(KasAddressList.GenerateName("union")); - var second_result = new KasAddressList(KasAddressList.GenerateName("union_rest")); + var result = new KasAddressList(await KasAddressList.GenerateName("union")); + var second_result = new KasAddressList(await KasAddressList.GenerateName("union_rest", false)); if (address_lists == null || address_lists.Count == 0) return (result, null); @@ -178,8 +153,8 @@ public class CombineAddresses public async Task<(KasAddressList, KasAddressList)> Intersection(List address_lists, bool? return_unused, Progress progress = null) { - var result = new KasAddressList(KasAddressList.GenerateName("intersection")); - var second_result = new KasAddressList(KasAddressList.GenerateName("intersection_rest")); + var result = new KasAddressList(await KasAddressList.GenerateName("intersection")); + var second_result = new KasAddressList(await KasAddressList.GenerateName("intersection_rest", false)); if (address_lists == null || address_lists.Count == 0) return (result, null); @@ -225,8 +200,8 @@ public class CombineAddresses public async Task<(KasAddressList, KasAddressList)> SymmetricDifference(List 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")); + var result = new KasAddressList(await KasAddressList.GenerateName("symmetric_difference")); + var second_result = new KasAddressList(await KasAddressList.GenerateName("symmetric_rest", false)); if (address_lists == null || address_lists.Count == 0) return (result, null); @@ -354,4 +329,4 @@ public class Progress var comparedPersons = ComparedPersons; Interlocked.Increment(ref comparedPersons); } -} \ No newline at end of file +} diff --git a/Tasks/DataImport.cs b/Tasks/DataImport.cs index d7e5940..d2961f6 100644 --- a/Tasks/DataImport.cs +++ b/Tasks/DataImport.cs @@ -4,20 +4,21 @@ using System.IO; using System.Linq; using System.Reflection; using System.Text; +using System.Threading.Tasks; namespace Logof_Client; public class DataImport { - public static (bool, KasAddressList) ImportKasAddressList(Uri pathToCsv, AddressPatch patch = null, + public static async Task<(bool, KasAddressList)> ImportKasAddressList(Uri pathToCsv, AddressPatch patch = null, char separator = ',') { if (patch == null) - return ImportKasAddressListWithoutPatch(pathToCsv, separator); - return ImportKasAddressListWithPatch(pathToCsv, patch, separator); + return await ImportKasAddressListWithoutPatch(pathToCsv, separator); + return await ImportKasAddressListWithPatch(pathToCsv, patch, separator); } - private static (bool, KasAddressList) ImportKasAddressListWithoutPatch(Uri pathToCsv, char separator) + private static async Task<(bool, KasAddressList)> ImportKasAddressListWithoutPatch(Uri pathToCsv, char separator) { if (!File.Exists(pathToCsv.LocalPath)) { @@ -33,8 +34,8 @@ public class DataImport return (false, null); } - var imported = - new KasAddressList(KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath))); + var imported = new KasAddressList( + await KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath))); while (!reader.EndOfStream) { @@ -91,7 +92,7 @@ public class DataImport return (true, imported); } - private static (bool, KasAddressList) ImportKasAddressListWithPatch(Uri pathToCsv, AddressPatch patch, + private static async Task<(bool, KasAddressList)> ImportKasAddressListWithPatch(Uri pathToCsv, AddressPatch patch, char separator) { if (!File.Exists(pathToCsv.LocalPath)) @@ -110,8 +111,8 @@ public class DataImport var headers = ParseCsvLine(headerLine, separator); - var imported = - new KasAddressList(KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath))); + var imported = new KasAddressList( + await KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath))); var patchType = typeof(AddressPatch); var binding = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; From 43e6c35beb2296fc4154ed06c9756b131c8dda67 Mon Sep 17 00:00:00 2001 From: Elias Fierke Date: Thu, 23 Apr 2026 09:02:45 +0200 Subject: [PATCH 06/15] [gui:] export margin options gui --- MainWindow.axaml | 123 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 33 deletions(-) diff --git a/MainWindow.axaml b/MainWindow.axaml index 10bf928..7dae503 100644 --- a/MainWindow.axaml +++ b/MainWindow.axaml @@ -28,7 +28,7 @@