diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 8befe4e0..fc4e5346 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -99,7 +99,7 @@ jobs:
# GUI assets aren't suffixed, unlike the CLI assets
asset: DiscordChatExporter
- runs-on: ubuntu-latest
+ runs-on: ${{ startsWith(matrix.rid, 'win-') && 'windows-latest' || startsWith(matrix.rid, 'osx-') && 'macos-latest' || 'ubuntu-latest' }}
timeout-minutes: 10
permissions:
diff --git a/DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj b/DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj
index 3b19906b..facdde20 100644
--- a/DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj
+++ b/DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj
@@ -3,6 +3,8 @@
Exe
..\favicon.ico
+ true
+ $(NoWarn);IL2104
diff --git a/DiscordChatExporter.Cli/Program.cs b/DiscordChatExporter.Cli/Program.cs
index d0d8ba9b..f849e6d1 100644
--- a/DiscordChatExporter.Cli/Program.cs
+++ b/DiscordChatExporter.Cli/Program.cs
@@ -1,3 +1,37 @@
-using CliFx;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using CliFx;
+using DiscordChatExporter.Cli.Commands;
+using DiscordChatExporter.Cli.Commands.Converters;
-return await new CliApplicationBuilder().AddCommandsFromThisAssembly().Build().RunAsync(args);
+namespace DiscordChatExporter.Cli;
+
+public static class Program
+{
+ // Explicit references because CliFx relies on reflection and we're publishing with trimming enabled
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportAllCommand))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportChannelsCommand))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportDirectMessagesCommand))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportGuildCommand))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetChannelsCommand))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetDirectChannelsCommand))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetGuildsCommand))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GuideCommand))]
+ [DynamicDependency(
+ DynamicallyAccessedMemberTypes.All,
+ typeof(ThreadInclusionModeBindingConverter)
+ )]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(TruthyBooleanBindingConverter))]
+ public static async Task Main(string[] args) =>
+ await new CliApplicationBuilder()
+ .AddCommand()
+ .AddCommand()
+ .AddCommand()
+ .AddCommand()
+ .AddCommand()
+ .AddCommand()
+ .AddCommand()
+ .AddCommand()
+ .Build()
+ .RunAsync(args);
+}
diff --git a/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj b/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj
index 5158a3b8..00321377 100644
--- a/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj
+++ b/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj
@@ -4,6 +4,18 @@
WinExe
DiscordChatExporter
..\favicon.ico
+ true
+ true
+ $(NoWarn);IL2104
+
+
+
+
+ true
+
+ $(NoWarn);IL2026
+
+ $(NoWarn);IL2035
diff --git a/DiscordChatExporter.Gui/Framework/ViewManager.cs b/DiscordChatExporter.Gui/Framework/ViewManager.cs
index f335e449..a9dc2aa3 100644
--- a/DiscordChatExporter.Gui/Framework/ViewManager.cs
+++ b/DiscordChatExporter.Gui/Framework/ViewManager.cs
@@ -1,25 +1,31 @@
-using System;
-using Avalonia.Controls;
+using Avalonia.Controls;
using Avalonia.Controls.Templates;
+using DiscordChatExporter.Gui.ViewModels;
+using DiscordChatExporter.Gui.ViewModels.Components;
+using DiscordChatExporter.Gui.ViewModels.Dialogs;
+using DiscordChatExporter.Gui.Views;
+using DiscordChatExporter.Gui.Views.Components;
+using DiscordChatExporter.Gui.Views.Dialogs;
namespace DiscordChatExporter.Gui.Framework;
public partial class ViewManager
{
+ private Control? TryCreateView(ViewModelBase viewModel) =>
+ viewModel switch
+ {
+ MainViewModel => new MainView(),
+ DashboardViewModel => new DashboardView(),
+ ExportSetupViewModel => new ExportSetupView(),
+ MessageBoxViewModel => new MessageBoxView(),
+ SettingsViewModel => new SettingsView(),
+ _ => null
+ };
+
public Control? TryBindView(ViewModelBase viewModel)
{
- var name = viewModel
- .GetType()
- .FullName?.Replace("ViewModel", "View", StringComparison.Ordinal);
-
- if (string.IsNullOrWhiteSpace(name))
- return null;
-
- var type = Type.GetType(name);
- if (type is null)
- return null;
-
- if (Activator.CreateInstance(type) is not Control view)
+ var view = TryCreateView(viewModel);
+ if (view is null)
return null;
view.DataContext ??= viewModel;
diff --git a/DiscordChatExporter.Gui/Views/Components/DashboardView.axaml b/DiscordChatExporter.Gui/Views/Components/DashboardView.axaml
index 02b1b515..44e537c0 100644
--- a/DiscordChatExporter.Gui/Views/Components/DashboardView.axaml
+++ b/DiscordChatExporter.Gui/Views/Components/DashboardView.axaml
@@ -9,11 +9,8 @@
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:materialStyles="clr-namespace:Material.Styles.Controls;assembly=Material.Styles"
x:Name="UserControl"
+ x:DataType="components:DashboardViewModel"
Loaded="UserControl_OnLoaded">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -339,6 +216,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+