mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-07-19 12:06:16 +02:00
Compare commits
9 Commits
b7f55ff633
...
32f93a670e
| Author | SHA1 | Date | |
|---|---|---|---|
| 32f93a670e | |||
| 752263a4da | |||
| 910b1d9334 | |||
| 81fd5001b7 | |||
| 2efddb3b2c | |||
| 2b20bf97e3 | |||
| dbc16f9f63 | |||
| 3daf49cb52 | |||
| f6ded3fc8c |
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
using DiscordChatExporter.Gui.Views.Controls;
|
||||
using Markdig;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
@@ -19,6 +20,14 @@ public class MarkdownToInlinesConverter : IValueConverter
|
||||
.UseEmphasisExtras()
|
||||
.Build();
|
||||
|
||||
private static string GetPlainText(MarkdownInline inline) =>
|
||||
inline switch
|
||||
{
|
||||
LiteralInline literal => literal.Content.ToString(),
|
||||
ContainerInline container => string.Concat(container.Select(GetPlainText)),
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
private static void ProcessInline(
|
||||
InlineCollection inlines,
|
||||
MarkdownInline markdownInline,
|
||||
@@ -78,6 +87,17 @@ public class MarkdownToInlinesConverter : IValueConverter
|
||||
break;
|
||||
}
|
||||
|
||||
case LinkInline link:
|
||||
{
|
||||
inlines.Add(
|
||||
new InlineUIContainer(
|
||||
new HyperLink { Text = GetPlainText(link), Url = link.Url }
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ContainerInline container:
|
||||
{
|
||||
foreach (var child in container)
|
||||
@@ -96,55 +116,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<ListItemBlock>())
|
||||
{
|
||||
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<ParagraphBlock>())
|
||||
{
|
||||
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<ListItemBlock>())
|
||||
{
|
||||
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<ParagraphBlock>())
|
||||
{
|
||||
if (subBlock is { Inline: not null } p)
|
||||
foreach (var markdownInline in p.Inline)
|
||||
ProcessInline(inlines, markdownInline);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ public partial class LocalizationManager
|
||||
""",
|
||||
// Token instructions (bot)
|
||||
[nameof(TokenBotHeader)] = "To get the token for your bot:",
|
||||
[nameof(TokenBotIntro)] =
|
||||
"The token is generated during bot creation. If you lost it, generate a new one:",
|
||||
[nameof(TokenBotStep1)] = "1. Open Discord",
|
||||
[nameof(TokenBotInstructions)] = """
|
||||
The token is generated during bot creation. If you lost it, generate a new one:
|
||||
|
||||
1. Open Discord [developer portal](https://discord.com/developers/applications)
|
||||
2. Open your application's settings
|
||||
3. Navigate to the **Bot** section on the left
|
||||
4. Under **Token** click **Reset Token**
|
||||
@@ -41,9 +41,8 @@ public partial class LocalizationManager
|
||||
* Integrations using the previous token will stop working until updated
|
||||
* Your bot needs to have the **Message Content Intent** enabled to read messages
|
||||
""",
|
||||
[nameof(TokenDeveloperPortalLinkText)] = "developer portal",
|
||||
[nameof(TokenDocumentationLinkText)] = "documentation",
|
||||
[nameof(TokenHelpText)] = "If you have questions or issues, please refer to the",
|
||||
[nameof(TokenHelpText)] =
|
||||
"If you have questions or issues, please refer to the [documentation](https://github.com/Tyrrrz/DiscordChatExporter/tree/master/.docs)",
|
||||
// Settings
|
||||
[nameof(SettingsTitle)] = "Settings",
|
||||
[nameof(ThemeLabel)] = "Theme",
|
||||
@@ -69,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)",
|
||||
@@ -124,7 +143,7 @@ public partial class LocalizationManager
|
||||
"Update has been downloaded and will be installed when you exit",
|
||||
[nameof(UpdateInstallNowButton)] = "INSTALL NOW",
|
||||
[nameof(UpdateFailedMessage)] = "Failed to perform application update",
|
||||
[nameof(ErrorPullingServersTitle)] = "Error pulling servers",
|
||||
[nameof(ErrorPullingGuildsTitle)] = "Error pulling servers",
|
||||
[nameof(ErrorPullingChannelsTitle)] = "Error pulling channels",
|
||||
[nameof(ErrorExportingTitle)] = "Error exporting channel(s)",
|
||||
[nameof(SuccessfulExportMessage)] = "Successfully exported {0} channel(s)",
|
||||
|
||||
@@ -32,10 +32,10 @@ public partial class LocalizationManager
|
||||
""",
|
||||
// Token instructions (bot)
|
||||
[nameof(TokenBotHeader)] = "Obtenir le token pour votre bot :",
|
||||
[nameof(TokenBotIntro)] =
|
||||
"Le token est généré lors de la création du bot. Si vous l'avez perdu, générez-en un nouveau :",
|
||||
[nameof(TokenBotStep1)] = "1. Ouvrez Discord",
|
||||
[nameof(TokenBotInstructions)] = """
|
||||
Le token est généré lors de la création du bot. Si vous l'avez perdu, générez-en un nouveau :
|
||||
|
||||
1. Ouvrez Discord [portail développeur](https://discord.com/developers/applications)
|
||||
2. Ouvrez les paramètres de votre application
|
||||
3. Naviguez vers la section **Bot** à gauche
|
||||
4. Sous **Token**, cliquez sur **Reset Token**
|
||||
@@ -43,9 +43,8 @@ public partial class LocalizationManager
|
||||
* Les intégrations utilisant l'ancien token cesseront de fonctionner jusqu'à leur mise à jour
|
||||
* Votre bot doit avoir l'option **Message Content Intent** activée pour lire les messages
|
||||
""",
|
||||
[nameof(TokenDeveloperPortalLinkText)] = "portail développeur",
|
||||
[nameof(TokenDocumentationLinkText)] = "documentation",
|
||||
[nameof(TokenHelpText)] = "Pour les questions ou problèmes, veuillez consulter la",
|
||||
[nameof(TokenHelpText)] =
|
||||
"Pour les questions ou problèmes, veuillez consulter la [documentation](https://github.com/Tyrrrz/DiscordChatExporter/tree/master/.docs)",
|
||||
// Settings
|
||||
[nameof(SettingsTitle)] = "Paramètres",
|
||||
[nameof(ThemeLabel)] = "Thème",
|
||||
@@ -71,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)",
|
||||
@@ -126,7 +145,7 @@ public partial class LocalizationManager
|
||||
"La mise à jour a été téléchargée et sera installée à la fermeture",
|
||||
[nameof(UpdateInstallNowButton)] = "INSTALLER MAINTENANT",
|
||||
[nameof(UpdateFailedMessage)] = "Échec de la mise à jour de l'application",
|
||||
[nameof(ErrorPullingServersTitle)] = "Erreur lors du chargement des serveurs",
|
||||
[nameof(ErrorPullingGuildsTitle)] = "Erreur lors du chargement des serveurs",
|
||||
[nameof(ErrorPullingChannelsTitle)] = "Erreur lors du chargement des canaux",
|
||||
[nameof(ErrorExportingTitle)] = "Erreur lors de l'exportation des canaux",
|
||||
[nameof(SuccessfulExportMessage)] = "{0} canal(-aux) exporté(s) avec succès",
|
||||
|
||||
@@ -32,10 +32,10 @@ public partial class LocalizationManager
|
||||
""",
|
||||
// Token instructions (bot)
|
||||
[nameof(TokenBotHeader)] = "Token für Ihren Bot abrufen:",
|
||||
[nameof(TokenBotIntro)] =
|
||||
"Der Token wird bei der Bot-Erstellung generiert. Falls er verloren gegangen ist, generieren Sie einen neuen:",
|
||||
[nameof(TokenBotStep1)] = "1. Öffnen Sie Discord",
|
||||
[nameof(TokenBotInstructions)] = """
|
||||
Der Token wird bei der Bot-Erstellung generiert. Falls er verloren gegangen ist, generieren Sie einen neuen:
|
||||
|
||||
1. Öffnen Sie Discord [Entwicklerportal](https://discord.com/developers/applications)
|
||||
2. Öffnen Sie die Einstellungen Ihrer Anwendung
|
||||
3. Navigieren Sie zum Abschnitt **Bot** auf der linken Seite
|
||||
4. Klicken Sie unter **Token** auf **Reset Token**
|
||||
@@ -43,9 +43,8 @@ public partial class LocalizationManager
|
||||
* Integrationen, die den alten Token verwenden, hören auf zu funktionieren, bis sie aktualisiert werden
|
||||
* Ihr Bot benötigt die aktivierte **Message Content Intent**, um Nachrichten zu lesen
|
||||
""",
|
||||
[nameof(TokenDeveloperPortalLinkText)] = "Entwicklerportal",
|
||||
[nameof(TokenDocumentationLinkText)] = "Dokumentation",
|
||||
[nameof(TokenHelpText)] = "Bei Fragen oder Problemen lesen Sie die",
|
||||
[nameof(TokenHelpText)] =
|
||||
"Bei Fragen oder Problemen lesen Sie die [Dokumentation](https://github.com/Tyrrrz/DiscordChatExporter/tree/master/.docs)",
|
||||
// Settings
|
||||
[nameof(SettingsTitle)] = "Einstellungen",
|
||||
[nameof(ThemeLabel)] = "Design",
|
||||
@@ -71,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)",
|
||||
@@ -130,7 +149,7 @@ public partial class LocalizationManager
|
||||
"Update wurde heruntergeladen und wird beim Beenden installiert",
|
||||
[nameof(UpdateInstallNowButton)] = "JETZT INSTALLIEREN",
|
||||
[nameof(UpdateFailedMessage)] = "Anwendungsupdate konnte nicht durchgeführt werden",
|
||||
[nameof(ErrorPullingServersTitle)] = "Fehler beim Laden der Server",
|
||||
[nameof(ErrorPullingGuildsTitle)] = "Fehler beim Laden der Server",
|
||||
[nameof(ErrorPullingChannelsTitle)] = "Fehler beim Laden der Kanäle",
|
||||
[nameof(ErrorExportingTitle)] = "Fehler beim Exportieren der Kanäle",
|
||||
[nameof(SuccessfulExportMessage)] = "{0} Kanal/-äle erfolgreich exportiert",
|
||||
|
||||
@@ -30,10 +30,10 @@ public partial class LocalizationManager
|
||||
""",
|
||||
// Token instructions (bot)
|
||||
[nameof(TokenBotHeader)] = "Cómo obtener el token para tu bot:",
|
||||
[nameof(TokenBotIntro)] =
|
||||
"El token se genera al crear el bot. Si lo perdiste, genera uno nuevo:",
|
||||
[nameof(TokenBotStep1)] = "1. Abre Discord",
|
||||
[nameof(TokenBotInstructions)] = """
|
||||
El token se genera al crear el bot. Si lo perdiste, genera uno nuevo:
|
||||
|
||||
1. Abre Discord [portal de desarrolladores](https://discord.com/developers/applications)
|
||||
2. Abre la configuración de tu aplicación
|
||||
3. Navega a la sección **Bot** en el lado izquierdo
|
||||
4. En **Token**, haz clic en **Reset Token**
|
||||
@@ -41,9 +41,8 @@ public partial class LocalizationManager
|
||||
* Las integraciones que usen el token anterior dejarán de funcionar hasta que se actualicen
|
||||
* Tu bot necesita tener habilitado **Message Content Intent** para leer mensajes
|
||||
""",
|
||||
[nameof(TokenDeveloperPortalLinkText)] = "portal de desarrolladores",
|
||||
[nameof(TokenDocumentationLinkText)] = "documentación",
|
||||
[nameof(TokenHelpText)] = "Si tienes preguntas o problemas, consulta la",
|
||||
[nameof(TokenHelpText)] =
|
||||
"Si tienes preguntas o problemas, consulta la [documentación](https://github.com/Tyrrrz/DiscordChatExporter/tree/master/.docs)",
|
||||
// Settings
|
||||
[nameof(SettingsTitle)] = "Ajustes",
|
||||
[nameof(ThemeLabel)] = "Tema",
|
||||
@@ -69,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)",
|
||||
@@ -124,7 +143,7 @@ public partial class LocalizationManager
|
||||
"La actualización se ha descargado y se instalará al salir",
|
||||
[nameof(UpdateInstallNowButton)] = "INSTALAR AHORA",
|
||||
[nameof(UpdateFailedMessage)] = "Error al realizar la actualización de la aplicación",
|
||||
[nameof(ErrorPullingServersTitle)] = "Error al cargar servidores",
|
||||
[nameof(ErrorPullingGuildsTitle)] = "Error al cargar servidores",
|
||||
[nameof(ErrorPullingChannelsTitle)] = "Error al cargar canales",
|
||||
[nameof(ErrorExportingTitle)] = "Error al exportar canal(es)",
|
||||
[nameof(SuccessfulExportMessage)] = "{0} canal(es) exportado(s) con éxito",
|
||||
|
||||
@@ -30,10 +30,10 @@ public partial class LocalizationManager
|
||||
""",
|
||||
// Token instructions (bot)
|
||||
[nameof(TokenBotHeader)] = "Як отримати токен для бота:",
|
||||
[nameof(TokenBotIntro)] =
|
||||
"Токен генерується під час створення бота. Якщо ви його втратили, згенеруйте новий:",
|
||||
[nameof(TokenBotStep1)] = "1. Відкрийте Discord",
|
||||
[nameof(TokenBotInstructions)] = """
|
||||
Токен генерується під час створення бота. Якщо ви його втратили, згенеруйте новий:
|
||||
|
||||
1. Відкрийте Discord [портал розробника](https://discord.com/developers/applications)
|
||||
2. Відкрийте налаштування вашого застосунку
|
||||
3. Перейдіть до розділу **Bot** ліворуч
|
||||
4. В розділі **Token** натисніть **Reset Token**
|
||||
@@ -41,9 +41,8 @@ public partial class LocalizationManager
|
||||
* Інтеграції, що використовують попередній токен, перестануть працювати
|
||||
* Ваш бот повинен мати включений **Message Content Intent** для читання повідомлень
|
||||
""",
|
||||
[nameof(TokenDeveloperPortalLinkText)] = "портал розробника",
|
||||
[nameof(TokenDocumentationLinkText)] = "документацію",
|
||||
[nameof(TokenHelpText)] = "Якщо у вас є запитання або проблеми, зверніться до",
|
||||
[nameof(TokenHelpText)] =
|
||||
"Якщо у вас є запитання або проблеми, зверніться до [документації](https://github.com/Tyrrrz/DiscordChatExporter/tree/master/.docs)",
|
||||
// Settings
|
||||
[nameof(SettingsTitle)] = "Налаштування",
|
||||
[nameof(ThemeLabel)] = "Тема",
|
||||
@@ -69,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)] = "Після (дата)",
|
||||
@@ -123,7 +142,7 @@ public partial class LocalizationManager
|
||||
[nameof(UpdateReadyMessage)] = "Оновлення завантажено та буде встановлено після виходу",
|
||||
[nameof(UpdateInstallNowButton)] = "ВСТАНОВИТИ ЗАРАЗ",
|
||||
[nameof(UpdateFailedMessage)] = "Не вдалося виконати оновлення програми",
|
||||
[nameof(ErrorPullingServersTitle)] = "Помилка завантаження серверів",
|
||||
[nameof(ErrorPullingGuildsTitle)] = "Помилка завантаження серверів",
|
||||
[nameof(ErrorPullingChannelsTitle)] = "Помилка завантаження каналів",
|
||||
[nameof(ErrorExportingTitle)] = "Помилка експорту каналу(-ів)",
|
||||
[nameof(SuccessfulExportMessage)] = "Успішно експортовано {0} канал(-ів)",
|
||||
|
||||
@@ -91,11 +91,7 @@ public partial class LocalizationManager
|
||||
|
||||
// Token instructions (bot)
|
||||
public string TokenBotHeader => Get();
|
||||
public string TokenBotIntro => Get();
|
||||
public string TokenBotStep1 => Get();
|
||||
public string TokenBotInstructions => Get();
|
||||
public string TokenDeveloperPortalLinkText => Get();
|
||||
public string TokenDocumentationLinkText => Get();
|
||||
public string TokenHelpText => Get();
|
||||
|
||||
// ---- Settings ----
|
||||
@@ -124,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();
|
||||
@@ -166,7 +163,7 @@ public partial class LocalizationManager
|
||||
public string UpdateReadyMessage => Get();
|
||||
public string UpdateInstallNowButton => Get();
|
||||
public string UpdateFailedMessage => Get();
|
||||
public string ErrorPullingServersTitle => Get();
|
||||
public string ErrorPullingGuildsTitle => Get();
|
||||
public string ErrorPullingChannelsTitle => Get();
|
||||
public string ErrorExportingTitle => Get();
|
||||
public string SuccessfulExportMessage => Get();
|
||||
|
||||
@@ -107,9 +107,6 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
private async Task ShowSettingsAsync() =>
|
||||
await _dialogManager.ShowDialogAsync(_viewModelManager.CreateSettingsViewModel());
|
||||
|
||||
[RelayCommand]
|
||||
private void ShowHelp() => Process.StartShellExecute(Program.ProjectDocumentationUrl);
|
||||
|
||||
private bool CanPullGuilds() => !IsBusy && !string.IsNullOrWhiteSpace(Token);
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanPullGuilds))]
|
||||
@@ -146,7 +143,7 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
catch (Exception ex)
|
||||
{
|
||||
var dialog = _viewModelManager.CreateMessageBoxViewModel(
|
||||
LocalizationManager.ErrorPullingServersTitle,
|
||||
LocalizationManager.ErrorPullingGuildsTitle,
|
||||
ex.ToString()
|
||||
);
|
||||
|
||||
@@ -330,13 +327,6 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenDiscord() => Process.StartShellExecute("https://discord.com/app");
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenDiscordDeveloperPortal() =>
|
||||
Process.StartShellExecute("https://discord.com/developers/applications");
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
|
||||
xmlns:components="clr-namespace:DiscordChatExporter.Gui.ViewModels.Components"
|
||||
xmlns:controls="clr-namespace:DiscordChatExporter.Gui.Views.Controls"
|
||||
xmlns:converters="clr-namespace:DiscordChatExporter.Gui.Converters"
|
||||
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:materialStyles="clr-namespace:Material.Styles.Controls;assembly=Material.Styles"
|
||||
@@ -220,14 +219,6 @@
|
||||
<Panel IsVisible="{Binding !AvailableGuilds.Count}">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Margin="32,16" Spacing="0">
|
||||
<StackPanel.Styles>
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="FontWeight" Value="Light" />
|
||||
<Setter Property="LineHeight" Value="23" />
|
||||
<Setter Property="TextWrapping" Value="Wrap" />
|
||||
</Style>
|
||||
</StackPanel.Styles>
|
||||
|
||||
<!-- User token -->
|
||||
<TextBlock>
|
||||
@@ -246,9 +237,17 @@
|
||||
Text="{Binding LocalizationManager.TokenPersonalHeader}" />
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Inlines="{Binding LocalizationManager.TokenPersonalTosWarning, Converter={x:Static converters:MarkdownToInlinesConverter.Instance}}" />
|
||||
<TextBlock Inlines="{Binding LocalizationManager.TokenPersonalTosWarning, Converter={x:Static converters:MarkdownToInlinesConverter.Instance}}"
|
||||
FontSize="14"
|
||||
FontWeight="Light"
|
||||
LineHeight="23"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock Inlines="{Binding LocalizationManager.TokenPersonalInstructions, Converter={x:Static converters:MarkdownToInlinesConverter.Instance}}" />
|
||||
<TextBlock Inlines="{Binding LocalizationManager.TokenPersonalInstructions, Converter={x:Static converters:MarkdownToInlinesConverter.Instance}}"
|
||||
FontSize="14"
|
||||
FontWeight="Light"
|
||||
LineHeight="23"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<!-- Bot token -->
|
||||
<TextBlock Margin="0,12,0,0">
|
||||
@@ -267,19 +266,18 @@
|
||||
Text="{Binding LocalizationManager.TokenBotHeader}" />
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Text="{Binding LocalizationManager.TokenBotIntro}" />
|
||||
<TextBlock Inlines="{Binding LocalizationManager.TokenBotInstructions, Converter={x:Static converters:MarkdownToInlinesConverter.Instance}}"
|
||||
FontSize="14"
|
||||
FontWeight="Light"
|
||||
LineHeight="23"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock>
|
||||
<Run Text="{Binding LocalizationManager.TokenBotStep1}" />
|
||||
<controls:HyperLink Command="{Binding OpenDiscordDeveloperPortalCommand}" Text="{Binding LocalizationManager.TokenDeveloperPortalLinkText}" />
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Inlines="{Binding LocalizationManager.TokenBotInstructions, Converter={x:Static converters:MarkdownToInlinesConverter.Instance}}" />
|
||||
|
||||
<TextBlock Margin="0,12,0,0">
|
||||
<Run Text="{Binding LocalizationManager.TokenHelpText}" />
|
||||
<controls:HyperLink Command="{Binding ShowHelpCommand}" Text="{Binding LocalizationManager.TokenDocumentationLinkText}" />
|
||||
</TextBlock>
|
||||
<TextBlock Margin="0,12,0,0"
|
||||
FontSize="14"
|
||||
FontWeight="Light"
|
||||
LineHeight="23"
|
||||
TextWrapping="Wrap"
|
||||
Inlines="{Binding LocalizationManager.TokenHelpText, Converter={x:Static converters:MarkdownToInlinesConverter.Instance}}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Panel>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Windows.Input;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Views.Controls;
|
||||
|
||||
@@ -16,6 +18,12 @@ public partial class HyperLink : UserControl
|
||||
public static readonly StyledProperty<object?> CommandParameterProperty =
|
||||
Button.CommandParameterProperty.AddOwner<HyperLink>();
|
||||
|
||||
// If Url is set and Command is not set, clicking will open this URL in the default browser.
|
||||
public static readonly StyledProperty<string?> UrlProperty = AvaloniaProperty.Register<
|
||||
HyperLink,
|
||||
string?
|
||||
>(nameof(Url));
|
||||
|
||||
public HyperLink() => InitializeComponent();
|
||||
|
||||
public string? Text
|
||||
@@ -36,14 +44,22 @@ public partial class HyperLink : UserControl
|
||||
set => SetValue(CommandParameterProperty, value);
|
||||
}
|
||||
|
||||
public string? Url
|
||||
{
|
||||
get => GetValue(UrlProperty);
|
||||
set => SetValue(UrlProperty, value);
|
||||
}
|
||||
|
||||
private void TextBlock_OnPointerReleased(object? sender, PointerReleasedEventArgs args)
|
||||
{
|
||||
if (Command is null)
|
||||
return;
|
||||
|
||||
if (!Command.CanExecute(CommandParameter))
|
||||
return;
|
||||
|
||||
Command.Execute(CommandParameter);
|
||||
if (Command is not null)
|
||||
{
|
||||
if (Command.CanExecute(CommandParameter))
|
||||
Command.Execute(CommandParameter);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(Url))
|
||||
{
|
||||
Process.StartShellExecute(Url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,60 +73,10 @@
|
||||
Text="{Binding OutputPath}"
|
||||
Theme="{DynamicResource FilledTextBox}">
|
||||
<ToolTip.Tip>
|
||||
<TextBlock>
|
||||
<Run Text="Output file or directory path." />
|
||||
<LineBreak />
|
||||
<Run Text="If a directory is specified, file names will be generated automatically based on the channel names and export parameters." />
|
||||
<LineBreak />
|
||||
<Run Text="Directory paths must end with a slash to avoid ambiguity." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Run Text="Available template tokens:" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%g" />
|
||||
<Run Text="— server ID" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%G" />
|
||||
<Run Text="— server name" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%t" />
|
||||
<Run Text="— category ID" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%T" />
|
||||
<Run Text="— category name" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%c" />
|
||||
<Run Text="— channel ID" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%C" />
|
||||
<Run Text="— channel name" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%p" />
|
||||
<Run Text="— channel position" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%P" />
|
||||
<Run Text="— category position" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%a" />
|
||||
<Run Text="— after date" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%b" />
|
||||
<Run Text="— before date" />
|
||||
<LineBreak />
|
||||
<Run Text=" " />
|
||||
<Run FontWeight="SemiBold" Text="%d" />
|
||||
<Run Text="— current date" />
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
MaxWidth="400"
|
||||
TextWrapping="Wrap"
|
||||
Inlines="{Binding LocalizationManager.OutputPathTooltip, Converter={x:Static converters:MarkdownToInlinesConverter.Instance}}" />
|
||||
</ToolTip.Tip>
|
||||
<TextBox.InnerRightContent>
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user