diff --git a/src/Files.App/App.xaml b/src/Files.App/App.xaml index aa4e10a5ea79..4b46b5bb8077 100644 --- a/src/Files.App/App.xaml +++ b/src/Files.App/App.xaml @@ -5,6 +5,7 @@ + 36 @@ -75,6 +76,7 @@ + - \ No newline at end of file + diff --git a/src/Files.App/App.xaml.cs b/src/Files.App/App.xaml.cs index 75248cba6c3e..1eef42a97d81 100644 --- a/src/Files.App/App.xaml.cs +++ b/src/Files.App/App.xaml.cs @@ -48,12 +48,8 @@ using Windows.Storage; using Windows.UI.Notifications; - namespace Files.App { - /// - /// Provides application-specific behavior to supplement the default Application class. - /// public partial class App : Application { private static bool ShowErrorNotification = false; @@ -140,10 +136,12 @@ await Task.WhenAll( OptionalTask(FileTagsManager.UpdateFileTagsAsync(), preferencesSettingsService.ShowFileTagsSection), QuickAccessManager.InitializeAsync() ); + await Task.WhenAll( JumpListHelper.InitializeUpdatesAsync(), addItemService.GetNewEntriesAsync() ); + FileTagsHelper.UpdateTagsDb(); }); @@ -233,10 +231,12 @@ protected override void OnLaunched(LaunchActivatedEventArgs e) .AddSingleton() ) .Build(); + Logger = host.Services.GetRequiredService>(); App.Logger.LogInformation($"App launched. Launch args type: {activatedEventArgs.Data.GetType().Name}"); Ioc.Default.ConfigureServices(host.Services); + EnsureSettingsAndConfigurationAreBootstrapped(); _ = InitializeAppComponentsAsync().ContinueWith(t => Logger.LogWarning(t.Exception, "Error during InitializeAppComponentsAsync()"), TaskContinuationOptions.OnlyOnFaulted); @@ -266,6 +266,7 @@ public void OnActivated(AppActivationArguments activatedEventArgs) { App.Logger.LogInformation($"App activated. Activated args type: {activatedEventArgs.Data.GetType().Name}"); var data = activatedEventArgs.Data; + // InitializeApplication accesses UI, needs to be called on UI thread _ = Window.DispatcherQueue.EnqueueAsync(() => Window.InitializeApplication(data)); } @@ -288,7 +289,8 @@ private async void Window_Closed(object sender, WindowEventArgs args) return; } - await Task.Yield(); // Method can take a long time, make sure the window is hidden + // Method can take a long time, make sure the window is hidden + await Task.Yield(); SaveSessionTabs(); @@ -299,11 +301,14 @@ await SafetyExtensions.IgnoreExceptions(async () => var instance = MainPageViewModel.AppInstances.FirstOrDefault(x => x.Control.TabItemContent.IsCurrentInstance); if (instance is null) return; + var items = (instance.Control.TabItemContent as PaneHolderPage)?.ActivePane?.SlimContentPage?.SelectedItems; if (items is null) return; + await FileIO.WriteLinesAsync(await StorageFile.GetFileFromPathAsync(OutputPath), items.Select(x => x.ItemPath)); - }, Logger); + }, + Logger); } DrivesManager?.Dispose(); @@ -317,13 +322,17 @@ await SafetyExtensions.IgnoreExceptions(async () => if (dataPackage.Contains(StandardDataFormats.StorageItems)) Clipboard.Flush(); } - }, Logger); + }, + Logger); // Wait for ongoing file operations FileOperationsHelpers.WaitForCompletion(); } - public static void SaveSessionTabs() // Enumerates through all tabs and gets the Path property and saves it to AppSettings.LastSessionPages + /// + /// Enumerates through all tabs and gets the Path property and saves it to AppSettings.LastSessionPages. + /// + public static void SaveSessionTabs() { IUserSettingsService userSettingsService = Ioc.Default.GetRequiredService(); IBundlesSettingsService bundlesSettingsService = Ioc.Default.GetRequiredService(); @@ -341,21 +350,33 @@ public static void SaveSessionTabs() // Enumerates through all tabs and gets the var defaultArg = new TabItemArguments() { InitialPageType = typeof(PaneHolderPage), NavigationArg = "Home" }; return defaultArg.Serialize(); } - }).ToList(); + }) + .ToList(); } - // Occurs when an exception is not handled on the UI thread. - private static void OnUnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) => AppUnhandledException(e.Exception, true); + /// + /// Occurs when an exception is not handled on the UI thread. + /// + /// + /// + private static void OnUnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) + => AppUnhandledException(e.Exception, true); - // Occurs when an exception is not handled on a background thread. - // ie. A task is fired and forgotten Task.Run(() => {...}) - private static void OnUnobservedException(object sender, UnobservedTaskExceptionEventArgs e) => AppUnhandledException(e.Exception, false); + /// + /// Occurs when an exception is not handled on a background thread. + /// i.e. A task is fired and forgotten Task.Run(() => {...}) + /// + /// + /// + private static void OnUnobservedException(object sender, UnobservedTaskExceptionEventArgs e) + => AppUnhandledException(e.Exception, false); private static void AppUnhandledException(Exception ex, bool shouldShowNotification) { StringBuilder formattedException = new StringBuilder() { Capacity = 200 }; formattedException.Append("--------- UNHANDLED EXCEPTION ---------"); + if (ex is not null) { formattedException.Append($"\n>>>> HRESULT: {ex.HResult}\n"); @@ -389,7 +410,8 @@ private static void AppUnhandledException(Exception ex, bool shouldShowNotificat Debug.WriteLine(formattedException.ToString()); - Debugger.Break(); // Please check "Output Window" for exception details (View -> Output Window) (CTRL + ALT + O) + // Please check "Output Window" for exception details (View -> Output Window) (CTRL + ALT + O) + Debugger.Break(); SaveSessionTabs(); App.Logger.LogError(ex, ex.Message); @@ -399,7 +421,7 @@ private static void AppUnhandledException(Exception ex, bool shouldShowNotificat var toastContent = new ToastContent() { - Visual = new ToastVisual() + Visual = new() { BindingGeneric = new ToastBindingGeneric() { @@ -414,7 +436,7 @@ private static void AppUnhandledException(Exception ex, bool shouldShowNotificat Text = "ExceptionNotificationBody".GetLocalizedResource() } }, - AppLogoOverride = new ToastGenericAppLogo() + AppLogoOverride = new() { Source = "ms-appx:///Assets/error.png" } @@ -440,9 +462,7 @@ private static void AppUnhandledException(Exception ex, bool shouldShowNotificat } public static void CloseApp() - { - Window.Close(); - } + => Window.Close(); public static AppWindow GetAppWindow(Window w) { diff --git a/src/Files.App/BaseLayout.cs b/src/Files.App/BaseLayout.cs index c40906ede46b..fbde2c345616 100644 --- a/src/Files.App/BaseLayout.cs +++ b/src/Files.App/BaseLayout.cs @@ -515,9 +515,7 @@ navigationArguments.SelectItems is not null && ItemManipulationModel.FocusFileList(); } } - catch (Exception) - { - } + catch (Exception) { } } private CancellationTokenSource? groupingCancellationToken; @@ -565,7 +563,8 @@ public async void ItemContextFlyout_Opening(object? sender, object e) try { - if (!IsItemSelected && ((sender as CommandBarFlyout)?.Target as ListViewItem)?.Content is ListedItem li) // Workaround for item sometimes not getting selected + // Workaround for item sometimes not getting selected + if (!IsItemSelected && (sender as CommandBarFlyout)?.Target is ListViewItem { Content: ListedItem li }) ItemManipulationModel.SetSelectedItem(li); if (IsItemSelected) @@ -654,10 +653,13 @@ private async Task LoadMenuItemsAsync() shellContextMenuItemCancellationToken?.Cancel(); shellContextMenuItemCancellationToken = new CancellationTokenSource(); SelectedItemsPropertiesViewModel.CheckAllFileExtensions(SelectedItems!.Select(selectedItem => selectedItem?.FileExtension).ToList()!); + var shiftPressed = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down); var items = ContextFlyoutItemHelper.GetItemContextCommandsWithoutShellItems(currentInstanceViewModel: InstanceViewModel!, selectedItems: SelectedItems!, selectedItemsPropertiesViewModel: SelectedItemsPropertiesViewModel, commandsViewModel: CommandsViewModel!, shiftPressed: shiftPressed, itemViewModel: null); + ItemContextMenuFlyout.PrimaryCommands.Clear(); ItemContextMenuFlyout.SecondaryCommands.Clear(); + var (primaryElements, secondaryElements) = ItemModelListToContextFlyoutHelper.GetAppBarItemsFromModel(items); AddCloseHandler(ItemContextMenuFlyout, primaryElements, secondaryElements); primaryElements.ForEach(ItemContextMenuFlyout.PrimaryCommands.Add); @@ -747,7 +749,7 @@ private async Task AddShellMenuItemsAsync(List s var requiredHeight = contextMenuFlyout.SecondaryCommands.Concat(mainItems).Where(x => x is not AppBarSeparator).Count() * Constants.UI.ContextMenuSecondaryItemsHeight; var availableHeight = App.Window.Bounds.Height - cMenuPos.Y - Constants.UI.ContextMenuPrimaryItemsHeight; - // Set menu max height to current height (avoids menu repositioning) + // Set menu max height to current height (Avoid menu repositioning) if (requiredHeight > availableHeight) itemsControl.MaxHeight = Math.Min(Constants.UI.ContextMenuMaxHeight, Math.Max(itemsControl.ActualHeight, Math.Min(availableHeight, requiredHeight))); @@ -854,34 +856,31 @@ private async Task AddShellMenuItemsAsync(List s ShellContextmenuHelper.AddItemsToOverflowMenu(overflowItem, x); }); - if (itemsControl is not null) + itemsControl?.Items.OfType().ForEach(item => { - itemsControl.Items.OfType().ForEach(item => - { - // Enable CharacterEllipsis text trimming for menu items - if (item.FindDescendant("OverflowTextLabel") is TextBlock label) - label.TextTrimming = TextTrimming.CharacterEllipsis; + // Enable CharacterEllipsis text trimming for menu items + if (item.FindDescendant("OverflowTextLabel") is TextBlock label) + label.TextTrimming = TextTrimming.CharacterEllipsis; - // Close main menu when clicking on subitems (#5508) - if ((item as AppBarButton)?.Flyout as MenuFlyout is MenuFlyout flyout) + // Close main menu when clicking on subitems (#5508) + if ((item as AppBarButton)?.Flyout as MenuFlyout is MenuFlyout flyout) + { + Action> clickAction = null!; + clickAction = (items) => { - Action> clickAction = null!; - clickAction = (items) => + items.OfType().ForEach(i => { - items.OfType().ForEach(i => - { - i.Click += new RoutedEventHandler((s, e) => contextMenuFlyout.Hide()); - }); - items.OfType().ForEach(i => - { - clickAction(i.Items); - }); - }; + i.Click += new RoutedEventHandler((s, e) => contextMenuFlyout.Hide()); + }); + items.OfType().ForEach(i => + { + clickAction(i.Items); + }); + }; - clickAction(flyout.Items); - } - }); - } + clickAction(flyout.Items); + } + }); } private void RemoveOverflow(CommandBarFlyout contextMenuFlyout) @@ -913,6 +912,7 @@ protected void FileList_DragItemsStarting(object sender, DragItemsStartingEventA { var iddo = shellItemList[0].Parent.GetChildrenUIObjects(HWND.NULL, shellItemList); shellItemList.ForEach(x => x.Dispose()); + var format = System.Windows.Forms.DataFormats.GetFormat("Shell IDList Array"); if (iddo.TryGetData((uint)format.Id, out var data)) { @@ -951,6 +951,7 @@ protected async void Item_DragOver(object sender, DragEventArgs e) return; DragOperationDeferral? deferral = null; + try { deferral = e.GetDeferral(); @@ -1048,6 +1049,7 @@ protected async void Item_Drop(object sender, DragEventArgs e) var item = GetItemFromElement(sender); if (item is not null) await ParentShellPageInstance!.FilesystemHelpers.PerformOperationTypeAsync(e.AcceptedOperation, e.DataView, (item as ShortcutItem)?.TargetPath ?? item.ItemPath, false, true, item.IsExecutable); + deferral.Complete(); } @@ -1139,13 +1141,13 @@ protected internal void FileListItem_PointerEntered(object sender, PointerRouted hoverTimer.Stop(); - // selection of multiple individual items with control + // Selection of multiple individual items with control if (e.KeyModifiers == VirtualKeyModifiers.Control && selectedItems is not null) { ItemManipulationModel.AddSelectedItem(hoveredItem); } - // selection of a range of items with shift + // Selection of a range of items with shift else if (e.KeyModifiers == VirtualKeyModifiers.Shift && selectedItems is not null && selectedItems.Any()) @@ -1161,9 +1163,8 @@ selectedItems is not null && ItemManipulationModel.AddSelectedItem((ListedItem)ItemsControl.Items[i]); } } - // avoid resetting the selection if multiple items are selected - else if (SelectedItems is null || - SelectedItems.Count <= 1) + // Avoid resetting the selection if multiple items are selected + else if (SelectedItems is null || SelectedItems.Count <= 1) { ItemManipulationModel.SetSelectedItem(hoveredItem); } @@ -1211,7 +1212,7 @@ protected void UninitializeDrag(UIElement element) element.Drop -= Item_Drop; } - // VirtualKey doesn't support / accept plus and minus by default. + // VirtualKey doesn't support or accept plus and minus by default. public readonly VirtualKey PlusKey = (VirtualKey)187; public readonly VirtualKey MinusKey = (VirtualKey)189; @@ -1239,7 +1240,7 @@ private void UpdateCollectionViewSource() if (ParentShellPageInstance.FilesystemViewModel.FilesAndFolders.IsGrouped) { - CollectionViewSource = new CollectionViewSource() + CollectionViewSource = new() { IsSourceGrouped = true, Source = ParentShellPageInstance.FilesystemViewModel.FilesAndFolders.GroupedCollection @@ -1247,7 +1248,7 @@ private void UpdateCollectionViewSource() } else { - CollectionViewSource = new CollectionViewSource() + CollectionViewSource = new() { IsSourceGrouped = false, Source = ParentShellPageInstance.FilesystemViewModel.FilesAndFolders diff --git a/src/Files.App/IShellPage.cs b/src/Files.App/IShellPage.cs index 6808ba6072ab..9ce7570cc118 100644 --- a/src/Files.App/IShellPage.cs +++ b/src/Files.App/IShellPage.cs @@ -94,9 +94,9 @@ public interface IPaneHolder : IDisposable, INotifyPropertyChanged public interface IMultiPaneInfo { - // The instance is the left (or only) pane + // The instance is the left or only pane public bool IsPageMainPane { get; } public IPaneHolder PaneHolder { get; } } -} \ No newline at end of file +} diff --git a/src/Files.App/MainWindow.xaml b/src/Files.App/MainWindow.xaml index 895167b16cba..74eda8b9d29a 100644 --- a/src/Files.App/MainWindow.xaml +++ b/src/Files.App/MainWindow.xaml @@ -7,9 +7,9 @@ xmlns:winuiex="using:WinUIEx" mc:Ignorable="d"> + - - \ No newline at end of file + diff --git a/src/Files.App/MainWindow.xaml.cs b/src/Files.App/MainWindow.xaml.cs index e555bdcdd51a..c66dcfe3185c 100644 --- a/src/Files.App/MainWindow.xaml.cs +++ b/src/Files.App/MainWindow.xaml.cs @@ -22,14 +22,8 @@ using WinUIEx; using IO = System.IO; -// To learn more about WinUI, the WinUI project structure, -// and more about our project templates, see: http://aka.ms/winui-project-info. - namespace Files.App { - /// - /// An empty window that can be used on its own or navigated to within a Frame. - /// public sealed partial class MainWindow : WindowEx { public MainWindow() @@ -56,7 +50,7 @@ private void EnsureEarlyWindow() AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent; AppWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent; - // Set min size + // Set minimum sizes base.MinHeight = 328; base.MinWidth = 516; } @@ -66,13 +60,12 @@ public async Task InitializeApplication(object activatedEventArgs) var rootFrame = EnsureWindowIsInitialized(); Activate(); - // WINUI3: port activation args from App.xaml.cs.old: OnActivated, OnFileActivated switch (activatedEventArgs) { case ILaunchActivatedEventArgs launchArgs: if (launchArgs.Arguments is not null && launchArgs.Arguments.Contains($"files.exe", StringComparison.OrdinalIgnoreCase)) { - // WINUI3 bug: when launching from commandline the argument is not ICommandLineActivatedEventArgs (#10370) + // 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()); @@ -82,8 +75,7 @@ public async Task InitializeApplication(object activatedEventArgs) else if (rootFrame.Content is null) { // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter + // configuring the new page by passing required information as a navigation parameter rootFrame.Navigate(typeof(MainPage), launchArgs.Arguments, new SuppressNavigationTransitionInfo()); } else @@ -107,7 +99,8 @@ public async Task InitializeApplication(object activatedEventArgs) var folder = (StorageFolder)await FilesystemTasks.Wrap(() => StorageFolder.GetFolderFromPathAsync(unescapedValue).AsTask()); if (folder is not null && !string.IsNullOrEmpty(folder.Path)) { - unescapedValue = folder.Path; // Convert short name to long name (#6190) + // Convert short name to long name (#6190) + unescapedValue = folder.Path; } switch (parsedArgs[0]) { @@ -157,8 +150,7 @@ public async Task InitializeApplication(object activatedEventArgs) if (rootFrame.Content is null) { // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter + // configuring the new page by passing required information as a navigation parameter rootFrame.Navigate(typeof(MainPage), fileArgs.Files.First().Path, new SuppressNavigationTransitionInfo()); index = 1; } @@ -170,15 +162,14 @@ public async Task InitializeApplication(object activatedEventArgs) } if (rootFrame.Content is null) - { rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); - } } private Frame EnsureWindowIsInitialized() { - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active + // NOTE: + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active if (!(App.Window.Content is Frame rootFrame)) { // Create a Frame to act as the navigation context and navigate to the first page @@ -199,9 +190,7 @@ private Frame EnsureWindowIsInitialized() /// The Frame which failed navigation /// Details about the navigation failure private void OnNavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } + => throw new Exception("Failed to load Page " + e.SourcePageType.FullName); private async Task InitializeFromCmdLineArgs(Frame rootFrame, ParsedCommands parsedCommands, string activationPath = "") { @@ -212,23 +201,19 @@ async Task PerformNavigation(string payload, string selectItem = null) payload = CommonPaths.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 paneNavigationArgs = new PaneNavigationArguments { LeftPaneNavPathParam = payload, LeftPaneSelectItemParam = selectItem, }; + if (rootFrame.Content is not null) - { await MainPageViewModel.AddNewTabByParam(typeof(PaneHolderPage), paneNavigationArgs); - } else - { rootFrame.Navigate(typeof(MainPage), paneNavigationArgs, new SuppressNavigationTransitionInfo()); - } } foreach (var command in parsedCommands) { @@ -243,9 +228,7 @@ async Task PerformNavigation(string payload, string selectItem = null) case ParsedCommandType.SelectItem: if (IO.Path.IsPathRooted(command.Payload)) - { await PerformNavigation(IO.Path.GetDirectoryName(command.Payload), IO.Path.GetFileName(command.Payload)); - } break; case ParsedCommandType.TagFiles: diff --git a/src/Files.App/Program.cs b/src/Files.App/Program.cs index 5eac555409f7..468395b53a77 100644 --- a/src/Files.App/Program.cs +++ b/src/Files.App/Program.cs @@ -20,10 +20,11 @@ namespace Files.App { internal class Program { - // Note: We can't declare Main to be async because in a WinUI app - // This prevents Narrator from reading XAML elements - // https://github.com/microsoft/WindowsAppSDK-Samples/blob/main/Samples/AppLifecycle/Instancing/cs-winui-packaged/CsWinUiDesktopInstancing/CsWinUiDesktopInstancing/Program.cs - // STAThread has no effect if main is async, needed for Clipboard + // Note: + // We can't declare Main to be async because in a WinUI app + // This prevents Narrator from reading XAML elements + // https://github.com/microsoft/WindowsAppSDK-Samples/blob/main/Samples/AppLifecycle/Instancing/cs-winui-packaged/CsWinUiDesktopInstancing/CsWinUiDesktopInstancing/Program.cs + // STAThread has no effect if main is async, needed for Clipboard [STAThread] private static void Main() { @@ -76,8 +77,7 @@ private static void Main() } } } - - if (activatedArgs.Data is ILaunchActivatedEventArgs tileArgs) + else if (activatedArgs.Data is ILaunchActivatedEventArgs tileArgs) { if (tileArgs.Arguments is not null && !tileArgs.Arguments.Contains($"files.exe", StringComparison.OrdinalIgnoreCase) && @@ -134,6 +134,7 @@ private static void Main() { currentInstance.Activated += OnActivated; } + ApplicationData.Current.LocalSettings.Values["INSTANCE_ACTIVE"] = -proc.Id; Application.Start((p) => diff --git a/src/Files.App/ViewModels/Pages/YourHomeViewModel.cs b/src/Files.App/ViewModels/HomeViewModel.cs similarity index 86% rename from src/Files.App/ViewModels/Pages/YourHomeViewModel.cs rename to src/Files.App/ViewModels/HomeViewModel.cs index 1fd7f4d8c74d..281ce28bc96c 100644 --- a/src/Files.App/ViewModels/Pages/YourHomeViewModel.cs +++ b/src/Files.App/ViewModels/HomeViewModel.cs @@ -6,12 +6,11 @@ using Files.App.ViewModels.Widgets.Bundles; using Microsoft.UI.Xaml; using System; -using System.Text.Json; using System.Windows.Input; -namespace Files.App.ViewModels.Pages +namespace Files.App.ViewModels { - public class YourHomeViewModel : ObservableObject, IDisposable + public class HomeViewModel : ObservableObject, IDisposable { private BundlesViewModel bundlesViewModel; @@ -19,15 +18,13 @@ public class YourHomeViewModel : ObservableObject, IDisposable private IShellPage associatedInstance; - private readonly JsonElement defaultJson = JsonSerializer.SerializeToElement("{}"); - public event EventHandler YourHomeLoadedInvoked; public ICommand YourHomeLoadedCommand { get; private set; } public ICommand LoadBundlesCommand { get; private set; } - public YourHomeViewModel(WidgetsListControlViewModel widgetsViewModel, IShellPage associatedInstance) + public HomeViewModel(WidgetsListControlViewModel widgetsViewModel, IShellPage associatedInstance) { this.widgetsViewModel = widgetsViewModel; this.associatedInstance = associatedInstance; @@ -69,8 +66,6 @@ private async void BundlesViewModel_OpenPathEvent(object sender, BundlesOpenPath await NavigationHelpers.OpenPath(e.path, associatedInstance, e.itemType, e.openSilent, e.openViaApplicationPicker, e.selectItems); } - #region IDisposable - public void Dispose() { if (bundlesViewModel is not null) @@ -81,7 +76,5 @@ public void Dispose() widgetsViewModel?.Dispose(); } - - #endregion IDisposable } } diff --git a/src/Files.App/ViewModels/ToolbarViewModel.cs b/src/Files.App/ViewModels/ToolbarViewModel.cs index d3cb782af1ff..97952cc8c9ef 100644 --- a/src/Files.App/ViewModels/ToolbarViewModel.cs +++ b/src/Files.App/ViewModels/ToolbarViewModel.cs @@ -660,7 +660,7 @@ public async Task CheckPathInput(string currentInput, string currentSelectedPath if (currentSelectedPath == currentInput || string.IsNullOrWhiteSpace(currentInput)) return; - if (currentInput != shellPage.FilesystemViewModel.WorkingDirectory || shellPage.CurrentPageType == typeof(WidgetsPage)) + if (currentInput != shellPage.FilesystemViewModel.WorkingDirectory || shellPage.CurrentPageType == typeof(HomePage)) { if (currentInput.Equals("Home", StringComparison.OrdinalIgnoreCase) || currentInput.Equals("Home".GetLocalizedResource(), StringComparison.OrdinalIgnoreCase)) { @@ -707,7 +707,7 @@ public async Task CheckPathInput(string currentInput, string currentSelectedPath { var workingDir = string.IsNullOrEmpty(shellPage.FilesystemViewModel.WorkingDirectory) || - shellPage.CurrentPageType == typeof(WidgetsPage) ? + shellPage.CurrentPageType == typeof(HomePage) ? CommonPaths.HomePath : shellPage.FilesystemViewModel.WorkingDirectory; diff --git a/src/Files.App/Views/BaseShellPage.cs b/src/Files.App/Views/BaseShellPage.cs index 0e983e9a0d30..3a9f9d9db6c8 100644 --- a/src/Files.App/Views/BaseShellPage.cs +++ b/src/Files.App/Views/BaseShellPage.cs @@ -88,6 +88,7 @@ public BaseLayout ContentPage if (value != contentPage) { contentPage = value; + NotifyPropertyChanged(nameof(ContentPage)); NotifyPropertyChanged(nameof(SlimContentPage)); } @@ -103,6 +104,7 @@ public bool IsPageMainPane if (value != isPageMainPane) { isPageMainPane = value; + NotifyPropertyChanged(nameof(IsPageMainPane)); } } @@ -117,6 +119,7 @@ public IPaneHolder PaneHolder if (value != paneHolder) { paneHolder = value; + NotifyPropertyChanged(nameof(PaneHolder)); } } @@ -145,10 +148,12 @@ public bool IsCurrentInstance if (isCurrentInstance != value) { isCurrentInstance = value; + if (isCurrentInstance) ContentPage?.ItemManipulationModel.FocusFileList(); else if (SlimContentPage is not ColumnViewBrowser) ToolbarViewModel.IsEditModeEnabled = false; + NotifyPropertyChanged(nameof(IsCurrentInstance)); } } @@ -156,8 +161,8 @@ public bool IsCurrentInstance public SolidColorBrush CurrentInstanceBorderBrush { - get { return (SolidColorBrush)GetValue(CurrentInstanceBorderBrushProperty); } - set { SetValue(CurrentInstanceBorderBrushProperty, value); } + get => (SolidColorBrush)GetValue(CurrentInstanceBorderBrushProperty); + set => SetValue(CurrentInstanceBorderBrushProperty, value); } public static readonly DependencyProperty CurrentInstanceBorderBrushProperty = @@ -181,13 +186,12 @@ public BaseShellPage(CurrentInstanceViewModel instanceViewModel) DisplayFilesystemConsentDialog(); - /*TODO ResourceContext.GetForCurrentView and ResourceContext.GetForViewIndependentUse do not exist in Windows App SDK - Use your ResourceManager instance to create a ResourceContext as below.If you already have a ResourceManager instance, - replace the new instance created below with correct instance. - Read: https://learn.microsoft.com/windows/apps/windows-app-sdk/migrate-to-windows-app-sdk/guides/mrtcore - */ + // TODO: + // ResourceContext.GetForCurrentView and ResourceContext.GetForViewIndependentUse do not exist in Windows App SDK + // Use your ResourceManager instance to create a ResourceContext as below.If you already have a ResourceManager instance, + // replace the new instance created below with correct instance. + // Read: https://docs.microsoft.com/en-us/windows/apps/windows-app-sdk/migrate-to-windows-app-sdk/guides/mrtcore var flowDirectionSetting = new Microsoft.Windows.ApplicationModel.Resources.ResourceManager().CreateResourceContext().QualifierValues["LayoutDirection"]; - if (flowDirectionSetting == "RTL") FlowDirection = FlowDirection.RightToLeft; @@ -208,14 +212,7 @@ public BaseShellPage(CurrentInstanceViewModel instanceViewModel) InstanceViewModel.FolderSettings.SortOptionPreferenceUpdated += AppSettings_SortOptionPreferenceUpdated; InstanceViewModel.FolderSettings.SortDirectoriesAlongsideFilesPreferenceUpdated += AppSettings_SortDirectoriesAlongsideFilesPreferenceUpdated; - this.PointerPressed += CoreWindow_PointerPressed; - - /* - TODO UA307 Default back button in the title bar does not exist in WinUI3 apps. - The tool has generated a custom back button in the MainWindow.xaml.cs file. - Feel free to edit its position, behavior and use the custom back button instead. - Read: https://learn.microsoft.com/windows/apps/windows-app-sdk/migrate-to-windows-app-sdk/case-study-1#restoring-back-button-functionality - */ + PointerPressed += CoreWindow_PointerPressed; App.DrivesManager.PropertyChanged += DrivesManager_PropertyChanged; @@ -234,7 +231,7 @@ protected void FilesystemViewModel_PageTypeUpdated(object sender, PageTypeUpdate protected void FilesystemViewModel_OnSelectionRequestedEvent(object sender, List e) { - // set focus since selection might occur before the UI finishes updating + // Set focus since selection might occur before the UI finishes updating ContentPage.ItemManipulationModel.FocusFileList(); ContentPage.ItemManipulationModel.SetSelectedItems(e); } @@ -258,31 +255,28 @@ protected virtual void Page_Loaded(object sender, RoutedEventArgs e) this.Loaded -= Page_Loaded; } - /** - * Some keys are overridden by control built-in defaults (e.g. 'Space'). - * They must be handled here since they're not propagated to KeyboardAccelerator. - */ + // Some keys are overridden by control built-in defaults(e.g. 'Space'). + // They must be handled here since they're not propagated to KeyboardAccelerator. protected void ShellPage_PreviewKeyDown(object sender, KeyRoutedEventArgs args) { var ctrl = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down); var shift = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down); var alt = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down); - var tabInstance = CurrentPageType == typeof(DetailsLayoutBrowser) || - CurrentPageType == typeof(GridViewBrowser) || - CurrentPageType == typeof(ColumnViewBrowser) || - CurrentPageType == typeof(ColumnViewBase); + var tabInstance = + CurrentPageType == typeof(DetailsLayoutBrowser) || + CurrentPageType == typeof(GridViewBrowser) || + CurrentPageType == typeof(ColumnViewBrowser) || + CurrentPageType == typeof(ColumnViewBase); switch (c: ctrl, s: shift, a: alt, t: tabInstance, k: args.Key) { - // Ctrl + space, toggle media playback + // Ctrl + Space, toggle media playback case (true, false, false, true, VirtualKey.Space): - if (Ioc.Default.GetRequiredService().PreviewPaneContent is UserControls.FilePreviews.MediaPreview mediaPreviewContent) { mediaPreviewContent.ViewModel.TogglePlayback(); args.Handled = true; } - break; } } @@ -299,6 +293,7 @@ protected async void ShellPage_TextChanged(ISearchBox sender, SearchBoxTextChang { if (e.Reason != SearchBoxTextChangeReason.UserInput) return; + if (!string.IsNullOrWhiteSpace(sender.Query)) { var search = new FolderSearch @@ -308,6 +303,7 @@ protected async void ShellPage_TextChanged(ISearchBox sender, SearchBoxTextChang MaxItemCount = 10, SearchUnindexedItems = userSettingsService.PreferencesSettingsService.SearchUnindexedItems }; + sender.SetSuggestions((await search.SearchAsync()).Select(suggestion => new SuggestionModel(suggestion))); } else @@ -340,6 +336,7 @@ protected void CoreWindow_PointerPressed(object sender, PointerRoutedEventArgs a { if (!IsCurrentInstance) return; + if (args.GetCurrentPoint(this).Properties.IsXButton1Pressed) Back_Click(); else if (args.GetCurrentPoint(this).Properties.IsXButton2Pressed) @@ -387,11 +384,9 @@ protected void DrivesManager_PropertyChanged(object sender, PropertyChangedEvent DisplayFilesystemConsentDialog(); } - /* - * Ensure that the path bar gets updated for user interaction - * whenever the path changes. We will get the individual directories from - * the updated, most-current path and add them to the UI. - */ + // Ensure that the path bar gets updated for user interaction + // whenever the path changes.We will get the individual directories from + // the updated, most-current path and add them to the UI. public void UpdatePathUIToWorkingDirectory(string newWorkingDir, string singleItemOverride = null) { if (string.IsNullOrWhiteSpace(singleItemOverride)) @@ -447,6 +442,7 @@ public void NavigateToPath(string navigationPath, NavigationArguments? navArgs = var layout = navigationPath.StartsWith("tag:") ? typeof(DetailsLayoutBrowser) : FolderSettings.GetLayoutType(navigationPath); + NavigateToPath(navigationPath, layout, navArgs); } @@ -472,9 +468,10 @@ public async void Refresh_Click() ThumbnailSize = InstanceViewModel.FolderSettings.GetIconSize(), SearchUnindexedItems = InstanceViewModel.SearchedUnindexedItems }; + await FilesystemViewModel.SearchAsync(searchInstance); } - else if (CurrentPageType != typeof(WidgetsPage)) + else if (CurrentPageType != typeof(HomePage)) { ToolbarViewModel.CanRefresh = false; FilesystemViewModel?.RefreshItems(null); @@ -486,7 +483,7 @@ public virtual void Back_Click() var previousPageContent = ItemDisplay.BackStack[ItemDisplay.BackStack.Count - 1]; HandleBackForwardRequest(previousPageContent); - if (previousPageContent.SourcePageType == typeof(WidgetsPage)) + if (previousPageContent.SourcePageType == typeof(HomePage)) ItemDisplay.GoBack(new EntranceNavigationTransitionInfo()); else ItemDisplay.GoBack(); @@ -496,6 +493,7 @@ public virtual void Forward_Click() { var incomingPageContent = ItemDisplay.ForwardStack[ItemDisplay.ForwardStack.Count - 1]; HandleBackForwardRequest(incomingPageContent); + ItemDisplay.GoForward(); } @@ -550,7 +548,6 @@ protected void FilesystemViewModel_ItemLoadStatusChanged(object sender, ItemLoad ToolbarViewModel.CanRefresh = false; SetLoadingIndicatorForTabs(true); break; - case ItemLoadStatusChangedEventArgs.ItemLoadStatus.InProgress: var columnCanNavigateBackward = false; var columnCanNavigateForward = false; @@ -563,13 +560,13 @@ protected void FilesystemViewModel_ItemLoadStatusChanged(object sender, ItemLoad ToolbarViewModel.CanGoForward = ItemDisplay.CanGoForward || columnCanNavigateForward; SetLoadingIndicatorForTabs(true); break; - case ItemLoadStatusChangedEventArgs.ItemLoadStatus.Complete: SetLoadingIndicatorForTabs(false); ToolbarViewModel.CanRefresh = true; // Select previous directory if (!string.IsNullOrWhiteSpace(e.PreviousDirectory) && - e.PreviousDirectory.Contains(e.Path, StringComparison.Ordinal) && !e.PreviousDirectory.Contains(CommonPaths.RecycleBinPath, StringComparison.Ordinal)) + e.PreviousDirectory.Contains(e.Path, StringComparison.Ordinal) && + !e.PreviousDirectory.Contains(CommonPaths.RecycleBinPath, StringComparison.Ordinal)) { // Remove the WorkingDir from previous dir e.PreviousDirectory = e.PreviousDirectory.Replace(e.Path, string.Empty, StringComparison.Ordinal); @@ -631,12 +628,13 @@ protected void InitToolbarCommands() protected async Task GetContentOrNullAsync() { - // WINUI3: make sure not to run this synchronously, do not use EnqueueAsync + // WINUI3: Make sure not to run this synchronously, do not use EnqueueAsync var tcs = new TaskCompletionSource(); DispatcherQueue.TryEnqueue(() => { tcs.SetResult(ItemDisplay.Content); }); + return await tcs.Task as BaseLayout; } @@ -655,7 +653,7 @@ await DispatcherQueue.EnqueueAsync(async () => protected void SelectSidebarItemFromPath(Type incomingSourcePageType = null) { - if (incomingSourcePageType == typeof(WidgetsPage) && incomingSourcePageType is not null) + if (incomingSourcePageType == typeof(HomePage) && incomingSourcePageType is not null) ToolbarViewModel.PathControlDisplayText = "Home".GetLocalizedResource(); } @@ -684,8 +682,11 @@ private void HandleBackForwardRequest(PageStackEntry pageContent) { var incomingPageNavPath = pageContent.Parameter as NavigationArguments; incomingPageNavPath.IsLayoutSwitch = false; - if (pageContent.SourcePageType != typeof(WidgetsPage)) // Update layout type + + // Update layout type + if (pageContent.SourcePageType != typeof(HomePage)) InstanceViewModel.FolderSettings.GetLayoutType(incomingPageNavPath.IsSearchResultPage ? incomingPageNavPath.SearchPathParam : incomingPageNavPath.NavPathParam); + SelectSidebarItemFromPath(pageContent.SourcePageType); } @@ -717,7 +718,8 @@ public virtual void Dispose() InstanceViewModel.FolderSettings.SortOptionPreferenceUpdated -= AppSettings_SortOptionPreferenceUpdated; InstanceViewModel.FolderSettings.SortDirectoriesAlongsideFilesPreferenceUpdated -= AppSettings_SortDirectoriesAlongsideFilesPreferenceUpdated; - if (FilesystemViewModel is not null) // Prevent weird case of this being null when many tabs are opened/closed quickly + // Prevent weird case of this being null when many tabs are opened/closed quickly + if (FilesystemViewModel is not null) { FilesystemViewModel.WorkingDirectoryModified -= ViewModel_WorkingDirectoryModified; FilesystemViewModel.ItemLoadStatusChanged -= FilesystemViewModel_ItemLoadStatusChanged; diff --git a/src/Files.App/Views/ColumnParam.cs b/src/Files.App/Views/ColumnParam.cs index fb85cbd626dd..3b1514034792 100644 --- a/src/Files.App/Views/ColumnParam.cs +++ b/src/Files.App/Views/ColumnParam.cs @@ -5,6 +5,7 @@ namespace Files.App.Views public class ColumnParam : NavigationArguments { public int Column { get; set; } + public ListView ListView { get; set; } } -} \ No newline at end of file +} diff --git a/src/Files.App/Views/ColumnShellPage.xaml b/src/Files.App/Views/ColumnShellPage.xaml index cc8b2cfe7e7d..9d76437fdccd 100644 --- a/src/Files.App/Views/ColumnShellPage.xaml +++ b/src/Files.App/Views/ColumnShellPage.xaml @@ -2,20 +2,20 @@ x:Class="Files.App.Views.ColumnShellPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:Files.App.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:wctconverters="using:CommunityToolkit.WinUI.UI.Converters" x:Name="RootPage" Background="Transparent" KeyboardAcceleratorPlacementMode="Hidden" Loaded="Page_Loaded" mc:Ignorable="d"> + - - - + + @@ -76,6 +76,7 @@ IsEnabled="{x:Bind IsCurrentInstance, Mode=OneWay}" Modifiers="Menu" /> + - @@ -109,5 +109,6 @@ x:FieldModifier="public" Canvas.ZIndex="30" Navigated="ItemDisplayFrame_Navigated" /> + - \ No newline at end of file + diff --git a/src/Files.App/Views/ColumnShellPage.xaml.cs b/src/Files.App/Views/ColumnShellPage.xaml.cs index 0ac3ae73bc59..f2ee256f116d 100644 --- a/src/Files.App/Views/ColumnShellPage.xaml.cs +++ b/src/Files.App/Views/ColumnShellPage.xaml.cs @@ -22,6 +22,7 @@ namespace Files.App.Views public sealed partial class ColumnShellPage : BaseShellPage { public override bool CanNavigateBackward => false; + public override bool CanNavigateForward => false; protected override Frame ItemDisplay => ItemDisplayFrame; @@ -34,6 +35,7 @@ public ColumnShellPage() : base(new CurrentInstanceViewModel(FolderLayoutModes.C protected override void OnNavigatedTo(NavigationEventArgs eventArgs) { base.OnNavigatedTo(eventArgs); + ColumnParams = eventArgs.Parameter as ColumnParam; if (ColumnParams?.IsLayoutSwitch ?? false) FilesystemViewModel_DirectoryInfoUpdated(this, EventArgs.Empty); @@ -59,7 +61,8 @@ public ColumnParam ColumnParams protected override void OnNavigationParamsChanged() { - ItemDisplayFrame.Navigate(typeof(ColumnViewBase), + ItemDisplayFrame.Navigate( + typeof(ColumnViewBase), new NavigationArguments() { IsSearchResultPage = columnParams.IsSearchResultPage, @@ -79,7 +82,9 @@ protected override void Page_Loaded(object sender, RoutedEventArgs e) FilesystemViewModel.DirectoryInfoUpdated += FilesystemViewModel_DirectoryInfoUpdated; FilesystemViewModel.PageTypeUpdated += FilesystemViewModel_PageTypeUpdated; FilesystemViewModel.OnSelectionRequestedEvent += FilesystemViewModel_OnSelectionRequestedEvent; + base.Page_Loaded(sender, e); + NotifyPropertyChanged(nameof(FilesystemViewModel)); } @@ -90,19 +95,22 @@ protected override void ViewModel_WorkingDirectoryModified(object sender, Workin UpdatePathUIToWorkingDirectory(value); } - private async void ItemDisplayFrame_Navigated(object sender, NavigationEventArgs e) + private async void ItemDisplayFrame_Navigated(object sender, NavigationEventArgs e) { ContentPage = await GetContentOrNullAsync(); + if (!ToolbarViewModel.SearchBox.WasQuerySubmitted) { ToolbarViewModel.SearchBox.Query = string.Empty; ToolbarViewModel.IsSearchBoxVisible = false; } + if (ItemDisplayFrame.CurrentSourcePageType == typeof(ColumnViewBase)) { // Reset DataGrid Rows that may be in "cut" command mode ContentPage.ResetItemOpacity(); } + var parameters = e.Parameter as NavigationArguments; TabItemArguments = new TabItemArguments() { @@ -114,10 +122,11 @@ private async void ItemDisplayFrame_Navigated(object sender, NavigationEventArgs private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) { args.Handled = true; - var tabInstance = CurrentPageType == typeof(DetailsLayoutBrowser) || - CurrentPageType == typeof(GridViewBrowser) || - CurrentPageType == typeof(ColumnViewBrowser) || - CurrentPageType == typeof(ColumnViewBase); + var tabInstance = + CurrentPageType == typeof(DetailsLayoutBrowser) || + CurrentPageType == typeof(GridViewBrowser) || + CurrentPageType == typeof(ColumnViewBrowser) || + CurrentPageType == typeof(ColumnViewBase); var ctrl = args.KeyboardAccelerator.Modifiers.HasFlag(VirtualKeyModifiers.Control); var shift = args.KeyboardAccelerator.Modifiers.HasFlag(VirtualKeyModifiers.Shift); @@ -125,17 +134,18 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo switch (c: ctrl, s: shift, a: alt, t: tabInstance, k: args.KeyboardAccelerator.Key) { - case (true, false, false, true, VirtualKey.Z): // ctrl + z, undo + // Ctrl + Z: undo + case (true, false, false, true, VirtualKey.Z): if (!InstanceViewModel.IsPageTypeSearchResults) await storageHistoryHelpers.TryUndo(); break; - - case (true, false, false, true, VirtualKey.Y): // ctrl + y, redo + // Ctrl + Y: Redo + case (true, false, false, true, VirtualKey.Y): if (!InstanceViewModel.IsPageTypeSearchResults) await storageHistoryHelpers.TryRedo(); break; - - case (true, true, false, true, VirtualKey.N): // ctrl + shift + n, new item + // Ctrl + Shift + N: New item + case (true, true, false, true, VirtualKey.N): if (InstanceViewModel.CanCreateFileInPage) { var addItemDialogViewModel = new AddItemDialogViewModel(); @@ -149,34 +159,37 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo this); } break; - - case (false, true, false, true, VirtualKey.Delete): // shift + delete, PermanentDelete + // Shift + Del, Permanent delete + case (false, true, false, true, VirtualKey.Delete): if (ContentPage.IsItemSelected && !ToolbarViewModel.IsEditModeEnabled && !InstanceViewModel.IsPageTypeSearchResults) { var items = SlimContentPage.SelectedItems.ToList().Select((item) => StorageHelpers.FromPathAndType( item.ItemPath, item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)); + await FilesystemHelpers.DeleteItemsAsync(items, userSettingsService.FoldersSettingsService.DeleteConfirmationPolicy, true, true); } break; - - case (true, false, false, true, VirtualKey.V): // ctrl + v, paste + // Ctrl + V, Paste + case (true, false, false, true, VirtualKey.V): if (!ToolbarViewModel.IsEditModeEnabled && !ContentPage.IsRenamingItem && !InstanceViewModel.IsPageTypeSearchResults && !ToolbarViewModel.SearchHasFocus) await UIFilesystemHelpers.PasteItemAsync(FilesystemViewModel.WorkingDirectory, this); break; - - case (true, false, false, true, VirtualKey.D): // ctrl + d, delete item + // Ctrl + D, Delete item + case (true, false, false, true, VirtualKey.D): if (ContentPage.IsItemSelected && !ContentPage.IsRenamingItem && !InstanceViewModel.IsPageTypeSearchResults) { var items = SlimContentPage.SelectedItems.ToList().Select((item) => StorageHelpers.FromPathAndType( item.ItemPath, item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)); + await FilesystemHelpers.DeleteItemsAsync(items, userSettingsService.FoldersSettingsService.DeleteConfirmationPolicy, false, true); } break; - - case (false, false, true, true, VirtualKey.D): // alt + d, select address bar (english) - case (true, false, false, true, VirtualKey.L): // ctrl + l, select address bar + // Alt + D, Select address bar (English) + case (false, false, true, true, VirtualKey.D): + // Ctrl + L, Select address bar + case (true, false, false, true, VirtualKey.L): ToolbarViewModel.IsEditModeEnabled = true; break; } @@ -211,9 +224,7 @@ public override void NavigateToPath(string navigationPath, Type sourcePageType, } public override void NavigateHome() - { - throw new NotImplementedException("Can't show Home page in Column View"); - } + => throw new NotImplementedException("Can't show HomePage in ColumnView"); public void RemoveLastPageFromBackStack() { @@ -233,10 +244,11 @@ public void SubmitSearch(string query, bool searchUnindexedItems) SearchQuery = query, SearchUnindexedItems = searchUnindexedItems, }); + //this.FindAscendant().SetSelectedPathOrNavigate(null, typeof(ColumnViewBase), navArgs); } private async void CreateNewShortcutFromDialog() => await UIFilesystemHelpers.CreateShortcutFromDialogAsync(this); } -} \ No newline at end of file +} diff --git a/src/Files.App/Views/WidgetsPage.xaml b/src/Files.App/Views/HomePage.xaml similarity index 88% rename from src/Files.App/Views/WidgetsPage.xaml rename to src/Files.App/Views/HomePage.xaml index 1710f76077df..e9753a6fa915 100644 --- a/src/Files.App/Views/WidgetsPage.xaml +++ b/src/Files.App/Views/HomePage.xaml @@ -1,5 +1,5 @@  + + + \ No newline at end of file diff --git a/src/Files.App/Views/WidgetsPage.xaml.cs b/src/Files.App/Views/HomePage.xaml.cs similarity index 82% rename from src/Files.App/Views/WidgetsPage.xaml.cs rename to src/Files.App/Views/HomePage.xaml.cs index c51858ff8deb..d8d4b70d3f08 100644 --- a/src/Files.App/Views/WidgetsPage.xaml.cs +++ b/src/Files.App/Views/HomePage.xaml.cs @@ -5,7 +5,6 @@ using Files.App.Helpers; using Files.App.UserControls.Widgets; using Files.App.ViewModels; -using Files.App.ViewModels.Pages; using Files.Backend.Services.Settings; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; @@ -18,11 +17,12 @@ namespace Files.App.Views { - public sealed partial class WidgetsPage : Page, IDisposable + public sealed partial class HomePage : Page, IDisposable { private IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); private IShellPage AppInstance = null; + public FolderSettingsViewModel FolderSettings => AppInstance?.InstanceViewModel.FolderSettings; private QuickAccessWidget quickAccessWidget; @@ -31,17 +31,14 @@ public sealed partial class WidgetsPage : Page, IDisposable private FileTagsWidget fileTagsWidget; private RecentFilesWidget recentFilesWidget; - public YourHomeViewModel ViewModel - { - get => (YourHomeViewModel)DataContext; - set => DataContext = value; - } + public HomeViewModel ViewModel { get; set; } - public WidgetsPage() + public HomePage() { InitializeComponent(); - ViewModel = new YourHomeViewModel(Widgets.ViewModel, AppInstance); + ViewModel = new(Widgets.ViewModel, AppInstance); + ViewModel.YourHomeLoadedInvoked += ViewModel_YourHomeLoadedInvoked; Widgets.ViewModel.WidgetListRefreshRequestedInvoked += ViewModel_WidgetListRefreshRequestedInvoked; } @@ -49,6 +46,7 @@ public WidgetsPage() protected override void OnNavigatedFrom(NavigationEventArgs e) { Dispose(); + base.OnNavigatedFrom(e); } @@ -61,15 +59,21 @@ private void ViewModel_WidgetListRefreshRequestedInvoked(object? sender, EventAr public void ReloadWidgets() { - quickAccessWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadQuickAccessWidget, quickAccessWidget); - drivesWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadDrivesWidget, drivesWidget); - bundlesWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadBundles, bundlesWidget); - fileTagsWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadFileTags, fileTagsWidget); - recentFilesWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadRecentFiles, recentFilesWidget); + quickAccessWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadQuickAccessWidget, quickAccessWidget); + drivesWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadDrivesWidget, drivesWidget); + bundlesWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadBundles, bundlesWidget); + fileTagsWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadFileTags, fileTagsWidget); + recentFilesWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.PreferencesSettingsService, Widgets.ViewModel, out bool shouldReloadRecentFiles, recentFilesWidget); + // Reload QuickAccessWidget if (shouldReloadQuickAccessWidget && quickAccessWidget is not null) { - Widgets.ViewModel.InsertWidget(new(quickAccessWidget, (value) => UserSettingsService.PreferencesSettingsService.FoldersWidgetExpanded = value, () => UserSettingsService.PreferencesSettingsService.FoldersWidgetExpanded), 0); + Widgets.ViewModel.InsertWidget( + new( + quickAccessWidget, + (value) => UserSettingsService.PreferencesSettingsService.FoldersWidgetExpanded = value, + () => UserSettingsService.PreferencesSettingsService.FoldersWidgetExpanded), + 0); quickAccessWidget.CardInvoked -= QuickAccessWidget_CardInvoked; quickAccessWidget.CardNewPaneInvoked -= WidgetCardNewPaneInvoked; @@ -78,6 +82,8 @@ public void ReloadWidgets() quickAccessWidget.CardNewPaneInvoked += WidgetCardNewPaneInvoked; quickAccessWidget.CardPropertiesInvoked += QuickAccessWidget_CardPropertiesInvoked; } + + // Reload DrivesWidget if (shouldReloadDrivesWidget && drivesWidget is not null) { Widgets.ViewModel.InsertWidget(new(drivesWidget, (value) => UserSettingsService.PreferencesSettingsService.DrivesWidgetExpanded = value, () => UserSettingsService.PreferencesSettingsService.DrivesWidgetExpanded), 1); @@ -88,6 +94,8 @@ public void ReloadWidgets() drivesWidget.DrivesWidgetInvoked += DrivesWidget_DrivesWidgetInvoked; drivesWidget.DrivesWidgetNewPaneInvoked += DrivesWidget_DrivesWidgetNewPaneInvoked; } + + // Reload FileTags if (shouldReloadFileTags && fileTagsWidget is not null) { Widgets.ViewModel.InsertWidget(new(fileTagsWidget, (value) => UserSettingsService.PreferencesSettingsService.FileTagsWidgetExpanded = value, () => UserSettingsService.PreferencesSettingsService.FileTagsWidgetExpanded), 2); @@ -100,11 +108,15 @@ public void ReloadWidgets() fileTagsWidget.FileTagsNewPaneInvoked += WidgetCardNewPaneInvoked; _ = fileTagsWidget.ViewModel.InitAsync(); } + + // Reload BundlesWidget if (shouldReloadBundles && bundlesWidget is not null) { Widgets.ViewModel.InsertWidget(new(bundlesWidget, (value) => UserSettingsService.PreferencesSettingsService.BundlesWidgetExpanded = value, () => UserSettingsService.PreferencesSettingsService.BundlesWidgetExpanded), 3); ViewModel.LoadBundlesCommand.Execute(bundlesWidget.ViewModel); } + + // Reload RecentFilesWidget if (shouldReloadRecentFiles && recentFilesWidget is not null) { Widgets.ViewModel.InsertWidget(new(recentFilesWidget, (value) => UserSettingsService.PreferencesSettingsService.RecentFilesWidgetExpanded = value, () => UserSettingsService.PreferencesSettingsService.RecentFilesWidgetExpanded), 4); @@ -118,8 +130,9 @@ public void ReloadWidgets() private void ViewModel_YourHomeLoadedInvoked(object? sender, Microsoft.UI.Xaml.RoutedEventArgs e) { - // We must change the associatedInstance because only now it has loaded and not null + // NOTE: We must change the associatedInstance because only now it has loaded and not null ViewModel.ChangeAppInstance(AppInstance); + ReloadWidgets(); } @@ -127,9 +140,8 @@ private void ViewModel_YourHomeLoadedInvoked(object? sender, Microsoft.UI.Xaml.R private static ContentDialog SetContentDialogRoot(ContentDialog contentDialog) { if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) - { contentDialog.XamlRoot = App.Window.Content.XamlRoot; - } + return contentDialog; } @@ -144,10 +156,12 @@ private async void RecentFilesWidget_RecentFileInvoked(object sender, UserContro } else { - AppInstance.NavigateWithArguments(FolderSettings.GetLayoutType(e.ItemPath), new NavigationArguments() - { - NavPathParam = e.ItemPath - }); + AppInstance.NavigateWithArguments( + FolderSettings.GetLayoutType(e.ItemPath), + new() + { + NavPathParam = e.ItemPath + }); } } catch (UnauthorizedAccessException) @@ -155,12 +169,8 @@ private async void RecentFilesWidget_RecentFileInvoked(object sender, UserContro DynamicDialog dialog = DynamicDialogFactory.GetFor_ConsentDialog(); await SetContentDialogRoot(dialog).ShowAsync(); } - catch (COMException) - { - } - catch (ArgumentException) - { - } + catch (COMException) { } + catch (ArgumentException) { } } private void WidgetOpenLocationInvoked(object sender, UserControls.PathNavigationEventArgs e) @@ -179,7 +189,9 @@ private void QuickAccessWidget_CardInvoked(object sender, QuickAccessCardInvoked { NavPathParam = e.Path }); - AppInstance.InstanceViewModel.IsPageTypeNotHome = true; // show controls that were hidden on the home page + + // Show controls that were hidden on the home page + AppInstance.InstanceViewModel.IsPageTypeNotHome = true; } private void WidgetCardNewPaneInvoked(object sender, QuickAccessCardInvokedEventArgs e) @@ -196,6 +208,7 @@ private async void QuickAccessWidget_CardPropertiesInvoked(object sender, QuickA PrimaryItemAttribute = StorageItemTypes.Folder, ItemType = "Folder".GetLocalizedResource(), }; + await FilePropertiesHelpers.OpenPropertiesWindowAsync(listedItem, AppInstance); } @@ -210,12 +223,15 @@ private void DrivesWidget_DrivesWidgetInvoked(object sender, DrivesWidget.Drives { NavPathParam = e.Path }); - AppInstance.InstanceViewModel.IsPageTypeNotHome = true; // show controls that were hidden on the home page + + // Show controls that were hidden on the home page + AppInstance.InstanceViewModel.IsPageTypeNotHome = true; } protected override async void OnNavigatedTo(NavigationEventArgs eventArgs) { var parameters = eventArgs.Parameter as NavigationArguments; + AppInstance = parameters.AssociatedTabInstance; AppInstance.InstanceViewModel.IsPageTypeNotHome = false; AppInstance.InstanceViewModel.IsPageTypeSearchResults = false; @@ -240,11 +256,12 @@ protected override async void OnNavigatedTo(NavigationEventArgs eventArgs) AppInstance.ToolbarViewModel.PathComponents.Clear(); string componentLabel = parameters.NavPathParam == "Home" ? "Home".GetLocalizedResource() : parameters.NavPathParam; string tag = parameters.NavPathParam; - PathBoxItem item = new PathBoxItem() + var item = new PathBoxItem() { Title = componentLabel, Path = tag, }; + AppInstance.ToolbarViewModel.PathComponents.Add(item); base.OnNavigatedTo(eventArgs); } @@ -252,6 +269,7 @@ protected override async void OnNavigatedTo(NavigationEventArgs eventArgs) protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) { base.OnNavigatingFrom(e); + AppInstance.ToolbarViewModel.RefreshRequested -= ToolbarViewModel_RefreshRequested; } @@ -270,4 +288,4 @@ public void Dispose() ViewModel?.Dispose(); } } -} \ No newline at end of file +} diff --git a/src/Files.App/Views/LayoutModes/ColumnViewBase.xaml b/src/Files.App/Views/LayoutModes/ColumnViewBase.xaml index f40bde2cfb2b..46c029c3e091 100644 --- a/src/Files.App/Views/LayoutModes/ColumnViewBase.xaml +++ b/src/Files.App/Views/LayoutModes/ColumnViewBase.xaml @@ -1,447 +1,481 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + x:Class="Files.App.Views.LayoutModes.ColumnViewBase" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:cloud="using:Files.App.Filesystem.Cloud" + xmlns:converters="using:Files.App.Converters" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:filesystem="using:Files.App.Filesystem" + xmlns:helpers="using:Files.App.Helpers" + xmlns:local="using:Files.App" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:uc="using:Files.App.UserControls" + xmlns:valueconverters="using:Files.App.ValueConverters" + xmlns:wct="using:CommunityToolkit.WinUI.UI" + xmlns:wctconverters="using:CommunityToolkit.WinUI.UI.Converters" + x:Name="PageRoot" + mc:Ignorable="d"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Files.App/Views/LayoutModes/ColumnViewBase.xaml.cs b/src/Files.App/Views/LayoutModes/ColumnViewBase.xaml.cs index 3646d7576504..01ff2fb5b8e9 100644 --- a/src/Files.App/Views/LayoutModes/ColumnViewBase.xaml.cs +++ b/src/Files.App/Views/LayoutModes/ColumnViewBase.xaml.cs @@ -33,6 +33,7 @@ public sealed partial class ColumnViewBase : StandardViewBase protected override SemanticZoom RootZoom => RootGridZoom; private ColumnViewBrowser? columnsOwner; + private ListViewItem? openedFolderPresenter; public ColumnViewBase() : base() diff --git a/src/Files.App/Views/LayoutModes/ColumnViewBrowser.xaml.cs b/src/Files.App/Views/LayoutModes/ColumnViewBrowser.xaml.cs index ea404aa602b2..821930085e17 100644 --- a/src/Files.App/Views/LayoutModes/ColumnViewBrowser.xaml.cs +++ b/src/Files.App/Views/LayoutModes/ColumnViewBrowser.xaml.cs @@ -19,9 +19,11 @@ namespace Files.App.Views.LayoutModes public sealed partial class ColumnViewBrowser : BaseLayout { protected override uint IconSize => Browser.ColumnViewBrowser.ColumnViewSizeSmall; + protected override ItemsControl ItemsControl => ColumnHost; public string? OwnerPath { get; private set; } + public int FocusIndex { get; private set; } public ColumnViewBrowser() : base() @@ -116,6 +118,7 @@ protected override void OnNavigatedTo(NavigationEventArgs eventArgs) SearchPathParam = navigationArguments.SearchPathParam, NavPathParam = path }); + var index = 0; while (pathStack.TryPop(out path)) { @@ -137,14 +140,14 @@ protected override void InitializeCommandsViewModel() protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) { base.OnNavigatingFrom(e); + Dispose(); } - #region IDisposable - public override void Dispose() { base.Dispose(); + var columnHostItems = ColumnHost.Items.OfType().Select(blade => blade.Content as Frame); foreach (var frame in columnHostItems) { @@ -158,17 +161,18 @@ public override void Dispose() viewBase.KeyUp -= ColumnViewBase_KeyUp; } } + if (frame?.Content is UIElement element) element.GotFocus -= ColumnViewBrowser_GotFocus; + if (frame?.Content is IDisposable disposable) disposable.Dispose(); } + UnhookEvents(); CommandsViewModel?.Dispose(); } - #endregion IDisposable - private void DismissOtherBlades(ListView listView) { DismissOtherBlades(listView.FindAscendant()); @@ -188,19 +192,24 @@ private void DismissOtherBlades(int index) while (ColumnHost.ActiveBlades.Count > index + 1) { var frame = ColumnHost.ActiveBlades[index + 1].Content as Frame; + if (frame?.Content is IDisposable disposableContent) disposableContent.Dispose(); + if ((frame?.Content as ColumnShellPage)?.SlimContentPage is ColumnViewBase columnLayout) { columnLayout.ItemInvoked -= ColumnViewBase_ItemInvoked; columnLayout.ItemTapped -= ColumnViewBase_ItemTapped; columnLayout.KeyUp -= ColumnViewBase_KeyUp; } + (frame?.Content as UIElement).GotFocus -= ColumnViewBrowser_GotFocus; (frame?.Content as ColumnShellPage).ContentChanged -= ColumnViewBrowser_ContentChanged; + ColumnHost.Items.RemoveAt(index + 1); ColumnHost.ActiveBlades.RemoveAt(index + 1); } + if ((ColumnHost.ActiveBlades[index].Content as Frame)?.Content is ColumnShellPage s) { navigationArguments.NavPathParam = s.FilesystemViewModel.WorkingDirectory; @@ -208,6 +217,7 @@ private void DismissOtherBlades(int index) } }); } + ContentChanged(ActiveColumnShellPage); } @@ -223,6 +233,7 @@ private void ColumnViewBrowser_GotFocus(object sender, RoutedEventArgs e) { if (sender is not IShellPage shPage || shPage.IsCurrentInstance) return; + var currentBlade = ColumnHost.ActiveBlades.Single(x => (x.Content as Frame)?.Content == sender); currentBlade.StartBringIntoView(); if (ColumnHost.ActiveBlades is not null) @@ -233,6 +244,7 @@ private void ColumnViewBrowser_GotFocus(object sender, RoutedEventArgs e) shellPage.IsCurrentInstance = false; }); } + shPage.IsCurrentInstance = true; ContentChanged(shPage); } @@ -250,6 +262,7 @@ private void ColumnViewBrowser_ContentChanged(object sender, UserControls.Multit columnView.KeyUp -= ColumnViewBase_KeyUp; columnView.KeyUp += ColumnViewBase_KeyUp; } + ContentChanged(c); } @@ -291,7 +304,7 @@ public void MoveFocusToPreviousBlade(int currentBladeIndex) if (activeBladeColumnViewBase is null) return; - //This allows to deselect and reselect the parent folder, hence forcing the refocus. + // This allows to deselect and reselect the parent folder, hence forcing the refocus. var selectedItem = activeBladeColumnViewBase.FileList.SelectedItem; activeBladeColumnViewBase.FileList.SelectedItem = null; activeBladeColumnViewBase.FileList.SelectedItem = selectedItem; @@ -313,8 +326,10 @@ public void MoveFocusToNextBlade(int currentBladeIndex) private ColumnViewBase? RetrieveBladeColumnViewBase(BladeItem blade) { - if (blade.Content is not Frame activeBladeFrame || activeBladeFrame.Content is not ColumnShellPage activeBladePage) + if (blade.Content is not Frame activeBladeFrame || + activeBladeFrame.Content is not ColumnShellPage activeBladePage) return null; + return activeBladePage.SlimContentPage as ColumnViewBase; } @@ -337,9 +352,7 @@ public void SetSelectedPathOrNavigate(string navigationPath, Type sourcePageType } var destComponents = StorageFileExtensions.GetDirectoryPathComponents(destPath); - var (lastCommonItemIndex, relativeIndex) = GetLastCommonAndRelativeIndex(destComponents, columnPath, columnFirstPath); - if (relativeIndex < 0 || destComponents.Count - (lastCommonItemIndex + 1) > 1) // Going above parent or too deep down { ParentShellPageInstance?.NavigateToPath(navigationPath, sourcePageType, navArgs); @@ -357,6 +370,7 @@ public void SetSelectedPathOrNavigate(string navigationPath, Type sourcePageType Column = ColumnHost.ActiveBlades.IndexOf(newblade), NavPathParam = destComponents[ii].Path }; + if (navArgs is not null) { columnParam.IsSearchResultPage = navArgs.IsSearchResultPage; @@ -364,6 +378,7 @@ public void SetSelectedPathOrNavigate(string navigationPath, Type sourcePageType columnParam.SearchUnindexedItems = navArgs.SearchUnindexedItems; columnParam.SearchPathParam = navArgs.SearchPathParam; } + frame.Navigate(typeof(ColumnShellPage), columnParam); } } @@ -457,8 +472,9 @@ private void CloseUnnecessaryColumns(ColumnParam column) { Content = frame }; + ColumnHost.Items.Add(newblade); return (frame, newblade); } } -} \ No newline at end of file +} diff --git a/src/Files.App/Views/LayoutModes/DetailsLayoutBrowser.xaml b/src/Files.App/Views/LayoutModes/DetailsLayoutBrowser.xaml index 9e88c5990675..fd6dfbed2147 100644 --- a/src/Files.App/Views/LayoutModes/DetailsLayoutBrowser.xaml +++ b/src/Files.App/Views/LayoutModes/DetailsLayoutBrowser.xaml @@ -2,27 +2,25 @@ x:Class="Files.App.Views.LayoutModes.DetailsLayoutBrowser" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:behaviors2="using:Files.App.Behaviors" - xmlns:controls="using:CommunityToolkit.WinUI.UI.Controls" - xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters" - xmlns:converters1="using:Files.App.Converters" + xmlns:behaviors="using:Files.App.Behaviors" + xmlns:converters="using:Files.App.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:filesystem="using:Files.App.Filesystem" xmlns:filetags="using:Files.Backend.ViewModels.FileTags" xmlns:helpers="using:Files.App.Helpers" xmlns:i="using:Microsoft.Xaml.Interactivity" xmlns:icore="using:Microsoft.Xaml.Interactions.Core" - xmlns:layoutmode="Files.App.Views.LayoutModes" xmlns:local="using:Files.App" - xmlns:local2="using:Files.App.Filesystem" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:triggers="using:CommunityToolkit.WinUI.UI.Triggers" - xmlns:tui="using:CommunityToolkit.WinUI.UI" + xmlns:toolkit="using:CommunityToolkit.WinUI.UI.Controls" xmlns:uc="using:Files.App.UserControls" - xmlns:vc="using:Files.App.ValueConverters" - xmlns:winui="using:ABI.Microsoft.UI.Xaml.Controls" + xmlns:valueconverters="using:Files.App.ValueConverters" + xmlns:wct="using:CommunityToolkit.WinUI.UI" + xmlns:wctconverters="using:CommunityToolkit.WinUI.UI.Converters" x:Name="PageRoot" NavigationCacheMode="Enabled" mc:Ignorable="d"> + @@ -31,30 +29,30 @@ + - - + - - - - - + + + + + + + + + + + + - - - - - - - - - + + - + + - + + + + + + + + + + + + - \ No newline at end of file + diff --git a/src/Files.App/Views/LayoutModes/GridViewBrowser.xaml b/src/Files.App/Views/LayoutModes/GridViewBrowser.xaml index 825fe8f69e97..8cb552939f6a 100644 --- a/src/Files.App/Views/LayoutModes/GridViewBrowser.xaml +++ b/src/Files.App/Views/LayoutModes/GridViewBrowser.xaml @@ -1,26 +1,26 @@ - + @@ -29,30 +29,31 @@ - + + + - - + - - - + - - - + + + + + + + + + + + + Glyph="{x:Bind ((cloud:CloudDriveSyncStatusUI)SyncStatusUI).Glyph, Mode=OneWay}" /> + + + + + - + - + - + + + + + + + + + + + + + @@ -439,6 +467,7 @@ + + - @@ -473,7 +502,6 @@ - @@ -494,14 +522,11 @@ - + - + + + + + + - - + + @@ -568,6 +598,7 @@ + + - + - + + - - + + + - - + + + + + + + + + + - \ No newline at end of file + diff --git a/src/Files.App/Views/LayoutModes/GridViewBrowser.xaml.cs b/src/Files.App/Views/LayoutModes/GridViewBrowser.xaml.cs index d9cf4ef982c4..567b26edf37a 100644 --- a/src/Files.App/Views/LayoutModes/GridViewBrowser.xaml.cs +++ b/src/Files.App/Views/LayoutModes/GridViewBrowser.xaml.cs @@ -41,11 +41,11 @@ public bool IsPointerOver get { return (bool)GetValue(IsPointerOverProperty); } set { SetValue(IsPointerOverProperty, value); } } + public static readonly DependencyProperty IsPointerOverProperty = DependencyProperty.Register("IsPointerOver", typeof(bool), typeof(GridViewBrowser), new PropertyMetadata(false)); - public GridViewBrowser() - : base() + public GridViewBrowser() : base() { InitializeComponent(); DataContext = this; @@ -94,8 +94,11 @@ protected override void OnNavigatedTo(NavigationEventArgs eventArgs) FolderSettings.GroupOptionPreferenceUpdated += ZoomIn; FolderSettings.LayoutModeChangeRequested -= FolderSettings_LayoutModeChangeRequested; FolderSettings.LayoutModeChangeRequested += FolderSettings_LayoutModeChangeRequested; - SetItemTemplate(); // Set ItemTemplate + + // Set ItemTemplate + SetItemTemplate(); FileList.ItemsSource ??= ParentShellPageInstance.FilesystemViewModel.FilesAndFolders; + var parameters = (NavigationArguments)eventArgs.Parameter; if (parameters.IsLayoutSwitch) ReloadItemIcons(); @@ -104,6 +107,7 @@ protected override void OnNavigatedTo(NavigationEventArgs eventArgs) protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) { base.OnNavigatingFrom(e); + FolderSettings.LayoutModeChangeRequested -= FolderSettings_LayoutModeChangeRequested; FolderSettings.GridViewSizeChangeRequested -= FolderSettings_GridViewSizeChangeRequested; } @@ -112,7 +116,9 @@ private void FolderSettings_LayoutModeChangeRequested(object? sender, LayoutMode { if (FolderSettings.LayoutMode == FolderLayoutModes.GridView || FolderSettings.LayoutMode == FolderLayoutModes.TilesView) { - SetItemTemplate(); // Set ItemTemplate + // Set ItemTemplate + SetItemTemplate(); + var requestedIconSize = FolderSettings.GetIconSize(); if (requestedIconSize != currentIconSize) { @@ -147,6 +153,7 @@ private void SetItemMinWidth() protected override async void FileList_SelectionChanged(object sender, SelectionChangedEventArgs e) { base.FileList_SelectionChanged(sender, e); + if (e != null) { foreach (var item in e.AddedItems) @@ -167,9 +174,7 @@ override public void StartRenameItem() GridViewItem gridViewItem = FileList.ContainerFromItem(RenamingItem) as GridViewItem; if (gridViewItem is null) - { return; - } TextBox textBox = null; @@ -200,6 +205,7 @@ override public void StartRenameItem() int selectedTextLength = SelectedItem.Name.Length; if (!SelectedItem.IsShortcut && UserSettingsService.FoldersSettingsService.ShowFileExtensions) selectedTextLength -= extensionLength; + textBox.Select(0, selectedTextLength); IsRenamingItem = true; } @@ -222,7 +228,7 @@ protected override void EndRename(TextBox textBox) if (textBox is null || gridViewItem is null) { - // Navigating away, do nothing + // NOTE: Navigating away, do nothing } else if (FolderSettings.LayoutMode == FolderLayoutModes.GridView) { @@ -325,12 +331,15 @@ protected override bool CanGetItemFromElement(object element) private void FolderSettings_GridViewSizeChangeRequested(object? sender, EventArgs e) { SetItemMinWidth(); - var requestedIconSize = FolderSettings.GetIconSize(); // Get new icon size + + // Get new icon size + var requestedIconSize = FolderSettings.GetIconSize(); // Prevents reloading icons when the icon size hasn't changed if (requestedIconSize != currentIconSize) { - currentIconSize = requestedIconSize; // Update icon size before refreshing + // Update icon size before refreshing + currentIconSize = requestedIconSize; ReloadItemIcons(); } } @@ -359,12 +368,9 @@ private async void FileList_ItemTapped(object sender, TappedRoutedEventArgs e) return; // Skip code if the control or shift key is pressed or if the user is using multiselect - if - ( - ctrlPressed || + if (ctrlPressed || shiftPressed || - clickedItem is Microsoft.UI.Xaml.Shapes.Rectangle - ) + clickedItem is Microsoft.UI.Xaml.Shapes.Rectangle) { e.Handled = true; return; @@ -390,11 +396,13 @@ clickedItem is Microsoft.UI.Xaml.Shapes.Rectangle { Popup popup = gridViewItem.FindDescendant("EditPopup") as Popup; var textBox = popup.Child as TextBox; + await CommitRename(textBox); } else { var textBox = gridViewItem.FindDescendant("TileViewTextBoxItemName") as TextBox; + await CommitRename(textBox); } } @@ -405,27 +413,28 @@ clickedItem is Microsoft.UI.Xaml.Shapes.Rectangle private void FileList_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e) { // Skip opening selected items if the double tap doesn't capture an item - if ((e.OriginalSource as FrameworkElement)?.DataContext is ListedItem item - && !UserSettingsService.FoldersSettingsService.OpenItemsWithOneClick) - { + if ((e.OriginalSource as FrameworkElement)?.DataContext is ListedItem item && + !UserSettingsService.FoldersSettingsService.OpenItemsWithOneClick) _ = NavigationHelpers.OpenSelectedItems(ParentShellPageInstance, false); - } else if (UserSettingsService.FoldersSettingsService.DoubleClickToGoUp) - { ParentShellPageInstance.Up_Click(); - } + ResetRenameDoubleClick(); } private void ItemSelected_Checked(object sender, RoutedEventArgs e) { - if (sender is CheckBox checkBox && checkBox.DataContext is ListedItem item && !FileList.SelectedItems.Contains(item)) + if (sender is CheckBox checkBox && + checkBox.DataContext is ListedItem item && + !FileList.SelectedItems.Contains(item)) FileList.SelectedItems.Add(item); } private void ItemSelected_Unchecked(object sender, RoutedEventArgs e) { - if (sender is CheckBox checkBox && checkBox.DataContext is ListedItem item && FileList.SelectedItems.Contains(item)) + if (sender is CheckBox checkBox && + checkBox.DataContext is ListedItem item && + FileList.SelectedItems.Contains(item)) FileList.SelectedItems.Remove(item); } @@ -460,6 +469,7 @@ private void SetCheckboxSelectionState(object item, GridViewItem? lviContainer = checkbox.Checked += ItemSelected_Checked; checkbox.Unchecked += ItemSelected_Unchecked; } + UpdateCheckboxVisibility(container); } } @@ -469,8 +479,10 @@ private void Grid_Loaded(object sender, RoutedEventArgs e) // This is the best way I could find to set the context flyout, as doing it in the styles isn't possible // because you can't use bindings in the setters DependencyObject item = VisualTreeHelper.GetParent(sender as Grid); + while (item is not GridViewItem) item = VisualTreeHelper.GetParent(item); + if (item is GridViewItem itemContainer) itemContainer.ContextFlyout = ItemContextMenuFlyout; } @@ -505,4 +517,4 @@ private void UpdateCheckboxVisibility(object sender, bool? isPointerOver = null) } } } -} \ No newline at end of file +} diff --git a/src/Files.App/Views/LayoutModes/StandardLayoutMode.cs b/src/Files.App/Views/LayoutModes/StandardLayoutMode.cs index 27720c39af77..37e258c3983b 100644 --- a/src/Files.App/Views/LayoutModes/StandardLayoutMode.cs +++ b/src/Files.App/Views/LayoutModes/StandardLayoutMode.cs @@ -26,21 +26,14 @@ public abstract class StandardViewBase : BaseLayout protected int NextRenameIndex = 0; - protected abstract ListViewBase ListViewBase - { - get; - } + protected abstract ListViewBase ListViewBase { get; } protected override ItemsControl ItemsControl => ListViewBase; - protected abstract SemanticZoom RootZoom - { - get; - } + protected abstract SemanticZoom RootZoom { get; } public StandardViewBase() : base() { - } protected override void InitializeCommandsViewModel() @@ -51,6 +44,7 @@ protected override void InitializeCommandsViewModel() protected override void HookEvents() { UnhookEvents(); + ItemManipulationModel.FocusFileListInvoked += ItemManipulationModel_FocusFileListInvoked; ItemManipulationModel.SelectAllItemsInvoked += ItemManipulationModel_SelectAllItemsInvoked; ItemManipulationModel.ClearSelectionInvoked += ItemManipulationModel_ClearSelectionInvoked; @@ -96,6 +90,7 @@ protected virtual async void ReloadSelectedItemIcon() { ParentShellPageInstance.FilesystemViewModel.CancelExtendedPropertiesLoading(); ParentShellPageInstance.SlimContentPage.SelectedItem.ItemPropertiesInitialized = false; + await ParentShellPageInstance.FilesystemViewModel.LoadExtendedItemProperties(ParentShellPageInstance.SlimContentPage.SelectedItem, IconSize); } @@ -217,6 +212,7 @@ protected virtual async Task CommitRename(TextBox textBox) { EndRename(textBox); string newItemName = textBox.Text.Trim().TrimEnd('.'); + await UIFilesystemHelpers.RenameFileItemAsync(RenamingItem, newItemName, ParentShellPageInstance); } @@ -276,11 +272,8 @@ protected async void RenameTextBox_KeyDown(object sender, KeyRoutedEventArgs e) NextRenameIndex = 0; EndRename(textBox); - if - ( - newIndex >= 0 && - newIndex < ListViewBase.Items.Count - ) + if (newIndex >= 0 && + newIndex < ListViewBase.Items.Count) { ListViewBase.SelectedIndex = newIndex; StartRenameItem(); @@ -297,11 +290,8 @@ protected bool TryStartRenameNextItem(ListedItem item) var nextItemIndex = ListViewBase.Items.IndexOf(item) + NextRenameIndex; NextRenameIndex = 0; - if - ( - nextItemIndex >= 0 && - nextItemIndex < ListViewBase.Items.Count - ) + if (nextItemIndex >= 0 && + nextItemIndex < ListViewBase.Items.Count) { ListViewBase.SelectedIndex = nextItemIndex; StartRenameItem(); diff --git a/src/Files.App/Views/MainPage.xaml b/src/Files.App/Views/MainPage.xaml index 67c6538ef1ba..56ba31364f69 100644 --- a/src/Files.App/Views/MainPage.xaml +++ b/src/Files.App/Views/MainPage.xaml @@ -2,17 +2,18 @@ x:Class="Files.App.Views.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:controls="using:Files.App.UserControls" - xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters" - xmlns:custom="using:CommunityToolkit.WinUI.UI.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:i="using:Microsoft.Xaml.Interactivity" xmlns:icore="using:Microsoft.Xaml.Interactions.Core" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:toolkit="using:CommunityToolkit.WinUI.UI.Controls" + xmlns:uc="using:Files.App.UserControls" xmlns:usercontrols="using:Files.App.UserControls.MultitaskingControl" xmlns:viewmodels="using:Files.App.ViewModels" + xmlns:wctconverters="using:CommunityToolkit.WinUI.UI.Converters" AllowDrop="True" Background="{ThemeResource App.Theme.BackgroundBrush}" + DataContext="{x:Bind ViewModel, Mode=OneWay}" KeyboardAcceleratorPlacementMode="Hidden" Loaded="Page_Loaded" NavigationCacheMode="Required" @@ -28,7 +29,8 @@ True False - + + @@ -106,7 +108,8 @@ - + - + + + + @@ -164,7 +169,8 @@ - + + - + + - - + + - + - + - + + - + + @@ -263,7 +277,6 @@ - @@ -283,4 +296,4 @@ - \ No newline at end of file + diff --git a/src/Files.App/Views/MainPage.xaml.cs b/src/Files.App/Views/MainPage.xaml.cs index 75a2adcc1005..ff3f69b41474 100644 --- a/src/Files.App/Views/MainPage.xaml.cs +++ b/src/Files.App/Views/MainPage.xaml.cs @@ -20,6 +20,7 @@ using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Navigation; +using Microsoft.Windows.ApplicationModel.Resources; using System; using System.ComponentModel; using System.Runtime.CompilerServices; @@ -32,26 +33,22 @@ namespace Files.App.Views { - /// - /// The root page of Files - /// public sealed partial class MainPage : Page, INotifyPropertyChanged { - private VirtualKeyModifiers currentModifiers = VirtualKeyModifiers.None; + public IUserSettingsService UserSettingsService { get; } - public IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); - public ICommandManager Commands { get; } = Ioc.Default.GetRequiredService(); - public IWindowContext WindowContext { get; } = Ioc.Default.GetRequiredService(); + public ICommandManager Commands { get; } - public SidebarViewModel SidebarAdaptiveViewModel = Ioc.Default.GetRequiredService(); + public IWindowContext WindowContext { get; } - public AppModel AppModel => App.AppModel; + public SidebarViewModel SidebarAdaptiveViewModel { get; } - public MainPageViewModel ViewModel - { - get => (MainPageViewModel)DataContext; - set => DataContext = value; - } + public MainPageViewModel ViewModel { get; } + + public OngoingTasksViewModel OngoingTasksViewModel { get; } + + public static AppModel AppModel + => App.AppModel; /// /// True if the user is currently resizing the preview pane @@ -60,14 +57,19 @@ public MainPageViewModel ViewModel private bool keyReleased = true; - public readonly OngoingTasksViewModel OngoingTasksViewModel; - public MainPage() { InitializeComponent(); - DataContext = Ioc.Default.GetRequiredService(); + + // Dependency Injection + UserSettingsService = Ioc.Default.GetRequiredService(); + Commands = Ioc.Default.GetRequiredService(); + WindowContext = Ioc.Default.GetRequiredService(); + SidebarAdaptiveViewModel = Ioc.Default.GetRequiredService(); + ViewModel = Ioc.Default.GetRequiredService(); OngoingTasksViewModel = Ioc.Default.GetRequiredService(); - var flowDirectionSetting = new Microsoft.Windows.ApplicationModel.Resources.ResourceManager().CreateResourceContext().QualifierValues["LayoutDirection"]; + + var flowDirectionSetting = new ResourceManager().CreateResourceContext().QualifierValues["LayoutDirection"]; if (flowDirectionSetting == "RTL") FlowDirection = FlowDirection.RightToLeft; @@ -85,7 +87,6 @@ private async Task PromptForReview() }; var result = await SetContentDialogRoot(promptForReviewDialog).ShowAsync(); - if (result == ContentDialogResult.Primary) { try @@ -104,6 +105,7 @@ private ContentDialog SetContentDialogRoot(ContentDialog contentDialog) { if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) contentDialog.XamlRoot = App.Window.Content.XamlRoot; + return contentDialog; } @@ -131,7 +133,8 @@ private void HorizontalMultitaskingControl_Loaded(object sender, RoutedEventArgs private void SetRectDragRegion() { - DragZoneHelper.SetDragZones(App.Window, + DragZoneHelper.SetDragZones( + App.Window, dragZoneLeftIndent: (int)(TabControl.ActualWidth + TabControl.Margin.Left - TabControl.DragArea.ActualWidth)); } @@ -143,6 +146,7 @@ public void TabItemContent_ContentChanged(object? sender, TabItemArguments e) var paneArgs = e.NavigationArg as PaneNavigationArguments; SidebarAdaptiveViewModel.UpdateSidebarSelectedItemFromArgs(SidebarAdaptiveViewModel.PaneHolder.IsLeftPaneActive ? paneArgs.LeftPaneNavPathParam : paneArgs.RightPaneNavPathParam); + UpdateStatusBarProperties(); LoadPaneChanged(); UpdateNavToolbarProperties(); @@ -158,10 +162,12 @@ public void MultitaskingControl_CurrentInstanceChanged(object? sender, CurrentIn SidebarAdaptiveViewModel.PaneHolder = e.CurrentInstance as IPaneHolder; SidebarAdaptiveViewModel.PaneHolder.PropertyChanged += PaneHolder_PropertyChanged; SidebarAdaptiveViewModel.NotifyInstanceRelatedPropertiesChanged((navArgs as PaneNavigationArguments).LeftPaneNavPathParam); + UpdateStatusBarProperties(); UpdateNavToolbarProperties(); LoadPaneChanged(); ViewModel.UpdateInstanceProperties(navArgs); + e.CurrentInstance.ContentChanged -= TabItemContent_ContentChanged; e.CurrentInstance.ContentChanged += TabItemContent_ContentChanged; } @@ -199,6 +205,7 @@ private void UpdateNavToolbarProperties() protected override void OnNavigatedTo(NavigationEventArgs e) { ViewModel.OnNavigatedTo(e); + SidebarControl.SidebarItemInvoked += SidebarControl_SidebarItemInvoked; SidebarControl.SidebarItemPropertiesInvoked += SidebarControl_SidebarItemPropertiesInvoked; SidebarControl.SidebarItemDropped += SidebarControl_SidebarItemDropped; @@ -226,13 +233,10 @@ protected override async void OnPreviewKeyDown(KeyRoutedEventArgs e) if (isTextBox) { if (hotKey.IsTextBoxHotKey()) - { break; - } + if (currentModifiers is VirtualKeyModifiers.None && !e.Key.IsGlobalKey()) - { break; - } } // Execute command for hotkey @@ -282,13 +286,9 @@ private async void SidebarControl_SidebarItemDropped(object sender, SidebarItemD private async void SidebarControl_SidebarItemPropertiesInvoked(object sender, SidebarItemPropertiesInvokedEventArgs e) { if (e.InvokedItemDataContext is DriveItem) - { await FilePropertiesHelpers.OpenPropertiesWindowAsync(e.InvokedItemDataContext, SidebarAdaptiveViewModel.PaneHolder.ActivePane); - } else if (e.InvokedItemDataContext is LibraryLocationItem library) - { await FilePropertiesHelpers.OpenPropertiesWindowAsync(new LibraryItem(library), SidebarAdaptiveViewModel.PaneHolder.ActivePane); - } else if (e.InvokedItemDataContext is LocationItem locationItem) { ListedItem listedItem = new ListedItem(null!) @@ -298,6 +298,7 @@ private async void SidebarControl_SidebarItemPropertiesInvoked(object sender, Si PrimaryItemAttribute = StorageItemTypes.Folder, ItemType = "Folder".GetLocalizedResource(), }; + await FilePropertiesHelpers.OpenPropertiesWindowAsync(listedItem, SidebarAdaptiveViewModel.PaneHolder.ActivePane); } } @@ -312,32 +313,38 @@ private void SidebarControl_SidebarItemInvoked(object sender, SidebarItemInvoked { var invokedItemContainer = e.InvokedItemContainer; - string? navigationPath; // path to navigate - Type? sourcePageType = null; // type of page to navigate + // Path to navigate + string? navigationPath; + + // Type of page to navigate + Type? sourcePageType = null; switch ((invokedItemContainer.DataContext as INavigationControlItem)?.ItemType) { case NavigationControlItemType.Location: { - var ItemPath = (invokedItemContainer.DataContext as INavigationControlItem)?.Path; // Get the path of the invoked item + // Get the path of the invoked item + var ItemPath = (invokedItemContainer.DataContext as INavigationControlItem)?.Path; - if (string.IsNullOrEmpty(ItemPath)) // Section item + // Section item + if (string.IsNullOrEmpty(ItemPath)) { navigationPath = invokedItemContainer.Tag?.ToString(); } - else if (ItemPath.Equals("Home", StringComparison.OrdinalIgnoreCase)) // Home item + // Home item + else if (ItemPath.Equals("Home", StringComparison.OrdinalIgnoreCase)) { if (ItemPath.Equals(SidebarAdaptiveViewModel.SidebarSelectedItem?.Path, StringComparison.OrdinalIgnoreCase)) return; // return if already selected navigationPath = "Home"; - sourcePageType = typeof(WidgetsPage); + sourcePageType = typeof(HomePage); } - else // Any other item + // Any other item + else { navigationPath = invokedItemContainer.Tag?.ToString(); } - break; } @@ -403,7 +410,8 @@ private void Page_SizeChanged(object sender, SizeChangedEventArgs e) private void SidebarControl_Loaded(object sender, RoutedEventArgs e) { - SidebarAdaptiveViewModel.UpdateTabControlMargin(); // Set the correct tab margin on startup + // Set the correct tab margin on startup + SidebarAdaptiveViewModel.UpdateTabControlMargin(); } private void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e) => LoadPaneChanged(); @@ -555,4 +563,4 @@ private void RootGrid_PreviewKeyDown(object sender, KeyRoutedEventArgs e) private void NavToolbar_Loaded(object sender, RoutedEventArgs e) => UpdateNavToolbarProperties(); } -} \ No newline at end of file +} diff --git a/src/Files.App/Views/ModernShellPage.xaml b/src/Files.App/Views/ModernShellPage.xaml index aa6e585a3805..9f986f4defe9 100644 --- a/src/Files.App/Views/ModernShellPage.xaml +++ b/src/Files.App/Views/ModernShellPage.xaml @@ -2,19 +2,19 @@ x:Class="Files.App.Views.ModernShellPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:Files.App.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:wctconverters="using:CommunityToolkit.WinUI.UI.Converters" x:Name="RootPage" KeyboardAcceleratorPlacementMode="Hidden" Loaded="Page_Loaded" mc:Ignorable="d"> + - - - + + @@ -83,4 +83,5 @@ BorderBrush="{x:Bind CurrentInstanceBorderBrush, Mode=OneWay}" BorderThickness="{x:Bind CurrentInstanceBorderThickness, Mode=OneWay}" Navigated="ItemDisplayFrame_Navigated" /> - \ No newline at end of file + + diff --git a/src/Files.App/Views/ModernShellPage.xaml.cs b/src/Files.App/Views/ModernShellPage.xaml.cs index c23632faa699..be80b37ae831 100644 --- a/src/Files.App/Views/ModernShellPage.xaml.cs +++ b/src/Files.App/Views/ModernShellPage.xaml.cs @@ -25,14 +25,15 @@ namespace Files.App.Views public sealed partial class ModernShellPage : BaseShellPage { public override bool CanNavigateBackward => ItemDisplayFrame.CanGoBack; + public override bool CanNavigateForward => ItemDisplayFrame.CanGoForward; protected override Frame ItemDisplay => ItemDisplayFrame; public Thickness CurrentInstanceBorderThickness { - get { return (Thickness)GetValue(CurrentInstanceBorderThicknessProperty); } - set { SetValue(CurrentInstanceBorderThicknessProperty, value); } + get => (Thickness)GetValue(CurrentInstanceBorderThicknessProperty); + set => SetValue(CurrentInstanceBorderThicknessProperty, value); } // Using a DependencyProperty as the backing store for CurrentInstanceBorderThickness. This enables animation, styling, binding, etc... @@ -57,7 +58,7 @@ public ModernShellPage() : base(new CurrentInstanceViewModel()) private void ModernShellPage_RefreshWidgetsRequested(object sender, EventArgs e) { - if (ItemDisplayFrame?.Content is WidgetsPage currentPage) + if (ItemDisplayFrame?.Content is HomePage currentPage) currentPage.RefreshWidgetList(); } @@ -74,6 +75,7 @@ protected override void FolderSettings_LayoutPreferencesUpdateRequired(object se protected override void OnNavigatedTo(NavigationEventArgs eventArgs) { base.OnNavigatedTo(eventArgs); + if (eventArgs.Parameter is string navPath) NavParams = new NavigationParams { NavPath = navPath }; else if (eventArgs.Parameter is NavigationParams navParams) @@ -98,6 +100,7 @@ public NavigationParams NavParams if (value != navParams) { navParams = value; + if (IsLoaded) OnNavigationParamsChanged(); } @@ -108,7 +111,8 @@ protected override void OnNavigationParamsChanged() { if (string.IsNullOrEmpty(NavParams?.NavPath) || NavParams.NavPath == "Home") { - ItemDisplayFrame.Navigate(typeof(WidgetsPage), + ItemDisplayFrame.Navigate( + typeof(HomePage), new NavigationArguments() { NavPathParam = NavParams?.NavPath, @@ -119,7 +123,8 @@ protected override void OnNavigationParamsChanged() { var isTagSearch = NavParams.NavPath.StartsWith("tag:"); - ItemDisplayFrame.Navigate(InstanceViewModel.FolderSettings.GetLayoutType(NavParams.NavPath), + ItemDisplayFrame.Navigate( + InstanceViewModel.FolderSettings.GetLayoutType(NavParams.NavPath), new NavigationArguments() { NavPathParam = NavParams.NavPath, @@ -151,6 +156,7 @@ private async void ItemDisplayFrame_Navigated(object sender, NavigationEventArgs ToolbarViewModel.SearchBox.Query = string.Empty; ToolbarViewModel.IsSearchBoxVisible = false; } + ToolbarViewModel.UpdateAdditionalActions(); if (ItemDisplayFrame.CurrentSourcePageType == (typeof(DetailsLayoutBrowser)) || ItemDisplayFrame.CurrentSourcePageType == typeof(GridViewBrowser)) @@ -158,13 +164,15 @@ private async void ItemDisplayFrame_Navigated(object sender, NavigationEventArgs // Reset DataGrid Rows that may be in "cut" command mode ContentPage.ResetItemOpacity(); } + var parameters = e.Parameter as NavigationArguments; var isTagSearch = parameters.NavPathParam is not null && parameters.NavPathParam.StartsWith("tag:"); - TabItemArguments = new TabItemArguments() + TabItemArguments = new() { InitialPageType = typeof(ModernShellPage), NavigationArg = parameters.IsSearchResultPage && !isTagSearch ? parameters.SearchPathParam : parameters.NavPathParam }; + if (parameters.IsLayoutSwitch) FilesystemViewModel_DirectoryInfoUpdated(sender, EventArgs.Empty); } @@ -172,8 +180,9 @@ private async void ItemDisplayFrame_Navigated(object sender, NavigationEventArgs private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) { args.Handled = true; - var tabInstance = CurrentPageType == typeof(DetailsLayoutBrowser) || - CurrentPageType == typeof(GridViewBrowser); + var tabInstance = + CurrentPageType == typeof(DetailsLayoutBrowser) || + CurrentPageType == typeof(GridViewBrowser); var ctrl = args.KeyboardAccelerator.Modifiers.HasFlag(VirtualKeyModifiers.Control); var shift = args.KeyboardAccelerator.Modifiers.HasFlag(VirtualKeyModifiers.Shift); @@ -181,23 +190,23 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo switch (c: ctrl, s: shift, a: alt, t: tabInstance, k: args.KeyboardAccelerator.Key) { - case (true, false, false, true, VirtualKey.Z): // ctrl + z, undo + // Ctrl + Z, Undo + case (true, false, false, true, VirtualKey.Z): if (!InstanceViewModel.IsPageTypeSearchResults) await storageHistoryHelpers.TryUndo(); - break; - - case (true, false, false, true, VirtualKey.Y): // ctrl + y, redo + // Ctrl + Y, Redo + case (true, false, false, true, VirtualKey.Y): if (!InstanceViewModel.IsPageTypeSearchResults) await storageHistoryHelpers.TryRedo(); - break; - - case (true, true, false, true, VirtualKey.N): // ctrl + shift + n, new item + // Ctrl + Shift + N, New item + case (true, true, false, true, VirtualKey.N): if (InstanceViewModel.CanCreateFileInPage) { var addItemDialogViewModel = new AddItemDialogViewModel(); await dialogService.ShowDialogAsync(addItemDialogViewModel); + if (addItemDialogViewModel.ResultType.ItemType == AddItemDialogItemType.Shortcut) CreateNewShortcutFromDialog(); else if (addItemDialogViewModel.ResultType.ItemType != AddItemDialogItemType.Cancel) @@ -207,40 +216,39 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo this); } break; - - case (false, true, false, true, VirtualKey.Delete): // shift + delete, PermanentDelete + // Shift + Del, Permanent delete + case (false, true, false, true, VirtualKey.Delete): if (ContentPage.IsItemSelected && !ToolbarViewModel.IsEditModeEnabled && !InstanceViewModel.IsPageTypeSearchResults) { var items = SlimContentPage.SelectedItems.ToList().Select((item) => StorageHelpers.FromPathAndType( item.ItemPath, item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)); + await FilesystemHelpers.DeleteItemsAsync(items, userSettingsService.FoldersSettingsService.DeleteConfirmationPolicy, true, true); } - break; - - case (true, false, false, true, VirtualKey.V): // ctrl + v, paste + // Ctrl + V, Paste + case (true, false, false, true, VirtualKey.V): if (!ToolbarViewModel.IsEditModeEnabled && !ContentPage.IsRenamingItem && !InstanceViewModel.IsPageTypeSearchResults && !ToolbarViewModel.SearchHasFocus) await UIFilesystemHelpers.PasteItemAsync(FilesystemViewModel.WorkingDirectory, this); - break; - - case (true, false, false, true, VirtualKey.D): // ctrl + d, delete item + // Ctrl + D, Delete item + case (true, false, false, true, VirtualKey.D): if (ContentPage.IsItemSelected && !ContentPage.IsRenamingItem && !InstanceViewModel.IsPageTypeSearchResults) { var items = SlimContentPage.SelectedItems.ToList().Select((item) => StorageHelpers.FromPathAndType( item.ItemPath, item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)); + await FilesystemHelpers.DeleteItemsAsync(items, userSettingsService.FoldersSettingsService.DeleteConfirmationPolicy, false, true); } - break; - - case (false, false, true, _, VirtualKey.D): // alt + d, select address bar (english) - case (true, false, false, _, VirtualKey.L): // ctrl + l, select address bar - if (tabInstance || CurrentPageType == typeof(WidgetsPage)) + // Alt + D, Select address bar (English) + case (false, false, true, _, VirtualKey.D): + // Ctrl + L, Select address bar + case (true, false, false, _, VirtualKey.L): + if (tabInstance || CurrentPageType == typeof(HomePage)) ToolbarViewModel.IsEditModeEnabled = true; - break; } } @@ -273,10 +281,10 @@ public override void Up_Click() return; bool isPathRooted = string.Equals(FilesystemViewModel.WorkingDirectory, PathNormalization.GetPathRoot(FilesystemViewModel.WorkingDirectory), StringComparison.OrdinalIgnoreCase); - if (isPathRooted) { - ItemDisplayFrame.Navigate(typeof(WidgetsPage), + ItemDisplayFrame.Navigate( + typeof(HomePage), new NavigationArguments() { NavPathParam = "Home", @@ -296,7 +304,8 @@ public override void Up_Click() parentDirectoryOfPath += '\\'; SelectSidebarItemFromPath(); - ItemDisplayFrame.Navigate(InstanceViewModel.FolderSettings.GetLayoutType(parentDirectoryOfPath), + ItemDisplayFrame.Navigate( + InstanceViewModel.FolderSettings.GetLayoutType(parentDirectoryOfPath), new NavigationArguments() { NavPathParam = parentDirectoryOfPath, @@ -314,7 +323,8 @@ public override void Dispose() public override void NavigateHome() { - ItemDisplayFrame.Navigate(typeof(WidgetsPage), + ItemDisplayFrame.Navigate( + typeof(HomePage), new NavigationArguments() { NavPathParam = "Home", @@ -330,9 +340,9 @@ public override void NavigateToPath(string? navigationPath, Type? sourcePageType if (navArgs is not null && navArgs.AssociatedTabInstance is not null) { ItemDisplayFrame.Navigate( - sourcePageType, - navArgs, - new SuppressNavigationTransitionInfo()); + sourcePageType, + navArgs, + new SuppressNavigationTransitionInfo()); } else { @@ -343,7 +353,7 @@ public override void NavigateToPath(string? navigationPath, Type? sourcePageType StringComparison.OrdinalIgnoreCase)) && (TabItemArguments.NavigationArg is not string navArg || string.IsNullOrEmpty(navArg) || - !navArg.StartsWith("tag:"))) // return if already selected + !navArg.StartsWith("tag:"))) // Return if already selected { if (InstanceViewModel?.FolderSettings is FolderSettingsViewModel fsModel) fsModel.IsLayoutModeChanging = false; @@ -356,21 +366,21 @@ public override void NavigateToPath(string? navigationPath, Type? sourcePageType NavigationTransitionInfo transition = new SuppressNavigationTransitionInfo(); - if (sourcePageType == typeof(WidgetsPage) - || ItemDisplayFrame.Content.GetType() == typeof(WidgetsPage) && + if (sourcePageType == typeof(HomePage) || + ItemDisplayFrame.Content.GetType() == typeof(HomePage) && (sourcePageType == typeof(DetailsLayoutBrowser) || sourcePageType == typeof(GridViewBrowser))) { transition = new SuppressNavigationTransitionInfo(); } ItemDisplayFrame.Navigate( - sourcePageType, - new NavigationArguments() - { - NavPathParam = navigationPath, - AssociatedTabInstance = this - }, - transition); + sourcePageType, + new NavigationArguments() + { + NavPathParam = navigationPath, + AssociatedTabInstance = this + }, + transition); } ToolbarViewModel.PathControlDisplayText = FilesystemViewModel.WorkingDirectory; diff --git a/src/Files.App/Views/PaneHolderPage.xaml b/src/Files.App/Views/PaneHolderPage.xaml index 2c14bffa4da9..a5debb7d91a3 100644 --- a/src/Files.App/Views/PaneHolderPage.xaml +++ b/src/Files.App/Views/PaneHolderPage.xaml @@ -2,15 +2,14 @@ x:Class="Files.App.Views.PaneHolderPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:Core="using:Microsoft.Xaml.Interactions.Core" - xmlns:Custom="using:CommunityToolkit.WinUI.UI.Controls" - xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" - xmlns:animations="using:CommunityToolkit.WinUI.UI.Animations" xmlns:converters="using:Files.App.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:i="using:Microsoft.Xaml.Interactivity" + xmlns:icore="using:Microsoft.Xaml.Interactions.Core" xmlns:local="using:Files.App.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:mconv="using:CommunityToolkit.WinUI.UI.Converters" + xmlns:toolkit="using:CommunityToolkit.WinUI.UI.Controls" + xmlns:wctconverters="using:CommunityToolkit.WinUI.UI.Converters" mc:Ignorable="d"> @@ -33,15 +32,39 @@ - + + - + + + + + + + + + + + - + - + - - + + - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - - + + - - - - + + + - - - - - - - - \ No newline at end of file + diff --git a/src/Files.App/Views/PaneHolderPage.xaml.cs b/src/Files.App/Views/PaneHolderPage.xaml.cs index 51575bded2b0..7a724c7104db 100644 --- a/src/Files.App/Views/PaneHolderPage.xaml.cs +++ b/src/Files.App/Views/PaneHolderPage.xaml.cs @@ -21,17 +21,20 @@ public sealed partial class PaneHolderPage : Page, IPaneHolder, ITabItemContent private IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); - public bool IsLeftPaneActive => ActivePane == PaneLeft; - public bool IsRightPaneActive => ActivePane == PaneRight; + public bool IsLeftPaneActive + => ActivePane == PaneLeft; + + public bool IsRightPaneActive + => ActivePane == PaneRight; public event EventHandler ContentChanged; public event PropertyChangedEventHandler PropertyChanged; - public IFilesystemHelpers FilesystemHelpers => ActivePane?.FilesystemHelpers; + public IFilesystemHelpers FilesystemHelpers + => ActivePane?.FilesystemHelpers; private TabItemArguments tabItemArguments; - public TabItemArguments TabItemArguments { get => tabItemArguments; @@ -40,13 +43,13 @@ public TabItemArguments TabItemArguments if (tabItemArguments != value) { tabItemArguments = value; + ContentChanged?.Invoke(this, value); } } } private bool _windowIsCompact = App.Window.Bounds.Width <= 750; - private bool windowIsCompact { get => _windowIsCompact; @@ -55,6 +58,7 @@ private bool windowIsCompact if (value != _windowIsCompact) { _windowIsCompact = value; + if (value) { wasRightPaneVisible = isRightPaneVisible; @@ -65,6 +69,7 @@ private bool windowIsCompact IsRightPaneVisible = true; wasRightPaneVisible = false; } + NotifyPropertyChanged(nameof(IsMultiPaneEnabled)); } } @@ -72,15 +77,13 @@ private bool windowIsCompact private bool wasRightPaneVisible; - public bool IsMultiPaneActive => IsRightPaneVisible; + public bool IsMultiPaneActive + => IsRightPaneVisible; public bool IsMultiPaneEnabled - { - get => !(App.Window.Bounds.Width <= 750); - } + => !(App.Window.Bounds.Width <= 750); private NavigationParams navParamsLeft; - public NavigationParams NavParamsLeft { get => navParamsLeft; @@ -89,13 +92,13 @@ public NavigationParams NavParamsLeft if (navParamsLeft != value) { navParamsLeft = value; + NotifyPropertyChanged(nameof(NavParamsLeft)); } } } private NavigationParams navParamsRight; - public NavigationParams NavParamsRight { get => navParamsRight; @@ -104,13 +107,13 @@ public NavigationParams NavParamsRight if (navParamsRight != value) { navParamsRight = value; + NotifyPropertyChanged(nameof(NavParamsRight)); } } } private IShellPage activePane; - public IShellPage ActivePane { get => activePane; @@ -119,15 +122,14 @@ public IShellPage ActivePane if (activePane != value) { activePane = value; + PaneLeft.IsCurrentInstance = false; + if (PaneRight is not null) - { PaneRight.IsCurrentInstance = false; - } if (ActivePane is not null) - { ActivePane.IsCurrentInstance = isCurrentInstance; - } + NotifyPropertyChanged(nameof(ActivePane)); NotifyPropertyChanged(nameof(IsLeftPaneActive)); NotifyPropertyChanged(nameof(IsRightPaneActive)); @@ -142,16 +144,13 @@ public IShellPage ActivePaneOrColumn get { if (ActivePane is not null && ActivePane.IsColumnView) - { return (ActivePane.SlimContentPage as ColumnViewBrowser).ActiveColumnShellPage; - } return ActivePane ?? PaneLeft; } } private bool isRightPaneVisible; - public bool IsRightPaneVisible { get => isRightPaneVisible; @@ -161,9 +160,8 @@ public bool IsRightPaneVisible { isRightPaneVisible = value; if (!isRightPaneVisible) - { ActivePane = PaneLeft; - } + Pane_ContentChanged(null, null); NotifyPropertyChanged(nameof(IsRightPaneVisible)); NotifyPropertyChanged(nameof(IsMultiPaneActive)); @@ -172,7 +170,6 @@ public bool IsRightPaneVisible } private bool isCurrentInstance; - public bool IsCurrentInstance { get => isCurrentInstance; @@ -183,14 +180,12 @@ public bool IsCurrentInstance isCurrentInstance = value; PaneLeft.IsCurrentInstance = false; + if (PaneRight is not null) - { PaneRight.IsCurrentInstance = false; - } + if (ActivePane is not null) - { ActivePane.IsCurrentInstance = value; - } CurrentInstanceChanged?.Invoke(null, this); } @@ -205,7 +200,7 @@ public PaneHolderPage() ActivePane = PaneLeft; IsRightPaneVisible = IsMultiPaneEnabled && UserSettingsService.PreferencesSettingsService.AlwaysOpenDualPaneInNewTab; - // TODO: fallback / error when failed to get NavigationViewCompactPaneLength value? + // TODO?: Fallback or an error can occur when failing to get NavigationViewCompactPaneLength value } private void Current_SizeChanged(object sender, WindowSizeChangedEventArgs e) @@ -219,25 +214,26 @@ protected override void OnNavigatedTo(NavigationEventArgs eventArgs) if (eventArgs.Parameter is string navPath) { - NavParamsLeft = new NavigationParams { NavPath = navPath }; - NavParamsRight = new NavigationParams { NavPath = "Home" }; + NavParamsLeft = new() { NavPath = navPath }; + NavParamsRight = new() { NavPath = "Home" }; } else if (eventArgs.Parameter is PaneNavigationArguments paneArgs) { - NavParamsLeft = new NavigationParams + NavParamsLeft = new() { NavPath = paneArgs.LeftPaneNavPathParam, SelectItem = paneArgs.LeftPaneSelectItemParam }; - NavParamsRight = new NavigationParams + NavParamsRight = new() { NavPath = paneArgs.RightPaneNavPathParam, SelectItem = paneArgs.RightPaneSelectItemParam }; + IsRightPaneVisible = IsMultiPaneEnabled && paneArgs.RightPaneNavPathParam is not null; } - TabItemArguments = new TabItemArguments() + TabItemArguments = new() { InitialPageType = typeof(PaneHolderPage), NavigationArg = new PaneNavigationArguments() @@ -253,14 +249,12 @@ protected override void OnNavigatedTo(NavigationEventArgs eventArgs) private void PaneResizer_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) { if (PaneRight is not null && PaneRight.ActualWidth <= 300) - { IsRightPaneVisible = false; - } } private void Pane_ContentChanged(object sender, TabItemArguments e) { - TabItemArguments = new TabItemArguments() + TabItemArguments = new() { InitialPageType = typeof(PaneHolderPage), NavigationArg = new PaneNavigationArguments() @@ -278,7 +272,7 @@ private void Pane_ContentChanged(object sender, TabItemArguments e) public void OpenPathInNewPane(string path) { IsRightPaneVisible = true; - NavParamsRight = new NavigationParams { NavPath = path }; + NavParamsRight = new() { NavPath = path }; ActivePane = PaneRight; } @@ -326,7 +320,7 @@ private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") public void CloseActivePane() { - // Can only close right pane atm + // NOTE: Can only close right pane at the moment IsRightPaneVisible = false; } @@ -368,4 +362,4 @@ public class PaneNavigationArguments public string RightPaneNavPathParam { get; set; } = null; public string RightPaneSelectItemParam { get; set; } = null; } -} \ No newline at end of file +}