Skip to content

Commit 0c89bdc

Browse files
committed
🪟 Remember window size (but not position)
- Save and apply window width and height. - Add button to reset window size in settings.
1 parent 38e59b1 commit 0c89bdc

File tree

8 files changed

+128
-37
lines changed

8 files changed

+128
-37
lines changed

‎YoutubeDl.Wpf/MainWindow.xaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
TextOptions.TextRenderingMode="Auto"
1818
Background="{DynamicResource MaterialDesignPaper}"
1919
FontFamily="{materialDesign:MaterialDesignFont}"
20-
Title="Cube YouTube Downloader" Height="720" Width="904" MinHeight="644" MinWidth="620">
20+
Title="Cube YouTube Downloader" MinHeight="644" MinWidth="620">
2121
<materialDesign:DialogHost x:Name="rootDialogHost" Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}" Style="{StaticResource MaterialDesignEmbeddedDialogHost}">
2222
<materialDesign:DialogHost.DialogContentTemplate>
2323
<DataTemplate>

‎YoutubeDl.Wpf/MainWindow.xaml.cs‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,29 @@ public partial class MainWindow
1212
public MainWindow()
1313
{
1414
InitializeComponent();
15-
TaskbarItemInfo = new();
16-
ViewModel = new(MainSnackbar.MessageQueue!); // Null forgiving reason: following upstream
15+
1716
MainSnackbar.MessageQueue!.DiscardDuplicates = true;
17+
ViewModel = new(MainSnackbar.MessageQueue);
18+
19+
// Set window size here to avoid flickering.
20+
Width = ViewModel.SharedSettings.WindowWidth;
21+
Height = ViewModel.SharedSettings.WindowHeight;
22+
23+
TaskbarItemInfo = new();
24+
1825
this.WhenActivated(disposables =>
1926
{
27+
// Window size
28+
this.Bind(ViewModel,
29+
viewModel => viewModel.SharedSettings.WindowWidth,
30+
view => view.Width)
31+
.DisposeWith(disposables);
32+
33+
this.Bind(ViewModel,
34+
viewModel => viewModel.SharedSettings.WindowHeight,
35+
view => view.Height)
36+
.DisposeWith(disposables);
37+
2038
// Window closing
2139
this.Events().Closing
2240
.InvokeCommand(ViewModel.SaveSettingsAsyncCommand)

‎YoutubeDl.Wpf/Models/ObservableSettings.cs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ public class ObservableSettings : ReactiveObject
1414

1515
public BaseTheme AppColorMode { get; set; }
1616

17+
[Reactive]
18+
public double WindowWidth { get; set; }
19+
20+
[Reactive]
21+
public double WindowHeight { get; set; }
22+
1723
[Reactive]
1824
public BackendTypes Backend { get; set; }
1925

@@ -106,6 +112,8 @@ public ObservableSettings(Settings settings)
106112
{
107113
AppSettings = settings;
108114
AppColorMode = settings.AppColorMode;
115+
WindowWidth = settings.WindowWidth;
116+
WindowHeight = settings.WindowHeight;
109117
Backend = settings.Backend;
110118
BackendPath = settings.BackendPath;
111119
BackendGlobalArguments = new(settings.BackendGlobalArguments);
@@ -135,6 +143,8 @@ public ObservableSettings(Settings settings)
135143
public void UpdateAppSettings()
136144
{
137145
AppSettings.AppColorMode = AppColorMode;
146+
AppSettings.WindowWidth = WindowWidth;
147+
AppSettings.WindowHeight = WindowHeight;
138148
AppSettings.Backend = Backend;
139149
AppSettings.BackendPath = BackendPath;
140150
AppSettings.BackendGlobalArguments = BackendGlobalArguments.ToArray();

‎YoutubeDl.Wpf/Models/Settings.cs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ public class Settings
1515
/// </summary>
1616
public const int DefaultVersion = 1;
1717

18+
/// <summary>
19+
/// Defines the default width of the main window.
20+
/// </summary>
21+
public const double DefaultWindowWidth = 904.0;
22+
23+
/// <summary>
24+
/// Defines the default height of the main window.
25+
/// </summary>
26+
public const double DefaultWindowHeight = 720.0;
27+
1828
/// <summary>
1929
/// Defines the default limit on the number of log messages
2030
/// displayed in the logs view.
@@ -33,6 +43,10 @@ public class Settings
3343
/// </summary>
3444
public int Version { get; set; } = DefaultVersion;
3545

46+
public double WindowWidth { get; set; } = DefaultWindowWidth;
47+
48+
public double WindowHeight { get; set; } = DefaultWindowHeight;
49+
3650
public BaseTheme AppColorMode { get; set; } = BaseTheme.Inherit;
3751

3852
public BackendTypes Backend { get; set; } = BackendTypes.Ytdlp;

‎YoutubeDl.Wpf/ViewModels/MainWindowViewModel.cs‎

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@ namespace YoutubeDl.Wpf.ViewModels
1414
{
1515
public class MainWindowViewModel : ReactiveObject
1616
{
17-
private readonly Settings _settings;
18-
private readonly ObservableSettings _observableSettings;
1917
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
18+
private readonly Settings _settings;
2019

20+
public ObservableSettings SharedSettings { get; }
2121
public BackendService BackendService { get; }
2222
public PresetDialogViewModel PresetDialogVM { get; }
23-
public HomeViewModel HomeVM { get; }
24-
public SettingsViewModel SettingsVM { get; }
2523
public object[] Tabs { get; }
2624

2725
[Reactive]
@@ -31,6 +29,8 @@ public class MainWindowViewModel : ReactiveObject
3129

3230
public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue)
3331
{
32+
_snackbarMessageQueue = snackbarMessageQueue;
33+
3434
try
3535
{
3636
_settings = Settings.LoadAsync().GetAwaiter().GetResult();
@@ -41,24 +41,20 @@ public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue)
4141
_settings = new();
4242
}
4343

44-
_observableSettings = new(_settings);
45-
_snackbarMessageQueue = snackbarMessageQueue;
46-
4744
// Configure logging.
4845
var queuedTextBoxsink = new QueuedTextBoxSink(_settings);
4946
var logger = new LoggerConfiguration()
5047
.WriteTo.Sink(queuedTextBoxsink)
5148
.CreateLogger();
5249
Locator.CurrentMutable.UseSerilogFullLogger(logger);
5350

54-
BackendService = new(_observableSettings);
51+
SharedSettings = new(_settings);
52+
BackendService = new(SharedSettings);
5553
PresetDialogVM = new(ControlDialog);
56-
HomeVM = new(_observableSettings, BackendService, queuedTextBoxsink, PresetDialogVM, snackbarMessageQueue);
57-
SettingsVM = new(_observableSettings, BackendService, snackbarMessageQueue);
5854
Tabs = new object[]
5955
{
60-
HomeVM,
61-
SettingsVM,
56+
new HomeViewModel(SharedSettings, BackendService, queuedTextBoxsink, PresetDialogVM, snackbarMessageQueue),
57+
new SettingsViewModel(SharedSettings, BackendService, snackbarMessageQueue),
6258
};
6359

6460
SaveSettingsAsyncCommand = ReactiveCommand.CreateFromTask<CancelEventArgs?, bool>(SaveSettingsAsync);
@@ -68,7 +64,7 @@ public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue)
6864

6965
private async Task<bool> SaveSettingsAsync(CancelEventArgs? cancelEventArgs = null, CancellationToken cancellationToken = default)
7066
{
71-
_observableSettings.UpdateAppSettings();
67+
SharedSettings.UpdateAppSettings();
7268

7369
try
7470
{

‎YoutubeDl.Wpf/ViewModels/SettingsViewModel.cs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using DynamicData;
22
using MaterialDesignThemes.Wpf;
33
using ReactiveUI;
4+
using ReactiveUI.Fody.Helpers;
45
using ReactiveUI.Validation.Extensions;
56
using ReactiveUI.Validation.Helpers;
67
using System;
@@ -27,13 +28,17 @@ public class SettingsViewModel : ReactiveValidationObject
2728

2829
public ObservableSettings SharedSettings { get; }
2930

31+
[Reactive]
32+
public string WindowSizeText { get; set; }
33+
3034
/// <summary>
3135
/// Gets the collection of view models of the arguments area.
3236
/// A view model in this collection must be of either
3337
/// <see cref="ArgumentChipViewModel"/> or <see cref="AddArgumentViewModel"/> type.
3438
/// </summary>
3539
public ObservableCollection<object> GlobalArguments { get; } = new();
3640

41+
public ReactiveCommand<Unit, Unit> ResetWindowSizeCommand { get; }
3742
public ReactiveCommand<BaseTheme, Unit> ChangeColorModeCommand { get; }
3843
public ReactiveCommand<Unit, Unit> BrowseDlBinaryCommand { get; }
3944
public ReactiveCommand<Unit, Unit> UpdateBackendCommand { get; }
@@ -48,6 +53,7 @@ public SettingsViewModel(ObservableSettings settings, BackendService backendServ
4853

4954
Version = Assembly.GetEntryAssembly()?.GetName()?.Version?.ToString() ?? "";
5055
SharedSettings = settings;
56+
WindowSizeText = GenerateWindowSizeText(settings.WindowWidth, settings.WindowHeight);
5157

5258
GlobalArguments.AddRange(SharedSettings.BackendGlobalArguments.Select(x => new ArgumentChipViewModel(x, true, DeleteArgumentChip)));
5359
GlobalArguments.Add(new AddArgumentViewModel(AddArgument));
@@ -104,6 +110,10 @@ public SettingsViewModel(ObservableSettings settings, BackendService backendServ
104110
}
105111
});
106112

113+
// Update window size text on size change.
114+
this.WhenAnyValue(x => x.SharedSettings.WindowWidth, x => x.SharedSettings.WindowHeight)
115+
.Subscribe(((double width, double height) x) => WindowSizeText = GenerateWindowSizeText(x.width, x.height));
116+
107117
// Guess the backend type from binary name.
108118
this.WhenAnyValue(x => x.SharedSettings.BackendPath)
109119
.Select(dlPath => Path.GetFileNameWithoutExtension(dlPath))
@@ -119,13 +129,22 @@ public SettingsViewModel(ObservableSettings settings, BackendService backendServ
119129

120130
var canUpdateBackend = this.WhenAnyValue(x => x._backendService.CanUpdate);
121131

132+
ResetWindowSizeCommand = ReactiveCommand.Create(ResetWindowSize);
122133
ChangeColorModeCommand = ReactiveCommand.Create<BaseTheme>(ChangeColorMode);
123134
BrowseDlBinaryCommand = ReactiveCommand.Create(BrowseDlBinary);
124135
UpdateBackendCommand = ReactiveCommand.CreateFromTask(_backendService.UpdateBackendAsync, canUpdateBackend);
125136
BrowseFfmpegBinaryCommand = ReactiveCommand.Create(BrowseFfmpegBinary);
126137
OpenUri = ReactiveCommand.Create<string>(WpfHelper.OpenUri);
127138
}
128139

140+
private static string GenerateWindowSizeText(double width, double height) => $"{width:F} × {height:F}";
141+
142+
private void ResetWindowSize()
143+
{
144+
SharedSettings.WindowWidth = Settings.DefaultWindowWidth;
145+
SharedSettings.WindowHeight = Settings.DefaultWindowHeight;
146+
}
147+
129148
private void ChangeColorMode(BaseTheme colorMode)
130149
{
131150
// Get current theme.

0 commit comments

Comments
 (0)