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