mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-04-02 11:49:02 +00:00
Automate view initialization
This commit is contained in:
@@ -12,7 +12,6 @@ using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using DiscordChatExporter.Gui.ViewModels;
|
||||
using DiscordChatExporter.Gui.ViewModels.Components;
|
||||
using DiscordChatExporter.Gui.ViewModels.Dialogs;
|
||||
using DiscordChatExporter.Gui.Views;
|
||||
using Material.Styles.Themes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
@@ -20,11 +19,8 @@ namespace DiscordChatExporter.Gui;
|
||||
|
||||
public class App : Application, IDisposable
|
||||
{
|
||||
private readonly DisposableCollector _eventRoot = new();
|
||||
|
||||
private readonly ServiceProvider _services;
|
||||
private readonly SettingsService _settingsService;
|
||||
private readonly MainViewModel _mainViewModel;
|
||||
private readonly DisposableCollector _eventRoot = new();
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
@@ -53,35 +49,30 @@ public class App : Application, IDisposable
|
||||
services.AddTransient<SettingsViewModel>();
|
||||
|
||||
_services = services.BuildServiceProvider(true);
|
||||
_settingsService = _services.GetRequiredService<SettingsService>();
|
||||
_mainViewModel = _services.GetRequiredService<ViewModelManager>().CreateMainViewModel();
|
||||
|
||||
// Re-initialize the theme when the user changes it
|
||||
_eventRoot.Add(
|
||||
_settingsService.WatchProperty(
|
||||
o => o.Theme,
|
||||
() =>
|
||||
{
|
||||
RequestedThemeVariant = _settingsService.Theme switch
|
||||
_services
|
||||
.GetRequiredService<SettingsService>()
|
||||
.WatchProperty(
|
||||
o => o.Theme,
|
||||
() =>
|
||||
{
|
||||
ThemeVariant.Light => Avalonia.Styling.ThemeVariant.Light,
|
||||
ThemeVariant.Dark => Avalonia.Styling.ThemeVariant.Dark,
|
||||
_ => Avalonia.Styling.ThemeVariant.Default,
|
||||
};
|
||||
RequestedThemeVariant = _services
|
||||
.GetRequiredService<SettingsService>()
|
||||
.Theme switch
|
||||
{
|
||||
ThemeVariant.Light => Avalonia.Styling.ThemeVariant.Light,
|
||||
ThemeVariant.Dark => Avalonia.Styling.ThemeVariant.Dark,
|
||||
_ => Avalonia.Styling.ThemeVariant.Default,
|
||||
};
|
||||
|
||||
InitializeTheme();
|
||||
}
|
||||
)
|
||||
InitializeTheme();
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void InitializeTheme()
|
||||
{
|
||||
var actualTheme = RequestedThemeVariant?.Key switch
|
||||
@@ -97,25 +88,28 @@ public class App : Application, IDisposable
|
||||
: Theme.Create(Theme.Dark, Color.Parse("#E8E8E8"), Color.Parse("#F9A825"));
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow = new MainView { DataContext = _mainViewModel };
|
||||
|
||||
void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs args)
|
||||
{
|
||||
if (sender is IControlledApplicationLifetime lifetime)
|
||||
lifetime.Exit -= OnExit;
|
||||
|
||||
Dispose();
|
||||
}
|
||||
desktop.MainWindow = _services
|
||||
.GetRequiredService<ViewManager>()
|
||||
.TryBindWindow(
|
||||
_services.GetRequiredService<ViewModelManager>().CreateMainViewModel()
|
||||
);
|
||||
|
||||
// Although `App.Dispose()` is invoked from `Program.Main(...)`, on some platforms
|
||||
// it may be called too late in the shutdown lifecycle. Attach an exit
|
||||
// handler to ensure timely disposal as a safeguard.
|
||||
// https://github.com/Tyrrrz/YoutubeDownloader/issues/795
|
||||
desktop.Exit += OnExit;
|
||||
desktop.Exit += (_, _) => Dispose();
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
@@ -124,7 +118,7 @@ public class App : Application, IDisposable
|
||||
InitializeTheme();
|
||||
|
||||
// Load settings
|
||||
_settingsService.Load();
|
||||
_services.GetRequiredService<SettingsService>().Load();
|
||||
}
|
||||
|
||||
private void Application_OnActualThemeVariantChanged(object? sender, EventArgs args) =>
|
||||
|
||||
@@ -30,8 +30,23 @@ public partial class ViewManager
|
||||
|
||||
view.DataContext ??= viewModel;
|
||||
|
||||
if (view.IsInitialized)
|
||||
{
|
||||
_ = viewModel.InitializeAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
view.Initialized += async (_, _) => await viewModel.InitializeAsync();
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
public UserControl<T>? TryBindUserControl<T>(T viewModel)
|
||||
where T : ViewModelBase => TryBindView(viewModel) as UserControl<T>;
|
||||
|
||||
public Window<T>? TryBindWindow<T>(T viewModel)
|
||||
where T : ViewModelBase => TryBindView(viewModel) as Window<T>;
|
||||
}
|
||||
|
||||
public partial class ViewManager : IDataTemplate
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Framework;
|
||||
@@ -9,6 +10,8 @@ public abstract class ViewModelBase : ObservableObject, IDisposable
|
||||
|
||||
protected void OnAllPropertiesChanged() => OnPropertyChanged(string.Empty);
|
||||
|
||||
public virtual Task InitializeAsync() => Task.CompletedTask;
|
||||
|
||||
protected virtual void Dispose(bool disposing) { }
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -96,11 +95,12 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
|
||||
public ObservableCollection<ChannelConnection> SelectedChannels { get; } = [];
|
||||
|
||||
[RelayCommand]
|
||||
private void Initialize()
|
||||
public override Task InitializeAsync()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_settingsService.LastToken))
|
||||
Token = _settingsService.LastToken;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
||||
@@ -102,8 +102,7 @@ public partial class ExportSetupViewModel(
|
||||
? MessageFilter.Parse(MessageFilterValue)
|
||||
: MessageFilter.Null;
|
||||
|
||||
[RelayCommand]
|
||||
private void Initialize()
|
||||
public override Task InitializeAsync()
|
||||
{
|
||||
// Persist preferences
|
||||
SelectedFormat = settingsService.LastExportFormat;
|
||||
@@ -126,6 +125,8 @@ public partial class ExportSetupViewModel(
|
||||
|| ShouldReuseAssets
|
||||
|| !string.IsNullOrWhiteSpace(AssetsDirPath)
|
||||
|| IsReverseMessageOrder;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.Localization;
|
||||
using DiscordChatExporter.Gui.Services;
|
||||
@@ -100,8 +99,7 @@ public partial class MainViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task InitializeAsync()
|
||||
public override async Task InitializeAsync()
|
||||
{
|
||||
await ShowUkraineSupportMessageAsync();
|
||||
await ShowDevelopmentBuildMessageAsync();
|
||||
|
||||
@@ -12,11 +12,8 @@ public partial class DashboardView : UserControl<DashboardViewModel>
|
||||
{
|
||||
public DashboardView() => InitializeComponent();
|
||||
|
||||
private void UserControl_OnLoaded(object? sender, RoutedEventArgs args)
|
||||
{
|
||||
DataContext.InitializeCommand.Execute(null);
|
||||
private void UserControl_OnLoaded(object? sender, RoutedEventArgs args) =>
|
||||
TokenValueTextBox.Focus();
|
||||
}
|
||||
|
||||
private void AvailableGuildsListBox_OnSelectionChanged(
|
||||
object? sender,
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
xmlns:utils="clr-namespace:DiscordChatExporter.Gui.Utils"
|
||||
x:Name="UserControl"
|
||||
Width="380"
|
||||
x:DataType="dialogs:ExportSetupViewModel"
|
||||
Loaded="UserControl_OnLoaded">
|
||||
x:DataType="dialogs:ExportSetupViewModel">
|
||||
<Grid RowDefinitions="Auto,*,Auto">
|
||||
<!-- Guild/channel info -->
|
||||
<Grid
|
||||
@@ -292,4 +291,4 @@
|
||||
Theme="{DynamicResource MaterialOutlineButton}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Avalonia.Interactivity;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.ViewModels.Dialogs;
|
||||
|
||||
@@ -7,7 +6,4 @@ namespace DiscordChatExporter.Gui.Views.Dialogs;
|
||||
public partial class ExportSetupView : UserControl<ExportSetupViewModel>
|
||||
{
|
||||
public ExportSetupView() => InitializeComponent();
|
||||
|
||||
private void UserControl_OnLoaded(object? sender, RoutedEventArgs args) =>
|
||||
DataContext.InitializeCommand.Execute(null);
|
||||
}
|
||||
|
||||
@@ -14,12 +14,9 @@
|
||||
Icon="/favicon.ico"
|
||||
RenderOptions.BitmapInterpolationMode="HighQuality"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
<dialogHostAvalonia:DialogHost
|
||||
x:Name="DialogHost"
|
||||
CloseOnClickAway="False"
|
||||
Loaded="DialogHost_OnLoaded">
|
||||
<dialogHostAvalonia:DialogHost x:Name="DialogHost" CloseOnClickAway="False">
|
||||
<materialStyles:SnackbarHost HostName="Root" SnackbarMaxCounts="3">
|
||||
<ContentControl Content="{Binding Dashboard}" />
|
||||
</materialStyles:SnackbarHost>
|
||||
</dialogHostAvalonia:DialogHost>
|
||||
</Window>
|
||||
</Window>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Avalonia.Interactivity;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.ViewModels;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Views;
|
||||
@@ -7,7 +6,4 @@ namespace DiscordChatExporter.Gui.Views;
|
||||
public partial class MainView : Window<MainViewModel>
|
||||
{
|
||||
public MainView() => InitializeComponent();
|
||||
|
||||
private void DialogHost_OnLoaded(object? sender, RoutedEventArgs args) =>
|
||||
DataContext.InitializeCommand.Execute(null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user