Skip to content

Commit 01dafeb

Browse files
committed
Automate view initialization
1 parent 9ba5926 commit 01dafeb

14 files changed

Lines changed: 69 additions & 77 deletions

‎YoutubeDownloader/App.axaml.cs‎

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,13 @@
1515
using YoutubeDownloader.ViewModels;
1616
using YoutubeDownloader.ViewModels.Components;
1717
using YoutubeDownloader.ViewModels.Dialogs;
18-
using YoutubeDownloader.Views;
1918

2019
namespace YoutubeDownloader;
2120

2221
public class App : Application, IDisposable
2322
{
24-
private readonly DisposableCollector _eventRoot = new();
25-
2623
private readonly ServiceProvider _services;
27-
private readonly SettingsService _settingsService;
28-
private readonly MainViewModel _mainViewModel;
24+
private readonly DisposableCollector _eventRoot = new();
2925

3026
private bool _isDisposed;
3127

@@ -57,42 +53,30 @@ public App()
5753
services.AddTransient<SettingsViewModel>();
5854

5955
_services = services.BuildServiceProvider(true);
60-
_settingsService = _services.GetRequiredService<SettingsService>();
61-
_mainViewModel = _services.GetRequiredService<ViewModelManager>().CreateMainViewModel();
6256

6357
// Re-initialize the theme when the user changes it
6458
_eventRoot.Add(
65-
_settingsService.WatchProperty(
66-
o => o.Theme,
67-
() =>
68-
{
69-
RequestedThemeVariant = _settingsService.Theme switch
59+
_services
60+
.GetRequiredService<SettingsService>()
61+
.WatchProperty(
62+
o => o.Theme,
63+
() =>
7064
{
71-
ThemeVariant.Light => Avalonia.Styling.ThemeVariant.Light,
72-
ThemeVariant.Dark => Avalonia.Styling.ThemeVariant.Dark,
73-
_ => Avalonia.Styling.ThemeVariant.Default,
74-
};
75-
76-
InitializeTheme();
77-
}
78-
)
65+
RequestedThemeVariant = _services
66+
.GetRequiredService<SettingsService>()
67+
.Theme switch
68+
{
69+
ThemeVariant.Light => Avalonia.Styling.ThemeVariant.Light,
70+
ThemeVariant.Dark => Avalonia.Styling.ThemeVariant.Dark,
71+
_ => Avalonia.Styling.ThemeVariant.Default,
72+
};
73+
74+
InitializeTheme();
75+
}
76+
)
7977
);
8078
}
8179

82-
public override void Initialize()
83-
{
84-
base.Initialize();
85-
86-
AvaloniaXamlLoader.Load(this);
87-
}
88-
89-
public override void RegisterServices()
90-
{
91-
base.RegisterServices();
92-
93-
AvaloniaWebViewBuilder.Initialize(config => config.IsInPrivateModeEnabled = true);
94-
}
95-
9680
private void InitializeTheme()
9781
{
9882
var actualTheme = RequestedThemeVariant?.Key switch
@@ -108,25 +92,35 @@ private void InitializeTheme()
10892
: Theme.Create(Theme.Dark, Color.Parse("#E8E8E8"), Color.Parse("#F9A825"));
10993
}
11094

95+
public override void Initialize()
96+
{
97+
base.Initialize();
98+
99+
AvaloniaXamlLoader.Load(this);
100+
}
101+
102+
public override void RegisterServices()
103+
{
104+
base.RegisterServices();
105+
106+
AvaloniaWebViewBuilder.Initialize(config => config.IsInPrivateModeEnabled = true);
107+
}
108+
111109
public override void OnFrameworkInitializationCompleted()
112110
{
113111
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
114112
{
115-
desktop.MainWindow = new MainView { DataContext = _mainViewModel };
116-
117-
void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs args)
118-
{
119-
if (sender is IControlledApplicationLifetime lifetime)
120-
lifetime.Exit -= OnExit;
121-
122-
Dispose();
123-
}
113+
desktop.MainWindow = _services
114+
.GetRequiredService<ViewManager>()
115+
.TryBindWindow(
116+
_services.GetRequiredService<ViewModelManager>().CreateMainViewModel()
117+
);
124118

125119
// Although `App.Dispose()` is invoked from `Program.Main(...)`, on some platforms
126120
// it may be called too late in the shutdown lifecycle. Attach an exit
127121
// handler to ensure timely disposal as a safeguard.
128122
// https://github.com/Tyrrrz/YoutubeDownloader/issues/795
129-
desktop.Exit += OnExit;
123+
desktop.Exit += (_, _) => Dispose();
130124
}
131125

132126
base.OnFrameworkInitializationCompleted();
@@ -135,7 +129,7 @@ void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs args)
135129
InitializeTheme();
136130

137131
// Load settings
138-
_settingsService.Load();
132+
_services.GetRequiredService<SettingsService>().Load();
139133
}
140134

141135
private void Application_OnActualThemeVariantChanged(object? sender, EventArgs args) =>

‎YoutubeDownloader/Framework/ViewManager.cs‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,23 @@ public partial class ViewManager
3232

3333
view.DataContext ??= viewModel;
3434

35+
if (view.IsInitialized)
36+
{
37+
_ = viewModel.InitializeAsync();
38+
}
39+
else
40+
{
41+
view.Initialized += async (_, _) => await viewModel.InitializeAsync();
42+
}
43+
3544
return view;
3645
}
46+
47+
public UserControl<T>? TryBindUserControl<T>(T viewModel)
48+
where T : ViewModelBase => TryBindView(viewModel) as UserControl<T>;
49+
50+
public Window<T>? TryBindWindow<T>(T viewModel)
51+
where T : ViewModelBase => TryBindView(viewModel) as Window<T>;
3752
}
3853

3954
public partial class ViewManager : IDataTemplate

‎YoutubeDownloader/Framework/ViewModelBase.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading.Tasks;
23
using CommunityToolkit.Mvvm.ComponentModel;
34

45
namespace YoutubeDownloader.Framework;
@@ -9,6 +10,8 @@ public abstract class ViewModelBase : ObservableObject, IDisposable
910

1011
protected void OnAllPropertiesChanged() => OnPropertyChanged(string.Empty);
1112

13+
public virtual Task InitializeAsync() => Task.CompletedTask;
14+
1215
protected virtual void Dispose(bool disposing) { }
1316

1417
public void Dispose()

‎YoutubeDownloader/ViewModels/Components/DashboardViewModel.cs‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ await _dialogManager.ShowDialogAsync(
137137
}
138138
}
139139

140-
[RelayCommand]
141-
private async Task InitializeAsync() => await EnsureFFmpegAsync();
140+
public override async Task InitializeAsync() => await EnsureFFmpegAsync();
142141

143142
private bool CanShowAuthSetup() => !IsBusy;
144143

‎YoutubeDownloader/ViewModels/Dialogs/DownloadMultipleSetupViewModel.cs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ SettingsService settingsService
4949
// Without .AsEnumerable(), the below line throws a compile-time error starting with .NET SDK v9.0.200
5050
Enum.GetValues<VideoQualityPreference>().AsEnumerable().Reverse().ToArray();
5151

52-
[RelayCommand]
53-
private void Initialize()
52+
public override Task InitializeAsync()
5453
{
5554
SelectedContainer = settingsService.LastContainer;
5655
SelectedVideoQualityPreference = settingsService.LastVideoQualityPreference;
5756
SelectedVideos.CollectionChanged += (_, _) => ConfirmCommand.NotifyCanExecuteChanged();
57+
58+
return Task.CompletedTask;
5859
}
5960

6061
[RelayCommand]

‎YoutubeDownloader/ViewModels/Dialogs/DownloadSingleSetupViewModel.cs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@ SettingsService settingsService
3434
[ObservableProperty]
3535
public partial VideoDownloadOption? SelectedDownloadOption { get; set; }
3636

37-
[RelayCommand]
38-
private void Initialize()
37+
public override Task InitializeAsync()
3938
{
4039
SelectedDownloadOption = AvailableDownloadOptions?.FirstOrDefault(o =>
4140
o.Container == settingsService.LastContainer
4241
);
42+
43+
return Task.CompletedTask;
4344
}
4445

4546
[RelayCommand]

‎YoutubeDownloader/ViewModels/MainViewModel.cs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Diagnostics;
33
using System.Threading.Tasks;
44
using Avalonia;
5-
using CommunityToolkit.Mvvm.Input;
65
using YoutubeDownloader.Framework;
76
using YoutubeDownloader.Localization;
87
using YoutubeDownloader.Services;
@@ -100,8 +99,7 @@ private async Task CheckForUpdatesAsync()
10099
}
101100
}
102101

103-
[RelayCommand]
104-
private async Task InitializeAsync()
102+
public override async Task InitializeAsync()
105103
{
106104
await ShowUkraineSupportMessageAsync();
107105
await ShowDevelopmentBuildMessageAsync();

‎YoutubeDownloader/Views/Components/DashboardView.axaml.cs‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@ public DashboardView()
1616
QueryTextBox.AddHandler(KeyDownEvent, QueryTextBox_OnKeyDown, RoutingStrategies.Tunnel);
1717
}
1818

19-
private void UserControl_OnLoaded(object? sender, RoutedEventArgs args)
20-
{
21-
DataContext.InitializeCommand.Execute(null);
22-
QueryTextBox.Focus();
23-
}
19+
private void UserControl_OnLoaded(object? sender, RoutedEventArgs args) => QueryTextBox.Focus();
2420

2521
private void QueryTextBox_OnKeyDown(object? sender, KeyEventArgs args)
2622
{

‎YoutubeDownloader/Views/Dialogs/DownloadMultipleSetupView.axaml‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
1010
x:Name="UserControl"
1111
Width="500"
12-
x:DataType="dialogs:DownloadMultipleSetupViewModel"
13-
Loaded="UserControl_OnLoaded">
12+
x:DataType="dialogs:DownloadMultipleSetupViewModel">
1413
<Grid RowDefinitions="Auto,*,Auto,Auto">
1514
<!-- Title -->
1615
<TextBlock
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using Avalonia.Interactivity;
21
using YoutubeDownloader.Framework;
32
using YoutubeDownloader.ViewModels.Dialogs;
43

@@ -7,7 +6,4 @@ namespace YoutubeDownloader.Views.Dialogs;
76
public partial class DownloadMultipleSetupView : UserControl<DownloadMultipleSetupViewModel>
87
{
98
public DownloadMultipleSetupView() => InitializeComponent();
10-
11-
private void UserControl_OnLoaded(object? sender, RoutedEventArgs args) =>
12-
DataContext.InitializeCommand.Execute(null);
139
}

0 commit comments

Comments
 (0)