From 2efddb3b2cc4edfbad17223b7304f2597efd65a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:13:16 +0000 Subject: [PATCH] Inline local functions; simplify URL handling; localize OutputPathTooltip Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> --- .../Converters/MarkdownToInlinesConverter.cs | 79 +++++++++---------- .../LocalizationManager.English.cs | 20 +++++ .../LocalizationManager.French.cs | 20 +++++ .../LocalizationManager.German.cs | 20 +++++ .../LocalizationManager.Spanish.cs | 20 +++++ .../LocalizationManager.Ukrainian.cs | 20 +++++ .../Localization/LocalizationManager.cs | 1 + .../Views/Controls/HyperLink.axaml.cs | 11 +-- .../Views/Dialogs/ExportSetupView.axaml | 58 +------------- 9 files changed, 146 insertions(+), 103 deletions(-) diff --git a/DiscordChatExporter.Gui/Converters/MarkdownToInlinesConverter.cs b/DiscordChatExporter.Gui/Converters/MarkdownToInlinesConverter.cs index bac30f31..41142482 100644 --- a/DiscordChatExporter.Gui/Converters/MarkdownToInlinesConverter.cs +++ b/DiscordChatExporter.Gui/Converters/MarkdownToInlinesConverter.cs @@ -114,55 +114,52 @@ public class MarkdownToInlinesConverter : IValueConverter var isFirst = true; - void RenderParagraph(ParagraphBlock paragraph) - { - if (!isFirst) - { - // Insert a blank line between paragraphs - inlines.Add(new LineBreak()); - inlines.Add(new LineBreak()); - } - - isFirst = false; - - foreach (var markdownInline in paragraph.Inline!) - ProcessInline(inlines, markdownInline); - } - - void RenderListBlock(ListBlock list) - { - var itemOrder = 1; - if (list.IsOrdered && int.TryParse(list.OrderedStart, out var startNum)) - itemOrder = startNum; - - foreach (var listItem in list.OfType()) - { - if (!isFirst) - inlines.Add(new LineBreak()); - isFirst = false; - - var prefix = list.IsOrdered ? $"{itemOrder++}. " : $"{list.BulletType} "; - inlines.Add(new Run(prefix)); - - foreach (var subBlock in listItem.OfType()) - { - if (subBlock is { Inline: not null } p) - foreach (var markdownInline in p.Inline) - ProcessInline(inlines, markdownInline); - } - } - } - foreach (var block in Markdown.Parse(text, MarkdownPipeline)) { switch (block) { case ParagraphBlock { Inline: not null } paragraph: - RenderParagraph(paragraph); + { + if (!isFirst) + { + // Insert a blank line between paragraphs + inlines.Add(new LineBreak()); + inlines.Add(new LineBreak()); + } + + isFirst = false; + + foreach (var markdownInline in paragraph.Inline!) + ProcessInline(inlines, markdownInline); + break; + } + case ListBlock list: - RenderListBlock(list); + { + var itemOrder = 1; + if (list.IsOrdered && int.TryParse(list.OrderedStart, out var startNum)) + itemOrder = startNum; + + foreach (var listItem in list.OfType()) + { + if (!isFirst) + inlines.Add(new LineBreak()); + isFirst = false; + + var prefix = list.IsOrdered ? $"{itemOrder++}. " : $"{list.BulletType} "; + inlines.Add(new Run(prefix)); + + foreach (var subBlock in listItem.OfType()) + { + if (subBlock is { Inline: not null } p) + foreach (var markdownInline in p.Inline) + ProcessInline(inlines, markdownInline); + } + } + break; + } } } diff --git a/DiscordChatExporter.Gui/Localization/LocalizationManager.English.cs b/DiscordChatExporter.Gui/Localization/LocalizationManager.English.cs index 274e09f2..d8a2e47b 100644 --- a/DiscordChatExporter.Gui/Localization/LocalizationManager.English.cs +++ b/DiscordChatExporter.Gui/Localization/LocalizationManager.English.cs @@ -68,6 +68,26 @@ public partial class LocalizationManager // Export Setup [nameof(ChannelsSelectedText)] = "channels selected", [nameof(OutputPathLabel)] = "Output path", + [nameof(OutputPathTooltip)] = """ + Output file or directory path. + + If a directory is specified, file names will be generated automatically based on the channel names and export parameters. + + Directory paths must end with a slash to avoid ambiguity. + + Available template tokens: + * **%g** — server ID + * **%G** — server name + * **%t** — category ID + * **%T** — category name + * **%c** — channel ID + * **%C** — channel name + * **%p** — channel position + * **%P** — category position + * **%a** — after date + * **%b** — before date + * **%d** — current date + """, [nameof(FormatLabel)] = "Format", [nameof(FormatTooltip)] = "Export format", [nameof(AfterDateLabel)] = "After (date)", diff --git a/DiscordChatExporter.Gui/Localization/LocalizationManager.French.cs b/DiscordChatExporter.Gui/Localization/LocalizationManager.French.cs index 5537c788..f970dbe3 100644 --- a/DiscordChatExporter.Gui/Localization/LocalizationManager.French.cs +++ b/DiscordChatExporter.Gui/Localization/LocalizationManager.French.cs @@ -70,6 +70,26 @@ public partial class LocalizationManager // Export Setup [nameof(ChannelsSelectedText)] = "canaux sélectionnés", [nameof(OutputPathLabel)] = "Chemin de sortie", + [nameof(OutputPathTooltip)] = """ + Chemin du fichier ou répertoire de sortie. + + Si un répertoire est spécifié, les noms de fichiers seront générés automatiquement en fonction des noms de canaux et des paramètres d'exportation. + + Les chemins de répertoire doivent se terminer par un slash pour éviter toute ambiguïté. + + Jetons de modèle disponibles : + * **%g** — ID du serveur + * **%G** — nom du serveur + * **%t** — ID de la catégorie + * **%T** — nom de la catégorie + * **%c** — ID du canal + * **%C** — nom du canal + * **%p** — position du canal + * **%P** — position de la catégorie + * **%a** — date après + * **%b** — date avant + * **%d** — date actuelle + """, [nameof(FormatLabel)] = "Format", [nameof(FormatTooltip)] = "Format d'exportation", [nameof(AfterDateLabel)] = "Après (date)", diff --git a/DiscordChatExporter.Gui/Localization/LocalizationManager.German.cs b/DiscordChatExporter.Gui/Localization/LocalizationManager.German.cs index 57f8ffa0..63a61142 100644 --- a/DiscordChatExporter.Gui/Localization/LocalizationManager.German.cs +++ b/DiscordChatExporter.Gui/Localization/LocalizationManager.German.cs @@ -70,6 +70,26 @@ public partial class LocalizationManager // Export Setup [nameof(ChannelsSelectedText)] = "Kanäle ausgewählt", [nameof(OutputPathLabel)] = "Ausgabepfad", + [nameof(OutputPathTooltip)] = """ + Ausgabedatei- oder Verzeichnispfad. + + Wenn ein Verzeichnis angegeben wird, werden Dateinamen automatisch basierend auf den Kanalnamen und Exportparametern generiert. + + Verzeichnispfade müssen mit einem Schrägstrich enden, um Mehrdeutigkeiten zu vermeiden. + + Verfügbare Vorlagen-Token: + * **%g** — Server-ID + * **%G** — Servername + * **%t** — Kategorie-ID + * **%T** — Kategoriename + * **%c** — Kanal-ID + * **%C** — Kanalname + * **%p** — Kanalposition + * **%P** — Kategorieposition + * **%a** — Datum ab + * **%b** — Datum bis + * **%d** — aktuelles Datum + """, [nameof(FormatLabel)] = "Format", [nameof(FormatTooltip)] = "Exportformat", [nameof(AfterDateLabel)] = "Nach (Datum)", diff --git a/DiscordChatExporter.Gui/Localization/LocalizationManager.Spanish.cs b/DiscordChatExporter.Gui/Localization/LocalizationManager.Spanish.cs index a953ea84..e993ca3e 100644 --- a/DiscordChatExporter.Gui/Localization/LocalizationManager.Spanish.cs +++ b/DiscordChatExporter.Gui/Localization/LocalizationManager.Spanish.cs @@ -68,6 +68,26 @@ public partial class LocalizationManager // Export Setup [nameof(ChannelsSelectedText)] = "canales seleccionados", [nameof(OutputPathLabel)] = "Ruta de salida", + [nameof(OutputPathTooltip)] = """ + Ruta del archivo o directorio de salida. + + Si se especifica un directorio, los nombres de archivo se generarán automáticamente según los nombres de los canales y los parámetros de exportación. + + Las rutas de directorio deben terminar con una barra diagonal para evitar ambigüedades. + + Tokens de plantilla disponibles: + * **%g** — ID del servidor + * **%G** — nombre del servidor + * **%t** — ID de categoría + * **%T** — nombre de categoría + * **%c** — ID del canal + * **%C** — nombre del canal + * **%p** — posición del canal + * **%P** — posición de la categoría + * **%a** — fecha desde + * **%b** — fecha hasta + * **%d** — fecha actual + """, [nameof(FormatLabel)] = "Formato", [nameof(FormatTooltip)] = "Formato de exportación", [nameof(AfterDateLabel)] = "Después (fecha)", diff --git a/DiscordChatExporter.Gui/Localization/LocalizationManager.Ukrainian.cs b/DiscordChatExporter.Gui/Localization/LocalizationManager.Ukrainian.cs index e6fd8371..2f9cfbd8 100644 --- a/DiscordChatExporter.Gui/Localization/LocalizationManager.Ukrainian.cs +++ b/DiscordChatExporter.Gui/Localization/LocalizationManager.Ukrainian.cs @@ -68,6 +68,26 @@ public partial class LocalizationManager // Export Setup [nameof(ChannelsSelectedText)] = "каналів вибрано", [nameof(OutputPathLabel)] = "Шлях збереження", + [nameof(OutputPathTooltip)] = """ + Шлях до файлу або директорії виводу. + + Якщо вказано директорію, імена файлів генеруватимуться автоматично на основі назв каналів та параметрів експорту. + + Шляхи до директорій повинні закінчуватись слешем для уникнення неоднозначності. + + Доступні шаблонні токени: + * **%g** — ID сервера + * **%G** — назва сервера + * **%t** — ID категорії + * **%T** — назва категорії + * **%c** — ID каналу + * **%C** — назва каналу + * **%p** — позиція каналу + * **%P** — позиція категорії + * **%a** — дата після + * **%b** — дата до + * **%d** — поточна дата + """, [nameof(FormatLabel)] = "Формат", [nameof(FormatTooltip)] = "Формат експорту", [nameof(AfterDateLabel)] = "Після (дата)", diff --git a/DiscordChatExporter.Gui/Localization/LocalizationManager.cs b/DiscordChatExporter.Gui/Localization/LocalizationManager.cs index 5084f889..2181fbf3 100644 --- a/DiscordChatExporter.Gui/Localization/LocalizationManager.cs +++ b/DiscordChatExporter.Gui/Localization/LocalizationManager.cs @@ -120,6 +120,7 @@ public partial class LocalizationManager public string ChannelsSelectedText => Get(); public string OutputPathLabel => Get(); + public string OutputPathTooltip => Get(); public string FormatLabel => Get(); public string FormatTooltip => Get(); public string AfterDateLabel => Get(); diff --git a/DiscordChatExporter.Gui/Views/Controls/HyperLink.axaml.cs b/DiscordChatExporter.Gui/Views/Controls/HyperLink.axaml.cs index 31bd84b8..f0482133 100644 --- a/DiscordChatExporter.Gui/Views/Controls/HyperLink.axaml.cs +++ b/DiscordChatExporter.Gui/Views/Controls/HyperLink.axaml.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using System.Windows.Input; using Avalonia; using Avalonia.Controls; @@ -58,11 +57,7 @@ public partial class HyperLink : UserControl if (Command.CanExecute(CommandParameter)) Command.Execute(CommandParameter); } - else if ( - !string.IsNullOrWhiteSpace(Url) && Uri.TryCreate(Url, UriKind.Absolute, out var uri) - ) - { - Process.StartShellExecute(uri.AbsoluteUri); - } + else if (!string.IsNullOrWhiteSpace(Url)) + Process.StartShellExecute(Url); } } diff --git a/DiscordChatExporter.Gui/Views/Dialogs/ExportSetupView.axaml b/DiscordChatExporter.Gui/Views/Dialogs/ExportSetupView.axaml index 3d8a5e28..ea0acc72 100644 --- a/DiscordChatExporter.Gui/Views/Dialogs/ExportSetupView.axaml +++ b/DiscordChatExporter.Gui/Views/Dialogs/ExportSetupView.axaml @@ -73,60 +73,10 @@ Text="{Binding OutputPath}" Theme="{DynamicResource FilledTextBox}"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +