Skip to content

Commit 248f3ff

Browse files
authored
Feature: Added a splash screen (#12979)
1 parent ffb213a commit 248f3ff

File tree

5 files changed

+164
-98
lines changed

5 files changed

+164
-98
lines changed

src/Files.App/App.xaml.cs

Lines changed: 82 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -95,69 +95,65 @@ private IHost ConfigureHost()
9595
{
9696
return Host.CreateDefaultBuilder()
9797
.UseEnvironment(ApplicationService.AppEnvironment.ToString())
98-
.ConfigureLogging(builder =>
99-
builder
98+
.ConfigureLogging(builder => builder
10099
.AddProvider(new FileLoggerProvider(Path.Combine(ApplicationData.Current.LocalFolder.Path, "debug.log")))
101-
.SetMinimumLevel(LogLevel.Information)
102-
)
103-
.ConfigureServices(services =>
104-
services
105-
.AddSingleton<IUserSettingsService, UserSettingsService>()
106-
.AddSingleton<IAppearanceSettingsService, AppearanceSettingsService>(sp => new AppearanceSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
107-
.AddSingleton<IGeneralSettingsService, GeneralSettingsService>(sp => new GeneralSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
108-
.AddSingleton<IFoldersSettingsService, FoldersSettingsService>(sp => new FoldersSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
109-
.AddSingleton<IApplicationSettingsService, ApplicationSettingsService>(sp => new ApplicationSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
110-
.AddSingleton<IPreviewPaneSettingsService, PreviewPaneSettingsService>(sp => new PreviewPaneSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
111-
.AddSingleton<ILayoutSettingsService, LayoutSettingsService>(sp => new LayoutSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
112-
.AddSingleton<IAppSettingsService, AppSettingsService>(sp => new AppSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
113-
.AddSingleton<IFileTagsSettingsService, FileTagsSettingsService>()
114-
.AddSingleton<IPageContext, PageContext>()
115-
.AddSingleton<IContentPageContext, ContentPageContext>()
116-
.AddSingleton<IDisplayPageContext, DisplayPageContext>()
117-
.AddSingleton<IWindowContext, WindowContext>()
118-
.AddSingleton<IMultitaskingContext, MultitaskingContext>()
119-
.AddSingleton<ITagsContext, TagsContext>()
120-
.AddSingleton<IDialogService, DialogService>()
121-
.AddSingleton<IImageService, ImagingService>()
122-
.AddSingleton<IThreadingService, ThreadingService>()
123-
.AddSingleton<ILocalizationService, LocalizationService>()
124-
.AddSingleton<ICloudDetector, CloudDetector>()
125-
.AddSingleton<IFileTagsService, FileTagsService>()
126-
.AddSingleton<ICommandManager, CommandManager>()
127-
.AddSingleton<IModifiableCommandManager, ModifiableCommandManager>()
128-
.AddSingleton<IApplicationService, ApplicationService>()
100+
.SetMinimumLevel(LogLevel.Information))
101+
.ConfigureServices(services => services
102+
.AddSingleton<IUserSettingsService, UserSettingsService>()
103+
.AddSingleton<IAppearanceSettingsService, AppearanceSettingsService>(sp => new AppearanceSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
104+
.AddSingleton<IGeneralSettingsService, GeneralSettingsService>(sp => new GeneralSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
105+
.AddSingleton<IFoldersSettingsService, FoldersSettingsService>(sp => new FoldersSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
106+
.AddSingleton<IApplicationSettingsService, ApplicationSettingsService>(sp => new ApplicationSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
107+
.AddSingleton<IPreviewPaneSettingsService, PreviewPaneSettingsService>(sp => new PreviewPaneSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
108+
.AddSingleton<ILayoutSettingsService, LayoutSettingsService>(sp => new LayoutSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
109+
.AddSingleton<IAppSettingsService, AppSettingsService>(sp => new AppSettingsService((sp.GetService<IUserSettingsService>() as UserSettingsService).GetSharingContext()))
110+
.AddSingleton<IFileTagsSettingsService, FileTagsSettingsService>()
111+
.AddSingleton<IPageContext, PageContext>()
112+
.AddSingleton<IContentPageContext, ContentPageContext>()
113+
.AddSingleton<IDisplayPageContext, DisplayPageContext>()
114+
.AddSingleton<IWindowContext, WindowContext>()
115+
.AddSingleton<IMultitaskingContext, MultitaskingContext>()
116+
.AddSingleton<ITagsContext, TagsContext>()
117+
.AddSingleton<IDialogService, DialogService>()
118+
.AddSingleton<IImageService, ImagingService>()
119+
.AddSingleton<IThreadingService, ThreadingService>()
120+
.AddSingleton<ILocalizationService, LocalizationService>()
121+
.AddSingleton<ICloudDetector, CloudDetector>()
122+
.AddSingleton<IFileTagsService, FileTagsService>()
123+
.AddSingleton<ICommandManager, CommandManager>()
124+
.AddSingleton<IModifiableCommandManager, ModifiableCommandManager>()
125+
.AddSingleton<IApplicationService, ApplicationService>()
129126
#if UWP
130-
.AddSingleton<IStorageService, WindowsStorageService>()
127+
.AddSingleton<IStorageService, WindowsStorageService>()
131128
#else
132-
.AddSingleton<IStorageService, NativeStorageService>()
129+
.AddSingleton<IStorageService, NativeStorageService>()
133130
#endif
134-
.AddSingleton<IFtpStorageService, FtpStorageService>()
135-
.AddSingleton<IAddItemService, AddItemService>()
131+
.AddSingleton<IFtpStorageService, FtpStorageService>()
132+
.AddSingleton<IAddItemService, AddItemService>()
136133
#if STABLE || PREVIEW
137-
.AddSingleton<IUpdateService, SideloadUpdateService>()
134+
.AddSingleton<IUpdateService, SideloadUpdateService>()
138135
#else
139-
.AddSingleton<IUpdateService, UpdateService>()
136+
.AddSingleton<IUpdateService, UpdateService>()
140137
#endif
141-
.AddSingleton<IPreviewPopupService, PreviewPopupService>()
142-
.AddSingleton<IDateTimeFormatterFactory, DateTimeFormatterFactory>()
143-
.AddSingleton<IDateTimeFormatter, UserDateTimeFormatter>()
144-
.AddSingleton<IVolumeInfoFactory, VolumeInfoFactory>()
145-
.AddSingleton<ISizeProvider, UserSizeProvider>()
146-
.AddSingleton<IQuickAccessService, QuickAccessService>()
147-
.AddSingleton<IResourcesService, ResourcesService>()
148-
.AddSingleton<IJumpListService, JumpListService>()
149-
.AddSingleton<IRemovableDrivesService, RemovableDrivesService>()
150-
.AddSingleton<INetworkDrivesService, NetworkDrivesService>()
151-
.AddSingleton<MainPageViewModel>()
152-
.AddSingleton<PreviewPaneViewModel>()
153-
.AddSingleton<SidebarViewModel>()
154-
.AddSingleton<SettingsViewModel>()
155-
.AddSingleton<DrivesViewModel>()
156-
.AddSingleton<NetworkDrivesViewModel>()
157-
.AddSingleton<OngoingTasksViewModel>()
158-
.AddSingleton<AppearanceViewModel>()
159-
)
160-
.Build();
138+
.AddSingleton<IPreviewPopupService, PreviewPopupService>()
139+
.AddSingleton<IDateTimeFormatterFactory, DateTimeFormatterFactory>()
140+
.AddSingleton<IDateTimeFormatter, UserDateTimeFormatter>()
141+
.AddSingleton<IVolumeInfoFactory, VolumeInfoFactory>()
142+
.AddSingleton<ISizeProvider, UserSizeProvider>()
143+
.AddSingleton<IQuickAccessService, QuickAccessService>()
144+
.AddSingleton<IResourcesService, ResourcesService>()
145+
.AddSingleton<IJumpListService, JumpListService>()
146+
.AddSingleton<IRemovableDrivesService, RemovableDrivesService>()
147+
.AddSingleton<INetworkDrivesService, NetworkDrivesService>()
148+
.AddSingleton<MainPageViewModel>()
149+
.AddSingleton<PreviewPaneViewModel>()
150+
.AddSingleton<SidebarViewModel>()
151+
.AddSingleton<SettingsViewModel>()
152+
.AddSingleton<DrivesViewModel>()
153+
.AddSingleton<NetworkDrivesViewModel>()
154+
.AddSingleton<OngoingTasksViewModel>()
155+
.AddSingleton<AppearanceViewModel>()
156+
).Build();
161157
}
162158

163159
private static async Task InitializeAppComponentsAsync()
@@ -207,28 +203,42 @@ static async Task OptionalTask(Task task, bool condition)
207203
/// <param name="e">Details about the launch request and process.</param>
208204
protected override void OnLaunched(LaunchActivatedEventArgs e)
209205
{
210-
// Get AppActivationArguments
211-
var appActivationArguments = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
206+
_ = ActivateAsync();
212207

213-
// Start tracking app usage
214-
if (appActivationArguments.Data is Windows.ApplicationModel.Activation.IActivatedEventArgs activationEventArgs)
215-
SystemInformation.Instance.TrackAppUse(activationEventArgs);
208+
async Task ActivateAsync()
209+
{
210+
// Initialize and activate MainWindow
211+
EnsureSuperEarlyWindow();
212+
213+
// Wait for the Window to initialize
214+
await Task.Delay(10);
215+
216+
MainWindow.Instance.ShowSplashScreen();
217+
218+
// Wait for the UI to update
219+
await Task.Delay(500);
216220

217-
// Configure Host and IoC
218-
_host = ConfigureHost();
219-
Ioc.Default.ConfigureServices(_host.Services);
221+
// Get AppActivationArguments
222+
var appActivationArguments = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
220223

221-
EnsureSettingsAndConfigurationAreBootstrapped();
224+
// Start tracking app usage
225+
if (appActivationArguments.Data is Windows.ApplicationModel.Activation.IActivatedEventArgs activationEventArgs)
226+
SystemInformation.Instance.TrackAppUse(activationEventArgs);
222227

223-
// Initialize and activate MainWindow
224-
EnsureSuperEarlyWindow();
228+
// Configure Host and IoC
229+
_host = ConfigureHost();
230+
Ioc.Default.ConfigureServices(_host.Services);
225231

226-
// TODO(s)
227-
Logger = Ioc.Default.GetRequiredService<ILogger<App>>();
228-
Logger.LogInformation($"App launched. Launch args type: {appActivationArguments.Data.GetType().Name}");
232+
EnsureSettingsAndConfigurationAreBootstrapped();
229233

230-
_ = InitializeAppComponentsAsync().ContinueWith(t => Logger.LogWarning(t.Exception, "Error during InitializeAppComponentsAsync()"), TaskContinuationOptions.OnlyOnFaulted);
231-
_ = MainWindow.Instance.InitializeApplication(appActivationArguments.Data);
234+
// TODO: Remove App.Logger instance and replace with DI
235+
Logger = Ioc.Default.GetRequiredService<ILogger<App>>();
236+
Logger.LogInformation($"App launched. Launch args type: {appActivationArguments.Data.GetType().Name}");
237+
238+
_ = InitializeAppComponentsAsync().ContinueWith(t => Logger.LogWarning(t.Exception, "Error during InitializeAppComponentsAsync()"), TaskContinuationOptions.OnlyOnFaulted);
239+
240+
_ = MainWindow.Instance.InitializeApplication(appActivationArguments.Data);
241+
}
232242
}
233243

234244
private static void EnsureSettingsAndConfigurationAreBootstrapped()

src/Files.App/GlobalUsings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
global using global::Files.App.Data.Models;
4545
global using global::Files.App.Data.Parameters;
4646
global using global::Files.App.Data.TemplateSelectors;
47+
global using global::Files.App.Services;
4748
global using global::Files.App.UserControls;
4849
global using global::Files.App.ViewModels;
4950
global using global::Files.App.ViewModels.UserControls;

src/Files.App/MainWindow.xaml.cs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT License. See the LICENSE.
33

44
using Files.App.UserControls.MultitaskingControl;
5-
using Files.Core.Utils.CommandLine;
65
using Microsoft.UI;
76
using Microsoft.UI.Windowing;
87
using Microsoft.UI.Xaml.Controls;
@@ -19,20 +18,23 @@ namespace Files.App
1918
{
2019
public sealed partial class MainWindow : WindowEx
2120
{
21+
private readonly IApplicationService ApplicationService;
22+
23+
private MainPageViewModel mainPageViewModel;
24+
2225
private static MainWindow? _Instance;
2326
public static MainWindow Instance => _Instance ??= new();
2427

2528
public IntPtr WindowHandle { get; }
2629

27-
private MainPageViewModel mainPageViewModel;
28-
29-
private IApplicationService ApplicationService { get; } = Ioc.Default.GetRequiredService<IApplicationService>();
30-
3130
private MainWindow()
3231
{
32+
ApplicationService = new ApplicationService();
33+
3334
WindowHandle = this.GetWindowHandle();
3435

3536
InitializeComponent();
37+
3638
EnsureEarlyWindow();
3739
}
3840

@@ -41,30 +43,32 @@ private void EnsureEarlyWindow()
4143
// Set PersistenceId
4244
PersistenceId = "FilesMainWindow";
4345

44-
// Set title
45-
AppWindow.Title = "Files";
46+
// Set minimum sizes
47+
MinHeight = 416;
48+
MinWidth = 516;
4649

47-
// Set logo
50+
AppWindow.Title = "Files";
4851
AppWindow.SetIcon(Path.Combine(Package.Current.InstalledLocation.Path, ApplicationService.AppIcoPath));
49-
50-
// Extend title bar
5152
AppWindow.TitleBar.ExtendsContentIntoTitleBar = true;
52-
53-
// Set window buttons background to transparent
5453
AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
5554
AppWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
55+
}
5656

57-
// Set minimum sizes
58-
base.MinHeight = 328;
59-
base.MinWidth = 516;
57+
public void ShowSplashScreen()
58+
{
59+
var rootFrame = EnsureWindowIsInitialized();
60+
61+
rootFrame.Navigate(typeof(SplashScreenPage));
6062
}
6163

6264
public async Task InitializeApplication(object activatedEventArgs)
6365
{
66+
// Set system backdrop
67+
SystemBackdrop = new AppSystemBackdrop();
68+
6469
mainPageViewModel = Ioc.Default.GetRequiredService<MainPageViewModel>();
6570

6671
var rootFrame = EnsureWindowIsInitialized();
67-
Activate();
6872

6973
switch (activatedEventArgs)
7074
{
@@ -78,7 +82,7 @@ public async Task InitializeApplication(object activatedEventArgs)
7882
else
7983
await InitializeFromCmdLineArgs(rootFrame, ppm);
8084
}
81-
else if (rootFrame.Content is null)
85+
else if (rootFrame.Content is null || rootFrame.Content as SplashScreenPage is not null)
8286
{
8387
// When the navigation stack isn't restored navigate to the first page,
8488
// configuring the new page by passing required information as a navigation parameter
@@ -147,7 +151,7 @@ public async Task InitializeApplication(object activatedEventArgs)
147151

148152
case IFileActivatedEventArgs fileArgs:
149153
var index = 0;
150-
if (rootFrame.Content is null)
154+
if (rootFrame.Content is null || rootFrame.Content as SplashScreenPage is not null)
151155
{
152156
// When the navigation stack isn't restored navigate to the first page,
153157
// configuring the new page by passing required information as a navigation parameter
@@ -161,7 +165,7 @@ public async Task InitializeApplication(object activatedEventArgs)
161165
break;
162166
}
163167

164-
if (rootFrame.Content is null)
168+
if (rootFrame.Content is null || rootFrame.Content as SplashScreenPage is not null)
165169
rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo());
166170
}
167171

@@ -170,18 +174,14 @@ private Frame EnsureWindowIsInitialized()
170174
// NOTE:
171175
// Do not repeat app initialization when the Window already has content,
172176
// just ensure that the window is active
173-
if (!(MainWindow.Instance.Content is Frame rootFrame))
177+
if (Instance.Content is not Frame rootFrame)
174178
{
175-
// Set system backdrop
176-
this.SystemBackdrop = new AppSystemBackdrop();
177-
178179
// Create a Frame to act as the navigation context and navigate to the first page
179-
rootFrame = new Frame();
180-
rootFrame.CacheSize = 1;
180+
rootFrame = new() { CacheSize = 1 };
181181
rootFrame.NavigationFailed += OnNavigationFailed;
182182

183183
// Place the frame in the current Window
184-
MainWindow.Instance.Content = rootFrame;
184+
Instance.Content = rootFrame;
185185
}
186186

187187
return rootFrame;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!-- Copyright (c) 2023 Files Community. Licensed under the MIT License. See the LICENSE. -->
2+
<Page
3+
x:Class="Files.App.Views.SplashScreenPage"
4+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
9+
mc:Ignorable="d">
10+
11+
<Grid>
12+
<Image
13+
x:Name="MainSplashScreenImage"
14+
Width="420"
15+
Source="\Assets\AppTiles\Dev\SplashScreen.png" />
16+
17+
<ProgressRing
18+
x:Name="MainProgressRing"
19+
Margin="0,0,0,88"
20+
VerticalAlignment="Bottom"
21+
Foreground="{ThemeResource ApplicationForegroundThemeBrush}"
22+
IsIndeterminate="True" />
23+
24+
<VisualStateManager.VisualStateGroups>
25+
<VisualStateGroup x:Name="SizeChangesState">
26+
<VisualState>
27+
<VisualState.StateTriggers>
28+
<AdaptiveTrigger MinWindowWidth="640" />
29+
</VisualState.StateTriggers>
30+
<VisualState.Setters>
31+
<Setter Target="MainSplashScreenImage.Width" Value="480" />
32+
</VisualState.Setters>
33+
</VisualState>
34+
</VisualStateGroup>
35+
</VisualStateManager.VisualStateGroups>
36+
</Grid>
37+
</Page>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) 2023 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Microsoft.UI.Xaml.Controls;
5+
6+
namespace Files.App.Views
7+
{
8+
/// <summary>
9+
/// Display the app splash screen.
10+
/// </summary>
11+
public sealed partial class SplashScreenPage : Page
12+
{
13+
public SplashScreenPage()
14+
{
15+
InitializeComponent();
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)