From 6dca8eb12995f5fa496694309e09a889ba718ae9 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 15:26:02 +0530 Subject: [PATCH 01/13] Update MainWindow.xaml.cs --- src/Files.App/MainWindow.xaml.cs | 515 +++++++++++-------------------- 1 file changed, 188 insertions(+), 327 deletions(-) diff --git a/src/Files.App/MainWindow.xaml.cs b/src/Files.App/MainWindow.xaml.cs index e80e55247649..eea9ba19067d 100644 --- a/src/Files.App/MainWindow.xaml.cs +++ b/src/Files.App/MainWindow.xaml.cs @@ -4,340 +4,201 @@ using Microsoft.Extensions.Logging; using Microsoft.UI; using Microsoft.UI.Windowing; +using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media.Animation; +using System.Globalization; using System.Runtime.InteropServices; using Windows.ApplicationModel.Activation; +using Windows.Globalization; using Windows.Storage; using IO = System.IO; +using System.Threading.Tasks; +using System.Linq; namespace Files.App { - public sealed partial class MainWindow : WinUIEx.WindowEx - { - private static MainWindow? _Instance; - public static MainWindow Instance => _Instance ??= new(); - - public nint WindowHandle { get; } - - public MainWindow() - { - InitializeComponent(); - - WindowHandle = WinUIEx.WindowExtensions.GetWindowHandle(this); - MinHeight = 316; - MinWidth = 416; - ExtendsContentIntoTitleBar = true; - Title = "Files"; - PersistenceId = "FilesMainWindow"; - AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent; - AppWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent; - AppWindow.TitleBar.ButtonPressedBackgroundColor = Colors.Transparent; - AppWindow.TitleBar.ButtonHoverBackgroundColor = Colors.Transparent; - AppWindow.SetIcon(AppLifecycleHelper.AppIconPath); - } - - public void ShowSplashScreen() - { - var rootFrame = EnsureWindowIsInitialized(); - - rootFrame?.Navigate(typeof(SplashScreenPage)); - } - - public async Task InitializeApplicationAsync(object activatedEventArgs) - { - var rootFrame = EnsureWindowIsInitialized(); - - if (rootFrame is null) - return; - - // Set system backdrop - SystemBackdrop = new AppSystemBackdrop(); - - switch (activatedEventArgs) - { - case ILaunchActivatedEventArgs launchArgs: - if (launchArgs.Arguments is not null && - (CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith($"files.exe", StringComparison.OrdinalIgnoreCase) - || CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith($"files", StringComparison.OrdinalIgnoreCase))) - { - // WINUI3: When launching from commandline the argument is not ICommandLineActivatedEventArgs (#10370) - var ppm = CommandLineParser.ParseUntrustedCommands(launchArgs.Arguments); - if (ppm.IsEmpty()) - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - else - await InitializeFromCmdLineArgsAsync(rootFrame, ppm); - } - else if (rootFrame.Content is null || rootFrame.Content is SplashScreenPage || !MainPageViewModel.AppInstances.Any()) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation parameter - rootFrame.Navigate(typeof(MainPage), launchArgs.Arguments, new SuppressNavigationTransitionInfo()); - } - else if (!(string.IsNullOrEmpty(launchArgs.Arguments) && MainPageViewModel.AppInstances.Count > 0)) - { - // Bring to foreground (#14730) - Win32Helper.BringToForegroundEx(new(WindowHandle)); - - await NavigationHelpers.AddNewTabByPathAsync(typeof(ShellPanesPage), launchArgs.Arguments, true); - } - else - { - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - } - break; - - case IProtocolActivatedEventArgs eventArgs: - if (eventArgs.Uri.AbsoluteUri == "files-uwp:") - { - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - - if (MainPageViewModel.AppInstances.Count > 0) - { - // Bring to foreground (#14730) - Win32Helper.BringToForegroundEx(new(WindowHandle)); - } - } - else - { - var parsedArgs = eventArgs.Uri.Query.TrimStart('?').Split('='); - var unescapedValue = Uri.UnescapeDataString(parsedArgs[1]); - var folder = (StorageFolder)await FilesystemTasks.Wrap(() => StorageFolder.GetFolderFromPathAsync(unescapedValue).AsTask()); - if (folder is not null && !string.IsNullOrEmpty(folder.Path)) - { - // Convert short name to long name (#6190) - unescapedValue = folder.Path; - } - switch (parsedArgs[0]) - { - case "tab": - rootFrame.Navigate(typeof(MainPage), - new MainPageNavigationArguments() { Parameter = TabBarItemParameter.Deserialize(unescapedValue), IgnoreStartupSettings = true }, - new SuppressNavigationTransitionInfo()); - break; - - case "folder": - rootFrame.Navigate(typeof(MainPage), - new MainPageNavigationArguments() { Parameter = unescapedValue, IgnoreStartupSettings = true }, - new SuppressNavigationTransitionInfo()); - break; - - case "cmd": - var ppm = CommandLineParser.ParseUntrustedCommands(unescapedValue); - if (ppm.IsEmpty()) - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - else - await InitializeFromCmdLineArgsAsync(rootFrame, ppm); - break; - default: - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - break; - } - } - break; - - case ICommandLineActivatedEventArgs cmdLineArgs: - var operation = cmdLineArgs.Operation; - var cmdLineString = operation.Arguments; - var activationPath = operation.CurrentDirectoryPath; - - var parsedCommands = CommandLineParser.ParseUntrustedCommands(cmdLineString); - if (parsedCommands is not null && parsedCommands.Count > 0) - { - await InitializeFromCmdLineArgsAsync(rootFrame, parsedCommands, activationPath); - } - else - { - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - } - break; - - case IFileActivatedEventArgs fileArgs: - var index = 0; - if (rootFrame.Content is null || rootFrame.Content is SplashScreenPage || !MainPageViewModel.AppInstances.Any()) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation parameter - rootFrame.Navigate(typeof(MainPage), fileArgs.Files.First().Path, new SuppressNavigationTransitionInfo()); - index = 1; - } - else - { - // Bring to foreground (#14730) - Win32Helper.BringToForegroundEx(new(WindowHandle)); - } - - for (; index < fileArgs.Files.Count; index++) - { - await NavigationHelpers.AddNewTabByPathAsync(typeof(ShellPanesPage), fileArgs.Files[index].Path, true); - } - break; - - case IStartupTaskActivatedEventArgs startupArgs: - // Just launch the app with no arguments - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - break; - - default: - // Just launch the app with no arguments - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - break; - } - - if (!AppWindow.IsVisible) - { - // When resuming the cached instance - AppWindow.Show(); - Activate(); - - // Bring to foreground (#14730) in case Activate() doesn't - Win32Helper.BringToForegroundEx(new(WindowHandle)); - } - - if (Windows.Win32.PInvoke.IsIconic(new(WindowHandle))) - WinUIEx.WindowExtensions.Restore(Instance); // Restore window if minimized - } - - private Frame? EnsureWindowIsInitialized() - { - try - { - // NOTE: - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (Instance.Content is not Frame rootFrame) - { - // Create a Frame to act as the navigation context and navigate to the first page - rootFrame = new() { CacheSize = 1 }; - rootFrame.NavigationFailed += (s, e) => - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - }; - - // Place the frame in the current Window - Instance.Content = rootFrame; - } - - return rootFrame; - } - catch (COMException) - { - return null; - } - } - - private async Task InitializeFromCmdLineArgsAsync(Frame rootFrame, ParsedCommands parsedCommands, string activationPath = "") - { - async Task PerformNavigationAsync(string payload, string selectItem = null) - { - if (!string.IsNullOrEmpty(payload)) - { - payload = Constants.UserEnvironmentPaths.ShellPlaces.Get(payload.ToUpperInvariant(), payload); - var folder = (StorageFolder)await FilesystemTasks.Wrap(() => StorageFolder.GetFolderFromPathAsync(payload).AsTask()); - if (folder is not null && !string.IsNullOrEmpty(folder.Path)) - payload = folder.Path; // Convert short name to long name (#6190) - } - - var generalSettingsService = Ioc.Default.GetService(); - - double boundsWidth = 0; - try - { - boundsWidth = Bounds.Width; - } - catch (Exception ex) - { - // Handle exception in case WinUI Windows is closed - // (see https://github.com/files-community/Files/issues/15599) - - App.Logger.LogWarning(ex, ex.Message); - return; - } - - var paneNavigationArgs = new PaneNavigationArguments - { - LeftPaneNavPathParam = payload, - LeftPaneSelectItemParam = selectItem, - RightPaneNavPathParam = boundsWidth > Constants.UI.MultiplePaneWidthThreshold && (generalSettingsService?.AlwaysOpenDualPaneInNewTab ?? false) ? "Home" : null, - }; - - if (rootFrame.Content is MainPage && MainPageViewModel.AppInstances.Any()) - { - // Bring to foreground (#14730) - Win32Helper.BringToForegroundEx(new(WindowHandle)); - - var existingTabIndex = MainPageViewModel.AppInstances - .Select((tabItem, idx) => new { tabItem, idx }) - .FirstOrDefault(x => - x.tabItem.NavigationParameter.NavigationParameter is PaneNavigationArguments paneArgs && - (paneNavigationArgs.LeftPaneNavPathParam == paneArgs.LeftPaneNavPathParam || - paneNavigationArgs.LeftPaneNavPathParam == paneArgs.RightPaneNavPathParam))?.idx ?? -1; - - if (existingTabIndex >= 0) - App.AppModel.TabStripSelectedIndex = existingTabIndex; - else - await NavigationHelpers.AddNewTabByParamAsync(typeof(ShellPanesPage), paneNavigationArgs); - } - else - rootFrame.Navigate(typeof(MainPage), paneNavigationArgs, new SuppressNavigationTransitionInfo()); - } - foreach (var command in parsedCommands) - { - switch (command.Type) - { - case ParsedCommandType.OpenDirectory: - case ParsedCommandType.OpenPath: - case ParsedCommandType.ExplorerShellCommand: - var selectItemCommand = parsedCommands.FirstOrDefault(x => x.Type == ParsedCommandType.SelectItem); - await PerformNavigationAsync(command.Payload, selectItemCommand?.Payload); - break; - - case ParsedCommandType.SelectItem: - if (IO.Path.IsPathRooted(command.Payload)) - await PerformNavigationAsync(IO.Path.GetDirectoryName(command.Payload), IO.Path.GetFileName(command.Payload)); - break; - - case ParsedCommandType.TagFiles: - var tagService = Ioc.Default.GetService(); - var tag = tagService.GetTagsByName(command.Payload).FirstOrDefault(); - foreach (var file in command.Args.Skip(1)) - { - var fileFRN = await FilesystemTasks.Wrap(() => StorageHelpers.ToStorageItem(file)) - .OnSuccess(item => FileTagsHelper.GetFileFRN(item)); - if (fileFRN is not null) - { - var tagUid = tag is not null ? new[] { tag.Uid } : []; - var dbInstance = FileTagsHelper.GetDbInstance(); - dbInstance.SetTags(file, fileFRN, tagUid); - FileTagsHelper.WriteFileTag(file, tagUid); - } - } - break; - - case ParsedCommandType.Unknown: - if (command.Payload.Equals(".")) - { - await PerformNavigationAsync(activationPath); - } - else - { - if (!string.IsNullOrEmpty(command.Payload)) - { - var target = IO.Path.GetFullPath(IO.Path.Combine(activationPath, command.Payload)); - await PerformNavigationAsync(target); - } - else - { - await PerformNavigationAsync(null); - } - } - break; - - case ParsedCommandType.OutputPath: - App.OutputPath = command.Payload; - break; - } - } - } - } + public sealed partial class MainWindow : WinUIEx.WindowEx + { + private static MainWindow? _Instance; + public static MainWindow Instance => _Instance ??= new(); + + public nint WindowHandle { get; } + + public MainWindow() + { + InitializeComponent(); + + // Force the app to use the correct culture for UI elements + SetAppCulture(); + + WindowHandle = WinUIEx.WindowExtensions.GetWindowHandle(this); + MinHeight = 316; + MinWidth = 416; + ExtendsContentIntoTitleBar = true; + Title = "Files"; + PersistenceId = "FilesMainWindow"; + AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent; + AppWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent; + AppWindow.TitleBar.ButtonPressedBackgroundColor = Colors.Transparent; + AppWindow.TitleBar.ButtonHoverBackgroundColor = Colors.Transparent; + AppWindow.SetIcon(AppLifecycleHelper.AppIconPath); + } + + /// + /// Set the application's culture to match the system's current UI culture. + /// This ensures that the correct language is applied to all UI elements. + /// + private void SetAppCulture() + { + var culture = CultureInfo.CurrentUICulture; + + // Apply the system's UI culture across the application + CultureInfo.DefaultThreadCurrentUICulture = culture; + CultureInfo.DefaultThreadCurrentCulture = culture; + ApplicationLanguages.PrimaryLanguageOverride = culture.Name; + } + + public void ShowSplashScreen() + { + var rootFrame = EnsureWindowIsInitialized(); + + rootFrame?.Navigate(typeof(SplashScreenPage)); + } + + public async Task InitializeApplicationAsync(object activatedEventArgs) + { + var rootFrame = EnsureWindowIsInitialized(); + + if (rootFrame is null) + return; + + // Set system backdrop + SystemBackdrop = new AppSystemBackdrop(); + + switch (activatedEventArgs) + { + case ILaunchActivatedEventArgs launchArgs: + if (launchArgs.Arguments is not null && + (CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith($"files.exe", StringComparison.OrdinalIgnoreCase) + || CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith($"files", StringComparison.OrdinalIgnoreCase))) + { + var ppm = CommandLineParser.ParseUntrustedCommands(launchArgs.Arguments); + if (ppm.IsEmpty()) + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + else + await InitializeFromCmdLineArgsAsync(rootFrame, ppm); + } + else if (rootFrame.Content is null || rootFrame.Content is SplashScreenPage || !MainPageViewModel.AppInstances.Any()) + { + rootFrame.Navigate(typeof(MainPage), launchArgs.Arguments, new SuppressNavigationTransitionInfo()); + } + else if (!(string.IsNullOrEmpty(launchArgs.Arguments) && MainPageViewModel.AppInstances.Count > 0)) + { + Win32Helper.BringToForegroundEx(new(WindowHandle)); + await NavigationHelpers.AddNewTabByPathAsync(typeof(ShellPanesPage), launchArgs.Arguments, true); + } + else + { + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + } + break; + + case IProtocolActivatedEventArgs eventArgs: + if (eventArgs.Uri.AbsoluteUri == "files-uwp:") + { + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + if (MainPageViewModel.AppInstances.Count > 0) + { + Win32Helper.BringToForegroundEx(new(WindowHandle)); + } + } + else + { + var parsedArgs = eventArgs.Uri.Query.TrimStart('?').Split('='); + var unescapedValue = Uri.UnescapeDataString(parsedArgs[1]); + var folder = (StorageFolder)await FilesystemTasks.Wrap(() => StorageFolder.GetFolderFromPathAsync(unescapedValue).AsTask()); + if (folder is not null && !string.IsNullOrEmpty(folder.Path)) + { + unescapedValue = folder.Path; + } + switch (parsedArgs[0]) + { + case "tab": + rootFrame.Navigate(typeof(MainPage), + new MainPageNavigationArguments() { Parameter = TabBarItemParameter.Deserialize(unescapedValue), IgnoreStartupSettings = true }, + new SuppressNavigationTransitionInfo()); + break; + + case "folder": + rootFrame.Navigate(typeof(MainPage), + new MainPageNavigationArguments() { Parameter = unescapedValue, IgnoreStartupSettings = true }, + new SuppressNavigationTransitionInfo()); + break; + + case "cmd": + var ppm = CommandLineParser.ParseUntrustedCommands(unescapedValue); + if (ppm.IsEmpty()) + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + else + await InitializeFromCmdLineArgsAsync(rootFrame, ppm); + break; + default: + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + break; + } + } + break; + + case IFileActivatedEventArgs fileArgs: + if (fileArgs.Files.Count > 0) + { + rootFrame.Navigate(typeof(MainPage), fileArgs.Files, new SuppressNavigationTransitionInfo()); + } + break; + + default: + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + break; + } + } + + private Frame? EnsureWindowIsInitialized() + { + try + { + if (Instance.Content is not Frame rootFrame) + { + rootFrame = new() { CacheSize = 1 }; + rootFrame.NavigationFailed += (s, e) => + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + }; + + Instance.Content = rootFrame; + } + + return rootFrame; + } + catch (COMException) + { + return null; + } + } + + private async Task InitializeFromCmdLineArgsAsync(Frame rootFrame, CommandLineParameterModel ppm) + { + if (ppm.Commands?.FirstOrDefault() is string cmd) + { + if (cmd.Equals("open", StringComparison.OrdinalIgnoreCase) && ppm.Parameters?.FirstOrDefault() is string path) + { + await NavigationHelpers.AddNewTabByPathAsync(typeof(ShellPanesPage), path, true); + } + else if (cmd.Equals("new", StringComparison.OrdinalIgnoreCase)) + { + rootFrame.Navigate(typeof(MainPage), new MainPageNavigationArguments() { Parameter = null }, new SuppressNavigationTransitionInfo()); + } + } + } + } } From 8fe8e7773251cb7d66a488d69cfacc129414da14 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 15:55:40 +0530 Subject: [PATCH 02/13] Update MainPage.xaml.cs --- src/Files.App/Views/MainPage.xaml.cs | 99 ++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/Files.App/Views/MainPage.xaml.cs b/src/Files.App/Views/MainPage.xaml.cs index 55b9a425aaa8..32e65474741b 100644 --- a/src/Files.App/Views/MainPage.xaml.cs +++ b/src/Files.App/Views/MainPage.xaml.cs @@ -56,8 +56,104 @@ public MainPage() _updateDateDisplayTimer = DispatcherQueue.CreateTimer(); _updateDateDisplayTimer.Interval = TimeSpan.FromSeconds(1); _updateDateDisplayTimer.Tick += UpdateDateDisplayTimer_Tick; + +private void LoadPaneChanged() +{ + try + { + // Check if there is an active pane holder + if (SidebarAdaptiveViewModel.PaneHolder != null) + { + // Determine if the current view is a home page or multi-pane + bool isHomePage = !(SidebarAdaptiveViewModel.PaneHolder.ActivePane.InstanceViewModel is not IShellPanesPage); + bool isMultiPane = SidebarAdaptiveViewModel.PaneHolder.IsMultiPaneActive; + + // Check if the main window is sufficiently sized + bool isBigEnough = !App.AppModel.IsMainWindowClosed && + (MainWindow.Instance.Bounds.Width > 450 && MainWindow.Instance.Bounds.Height > 450 || + RootGrid.ActualWidth > 700 && MainWindow.Instance.Bounds.Height > 360); + + // Determine if the preview pane should be displayed + ViewModel.ShouldPreviewPaneBeDisplayed = (!isHomePage || isMultiPane) && isBigEnough; + ViewModel.ShouldPreviewPaneBeActive = UserSettingsService.InfoPaneSettingsService.IsInfoPaneEnabled && ViewModel.ShouldPreviewPaneBeDisplayed; + + // Update the status bar based on the active pane + UpdateStatusBarProperties(); + + // Update navigation toolbar properties + UpdateNavToolbarProperties(); + + // Adjust pane positioning + UpdatePositioning(); + } + } + catch (Exception ex) + { + // Log any exceptions that occur during pane loading + App.Logger.LogWarning(ex, "Error while loading pane changes: {Message}", ex.Message); + } +} + + } + private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) +{ + switch (e.PropertyName) + { + case nameof(ViewModel.ShouldPreviewPaneBeActive): + if (ViewModel.ShouldPreviewPaneBeActive) + { + // Load the preview pane with the selected item details + var infoPaneViewModel = Ioc.Default.GetRequiredService(); + infoPaneViewModel.UpdateSelectedItemPreviewAsync(); + } + break; + + case nameof(ViewModel.ShouldViewControlBeDisplayed): + if (ViewModel.ShouldViewControlBeDisplayed) + { + // Show view control + ViewControl.Visibility = Visibility.Visible; + } + else + { + // Hide view control + ViewControl.Visibility = Visibility.Collapsed; + } + break; + + case nameof(ViewModel.MultitaskingControl): + // Update the multitasking control UI + UpdateMultitaskingControl(ViewModel.MultitaskingControl); + break; + + case nameof(ViewModel.SelectedTabIndex): + // Logic for when the selected tab index changes + UpdateTabSelection(ViewModel.SelectedTabIndex); + break; + } +} + + + +private void UpdateMultitaskingControl(object multitaskingControl) +{ + // Logic to refresh the multitasking UI + if (multitaskingControl is TabBar tabBar) + { + // Update the tab bar with the new multitasking control + TabControl.ItemsSource = tabBar.Items; + } +} + +private void UpdateTabSelection(int selectedIndex) +{ + // Logic to update UI based on selected tab + TabControl.SelectedIndex = selectedIndex; +} + + private async Task PromptForReviewAsync() { var promptForReviewDialog = new ContentDialog @@ -158,6 +254,9 @@ public async void TabItemContent_ContentChanged(object? sender, TabBarItemParame // Save the updated tab list AppLifecycleHelper.SaveSessionTabs(); + + // Call LoadPaneChanged to update the UI as needed + LoadPaneChanged(); } public async void MultitaskingControl_CurrentInstanceChanged(object? sender, CurrentInstanceChangedEventArgs e) From 89c868a4d14ca031b666e592087b091c08058692 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:00:19 +0530 Subject: [PATCH 03/13] Create dotnet.yml --- .github/workflows/dotnet.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/dotnet.yml diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 000000000000..dde88a1e7418 --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,28 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: .NET + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: windows-latest # Change from ubuntu-latest to windows-latest + + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal From b2502b15b89dafa904025a70890f00869ad3ac75 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:04:11 +0530 Subject: [PATCH 04/13] Update dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index dde88a1e7418..cd399faaec56 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -19,7 +19,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.x + dotnet-version: 8.0.403 - name: Restore dependencies run: dotnet restore - name: Build From 1307493a11fc3e8b0ec2971e1dbaf6a025ccc3e8 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:10:43 +0530 Subject: [PATCH 05/13] Update dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index cd399faaec56..ad47ab912e40 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -19,7 +19,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.403 + dotnet-version: 7.0.120 - name: Restore dependencies run: dotnet restore - name: Build From 35ace2ad934d7ee2a6b9377122162e5045d8f5a0 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:12:54 +0530 Subject: [PATCH 06/13] Update dotnet.yml --- .github/workflows/dotnet.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index ad47ab912e40..affdb2c097a0 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -12,17 +12,26 @@ on: jobs: build: - runs-on: windows-latest # Change from ubuntu-latest to windows-latest + runs-on: windows-latest # Set the environment to Windows steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 7.0.120 + dotnet-version: '7.0.x' # Use '7.0.x' to get the latest patch of .NET 7.0 + - name: Restore dependencies run: dotnet restore + - name: Build - run: dotnet build --no-restore - - name: Test - run: dotnet test --no-build --verbosity normal + run: dotnet build --configuration Release --no-restore # Use Release configuration for builds + + - name: Run Tests + run: dotnet test --configuration Release --no-build --verbosity normal # Run tests with Release configuration + + - name: Publish + run: dotnet publish --configuration Release --no-build -o ./output # Optional: Publish the project + From 56116ce12d3b1e20e40e4870ccd1ddbf76a18acc Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:20:44 +0530 Subject: [PATCH 07/13] Update global.json --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 62a1920fd79d..a0699d2f1ac4 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.303" + "version": "8.0.403" } } From 3724fc6165961a1dbb7d061b4cb74f22810365f2 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:21:09 +0530 Subject: [PATCH 08/13] Update dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index affdb2c097a0..9a9d116479f2 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -21,7 +21,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: '7.0.x' # Use '7.0.x' to get the latest patch of .NET 7.0 + dotnet-version: '8.0.403' # Use '7.0.x' to get the latest patch of .NET 7.0 - name: Restore dependencies run: dotnet restore From 10fd6f96abc95046362a87e78c06502ed5f2a2ea Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 20:18:24 +0530 Subject: [PATCH 09/13] Update dotnet.yml --- .github/workflows/dotnet.yml | 38 ++++++++++++------------------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 9a9d116479f2..0fee93765760 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -1,7 +1,5 @@ -# This workflow will build a .NET project -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net - -name: .NET +# This workflow will build a C++ project using g++ +name: C++ Build with g++ on: push: @@ -12,26 +10,16 @@ on: jobs: build: - runs-on: windows-latest # Set the environment to Windows + runs-on: windows-latest steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '8.0.403' # Use '7.0.x' to get the latest patch of .NET 7.0 - - - name: Restore dependencies - run: dotnet restore - - - name: Build - run: dotnet build --configuration Release --no-restore # Use Release configuration for builds - - - name: Run Tests - run: dotnet test --configuration Release --no-build --verbosity normal # Run tests with Release configuration - - - name: Publish - run: dotnet publish --configuration Release --no-build -o ./output # Optional: Publish the project - + - uses: actions/checkout@v4 + - name: Install MinGW (for g++) + run: | + choco install mingw + echo "C:\tools\mingw64\bin" >> $env:GITHUB_PATH + - name: Build C++ Project + run: | + g++ -o output.exe -Wall -Wextra -O2 ./src/*.cpp + - name: Run Executable + run: ./output.exe From 06d9d0607facce58ce5d3c5f300becb844f436dd Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 20:24:15 +0530 Subject: [PATCH 10/13] Update dotnet.yml --- .github/workflows/dotnet.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 0fee93765760..711fc1c8e121 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -20,6 +20,7 @@ jobs: echo "C:\tools\mingw64\bin" >> $env:GITHUB_PATH - name: Build C++ Project run: | - g++ -o output.exe -Wall -Wextra -O2 ./src/*.cpp + $cppFiles = Get-ChildItem -Path ./src -Filter *.cpp | ForEach-Object { $_.FullName } + g++ -o output.exe -Wall -Wextra -O2 $cppFiles - name: Run Executable run: ./output.exe From 9dcf54b2e104a88e52f9c40ae1a7737958883b78 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 20:29:07 +0530 Subject: [PATCH 11/13] Update dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 711fc1c8e121..0d6d3272285d 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -20,7 +20,7 @@ jobs: echo "C:\tools\mingw64\bin" >> $env:GITHUB_PATH - name: Build C++ Project run: | - $cppFiles = Get-ChildItem -Path ./src -Filter *.cpp | ForEach-Object { $_.FullName } + $cppFiles = Get-ChildItem -Path ../../../src -Filter *.cs | ForEach-Object { $_.FullName } g++ -o output.exe -Wall -Wextra -O2 $cppFiles - name: Run Executable run: ./output.exe From 283a47e76fec61fe28b861c1b5e578e1d47b49b3 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 20:41:19 +0530 Subject: [PATCH 12/13] Update MainWindow.xaml.cs --- src/Files.App/MainWindow.xaml.cs | 202 +++++++++++++++++-------------- 1 file changed, 113 insertions(+), 89 deletions(-) diff --git a/src/Files.App/MainWindow.xaml.cs b/src/Files.App/MainWindow.xaml.cs index eea9ba19067d..34c56753f42c 100644 --- a/src/Files.App/MainWindow.xaml.cs +++ b/src/Files.App/MainWindow.xaml.cs @@ -1,6 +1,3 @@ -// Copyright (c) 2024 Files Community -// Licensed under the MIT License. See the LICENSE. - using Microsoft.Extensions.Logging; using Microsoft.UI; using Microsoft.UI.Windowing; @@ -12,16 +9,17 @@ using Windows.ApplicationModel.Activation; using Windows.Globalization; using Windows.Storage; -using IO = System.IO; -using System.Threading.Tasks; +using System; using System.Linq; +using System.Threading.Tasks; +using System.IO; namespace Files.App { public sealed partial class MainWindow : WinUIEx.WindowEx { - private static MainWindow? _Instance; - public static MainWindow Instance => _Instance ??= new(); + private static readonly Lazy _Instance = new(() => new MainWindow()); + public static MainWindow Instance => _Instance.Value; public nint WindowHandle { get; } @@ -45,15 +43,9 @@ public MainWindow() AppWindow.SetIcon(AppLifecycleHelper.AppIconPath); } - /// - /// Set the application's culture to match the system's current UI culture. - /// This ensures that the correct language is applied to all UI elements. - /// private void SetAppCulture() { var culture = CultureInfo.CurrentUICulture; - - // Apply the system's UI culture across the application CultureInfo.DefaultThreadCurrentUICulture = culture; CultureInfo.DefaultThreadCurrentCulture = culture; ApplicationLanguages.PrimaryLanguageOverride = culture.Name; @@ -63,103 +55,135 @@ public void ShowSplashScreen() { var rootFrame = EnsureWindowIsInitialized(); - rootFrame?.Navigate(typeof(SplashScreenPage)); + if (rootFrame != null) + { + rootFrame.Navigate(typeof(SplashScreenPage)); + } } public async Task InitializeApplicationAsync(object activatedEventArgs) { var rootFrame = EnsureWindowIsInitialized(); - if (rootFrame is null) + if (rootFrame == null) return; // Set system backdrop SystemBackdrop = new AppSystemBackdrop(); - switch (activatedEventArgs) + try { - case ILaunchActivatedEventArgs launchArgs: - if (launchArgs.Arguments is not null && - (CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith($"files.exe", StringComparison.OrdinalIgnoreCase) - || CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith($"files", StringComparison.OrdinalIgnoreCase))) - { - var ppm = CommandLineParser.ParseUntrustedCommands(launchArgs.Arguments); - if (ppm.IsEmpty()) - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - else - await InitializeFromCmdLineArgsAsync(rootFrame, ppm); - } - else if (rootFrame.Content is null || rootFrame.Content is SplashScreenPage || !MainPageViewModel.AppInstances.Any()) - { - rootFrame.Navigate(typeof(MainPage), launchArgs.Arguments, new SuppressNavigationTransitionInfo()); - } - else if (!(string.IsNullOrEmpty(launchArgs.Arguments) && MainPageViewModel.AppInstances.Count > 0)) - { - Win32Helper.BringToForegroundEx(new(WindowHandle)); - await NavigationHelpers.AddNewTabByPathAsync(typeof(ShellPanesPage), launchArgs.Arguments, true); - } - else - { + switch (activatedEventArgs) + { + case ILaunchActivatedEventArgs launchArgs: + await HandleLaunchArgsAsync(rootFrame, launchArgs); + break; + + case IProtocolActivatedEventArgs protocolArgs: + await HandleProtocolArgsAsync(rootFrame, protocolArgs); + break; + + case IFileActivatedEventArgs fileArgs: + HandleFileArgs(rootFrame, fileArgs); + break; + + default: rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - } - break; + break; + } + } + catch (Exception ex) + { + // Log or handle exceptions accordingly + Console.WriteLine($"Error during initialization: {ex.Message}"); + } + } + + private async Task HandleLaunchArgsAsync(Frame rootFrame, ILaunchActivatedEventArgs launchArgs) + { + var args = CommandLineParser.SplitArguments(launchArgs.Arguments, true); + if (args.Length > 0 && + (args[0].EndsWith("files.exe", StringComparison.OrdinalIgnoreCase) || + args[0].EndsWith("files", StringComparison.OrdinalIgnoreCase))) + { + var ppm = CommandLineParser.ParseUntrustedCommands(launchArgs.Arguments); + if (ppm.IsEmpty()) + { + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + } + else + { + await InitializeFromCmdLineArgsAsync(rootFrame, ppm); + } + } + else if (rootFrame.Content is null || rootFrame.Content is SplashScreenPage || !MainPageViewModel.AppInstances.Any()) + { + rootFrame.Navigate(typeof(MainPage), launchArgs.Arguments, new SuppressNavigationTransitionInfo()); + } + else + { + Win32Helper.BringToForegroundEx(new(WindowHandle)); + await NavigationHelpers.AddNewTabByPathAsync(typeof(ShellPanesPage), launchArgs.Arguments, true); + } + } - case IProtocolActivatedEventArgs eventArgs: - if (eventArgs.Uri.AbsoluteUri == "files-uwp:") + private async Task HandleProtocolArgsAsync(Frame rootFrame, IProtocolActivatedEventArgs eventArgs) + { + if (eventArgs.Uri.AbsoluteUri == "files-uwp:") + { + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + if (MainPageViewModel.AppInstances.Count > 0) + { + Win32Helper.BringToForegroundEx(new(WindowHandle)); + } + } + else + { + var parsedArgs = eventArgs.Uri.Query.TrimStart('?').Split('='); + if (parsedArgs.Length == 2) + { + var unescapedValue = Uri.UnescapeDataString(parsedArgs[1]); + var folder = (StorageFolder)await FilesystemTasks.Wrap(() => StorageFolder.GetFolderFromPathAsync(unescapedValue).AsTask()); + if (folder != null && !string.IsNullOrEmpty(folder.Path)) { - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - if (MainPageViewModel.AppInstances.Count > 0) - { - Win32Helper.BringToForegroundEx(new(WindowHandle)); - } + unescapedValue = folder.Path; } - else + + switch (parsedArgs[0]) { - var parsedArgs = eventArgs.Uri.Query.TrimStart('?').Split('='); - var unescapedValue = Uri.UnescapeDataString(parsedArgs[1]); - var folder = (StorageFolder)await FilesystemTasks.Wrap(() => StorageFolder.GetFolderFromPathAsync(unescapedValue).AsTask()); - if (folder is not null && !string.IsNullOrEmpty(folder.Path)) - { - unescapedValue = folder.Path; - } - switch (parsedArgs[0]) - { - case "tab": - rootFrame.Navigate(typeof(MainPage), - new MainPageNavigationArguments() { Parameter = TabBarItemParameter.Deserialize(unescapedValue), IgnoreStartupSettings = true }, - new SuppressNavigationTransitionInfo()); - break; - - case "folder": - rootFrame.Navigate(typeof(MainPage), - new MainPageNavigationArguments() { Parameter = unescapedValue, IgnoreStartupSettings = true }, - new SuppressNavigationTransitionInfo()); - break; - - case "cmd": - var ppm = CommandLineParser.ParseUntrustedCommands(unescapedValue); - if (ppm.IsEmpty()) - rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - else - await InitializeFromCmdLineArgsAsync(rootFrame, ppm); - break; - default: + case "tab": + rootFrame.Navigate(typeof(MainPage), new MainPageNavigationArguments() { Parameter = TabBarItemParameter.Deserialize(unescapedValue), IgnoreStartupSettings = true }, new SuppressNavigationTransitionInfo()); + break; + + case "folder": + rootFrame.Navigate(typeof(MainPage), new MainPageNavigationArguments() { Parameter = unescapedValue, IgnoreStartupSettings = true }, new SuppressNavigationTransitionInfo()); + break; + + case "cmd": + var ppm = CommandLineParser.ParseUntrustedCommands(unescapedValue); + if (ppm.IsEmpty()) rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - break; - } - } - break; + else + await InitializeFromCmdLineArgsAsync(rootFrame, ppm); + break; - case IFileActivatedEventArgs fileArgs: - if (fileArgs.Files.Count > 0) - { - rootFrame.Navigate(typeof(MainPage), fileArgs.Files, new SuppressNavigationTransitionInfo()); + default: + rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); + break; } - break; - - default: + } + else + { rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - break; + } + } + } + + private void HandleFileArgs(Frame rootFrame, IFileActivatedEventArgs fileArgs) + { + if (fileArgs.Files.Count > 0) + { + rootFrame.Navigate(typeof(MainPage), fileArgs.Files, new SuppressNavigationTransitionInfo()); } } From 9801050728d7f201a295a5d573529a498c3f6705 Mon Sep 17 00:00:00 2001 From: Sanidhyafeaturist <141141037+Sanidhyafeaturist@users.noreply.github.com> Date: Sat, 19 Oct 2024 20:48:28 +0530 Subject: [PATCH 13/13] Update MainPage.xaml.cs --- src/Files.App/Views/MainPage.xaml.cs | 759 ++++++++------------------- 1 file changed, 216 insertions(+), 543 deletions(-) diff --git a/src/Files.App/Views/MainPage.xaml.cs b/src/Files.App/Views/MainPage.xaml.cs index 32e65474741b..389ac33460b4 100644 --- a/src/Files.App/Views/MainPage.xaml.cs +++ b/src/Files.App/Views/MainPage.xaml.cs @@ -21,569 +21,242 @@ namespace Files.App.Views { - public sealed partial class MainPage : Page - { - private IGeneralSettingsService generalSettingsService { get; } = Ioc.Default.GetRequiredService(); - public IUserSettingsService UserSettingsService { get; } - private readonly IWindowContext WindowContext = Ioc.Default.GetRequiredService(); - public ICommandManager Commands { get; } - public SidebarViewModel SidebarAdaptiveViewModel { get; } - public MainPageViewModel ViewModel { get; } - public StatusCenterViewModel OngoingTasksViewModel { get; } - - private bool keyReleased = true; - - private DispatcherQueueTimer _updateDateDisplayTimer; - - public MainPage() - { - InitializeComponent(); - - // Dependency Injection - UserSettingsService = Ioc.Default.GetRequiredService(); - Commands = Ioc.Default.GetRequiredService(); - SidebarAdaptiveViewModel = Ioc.Default.GetRequiredService(); - SidebarAdaptiveViewModel.PaneFlyout = (MenuFlyout)Resources["SidebarContextMenu"]; - ViewModel = Ioc.Default.GetRequiredService(); - OngoingTasksViewModel = Ioc.Default.GetRequiredService(); - - if (FilePropertiesHelpers.FlowDirectionSettingIsRightToLeft) - FlowDirection = FlowDirection.RightToLeft; - - ViewModel.PropertyChanged += ViewModel_PropertyChanged; - UserSettingsService.OnSettingChangedEvent += UserSettingsService_OnSettingChangedEvent; - - _updateDateDisplayTimer = DispatcherQueue.CreateTimer(); - _updateDateDisplayTimer.Interval = TimeSpan.FromSeconds(1); - _updateDateDisplayTimer.Tick += UpdateDateDisplayTimer_Tick; - -private void LoadPaneChanged() -{ - try + public sealed partial class MainPage : Page { - // Check if there is an active pane holder - if (SidebarAdaptiveViewModel.PaneHolder != null) + private IGeneralSettingsService generalSettingsService = Ioc.Default.GetRequiredService(); + public IUserSettingsService UserSettingsService { get; } + private readonly IWindowContext WindowContext = Ioc.Default.GetRequiredService(); + public ICommandManager Commands { get; } + public SidebarViewModel SidebarAdaptiveViewModel { get; } + public MainPageViewModel ViewModel { get; } + public StatusCenterViewModel OngoingTasksViewModel { get; } + + private bool keyReleased = true; + private DispatcherQueueTimer _updateDateDisplayTimer; + + public MainPage() { - // Determine if the current view is a home page or multi-pane - bool isHomePage = !(SidebarAdaptiveViewModel.PaneHolder.ActivePane.InstanceViewModel is not IShellPanesPage); - bool isMultiPane = SidebarAdaptiveViewModel.PaneHolder.IsMultiPaneActive; + InitializeComponent(); - // Check if the main window is sufficiently sized - bool isBigEnough = !App.AppModel.IsMainWindowClosed && - (MainWindow.Instance.Bounds.Width > 450 && MainWindow.Instance.Bounds.Height > 450 || - RootGrid.ActualWidth > 700 && MainWindow.Instance.Bounds.Height > 360); + UserSettingsService = Ioc.Default.GetRequiredService(); + Commands = Ioc.Default.GetRequiredService(); + SidebarAdaptiveViewModel = Ioc.Default.GetRequiredService(); + SidebarAdaptiveViewModel.PaneFlyout = (MenuFlyout)Resources["SidebarContextMenu"]; + ViewModel = Ioc.Default.GetRequiredService(); + OngoingTasksViewModel = Ioc.Default.GetRequiredService(); - // Determine if the preview pane should be displayed - ViewModel.ShouldPreviewPaneBeDisplayed = (!isHomePage || isMultiPane) && isBigEnough; - ViewModel.ShouldPreviewPaneBeActive = UserSettingsService.InfoPaneSettingsService.IsInfoPaneEnabled && ViewModel.ShouldPreviewPaneBeDisplayed; + if (FilePropertiesHelpers.FlowDirectionSettingIsRightToLeft) + FlowDirection = FlowDirection.RightToLeft; - // Update the status bar based on the active pane - UpdateStatusBarProperties(); + ViewModel.PropertyChanged += ViewModel_PropertyChanged; + UserSettingsService.OnSettingChangedEvent += UserSettingsService_OnSettingChangedEvent; - // Update navigation toolbar properties - UpdateNavToolbarProperties(); + _updateDateDisplayTimer = DispatcherQueue.CreateTimer(); + _updateDateDisplayTimer.Interval = TimeSpan.FromSeconds(1); + _updateDateDisplayTimer.Tick += UpdateDateDisplayTimer_Tick; + } - // Adjust pane positioning - UpdatePositioning(); + private void LoadPaneChanged() + { + try + { + if (SidebarAdaptiveViewModel.PaneHolder != null) + { + bool isHomePage = !(SidebarAdaptiveViewModel.PaneHolder.ActivePane.InstanceViewModel is not IShellPanesPage); + bool isMultiPane = SidebarAdaptiveViewModel.PaneHolder.IsMultiPaneActive; + bool isBigEnough = !App.AppModel.IsMainWindowClosed && + (MainWindow.Instance.Bounds.Width > 450 && MainWindow.Instance.Bounds.Height > 450 || + RootGrid.ActualWidth > 700 && MainWindow.Instance.Bounds.Height > 360); + + ViewModel.ShouldPreviewPaneBeDisplayed = (!isHomePage || isMultiPane) && isBigEnough; + ViewModel.ShouldPreviewPaneBeActive = UserSettingsService.InfoPaneSettingsService.IsInfoPaneEnabled && ViewModel.ShouldPreviewPaneBeDisplayed; + + UpdateStatusBarProperties(); + UpdateNavToolbarProperties(); + UpdatePositioning(); + } + } + catch (Exception ex) + { + App.Logger.LogWarning(ex, "Error while loading pane changes: {Message}", ex.Message); + } } - } - catch (Exception ex) - { - // Log any exceptions that occur during pane loading - App.Logger.LogWarning(ex, "Error while loading pane changes: {Message}", ex.Message); - } -} - - } + private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + switch (e.PropertyName) + { + case nameof(ViewModel.ShouldPreviewPaneBeActive): + if (ViewModel.ShouldPreviewPaneBeActive) + { + var infoPaneViewModel = Ioc.Default.GetRequiredService(); + infoPaneViewModel.UpdateSelectedItemPreviewAsync(); + } + break; + + case nameof(ViewModel.ShouldViewControlBeDisplayed): + ViewControl.Visibility = ViewModel.ShouldViewControlBeDisplayed ? Visibility.Visible : Visibility.Collapsed; + break; + + case nameof(ViewModel.MultitaskingControl): + UpdateMultitaskingControl(ViewModel.MultitaskingControl); + break; + + case nameof(ViewModel.SelectedTabIndex): + UpdateTabSelection(ViewModel.SelectedTabIndex); + break; + } + } - private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) -{ - switch (e.PropertyName) - { - case nameof(ViewModel.ShouldPreviewPaneBeActive): - if (ViewModel.ShouldPreviewPaneBeActive) + private void UpdateMultitaskingControl(object multitaskingControl) + { + if (multitaskingControl is TabBar tabBar) + { + TabControl.ItemsSource = tabBar.Items; + } + } + + private void UpdateTabSelection(int selectedIndex) + { + TabControl.SelectedIndex = selectedIndex; + } + + private async Task PromptForReviewAsync() + { + var promptForReviewDialog = new ContentDialog + { + Title = "ReviewFiles", + Content = "ReviewFilesContent", + PrimaryButtonText = "Yes", + SecondaryButtonText = "No" + }; + + if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) + promptForReviewDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot; + + var result = await promptForReviewDialog.TryShowAsync(); + + if (result == ContentDialogResult.Primary) + { + try + { + var storeContext = StoreContext.GetDefault(); + InitializeWithWindow.Initialize(storeContext, MainWindow.Instance.WindowHandle); + var storeRateAndReviewResult = await storeContext.RequestRateAndReviewAppAsync(); + + App.Logger.LogInformation($"STORE: review request status: {storeRateAndReviewResult.Status}"); + + UserSettingsService.ApplicationSettingsService.ClickedToReviewApp = true; + } + catch (Exception) { } + } + } + + private async Task AppRunningAsAdminPromptAsync() + { + var runningAsAdminPrompt = new ContentDialog + { + Title = "FilesRunningAsAdmin", + Content = "FilesRunningAsAdminContent", + PrimaryButtonText = "Ok", + SecondaryButtonText = "DontShowAgain" + }; + + var result = await SetContentDialogRoot(runningAsAdminPrompt).TryShowAsync(); + + if (result == ContentDialogResult.Secondary) + UserSettingsService.ApplicationSettingsService.ShowRunningAsAdminPrompt = false; + } + + private ContentDialog SetContentDialogRoot(ContentDialog contentDialog) + { + if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) + contentDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot; + + return contentDialog; + } + + private void UserSettingsService_OnSettingChangedEvent(object? sender, SettingChangedEventArgs e) + { + if (e.SettingName == nameof(IInfoPaneSettingsService.IsInfoPaneEnabled)) { - // Load the preview pane with the selected item details - var infoPaneViewModel = Ioc.Default.GetRequiredService(); - infoPaneViewModel.UpdateSelectedItemPreviewAsync(); + LoadPaneChanged(); } - break; - - case nameof(ViewModel.ShouldViewControlBeDisplayed): - if (ViewModel.ShouldViewControlBeDisplayed) + } + + private void HorizontalMultitaskingControl_Loaded(object sender, RoutedEventArgs e) + { + TabControl.DragArea.SizeChanged += (_, _) => MainWindow.Instance.RaiseSetTitleBarDragRegion(SetTitleBarDragRegion); + if (ViewModel.MultitaskingControl is not TabBar) { - // Show view control - ViewControl.Visibility = Visibility.Visible; + ViewModel.MultitaskingControl = TabControl; + ViewModel.MultitaskingControls.Add(TabControl); + ViewModel.MultitaskingControl.CurrentInstanceChanged += MultitaskingControl_CurrentInstanceChanged; } - else + } + + private int SetTitleBarDragRegion(InputNonClientPointerSource source, SizeInt32 size, double scaleFactor, Func getScaledRect) + { + var height = (int)TabControl.ActualHeight; + source.SetRegionRects(NonClientRegionKind.Passthrough, [getScaledRect(this, new RectInt32(0, 0, (int)(TabControl.ActualWidth + TabControl.Margin.Left - TabControl.DragArea.ActualWidth), height))]); + return height; + } + + public async void TabItemContent_ContentChanged(object? sender, TabBarItemParameter e) + { + if (SidebarAdaptiveViewModel.PaneHolder is null) + return; + + var paneArgs = e.NavigationParameter as PaneNavigationArguments; + SidebarAdaptiveViewModel.UpdateSidebarSelectedItemFromArgs(SidebarAdaptiveViewModel.PaneHolder.IsLeftPaneActive ? + paneArgs?.LeftPaneNavPathParam : paneArgs?.RightPaneNavPathParam); + + UpdateStatusBarProperties(); + LoadPaneChanged(); + UpdateNavToolbarProperties(); + await NavigationHelpers.UpdateInstancePropertiesAsync(paneArgs); + + AppLifecycleHelper.SaveSessionTabs(); + LoadPaneChanged(); + } + + public async void MultitaskingControl_CurrentInstanceChanged(object? sender, CurrentInstanceChangedEventArgs e) + { + if (SidebarAdaptiveViewModel.PaneHolder is not null) + SidebarAdaptiveViewModel.PaneHolder.PropertyChanged -= PaneHolder_PropertyChanged; + + var navArgs = e.CurrentInstance.TabBarItemParameter?.NavigationParameter; + if (e.CurrentInstance is IShellPanesPage currentInstance) { - // Hide view control - ViewControl.Visibility = Visibility.Collapsed; + SidebarAdaptiveViewModel.PaneHolder = currentInstance; + SidebarAdaptiveViewModel.PaneHolder.PropertyChanged += PaneHolder_PropertyChanged; } - break; - - case nameof(ViewModel.MultitaskingControl): - // Update the multitasking control UI - UpdateMultitaskingControl(ViewModel.MultitaskingControl); - break; - - case nameof(ViewModel.SelectedTabIndex): - // Logic for when the selected tab index changes - UpdateTabSelection(ViewModel.SelectedTabIndex); - break; - } -} + SidebarAdaptiveViewModel.NotifyInstanceRelatedPropertiesChanged((navArgs as PaneNavigationArguments)?.LeftPaneNavPathParam); + if (SidebarAdaptiveViewModel.PaneHolder?.ActivePaneOrColumn.SlimContentPage?.StatusBarViewModel is not null) + SidebarAdaptiveViewModel.PaneHolder.ActivePaneOrColumn.SlimContentPage.StatusBarViewModel.ShowLocals = true; -private void UpdateMultitaskingControl(object multitaskingControl) -{ - // Logic to refresh the multitasking UI - if (multitaskingControl is TabBar tabBar) - { - // Update the tab bar with the new multitasking control - TabControl.ItemsSource = tabBar.Items; - } -} + UpdateStatusBarProperties(); + UpdateNavToolbarProperties(); + LoadPaneChanged(); -private void UpdateTabSelection(int selectedIndex) -{ - // Logic to update UI based on selected tab - TabControl.SelectedIndex = selectedIndex; -} + e.CurrentInstance.ContentChanged -= TabItemContent_ContentChanged; + e.CurrentInstance.ContentChanged += TabItemContent_ContentChanged; + + await NavigationHelpers.UpdateInstancePropertiesAsync(navArgs); + } + private void PaneHolder_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + SidebarAdaptiveViewModel.NotifyInstanceRelatedPropertiesChanged(SidebarAdaptiveViewModel.PaneHolder.ActivePane?.TabBarItemParameter?.NavigationParameter); + UpdateStatusBarProperties(); + UpdateNavToolbarProperties(); + } - private async Task PromptForReviewAsync() - { - var promptForReviewDialog = new ContentDialog - { - Title = "ReviewFiles".ToLocalized(), - Content = "ReviewFilesContent".ToLocalized(), - PrimaryButtonText = "Yes".ToLocalized(), - SecondaryButtonText = "No".ToLocalized() - }; - - if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) - promptForReviewDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot; - - var result = await promptForReviewDialog.TryShowAsync(); - - if (result == ContentDialogResult.Primary) - { - try - { - var storeContext = StoreContext.GetDefault(); - InitializeWithWindow.Initialize(storeContext, MainWindow.Instance.WindowHandle); - var storeRateAndReviewResult = await storeContext.RequestRateAndReviewAppAsync(); - - App.Logger.LogInformation($"STORE: review request status: {storeRateAndReviewResult.Status}"); - - UserSettingsService.ApplicationSettingsService.ClickedToReviewApp = true; - } - catch (Exception) { } - } - } - - private async Task AppRunningAsAdminPromptAsync() - { - var runningAsAdminPrompt = new ContentDialog - { - Title = "FilesRunningAsAdmin".ToLocalized(), - Content = "FilesRunningAsAdminContent".ToLocalized(), - PrimaryButtonText = "Ok".ToLocalized(), - SecondaryButtonText = "DontShowAgain".ToLocalized() - }; - - var result = await SetContentDialogRoot(runningAsAdminPrompt).TryShowAsync(); - - if (result == ContentDialogResult.Secondary) - UserSettingsService.ApplicationSettingsService.ShowRunningAsAdminPrompt = false; - } - - // WINUI3 - private ContentDialog SetContentDialogRoot(ContentDialog contentDialog) - { - if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) - contentDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot; - - return contentDialog; - } - - private void UserSettingsService_OnSettingChangedEvent(object? sender, SettingChangedEventArgs e) - { - switch (e.SettingName) - { - case nameof(IInfoPaneSettingsService.IsInfoPaneEnabled): - LoadPaneChanged(); - break; - } - } - - private void HorizontalMultitaskingControl_Loaded(object sender, RoutedEventArgs e) - { - TabControl.DragArea.SizeChanged += (_, _) => MainWindow.Instance.RaiseSetTitleBarDragRegion(SetTitleBarDragRegion); - if (ViewModel.MultitaskingControl is not TabBar) - { - ViewModel.MultitaskingControl = TabControl; - ViewModel.MultitaskingControls.Add(TabControl); - ViewModel.MultitaskingControl.CurrentInstanceChanged += MultitaskingControl_CurrentInstanceChanged; - } - } - - private int SetTitleBarDragRegion(InputNonClientPointerSource source, SizeInt32 size, double scaleFactor, Func getScaledRect) - { - var height = (int)TabControl.ActualHeight; - source.SetRegionRects(NonClientRegionKind.Passthrough, [getScaledRect(this, new RectInt32(0, 0, (int)(TabControl.ActualWidth + TabControl.Margin.Left - TabControl.DragArea.ActualWidth), height))]); - return height; - } - - public async void TabItemContent_ContentChanged(object? sender, TabBarItemParameter e) - { - if (SidebarAdaptiveViewModel.PaneHolder is null) - return; - - var paneArgs = e.NavigationParameter as PaneNavigationArguments; - SidebarAdaptiveViewModel.UpdateSidebarSelectedItemFromArgs(SidebarAdaptiveViewModel.PaneHolder.IsLeftPaneActive ? - paneArgs?.LeftPaneNavPathParam : paneArgs?.RightPaneNavPathParam); - - UpdateStatusBarProperties(); - LoadPaneChanged(); - UpdateNavToolbarProperties(); - await NavigationHelpers.UpdateInstancePropertiesAsync(paneArgs); - - // Save the updated tab list - AppLifecycleHelper.SaveSessionTabs(); - - // Call LoadPaneChanged to update the UI as needed - LoadPaneChanged(); - } - - public async void MultitaskingControl_CurrentInstanceChanged(object? sender, CurrentInstanceChangedEventArgs e) - { - if (SidebarAdaptiveViewModel.PaneHolder is not null) - SidebarAdaptiveViewModel.PaneHolder.PropertyChanged -= PaneHolder_PropertyChanged; - - var navArgs = e.CurrentInstance.TabBarItemParameter?.NavigationParameter; - if (e.CurrentInstance is IShellPanesPage currentInstance) - { - SidebarAdaptiveViewModel.PaneHolder = currentInstance; - SidebarAdaptiveViewModel.PaneHolder.PropertyChanged += PaneHolder_PropertyChanged; - } - SidebarAdaptiveViewModel.NotifyInstanceRelatedPropertiesChanged((navArgs as PaneNavigationArguments)?.LeftPaneNavPathParam); - - if (SidebarAdaptiveViewModel.PaneHolder?.ActivePaneOrColumn.SlimContentPage?.StatusBarViewModel is not null) - SidebarAdaptiveViewModel.PaneHolder.ActivePaneOrColumn.SlimContentPage.StatusBarViewModel.ShowLocals = true; - - UpdateStatusBarProperties(); - UpdateNavToolbarProperties(); - LoadPaneChanged(); - - e.CurrentInstance.ContentChanged -= TabItemContent_ContentChanged; - e.CurrentInstance.ContentChanged += TabItemContent_ContentChanged; - - await NavigationHelpers.UpdateInstancePropertiesAsync(navArgs); - } - - private void PaneHolder_PropertyChanged(object? sender, PropertyChangedEventArgs e) - { - SidebarAdaptiveViewModel.NotifyInstanceRelatedPropertiesChanged(SidebarAdaptiveViewModel.PaneHolder.ActivePane?.TabBarItemParameter?.NavigationParameter?.ToString()); - UpdateStatusBarProperties(); - UpdateNavToolbarProperties(); - LoadPaneChanged(); - } - - private void UpdateStatusBarProperties() - { - if (StatusBar is not null) - { - StatusBar.StatusBarViewModel = SidebarAdaptiveViewModel.PaneHolder?.ActivePaneOrColumn.SlimContentPage?.StatusBarViewModel; - StatusBar.SelectedItemsPropertiesViewModel = SidebarAdaptiveViewModel.PaneHolder?.ActivePaneOrColumn.SlimContentPage?.SelectedItemsPropertiesViewModel; - } - } - - private void UpdateNavToolbarProperties() - { - if (NavToolbar is not null) - NavToolbar.ViewModel = SidebarAdaptiveViewModel.PaneHolder?.ActivePaneOrColumn.ToolbarViewModel; - - if (InnerNavigationToolbar is not null) - InnerNavigationToolbar.ViewModel = SidebarAdaptiveViewModel.PaneHolder?.ActivePaneOrColumn.ToolbarViewModel; - } - - protected override void OnNavigatedTo(NavigationEventArgs e) - { - ViewModel.OnNavigatedToAsync(e); - } - - protected override async void OnPreviewKeyDown(KeyRoutedEventArgs e) => await OnPreviewKeyDownAsync(e); - - private async Task OnPreviewKeyDownAsync(KeyRoutedEventArgs e) - { - base.OnPreviewKeyDown(e); - - switch (e.Key) - { - case VirtualKey.Menu: - case VirtualKey.Control: - case VirtualKey.Shift: - case VirtualKey.LeftWindows: - case VirtualKey.RightWindows: - break; - default: - var currentModifiers = HotKeyHelpers.GetCurrentKeyModifiers(); - HotKey hotKey = new((Keys)e.Key, currentModifiers); - - // A textbox takes precedence over certain hotkeys. - if (e.OriginalSource is DependencyObject source && source.FindAscendantOrSelf() is not null) - break; - - // Execute command for hotkey - var command = Commands[hotKey]; - if (command.Code is not CommandCodes.None && keyReleased) - { - keyReleased = false; - e.Handled = command.IsExecutable; - await command.ExecuteAsync(); - } - break; - } - } - - protected override void OnPreviewKeyUp(KeyRoutedEventArgs e) - { - base.OnPreviewKeyUp(e); - - switch (e.Key) - { - case VirtualKey.Menu: - case VirtualKey.Control: - case VirtualKey.Shift: - case VirtualKey.LeftWindows: - case VirtualKey.RightWindows: - break; - default: - keyReleased = true; - break; - } - } - - // A workaround for issue with OnPreviewKeyUp not being called when the hotkey displays a dialog - protected override void OnLostFocus(RoutedEventArgs e) - { - base.OnLostFocus(e); - - keyReleased = true; - } - - private void Page_Loaded(object sender, RoutedEventArgs e) - { - MainWindow.Instance.AppWindow.Changed += (_, _) => MainWindow.Instance.RaiseSetTitleBarDragRegion(SetTitleBarDragRegion); - - // Defers the status bar loading until after the page has loaded to improve startup perf - FindName(nameof(StatusBar)); - FindName(nameof(InnerNavigationToolbar)); - FindName(nameof(TabControl)); - FindName(nameof(NavToolbar)); - - // Notify user that drag and drop is disabled - // Prompt is disabled in the dev environment to prevent issues with the automation testing - // ToDo put this in a StartupPromptService - if - ( - AppLifecycleHelper.AppEnvironment is not AppEnvironment.Dev && - WindowContext.IsRunningAsAdmin && - UserSettingsService.ApplicationSettingsService.ShowRunningAsAdminPrompt - ) - { - DispatcherQueue.TryEnqueue(async () => await AppRunningAsAdminPromptAsync()); - } - - // ToDo put this in a StartupPromptService - if (Package.Current.Id.Name != "49306atecsolution.FilesUWP" || UserSettingsService.ApplicationSettingsService.ClickedToReviewApp) - return; - - var totalLaunchCount = SystemInformation.Instance.TotalLaunchCount; - if (totalLaunchCount is 15 or 30 or 60) - { - // Prompt user to review app in the Store - DispatcherQueue.TryEnqueue(async () => await PromptForReviewAsync()); - } - } - - private void PreviewPane_Loaded(object sender, RoutedEventArgs e) - { - _updateDateDisplayTimer.Start(); - } - - private void PreviewPane_Unloaded(object sender, RoutedEventArgs e) - { - _updateDateDisplayTimer.Stop(); - } - - private void UpdateDateDisplayTimer_Tick(object sender, object e) - { - if (!App.AppModel.IsMainWindowClosed) - InfoPane?.ViewModel.UpdateDateDisplay(); - } - - private void Page_SizeChanged(object sender, SizeChangedEventArgs e) - { - switch (InfoPane?.Position) - { - case PreviewPanePositions.Right when ContentColumn.ActualWidth == ContentColumn.MinWidth: - UserSettingsService.InfoPaneSettingsService.VerticalSizePx += e.NewSize.Width - e.PreviousSize.Width; - UpdatePositioning(); - break; - case PreviewPanePositions.Bottom when ContentRow.ActualHeight == ContentRow.MinHeight: - UserSettingsService.InfoPaneSettingsService.HorizontalSizePx += e.NewSize.Height - e.PreviousSize.Height; - UpdatePositioning(); - break; - } - } - - private void SidebarControl_Loaded(object sender, RoutedEventArgs e) - { - // Set the correct tab margin on startup - SidebarAdaptiveViewModel.UpdateTabControlMargin(); - } - - private void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e) => LoadPaneChanged(); - - /// - /// Call this function to update the positioning of the preview pane. - /// This is a workaround as the VisualStateManager causes problems. - /// - private void UpdatePositioning() - { - if (InfoPane is null || !ViewModel.ShouldPreviewPaneBeActive) - { - PaneRow.MinHeight = 0; - PaneRow.MaxHeight = double.MaxValue; - PaneRow.Height = new GridLength(0); - PaneColumn.MinWidth = 0; - PaneColumn.MaxWidth = double.MaxValue; - PaneColumn.Width = new GridLength(0); - } - else - { - InfoPane.UpdatePosition(RootGrid.ActualWidth, RootGrid.ActualHeight); - switch (InfoPane.Position) - { - case PreviewPanePositions.None: - PaneRow.MinHeight = 0; - PaneRow.Height = new GridLength(0); - PaneColumn.MinWidth = 0; - PaneColumn.Width = new GridLength(0); - break; - case PreviewPanePositions.Right: - InfoPane.SetValue(Grid.RowProperty, 1); - InfoPane.SetValue(Grid.ColumnProperty, 2); - PaneSplitter.SetValue(Grid.RowProperty, 1); - PaneSplitter.SetValue(Grid.ColumnProperty, 1); - PaneSplitter.Width = 2; - PaneSplitter.Height = RootGrid.ActualHeight; - PaneSplitter.GripperCursor = GridSplitter.GripperCursorType.SizeWestEast; - PaneSplitter.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.SizeWestEast)); - PaneColumn.MinWidth = InfoPane.MinWidth; - PaneColumn.MaxWidth = InfoPane.MaxWidth; - PaneColumn.Width = new GridLength(UserSettingsService.InfoPaneSettingsService.VerticalSizePx, GridUnitType.Pixel); - PaneRow.MinHeight = 0; - PaneRow.MaxHeight = double.MaxValue; - PaneRow.Height = new GridLength(0); - break; - case PreviewPanePositions.Bottom: - InfoPane.SetValue(Grid.RowProperty, 3); - InfoPane.SetValue(Grid.ColumnProperty, 0); - PaneSplitter.SetValue(Grid.RowProperty, 2); - PaneSplitter.SetValue(Grid.ColumnProperty, 0); - PaneSplitter.Height = 2; - PaneSplitter.Width = RootGrid.ActualWidth; - PaneSplitter.GripperCursor = GridSplitter.GripperCursorType.SizeNorthSouth; - PaneSplitter.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.SizeNorthSouth)); - PaneColumn.MinWidth = 0; - PaneColumn.MaxWidth = double.MaxValue; - PaneColumn.Width = new GridLength(0); - PaneRow.MinHeight = InfoPane.MinHeight; - PaneRow.MaxHeight = InfoPane.MaxHeight; - PaneRow.Height = new GridLength(UserSettingsService.InfoPaneSettingsService.HorizontalSizePx, GridUnitType.Pixel); - break; - } - } - } - - private void PaneSplitter_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) - { - switch (InfoPane?.Position) - { - case PreviewPanePositions.Right: - UserSettingsService.InfoPaneSettingsService.VerticalSizePx = InfoPane.ActualWidth; - break; - case PreviewPanePositions.Bottom: - UserSettingsService.InfoPaneSettingsService.HorizontalSizePx = InfoPane.ActualHeight; - break; - } - - this.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.Arrow)); - } - - private void LoadPaneChanged() - { - try - { - var isHomePage = !(SidebarAdaptiveViewModel.PaneHolder?.ActivePane?.InstanceViewModel?.IsPageTypeNotHome ?? false); - var isMultiPane = SidebarAdaptiveViewModel.PaneHolder?.IsMultiPaneActive ?? false; - var isBigEnough = !App.AppModel.IsMainWindowClosed && - (MainWindow.Instance.Bounds.Width > 450 && MainWindow.Instance.Bounds.Height > 450 || RootGrid.ActualWidth > 700 && MainWindow.Instance.Bounds.Height > 360); - - ViewModel.ShouldPreviewPaneBeDisplayed = (!isHomePage || isMultiPane) && isBigEnough; - ViewModel.ShouldPreviewPaneBeActive = UserSettingsService.InfoPaneSettingsService.IsInfoPaneEnabled && ViewModel.ShouldPreviewPaneBeDisplayed; - ViewModel.ShouldViewControlBeDisplayed = SidebarAdaptiveViewModel.PaneHolder?.ActivePane?.InstanceViewModel?.IsPageTypeNotHome ?? false; - - UpdatePositioning(); - } - catch (Exception ex) - { - // Handle exception in case WinUI Windows is closed - // (see https://github.com/files-community/Files/issues/15599) - - App.Logger.LogWarning(ex, ex.Message); - } - } - - private async void ViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(ViewModel.ShouldPreviewPaneBeActive) && ViewModel.ShouldPreviewPaneBeActive) - await Ioc.Default.GetRequiredService().UpdateSelectedItemPreviewAsync(); - } - - private void RootGrid_PreviewKeyDown(object sender, KeyRoutedEventArgs e) - { - switch (e.Key) - { - case VirtualKey.Menu: - case VirtualKey.Control: - case VirtualKey.Shift: - case VirtualKey.LeftWindows: - case VirtualKey.RightWindows: - break; - default: - var currentModifiers = HotKeyHelpers.GetCurrentKeyModifiers(); - HotKey hotKey = new((Keys)e.Key, currentModifiers); - - // Prevents the arrow key events from navigating the list instead of switching compact overlay - if (Commands[hotKey].Code is CommandCodes.EnterCompactOverlay or CommandCodes.ExitCompactOverlay) - Focus(FocusState.Keyboard); - break; - } - } - - private void NavToolbar_Loaded(object sender, RoutedEventArgs e) => UpdateNavToolbarProperties(); - - private void PaneSplitter_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e) - { - this.ChangeCursor(InputSystemCursor.Create(PaneSplitter.GripperCursor == GridSplitter.GripperCursorType.SizeWestEast ? - InputSystemCursorShape.SizeWestEast : InputSystemCursorShape.SizeNorthSouth)); - } - } + private void UpdateDateDisplayTimer_Tick(object? sender, object e) + { + ViewModel.UpdateDateDisplay(); + } + } }