From cab1dc640206cb8341f191cda1f7b5c5706f2f10 Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Tue, 12 Jan 2021 10:24:26 +0100 Subject: [PATCH 01/19] Refactor Win32 storage enumeration into clean functions --- Files/Files.csproj | 4 +- .../FilesystemOperations.cs | 2 +- Files/Filesystem/FolderHelpers.cs | 60 +++ Files/Filesystem/Win32StorageEnumerator.cs | 333 ++++++++++++++++ Files/Interacts/Interaction.cs | 2 +- Files/ViewModels/ItemViewModel.cs | 363 +----------------- Files/Views/ModernShellPage.xaml.cs | 2 +- 7 files changed, 419 insertions(+), 347 deletions(-) create mode 100644 Files/Filesystem/FolderHelpers.cs create mode 100644 Files/Filesystem/Win32StorageEnumerator.cs diff --git a/Files/Files.csproj b/Files/Files.csproj index 4ae79d362e56..07b725601bd9 100644 --- a/Files/Files.csproj +++ b/Files/Files.csproj @@ -168,6 +168,8 @@ + + @@ -947,4 +949,4 @@ --> - + \ No newline at end of file diff --git a/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs b/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs index 8a253b6004e0..d301714ff67e 100644 --- a/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs +++ b/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs @@ -199,7 +199,7 @@ await DialogDisplayHelper.ShowDialogAsync( } if (fsCopyResult) { - if (associatedInstance.FilesystemViewModel.CheckFolderForHiddenAttribute(source.Path)) + if (FolderHelpers.CheckFolderForHiddenAttribute(source.Path)) { // The source folder was hidden, apply hidden attribute to destination NativeFileOperationsHelper.SetFileAttribute(fsCopyResult.Result.Path, FileAttributes.Hidden); diff --git a/Files/Filesystem/FolderHelpers.cs b/Files/Filesystem/FolderHelpers.cs new file mode 100644 index 000000000000..e636359af01d --- /dev/null +++ b/Files/Filesystem/FolderHelpers.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Windows.Storage; +using static Files.Helpers.NativeFindStorageItemHelper; +using FileAttributes = System.IO.FileAttributes; + +namespace Files.Filesystem +{ + public static class FolderHelpers + { + public static bool CheckFolderAccessWithWin32(string path) + { + FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; + int additionalFlags = FIND_FIRST_EX_LARGE_FETCH; + IntPtr hFileTsk = FindFirstFileExFromApp(path + "\\*.*", findInfoLevel, out WIN32_FIND_DATA findDataTsk, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, + additionalFlags); + if (hFileTsk.ToInt64() != -1) + { + FindClose(hFileTsk); + return true; + } + return false; + } + + public static bool CheckFolderForHiddenAttribute(string path) + { + if (string.IsNullOrEmpty(path)) + { + return false; + } + FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; + int additionalFlags = FIND_FIRST_EX_LARGE_FETCH; + IntPtr hFileTsk = FindFirstFileExFromApp(path + "\\*.*", findInfoLevel, out WIN32_FIND_DATA findDataTsk, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, + additionalFlags); + if (hFileTsk.ToInt64() == -1) + { + return false; + } + var isHidden = ((FileAttributes)findDataTsk.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden; + FindClose(hFileTsk); + return isHidden; + } + + public static async Task CheckBitlockerStatusAsync(StorageFolder rootFolder, string path) + { + if (rootFolder == null || rootFolder.Properties == null) + { + return false; + } + if (Path.IsPathRooted(path) && Path.GetPathRoot(path) == path) + { + IDictionary extraProperties = await rootFolder.Properties.RetrievePropertiesAsync(new string[] { "System.Volume.BitLockerProtection" }); + return (int?)extraProperties["System.Volume.BitLockerProtection"] == 6; // Drive is bitlocker protected and locked + } + return false; + } + } +} diff --git a/Files/Filesystem/Win32StorageEnumerator.cs b/Files/Filesystem/Win32StorageEnumerator.cs new file mode 100644 index 000000000000..58537ac9a41f --- /dev/null +++ b/Files/Filesystem/Win32StorageEnumerator.cs @@ -0,0 +1,333 @@ +using ByteSizeLib; +using Files.Extensions; +using Microsoft.Toolkit.Uwp.Extensions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Windows.ApplicationModel.AppService; +using Windows.Foundation.Collections; +using Windows.Storage; +using static Files.Helpers.NativeFindStorageItemHelper; +using FileAttributes = System.IO.FileAttributes; + +namespace Files.Filesystem +{ + public static class Win32StorageEnumerator + { + public static async Task> ListEntriesWin32( + string path, + string returnformat, + IntPtr hFile, + WIN32_FIND_DATA findData, + bool shouldDisplayFileExtensions, + AppServiceConnection connection, + CancellationToken cancellationToken, + Func, Task> intermediateAction + ) + { + var tempList = new List(); + var hasNextFile = false; + var count = 0; + + do + { + if (((FileAttributes)findData.dwFileAttributes & FileAttributes.System) != FileAttributes.System || !App.AppSettings.AreSystemItemsHidden) + { + if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) != FileAttributes.Hidden || App.AppSettings.AreHiddenItemsVisible) + { + if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory) + { + var listedItem = await AddFileWin32(findData, path, returnformat, shouldDisplayFileExtensions, connection, cancellationToken); + if (listedItem != null) + { + tempList.Add(listedItem); + ++count; + } + } + else if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory) + { + if (findData.cFileName != "." && findData.cFileName != "..") + { + var listedItem = AddFolderWin32(findData, path, returnformat, cancellationToken); + if (listedItem != null) + { + tempList.Add(listedItem); + ++count; + } + } + } + } + } + if (cancellationToken.IsCancellationRequested) + { + break; + } + + hasNextFile = FindNextFile(hFile, out findData); + if (intermediateAction != null && (count == 32 || count % 300 == 0)) + { + await intermediateAction(tempList); + + } + } while (hasNextFile); + + + + FindClose(hFile); + return tempList; + } + + public static ListedItem AddFolderWin32( + WIN32_FIND_DATA findData, + string pathRoot, + string dateReturnFormat, + CancellationToken cancellationToken + ) + { + if (cancellationToken.IsCancellationRequested) + { + return null; + } + + DateTime itemDate; + try + { + FileTimeToSystemTime(ref findData.ftLastWriteTime, out SYSTEMTIME systemTimeOutput); + itemDate = new DateTime( + systemTimeOutput.Year, systemTimeOutput.Month, systemTimeOutput.Day, + systemTimeOutput.Hour, systemTimeOutput.Minute, systemTimeOutput.Second, systemTimeOutput.Milliseconds, + DateTimeKind.Utc); + } + catch (ArgumentException) + { + // Invalid date means invalid findData, do not add to list + return null; + } + var itemPath = Path.Combine(pathRoot, findData.cFileName); + + bool isHidden = (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden); + double opacity = 1; + + if (isHidden) + { + opacity = 0.4; + } + + var pinned = App.SidebarPinnedController.Model.Items.Contains(itemPath); + + return new ListedItem(null, dateReturnFormat) + { + PrimaryItemAttribute = StorageItemTypes.Folder, + ItemName = findData.cFileName, + ItemDateModifiedReal = itemDate, + ItemType = "FileFolderListItem".GetLocalized(), + LoadFolderGlyph = true, + FileImage = null, + IsHiddenItem = isHidden, + Opacity = opacity, + LoadFileIcon = false, + ItemPath = itemPath, + LoadUnknownTypeGlyph = false, + FileSize = null, + FileSizeBytes = 0, + ContainsFilesOrFolders = CheckForFilesFolders(itemPath), + IsPinned = pinned, + //FolderTooltipText = tooltipString, + }; + } + + public static async Task AddFileWin32( + WIN32_FIND_DATA findData, + string pathRoot, + string dateReturnFormat, + bool shouldDisplayFileExtensions, + AppServiceConnection connection, + CancellationToken cancellationToken + ) + { + var itemPath = Path.Combine(pathRoot, findData.cFileName); + + string itemName; + if (shouldDisplayFileExtensions && !findData.cFileName.EndsWith(".lnk") && !findData.cFileName.EndsWith(".url")) + { + itemName = findData.cFileName; // never show extension for shortcuts + } + else + { + if (findData.cFileName.StartsWith(".")) + { + itemName = findData.cFileName; // Always show full name for dotfiles. + } + else + { + itemName = Path.GetFileNameWithoutExtension(itemPath); + } + } + + DateTime itemModifiedDate, itemCreatedDate, itemLastAccessDate; + try + { + FileTimeToSystemTime(ref findData.ftLastWriteTime, out SYSTEMTIME systemModifiedDateOutput); + itemModifiedDate = new DateTime( + systemModifiedDateOutput.Year, systemModifiedDateOutput.Month, systemModifiedDateOutput.Day, + systemModifiedDateOutput.Hour, systemModifiedDateOutput.Minute, systemModifiedDateOutput.Second, systemModifiedDateOutput.Milliseconds, + DateTimeKind.Utc); + + FileTimeToSystemTime(ref findData.ftCreationTime, out SYSTEMTIME systemCreatedDateOutput); + itemCreatedDate = new DateTime( + systemCreatedDateOutput.Year, systemCreatedDateOutput.Month, systemCreatedDateOutput.Day, + systemCreatedDateOutput.Hour, systemCreatedDateOutput.Minute, systemCreatedDateOutput.Second, systemCreatedDateOutput.Milliseconds, + DateTimeKind.Utc); + + FileTimeToSystemTime(ref findData.ftLastAccessTime, out SYSTEMTIME systemLastAccessOutput); + itemLastAccessDate = new DateTime( + systemLastAccessOutput.Year, systemLastAccessOutput.Month, systemLastAccessOutput.Day, + systemLastAccessOutput.Hour, systemLastAccessOutput.Minute, systemLastAccessOutput.Second, systemLastAccessOutput.Milliseconds, + DateTimeKind.Utc); + } + catch (ArgumentException) + { + // Invalid date means invalid findData, do not add to list + return null; + } + + long itemSizeBytes = findData.GetSize(); + var itemSize = ByteSize.FromBytes(itemSizeBytes).ToBinaryString().ConvertSizeAbbreviation(); + string itemType = "ItemTypeFile".GetLocalized(); + string itemFileExtension = null; + + if (findData.cFileName.Contains('.')) + { + itemFileExtension = Path.GetExtension(itemPath); + itemType = itemFileExtension.Trim('.') + " " + itemType; + } + + bool itemFolderImgVis = false; + bool itemThumbnailImgVis; + bool itemEmptyImgVis; + + itemEmptyImgVis = true; + itemThumbnailImgVis = false; + + if (cancellationToken.IsCancellationRequested) + { + return null; + } + + if (findData.cFileName.EndsWith(".lnk") || findData.cFileName.EndsWith(".url")) + { + if (connection != null) + { + var response = await connection.SendMessageAsync(new ValueSet() + { + { "Arguments", "FileOperation" }, + { "fileop", "ParseLink" }, + { "filepath", itemPath } + }); + // If the request was canceled return now + if (cancellationToken.IsCancellationRequested) + { + return null; + } + if (response.Status == AppServiceResponseStatus.Success + && response.Message.ContainsKey("TargetPath")) + { + var isUrl = findData.cFileName.EndsWith(".url"); + string target = (string)response.Message["TargetPath"]; + bool containsFilesOrFolders = false; + + if ((bool)response.Message["IsFolder"]) + { + containsFilesOrFolders = CheckForFilesFolders(target); + } + + bool isHidden = (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden); + double opacity = 1; + + if (isHidden) + { + opacity = 0.4; + } + + return new ShortcutItem(null, dateReturnFormat) + { + PrimaryItemAttribute = (bool)response.Message["IsFolder"] ? StorageItemTypes.Folder : StorageItemTypes.File, + FileExtension = itemFileExtension, + IsHiddenItem = isHidden, + Opacity = opacity, + FileImage = null, + LoadFileIcon = !(bool)response.Message["IsFolder"] && itemThumbnailImgVis, + LoadUnknownTypeGlyph = !(bool)response.Message["IsFolder"] && !isUrl && itemEmptyImgVis, + LoadFolderGlyph = (bool)response.Message["IsFolder"], + ItemName = itemName, + ItemDateModifiedReal = itemModifiedDate, + ItemDateAccessedReal = itemLastAccessDate, + ItemDateCreatedReal = itemCreatedDate, + ItemType = isUrl ? "ShortcutWebLinkFileType".GetLocalized() : "ShortcutFileType".GetLocalized(), + ItemPath = itemPath, + FileSize = itemSize, + FileSizeBytes = itemSizeBytes, + TargetPath = target, + Arguments = (string)response.Message["Arguments"], + WorkingDirectory = (string)response.Message["WorkingDirectory"], + RunAsAdmin = (bool)response.Message["RunAsAdmin"], + IsUrl = isUrl, + ContainsFilesOrFolders = containsFilesOrFolders + }; + } + } + } + else + { + bool isHidden = (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden); + double opacity = 1; + + if (isHidden) + { + opacity = 0.4; + } + + return new ListedItem(null, dateReturnFormat) + { + PrimaryItemAttribute = StorageItemTypes.File, + FileExtension = itemFileExtension, + LoadUnknownTypeGlyph = itemEmptyImgVis, + FileImage = null, + LoadFileIcon = itemThumbnailImgVis, + LoadFolderGlyph = itemFolderImgVis, + ItemName = itemName, + IsHiddenItem = isHidden, + Opacity = opacity, + ItemDateModifiedReal = itemModifiedDate, + ItemDateAccessedReal = itemLastAccessDate, + ItemDateCreatedReal = itemCreatedDate, + ItemType = itemType, + ItemPath = itemPath, + FileSize = itemSize, + FileSizeBytes = itemSizeBytes + }; + } + return null; + } + + /// + /// This function is used to determine whether or not a folder has any contents. + /// + /// The path to the target folder + /// + private static bool CheckForFilesFolders(string targetPath) + { + FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; + int additionalFlags = FIND_FIRST_EX_LARGE_FETCH; + + IntPtr hFile = FindFirstFileExFromApp(targetPath + "\\*.*", findInfoLevel, out WIN32_FIND_DATA _, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags); + FindNextFile(hFile, out _); + var result = FindNextFile(hFile, out _); + FindClose(hFile); + return result; + } + } +} diff --git a/Files/Interacts/Interaction.cs b/Files/Interacts/Interaction.cs index 4c93ba1764be..e686692f2067 100644 --- a/Files/Interacts/Interaction.cs +++ b/Files/Interacts/Interaction.cs @@ -460,7 +460,7 @@ private async void OpenSelectedItems(bool displayApplicationPicker) }); if (!opened) { - opened = (FilesystemResult)AssociatedInstance.FilesystemViewModel.CheckFolderAccessWithWin32(folderPath); + opened = (FilesystemResult)FolderHelpers.CheckFolderAccessWithWin32(folderPath); } if (opened) { diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index c059493233f7..a58cf9a76313 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -751,7 +751,7 @@ public async void LoadExtendedItemProperties(ListedItem item, uint thumbnailSize public void RefreshItems(string previousDir) { - AddItemsToCollectionAsync(WorkingDirectory, previousDir); + RapidAddItemsToCollectionAsync(WorkingDirectory, previousDir); } public async void RapidAddItemsToCollectionAsync(string path, string previousDir) @@ -971,7 +971,7 @@ public async Task EnumerateItemsFromStandardFolderAsync(string path) _rootFolder = _currentStorageFolder.Folder; enumFromStorageFolder = true; } - else if (!CheckFolderAccessWithWin32(path)) // The folder is really inaccessible + else if (!FolderHelpers.CheckFolderAccessWithWin32(path)) // The folder is really inaccessible { if (res == FilesystemErrorCode.ERROR_UNAUTHORIZED) { @@ -999,7 +999,7 @@ await DialogDisplayHelper.ShowDialogAsync( string returnformat = Enum.Parse(localSettings.Values[Constants.LocalSettings.DateTimeFormat].ToString()) == TimeStyle.Application ? "D" : "g"; shouldDisplayFileExtensions = App.AppSettings.ShowFileExtensions; - if (await CheckBitlockerStatusAsync(_rootFolder)) + if (await FolderHelpers.CheckBitlockerStatusAsync(_rootFolder, WorkingDirectory)) { var bitlockerDialog = new Dialogs.BitlockerDialog(Path.GetPathRoot(WorkingDirectory)); var bitlockerResult = await bitlockerDialog.ShowAsync(); @@ -1015,7 +1015,7 @@ await DialogDisplayHelper.ShowDialogAsync( value.Add("password", userInput); await Connection.SendMessageAsync(value); - if (await CheckBitlockerStatusAsync(_rootFolder)) + if (await FolderHelpers.CheckBitlockerStatusAsync(_rootFolder, WorkingDirectory)) { // Drive is still locked await DialogDisplayHelper.ShowDialogAsync("BitlockerInvalidPwDialog/Title".GetLocalized(), "BitlockerInvalidPwDialog/Text".GetLocalized()); @@ -1097,7 +1097,6 @@ await DialogDisplayHelper.ShowDialogAsync( FileSizeBytes = 0 }; - var count = 0; if (hFile == IntPtr.Zero) { await DialogDisplayHelper.ShowDialogAsync("DriveUnpluggedDialog/Title".GetLocalized(), ""); @@ -1112,61 +1111,27 @@ await DialogDisplayHelper.ShowDialogAsync( { await Task.Run(async () => { - var tempList = new List(); - var hasNextFile = false; - do + + var fileList = await Win32StorageEnumerator.ListEntriesWin32(path, returnformat, hFile, findData, shouldDisplayFileExtensions, Connection, _addFilesCTS.Token, intermediateAction: async (intermediateList) => { - var itemPath = Path.Combine(path, findData.cFileName); - if (((FileAttributes)findData.dwFileAttributes & FileAttributes.System) != FileAttributes.System || !AppSettings.AreSystemItemsHidden) - { - if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) != FileAttributes.Hidden || AppSettings.AreHiddenItemsVisible) - { - if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory) - { - var listedItem = await AddFile(findData, path, returnformat); - if (listedItem != null) - { - tempList.Add(listedItem); - ++count; - } - } - else if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory) - { - if (findData.cFileName != "." && findData.cFileName != "..") - { - var listedItem = AddFolder(findData, path, returnformat); - if (listedItem != null) - { - tempList.Add(listedItem); - ++count; - } - } - } - } - } - if (_addFilesCTS.IsCancellationRequested) + var orderedList = OrderFiles2(intermediateList); + await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => { - break; - } + OrderFiles(orderedList); + }); + }); - hasNextFile = FindNextFile(hFile, out findData); - if (count == 32 || count % 300 == 0 || !hasNextFile) - { - var orderedList = OrderFiles2(tempList); - await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => - { - OrderFiles(orderedList); - }); - } - } while (hasNextFile); + var finalList = OrderFiles2(fileList); + await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => + { + OrderFiles(finalList); + }); await fileListCache.SaveFileListToCache(path, new CacheEntry { CurrentFolder = CurrentFolder, - FileList = tempList + FileList = fileList }); - - FindClose(hFile); }); return true; } @@ -1246,52 +1211,7 @@ ex is UnauthorizedAccessException Debug.WriteLine($"Enumerating items in {WorkingDirectory} (device) completed in {stopwatch.ElapsedMilliseconds} milliseconds.\n"); } - public bool CheckFolderAccessWithWin32(string path) - { - FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; - int additionalFlags = FIND_FIRST_EX_LARGE_FETCH; - IntPtr hFileTsk = FindFirstFileExFromApp(path + "\\*.*", findInfoLevel, out WIN32_FIND_DATA findDataTsk, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, - additionalFlags); - if (hFileTsk.ToInt64() != -1) - { - FindClose(hFileTsk); - return true; - } - return false; - } - - public bool CheckFolderForHiddenAttribute(string path) - { - if (string.IsNullOrEmpty(path)) - { - return false; - } - FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; - int additionalFlags = FIND_FIRST_EX_LARGE_FETCH; - IntPtr hFileTsk = FindFirstFileExFromApp(path + "\\*.*", findInfoLevel, out WIN32_FIND_DATA findDataTsk, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, - additionalFlags); - if (hFileTsk.ToInt64() == -1) - { - return false; - } - var isHidden = ((FileAttributes)findDataTsk.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden; - FindClose(hFileTsk); - return isHidden; - } - - private async Task CheckBitlockerStatusAsync(StorageFolder rootFolder) - { - if (rootFolder == null || rootFolder.Properties == null) - { - return false; - } - if (Path.IsPathRooted(WorkingDirectory) && Path.GetPathRoot(WorkingDirectory) == WorkingDirectory) - { - IDictionary extraProperties = await rootFolder.Properties.RetrievePropertiesAsync(new string[] { "System.Volume.BitLockerProtection" }); - return (int?)extraProperties["System.Volume.BitLockerProtection"] == 6; // Drive is bitlocker protected and locked - } - return false; - } + private async Task CheckCloudDriveSyncStatusAsync(IStorageItem item) { @@ -1559,11 +1479,11 @@ private async Task AddFileOrFolderAsync(string fileOrFolderPath, string dateRetu ListedItem listedItem = null; if ((findData.dwFileAttributes & 0x10) > 0) // FILE_ATTRIBUTE_DIRECTORY { - listedItem = AddFolder(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat); + listedItem = Win32StorageEnumerator.AddFolderWin32(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, _addFilesCTS.Token); } else { - listedItem = await AddFile(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat); + listedItem = await Win32StorageEnumerator.AddFileWin32(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, shouldDisplayFileExtensions, Connection, _addFilesCTS.Token); } if (listedItem != null) @@ -1646,232 +1566,6 @@ public async Task RemoveFileOrFolderAsync(string path) } } - private ListedItem AddFolder(WIN32_FIND_DATA findData, string pathRoot, string dateReturnFormat) - { - if (_addFilesCTS.IsCancellationRequested) - { - return null; - } - - DateTime itemDate; - try - { - FileTimeToSystemTime(ref findData.ftLastWriteTime, out SYSTEMTIME systemTimeOutput); - itemDate = new DateTime( - systemTimeOutput.Year, systemTimeOutput.Month, systemTimeOutput.Day, - systemTimeOutput.Hour, systemTimeOutput.Minute, systemTimeOutput.Second, systemTimeOutput.Milliseconds, - DateTimeKind.Utc); - } - catch (ArgumentException) - { - // Invalid date means invalid findData, do not add to list - return null; - } - var itemPath = Path.Combine(pathRoot, findData.cFileName); - - bool isHidden = (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden); - double opacity = 1; - - if (isHidden) - { - opacity = 0.4; - } - - var pinned = App.SidebarPinnedController.Model.Items.Contains(itemPath); - - return new ListedItem(null, dateReturnFormat) - { - PrimaryItemAttribute = StorageItemTypes.Folder, - ItemName = findData.cFileName, - ItemDateModifiedReal = itemDate, - ItemType = "FileFolderListItem".GetLocalized(), - LoadFolderGlyph = true, - FileImage = null, - IsHiddenItem = isHidden, - Opacity = opacity, - LoadFileIcon = false, - ItemPath = itemPath, - LoadUnknownTypeGlyph = false, - FileSize = null, - FileSizeBytes = 0, - ContainsFilesOrFolders = CheckForFilesFolders(itemPath), - IsPinned = pinned, - //FolderTooltipText = tooltipString, - }; - } - - private async Task AddFile(WIN32_FIND_DATA findData, string pathRoot, string dateReturnFormat) - { - var itemPath = Path.Combine(pathRoot, findData.cFileName); - - string itemName; - if (shouldDisplayFileExtensions && !findData.cFileName.EndsWith(".lnk") && !findData.cFileName.EndsWith(".url")) - { - itemName = findData.cFileName; // never show extension for shortcuts - } - else - { - if (findData.cFileName.StartsWith(".")) - { - itemName = findData.cFileName; // Always show full name for dotfiles. - } - else - { - itemName = Path.GetFileNameWithoutExtension(itemPath); - } - } - - DateTime itemModifiedDate, itemCreatedDate, itemLastAccessDate; - try - { - FileTimeToSystemTime(ref findData.ftLastWriteTime, out SYSTEMTIME systemModifiedDateOutput); - itemModifiedDate = new DateTime( - systemModifiedDateOutput.Year, systemModifiedDateOutput.Month, systemModifiedDateOutput.Day, - systemModifiedDateOutput.Hour, systemModifiedDateOutput.Minute, systemModifiedDateOutput.Second, systemModifiedDateOutput.Milliseconds, - DateTimeKind.Utc); - - FileTimeToSystemTime(ref findData.ftCreationTime, out SYSTEMTIME systemCreatedDateOutput); - itemCreatedDate = new DateTime( - systemCreatedDateOutput.Year, systemCreatedDateOutput.Month, systemCreatedDateOutput.Day, - systemCreatedDateOutput.Hour, systemCreatedDateOutput.Minute, systemCreatedDateOutput.Second, systemCreatedDateOutput.Milliseconds, - DateTimeKind.Utc); - - FileTimeToSystemTime(ref findData.ftLastAccessTime, out SYSTEMTIME systemLastAccessOutput); - itemLastAccessDate = new DateTime( - systemLastAccessOutput.Year, systemLastAccessOutput.Month, systemLastAccessOutput.Day, - systemLastAccessOutput.Hour, systemLastAccessOutput.Minute, systemLastAccessOutput.Second, systemLastAccessOutput.Milliseconds, - DateTimeKind.Utc); - } - catch (ArgumentException) - { - // Invalid date means invalid findData, do not add to list - return null; - } - - long itemSizeBytes = findData.GetSize(); - var itemSize = ByteSize.FromBytes(itemSizeBytes).ToBinaryString().ConvertSizeAbbreviation(); - string itemType = "ItemTypeFile".GetLocalized(); - string itemFileExtension = null; - - if (findData.cFileName.Contains('.')) - { - itemFileExtension = Path.GetExtension(itemPath); - itemType = itemFileExtension.Trim('.') + " " + itemType; - } - - bool itemFolderImgVis = false; - bool itemThumbnailImgVis; - bool itemEmptyImgVis; - - itemEmptyImgVis = true; - itemThumbnailImgVis = false; - - if (_addFilesCTS.IsCancellationRequested) - { - return null; - } - - if (findData.cFileName.EndsWith(".lnk") || findData.cFileName.EndsWith(".url")) - { - if (Connection != null) - { - var response = await Connection.SendMessageAsync(new ValueSet() - { - { "Arguments", "FileOperation" }, - { "fileop", "ParseLink" }, - { "filepath", itemPath } - }); - // If the request was canceled return now - if (_addFilesCTS.IsCancellationRequested) - { - return null; - } - if (response.Status == AppServiceResponseStatus.Success - && response.Message.ContainsKey("TargetPath")) - { - var isUrl = findData.cFileName.EndsWith(".url"); - string target = (string)response.Message["TargetPath"]; - bool containsFilesOrFolders = false; - - if ((bool)response.Message["IsFolder"]) - { - containsFilesOrFolders = CheckForFilesFolders(target); - } - - bool isHidden = (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden); - double opacity = 1; - - if (isHidden) - { - opacity = 0.4; - } - - return new ShortcutItem(null, dateReturnFormat) - { - PrimaryItemAttribute = (bool)response.Message["IsFolder"] ? StorageItemTypes.Folder : StorageItemTypes.File, - FileExtension = itemFileExtension, - IsHiddenItem = isHidden, - Opacity = opacity, - FileImage = null, - LoadFileIcon = !(bool)response.Message["IsFolder"] && itemThumbnailImgVis, - LoadUnknownTypeGlyph = !(bool)response.Message["IsFolder"] && !isUrl && itemEmptyImgVis, - LoadFolderGlyph = (bool)response.Message["IsFolder"], - ItemName = itemName, - ItemDateModifiedReal = itemModifiedDate, - ItemDateAccessedReal = itemLastAccessDate, - ItemDateCreatedReal = itemCreatedDate, - ItemType = isUrl ? "ShortcutWebLinkFileType".GetLocalized() : "ShortcutFileType".GetLocalized(), - ItemPath = itemPath, - FileSize = itemSize, - FileSizeBytes = itemSizeBytes, - TargetPath = target, - Arguments = (string)response.Message["Arguments"], - WorkingDirectory = (string)response.Message["WorkingDirectory"], - RunAsAdmin = (bool)response.Message["RunAsAdmin"], - IsUrl = isUrl, - ContainsFilesOrFolders = containsFilesOrFolders - }; - } - } - } - else - { - bool isHidden = (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden); - double opacity = 1; - - if (isHidden) - { - opacity = 0.4; - } - - return new ListedItem(null, dateReturnFormat) - { - PrimaryItemAttribute = StorageItemTypes.File, - FileExtension = itemFileExtension, - LoadUnknownTypeGlyph = itemEmptyImgVis, - FileImage = null, - LoadFileIcon = itemThumbnailImgVis, - LoadFolderGlyph = itemFolderImgVis, - ItemName = itemName, - IsHiddenItem = isHidden, - Opacity = opacity, - ItemDateModifiedReal = itemModifiedDate, - ItemDateAccessedReal = itemLastAccessDate, - ItemDateCreatedReal = itemCreatedDate, - ItemType = itemType, - ItemPath = itemPath, - FileSize = itemSize, - FileSizeBytes = itemSizeBytes - }; - } - return null; - } - - public void AddItemsToCollectionAsync(string path, string previousDir) - { - RapidAddItemsToCollectionAsync(path, previousDir); - } - private async Task AddFolderAsync(StorageFolder folder, string dateReturnFormat) { var basicProperties = await folder.GetBasicPropertiesAsync(); @@ -2029,23 +1723,6 @@ public void Dispose() _semaphoreCTS?.Dispose(); CloseWatcher(); } - - /// - /// This function is used to determine whether or not a folder has any contents. - /// - /// The path to the target folder - /// - public bool CheckForFilesFolders(string targetPath) - { - FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; - int additionalFlags = FIND_FIRST_EX_LARGE_FETCH; - - IntPtr hFile = FindFirstFileExFromApp(targetPath + "\\*.*", findInfoLevel, out WIN32_FIND_DATA _, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags); - FindNextFile(hFile, out _); - var result = FindNextFile(hFile, out _); - FindClose(hFile); - return result; - } } public class WorkingDirectoryModifiedEventArgs : EventArgs diff --git a/Files/Views/ModernShellPage.xaml.cs b/Files/Views/ModernShellPage.xaml.cs index a82f1e7b5453..e45599b280aa 100644 --- a/Files/Views/ModernShellPage.xaml.cs +++ b/Files/Views/ModernShellPage.xaml.cs @@ -661,7 +661,7 @@ public async void CheckPathInput(ItemViewModel instance, string currentInput, st var item = await FilesystemTasks.Wrap(() => DrivesManager.GetRootFromPathAsync(currentInput)); var resFolder = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFolderWithPathFromPathAsync(currentInput, item)); - if (resFolder || FilesystemViewModel.CheckFolderAccessWithWin32(currentInput)) + if (resFolder || FolderHelpers.CheckFolderAccessWithWin32(currentInput)) { var pathToNavigate = resFolder.Result?.Path ?? currentInput; ContentFrame.Navigate(InstanceViewModel.FolderSettings.GetLayoutType(pathToNavigate), From cc09ff9e43169f5c365812bffa3948eeff849374 Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Tue, 12 Jan 2021 10:49:56 +0100 Subject: [PATCH 02/19] Refactor universal storage enumeration into clean functions --- Files/Files.csproj | 3 +- .../UniversalStorageEnumerator.cs | 225 ++++++++++++++++++ .../Win32StorageEnumerator.cs | 12 +- Files/ViewModels/ItemViewModel.cs | 215 ++--------------- 4 files changed, 253 insertions(+), 202 deletions(-) create mode 100644 Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs rename Files/Filesystem/{ => StorageEnumerators}/Win32StorageEnumerator.cs (96%) diff --git a/Files/Files.csproj b/Files/Files.csproj index 07b725601bd9..7ba8bd6977a3 100644 --- a/Files/Files.csproj +++ b/Files/Files.csproj @@ -169,7 +169,8 @@ - + + diff --git a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs new file mode 100644 index 000000000000..9886a6cb93cd --- /dev/null +++ b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs @@ -0,0 +1,225 @@ +using ByteSizeLib; +using Files.Extensions; +using Files.Views.LayoutModes; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Windows.Storage; +using Windows.Storage.FileProperties; +using Windows.UI.Xaml.Media.Imaging; + +namespace Files.Filesystem.StorageEnumerators +{ + public static class UniversalStorageEnumerator + { + public static async Task> ListEntries( + StorageFolder rootFolder, + StorageFolderWithPath currentStorageFolder, + string returnformat, + bool shouldDisplayFileExtensions, + Type sourcePageType, + CancellationToken cancellationToken, + Func, Task> intermediateAction + ) + { + var tempList = new List(); + uint count = 0; + while (true) + { + IStorageItem item = null; + try + { + var results = await rootFolder.GetItemsAsync(count, 1); + item = results?.FirstOrDefault(); + if (item == null) + { + break; + } + } + catch (NotImplementedException) + { + break; + } + catch (Exception ex) when ( + ex is UnauthorizedAccessException + || ex is FileNotFoundException + || (uint)ex.HResult == 0x80070490) // ERROR_NOT_FOUND + { + ++count; + continue; + } + if (item.IsOfType(StorageItemTypes.Folder)) + { + var folder = await AddFolderAsync(item as StorageFolder, currentStorageFolder, returnformat, cancellationToken); + if (folder != null) + { + tempList.Add(folder); + } + ++count; + } + else + { + var file = item as StorageFile; + var fileEntry = await AddFileAsync(file, currentStorageFolder, returnformat, shouldDisplayFileExtensions, true, sourcePageType, cancellationToken); + if (fileEntry != null) + { + tempList.Add(fileEntry); + } + ++count; + } + if (cancellationToken.IsCancellationRequested) + { + break; + } + if (intermediateAction != null && (count == 32 || count % 300 == 0)) + { + await intermediateAction(tempList); + } + } + return tempList; + } + + private static async Task AddFolderAsync(StorageFolder folder, StorageFolderWithPath currentStorageFolder, string dateReturnFormat, CancellationToken cancellationToken) + { + var basicProperties = await folder.GetBasicPropertiesAsync(); + + if (!cancellationToken.IsCancellationRequested) + { + return new ListedItem(folder.FolderRelativeId, dateReturnFormat) + { + PrimaryItemAttribute = StorageItemTypes.Folder, + ItemName = folder.Name, + ItemDateModifiedReal = basicProperties.DateModified, + ItemType = folder.DisplayType, + IsHiddenItem = false, + Opacity = 1, + LoadFolderGlyph = true, + FileImage = null, + LoadFileIcon = false, + ItemPath = string.IsNullOrEmpty(folder.Path) ? Path.Combine(currentStorageFolder.Path, folder.Name) : folder.Path, + LoadUnknownTypeGlyph = false, + FileSize = null, + FileSizeBytes = 0 + //FolderTooltipText = tooltipString, + }; + } + return null; + } + + private static async Task AddFileAsync( + StorageFile file, + StorageFolderWithPath currentStorageFolder, + string dateReturnFormat, + bool shouldDisplayFileExtensions, + bool suppressThumbnailLoading, + Type sourcePageType, + CancellationToken cancellationToken + ) + { + var basicProperties = await file.GetBasicPropertiesAsync(); + // Display name does not include extension + var itemName = string.IsNullOrEmpty(file.DisplayName) || shouldDisplayFileExtensions ? + file.Name : file.DisplayName; + var itemDate = basicProperties.DateModified; + var itemPath = string.IsNullOrEmpty(file.Path) ? Path.Combine(currentStorageFolder.Path, file.Name) : file.Path; + var itemSize = ByteSize.FromBytes(basicProperties.Size).ToBinaryString().ConvertSizeAbbreviation(); + var itemSizeBytes = basicProperties.Size; + var itemType = file.DisplayType; + var itemFolderImgVis = false; + var itemFileExtension = file.FileType; + + BitmapImage icon = new BitmapImage(); + bool itemThumbnailImgVis; + bool itemEmptyImgVis; + + if (!(sourcePageType == typeof(GridViewBrowser))) + { + try + { + var itemThumbnailImg = suppressThumbnailLoading ? null : + await file.GetThumbnailAsync(ThumbnailMode.ListView, 40, ThumbnailOptions.UseCurrentScale); + if (itemThumbnailImg != null) + { + itemEmptyImgVis = false; + itemThumbnailImgVis = true; + icon.DecodePixelWidth = 40; + icon.DecodePixelHeight = 40; + await icon.SetSourceAsync(itemThumbnailImg); + } + else + { + itemEmptyImgVis = true; + itemThumbnailImgVis = false; + } + } + catch + { + itemEmptyImgVis = true; + itemThumbnailImgVis = false; + // Catch here to avoid crash + } + } + else + { + try + { + var itemThumbnailImg = suppressThumbnailLoading ? null : + await file.GetThumbnailAsync(ThumbnailMode.ListView, 80, ThumbnailOptions.UseCurrentScale); + if (itemThumbnailImg != null) + { + itemEmptyImgVis = false; + itemThumbnailImgVis = true; + icon.DecodePixelWidth = 80; + icon.DecodePixelHeight = 80; + await icon.SetSourceAsync(itemThumbnailImg); + } + else + { + itemEmptyImgVis = true; + itemThumbnailImgVis = false; + } + } + catch + { + itemEmptyImgVis = true; + itemThumbnailImgVis = false; + } + } + if (cancellationToken.IsCancellationRequested) + { + return null; + } + + if (file.Name.EndsWith(".lnk") || file.Name.EndsWith(".url")) + { + // This shouldn't happen, StorageFile api does not support shortcuts + Debug.WriteLine("Something strange: StorageFile api returned a shortcut"); + } + else + { + return new ListedItem(file.FolderRelativeId, dateReturnFormat) + { + PrimaryItemAttribute = StorageItemTypes.File, + FileExtension = itemFileExtension, + IsHiddenItem = false, + Opacity = 1, + LoadUnknownTypeGlyph = itemEmptyImgVis, + FileImage = icon, + LoadFileIcon = itemThumbnailImgVis, + LoadFolderGlyph = itemFolderImgVis, + ItemName = itemName, + ItemDateModifiedReal = itemDate, + ItemType = itemType, + ItemPath = itemPath, + FileSize = itemSize, + FileSizeBytes = (long)itemSizeBytes, + }; + } + return null; + } + } +} diff --git a/Files/Filesystem/Win32StorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs similarity index 96% rename from Files/Filesystem/Win32StorageEnumerator.cs rename to Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs index 58537ac9a41f..61b0ab728074 100644 --- a/Files/Filesystem/Win32StorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs @@ -13,11 +13,11 @@ using static Files.Helpers.NativeFindStorageItemHelper; using FileAttributes = System.IO.FileAttributes; -namespace Files.Filesystem +namespace Files.Filesystem.StorageEnumerators { public static class Win32StorageEnumerator { - public static async Task> ListEntriesWin32( + public static async Task> ListEntries( string path, string returnformat, IntPtr hFile, @@ -40,7 +40,7 @@ Func, Task> intermediateAction { if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory) { - var listedItem = await AddFileWin32(findData, path, returnformat, shouldDisplayFileExtensions, connection, cancellationToken); + var listedItem = await GetFile(findData, path, returnformat, shouldDisplayFileExtensions, connection, cancellationToken); if (listedItem != null) { tempList.Add(listedItem); @@ -51,7 +51,7 @@ Func, Task> intermediateAction { if (findData.cFileName != "." && findData.cFileName != "..") { - var listedItem = AddFolderWin32(findData, path, returnformat, cancellationToken); + var listedItem = GetFolder(findData, path, returnformat, cancellationToken); if (listedItem != null) { tempList.Add(listedItem); @@ -80,7 +80,7 @@ Func, Task> intermediateAction return tempList; } - public static ListedItem AddFolderWin32( + public static ListedItem GetFolder( WIN32_FIND_DATA findData, string pathRoot, string dateReturnFormat, @@ -139,7 +139,7 @@ CancellationToken cancellationToken }; } - public static async Task AddFileWin32( + public static async Task GetFile( WIN32_FIND_DATA findData, string pathRoot, string dateReturnFormat, diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index a58cf9a76313..d2fd4f343b60 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -1,12 +1,10 @@ -using ByteSizeLib; using Files.Common; using Files.Enums; -using Files.Extensions; using Files.Filesystem; using Files.Filesystem.Cloud; +using Files.Filesystem.StorageEnumerators; using Files.Helpers; using Files.Helpers.FileListCache; -using Files.Views.LayoutModes; using Microsoft.Toolkit.Uwp.Extensions; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.Toolkit.Uwp.UI; @@ -1111,8 +1109,8 @@ await DialogDisplayHelper.ShowDialogAsync( { await Task.Run(async () => { - - var fileList = await Win32StorageEnumerator.ListEntriesWin32(path, returnformat, hFile, findData, shouldDisplayFileExtensions, Connection, _addFilesCTS.Token, intermediateAction: async (intermediateList) => + + var fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, shouldDisplayFileExtensions, Connection, _addFilesCTS.Token, intermediateAction: async (intermediateList) => { var orderedList = OrderFiles2(intermediateList); await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => @@ -1147,71 +1145,29 @@ private async Task EnumFromStorageFolderAsync() string returnformat = Enum.Parse(localSettings.Values[Constants.LocalSettings.DateTimeFormat].ToString()) == TimeStyle.Application ? "D" : "g"; shouldDisplayFileExtensions = App.AppSettings.ShowFileExtensions; - var tempList = new List(); - uint count = 0; - while (true) - { - IStorageItem item = null; - try - { - var results = await _rootFolder.GetItemsAsync(count, 1); - item = results?.FirstOrDefault(); - if (item == null) - { - break; - } - } - catch (NotImplementedException) - { - break; - } - catch (Exception ex) when ( - ex is UnauthorizedAccessException - || ex is FileNotFoundException - || (uint)ex.HResult == 0x80070490) // ERROR_NOT_FOUND - { - ++count; - continue; - } - if (item.IsOfType(StorageItemTypes.Folder)) - { - var folder = await AddFolderAsync(item as StorageFolder, returnformat); - if (folder != null) - { - tempList.Add(folder); - } - ++count; - } - else - { - var file = item as StorageFile; - var fileEntry = await AddFileAsync(file, returnformat, true); - if (fileEntry != null) - { - tempList.Add(fileEntry); - } - ++count; - } - if (_addFilesCTS.IsCancellationRequested) - { - break; - } - if (count == 32 || count % 300 == 0) - { - OrderFiles(OrderFiles2(tempList)); - } - } - OrderFiles(OrderFiles2(tempList)); + var finalList = await UniversalStorageEnumerator.ListEntries( + _rootFolder, + _currentStorageFolder, + returnformat, + shouldDisplayFileExtensions, + AssociatedInstance.ContentFrame.SourcePageType, + _addFilesCTS.Token, + (intermediateList) => + { + OrderFiles(OrderFiles2(intermediateList)); + return Task.CompletedTask; + }); + OrderFiles(OrderFiles2(finalList)); stopwatch.Stop(); await fileListCache.SaveFileListToCache(WorkingDirectory, new CacheEntry { CurrentFolder = CurrentFolder, - FileList = tempList + FileList = finalList }); Debug.WriteLine($"Enumerating items in {WorkingDirectory} (device) completed in {stopwatch.ElapsedMilliseconds} milliseconds.\n"); } - + private async Task CheckCloudDriveSyncStatusAsync(IStorageItem item) { @@ -1479,11 +1435,11 @@ private async Task AddFileOrFolderAsync(string fileOrFolderPath, string dateRetu ListedItem listedItem = null; if ((findData.dwFileAttributes & 0x10) > 0) // FILE_ATTRIBUTE_DIRECTORY { - listedItem = Win32StorageEnumerator.AddFolderWin32(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, _addFilesCTS.Token); + listedItem = Win32StorageEnumerator.GetFolder(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, _addFilesCTS.Token); } else { - listedItem = await Win32StorageEnumerator.AddFileWin32(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, shouldDisplayFileExtensions, Connection, _addFilesCTS.Token); + listedItem = await Win32StorageEnumerator.GetFile(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, shouldDisplayFileExtensions, Connection, _addFilesCTS.Token); } if (listedItem != null) @@ -1566,137 +1522,6 @@ public async Task RemoveFileOrFolderAsync(string path) } } - private async Task AddFolderAsync(StorageFolder folder, string dateReturnFormat) - { - var basicProperties = await folder.GetBasicPropertiesAsync(); - - if (!_addFilesCTS.IsCancellationRequested) - { - return new ListedItem(folder.FolderRelativeId, dateReturnFormat) - { - PrimaryItemAttribute = StorageItemTypes.Folder, - ItemName = folder.Name, - ItemDateModifiedReal = basicProperties.DateModified, - ItemType = folder.DisplayType, - IsHiddenItem = false, - Opacity = 1, - LoadFolderGlyph = true, - FileImage = null, - LoadFileIcon = false, - ItemPath = string.IsNullOrEmpty(folder.Path) ? Path.Combine(_currentStorageFolder.Path, folder.Name) : folder.Path, - LoadUnknownTypeGlyph = false, - FileSize = null, - FileSizeBytes = 0 - //FolderTooltipText = tooltipString, - }; - } - return null; - } - - private async Task AddFileAsync(StorageFile file, string dateReturnFormat, bool suppressThumbnailLoading = false) - { - var basicProperties = await file.GetBasicPropertiesAsync(); - // Display name does not include extension - var itemName = string.IsNullOrEmpty(file.DisplayName) || shouldDisplayFileExtensions ? - file.Name : file.DisplayName; - var itemDate = basicProperties.DateModified; - var itemPath = string.IsNullOrEmpty(file.Path) ? Path.Combine(_currentStorageFolder.Path, file.Name) : file.Path; - var itemSize = ByteSize.FromBytes(basicProperties.Size).ToBinaryString().ConvertSizeAbbreviation(); - var itemSizeBytes = basicProperties.Size; - var itemType = file.DisplayType; - var itemFolderImgVis = false; - var itemFileExtension = file.FileType; - - BitmapImage icon = new BitmapImage(); - bool itemThumbnailImgVis; - bool itemEmptyImgVis; - - if (!(AssociatedInstance.ContentFrame.SourcePageType == typeof(GridViewBrowser))) - { - try - { - var itemThumbnailImg = suppressThumbnailLoading ? null : - await file.GetThumbnailAsync(ThumbnailMode.ListView, 40, ThumbnailOptions.UseCurrentScale); - if (itemThumbnailImg != null) - { - itemEmptyImgVis = false; - itemThumbnailImgVis = true; - icon.DecodePixelWidth = 40; - icon.DecodePixelHeight = 40; - await icon.SetSourceAsync(itemThumbnailImg); - } - else - { - itemEmptyImgVis = true; - itemThumbnailImgVis = false; - } - } - catch - { - itemEmptyImgVis = true; - itemThumbnailImgVis = false; - // Catch here to avoid crash - } - } - else - { - try - { - var itemThumbnailImg = suppressThumbnailLoading ? null : - await file.GetThumbnailAsync(ThumbnailMode.ListView, 80, ThumbnailOptions.UseCurrentScale); - if (itemThumbnailImg != null) - { - itemEmptyImgVis = false; - itemThumbnailImgVis = true; - icon.DecodePixelWidth = 80; - icon.DecodePixelHeight = 80; - await icon.SetSourceAsync(itemThumbnailImg); - } - else - { - itemEmptyImgVis = true; - itemThumbnailImgVis = false; - } - } - catch - { - itemEmptyImgVis = true; - itemThumbnailImgVis = false; - } - } - if (_addFilesCTS.IsCancellationRequested) - { - return null; - } - - if (file.Name.EndsWith(".lnk") || file.Name.EndsWith(".url")) - { - // This shouldn't happen, StorageFile api does not support shortcuts - Debug.WriteLine("Something strange: StorageFile api returned a shortcut"); - } - else - { - return new ListedItem(file.FolderRelativeId, dateReturnFormat) - { - PrimaryItemAttribute = StorageItemTypes.File, - FileExtension = itemFileExtension, - IsHiddenItem = false, - Opacity = 1, - LoadUnknownTypeGlyph = itemEmptyImgVis, - FileImage = icon, - LoadFileIcon = itemThumbnailImgVis, - LoadFolderGlyph = itemFolderImgVis, - ItemName = itemName, - ItemDateModifiedReal = itemDate, - ItemType = itemType, - ItemPath = itemPath, - FileSize = itemSize, - FileSizeBytes = (long)itemSizeBytes, - }; - } - return null; - } - public void AddSearchResultsToCollection(ObservableCollection searchItems, string currentSearchPath) { _filesAndFolders.Clear(); From 7d8402563a3f4e1051241540c143c04b728f2362 Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Tue, 12 Jan 2021 11:27:24 +0100 Subject: [PATCH 03/19] Refactor universal items enumerator to batch reads --- .../UniversalStorageEnumerator.cs | 81 ++++++++++++++----- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs index 9886a6cb93cd..f7a45722a615 100644 --- a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs @@ -28,14 +28,20 @@ Func, Task> intermediateAction { var tempList = new List(); uint count = 0; + var firstRound = true; while (true) { - IStorageItem item = null; + IReadOnlyList items; + uint maxItemsToRetrieve = 300; + if (firstRound) + { + maxItemsToRetrieve = 32; + firstRound = false; + } try { - var results = await rootFolder.GetItemsAsync(count, 1); - item = results?.FirstOrDefault(); - if (item == null) + items = await rootFolder.GetItemsAsync(count, maxItemsToRetrieve); + if (items == null || items.Count == 0) { break; } @@ -49,36 +55,69 @@ ex is UnauthorizedAccessException || ex is FileNotFoundException || (uint)ex.HResult == 0x80070490) // ERROR_NOT_FOUND { - ++count; - continue; + // If some unexpected exception is thrown - enumerate this folder file by file - just to be sure + items = await EnumerateFileByFile(rootFolder, count, maxItemsToRetrieve); } - if (item.IsOfType(StorageItemTypes.Folder)) + foreach (var item in items) { - var folder = await AddFolderAsync(item as StorageFolder, currentStorageFolder, returnformat, cancellationToken); - if (folder != null) + if (item.IsOfType(StorageItemTypes.Folder)) + { + var folder = await AddFolderAsync(item as StorageFolder, currentStorageFolder, returnformat, cancellationToken); + if (folder != null) + { + tempList.Add(folder); + } + } + else { - tempList.Add(folder); + var file = item as StorageFile; + var fileEntry = await AddFileAsync(file, currentStorageFolder, returnformat, shouldDisplayFileExtensions, true, sourcePageType, cancellationToken); + if (fileEntry != null) + { + tempList.Add(fileEntry); + } + } + if (cancellationToken.IsCancellationRequested) + { + break; } - ++count; } - else + count += maxItemsToRetrieve; + if (intermediateAction != null && count % 300 == 32 && items.Count == maxItemsToRetrieve) { - var file = item as StorageFile; - var fileEntry = await AddFileAsync(file, currentStorageFolder, returnformat, shouldDisplayFileExtensions, true, sourcePageType, cancellationToken); - if (fileEntry != null) + await intermediateAction(tempList); + } + } + return tempList; + } + + private static async Task> EnumerateFileByFile(StorageFolder rootFolder, uint startFrom, uint itemsToIterate) + { + var tempList = new List(); + for (var i = startFrom; i < startFrom + itemsToIterate; i++) + { + IStorageItem item; + try + { + var results = await rootFolder.GetItemsAsync(i, 1); + item = results?.FirstOrDefault(); + if (item == null) { - tempList.Add(fileEntry); + break; } - ++count; } - if (cancellationToken.IsCancellationRequested) + catch (NotImplementedException) { break; } - if (intermediateAction != null && (count == 32 || count % 300 == 0)) + catch (Exception ex) when ( + ex is UnauthorizedAccessException + || ex is FileNotFoundException + || (uint)ex.HResult == 0x80070490) // ERROR_NOT_FOUND { - await intermediateAction(tempList); + continue; } + tempList.Add(item); } return tempList; } @@ -136,7 +175,7 @@ CancellationToken cancellationToken bool itemThumbnailImgVis; bool itemEmptyImgVis; - if (!(sourcePageType == typeof(GridViewBrowser))) + if (sourcePageType != typeof(GridViewBrowser)) { try { From c78b455338e25e37132db99615af479db6afe36b Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Tue, 12 Jan 2021 16:47:02 +0100 Subject: [PATCH 04/19] Add preemptive caching --- Files/Extensions/EnumerableExtensions.cs | 29 +++- Files/Extensions/TaskExtensions.cs | 21 +++ Files/Files.csproj | 1 + .../UniversalStorageEnumerator.cs | 14 +- .../Win32StorageEnumerator.cs | 6 +- Files/ViewModels/ItemViewModel.cs | 161 ++++++++++++------ 6 files changed, 167 insertions(+), 65 deletions(-) create mode 100644 Files/Extensions/TaskExtensions.cs diff --git a/Files/Extensions/EnumerableExtensions.cs b/Files/Extensions/EnumerableExtensions.cs index bdccefbde391..4ca5073168aa 100644 --- a/Files/Extensions/EnumerableExtensions.cs +++ b/Files/Extensions/EnumerableExtensions.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; namespace Files.Extensions { @@ -12,5 +15,29 @@ internal static class EnumerableExtensions /// with internal static IEnumerable CreateEnumerable(this T item) => new List() { item }; + + /// + /// Executes given lambda parallely on given data set with max degree of parallelism set up + /// + /// The item type + /// Data to process + /// Lambda to execute on all items + /// Max degree of parallelism (-1 for unbounded execution) + /// + internal static Task AsyncParallelForEach(this IEnumerable source, Func body, int maxDegreeOfParallelism) + { + var options = new ExecutionDataflowBlockOptions + { + MaxDegreeOfParallelism = maxDegreeOfParallelism + }; + + var block = new ActionBlock(body, options); + + foreach (var item in source) + block.Post(item); + + block.Complete(); + return block.Completion; + } } } \ No newline at end of file diff --git a/Files/Extensions/TaskExtensions.cs b/Files/Extensions/TaskExtensions.cs new file mode 100644 index 000000000000..e3160953dca6 --- /dev/null +++ b/Files/Extensions/TaskExtensions.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; + +namespace Files.Extensions +{ + internal static class TaskExtensions + { +#pragma warning disable RCS1175 // Unused this parameter. +#pragma warning disable IDE0060 // Remove unused parameter + /// + /// This function is to explicitly state that we know that we're runnign task without awaiting. + /// This makes visual studio to drop warning, but the programmer intent is still clearly stated. + /// + /// + internal static void Forget(this Task task) + { + // do nothing, just forget about the task + } +#pragma warning restore IDE0060 // Remove unused parameter +#pragma warning restore RCS1175 // Unused this parameter. + } +} diff --git a/Files/Files.csproj b/Files/Files.csproj index 7ba8bd6977a3..e1e9feff840d 100644 --- a/Files/Files.csproj +++ b/Files/Files.csproj @@ -168,6 +168,7 @@ + diff --git a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs index f7a45722a615..3da00b658749 100644 --- a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs @@ -20,7 +20,6 @@ public static async Task> ListEntries( StorageFolder rootFolder, StorageFolderWithPath currentStorageFolder, string returnformat, - bool shouldDisplayFileExtensions, Type sourcePageType, CancellationToken cancellationToken, Func, Task> intermediateAction @@ -33,7 +32,13 @@ Func, Task> intermediateAction { IReadOnlyList items; uint maxItemsToRetrieve = 300; - if (firstRound) + + if (intermediateAction == null) + { + // without intermediate action increase batches significantly + maxItemsToRetrieve = 1000; + } + else if (firstRound) { maxItemsToRetrieve = 32; firstRound = false; @@ -71,7 +76,7 @@ ex is UnauthorizedAccessException else { var file = item as StorageFile; - var fileEntry = await AddFileAsync(file, currentStorageFolder, returnformat, shouldDisplayFileExtensions, true, sourcePageType, cancellationToken); + var fileEntry = await AddFileAsync(file, currentStorageFolder, returnformat, true, sourcePageType, cancellationToken); if (fileEntry != null) { tempList.Add(fileEntry); @@ -153,7 +158,6 @@ private static async Task AddFileAsync( StorageFile file, StorageFolderWithPath currentStorageFolder, string dateReturnFormat, - bool shouldDisplayFileExtensions, bool suppressThumbnailLoading, Type sourcePageType, CancellationToken cancellationToken @@ -161,7 +165,7 @@ CancellationToken cancellationToken { var basicProperties = await file.GetBasicPropertiesAsync(); // Display name does not include extension - var itemName = string.IsNullOrEmpty(file.DisplayName) || shouldDisplayFileExtensions ? + var itemName = string.IsNullOrEmpty(file.DisplayName) || App.AppSettings.ShowFileExtensions ? file.Name : file.DisplayName; var itemDate = basicProperties.DateModified; var itemPath = string.IsNullOrEmpty(file.Path) ? Path.Combine(currentStorageFolder.Path, file.Name) : file.Path; diff --git a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs index 61b0ab728074..c55be6159e90 100644 --- a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs @@ -22,7 +22,6 @@ public static async Task> ListEntries( string returnformat, IntPtr hFile, WIN32_FIND_DATA findData, - bool shouldDisplayFileExtensions, AppServiceConnection connection, CancellationToken cancellationToken, Func, Task> intermediateAction @@ -40,7 +39,7 @@ Func, Task> intermediateAction { if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory) { - var listedItem = await GetFile(findData, path, returnformat, shouldDisplayFileExtensions, connection, cancellationToken); + var listedItem = await GetFile(findData, path, returnformat, connection, cancellationToken); if (listedItem != null) { tempList.Add(listedItem); @@ -143,7 +142,6 @@ public static async Task GetFile( WIN32_FIND_DATA findData, string pathRoot, string dateReturnFormat, - bool shouldDisplayFileExtensions, AppServiceConnection connection, CancellationToken cancellationToken ) @@ -151,7 +149,7 @@ CancellationToken cancellationToken var itemPath = Path.Combine(pathRoot, findData.cFileName); string itemName; - if (shouldDisplayFileExtensions && !findData.cFileName.EndsWith(".lnk") && !findData.cFileName.EndsWith(".url")) + if (App.AppSettings.ShowFileExtensions && !findData.cFileName.EndsWith(".lnk") && !findData.cFileName.EndsWith(".url")) { itemName = findData.cFileName; // never show extension for shortcuts } diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index d2fd4f343b60..64a0af684a27 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -1,5 +1,6 @@ using Files.Common; using Files.Enums; +using Files.Extensions; using Files.Filesystem; using Files.Filesystem.Cloud; using Files.Filesystem.StorageEnumerators; @@ -46,11 +47,9 @@ public class ItemViewModel : INotifyPropertyChanged, IDisposable public ReadOnlyObservableCollection FilesAndFolders { get; } public SettingsViewModel AppSettings => App.AppSettings; public FolderSettingsViewModel FolderSettings => AssociatedInstance?.InstanceViewModel.FolderSettings; - private bool shouldDisplayFileExtensions = false; public ListedItem CurrentFolder { get; private set; } public CollectionViewSource viewSource; private CancellationTokenSource _addFilesCTS, _semaphoreCTS; - private StorageFolder _rootFolder; public event PropertyChangedEventHandler PropertyChanged; @@ -337,7 +336,6 @@ public ItemViewModel(IShellPage appInstance) FilesAndFolders = new ReadOnlyObservableCollection(_filesAndFolders); _addFilesCTS = new CancellationTokenSource(); _semaphoreCTS = new CancellationTokenSource(); - shouldDisplayFileExtensions = App.AppSettings.ShowFileExtensions; jumpTimer.Interval = TimeSpan.FromSeconds(0.8); jumpTimer.Tick += JumpTimer_Tick; } @@ -804,10 +802,35 @@ public async void RapidAddItemsToCollectionAsync(string path, string previousDir } else { - if (await EnumerateItemsFromStandardFolderAsync(path)) + if (await EnumerateItemsFromStandardFolderAsync(path, _currentStorageFolder, _addFilesCTS.Token, cacheOnly: false)) { WatchForDirectoryChanges(path); } + + if (App.AppSettings.UseFileListCache && !_addFilesCTS.IsCancellationRequested) + { + // run background tasks to iterate through folders and cache all of them preemptively + Task.Run(async () => + { + var folders = _filesAndFolders.Where(e => e.PrimaryItemAttribute == StorageItemTypes.Folder); + await folders.AsyncParallelForEach(async (folder) => + { + if (_addFilesCTS.IsCancellationRequested) return; + + var path = folder.ItemPath; + StorageFolderWithPath storageFolder = null; + if (Path.IsPathRooted(path)) + { + var res = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFolderWithPathFromPathAsync(path, null, parentFolder: _currentStorageFolder)); + if (res) + { + storageFolder = res.Result; + } + } + await EnumerateItemsFromStandardFolderAsync(path, storageFolder, _addFilesCTS.Token, cacheOnly: true); + }, maxDegreeOfParallelism: 5); + }).Forget(); + } } IsFolderEmptyTextDisplayed = FilesAndFolders.Count == 0; @@ -895,7 +918,6 @@ public async Task EnumerateItemsFromSpecialFolderAsync(string path) { ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; string returnformat = Enum.Parse(localSettings.Values[Constants.LocalSettings.DateTimeFormat].ToString()) == TimeStyle.Application ? "D" : "g"; - shouldDisplayFileExtensions = App.AppSettings.ShowFileExtensions; CurrentFolder = new ListedItem(null, returnformat) { @@ -954,23 +976,26 @@ await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => }); } - public async Task EnumerateItemsFromStandardFolderAsync(string path) + public async Task EnumerateItemsFromStandardFolderAsync(string path, StorageFolderWithPath currentStorageFolder, CancellationToken cancellationToken, bool cacheOnly = false) { // Flag to use FindFirstFileExFromApp or StorageFolder enumeration bool enumFromStorageFolder = false; + StorageFolder rootFolder = null; var res = await FilesystemTasks.Wrap(() => StorageFolder.GetFolderFromPathAsync(path).AsTask()); if (res) { - _rootFolder = res.Result; + rootFolder = res.Result; } else if (_workingRoot != null) { - _rootFolder = _currentStorageFolder.Folder; + rootFolder = currentStorageFolder.Folder; enumFromStorageFolder = true; } else if (!FolderHelpers.CheckFolderAccessWithWin32(path)) // The folder is really inaccessible { + if (cacheOnly) return false; + if (res == FilesystemErrorCode.ERROR_UNAUTHORIZED) { //TODO: proper dialog @@ -995,9 +1020,8 @@ await DialogDisplayHelper.ShowDialogAsync( ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; string returnformat = Enum.Parse(localSettings.Values[Constants.LocalSettings.DateTimeFormat].ToString()) == TimeStyle.Application ? "D" : "g"; - shouldDisplayFileExtensions = App.AppSettings.ShowFileExtensions; - if (await FolderHelpers.CheckBitlockerStatusAsync(_rootFolder, WorkingDirectory)) + if (!cacheOnly && await FolderHelpers.CheckBitlockerStatusAsync(rootFolder, WorkingDirectory)) { var bitlockerDialog = new Dialogs.BitlockerDialog(Path.GetPathRoot(WorkingDirectory)); var bitlockerResult = await bitlockerDialog.ShowAsync(); @@ -1013,7 +1037,7 @@ await DialogDisplayHelper.ShowDialogAsync( value.Add("password", userInput); await Connection.SendMessageAsync(value); - if (await FolderHelpers.CheckBitlockerStatusAsync(_rootFolder, WorkingDirectory)) + if (await FolderHelpers.CheckBitlockerStatusAsync(rootFolder, WorkingDirectory)) { // Drive is still locked await DialogDisplayHelper.ShowDialogAsync("BitlockerInvalidPwDialog/Title".GetLocalized(), "BitlockerInvalidPwDialog/Text".GetLocalized()); @@ -1022,29 +1046,34 @@ await DialogDisplayHelper.ShowDialogAsync( } } - // Is folder synced to cloud storage? - var syncStatus = await CheckCloudDriveSyncStatusAsync(_rootFolder); - AssociatedInstance.InstanceViewModel.IsPageTypeCloudDrive = - syncStatus != CloudDriveSyncStatus.NotSynced && syncStatus != CloudDriveSyncStatus.Unknown; + if (!cacheOnly) + { + // Is folder synced to cloud storage? + var syncStatus = await CheckCloudDriveSyncStatusAsync(rootFolder); + AssociatedInstance.InstanceViewModel.IsPageTypeCloudDrive = + syncStatus != CloudDriveSyncStatus.NotSynced && syncStatus != CloudDriveSyncStatus.Unknown; + } if (enumFromStorageFolder) { - CurrentFolder = new ListedItem(_rootFolder.FolderRelativeId, returnformat) + var currentFolder = new ListedItem(rootFolder.FolderRelativeId, returnformat) { PrimaryItemAttribute = StorageItemTypes.Folder, ItemPropertiesInitialized = true, - ItemName = _rootFolder.Name, - ItemDateModifiedReal = (await _rootFolder.GetBasicPropertiesAsync()).DateModified, - ItemType = _rootFolder.DisplayType, + ItemName = rootFolder.Name, + ItemDateModifiedReal = (await rootFolder.GetBasicPropertiesAsync()).DateModified, + ItemType = rootFolder.DisplayType, LoadFolderGlyph = true, FileImage = null, LoadFileIcon = false, - ItemPath = string.IsNullOrEmpty(_rootFolder.Path) ? _currentStorageFolder.Path : _rootFolder.Path, + ItemPath = string.IsNullOrEmpty(rootFolder.Path) ? currentStorageFolder.Path : rootFolder.Path, LoadUnknownTypeGlyph = false, FileSize = null, FileSizeBytes = 0 }; - await EnumFromStorageFolderAsync(); + if (!cacheOnly) + CurrentFolder = currentFolder; + await EnumFromStorageFolderAsync(currentFolder, rootFolder, currentStorageFolder, cancellationToken, cacheOnly); return true; } else @@ -1077,7 +1106,7 @@ await DialogDisplayHelper.ShowDialogAsync( opacity = 0.4; } - CurrentFolder = new ListedItem(null, returnformat) + var currentFolder = new ListedItem(null, returnformat) { PrimaryItemAttribute = StorageItemTypes.Folder, ItemPropertiesInitialized = true, @@ -1094,40 +1123,50 @@ await DialogDisplayHelper.ShowDialogAsync( FileSize = null, FileSizeBytes = 0 }; + if (!cacheOnly) + CurrentFolder = currentFolder; if (hFile == IntPtr.Zero) { - await DialogDisplayHelper.ShowDialogAsync("DriveUnpluggedDialog/Title".GetLocalized(), ""); + if (!cacheOnly) + await DialogDisplayHelper.ShowDialogAsync("DriveUnpluggedDialog/Title".GetLocalized(), ""); return false; } else if (hFile.ToInt64() == -1) { - await EnumFromStorageFolderAsync(); + await EnumFromStorageFolderAsync(currentFolder, rootFolder, currentStorageFolder, cancellationToken, cacheOnly); return false; } else { await Task.Run(async () => { - - var fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, shouldDisplayFileExtensions, Connection, _addFilesCTS.Token, intermediateAction: async (intermediateList) => + List fileList; + if (cacheOnly) { - var orderedList = OrderFiles2(intermediateList); - await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => + fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, Connection, cancellationToken, null); + } + else + { + fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, Connection, cancellationToken, intermediateAction: async (intermediateList) => { - OrderFiles(orderedList); + var orderedList = OrderFiles2(intermediateList); + await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => + { + OrderFiles(orderedList); + }); }); - }); - var finalList = OrderFiles2(fileList); - await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => - { - OrderFiles(finalList); - }); + var finalList = OrderFiles2(fileList); + await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => + { + OrderFiles(finalList); + }); + } await fileListCache.SaveFileListToCache(path, new CacheEntry { - CurrentFolder = CurrentFolder, + CurrentFolder = currentFolder, FileList = fileList }); }); @@ -1136,32 +1175,44 @@ await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => } } - private async Task EnumFromStorageFolderAsync() + private async Task EnumFromStorageFolderAsync(ListedItem currentFolder, StorageFolder rootFolder, StorageFolderWithPath currentStorageFolder, CancellationToken cancellationToken, bool cacheOnly) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; string returnformat = Enum.Parse(localSettings.Values[Constants.LocalSettings.DateTimeFormat].ToString()) == TimeStyle.Application ? "D" : "g"; - shouldDisplayFileExtensions = App.AppSettings.ShowFileExtensions; - - var finalList = await UniversalStorageEnumerator.ListEntries( - _rootFolder, - _currentStorageFolder, - returnformat, - shouldDisplayFileExtensions, - AssociatedInstance.ContentFrame.SourcePageType, - _addFilesCTS.Token, - (intermediateList) => - { - OrderFiles(OrderFiles2(intermediateList)); - return Task.CompletedTask; - }); - OrderFiles(OrderFiles2(finalList)); + + List finalList; + if (cacheOnly) + { + finalList = await UniversalStorageEnumerator.ListEntries( + rootFolder, + currentStorageFolder, + returnformat, + AssociatedInstance.ContentFrame.SourcePageType, + cancellationToken, + null); + } + else + { + finalList = await UniversalStorageEnumerator.ListEntries( + rootFolder, + currentStorageFolder, + returnformat, + AssociatedInstance.ContentFrame.SourcePageType, + cancellationToken, + (intermediateList) => + { + OrderFiles(OrderFiles2(intermediateList)); + return Task.CompletedTask; + }); + OrderFiles(OrderFiles2(finalList)); + } stopwatch.Stop(); await fileListCache.SaveFileListToCache(WorkingDirectory, new CacheEntry { - CurrentFolder = CurrentFolder, + CurrentFolder = currentFolder, FileList = finalList }); Debug.WriteLine($"Enumerating items in {WorkingDirectory} (device) completed in {stopwatch.ElapsedMilliseconds} milliseconds.\n"); @@ -1364,7 +1415,7 @@ public ListedItem AddFileOrFolderFromShellFile(ShellFileItem item, string dateRe { // File string itemName; - if (shouldDisplayFileExtensions && !item.FileName.EndsWith(".lnk") && !item.FileName.EndsWith(".url")) + if (App.AppSettings.ShowFileExtensions && !item.FileName.EndsWith(".lnk") && !item.FileName.EndsWith(".url")) { itemName = item.FileName; // never show extension for shortcuts } @@ -1439,7 +1490,7 @@ private async Task AddFileOrFolderAsync(string fileOrFolderPath, string dateRetu } else { - listedItem = await Win32StorageEnumerator.GetFile(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, shouldDisplayFileExtensions, Connection, _addFilesCTS.Token); + listedItem = await Win32StorageEnumerator.GetFile(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, Connection, _addFilesCTS.Token); } if (listedItem != null) From b8656ab0c7f18467c4eb7d984b20facc13d13596 Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Tue, 12 Jan 2021 19:04:00 +0100 Subject: [PATCH 05/19] Fix crash on quicks forward navigation --- Files/ViewModels/ItemViewModel.cs | 50 ++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index 64a0af684a27..c9af04191cd7 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -802,7 +802,8 @@ public async void RapidAddItemsToCollectionAsync(string path, string previousDir } else { - if (await EnumerateItemsFromStandardFolderAsync(path, _currentStorageFolder, _addFilesCTS.Token, cacheOnly: false)) + var sourcePageType = AssociatedInstance.ContentFrame.SourcePageType; + if (await EnumerateItemsFromStandardFolderAsync(path, _currentStorageFolder, sourcePageType, _addFilesCTS.Token, cacheOnly: false)) { WatchForDirectoryChanges(path); } @@ -810,25 +811,34 @@ public async void RapidAddItemsToCollectionAsync(string path, string previousDir if (App.AppSettings.UseFileListCache && !_addFilesCTS.IsCancellationRequested) { // run background tasks to iterate through folders and cache all of them preemptively + var folders = _filesAndFolders.Where(e => e.PrimaryItemAttribute == StorageItemTypes.Folder); + var currentStorageFolderSnapshot = _currentStorageFolder; Task.Run(async () => { - var folders = _filesAndFolders.Where(e => e.PrimaryItemAttribute == StorageItemTypes.Folder); - await folders.AsyncParallelForEach(async (folder) => + try { - if (_addFilesCTS.IsCancellationRequested) return; - - var path = folder.ItemPath; - StorageFolderWithPath storageFolder = null; - if (Path.IsPathRooted(path)) + await folders.AsyncParallelForEach(async (folder) => { - var res = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFolderWithPathFromPathAsync(path, null, parentFolder: _currentStorageFolder)); - if (res) + if (_addFilesCTS.IsCancellationRequested) return; + + var path = folder.ItemPath; + StorageFolderWithPath storageFolder = null; + if (Path.IsPathRooted(path)) { - storageFolder = res.Result; + var res = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFolderWithPathFromPathAsync(path, null, parentFolder: currentStorageFolderSnapshot)); + if (res) + { + storageFolder = res.Result; + } } - } - await EnumerateItemsFromStandardFolderAsync(path, storageFolder, _addFilesCTS.Token, cacheOnly: true); - }, maxDegreeOfParallelism: 5); + await EnumerateItemsFromStandardFolderAsync(path, storageFolder, sourcePageType, _addFilesCTS.Token, cacheOnly: true); + }, maxDegreeOfParallelism: 5); + } + catch (Exception e) + { + // ignore exception. This is fine, it's only a caching that can fail + Debug.WriteLine(e.ToString()); + } }).Forget(); } } @@ -976,7 +986,7 @@ await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => }); } - public async Task EnumerateItemsFromStandardFolderAsync(string path, StorageFolderWithPath currentStorageFolder, CancellationToken cancellationToken, bool cacheOnly = false) + public async Task EnumerateItemsFromStandardFolderAsync(string path, StorageFolderWithPath currentStorageFolder, Type sourcePageType, CancellationToken cancellationToken, bool cacheOnly = false) { // Flag to use FindFirstFileExFromApp or StorageFolder enumeration bool enumFromStorageFolder = false; @@ -1073,7 +1083,7 @@ await DialogDisplayHelper.ShowDialogAsync( }; if (!cacheOnly) CurrentFolder = currentFolder; - await EnumFromStorageFolderAsync(currentFolder, rootFolder, currentStorageFolder, cancellationToken, cacheOnly); + await EnumFromStorageFolderAsync(currentFolder, rootFolder, currentStorageFolder, sourcePageType, cancellationToken, cacheOnly); return true; } else @@ -1134,7 +1144,7 @@ await DialogDisplayHelper.ShowDialogAsync( } else if (hFile.ToInt64() == -1) { - await EnumFromStorageFolderAsync(currentFolder, rootFolder, currentStorageFolder, cancellationToken, cacheOnly); + await EnumFromStorageFolderAsync(currentFolder, rootFolder, currentStorageFolder, sourcePageType, cancellationToken, cacheOnly); return false; } else @@ -1175,7 +1185,7 @@ await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => } } - private async Task EnumFromStorageFolderAsync(ListedItem currentFolder, StorageFolder rootFolder, StorageFolderWithPath currentStorageFolder, CancellationToken cancellationToken, bool cacheOnly) + private async Task EnumFromStorageFolderAsync(ListedItem currentFolder, StorageFolder rootFolder, StorageFolderWithPath currentStorageFolder, Type sourcePageType, CancellationToken cancellationToken, bool cacheOnly) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -1190,7 +1200,7 @@ private async Task EnumFromStorageFolderAsync(ListedItem currentFolder, StorageF rootFolder, currentStorageFolder, returnformat, - AssociatedInstance.ContentFrame.SourcePageType, + sourcePageType, cancellationToken, null); } @@ -1200,7 +1210,7 @@ private async Task EnumFromStorageFolderAsync(ListedItem currentFolder, StorageF rootFolder, currentStorageFolder, returnformat, - AssociatedInstance.ContentFrame.SourcePageType, + sourcePageType, cancellationToken, (intermediateList) => { From 931db917e6ac812b4c6163f2bf78bedd2a7f9511 Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Tue, 12 Jan 2021 19:25:07 +0100 Subject: [PATCH 06/19] Fix few styling issues --- Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs | 3 --- Files/ViewModels/ItemViewModel.cs | 2 -- 2 files changed, 5 deletions(-) diff --git a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs index c55be6159e90..22ab779d2880 100644 --- a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs @@ -69,12 +69,9 @@ Func, Task> intermediateAction if (intermediateAction != null && (count == 32 || count % 300 == 0)) { await intermediateAction(tempList); - } } while (hasNextFile); - - FindClose(hFile); return tempList; } diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index c9af04191cd7..6a9fe478b10f 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -1228,8 +1228,6 @@ private async Task EnumFromStorageFolderAsync(ListedItem currentFolder, StorageF Debug.WriteLine($"Enumerating items in {WorkingDirectory} (device) completed in {stopwatch.ElapsedMilliseconds} milliseconds.\n"); } - - private async Task CheckCloudDriveSyncStatusAsync(IStorageItem item) { int? syncStatus = null; From bfa8fbb264f770d7ce9aab1f5a561b976cf380e5 Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Tue, 12 Jan 2021 20:51:35 +0100 Subject: [PATCH 07/19] Add preemptive parallel limit setting --- Files/Strings/en-US/Resources.resw | 3 +++ Files/ViewModels/ItemViewModel.cs | 5 +++-- Files/ViewModels/SettingsViewModel.cs | 9 +++++++++ .../SettingsViewModels/ExperimentalViewModel.cs | 17 +++++++++++++++++ Files/Views/SettingsPages/Experimental.xaml | 11 +++++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Files/Strings/en-US/Resources.resw b/Files/Strings/en-US/Resources.resw index dc7f12e03d0c..7e1c5a1c0e3c 100644 --- a/Files/Strings/en-US/Resources.resw +++ b/Files/Strings/en-US/Resources.resw @@ -1554,6 +1554,9 @@ Cache files and folders for better performance + + Preemptive cache parallel limit (0 turns off the preemptive cache) + Add diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index 6a9fe478b10f..b453939b1d27 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -808,7 +808,8 @@ public async void RapidAddItemsToCollectionAsync(string path, string previousDir WatchForDirectoryChanges(path); } - if (App.AppSettings.UseFileListCache && !_addFilesCTS.IsCancellationRequested) + var parallelLimit = App.AppSettings.PreemptiveCacheParallelLimit; + if (App.AppSettings.UseFileListCache && parallelLimit > 0 && !_addFilesCTS.IsCancellationRequested) { // run background tasks to iterate through folders and cache all of them preemptively var folders = _filesAndFolders.Where(e => e.PrimaryItemAttribute == StorageItemTypes.Folder); @@ -832,7 +833,7 @@ await folders.AsyncParallelForEach(async (folder) => } } await EnumerateItemsFromStandardFolderAsync(path, storageFolder, sourcePageType, _addFilesCTS.Token, cacheOnly: true); - }, maxDegreeOfParallelism: 5); + }, maxDegreeOfParallelism: parallelLimit); } catch (Exception e) { diff --git a/Files/ViewModels/SettingsViewModel.cs b/Files/ViewModels/SettingsViewModel.cs index e16568da262a..3534e8906bcc 100644 --- a/Files/ViewModels/SettingsViewModel.cs +++ b/Files/ViewModels/SettingsViewModel.cs @@ -607,6 +607,15 @@ public bool UseFileListCache set => Set(value); } + /// + /// Gets or sets a value indicating the limit of parallel preemptive cache loading limit. + /// + public int PreemptiveCacheParallelLimit + { + get => Get(5); + set => Set(value); + } + #endregion Experimental #region Startup diff --git a/Files/ViewModels/SettingsViewModels/ExperimentalViewModel.cs b/Files/ViewModels/SettingsViewModels/ExperimentalViewModel.cs index 6c78e8694b54..b55f8f66359d 100644 --- a/Files/ViewModels/SettingsViewModels/ExperimentalViewModel.cs +++ b/Files/ViewModels/SettingsViewModels/ExperimentalViewModel.cs @@ -37,5 +37,22 @@ public bool UseFileListCache } } } + + private int preemptiveCacheParallelLimit = App.AppSettings.PreemptiveCacheParallelLimit; + + public int PreemptiveCacheParallelLimit + { + get + { + return preemptiveCacheParallelLimit; + } + set + { + if (SetProperty(ref preemptiveCacheParallelLimit, value)) + { + App.AppSettings.PreemptiveCacheParallelLimit = value; + } + } + } } } \ No newline at end of file diff --git a/Files/Views/SettingsPages/Experimental.xaml b/Files/Views/SettingsPages/Experimental.xaml index 755f8bc48641..b7e3df150979 100644 --- a/Files/Views/SettingsPages/Experimental.xaml +++ b/Files/Views/SettingsPages/Experimental.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:settingsviewmodels="using:Files.ViewModels.SettingsViewModels" + xmlns:controls="using:Microsoft.UI.Xaml.Controls" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" mc:Ignorable="d"> @@ -45,6 +46,16 @@ Header="Cache files and folders for better performance" HeaderTemplate="{StaticResource CustomHeaderStyle}" IsOn="{Binding UseFileListCache, Mode=TwoWay}" /> + + From 94c3947e6f127130bf130d80ca5a4fe5f507491c Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Wed, 13 Jan 2021 11:12:34 +0100 Subject: [PATCH 08/19] Minor ui adjustements --- Files/Views/SettingsPages/Experimental.xaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Files/Views/SettingsPages/Experimental.xaml b/Files/Views/SettingsPages/Experimental.xaml index b7e3df150979..8b1fc5932524 100644 --- a/Files/Views/SettingsPages/Experimental.xaml +++ b/Files/Views/SettingsPages/Experimental.xaml @@ -51,10 +51,11 @@ x:Uid="PreemptiveCacheParallelLimits" HorizontalAlignment="Left" Header="Preemptive cache parallel limit (0 turns off the preemptive cache)" - FontSize="17" SpinButtonPlacementMode="Inline" - Width="300" + Width="450" Value="{Binding PreemptiveCacheParallelLimit, Mode=TwoWay}" + HeaderTemplate="{StaticResource CustomHeaderStyle}" + IsEnabled="{Binding UseFileListCache, Mode=OneWay}" Minimum="0" /> From f393b7261ebe0e5ed388be44f74d7a040ee5cfc6 Mon Sep 17 00:00:00 2001 From: Yair Aichenbaum <39923744+yaichenbaum@users.noreply.github.com> Date: Wed, 13 Jan 2021 11:02:44 -0500 Subject: [PATCH 09/19] Update Files/Views/SettingsPages/Experimental.xaml --- Files/Views/SettingsPages/Experimental.xaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Files/Views/SettingsPages/Experimental.xaml b/Files/Views/SettingsPages/Experimental.xaml index 8b1fc5932524..913a1a0f0629 100644 --- a/Files/Views/SettingsPages/Experimental.xaml +++ b/Files/Views/SettingsPages/Experimental.xaml @@ -56,8 +56,10 @@ Value="{Binding PreemptiveCacheParallelLimit, Mode=TwoWay}" HeaderTemplate="{StaticResource CustomHeaderStyle}" IsEnabled="{Binding UseFileListCache, Mode=OneWay}" - Minimum="0" /> + Minimum="0" + HeaderTemplate="{StaticResource CustomHeaderStyle}" + IsEnabled="{Binding UseFileListCache, Mode=OneWay}"/> - \ No newline at end of file + From 741cf40b49e32db0c150245251a68807064892b5 Mon Sep 17 00:00:00 2001 From: Yair Aichenbaum <39923744+yaichenbaum@users.noreply.github.com> Date: Wed, 13 Jan 2021 11:29:53 -0500 Subject: [PATCH 10/19] Update Files/Views/SettingsPages/Experimental.xaml --- Files/Views/SettingsPages/Experimental.xaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Files/Views/SettingsPages/Experimental.xaml b/Files/Views/SettingsPages/Experimental.xaml index 913a1a0f0629..59cc69f8b6c8 100644 --- a/Files/Views/SettingsPages/Experimental.xaml +++ b/Files/Views/SettingsPages/Experimental.xaml @@ -54,8 +54,6 @@ SpinButtonPlacementMode="Inline" Width="450" Value="{Binding PreemptiveCacheParallelLimit, Mode=TwoWay}" - HeaderTemplate="{StaticResource CustomHeaderStyle}" - IsEnabled="{Binding UseFileListCache, Mode=OneWay}" Minimum="0" HeaderTemplate="{StaticResource CustomHeaderStyle}" IsEnabled="{Binding UseFileListCache, Mode=OneWay}"/> From 7a598abe2c975c2d8a49577e5ca7d0642ed4b3d3 Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Fri, 15 Jan 2021 11:28:04 +0100 Subject: [PATCH 11/19] Style update --- Files/Filesystem/FolderHelpers.cs | 17 +++++++++ .../Win32StorageEnumerator.cs | 21 +---------- Files/ViewModels/ItemViewModel.cs | 37 ++++++++++++------- 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/Files/Filesystem/FolderHelpers.cs b/Files/Filesystem/FolderHelpers.cs index e636359af01d..45bc061bd8c8 100644 --- a/Files/Filesystem/FolderHelpers.cs +++ b/Files/Filesystem/FolderHelpers.cs @@ -56,5 +56,22 @@ public static async Task CheckBitlockerStatusAsync(StorageFolder rootFolde } return false; } + + /// + /// This function is used to determine whether or not a folder has any contents. + /// + /// The path to the target folder + /// + public static bool CheckForFilesFolders(string targetPath) + { + FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; + int additionalFlags = FIND_FIRST_EX_LARGE_FETCH; + + IntPtr hFile = FindFirstFileExFromApp(targetPath + "\\*.*", findInfoLevel, out WIN32_FIND_DATA _, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags); + FindNextFile(hFile, out _); + var result = FindNextFile(hFile, out _); + FindClose(hFile); + return result; + } } } diff --git a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs index 22ab779d2880..d0482ab55c18 100644 --- a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs @@ -129,7 +129,7 @@ CancellationToken cancellationToken LoadUnknownTypeGlyph = false, FileSize = null, FileSizeBytes = 0, - ContainsFilesOrFolders = CheckForFilesFolders(itemPath), + ContainsFilesOrFolders = FolderHelpers.CheckForFilesFolders(itemPath), IsPinned = pinned, //FolderTooltipText = tooltipString, }; @@ -236,7 +236,7 @@ CancellationToken cancellationToken if ((bool)response.Message["IsFolder"]) { - containsFilesOrFolders = CheckForFilesFolders(target); + containsFilesOrFolders = FolderHelpers.CheckForFilesFolders(target); } bool isHidden = (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden); @@ -307,22 +307,5 @@ CancellationToken cancellationToken } return null; } - - /// - /// This function is used to determine whether or not a folder has any contents. - /// - /// The path to the target folder - /// - private static bool CheckForFilesFolders(string targetPath) - { - FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; - int additionalFlags = FIND_FIRST_EX_LARGE_FETCH; - - IntPtr hFile = FindFirstFileExFromApp(targetPath + "\\*.*", findInfoLevel, out WIN32_FIND_DATA _, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags); - FindNextFile(hFile, out _); - var result = FindNextFile(hFile, out _); - FindClose(hFile); - return result; - } } } diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index adbd45e9a8b0..1f52c3b0ee53 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -822,24 +822,24 @@ public async void RapidAddItemsToCollectionAsync(string path, string previousDir else { var sourcePageType = AssociatedInstance.ContentFrame.SourcePageType; - if (await EnumerateItemsFromStandardFolderAsync(path, _currentStorageFolder, sourcePageType, _addFilesCTS.Token, cacheOnly: false)) + if (await EnumerateItemsFromStandardFolderAsync(path, currentStorageFolder, sourcePageType, addFilesCTS.Token, cacheOnly: false)) { WatchForDirectoryChanges(path); } var parallelLimit = App.AppSettings.PreemptiveCacheParallelLimit; - if (App.AppSettings.UseFileListCache && parallelLimit > 0 && !_addFilesCTS.IsCancellationRequested) + if (App.AppSettings.UseFileListCache && parallelLimit > 0 && !addFilesCTS.IsCancellationRequested) { // run background tasks to iterate through folders and cache all of them preemptively - var folders = _filesAndFolders.Where(e => e.PrimaryItemAttribute == StorageItemTypes.Folder); - var currentStorageFolderSnapshot = _currentStorageFolder; + var folders = filesAndFolders.Where(e => e.PrimaryItemAttribute == StorageItemTypes.Folder); + var currentStorageFolderSnapshot = currentStorageFolder; Task.Run(async () => { try { await folders.AsyncParallelForEach(async (folder) => { - if (_addFilesCTS.IsCancellationRequested) return; + if (addFilesCTS.IsCancellationRequested) return; var path = folder.ItemPath; StorageFolderWithPath storageFolder = null; @@ -851,7 +851,7 @@ await folders.AsyncParallelForEach(async (folder) => storageFolder = res.Result; } } - await EnumerateItemsFromStandardFolderAsync(path, storageFolder, sourcePageType, _addFilesCTS.Token, cacheOnly: true); + await EnumerateItemsFromStandardFolderAsync(path, storageFolder, sourcePageType, addFilesCTS.Token, cacheOnly: true); }, maxDegreeOfParallelism: parallelLimit); } catch (Exception e) @@ -1006,7 +1006,7 @@ await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => }); } - public async Task EnumerateItemsFromStandardFolderAsync(string path, StorageFolderWithPath currentStorageFolder, Type sourcePageType, CancellationToken cancellationToken, bool cacheOnly = false) + public async Task EnumerateItemsFromStandardFolderAsync(string path, StorageFolderWithPath storageFolderForGivenPath, Type sourcePageType, CancellationToken cancellationToken, bool cacheOnly = false) { // Flag to use FindFirstFileExFromApp or StorageFolder enumeration bool enumFromStorageFolder = false; @@ -1019,12 +1019,15 @@ public async Task EnumerateItemsFromStandardFolderAsync(string path, Stora } else if (workingRoot != null) { - rootFolder = currentStorageFolder.Folder; + rootFolder = storageFolderForGivenPath.Folder; enumFromStorageFolder = true; } else if (!FolderHelpers.CheckFolderAccessWithWin32(path)) // The folder is really inaccessible { - if (cacheOnly) return false; + if (cacheOnly) + { + return false; + } if (res == FileSystemStatusCode.Unauthorized) { @@ -1096,14 +1099,16 @@ await DialogDisplayHelper.ShowDialogAsync( LoadFolderGlyph = true, FileImage = null, LoadFileIcon = false, - ItemPath = string.IsNullOrEmpty(rootFolder.Path) ? currentStorageFolder.Path : rootFolder.Path, + ItemPath = string.IsNullOrEmpty(rootFolder.Path) ? storageFolderForGivenPath.Path : rootFolder.Path, LoadUnknownTypeGlyph = false, FileSize = null, FileSizeBytes = 0 }; if (!cacheOnly) + { CurrentFolder = currentFolder; - await EnumFromStorageFolderAsync(currentFolder, rootFolder, currentStorageFolder, sourcePageType, cancellationToken, cacheOnly); + } + await EnumFromStorageFolderAsync(currentFolder, rootFolder, storageFolderForGivenPath, sourcePageType, cancellationToken, cacheOnly); return true; } else @@ -1154,17 +1159,21 @@ await DialogDisplayHelper.ShowDialogAsync( FileSizeBytes = 0 }; if (!cacheOnly) + { CurrentFolder = currentFolder; + } if (hFile == IntPtr.Zero) { if (!cacheOnly) + { await DialogDisplayHelper.ShowDialogAsync("DriveUnpluggedDialog/Title".GetLocalized(), ""); + } return false; } else if (hFile.ToInt64() == -1) { - await EnumFromStorageFolderAsync(currentFolder, rootFolder, currentStorageFolder, sourcePageType, cancellationToken, cacheOnly); + await EnumFromStorageFolderAsync(currentFolder, rootFolder, storageFolderForGivenPath, sourcePageType, cancellationToken, cacheOnly); return false; } else @@ -1514,11 +1523,11 @@ private async Task AddFileOrFolderAsync(string fileOrFolderPath, string dateRetu ListedItem listedItem = null; if ((findData.dwFileAttributes & 0x10) > 0) // FILE_ATTRIBUTE_DIRECTORY { - listedItem = Win32StorageEnumerator.GetFolder(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, _addFilesCTS.Token); + listedItem = Win32StorageEnumerator.GetFolder(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, addFilesCTS.Token); } else { - listedItem = await Win32StorageEnumerator.GetFile(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, Connection, _addFilesCTS.Token); + listedItem = await Win32StorageEnumerator.GetFile(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, Connection, addFilesCTS.Token); } if (listedItem != null) From 03a2481abb3df4bffa187c8456ae2aa1dda4ba01 Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Sun, 31 Jan 2021 20:58:53 +0100 Subject: [PATCH 12/19] Tackle the crash on startup issue --- .../PersistentSQLiteCacheAdapter.cs | 83 ++++++++++++------- Files/ViewModels/ItemViewModel.cs | 4 +- 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs b/Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs index 80259caad5aa..f0355b906989 100644 --- a/Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs +++ b/Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs @@ -1,4 +1,5 @@ using Microsoft.Data.Sqlite; +using Microsoft.Toolkit.Uwp.Helpers; using Newtonsoft.Json; using System; using System.Diagnostics; @@ -12,39 +13,15 @@ namespace Files.Helpers.FileListCache { internal class PersistentSQLiteCacheAdapter : IFileListCache, IDisposable { - private readonly SqliteConnection connection; + private SqliteConnection connection; private bool disposedValue; - public PersistentSQLiteCacheAdapter() + public async Task SaveFileListToCache(string path, CacheEntry cacheEntry) { - var localCacheFolder = ApplicationData.Current.LocalCacheFolder.Path; - string dbPath = Path.Combine(localCacheFolder, "cache.db"); - - bool schemaCreated = File.Exists(dbPath); - - SQLitePCL.Batteries_V2.Init(); - - connection = new SqliteConnection($"Data Source='{dbPath}'"); - connection.Open(); - - if (!schemaCreated) + if(!await InitializeIfNeeded()) { - // create db schema - var createSql = @"CREATE TABLE ""FileListCache"" ( - ""Id"" VARCHAR(5000) NOT NULL, - ""Timestamp"" INTEGER NOT NULL, - ""Entry"" TEXT NOT NULL, - PRIMARY KEY(""Id"") - )"; - using var cmd = new SqliteCommand(createSql, connection); - var result = cmd.ExecuteNonQuery(); + return; } - - RunCleanupRoutine(); - } - - public async Task SaveFileListToCache(string path, CacheEntry cacheEntry) - { const int maxCachedEntries = 128; try { @@ -85,12 +62,16 @@ public async Task SaveFileListToCache(string path, CacheEntry cacheEntry) } catch (Exception ex) { - Debug.WriteLine(ex.ToString()); + NLog.LogManager.GetCurrentClassLogger().Error(ex, ex.Message); } } public async Task ReadFileListFromCache(string path, CancellationToken cancellationToken) { + if (!await InitializeIfNeeded()) + { + return null; + } try { using var cmd = new SqliteCommand("SELECT Timestamp, Entry FROM FileListCache WHERE Id = @Id", connection); @@ -110,7 +91,7 @@ public async Task ReadFileListFromCache(string path, CancellationTok } catch (Exception ex) { - Debug.WriteLine(ex.ToString()); + NLog.LogManager.GetCurrentClassLogger().Error(ex, ex.Message); return null; } } @@ -145,9 +126,49 @@ private void RunCleanupRoutine() } catch (Exception ex) { - Debug.WriteLine(ex.ToString()); + NLog.LogManager.GetCurrentClassLogger().Error(ex, ex.Message); } }); } + + private async Task InitializeIfNeeded() + { + if (disposedValue) return false; + if (connection != null) return true; + + string dbPath = null; + try + { + bool schemaCreated = await ApplicationData.Current.LocalFolder.FileExistsAsync("cache.db"); + await ApplicationData.Current.LocalFolder.CreateFileAsync("cache.db"); + + dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, "cache.db"); + + SQLitePCL.Batteries_V2.Init(); + + connection = new SqliteConnection($"Data Source='{dbPath}'"); + connection.Open(); + + if (!schemaCreated) + { + // create db schema + var createSql = @"CREATE TABLE ""FileListCache"" ( + ""Id"" VARCHAR(5000) NOT NULL, + ""Timestamp"" INTEGER NOT NULL, + ""Entry"" TEXT NOT NULL, + PRIMARY KEY(""Id"") + )"; + using var cmd = new SqliteCommand(createSql, connection); + var result = cmd.ExecuteNonQuery(); + } + + RunCleanupRoutine(); + return true; + } catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Error(ex, $"Failed initializing database with path: {dbPath}"); + return false; + } + } } } \ No newline at end of file diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index d9e9a47173fc..8412d5f2cbc9 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -967,10 +967,10 @@ await folders.AsyncParallelForEach(async (folder) => await EnumerateItemsFromStandardFolderAsync(path, storageFolder, sourcePageType, addFilesCTS.Token, null, cacheOnly: true); }, maxDegreeOfParallelism: parallelLimit); } - catch (Exception e) + catch (Exception ex) { // ignore exception. This is fine, it's only a caching that can fail - Debug.WriteLine(e.ToString()); + NLog.LogManager.GetCurrentClassLogger().Error(ex, ex.Message); } }).Forget(); } From 2a5e708aedef6076515e8a9602c351bdaaa5bfff Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Sun, 31 Jan 2021 21:23:22 +0100 Subject: [PATCH 13/19] Cache only initial burst (32 items) --- .../UniversalStorageEnumerator.cs | 7 +++++++ .../Win32StorageEnumerator.cs | 3 ++- Files/ViewModels/ItemViewModel.cs | 18 ++++++++++-------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs index 6eab9135d787..6018ade48701 100644 --- a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs @@ -24,6 +24,7 @@ public static async Task> ListEntries( Type sourcePageType, CancellationToken cancellationToken, List skipItems, + int countLimit, Func, Task> intermediateAction ) { @@ -105,6 +106,12 @@ ex is UnauthorizedAccessException } } count += maxItemsToRetrieve; + + if (countLimit > -1 && count >= countLimit) + { + break; + } + if (intermediateAction != null && (items.Count == maxItemsToRetrieve || sampler.CheckNow())) { await intermediateAction(tempList); diff --git a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs index 2b846993db07..1651b22aedba 100644 --- a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs @@ -26,6 +26,7 @@ public static async Task> ListEntries( AppServiceConnection connection, CancellationToken cancellationToken, List skipItems, + int countLimit, Func, Task> intermediateAction ) { @@ -77,7 +78,7 @@ Func, Task> intermediateAction } } } - if (cancellationToken.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested || count == countLimit) { break; } diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index 8412d5f2cbc9..7a0acda8f72b 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -1218,7 +1218,7 @@ await DialogDisplayHelper.ShowDialogAsync( { CurrentFolder = currentFolder; } - await EnumFromStorageFolderAsync(path, rootFolder, storageFolderForGivenPath, sourcePageType, cancellationToken, skipItems, cacheOnly); + await EnumFromStorageFolderAsync(path, currentFolder, rootFolder, storageFolderForGivenPath, sourcePageType, cancellationToken, skipItems, cacheOnly); return true; } else @@ -1283,7 +1283,7 @@ await DialogDisplayHelper.ShowDialogAsync( } else if (hFile.ToInt64() == -1) { - await EnumFromStorageFolderAsync(path, rootFolder, storageFolderForGivenPath, sourcePageType, cancellationToken, skipItems, cacheOnly); + await EnumFromStorageFolderAsync(path, currentFolder, rootFolder, storageFolderForGivenPath, sourcePageType, cancellationToken, skipItems, cacheOnly); return false; } else @@ -1291,16 +1291,16 @@ await DialogDisplayHelper.ShowDialogAsync( List fileList; if (cacheOnly) { - fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, Connection, cancellationToken, skipItems, null); + fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, Connection, cancellationToken, skipItems, 32, null); await fileListCache.SaveFileListToCache(path, new CacheEntry { - CurrentFolder = CurrentFolder, + CurrentFolder = currentFolder, FileList = fileList }); } else { - fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, Connection, cancellationToken, skipItems, intermediateAction: async (intermediateList) => + fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, Connection, cancellationToken, skipItems, -1, intermediateAction: async (intermediateList) => { filesAndFolders.AddRange(intermediateList); await OrderFilesAndFoldersAsync(); @@ -1343,7 +1343,7 @@ await DialogDisplayHelper.ShowDialogAsync( } } - private async Task EnumFromStorageFolderAsync(string path, StorageFolder rootFolder, StorageFolderWithPath currentStorageFolder, Type sourcePageType, CancellationToken cancellationToken, List skipItems, bool cacheOnly) + private async Task EnumFromStorageFolderAsync(string path, ListedItem currentFolder, StorageFolder rootFolder, StorageFolderWithPath currentStorageFolder, Type sourcePageType, CancellationToken cancellationToken, List skipItems, bool cacheOnly) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -1361,10 +1361,11 @@ private async Task EnumFromStorageFolderAsync(string path, StorageFolder rootFol sourcePageType, cancellationToken, null, + 32, null); await fileListCache.SaveFileListToCache(path, new CacheEntry { - CurrentFolder = CurrentFolder, + CurrentFolder = currentFolder, FileList = finalList }); } @@ -1377,6 +1378,7 @@ private async Task EnumFromStorageFolderAsync(string path, StorageFolder rootFol sourcePageType, cancellationToken, skipItems, + -1, async (intermediateList) => { filesAndFolders.AddRange(intermediateList); @@ -1788,7 +1790,7 @@ private Task SaveCurrentListToCacheAsync(string path) { CurrentFolder = CurrentFolder, // since filesAndFolders could be mutated, memory cache needs a copy of current list - FileList = filesAndFolders.ToList() + FileList = filesAndFolders.Take(32).ToList() }); } From a30900f98735d08341798b3b4af327e70b0cfa7c Mon Sep 17 00:00:00 2001 From: Jakub Syty Date: Wed, 3 Feb 2021 11:22:06 +0100 Subject: [PATCH 14/19] Adjust settings --- Files/Strings/en-US/Resources.resw | 5 +++- Files/ViewModels/ItemViewModel.cs | 2 +- Files/ViewModels/SettingsViewModel.cs | 19 +++++++++---- .../ExperimentalViewModel.cs | 27 +++++++++++++++---- Files/Views/SettingsPages/Experimental.xaml | 16 ++++++++--- 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/Files/Strings/en-US/Resources.resw b/Files/Strings/en-US/Resources.resw index 39d1d0cada7b..895aba21bfd8 100644 --- a/Files/Strings/en-US/Resources.resw +++ b/Files/Strings/en-US/Resources.resw @@ -1561,7 +1561,7 @@ Cache files and folders for better performance - Preemptive cache parallel limit (0 turns off the preemptive cache) + Preemptive cache parallel limit (smaller numbers should work better for hard drives) Add @@ -1821,4 +1821,7 @@ Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + + Use preemptive cache (preload entries in child directories on navigation) + \ No newline at end of file diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index 7a0acda8f72b..d35f29ef8313 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -941,7 +941,7 @@ public async void RapidAddItemsToCollectionAsync(string path, string previousDir } var parallelLimit = App.AppSettings.PreemptiveCacheParallelLimit; - if (App.AppSettings.UseFileListCache && parallelLimit > 0 && !addFilesCTS.IsCancellationRequested) + if (App.AppSettings.UseFileListCache && App.AppSettings.UsePreemptiveCache && parallelLimit > 0 && !addFilesCTS.IsCancellationRequested) { // run background tasks to iterate through folders and cache all of them preemptively var folders = filesAndFolders.Where(e => e.PrimaryItemAttribute == StorageItemTypes.Folder); diff --git a/Files/ViewModels/SettingsViewModel.cs b/Files/ViewModels/SettingsViewModel.cs index ca867d520ea7..4dd9217ac0a7 100644 --- a/Files/ViewModels/SettingsViewModel.cs +++ b/Files/ViewModels/SettingsViewModel.cs @@ -653,13 +653,13 @@ public bool UseFileListCache get => Get(true); set => Set(value); } - + /// - /// Gets or sets a value indicating whether or not to enable the multiselect option. + /// Gets or sets a value indicating whether or not to use preemptive caching. /// - public bool ShowMultiselectOption + public bool UsePreemptiveCache { - get => Get(false); + get => Get(true); set => Set(value); } @@ -668,7 +668,16 @@ public bool ShowMultiselectOption /// public int PreemptiveCacheParallelLimit { - get => Get(5); + get => Get(2); + set => Set(value); + } + + /// + /// Gets or sets a value indicating whether or not to enable the multiselect option. + /// + public bool ShowMultiselectOption + { + get => Get(false); set => Set(value); } diff --git a/Files/ViewModels/SettingsViewModels/ExperimentalViewModel.cs b/Files/ViewModels/SettingsViewModels/ExperimentalViewModel.cs index 81003bb59a20..507a13fcd624 100644 --- a/Files/ViewModels/SettingsViewModels/ExperimentalViewModel.cs +++ b/Files/ViewModels/SettingsViewModels/ExperimentalViewModel.cs @@ -38,18 +38,19 @@ public bool UseFileListCache } } - private bool showMultiselectOption = App.AppSettings.ShowMultiselectOption; - public bool ShowMultiselectOption + private bool usePreemptiveCache = App.AppSettings.UsePreemptiveCache; + + public bool UsePreemptiveCache { get { - return showMultiselectOption; + return usePreemptiveCache; } set { - if (SetProperty(ref showMultiselectOption, value)) + if (SetProperty(ref usePreemptiveCache, value)) { - App.AppSettings.ShowMultiselectOption = value; + App.AppSettings.UsePreemptiveCache = value; } } } @@ -70,5 +71,21 @@ public int PreemptiveCacheParallelLimit } } } + + private bool showMultiselectOption = App.AppSettings.ShowMultiselectOption; + public bool ShowMultiselectOption + { + get + { + return showMultiselectOption; + } + set + { + if (SetProperty(ref showMultiselectOption, value)) + { + App.AppSettings.ShowMultiselectOption = value; + } + } + } } } \ No newline at end of file diff --git a/Files/Views/SettingsPages/Experimental.xaml b/Files/Views/SettingsPages/Experimental.xaml index 41f201c92fee..7e279e9dc9db 100644 --- a/Files/Views/SettingsPages/Experimental.xaml +++ b/Files/Views/SettingsPages/Experimental.xaml @@ -6,10 +6,11 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:settingsviewmodels="using:Files.ViewModels.SettingsViewModels" xmlns:controls="using:Microsoft.UI.Xaml.Controls" + xmlns:converters="using:Files.Converters" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" mc:Ignorable="d"> - + @@ -47,16 +48,23 @@ HeaderTemplate="{StaticResource CustomHeaderStyle}" IsOn="{Binding UseFileListCache, Mode=TwoWay}" /> + + + IsEnabled="{x:Bind converters:MultiBooleanConverter.AndConvert(viewModel.UseFileListCache, viewModel.UsePreemptiveCache), Mode=OneWay}"/> Date: Sun, 14 Feb 2021 18:56:34 +0100 Subject: [PATCH 15/19] Merge main --- Common/ShellFileItem.cs | 4 +- Files.Launcher/Files.Launcher.csproj | 8 +- Files.Launcher/Program.cs | 98 +- Files.Launcher/QuickLook.cs | 10 +- Files.Package/Files.Package.wapproj | 2 +- Files.Package/Package.appxmanifest | 2 +- Files/App.xaml.cs | 55 +- Files/BaseLayout.cs | 14 + Files/Controllers/SidebarPinnedController.cs | 12 +- Files/DataModels/SidebarPinnedModel.cs | 34 +- Files/Dialogs/ConsentDialog.xaml | 25 - Files/Dialogs/ConsentDialog.xaml.cs | 21 - Files/Dialogs/DynamicDialog.xaml | 12 +- Files/Dialogs/DynamicDialog.xaml.cs | 21 +- Files/Dialogs/PropertySaveError.xaml | 27 - Files/Dialogs/PropertySaveError.xaml.cs | 24 - Files/Dialogs/RenameDialog.xaml | 39 - Files/Dialogs/RenameDialog.xaml.cs | 59 - Files/Enums/DynamicDialogButtons.cs | 10 + Files/Enums/DynamicDialogResult.cs | 9 + Files/Enums/SortOption.cs | 1 + Files/Files.csproj | 34 +- .../Cloud/CloudProviderController.cs | 17 +- .../Cloud/Providers/OneDriveCloudProvider.cs | 42 +- .../OneDriveSharePointCloudProvider.cs | 51 + Files/Filesystem/CloudDrivesManager.cs | 60 +- Files/Filesystem/Drives.cs | 49 +- .../FilesystemOperations.cs | 31 +- .../Helpers/FilesystemHelpers.cs | 115 +- Files/Filesystem/LocationItem.cs | 2 +- Files/Helpers/AppServiceConnectionHelper.cs | 63 +- Files/Helpers/AppUpdater.cs | 1 - .../BulkConcurrentObservableCollection.cs | 54 +- Files/Helpers/CollectionDebugView.cs | 27 + Files/Helpers/DialogDisplayHelper.cs | 25 +- Files/Helpers/DynamicDialogFactory.cs | 115 + .../FileListCache/FileListCacheController.cs | 38 + Files/Helpers/FileListCache/IFileListCache.cs | 4 + .../PersistentSQLiteCacheAdapter.cs | 112 +- Files/Helpers/JumpListManager.cs | 18 +- Files/Helpers/PathNormalization.cs | 2 +- Files/Helpers/ThemeHelper.cs | 74 +- Files/Interacts/Interaction.cs | 52 +- Files/MultilingualResources/Files.ar.xlf | 56 +- Files/MultilingualResources/Files.cs-CZ.xlf | 56 +- Files/MultilingualResources/Files.da-DK.xlf | 56 +- Files/MultilingualResources/Files.da.xlf | 56 +- Files/MultilingualResources/Files.de-DE.xlf | 63 +- Files/MultilingualResources/Files.es-ES.xlf | 58 +- Files/MultilingualResources/Files.fr-FR.xlf | 59 +- Files/MultilingualResources/Files.he-IL.xlf | 56 +- Files/MultilingualResources/Files.hi-IN.xlf | 56 +- Files/MultilingualResources/Files.hu-HU.xlf | 512 ++-- Files/MultilingualResources/Files.it-IT.xlf | 56 +- Files/MultilingualResources/Files.ja-JP.xlf | 223 +- Files/MultilingualResources/Files.ko-KR.xlf | 61 + Files/MultilingualResources/Files.nl-NL.xlf | 56 +- Files/MultilingualResources/Files.or-IN.xlf | 56 +- Files/MultilingualResources/Files.pl-PL.xlf | 200 +- Files/MultilingualResources/Files.pt-BR.xlf | 56 +- Files/MultilingualResources/Files.ru-RU.xlf | 56 +- Files/MultilingualResources/Files.sv-SE.xlf | 2332 +++++++++++++++++ Files/MultilingualResources/Files.ta.xlf | 56 +- Files/MultilingualResources/Files.tr-TR.xlf | 56 +- Files/MultilingualResources/Files.uk-UA.xlf | 56 +- Files/MultilingualResources/Files.zh-Hans.xlf | 56 +- Files/MultilingualResources/Files.zh-Hant.xlf | 56 +- Files/Strings/de-DE/Resources.resw | 14 +- Files/Strings/en-US/Resources.resw | 41 +- Files/Strings/es-ES/Resources.resw | 45 + Files/Strings/fr-FR/Resources.resw | 6 + Files/Strings/hu-HU/Resources.resw | 480 ++-- Files/Strings/ja-JP/Resources.resw | 249 +- Files/Strings/pl-PL/Resources.resw | 181 +- Files/Strings/sv-SE/Resources.resw | 1716 ++++++++++++ .../FilePreviews/ImagePreview.xaml | 4 +- Files/UserControls/NavigationToolbar.xaml.cs | 31 +- .../Selection/RectangleSelection.cs | 7 +- .../Selection/RectangleSelection_DataGrid.cs | 12 +- .../RectangleSelection_ListViewBase.cs | 2 +- Files/UserControls/SidebarControl.xaml.cs | 18 + .../Bundles/BundleContainerViewModel.cs | 3 +- Files/ViewModels/Bundles/BundlesViewModel.cs | 3 +- .../Dialogs/DynamicDialogViewModel.cs | 239 +- Files/ViewModels/ItemViewModel.cs | 99 +- .../ViewModels/Properties/DriveProperties.cs | 4 +- Files/ViewModels/Properties/FileProperties.cs | 1 + .../ViewModels/Properties/FolderProperties.cs | 1 + Files/ViewModels/SettingsViewModel.cs | 27 +- .../Views/LayoutModes/GenericFileBrowser.xaml | 48 +- .../LayoutModes/GenericFileBrowser.xaml.cs | 36 +- Files/Views/LayoutModes/GridViewBrowser.xaml | 24 +- .../Views/LayoutModes/GridViewBrowser.xaml.cs | 11 +- Files/Views/MainPage.xaml.cs | 52 +- Files/Views/ModernShellPage.xaml.cs | 83 +- Files/Views/Pages/PropertiesDetails.xaml.cs | 13 +- Files/Views/YourHome.xaml.cs | 4 +- MessageRelay/Files.MessageRelay.csproj | 2 +- 98 files changed, 7933 insertions(+), 1400 deletions(-) delete mode 100644 Files/Dialogs/ConsentDialog.xaml delete mode 100644 Files/Dialogs/ConsentDialog.xaml.cs delete mode 100644 Files/Dialogs/PropertySaveError.xaml delete mode 100644 Files/Dialogs/PropertySaveError.xaml.cs delete mode 100644 Files/Dialogs/RenameDialog.xaml delete mode 100644 Files/Dialogs/RenameDialog.xaml.cs create mode 100644 Files/Enums/DynamicDialogButtons.cs create mode 100644 Files/Enums/DynamicDialogResult.cs create mode 100644 Files/Filesystem/Cloud/Providers/OneDriveSharePointCloudProvider.cs create mode 100644 Files/Helpers/CollectionDebugView.cs create mode 100644 Files/Helpers/DynamicDialogFactory.cs create mode 100644 Files/MultilingualResources/Files.sv-SE.xlf create mode 100644 Files/Strings/sv-SE/Resources.resw diff --git a/Common/ShellFileItem.cs b/Common/ShellFileItem.cs index 26b6c9e59e9b..50ef7977264d 100644 --- a/Common/ShellFileItem.cs +++ b/Common/ShellFileItem.cs @@ -10,6 +10,7 @@ public class ShellFileItem public string FilePath; public DateTime RecycleDate; public DateTime ModifiedDate; + public DateTime CreatedDate; public string FileSize; public ulong FileSizeBytes; public string FileType; @@ -20,7 +21,7 @@ public ShellFileItem() public ShellFileItem( bool isFolder, string recyclePath, string fileName, string filePath, - DateTime recycleDate, DateTime modifiedDate, string fileSize, ulong fileSizeBytes, string fileType) + DateTime recycleDate, DateTime modifiedDate, DateTime createdDate, string fileSize, ulong fileSizeBytes, string fileType) { this.IsFolder = isFolder; this.RecyclePath = recyclePath; @@ -28,6 +29,7 @@ public ShellFileItem( this.FilePath = filePath; this.RecycleDate = recycleDate; this.ModifiedDate = modifiedDate; + this.CreatedDate = createdDate; this.FileSize = fileSize; this.FileSizeBytes = fileSizeBytes; this.FileType = fileType; diff --git a/Files.Launcher/Files.Launcher.csproj b/Files.Launcher/Files.Launcher.csproj index 30900bbb821d..411e3d5dfb82 100644 --- a/Files.Launcher/Files.Launcher.csproj +++ b/Files.Launcher/Files.Launcher.csproj @@ -111,9 +111,6 @@ true - - ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll - @@ -126,9 +123,6 @@ - - $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd - @@ -164,7 +158,7 @@ 4.7.0 - 3.3.2 + 3.3.4 diff --git a/Files.Launcher/Program.cs b/Files.Launcher/Program.cs index 443450f74185..4c2da180174d 100644 --- a/Files.Launcher/Program.cs +++ b/Files.Launcher/Program.cs @@ -233,9 +233,13 @@ private static async Task ParseArgumentsAsync(AppServiceRequestReceivedEventArgs await ParseRecycleBinActionAsync(args, binAction); break; - case "StartupTasks": + case "DetectQuickLook": // Check QuickLook Availability - QuickLook.CheckQuickLookAvailability(localSettings); + var available = QuickLook.CheckQuickLookAvailability(); + await args.Request.SendResponseAsync(new ValueSet() + { + { "IsAvailable", available } + }); break; case "ToggleQuickLook": @@ -326,8 +330,10 @@ await args.Request.SendResponseAsync(new ValueSet() break; case "GetOneDriveAccounts": - using (var oneDriveAccountsKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\OneDrive\Accounts", false)) + try { + var oneDriveAccountsKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\OneDrive\Accounts", false); + if (oneDriveAccountsKey == null) { await args.Request.SendResponseAsync(new ValueSet()); @@ -348,6 +354,68 @@ await args.Request.SendResponseAsync(new ValueSet() } await args.Request.SendResponseAsync(oneDriveAccounts); } + catch + { + await args.Request.SendResponseAsync(new ValueSet()); + } + break; + + case "GetSharePointSyncLocationsFromOneDrive": + try + { + using var oneDriveAccountsKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\OneDrive\Accounts", false); + + if (oneDriveAccountsKey == null) + { + await args.Request.SendResponseAsync(new ValueSet()); + return; + } + + var sharepointAccounts = new ValueSet(); + + foreach (var account in oneDriveAccountsKey.GetSubKeyNames()) + { + var accountKeyName = @$"{oneDriveAccountsKey.Name}\{account}"; + var displayName = (string)Registry.GetValue(accountKeyName, "DisplayName", null); + var userFolderToExcludeFromResults = (string)Registry.GetValue(accountKeyName, "UserFolder", null); + var accountName = string.IsNullOrWhiteSpace(displayName) ? "SharePoint" : $"SharePoint - {displayName}"; + + var sharePointSyncFolders = new List(); + var mountPointKeyName = @$"SOFTWARE\Microsoft\OneDrive\Accounts\{account}\ScopeIdToMountPointPathCache"; + using (var mountPointsKey = Registry.CurrentUser.OpenSubKey(mountPointKeyName)) + { + if (mountPointsKey == null) + { + continue; + } + + var valueNames = mountPointsKey.GetValueNames(); + foreach (var valueName in valueNames) + { + var value = (string)Registry.GetValue(@$"HKEY_CURRENT_USER\{mountPointKeyName}", valueName, null); + if (!string.Equals(value, userFolderToExcludeFromResults, StringComparison.OrdinalIgnoreCase)) + { + sharePointSyncFolders.Add(value); + } + } + } + + foreach (var sharePointSyncFolder in sharePointSyncFolders.OrderBy(o => o)) + { + var parentFolder = System.IO.Directory.GetParent(sharePointSyncFolder)?.FullName ?? string.Empty; + if (!sharepointAccounts.Any(acc => string.Equals(acc.Key, accountName, StringComparison.OrdinalIgnoreCase)) && !string.IsNullOrWhiteSpace(parentFolder)) + { + sharepointAccounts.Add(accountName, parentFolder); + } + } + } + + await args.Request.SendResponseAsync(sharepointAccounts); + } + catch + { + await args.Request.SendResponseAsync(new ValueSet()); + } break; default: @@ -609,8 +677,18 @@ private static async Task ParseRecycleBinActionAsync(AppServiceRequestReceivedEv { try { - var shellFileItem = GetRecycleBinItem(folderItem); - folderContentsList.Add(shellFileItem); + // ShellLink Properties refer to destination and not shortcut + if (folderItem is ShellLink shellLink) + { + using var tempItem = new ShellItem(shellLink.PIDL); + var shellFileItem = GetRecycleBinItem(tempItem); + folderContentsList.Add(shellFileItem); + } + else + { + var shellFileItem = GetRecycleBinItem(folderItem); + folderContentsList.Add(shellFileItem); + } } catch (FileNotFoundException) { @@ -638,7 +716,7 @@ private static ShellFileItem GetRecycleBinItem(ShellItem folderItem) bool isFolder = folderItem.IsFolder && Path.GetExtension(folderItem.Name) != ".zip"; if (folderItem.Properties == null) { - return new ShellFileItem(isFolder, recyclePath, fileName, filePath, DateTime.Now, DateTime.Now, null, 0, null); + return new ShellFileItem(isFolder, recyclePath, fileName, filePath, DateTime.Now, DateTime.Now, DateTime.MinValue, null, 0, null); } folderItem.Properties.TryGetValue( Ole32.PROPERTYKEY.System.Recycle.DateDeleted, out var fileTime); @@ -651,7 +729,7 @@ private static ShellFileItem GetRecycleBinItem(ShellItem folderItem) folderItem.Properties.GetPropertyString(Ole32.PROPERTYKEY.System.Size) : null; folderItem.Properties.TryGetValue( Ole32.PROPERTYKEY.System.ItemTypeText, out var fileType); - return new ShellFileItem(isFolder, recyclePath, fileName, filePath, recycleDate, modifiedDate, fileSize, fileSizeBytes ?? 0, fileType); + return new ShellFileItem(isFolder, recyclePath, fileName, filePath, recycleDate, modifiedDate, DateTime.MinValue, fileSize, fileSizeBytes ?? 0, fileType); } private static void HandleApplicationsLaunch(IEnumerable applications, AppServiceRequestReceivedEventArgs args) @@ -788,12 +866,6 @@ private static bool HandleCommandLineArgs() return true; } - else if (arguments == "StartupTasks") - { - // Check QuickLook Availability - QuickLook.CheckQuickLookAvailability(localSettings); - return true; - } } return false; } diff --git a/Files.Launcher/QuickLook.cs b/Files.Launcher/QuickLook.cs index 88b89dd798eb..fbca309a763c 100644 --- a/Files.Launcher/QuickLook.cs +++ b/Files.Launcher/QuickLook.cs @@ -3,7 +3,6 @@ using System.IO; using System.IO.Pipes; using System.Security.Principal; -using Windows.Storage; namespace FilesFullTrust { @@ -30,7 +29,7 @@ public static void ToggleQuickLook(string path) } } - public static void CheckQuickLookAvailability(ApplicationDataContainer localSettings) + public static bool CheckQuickLookAvailability() { static int QuickLookServerAvailable() { @@ -51,7 +50,7 @@ static int QuickLookServerAvailable() return serverInstances; } - catch (TimeoutException e) + catch (TimeoutException) { client.Close(); return 0; @@ -61,14 +60,13 @@ static int QuickLookServerAvailable() try { var result = QuickLookServerAvailable(); - Logger.Info($"QuickLook detected: {result != 0}"); - localSettings.Values["quicklook_enabled"] = result != 0; + return result != 0; } catch (Exception ex) { Logger.Info(ex, ex.Message); - localSettings.Values["quicklook_enabled"] = 0; + return false; } } } diff --git a/Files.Package/Files.Package.wapproj b/Files.Package/Files.Package.wapproj index b94483523eb6..6ea572beb095 100644 --- a/Files.Package/Files.Package.wapproj +++ b/Files.Package/Files.Package.wapproj @@ -55,7 +55,7 @@ False True Scale|DXFeatureLevel - Language=ar;en-US;de-DE;es-ES;fr-FR;he-IL;hi-IN;hu-HU;it-IT;ja-JP;ko-KR;nl-NL;or-IN;pl-PL;pt-BR;ru-RU;cs-CZ;ta;tr-TR;uk-UA;zh-Hans;zh-Hant;da;da-DK + Language=ar;en-US;de-DE;es-ES;fr-FR;he-IL;hi-IN;hu-HU;it-IT;ja-JP;ko-KR;nl-NL;or-IN;pl-PL;pt-BR;ru-RU;sv-SE;cs-CZ;ta;tr-TR;uk-UA;zh-Hans;zh-Hant;da;da-DK StoreUpload 0 ..\Files\Files.csproj diff --git a/Files.Package/Package.appxmanifest b/Files.Package/Package.appxmanifest index f7a81468053f..aff263813d1a 100644 --- a/Files.Package/Package.appxmanifest +++ b/Files.Package/Package.appxmanifest @@ -9,7 +9,7 @@ xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" IgnorableNamespaces="uap uap5 mp rescap desktop4 desktop"> - + Files - Dev Yair A diff --git a/Files/App.xaml.cs b/Files/App.xaml.cs index 2faf4ff9d313..5f27a8bc5f9a 100644 --- a/Files/App.xaml.cs +++ b/Files/App.xaml.cs @@ -46,12 +46,12 @@ sealed partial class App : Application public static IBundlesSettings BundlesSettings = new BundlesSettingsViewModel(); - public static SettingsViewModel AppSettings { get; set; } - public static InteractionViewModel InteractionViewModel { get; set; } + public static SettingsViewModel AppSettings { get; private set; } + public static InteractionViewModel InteractionViewModel { get; private set; } public static JumpListManager JumpList { get; } = new JumpListManager(); - public static SidebarPinnedController SidebarPinnedController { get; set; } - public static CloudDrivesManager CloudDrivesManager { get; set; } - public static DrivesManager DrivesManager { get; set; } + public static SidebarPinnedController SidebarPinnedController { get; private set; } + public static CloudDrivesManager CloudDrivesManager { get; private set; } + public static DrivesManager DrivesManager { get; private set; } private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); @@ -79,50 +79,25 @@ public App() StartAppCenter(); } - internal static async Task EnsureSettingsAndConfigurationAreBootstrapped() + private static async Task EnsureSettingsAndConfigurationAreBootstrapped() { if (AppSettings == null) { //We can't create AppSettings at the same time as everything else as other dependencies depend on AppSettings AppSettings = await SettingsViewModel.CreateInstance(); - if (App.AppSettings?.AcrylicTheme == null) - { - Helpers.ThemeHelper.Initialize(); - } - } - - if (CloudDrivesManager == null) - { - //Enumerate cloud drives on in the background. It will update the UI itself when finished - _ = Files.Filesystem.CloudDrivesManager.Instance.ContinueWith(o => - { - CloudDrivesManager = o.Result; - }); } - //Start off a list of tasks we need to run before we can continue startup - var tasksToRun = new List(); - - if (SidebarPinnedController == null) - { - tasksToRun.Add(Files.Controllers.SidebarPinnedController.CreateInstance().ContinueWith(o => SidebarPinnedController = o.Result)); - } + InteractionViewModel ??= new InteractionViewModel(); + SidebarPinnedController ??= await SidebarPinnedController.CreateInstance(); + DrivesManager ??= new DrivesManager(); + CloudDrivesManager ??= new CloudDrivesManager(); - if (DrivesManager == null) + // Start off a list of tasks we need to run before we can continue startup + _ = Task.Factory.StartNew(async () => { - tasksToRun.Add(Files.Filesystem.DrivesManager.Instance.ContinueWith(o => DrivesManager = o.Result)); - } - - if (InteractionViewModel == null) - { - InteractionViewModel = new InteractionViewModel(); - } - - if (tasksToRun.Any()) - { - //Only proceed when all tasks are completed - await Task.WhenAll(tasksToRun); - } + await DrivesManager.EnumerateDrivesAsync(); + await CloudDrivesManager.EnumerateDrivesAsync(); + }); } private async void StartAppCenter() diff --git a/Files/BaseLayout.cs b/Files/BaseLayout.cs index db96eb80ca98..02e5bccef02f 100644 --- a/Files/BaseLayout.cs +++ b/Files/BaseLayout.cs @@ -290,6 +290,7 @@ private void FolderSettings_LayoutModeChangeRequested(object sender, EventArgs e if (layoutType != ParentShellPageInstance.CurrentPageType) { + FolderSettings.IsLayoutModeChanging = true; ParentShellPageInstance.ContentFrame.Navigate(layoutType, new NavigationArguments() { NavPathParam = navigationArguments.NavPathParam, @@ -800,6 +801,10 @@ await Connection.SendMessageAsync(new ValueSet() { { "droppath", ParentShellPageInstance.FilesystemViewModel.WorkingDirectory } }); } } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, ex.Message); + } if (!draggedItems.Any()) { e.AcceptedOperation = DataPackageOperation.None; @@ -928,6 +933,13 @@ protected async void Item_DragOver(object sender, DragEventArgs e) deferral.Complete(); return; } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, ex.Message); + e.AcceptedOperation = DataPackageOperation.None; + deferral.Complete(); + return; + } e.Handled = true; e.DragUIOverride.IsCaptionVisible = true; @@ -957,6 +969,8 @@ protected async void Item_Drop(object sender, DragEventArgs e) var deferral = e.GetDeferral(); e.Handled = true; + dragOverItem = null; // Reset dragged over item + ListedItem rowItem = GetItemFromElement(sender); if (rowItem != null) { diff --git a/Files/Controllers/SidebarPinnedController.cs b/Files/Controllers/SidebarPinnedController.cs index 0be5033c9fb9..5b6d3b152aa3 100644 --- a/Files/Controllers/SidebarPinnedController.cs +++ b/Files/Controllers/SidebarPinnedController.cs @@ -10,15 +10,15 @@ namespace Files.Controllers public class SidebarPinnedController : IJson { private StorageFolder Folder { get; set; } - private StorageFile JsonFile { get; set; } - public SidebarPinnedModel Model { get; set; } = new SidebarPinnedModel(); - + public SidebarPinnedModel Model { get; set; } public string JsonFileName { get; } = "PinnedItems.json"; private SidebarPinnedController() { + Model = new SidebarPinnedModel(); + Model.SetController(this); } public static Task CreateInstance() @@ -71,18 +71,20 @@ private async Task LoadAsync() Model = JsonConvert.DeserializeObject(await FileIO.ReadTextAsync(JsonFile)); if (Model == null) { - Model = new SidebarPinnedModel(); throw new Exception($"{JsonFileName} is empty, regenerating..."); } + Model.SetController(this); } catch (Exception) { await JsonFile.DeleteAsync(); + Model = new SidebarPinnedModel(); + Model.SetController(this); Model.AddDefaultItems(); Model.Save(); } - Model.AddAllItemsToSidebar(); + await Model.AddAllItemsToSidebar(); } public void SaveModel() diff --git a/Files/DataModels/SidebarPinnedModel.cs b/Files/DataModels/SidebarPinnedModel.cs index 04517eae54f3..3380686845b3 100644 --- a/Files/DataModels/SidebarPinnedModel.cs +++ b/Files/DataModels/SidebarPinnedModel.cs @@ -1,25 +1,36 @@ -using Files.Filesystem; +using Files.Controllers; +using Files.Filesystem; using Files.ViewModels; using Files.Views; using Newtonsoft.Json; +using NLog; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; +using Windows.ApplicationModel.Core; +using Windows.UI.Core; using Windows.UI.Xaml.Media; namespace Files.DataModels { public class SidebarPinnedModel { + private SidebarPinnedController controller; + [JsonIgnore] public SettingsViewModel AppSettings => App.AppSettings; [JsonProperty("items")] public List Items { get; set; } = new List(); + public void SetController(SidebarPinnedController controller) + { + this.controller = controller; + } + /// /// Adds the default items to the navigation page /// @@ -140,7 +151,7 @@ ex is ArgumentException // Pinned item was invalid Debug.WriteLine($"An error occured while swapping pinned items in the navigation sidebar. {ex.Message}"); this.Items = sidebarItemsBackup; this.RemoveStaleSidebarItems(); - this.AddAllItemsToSidebar(); + _ = this.AddAllItemsToSidebar(); } } @@ -168,7 +179,7 @@ public int IndexOfItem(INavigationControlItem locationItem, List /// Saves the model /// - public void Save() => App.SidebarPinnedController.SaveModel(); + public void Save() => controller?.SaveModel(); /// /// Adds the item do the navigation sidebar @@ -207,12 +218,21 @@ public async Task AddItemToSidebarAsync(string path) /// /// Adds all items to the navigation sidebar /// - public async void AddAllItemsToSidebar() + public async Task AddAllItemsToSidebar() { - for (int i = 0; i < Items.Count(); i++) + await MainPage.SideBarItemsSemaphore.WaitAsync(); + try + { + for (int i = 0; i < Items.Count(); i++) + { + string path = Items[i]; + await AddItemToSidebarAsync(path); + } + MainPage.SideBarItems.EndBulkOperation(); + } + finally { - string path = Items[i]; - await AddItemToSidebarAsync(path); + MainPage.SideBarItemsSemaphore.Release(); } } diff --git a/Files/Dialogs/ConsentDialog.xaml b/Files/Dialogs/ConsentDialog.xaml deleted file mode 100644 index 7855aaa537b0..000000000000 --- a/Files/Dialogs/ConsentDialog.xaml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Files/Dialogs/ConsentDialog.xaml.cs b/Files/Dialogs/ConsentDialog.xaml.cs deleted file mode 100644 index 69dea2bb102a..000000000000 --- a/Files/Dialogs/ConsentDialog.xaml.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Windows.System; -using Windows.UI.Xaml.Controls; - -// The Content Dialog item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 - -namespace Files.Dialogs -{ - public sealed partial class ConsentDialog : ContentDialog - { - public ConsentDialog() - { - this.InitializeComponent(); - } - - private async void PermissionDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) - { - await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-broadfilesystemaccess")); - } - } -} \ No newline at end of file diff --git a/Files/Dialogs/DynamicDialog.xaml b/Files/Dialogs/DynamicDialog.xaml index d1c23e64f28c..5204b7caf6db 100644 --- a/Files/Dialogs/DynamicDialog.xaml +++ b/Files/Dialogs/DynamicDialog.xaml @@ -17,8 +17,9 @@ PrimaryButtonText="{Binding PrimaryButtonText, Mode=OneWay}" SecondaryButtonStyle="{StaticResource DefaultButtonStyle}" SecondaryButtonText="{Binding SecondaryButtonText, Mode=OneWay}" + IsPrimaryButtonEnabled="{Binding IsPrimaryButtonEnabled, Mode=OneWay}" + IsSecondaryButtonEnabled="{Binding IsSecondaryButtonEnabled, Mode=OneWay}" mc:Ignorable="d"> - @@ -38,7 +39,7 @@ - + @@ -49,7 +50,10 @@ Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" - Text="{Binding SubtitleText, Mode=OneWay}" /> + Text="{Binding SubtitleText, Mode=OneWay}" + x:Load="{x:Bind ViewModel.SubtitleLoad, Mode=OneWay}" + x:Name="Subtitle" + TextWrapping="WrapWholeWords" /> \ No newline at end of file diff --git a/Files/Dialogs/DynamicDialog.xaml.cs b/Files/Dialogs/DynamicDialog.xaml.cs index 517fffb461fb..7d9c50d55528 100644 --- a/Files/Dialogs/DynamicDialog.xaml.cs +++ b/Files/Dialogs/DynamicDialog.xaml.cs @@ -1,11 +1,13 @@ -using Files.ViewModels.Dialogs; +using Files.Enums; +using Files.ViewModels.Dialogs; +using System; using Windows.UI.Xaml.Controls; // The Content Dialog item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 namespace Files.Dialogs { - public sealed partial class DynamicDialog : ContentDialog + public sealed partial class DynamicDialog : ContentDialog, IDisposable { public DynamicDialogViewModel ViewModel { @@ -13,6 +15,11 @@ public DynamicDialogViewModel ViewModel private set => DataContext = value; } + public DynamicDialogResult DynamicResult + { + get => ViewModel.DynamicResult; + } + public DynamicDialog(DynamicDialogViewModel dynamicDialogViewModel) { this.InitializeComponent(); @@ -20,5 +27,15 @@ public DynamicDialog(DynamicDialogViewModel dynamicDialogViewModel) dynamicDialogViewModel.HideDialog = this.Hide; this.ViewModel = dynamicDialogViewModel; } + + #region IDisposable + + public void Dispose() + { + ViewModel?.Dispose(); + ViewModel = null; + } + + #endregion } } \ No newline at end of file diff --git a/Files/Dialogs/PropertySaveError.xaml b/Files/Dialogs/PropertySaveError.xaml deleted file mode 100644 index 6c8f34b66178..000000000000 --- a/Files/Dialogs/PropertySaveError.xaml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Files/Dialogs/PropertySaveError.xaml.cs b/Files/Dialogs/PropertySaveError.xaml.cs deleted file mode 100644 index f9727a01e862..000000000000 --- a/Files/Dialogs/PropertySaveError.xaml.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Windows.UI.Xaml.Controls; - -// The Content Dialog item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 - -namespace Files.Dialogs -{ - public sealed partial class PropertySaveError : ContentDialog - { - public string Text { get; set; } - - public PropertySaveError() - { - this.InitializeComponent(); - } - - private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) - { - } - - private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) - { - } - } -} \ No newline at end of file diff --git a/Files/Dialogs/RenameDialog.xaml b/Files/Dialogs/RenameDialog.xaml deleted file mode 100644 index 831f99aa679d..000000000000 --- a/Files/Dialogs/RenameDialog.xaml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/Files/Dialogs/RenameDialog.xaml.cs b/Files/Dialogs/RenameDialog.xaml.cs deleted file mode 100644 index 7460bb8dc877..000000000000 --- a/Files/Dialogs/RenameDialog.xaml.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Files.Filesystem; -using Windows.System; -using Windows.UI.Xaml.Controls; - -// The Content Dialog item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 - -namespace Files.Dialogs -{ - public sealed partial class RenameDialog : ContentDialog - { - public TextBox inputBox; - public string storedRenameInput; - - public RenameDialog() - { - this.InitializeComponent(); - inputBox = RenameInput; - } - - private void NameDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) - { - storedRenameInput = inputBox.Text; - } - - private void RenameInput_TextChanged(object sender, TextChangedEventArgs e) - { - var textBox = sender as TextBox; - - if (FilesystemHelpers.ContainsRestrictedCharacters(textBox.Text)) - { - RenameDialogSymbolsTip.Opacity = 1; - IsPrimaryButtonEnabled = false; - return; - } - else - { - RenameDialogSymbolsTip.Opacity = 0; - IsPrimaryButtonEnabled = true; - } - - if (FilesystemHelpers.ContainsRestrictedFileName(textBox.Text)) - { - IsPrimaryButtonEnabled = false; - } - else - { - IsPrimaryButtonEnabled = true; - } - } - - private void NameDialog_KeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e) - { - if (e.Key.Equals(VirtualKey.Escape)) - { - Hide(); - } - } - } -} \ No newline at end of file diff --git a/Files/Enums/DynamicDialogButtons.cs b/Files/Enums/DynamicDialogButtons.cs new file mode 100644 index 000000000000..462ef76bfcbc --- /dev/null +++ b/Files/Enums/DynamicDialogButtons.cs @@ -0,0 +1,10 @@ +namespace Files.Enums +{ + public enum DynamicDialogButtons + { + Primary = 1, + Secondary = 2, + Cancel = 4, + None = 8 + } +} diff --git a/Files/Enums/DynamicDialogResult.cs b/Files/Enums/DynamicDialogResult.cs new file mode 100644 index 000000000000..a497620466e3 --- /dev/null +++ b/Files/Enums/DynamicDialogResult.cs @@ -0,0 +1,9 @@ +namespace Files.Enums +{ + public enum DynamicDialogResult + { + Primary = 1, + Secondary = 2, + Cancel = 4, + } +} diff --git a/Files/Enums/SortOption.cs b/Files/Enums/SortOption.cs index d8d38e2554ea..2c141d6f4496 100644 --- a/Files/Enums/SortOption.cs +++ b/Files/Enums/SortOption.cs @@ -4,6 +4,7 @@ public enum SortOption : byte { Name, DateModified, + DateCreated, Size, FileType, OriginalPath, diff --git a/Files/Files.csproj b/Files/Files.csproj index 09b37707a5d3..8993f2d3e6e7 100644 --- a/Files/Files.csproj +++ b/Files/Files.csproj @@ -11,7 +11,7 @@ Files en-US Scale|DXFeatureLevel - Language=ar;en-US;de-DE;es-ES;fr-FR;he-IL;hi-IN;hu-HU;it-IT;ja-JP;ko-KR;nl-NL;or-IN;pl-PL;pt-BR;ru-RU;cs-CZ;ta;tr-TR;uk-UA;zh-Hans;zh-Hant;da;da-DK + Language=ar;en-US;de-DE;es-ES;fr-FR;he-IL;hi-IN;hu-HU;it-IT;ja-JP;ko-KR;nl-NL;or-IN;pl-PL;pt-BR;ru-RU;sv-SE;cs-CZ;ta;tr-TR;uk-UA;zh-Hans;zh-Hant;da;da-DK UAP 10.0.19041.0 10.0.17763.0 @@ -175,6 +175,8 @@ DynamicDialog.xaml + + @@ -182,6 +184,7 @@ + @@ -200,6 +203,8 @@ RestartDialog.xaml + + @@ -342,9 +347,6 @@ AddItemDialog.xaml - - ConsentDialog.xaml - ExceptionDialog.xaml @@ -354,9 +356,6 @@ PropertiesDialog.xaml - - RenameDialog.xaml - @@ -364,9 +363,6 @@ - - PropertySaveError.xaml - @@ -675,6 +671,7 @@ Always + @@ -799,10 +796,6 @@ Designer MSBuild:Compile - - Designer - MSBuild:Compile - Designer MSBuild:Compile @@ -815,14 +808,6 @@ Designer MSBuild:Compile - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - Designer MSBuild:Compile @@ -961,13 +946,13 @@ 4.1.0 - 5.0.2 + 5.0.3 5.0.0 - 6.2.11 + 6.2.12 7.0.0-preview4 @@ -1039,6 +1024,7 @@ + diff --git a/Files/Filesystem/Cloud/CloudProviderController.cs b/Files/Filesystem/Cloud/CloudProviderController.cs index 49bfa8caac93..e8ff5114e332 100644 --- a/Files/Filesystem/Cloud/CloudProviderController.cs +++ b/Files/Filesystem/Cloud/CloudProviderController.cs @@ -7,9 +7,7 @@ namespace Files.Filesystem.Cloud { public class CloudProviderController { - private List cloudProviders = new List(); - - public List CloudProviderDetectors => new List + private List CloudProviderDetectors => new List { new GoogleDriveCloudProvider(), new DropBoxCloudProvider(), @@ -17,16 +15,11 @@ public class CloudProviderController new MegaCloudProvider(), new BoxCloudProvider(), new AppleCloudProvider(), - new AmazonDriveProvider() + new AmazonDriveProvider(), + new OneDriveSharePointCloudProvider(), }; - public List CloudProviders - { - get => cloudProviders.Where(x => !string.IsNullOrEmpty(x.SyncFolder)).ToList(); - set => cloudProviders = value; - } - - public async Task DetectInstalledCloudProvidersAsync() + public async Task> DetectInstalledCloudProvidersAsync() { var tasks = new List>>(); var results = new List(); @@ -38,7 +31,7 @@ public async Task DetectInstalledCloudProvidersAsync() await Task.WhenAll(tasks); - cloudProviders = tasks.SelectMany(o => o.Result).ToList(); + return tasks.SelectMany(o => o.Result).Distinct().ToList(); } } } \ No newline at end of file diff --git a/Files/Filesystem/Cloud/Providers/OneDriveCloudProvider.cs b/Files/Filesystem/Cloud/Providers/OneDriveCloudProvider.cs index e35fb65a2bfe..f4fc91971679 100644 --- a/Files/Filesystem/Cloud/Providers/OneDriveCloudProvider.cs +++ b/Files/Filesystem/Cloud/Providers/OneDriveCloudProvider.cs @@ -15,32 +15,32 @@ public async Task> DetectAsync() { try { - using var connection = await AppServiceConnectionHelper.BuildConnection(); - var (status, response) = await connection.SendMessageWithRetryAsync(new ValueSet() + var connection = await AppServiceConnectionHelper.Instance; + if (connection != null) { - { "Arguments", "GetOneDriveAccounts" } - }, TimeSpan.FromSeconds(10)); - if (status == AppServiceResponseStatus.Success) - { - var results = new List(); - foreach (var key in response.Message.Keys - .OrderByDescending(o => string.Equals(o, "OneDrive", StringComparison.OrdinalIgnoreCase)) - .ThenBy(o => o)) + var (status, response) = await connection.SendMessageWithRetryAsync(new ValueSet() + { + { "Arguments", "GetOneDriveAccounts" } + }, TimeSpan.FromSeconds(10)); + if (status == AppServiceResponseStatus.Success) { - results.Add(new CloudProvider() + var results = new List(); + foreach (var key in response.Message.Keys + .OrderByDescending(o => string.Equals(o, "OneDrive", StringComparison.OrdinalIgnoreCase)) + .ThenBy(o => o)) { - ID = CloudProviders.OneDrive, - Name = key, - SyncFolder = (string)response.Message[key] - }); - } + results.Add(new CloudProvider() + { + ID = CloudProviders.OneDrive, + Name = key, + SyncFolder = (string)response.Message[key] + }); + } - return results; - } - else - { - return Array.Empty(); + return results; + } } + return Array.Empty(); } catch { diff --git a/Files/Filesystem/Cloud/Providers/OneDriveSharePointCloudProvider.cs b/Files/Filesystem/Cloud/Providers/OneDriveSharePointCloudProvider.cs new file mode 100644 index 000000000000..ba57b16bac7e --- /dev/null +++ b/Files/Filesystem/Cloud/Providers/OneDriveSharePointCloudProvider.cs @@ -0,0 +1,51 @@ +using Files.Enums; +using Files.Helpers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Windows.ApplicationModel.AppService; +using Windows.Foundation.Collections; + +namespace Files.Filesystem.Cloud.Providers +{ + public class OneDriveSharePointCloudProvider : ICloudProviderDetector + { + public async Task> DetectAsync() + { + try + { + var connection = await AppServiceConnectionHelper.Instance; + if (connection != null) + { + var (status, response) = await connection.SendMessageWithRetryAsync(new ValueSet() + { + { "Arguments", "GetSharePointSyncLocationsFromOneDrive" } + }, TimeSpan.FromSeconds(10)); + if (status == AppServiceResponseStatus.Success) + { + var results = new List(); + foreach (var key in response.Message.Keys + .OrderBy(o => o)) + { + results.Add(new CloudProvider() + { + ID = CloudProviders.OneDrive, + Name = key, + SyncFolder = (string)response.Message[key] + }); + } + + return results; + } + } + return Array.Empty(); + } + catch + { + // Not detected + return Array.Empty(); + } + } + } +} \ No newline at end of file diff --git a/Files/Filesystem/CloudDrivesManager.cs b/Files/Filesystem/CloudDrivesManager.cs index 6ec0e92208c4..67c9b69d3350 100644 --- a/Files/Filesystem/CloudDrivesManager.cs +++ b/Files/Filesystem/CloudDrivesManager.cs @@ -5,8 +5,6 @@ using NLog; using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; using System.Linq; using System.Threading.Tasks; using Windows.ApplicationModel.Core; @@ -16,10 +14,8 @@ namespace Files.Filesystem { public class CloudDrivesManager : ObservableObject { - private static readonly Task _instanceTask = CreateSingleton(); - - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private List drivesList = new List(); + private readonly Logger Logger = LogManager.GetCurrentClassLogger(); + private readonly List drivesList = new List(); public IReadOnlyList Drives { @@ -33,16 +29,18 @@ public IReadOnlyList Drives } //Private as we want to prevent CloudDriveManager being constructed manually - private CloudDrivesManager() - { } + public CloudDrivesManager() + { + } - private async Task EnumerateDrivesAsync() + public async Task EnumerateDrivesAsync() { var cloudProviderController = new CloudProviderController(); - await cloudProviderController.DetectInstalledCloudProvidersAsync(); + var cloudProviders = await cloudProviderController.DetectInstalledCloudProvidersAsync(); - foreach (var provider in cloudProviderController.CloudProviders) + foreach (var provider in cloudProviders) { + Logger.Info($"Adding cloud provider \"{provider.Name}\" mapped to {provider.SyncFolder}"); var cloudProviderItem = new DriveItem() { Text = provider.Name, @@ -51,7 +49,10 @@ private async Task EnumerateDrivesAsync() }; lock (drivesList) { - drivesList.Add(cloudProviderItem); + if (!drivesList.Any(x => x.Path == cloudProviderItem.Path)) + { + drivesList.Add(cloudProviderItem); + } } } @@ -60,22 +61,15 @@ private async Task EnumerateDrivesAsync() return this; } - private static async Task CreateSingleton() - { - var drives = new CloudDrivesManager(); - return await drives.EnumerateDrivesAsync(); - } - - public static Task Instance => _instanceTask; - private async Task RefreshUI() { try { await SyncSideBarItemsUI(); } - catch (Exception) // UI Thread not ready yet, so we defer the pervious operation until it is. + catch (Exception ex) // UI Thread not ready yet, so we defer the previous operation until it is. { + Logger.Error(ex, "UI thread not ready yet"); System.Diagnostics.Debug.WriteLine($"RefreshUI Exception"); // Defer because UI-thread is not ready yet (and DriveItem requires it?) CoreApplication.MainView.Activated += RefreshUI; @@ -84,25 +78,28 @@ private async Task RefreshUI() private async void RefreshUI(CoreApplicationView sender, Windows.ApplicationModel.Activation.IActivatedEventArgs args) { - await SyncSideBarItemsUI(); CoreApplication.MainView.Activated -= RefreshUI; + await SyncSideBarItemsUI(); } private async Task SyncSideBarItemsUI() { - await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => { - lock (MainPage.SideBarItems) + await MainPage.SideBarItemsSemaphore.WaitAsync(); + try { + var drivesSnapshot = Drives.OrderBy(o => o.Text).ToList(); + var drivesSection = MainPage.SideBarItems.FirstOrDefault(x => x is HeaderTextItem && x.Text == "SidebarCloudDrives".GetLocalized()); - if (drivesSection != null && Drives.Count == 0) + if (drivesSection != null && drivesSnapshot.Count == 0) { //No drives - remove the header MainPage.SideBarItems.Remove(drivesSection); } - if (drivesSection == null && Drives.Count > 0) + if (drivesSection == null && drivesSnapshot.Count > 0) { drivesSection = new HeaderTextItem() { @@ -125,8 +122,6 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPrio } } - var sectionStartIndex = MainPage.SideBarItems.IndexOf(drivesSection); - //Remove all existing cloud drives from the sidebar foreach (var item in MainPage.SideBarItems .Where(x => x.ItemType == NavigationControlItemType.CloudDrive) @@ -136,12 +131,17 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPrio } //Add all cloud drives to the sidebar - var insertAt = sectionStartIndex + 1; - foreach (var drive in Drives.OrderBy(o => o.Text)) + var insertAt = MainPage.SideBarItems.IndexOf(drivesSection) + 1; + foreach (var drive in drivesSnapshot) { MainPage.SideBarItems.Insert(insertAt, drive); insertAt++; } + MainPage.SideBarItems.EndBulkOperation(); + } + finally + { + MainPage.SideBarItemsSemaphore.Release(); } }); } diff --git a/Files/Filesystem/Drives.cs b/Files/Filesystem/Drives.cs index 4103ae344082..7f519fa0967f 100644 --- a/Files/Filesystem/Drives.cs +++ b/Files/Filesystem/Drives.cs @@ -21,9 +21,8 @@ namespace Files.Filesystem { public class DrivesManager : ObservableObject { - private static readonly Task _instanceTask = CreateSingleton(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private List drivesList = new List(); + private readonly List drivesList = new List(); public IReadOnlyList Drives { @@ -48,20 +47,12 @@ public bool ShowUserConsentOnInit private bool driveEnumInProgress; //Private as we want to prevent CloudDriveManager being constructed manually - private DrivesManager() + public DrivesManager() { SetupDeviceWatcher(); } - private static async Task CreateSingleton() - { - var drives = new DrivesManager(); - return await drives.EnumerateDrivesAsync(); - } - - public static Task Instance => _instanceTask; - - private async Task EnumerateDrivesAsync() + public async Task EnumerateDrivesAsync() { driveEnumInProgress = true; @@ -128,19 +119,24 @@ private async void RefreshUI(CoreApplicationView sender, Windows.ApplicationMode private async Task SyncSideBarItemsUI() { - await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => { - lock (MainPage.SideBarItems) + await MainPage.SideBarItemsSemaphore.WaitAsync(); + try { + var drivesSnapshot = Drives.ToList(); + var drivesSection = MainPage.SideBarItems.FirstOrDefault(x => x is HeaderTextItem && x.Text == "SidebarDrives".GetLocalized()); - if (drivesSection != null && Drives.Count == 0) + if (drivesSection != null && drivesSnapshot.Count == 0) { //No drives - remove the header MainPage.SideBarItems.Remove(drivesSection); } - if (drivesSection == null && Drives.Count > 0) + drivesSection = MainPage.SideBarItems.FirstOrDefault(x => x is HeaderTextItem && x.Text == "SidebarDrives".GetLocalized()); + + if (drivesSection == null && drivesSnapshot.Count > 0) { drivesSection = new HeaderTextItem() { @@ -150,8 +146,6 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPrio MainPage.SideBarItems.Add(drivesSection); } - var sectionStartIndex = MainPage.SideBarItems.IndexOf(drivesSection); - //Remove all existing drives from the sidebar foreach (var item in MainPage.SideBarItems .Where(x => x.ItemType == NavigationControlItemType.Drive) @@ -162,17 +156,19 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPrio } //Add all drives to the sidebar - var insertAt = sectionStartIndex + 1; - foreach (var drive in Drives) + drivesSection = MainPage.SideBarItems.FirstOrDefault(x => x is HeaderTextItem && x.Text == "SidebarDrives".GetLocalized()); + var insertAt = MainPage.SideBarItems.IndexOf(drivesSection) + 1; + foreach (var drive in drivesSnapshot) { MainPage.SideBarItems.Insert(insertAt, drive); + DrivesWidget.ItemsAdded.Add(drive); insertAt++; - - if (drive.Type != DriveType.VirtualDrive) - { - DrivesWidget.ItemsAdded.Add(drive); - } } + MainPage.SideBarItems.EndBulkOperation(); + } + finally + { + MainPage.SideBarItemsSemaphore.Release(); } }); } @@ -308,8 +304,7 @@ private async Task GetDrivesAsync() private DriveType GetDriveType(DriveInfo drive) { - DriveType type = DriveType.Unknown; - + DriveType type; switch (drive.DriveType) { case System.IO.DriveType.CDRom: diff --git a/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs b/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs index 754f672f22c2..b0701cd9ef14 100644 --- a/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs +++ b/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs @@ -183,6 +183,11 @@ await DialogDisplayHelper.ShowDialogAsync( CloseButtonText = "ItemAlreadyExistsDialogCloseButtonText".GetLocalized() }; + if (Interacts.Interaction.IsAnyContentDialogOpen()) + { + // Only a single ContentDialog can be open at any time. + return null; + } ContentDialogResult result = await ItemAlreadyExistsDialog.ShowAsync(); if (result == ContentDialogResult.Primary) @@ -219,7 +224,7 @@ await DialogDisplayHelper.ShowDialogAsync( } else if (source.ItemType == FilesystemItemType.File) { - var fsResult = (FilesystemResult)NativeFileOperationsHelper.CopyFileFromApp(source.Path, destination, true); + var fsResult = (FilesystemResult) await Task.Run(() => NativeFileOperationsHelper.CopyFileFromApp(source.Path, destination, true)); if (!fsResult) { @@ -244,6 +249,11 @@ await DialogDisplayHelper.ShowDialogAsync( CloseButtonText = "ItemAlreadyExistsDialogCloseButtonText".GetLocalized() }; + if (Interacts.Interaction.IsAnyContentDialogOpen()) + { + // Only a single ContentDialog can be open at any time. + return null; + } ContentDialogResult result = await ItemAlreadyExistsDialog.ShowAsync(); if (result == ContentDialogResult.Primary) @@ -377,7 +387,7 @@ await DialogDisplayHelper.ShowDialogAsync( } else { - var fsResult = (FilesystemResult)NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination); + var fsResult = (FilesystemResult) await Task.Run(() => NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination)); if (!fsResult) { @@ -401,6 +411,11 @@ await DialogDisplayHelper.ShowDialogAsync( CloseButtonText = "ItemAlreadyExistsDialogCloseButtonText".GetLocalized() }; + if (Interacts.Interaction.IsAnyContentDialogOpen()) + { + // Only a single ContentDialog can be open at any time. + return null; + } ContentDialogResult result = await ItemAlreadyExistsDialog.ShowAsync(); if (result == ContentDialogResult.Primary) @@ -434,7 +449,7 @@ await DialogDisplayHelper.ShowDialogAsync( } else if (source.ItemType == FilesystemItemType.File) { - var fsResult = (FilesystemResult)NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination); + var fsResult = (FilesystemResult) await Task.Run(() => NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination)); if (!fsResult) { @@ -459,6 +474,11 @@ await DialogDisplayHelper.ShowDialogAsync( CloseButtonText = "ItemAlreadyExistsDialogCloseButtonText".GetLocalized() }; + if (Interacts.Interaction.IsAnyContentDialogOpen()) + { + // Only a single ContentDialog can be open at any time. + return null; + } ContentDialogResult result = await ItemAlreadyExistsDialog.ShowAsync(); if (result == ContentDialogResult.Primary) @@ -703,6 +723,11 @@ public async Task RenameAsync(IStorageItemWithPath source, CloseButtonText = "ItemAlreadyExistsDialogCloseButtonText".GetLocalized() }; + if (Interacts.Interaction.IsAnyContentDialogOpen()) + { + // Only a single ContentDialog can be open at any time. + return null; + } ContentDialogResult result = await ItemAlreadyExistsDialog.ShowAsync(); if (result == ContentDialogResult.Primary) diff --git a/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs b/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs index d67ab66ee806..7175ccfe6bd0 100644 --- a/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs +++ b/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs @@ -13,11 +13,10 @@ using System.Threading; using System.Threading.Tasks; using Windows.ApplicationModel.DataTransfer; -using Windows.Graphics.Imaging; using Windows.Storage; -using Windows.Storage.Streams; -using static Files.Helpers.NativeFindStorageItemHelper; using FileAttributes = System.IO.FileAttributes; +using Microsoft.Toolkit.Uwp.Extensions; +using static Files.Helpers.NativeFindStorageItemHelper; namespace Files.Filesystem { @@ -68,8 +67,8 @@ public FilesystemHelpers(IShellPage associatedInstance, CancellationToken cancel public async Task CreateAsync(IStorageItemWithPath source, bool registerHistory) { - FileSystemStatusCode returnCode = FileSystemStatusCode.InProgress; - Progress errorCode = new Progress(); + var returnCode = FileSystemStatusCode.InProgress; + var errorCode = new Progress(); errorCode.ProgressChanged += (s, e) => returnCode = e; IStorageHistory history = await filesystemOperations.CreateAsync(source, errorCode, cancellationToken); @@ -106,7 +105,7 @@ public async Task DeleteItemsAsync(IEnumerable returnStatus = e.ToStatus(); var pathsUnderRecycleBin = GetPathsUnderRecycleBin(source); @@ -137,7 +136,7 @@ public async Task DeleteItemsAsync(IEnumerable DeleteItemsAsync(IEnumerable)banner.Progress).Report(progress); } - if (rawStorageHistory.TrueForAll((item) => item != null)) + if (rawStorageHistory.Any() && rawStorageHistory.TrueForAll((item) => item != null)) { history = new StorageHistory( rawStorageHistory[0].OperationType, @@ -214,7 +213,7 @@ public async Task DeleteItemAsync(IStorageItemWithPath source, boo FileOperationType.Recycle); } - ReturnResult returnStatus = ReturnResult.InProgress; + var returnStatus = ReturnResult.InProgress; banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = e.ToStatus(); if (App.AppSettings.ShowConfirmDeleteDialog && showDialog) // Check if the setting to show a confirmation dialog is on @@ -241,7 +240,7 @@ public async Task DeleteItemAsync(IStorageItemWithPath source, boo permanently = dialog.PermanentlyDelete; } - Stopwatch sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); IStorageHistory history = await filesystemOperations.DeleteAsync(source, banner.Progress, banner.ErrorCode, permanently, cancellationToken); @@ -292,7 +291,7 @@ public async Task DeleteItemAsync(IStorageItem source, bool showDi FileOperationType.Recycle); } - ReturnResult returnStatus = ReturnResult.InProgress; + var returnStatus = ReturnResult.InProgress; banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = e.ToStatus(); if (App.AppSettings.ShowConfirmDeleteDialog && showDialog) // Check if the setting to show a confirmation dialog is on @@ -319,7 +318,7 @@ public async Task DeleteItemAsync(IStorageItem source, bool showDi permanently = dialog.PermanentlyDelete; } - Stopwatch sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); IStorageHistory history = await filesystemOperations.DeleteAsync(source, banner.Progress, banner.ErrorCode, permanently, cancellationToken); @@ -342,8 +341,8 @@ public async Task DeleteItemAsync(IStorageItem source, bool showDi public async Task RestoreFromTrashAsync(IStorageItemWithPath source, string destination, bool registerHistory) { - FileSystemStatusCode returnCode = FileSystemStatusCode.InProgress; - Progress errorCode = new Progress(); + var returnCode = FileSystemStatusCode.InProgress; + var errorCode = new Progress(); errorCode.ProgressChanged += (s, e) => returnCode = e; IStorageHistory history = await filesystemOperations.RestoreFromTrashAsync(source, destination, null, errorCode, cancellationToken); @@ -412,10 +411,10 @@ public async Task CopyItemsAsync(IEnumerable ReturnResult.InProgress, FileOperationType.Copy); - ReturnResult returnStatus = ReturnResult.InProgress; + var returnStatus = ReturnResult.InProgress; banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = e.ToStatus(); - Stopwatch sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); IStorageHistory history; @@ -432,11 +431,11 @@ public async Task CopyItemsAsync(IEnumerable banner.ErrorCode, cancellationToken)); - progress = ((float)i / (float)source.Count()) * 100.0f; + progress = i / (float)source.Count() * 100.0f; ((IProgress)banner.Progress).Report(progress); } - if (rawStorageHistory.TrueForAll((item) => item != null)) + if (rawStorageHistory.Any() && rawStorageHistory.TrueForAll((item) => item != null)) { history = new StorageHistory( rawStorageHistory[0].OperationType, @@ -474,10 +473,10 @@ public async Task CopyItemAsync(IStorageItemWithPath source, strin ReturnResult.InProgress, FileOperationType.Copy); - ReturnResult returnStatus = ReturnResult.InProgress; + var returnStatus = ReturnResult.InProgress; banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = e.ToStatus(); - Stopwatch sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); associatedInstance.ContentPage.ClearSelection(); @@ -514,13 +513,18 @@ public async Task CopyItemsFromClipboard(DataPackageView packageVi { source = await packageView.GetStorageItemsAsync(); } - catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A) + catch (Exception ex) when ((uint)ex.HResult == 0x80040064) { return ReturnResult.UnknownException; } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, ex.Message); + return ReturnResult.UnknownException; + } ReturnResult returnStatus = ReturnResult.InProgress; - List destinations = new List(); + var destinations = new List(); foreach (IStorageItem item in source) { destinations.Add(Path.Combine(destination, item.Name)); @@ -579,14 +583,14 @@ public async Task MoveItemsAsync(IEnumerable ReturnResult.InProgress, FileOperationType.Move); - ReturnResult returnStatus = ReturnResult.InProgress; + var returnStatus = ReturnResult.InProgress; banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = e.ToStatus(); - Stopwatch sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); IStorageHistory history; - List rawStorageHistory = new List(); + var rawStorageHistory = new List(); associatedInstance.ContentPage.ClearSelection(); float progress; @@ -599,11 +603,11 @@ public async Task MoveItemsAsync(IEnumerable banner.ErrorCode, cancellationToken)); - progress = ((float)i / (float)source.Count()) * 100.0f; + progress = i / (float)source.Count() * 100.0f; ((IProgress)banner.Progress).Report(progress); } - if (rawStorageHistory.TrueForAll((item) => item != null)) + if (rawStorageHistory.Any() && rawStorageHistory.TrueForAll((item) => item != null)) { history = new StorageHistory( rawStorageHistory[0].OperationType, @@ -641,10 +645,10 @@ public async Task MoveItemAsync(IStorageItemWithPath source, strin ReturnResult.InProgress, FileOperationType.Move); - ReturnResult returnStatus = ReturnResult.InProgress; + var returnStatus = ReturnResult.InProgress; banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = e.ToStatus(); - Stopwatch sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); associatedInstance.ContentPage.ClearSelection(); @@ -690,9 +694,14 @@ public async Task MoveItemsFromClipboard(DataPackageView packageVi { return ReturnResult.UnknownException; } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, ex.Message); + return ReturnResult.UnknownException; + } ReturnResult returnStatus = ReturnResult.InProgress; - List destinations = new List(); + var destinations = new List(); foreach (IStorageItem item in source) { destinations.Add(Path.Combine(destination, item.Name)); @@ -709,8 +718,8 @@ public async Task MoveItemsFromClipboard(DataPackageView packageVi public async Task RenameAsync(IStorageItem source, string newName, NameCollisionOption collision, bool registerHistory) { - FileSystemStatusCode returnCode = FileSystemStatusCode.InProgress; - Progress errorCode = new Progress(); + var returnCode = FileSystemStatusCode.InProgress; + var errorCode = new Progress(); errorCode.ProgressChanged += (s, e) => returnCode = e; IStorageHistory history = await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken); @@ -725,11 +734,47 @@ public async Task RenameAsync(IStorageItem source, string newName, public async Task RenameAsync(IStorageItemWithPath source, string newName, NameCollisionOption collision, bool registerHistory) { - FileSystemStatusCode returnCode = FileSystemStatusCode.InProgress; - Progress errorCode = new Progress(); + var returnCode = FileSystemStatusCode.InProgress; + var errorCode = new Progress(); errorCode.ProgressChanged += (s, e) => returnCode = e; - IStorageHistory history = await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken); + IStorageHistory history = null; + + switch (source.ItemType) + { + case FilesystemItemType.Directory: + history = await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken); + break; + case FilesystemItemType.File: + + if (Path.HasExtension(source.Path) && !Path.HasExtension(newName)) + { + newName += Path.GetExtension(source.Path); + } + + /* Only prompt user when extension has changed, + not when file name has changed + */ + if (Path.GetExtension(source.Path) != Path.GetExtension(newName)) + { + var renameDialogText = "RenameFileDialog/Text".GetLocalized(); + + var yesSelected = await DialogDisplayHelper.ShowDialogAsync("Rename", renameDialogText, "Yes", "No"); + if (yesSelected) + { + history = await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken); + break; + } + + break; + } + + history = await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken); + break; + default: + history = await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken); + break; + } if (registerHistory && !string.IsNullOrWhiteSpace(source.Path)) { diff --git a/Files/Filesystem/LocationItem.cs b/Files/Filesystem/LocationItem.cs index 6744e31f7da7..b519ebd6abce 100644 --- a/Files/Filesystem/LocationItem.cs +++ b/Files/Filesystem/LocationItem.cs @@ -14,7 +14,7 @@ public string Path set { path = value; - HoverDisplayText = Path.Contains("?") ? Text : Path; + HoverDisplayText = Path.Contains("?") || Path.StartsWith("Shell:") || Path == "Home" ? Text : Path; } } diff --git a/Files/Helpers/AppServiceConnectionHelper.cs b/Files/Helpers/AppServiceConnectionHelper.cs index a9d654059c1a..bd4973e8528f 100644 --- a/Files/Helpers/AppServiceConnectionHelper.cs +++ b/Files/Helpers/AppServiceConnectionHelper.cs @@ -10,24 +10,61 @@ namespace Files.Helpers { public static class AppServiceConnectionHelper { - public static async Task BuildConnection() + public static Task Instance = BuildConnection(); + + public static event EventHandler> ConnectionChanged; + + static AppServiceConnectionHelper() + { + App.Current.Suspending += OnSuspending; + App.Current.LeavingBackground += OnLeavingBackground; + } + + private static async void OnLeavingBackground(object sender, LeavingBackgroundEventArgs e) { - var serviceConnection = new AppServiceConnection(); - serviceConnection.AppServiceName = "FilesInteropService"; - serviceConnection.PackageFamilyName = Package.Current.Id.FamilyName; - serviceConnection.ServiceClosed += Connection_ServiceClosed; - AppServiceConnectionStatus status = await serviceConnection.OpenAsync(); - if (status != AppServiceConnectionStatus.Success) + if (await Instance == null) { - // TODO: error handling - serviceConnection?.Dispose(); - return null; + // Need to reinitialize AppService when app is resuming + Instance = BuildConnection(); + ConnectionChanged?.Invoke(null, Instance); } + } - // Launch fulltrust process - await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync(); + private async static void OnSuspending(object sender, SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + (await Instance)?.Dispose(); + Instance = Task.FromResult(null); + ConnectionChanged?.Invoke(null, Instance); + deferral.Complete(); + } - return serviceConnection; + private static async Task BuildConnection() + { + try + { + var serviceConnection = new AppServiceConnection(); + serviceConnection.AppServiceName = "FilesInteropService"; + serviceConnection.PackageFamilyName = Package.Current.Id.FamilyName; + serviceConnection.ServiceClosed += Connection_ServiceClosed; + AppServiceConnectionStatus status = await serviceConnection.OpenAsync(); + if (status != AppServiceConnectionStatus.Success) + { + // TODO: error handling + serviceConnection?.Dispose(); + return null; + } + + // Launch fulltrust process + await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync(); + + return serviceConnection; + } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, "Could not initialize AppServiceConnection!"); + return null; + } } public static async Task<(AppServiceResponseStatus Status, AppServiceResponse Data)> SendMessageWithRetryAsync(this AppServiceConnection serviceConnection, ValueSet valueSet, TimeSpan timeout) diff --git a/Files/Helpers/AppUpdater.cs b/Files/Helpers/AppUpdater.cs index b4fc8b505283..6359817b8ce6 100644 --- a/Files/Helpers/AppUpdater.cs +++ b/Files/Helpers/AppUpdater.cs @@ -15,7 +15,6 @@ internal class AppUpdater public AppUpdater() { - context = StoreContext.GetDefault(); } public async void CheckForUpdatesAsync(bool mandantoryOnly = true) diff --git a/Files/Helpers/BulkConcurrentObservableCollection.cs b/Files/Helpers/BulkConcurrentObservableCollection.cs index 5b6ea63aabb8..077c201333b3 100644 --- a/Files/Helpers/BulkConcurrentObservableCollection.cs +++ b/Files/Helpers/BulkConcurrentObservableCollection.cs @@ -1,13 +1,16 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; +using System.Diagnostics; using System.Linq; -using System.Threading; namespace Files.Helpers { + [DebuggerTypeProxy(typeof(CollectionDebugView<>))] + [DebuggerDisplay("Count = {Count}")] public class BulkConcurrentObservableCollection : INotifyCollectionChanged, INotifyPropertyChanged, ICollection, IList, ICollection, IList { private bool isBulkOperationStarted; @@ -43,7 +46,7 @@ public T this[int index] { var item = collection[index]; collection[index] = value; - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, item)); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, item, index), false); } } @@ -55,12 +58,16 @@ public void BeginBulkOperation() isBulkOperationStarted = true; } - protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e, bool countChanged = true) { if (!isBulkOperationStarted) { CollectionChanged?.Invoke(this, e); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + if (countChanged) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]")); } } @@ -68,6 +75,8 @@ public void EndBulkOperation() { isBulkOperationStarted = false; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]")); } public void Add(T item) @@ -102,15 +111,22 @@ public void CopyTo(T[] array, int arrayIndex) public bool Remove(T item) { - bool result; + int index; lock (syncRoot) { - result = collection.Remove(item); + index = collection.IndexOf(item); + + if (index == -1) + { + return true; + } + + collection.RemoveAt(index); } - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); - return result; + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); + return true; } public IEnumerator GetEnumerator() @@ -135,19 +151,20 @@ public void Insert(int index, T item) collection.Insert(index, item); } - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); } public void RemoveAt(int index) { - var item = collection[index]; + T item; lock (syncRoot) { + item = collection[index]; collection.RemoveAt(index); } - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); } public void AddRange(IEnumerable items) @@ -187,14 +204,15 @@ public void RemoveRange(int index, int count) return; } - var items = collection.Skip(index).Take(count).ToList(); + List items; lock (syncRoot) { + items = collection.Skip(index).Take(count).ToList(); collection.RemoveRange(index, count); } - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, items)); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, items, index)); } public void ReplaceRange(int index, IEnumerable items) @@ -206,16 +224,18 @@ public void ReplaceRange(int index, IEnumerable items) return; } - var oldItems = collection.Skip(index).Take(count).ToList(); - var newItems = items.ToList(); + List oldItems; + List newItems; lock (syncRoot) { + oldItems = collection.Skip(index).Take(count).ToList(); + newItems = items.ToList(); collection.InsertRange(index, newItems); collection.RemoveRange(index + count, count); } - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItems, oldItems)); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItems, oldItems, index)); } int IList.Add(object value) @@ -237,4 +257,4 @@ int IList.Add(object value) void IList.Remove(object value) => Remove((T)value); void ICollection.CopyTo(Array array, int index) => CopyTo((T[])array, index); } -} \ No newline at end of file +} diff --git a/Files/Helpers/CollectionDebugView.cs b/Files/Helpers/CollectionDebugView.cs new file mode 100644 index 000000000000..2c0cca4f8af1 --- /dev/null +++ b/Files/Helpers/CollectionDebugView.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Files.Helpers +{ + internal sealed class CollectionDebugView + { + private readonly ICollection _collection; + + public CollectionDebugView(ICollection collection) + { + _collection = collection ?? throw new ArgumentNullException(nameof(collection)); + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public T[] Items + { + get + { + var items = new T[_collection.Count]; + _collection.CopyTo(items, 0); + return items; + } + } + } +} diff --git a/Files/Helpers/DialogDisplayHelper.cs b/Files/Helpers/DialogDisplayHelper.cs index 071203ec7a97..52f8ddce0da5 100644 --- a/Files/Helpers/DialogDisplayHelper.cs +++ b/Files/Helpers/DialogDisplayHelper.cs @@ -1,4 +1,7 @@ -using System; +using Files.Dialogs; +using Files.Enums; +using Files.ViewModels.Dialogs; +using System; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -34,20 +37,18 @@ public static async Task ShowDialogAsync(string title, string message, str { if (Window.Current.Content is Frame rootFrame) { - var dialog = new ContentDialog + DynamicDialog dialog = new DynamicDialog(new DynamicDialogViewModel() { - Title = title, - Content = message, - PrimaryButtonText = primaryText - }; + TitleText = title, + SubtitleText = message, // We can use subtitle here as our actual message and skip DisplayControl + PrimaryButtonText = primaryText, + SecondaryButtonText = secondaryText, + DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Secondary + }); - if (!string.IsNullOrEmpty(secondaryText)) - { - dialog.SecondaryButtonText = secondaryText; - } - var dialogResult = await dialog.ShowAsync(); + await dialog.ShowAsync(); - result = (dialogResult == ContentDialogResult.Primary); + result = dialog.DynamicResult == DynamicDialogResult.Primary; } } catch (Exception) diff --git a/Files/Helpers/DynamicDialogFactory.cs b/Files/Helpers/DynamicDialogFactory.cs new file mode 100644 index 000000000000..82af60e01773 --- /dev/null +++ b/Files/Helpers/DynamicDialogFactory.cs @@ -0,0 +1,115 @@ +using Files.Dialogs; +using Files.Enums; +using Files.Filesystem; +using Files.ViewModels.Dialogs; +using Microsoft.Toolkit.Uwp.Extensions; +using System; +using Windows.System; +using Windows.UI.Xaml.Controls; + +namespace Files.Helpers +{ + public static class DynamicDialogFactory + { + public static DynamicDialog GetFor_PropertySaveErrorDialog() + { + DynamicDialog dialog = new DynamicDialog(new DynamicDialogViewModel() + { + TitleText = "PropertySaveErrorDialog/Title".GetLocalized(), + SubtitleText = "PropertySaveErrorMessage/Text".GetLocalized(), // We can use subtitle here as our content + PrimaryButtonText = "PropertySaveErrorDialog/PrimaryButtonText".GetLocalized(), + SecondaryButtonText = "PropertySaveErrorDialog/SecondaryButtonText".GetLocalized(), + CloseButtonText= "PropertySaveErrorDialog/CloseButtonText".GetLocalized(), + DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Secondary | DynamicDialogButtons.Cancel + }); + return dialog; + } + + public static DynamicDialog GetFor_ConsentDialog() + { + DynamicDialog dialog = new DynamicDialog(new DynamicDialogViewModel() + { + TitleText = "WelcomeDialog/Title".GetLocalized(), + SubtitleText = "WelcomeDialogTextBlock/Text".GetLocalized(), // We can use subtitle here as our content + PrimaryButtonText = "WelcomeDialog/PrimaryButtonText".GetLocalized(), + PrimaryButtonAction = async (vm, e) => await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-broadfilesystemaccess")), + DynamicButtons = DynamicDialogButtons.Primary + }); + return dialog; + } + + public static DynamicDialog GetFor_RenameDialog() + { + DynamicDialog dialog = null; + TextBox inputText = new TextBox() + { + Height = 35d, + PlaceholderText = "RenameDialogInputText/PlaceholderText".GetLocalized() + }; + + TextBlock tipText = new TextBlock() + { + Text = "RenameDialogSymbolsTip/Text".GetLocalized(), + Margin = new Windows.UI.Xaml.Thickness(0, 0, 4, 0), + TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap, + Opacity = 0.0d + }; + + inputText.TextChanged += (s, e) => + { + var textBox = s as TextBox; + dialog.ViewModel.AdditionalData = textBox.Text; + + if (FilesystemHelpers.ContainsRestrictedCharacters(textBox.Text)) + { + dialog.ViewModel.DynamicButtonsEnabled = DynamicDialogButtons.Cancel; + tipText.Opacity = 1.0d; + return; + } + else if (!string.IsNullOrWhiteSpace(textBox.Text)) + { + dialog.ViewModel.DynamicButtonsEnabled = DynamicDialogButtons.Primary | DynamicDialogButtons.Cancel; + } + else + { + dialog.ViewModel.DynamicButtonsEnabled = DynamicDialogButtons.Cancel; + } + + tipText.Opacity = 0.0d; + }; + + dialog = new DynamicDialog(new DynamicDialogViewModel() + { + TitleText = "RenameDialog/Title".GetLocalized(), + SubtitleText = null, + DisplayControl = new Grid() + { + MinWidth = 300d, + Children = + { + new StackPanel() + { + Orientation = Orientation.Vertical, + Spacing = 4d, + Children = + { + inputText, + tipText + } + } + } + }, + PrimaryButtonAction = (vm, e) => + { + vm.HideDialog(); // Rename successful + }, + PrimaryButtonText = "RenameDialog/PrimaryButtonText".GetLocalized(), + CloseButtonText = "RenameDialog/SecondaryButtonText".GetLocalized(), + DynamicButtonsEnabled = DynamicDialogButtons.Cancel, + DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Cancel + }); + + return dialog; + } + } +} diff --git a/Files/Helpers/FileListCache/FileListCacheController.cs b/Files/Helpers/FileListCache/FileListCacheController.cs index e8fdc29dfad2..93a04422b4eb 100644 --- a/Files/Helpers/FileListCache/FileListCacheController.cs +++ b/Files/Helpers/FileListCache/FileListCacheController.cs @@ -25,6 +25,11 @@ private FileListCacheController() SizeLimit = 1_000_000 }); + private readonly IMemoryCache fileNamesCache = new MemoryCache(new MemoryCacheOptions + { + SizeLimit = 1_000_000 + }); + public Task SaveFileListToCache(string path, CacheEntry cacheEntry) { if (!App.AppSettings.UseFileListCache) @@ -67,5 +72,38 @@ public async Task ReadFileListFromCache(string path, CancellationTok } return entry; } + + public async Task ReadFileDisplayNameFromCache(string path, CancellationToken cancellationToken) + { + var displayName = fileNamesCache.Get(path); + if (displayName == null) + { + displayName = await persistentAdapter.ReadFileDisplayNameFromCache(path, cancellationToken); + if (displayName != null) + { + fileNamesCache.Set(path, displayName, new MemoryCacheEntryOptions + { + Size = 1 + }); + } + } + return displayName; + } + + public Task SaveFileDisplayNameToCache(string path, string displayName) + { + if (displayName == null) + { + filesCache.Remove(path); + return persistentAdapter.SaveFileDisplayNameToCache(path, displayName); + } + filesCache.Set(path, displayName, new MemoryCacheEntryOptions + { + Size = 1 + }); + + // save entry to persistent cache in background + return persistentAdapter.SaveFileDisplayNameToCache(path, displayName); + } } } \ No newline at end of file diff --git a/Files/Helpers/FileListCache/IFileListCache.cs b/Files/Helpers/FileListCache/IFileListCache.cs index e1fcf4555ba6..c51ef2f588e0 100644 --- a/Files/Helpers/FileListCache/IFileListCache.cs +++ b/Files/Helpers/FileListCache/IFileListCache.cs @@ -8,5 +8,9 @@ internal interface IFileListCache public Task ReadFileListFromCache(string path, CancellationToken cancellationToken); public Task SaveFileListToCache(string path, CacheEntry cacheEntry); + + public Task ReadFileDisplayNameFromCache(string path, CancellationToken cancellationToken); + + public Task SaveFileDisplayNameToCache(string path, string displayName); } } \ No newline at end of file diff --git a/Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs b/Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs index f0355b906989..3271908bb868 100644 --- a/Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs +++ b/Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs @@ -18,7 +18,7 @@ internal class PersistentSQLiteCacheAdapter : IFileListCache, IDisposable public async Task SaveFileListToCache(string path, CacheEntry cacheEntry) { - if(!await InitializeIfNeeded()) + if (!await InitializeIfNeeded()) { return; } @@ -47,7 +47,11 @@ public async Task SaveFileListToCache(string path, CacheEntry cacheEntry) using var updateCommand = new SqliteCommand("UPDATE FileListCache SET Timestamp = @Timestamp, Entry = @Entry WHERE Id = @Id", connection); updateCommand.Parameters.Add("@Id", SqliteType.Text).Value = path; updateCommand.Parameters.Add("@Timestamp", SqliteType.Integer).Value = GetTimestamp(DateTime.UtcNow); - updateCommand.Parameters.Add("@Entry", SqliteType.Text).Value = JsonConvert.SerializeObject(cacheEntry); + var settings = new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Auto + }; + updateCommand.Parameters.Add("@Entry", SqliteType.Text).Value = JsonConvert.SerializeObject(cacheEntry, settings); await updateCommand.ExecuteNonQueryAsync(); } else @@ -56,7 +60,11 @@ public async Task SaveFileListToCache(string path, CacheEntry cacheEntry) using var insertCommand = new SqliteCommand("INSERT INTO FileListCache (Id, Timestamp, Entry) VALUES (@Id, @Timestamp, @Entry)", connection); insertCommand.Parameters.Add("@Id", SqliteType.Text).Value = path; insertCommand.Parameters.Add("@Timestamp", SqliteType.Integer).Value = GetTimestamp(DateTime.UtcNow); - insertCommand.Parameters.Add("@Entry", SqliteType.Text).Value = JsonConvert.SerializeObject(cacheEntry); + var settings = new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Auto + }; + insertCommand.Parameters.Add("@Entry", SqliteType.Text).Value = JsonConvert.SerializeObject(cacheEntry, settings); await insertCommand.ExecuteNonQueryAsync(); } } @@ -84,7 +92,11 @@ public async Task ReadFileListFromCache(string path, CancellationTok } var timestamp = reader.GetInt64(0); var entryAsJson = reader.GetString(1); - var entry = JsonConvert.DeserializeObject(entryAsJson); + var settings = new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Auto + }; + var entry = JsonConvert.DeserializeObject(entryAsJson, settings); entry.CurrentFolder.ItemPropertiesInitialized = false; entry.FileList.ForEach((item) => item.ItemPropertiesInitialized = false); return entry; @@ -96,6 +108,73 @@ public async Task ReadFileListFromCache(string path, CancellationTok } } + public async Task SaveFileDisplayNameToCache(string path, string displayName) + { + if (!await InitializeIfNeeded()) + { + return; + } + try + { + if (displayName == null) + { + using var deleteCommand = new SqliteCommand("DELETE FROM FileDisplayNameCache WHERE Id = @Id", connection); + deleteCommand.Parameters.Add("@Id", SqliteType.Text).Value = path; + await deleteCommand.ExecuteNonQueryAsync(); + return; + } + + using var cmd = new SqliteCommand("SELECT Id FROM FileDisplayNameCache WHERE Id = @Id", connection); + cmd.Parameters.Add("@Id", SqliteType.Text).Value = path; + using var reader = await cmd.ExecuteReaderAsync(); + if (reader.HasRows) + { + // need to update entry + using var updateCommand = new SqliteCommand("UPDATE FileDisplayNameCache SET DisplayName = @DisplayName WHERE Id = @Id", connection); + updateCommand.Parameters.Add("@Id", SqliteType.Text).Value = path; + updateCommand.Parameters.Add("@DisplayName", SqliteType.Text).Value = displayName; + await updateCommand.ExecuteNonQueryAsync(); + } + else + { + // need to insert entry + using var insertCommand = new SqliteCommand("INSERT INTO FileDisplayNameCache (Id, DisplayName) VALUES (@Id, @DisplayName)", connection); + insertCommand.Parameters.Add("@Id", SqliteType.Text).Value = path; + insertCommand.Parameters.Add("@DisplayName", SqliteType.Text).Value = displayName; + await insertCommand.ExecuteNonQueryAsync(); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public async Task ReadFileDisplayNameFromCache(string path, CancellationToken cancellationToken) + { + if (!await InitializeIfNeeded()) + { + return null; + } + try + { + using var cmd = new SqliteCommand("SELECT DisplayName FROM FileDisplayNameCache WHERE Id = @Id", connection); + cmd.Parameters.Add("@Id", SqliteType.Text).Value = path; + + using var reader = await cmd.ExecuteReaderAsync(cancellationToken); + if (!await reader.ReadAsync()) + { + return null; + } + return reader.GetString(0); + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + return null; + } + } + private long GetTimestamp(DateTime dateTime) { return new DateTimeOffset(dateTime).ToUnixTimeSeconds(); @@ -139,8 +218,7 @@ private async Task InitializeIfNeeded() string dbPath = null; try { - bool schemaCreated = await ApplicationData.Current.LocalFolder.FileExistsAsync("cache.db"); - await ApplicationData.Current.LocalFolder.CreateFileAsync("cache.db"); + await ApplicationData.Current.LocalFolder.CreateFileAsync("cache.db", CreationCollisionOption.OpenIfExists); dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, "cache.db"); @@ -149,22 +227,28 @@ private async Task InitializeIfNeeded() connection = new SqliteConnection($"Data Source='{dbPath}'"); connection.Open(); - if (!schemaCreated) - { - // create db schema - var createSql = @"CREATE TABLE ""FileListCache"" ( + // create db schema + var createFileListCacheTable = @"CREATE TABLE IF NOT EXISTS ""FileListCache"" ( ""Id"" VARCHAR(5000) NOT NULL, ""Timestamp"" INTEGER NOT NULL, ""Entry"" TEXT NOT NULL, PRIMARY KEY(""Id"") )"; - using var cmd = new SqliteCommand(createSql, connection); - var result = cmd.ExecuteNonQuery(); - } + using var cmdFileListCacheTable = new SqliteCommand(createFileListCacheTable, connection); + cmdFileListCacheTable.ExecuteNonQuery(); + + var createFileDisplayNameCacheTable = @"CREATE TABLE IF NOT EXISTS ""FileDisplayNameCache"" ( + ""Id"" VARCHAR(5000) NOT NULL, + ""DisplayName"" TEXT NOT NULL, + PRIMARY KEY(""Id"") + )"; + using var cmdFileDisplayNameCacheTable = new SqliteCommand(createFileDisplayNameCacheTable, connection); + cmdFileDisplayNameCacheTable.ExecuteNonQuery(); RunCleanupRoutine(); return true; - } catch (Exception ex) + } + catch (Exception ex) { NLog.LogManager.GetCurrentClassLogger().Error(ex, $"Failed initializing database with path: {dbPath}"); return false; diff --git a/Files/Helpers/JumpListManager.cs b/Files/Helpers/JumpListManager.cs index cd3a39ea86d6..6ca5e5a91585 100644 --- a/Files/Helpers/JumpListManager.cs +++ b/Files/Helpers/JumpListManager.cs @@ -21,13 +21,21 @@ public JumpListManager() private async void Initialize() { - if (JumpList.IsSupported()) + try { - instance = await JumpList.LoadCurrentAsync(); + if (JumpList.IsSupported()) + { + instance = await JumpList.LoadCurrentAsync(); - // Disable automatic jumplist. It doesn't work with Files UWP. - instance.SystemGroupKind = JumpListSystemGroupKind.None; - JumpListItemPaths = instance.Items.Select(item => item.Arguments).ToList(); + // Disable automatic jumplist. It doesn't work with Files UWP. + instance.SystemGroupKind = JumpListSystemGroupKind.None; + JumpListItemPaths = instance.Items.Select(item => item.Arguments).ToList(); + } + } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, ex.Message); + instance = null; } } diff --git a/Files/Helpers/PathNormalization.cs b/Files/Helpers/PathNormalization.cs index 9fb2f4815bf5..f83dda246268 100644 --- a/Files/Helpers/PathNormalization.cs +++ b/Files/Helpers/PathNormalization.cs @@ -32,7 +32,7 @@ public static string NormalizePath(string path) catch (UriFormatException ex) { LogManager.GetCurrentClassLogger().Error(ex, path); - throw; + return path; } } } diff --git a/Files/Helpers/ThemeHelper.cs b/Files/Helpers/ThemeHelper.cs index a67ee540153d..b80b865e2b32 100644 --- a/Files/Helpers/ThemeHelper.cs +++ b/Files/Helpers/ThemeHelper.cs @@ -18,26 +18,6 @@ public static class ThemeHelper // Keep reference so it does not get optimized/garbage collected public static UISettings UiSettings; - /// - /// Gets the current actual theme of the app based on the requested theme of the - /// root element, or if that value is Default, the requested theme of the Application. - /// - public static ElementTheme ActualTheme - { - get - { - if (Window.Current.Content is FrameworkElement rootElement) - { - if (rootElement.RequestedTheme != ElementTheme.Default) - { - return rootElement.RequestedTheme; - } - } - - return Interacts.Interaction.GetEnum(Application.Current.RequestedTheme.ToString()); - } - } - /// /// Gets or sets (with LocalSettings persistence) the RequestedTheme of the root element. /// @@ -45,46 +25,34 @@ public static ElementTheme RootTheme { get { - if (Window.Current.Content is FrameworkElement rootElement) + var savedTheme = ApplicationData.Current.LocalSettings.Values[selectedAppThemeKey]?.ToString(); + + if (!string.IsNullOrEmpty(savedTheme)) { - return rootElement.RequestedTheme; + return Interacts.Interaction.GetEnum(savedTheme); + } + else + { + return ElementTheme.Default; } - - return ElementTheme.Default; } set { - if (Window.Current.Content is FrameworkElement rootElement) - { - rootElement.RequestedTheme = value; - } - ApplicationData.Current.LocalSettings.Values[selectedAppThemeKey] = value.ToString(); - UpdateTheme(); + ApplyTheme(); } } public static void Initialize() { - App.AppSettings.AcrylicTheme = new AcrylicTheme(); + // Save reference as this might be null when the user is in another app + currentApplicationWindow = Window.Current; // Set TitleBar background color titleBar = ApplicationView.GetForCurrentView().TitleBar; - titleBar.ButtonBackgroundColor = Colors.Transparent; - titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; - // Save reference as this might be null when the user is in another app - currentApplicationWindow = Window.Current; - string savedTheme = ApplicationData.Current.LocalSettings.Values[selectedAppThemeKey]?.ToString(); - - if (!string.IsNullOrEmpty(savedTheme)) - { - RootTheme = Interacts.Interaction.GetEnum(savedTheme); - } - else - { - RootTheme = ElementTheme.Default; - } + //Apply the desired theme based on what is set in the application settings + ApplyTheme(); // Registering to color changes, thus we notice when user changes theme system wide UiSettings = new UISettings(); @@ -99,14 +67,24 @@ private static async void UiSettings_ColorValuesChanged(UISettings sender, objec // Dispatch on UI thread so that we have a current appbar to access and change await currentApplicationWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () => { - UpdateTheme(); + ApplyTheme(); }); } } - public static void UpdateTheme() + private static void ApplyTheme() { - switch (RootTheme) + var rootTheme = RootTheme; + + if (Window.Current.Content is FrameworkElement rootElement) + { + rootElement.RequestedTheme = rootTheme; + } + + titleBar.ButtonBackgroundColor = Colors.Transparent; + titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; + + switch (rootTheme) { case ElementTheme.Default: App.AppSettings.AcrylicTheme.SetDefaultTheme(); diff --git a/Files/Interacts/Interaction.cs b/Files/Interacts/Interaction.cs index afe5a5f71f8f..b9e99a3f98ef 100644 --- a/Files/Interacts/Interaction.cs +++ b/Files/Interacts/Interaction.cs @@ -394,6 +394,10 @@ public void OpenItemWithApplicationPicker_Click(object sender, RoutedEventArgs e public async void OpenFileLocation_Click(object sender, RoutedEventArgs e) { var item = AssociatedInstance.ContentPage.SelectedItem as ShortcutItem; + if (string.IsNullOrEmpty(item?.TargetPath)) + { + return; + } var folderPath = Path.GetDirectoryName(item.TargetPath); // Check if destination path exists var destFolder = await AssociatedInstance.FilesystemViewModel.GetFolderWithPathFromPathAsync(folderPath); @@ -412,7 +416,7 @@ public async void OpenFileLocation_Click(object sender, RoutedEventArgs e) else { await DialogDisplayHelper.ShowDialogAsync("InvalidItemDialogTitle".GetLocalized(), - string.Format("InvalidItemDialogContent".GetLocalized()), Environment.NewLine, destFolder.ErrorCode.ToString()); + string.Format("InvalidItemDialogContent".GetLocalized(), Environment.NewLine, destFolder.ErrorCode.ToString())); } } @@ -429,7 +433,6 @@ public async Task OpenPath(string path, FilesystemItemType? itemType = nul string previousDir = AssociatedInstance.FilesystemViewModel.WorkingDirectory; bool isHiddenItem = NativeFileOperationsHelper.HasFileAttribute(path, System.IO.FileAttributes.Hidden); bool isShortcutItem = path.EndsWith(".lnk") || path.EndsWith(".url"); // Determine - bool fileExists = await StorageItemHelpers.Exists(path, AssociatedInstance); FilesystemResult opened = (FilesystemResult)false; // Shortcut item variables @@ -439,11 +442,6 @@ public async Task OpenPath(string path, FilesystemItemType? itemType = nul bool shortcutRunAsAdmin = false; bool shortcutIsFolder = false; - if (!fileExists && !isShortcutItem && !isHiddenItem) - { - return false; - } - if (itemType == null || isShortcutItem || isHiddenItem) { if (isShortcutItem) @@ -618,6 +616,12 @@ public async Task OpenPath(string path, FilesystemItemType? itemType = nul queryOptions.SortOrder.Add(sortEntry); break; + case Enums.SortOption.DateCreated: + sortEntry.PropertyName = "System.DateCreated"; + queryOptions.SortOrder.Clear(); + queryOptions.SortOrder.Add(sortEntry); + break; + //Unfortunately this is unsupported | Remarks: https://docs.microsoft.com/en-us/uwp/api/windows.storage.search.queryoptions.sortorder?view=winrt-19041 //case Enums.SortOption.Size: @@ -667,7 +671,7 @@ public async Task OpenPath(string path, FilesystemItemType? itemType = nul await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var ContentOwnedViewModelInstance = AssociatedInstance.FilesystemViewModel; - ContentOwnedViewModelInstance.RefreshItems(previousDir); + ContentOwnedViewModelInstance?.RefreshItems(previousDir); }); } @@ -684,7 +688,9 @@ private async void OpenSelectedItems(bool openViaApplicationPicker = false) foreach (ListedItem item in AssociatedInstance.ContentPage.SelectedItems) { - await OpenPath(item.ItemPath, null, false, openViaApplicationPicker); + var type = item.PrimaryItemAttribute == StorageItemTypes.Folder ? + FilesystemItemType.Directory : FilesystemItemType.File; + await OpenPath(item.ItemPath, type, false, openViaApplicationPicker); } } @@ -726,13 +732,17 @@ private async void ShowProperties() else { await OpenPropertiesWindowAsync(App.DrivesManager.Drives - .Single(x => x.Path.Equals(AssociatedInstance.FilesystemViewModel.CurrentFolder.ItemPath))); + .SingleOrDefault(x => x.Path.Equals(AssociatedInstance.FilesystemViewModel.CurrentFolder.ItemPath))); } } } public async Task OpenPropertiesWindowAsync(object item) { + if (item == null) + { + return; + } if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) { CoreApplicationView newWindow = CoreApplication.CreateNewView(); @@ -944,10 +954,13 @@ public async void RestoreItem_Click(object sender, RoutedEventArgs e) { foreach (ListedItem listedItem in AssociatedInstance.ContentPage.SelectedItems) { - FilesystemItemType itemType = (listedItem as RecycleBinItem).PrimaryItemAttribute == StorageItemTypes.Folder ? FilesystemItemType.Directory : FilesystemItemType.File; - await FilesystemHelpers.RestoreFromTrashAsync(StorageItemHelpers.FromPathAndType( - (listedItem as RecycleBinItem).ItemPath, - itemType), (listedItem as RecycleBinItem).ItemOriginalPath, true); + if (listedItem is RecycleBinItem binItem) + { + FilesystemItemType itemType = binItem.PrimaryItemAttribute == StorageItemTypes.Folder ? FilesystemItemType.Directory : FilesystemItemType.File; + await FilesystemHelpers.RestoreFromTrashAsync(StorageItemHelpers.FromPathAndType( + (listedItem as RecycleBinItem).ItemPath, + itemType), (listedItem as RecycleBinItem).ItemOriginalPath, true); + } } } } @@ -1196,15 +1209,16 @@ public async void CreateFileFromDialogResultType(AddItemType itemType, ShellNewE } // Show rename dialog - RenameDialog renameDialog = new RenameDialog(); - var renameResult = await renameDialog.ShowAsync(); - if (renameResult != ContentDialogResult.Primary) + DynamicDialog dialog = DynamicDialogFactory.GetFor_RenameDialog(); + await dialog.ShowAsync(); + + if (dialog.DynamicResult != DynamicDialogResult.Primary) { return; } // Create file based on dialog result - string userInput = renameDialog.storedRenameInput; + string userInput = dialog.ViewModel.AdditionalData as string; var folderRes = await AssociatedInstance.FilesystemViewModel.GetFolderWithPathFromPathAsync(currentPath); FilesystemResult created = folderRes; if (folderRes) @@ -1289,7 +1303,7 @@ public async void ToggleQuickLook() await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var ContentOwnedViewModelInstance = AssociatedInstance.FilesystemViewModel; - ContentOwnedViewModelInstance.RefreshItems(null); + ContentOwnedViewModelInstance?.RefreshItems(null); }); } } diff --git a/Files/MultilingualResources/Files.ar.xlf b/Files/MultilingualResources/Files.ar.xlf index 4b3e4a943e82..45ab95990128 100644 --- a/Files/MultilingualResources/Files.ar.xlf +++ b/Files/MultilingualResources/Files.ar.xlf @@ -2271,8 +2271,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.cs-CZ.xlf b/Files/MultilingualResources/Files.cs-CZ.xlf index 10f65d40cac9..1a5073859e87 100644 --- a/Files/MultilingualResources/Files.cs-CZ.xlf +++ b/Files/MultilingualResources/Files.cs-CZ.xlf @@ -2291,8 +2291,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.da-DK.xlf b/Files/MultilingualResources/Files.da-DK.xlf index ef0962c6c83e..93bb76b302ad 100644 --- a/Files/MultilingualResources/Files.da-DK.xlf +++ b/Files/MultilingualResources/Files.da-DK.xlf @@ -2271,8 +2271,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.da.xlf b/Files/MultilingualResources/Files.da.xlf index 24350ebbd05e..df27593537bf 100644 --- a/Files/MultilingualResources/Files.da.xlf +++ b/Files/MultilingualResources/Files.da.xlf @@ -2271,8 +2271,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.de-DE.xlf b/Files/MultilingualResources/Files.de-DE.xlf index 1f101020b4b3..7108a1fbfe9a 100644 --- a/Files/MultilingualResources/Files.de-DE.xlf +++ b/Files/MultilingualResources/Files.de-DE.xlf @@ -1837,7 +1837,7 @@ List and sort directories alongside files - List and sort directories alongside files + Dateien zusammen mit Ordnern sortieren und nicht voneinander trennen Details @@ -1953,7 +1953,7 @@ Show copy location menu item - Show copy location menu item + 'Speicherort kopieren' Menüeintrag anzeigen Move overflow items into a sub menu @@ -2153,7 +2153,7 @@ Drag and drop any file or folder here to quickly access it - Füge Dateien und Ordner hier durch Ziehen und Ablegen hinzu um schnell Zugriff auf sie zu haben + Füge Dateien und Ordner durch Ziehen und Ablegen hinzu Confirm @@ -2169,7 +2169,7 @@ Rename Bundle - Gruppe umbennen + Gruppe umbenennen More options... @@ -2273,7 +2273,60 @@ Enable multiselect options (currently only available in the tiles and grid view layout modes) - Mehrfachauswahl aktivieren (derzeitig nur für Kachel- und Gridansicht) + Mehrfachauswahl aktivieren (derzeitig nur für Kachel- und Gridansicht) + Please verify the translation’s accuracy as the source string was updated after it was translated. + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.es-ES.xlf b/Files/MultilingualResources/Files.es-ES.xlf index 96f78c06f4d9..51aaea498ed8 100644 --- a/Files/MultilingualResources/Files.es-ES.xlf +++ b/Files/MultilingualResources/Files.es-ES.xlf @@ -2268,11 +2268,63 @@ Multiselect - Multiselect + Multiselección - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Habilitar opción de selección múltiple (No disponible en el modo de vista "Detalles") + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + Si cambia la extensión de un archivo, el archivo puede quedar inutilizable. ¿Estás seguro de que quieres cambiarlo? + + + CD ROM Drive + CD ROM + + + Cloud Drive + Unidad en la nube + + + Fixed Disk Drive + Disco local + + + Floppy Disk Drive + Disquete + + + Network Drive + Unidad de red + + + Unmounted Drive + Unidad desmontada + + + RAM Disk Drive + Unidad de RAM (RAMDisk) + + + Removable Storage Device + Unidad extraíble + + + Unknown + Desconocido + + + Virtual Drive + Unidad virtual + + + Date created + Fecha de creación + + + Date created + Fecha de creación diff --git a/Files/MultilingualResources/Files.fr-FR.xlf b/Files/MultilingualResources/Files.fr-FR.xlf index 275ecaf2b35c..0add8f91c3ea 100644 --- a/Files/MultilingualResources/Files.fr-FR.xlf +++ b/Files/MultilingualResources/Files.fr-FR.xlf @@ -2274,10 +2274,63 @@ Sélection Multiple - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Active l'option de sélection multiple (uniquement disponible sur la vue en tuiles ou en grilles pour le moment) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Active l'option de sélection multiple (uniquement disponible sur la vue en tuiles ou en grilles pour le moment) + Please verify the translation’s accuracy as the source string was updated after it was translated. + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created - + \ No newline at end of file diff --git a/Files/MultilingualResources/Files.he-IL.xlf b/Files/MultilingualResources/Files.he-IL.xlf index c6a12ee833c9..172684406eda 100644 --- a/Files/MultilingualResources/Files.he-IL.xlf +++ b/Files/MultilingualResources/Files.he-IL.xlf @@ -2273,8 +2273,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.hi-IN.xlf b/Files/MultilingualResources/Files.hi-IN.xlf index 9afbef1abc5a..1e4b7ff8b785 100644 --- a/Files/MultilingualResources/Files.hi-IN.xlf +++ b/Files/MultilingualResources/Files.hi-IN.xlf @@ -2284,8 +2284,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.hu-HU.xlf b/Files/MultilingualResources/Files.hu-HU.xlf index 2f2cd58f5419..8d4991f5a0cc 100644 --- a/Files/MultilingualResources/Files.hu-HU.xlf +++ b/Files/MultilingualResources/Files.hu-HU.xlf @@ -20,7 +20,7 @@ Permanently delete - Ideiglenes törlés + Végleges törlés Open in new tab @@ -32,11 +32,11 @@ New Tab - Új Lap + Új lap New Window - Új Ablak + Új ablak Folder @@ -44,15 +44,15 @@ Bitmap Image - Bitmap Kép + Bitmap kép Text Document - Szöveges Dokumentum + Szöveges dokumentum Copy location - Útvonal másolása + Elérési út másolása Paste @@ -88,7 +88,7 @@ Item Name - Fájlnév + Név Path: @@ -100,19 +100,19 @@ This action cannot be done - Az az a művelet nem elvégezhető + Ez a művelet nem hajtható végre The destination folder - Az érkezési mappa + A célmappa is a subfolder of the source folder - almappája az eredeti mappának + almappája a forrásmappának Skip - Tovább + Kihagyás Cancel @@ -120,11 +120,11 @@ Item type: - Elem típusa: + Típus: Select All - Mind kijelölése + Összes kijelölése Invert Selection @@ -140,11 +140,11 @@ Modified: - Módosítás dátuma: + Módosítva: Accessed: - Megnyitva: + Hozzáférés: Owner: @@ -164,7 +164,7 @@ Files you've previously accessed will show up here - Előzőleg megtekintett fájlok helye + Itt fognak megjelenni a korábban megnyitott fájlok Open file location @@ -176,7 +176,7 @@ Recent items - Legutóbb megnyitott + Előzmények Files @@ -192,11 +192,11 @@ Third Party Licenses - Harmadik személytől származó licenc-ek + Harmadik fél licencei About - Rólunk + Névjegy Acrylic sidebar @@ -204,7 +204,7 @@ Date format - Dátum formátuma + Dátumformátum App theme @@ -216,15 +216,15 @@ Show extensions for known file types - Kiterjesztés mutatása ismert fájlformátumoknál + Kiterjesztés megjelenítése ismert fájltípusoknál Files and Folders - Fájlok és Mappák + Fájlok és mappák Experimental - Kísérleti + Kísérleti beállítások Settings @@ -232,7 +232,7 @@ About - Rólunk + Névjegy Appearance @@ -240,11 +240,11 @@ Experimental - Kísérleti + Kísérleti beállítások Files and Folders - Fájlok és Mappák + Fájlok és mappák On Startup @@ -252,7 +252,7 @@ Preferences - Preferencia + Működés WARNING: EXPERIMENTAL FEATURES AHEAD! @@ -260,7 +260,7 @@ Continue where you left off - Folytassa ahol abbahagyta + Folytassa ott, ahol bezárta a programot Open a new tab @@ -268,7 +268,7 @@ Open a specific page or pages - Megadott oldal(ak) megnyitása + Megadott mappák megnyitása On Startup @@ -280,7 +280,7 @@ Preferences - Preferencia + Működés Desktop @@ -296,7 +296,7 @@ Home - Home + Kezdőoldal Music @@ -308,7 +308,7 @@ Unpin from sidebar - Levétel az oldalsávról + Eltávolítás az oldalsávról Videos @@ -356,7 +356,7 @@ MD5Hash: - MD5Hash: + MD5 hash: New @@ -428,11 +428,11 @@ Grant Permission - Engedély Biztosítása + Engedély megadása To get started, you'll need to grant us permission to display your files. This will open a Settings page where you can grant us this permission. You'll need to reopen the app once you've completed this step. - Kezdésként, engedély kell adnia a fájljai megjelenítéséhez. Ez meg fogja nyitni a Beállításokat ahol engedélyezheti. Amint befelyezte a lépést zárja be és nyissa meg újra a Files-t. + Kezdésként, engedélyt kell adnia a fájljai megjelenítéséhez. Ez meg fogja nyitni a Gépházat ahol ezt elvégezheti. Az engedély megadása és a Gépház bezárása után nyissa meg újra a Files-t. File folder @@ -444,15 +444,15 @@ Enter an item name - Írja be a fájl új nevét + Adja meg az elem új nevét Enter an item name - Írja be az új fájl nevét + Adja meg az elem új nevét Set Name - Név beállítása + Átnevezés Cancel @@ -484,11 +484,11 @@ New Folder - Új Mappa + Új mappa This folder is empty. - Üres mappa. + Ez a mappa üres. Back (Alt + Left Arrow) @@ -512,11 +512,11 @@ More options - Több lehetpség + További lehetőségek Properties - Tulajdonság + Tulajdonságok Attributes: @@ -532,23 +532,23 @@ An item with this name already exists in this directory. - Fájl ezzel a névvel már létezik ebben a mappában. + Ezzel a névvel már létezik elem ebben a mappában. Generate new name - Új név készítése + Átnevezés Replace existing item - Fájl lecserélése + Felülírás/összefésülés Item already exists - A fájl már létezik + Az elem már létezik Set as lockscreen background - Beállítás zárolt háttérképként + Beállítás zárolási képernyő háttérként Grid View (Large) @@ -572,15 +572,15 @@ We weren't able to delete this item - Nem tudtuk törölni a fájlt + Nem sikerült törölni ezt az elemet Access Denied - Hozzáférés Megtagadva + Hozzáférés megtagadva Please insert the necessary drive to access this item. - Helyezze be a meghajtót a fájlhoz való hozzáfáráshez. + Helyezze be a meghajtót a fájlhoz való hozzáféréshez. Drive Unplugged @@ -588,27 +588,27 @@ The file you are attempting to access may have been moved or deleted. - Az elérni próbált fájl törölt, vagy át lett helyezve. + A fájl, amit próbál megnyitni, már nem található ezen a helyen. File Not Found - A Fájl nem található + A fájl nem található The file you are attempting to preview may have been moved or deleted. - A fájl amit próbál megnézni, törölt, vagy át lett helyezve. + A fájl, amelynek az előnézetét próbálja betölteni, már nem található ezen a helyen. The folder you are attempting to access may have been moved or deleted. - A fájl amit próbál elérni, törölt, vagy át lett helyezve. + A mappa, amit próbál megnyitni, már nem található ezen a helyen. Did you delete this folder? - Ön törölte a mappát? + Ön törölte ezt a mappát? The file you're trying to delete is currently being used by an another application. - A fájl amelyet törölné jelenleg használatban van. + A törölni kívánt fájl jelenleg használatban van. File is in use @@ -616,7 +616,7 @@ Try again - Próbálja újra + Újra OK @@ -668,11 +668,11 @@ The requested operation is not supported - A kért művelet nem támogatott + Ez a művelet nem támogatott {0} free of {1} - {0} szabad a(z) {1}-ból/ből + Szabad hely: {0} / {1} Open With @@ -680,7 +680,7 @@ The item name must not contain the following characters: \ / : * ? " < > | - A fájlnév nem tartalmazhatja a következő karaktereket: \ / : * ? " < > | + A név nem tartalmazhatja a következő karaktereket: \ / : * ? " < > | OK @@ -688,7 +688,7 @@ The item name must not contain the following characters: \ / : * ? " < > | - A fájlnév nem tartalmazhatja a következő karaktereket: \ / : * ? " < > | + A név nem tartalmazhatja a következő karaktereket: \ / : * ? " < > | Open log location @@ -708,11 +708,11 @@ item - Elem + elem items - Elem + elem Deleting files @@ -732,7 +732,7 @@ Yes - OK + Igen Cancel @@ -740,7 +740,7 @@ Are you sure you want to permanently delete all these items? - Biztosan törölne minden elemet? + Biztosan véglegesen törölni szeretné ezeket az elemeket? Empty recycle bin @@ -748,7 +748,7 @@ bytes - bit + bájt KB @@ -780,7 +780,7 @@ Learn more about date formats - Tudjon meg többet a dátumok formátumáról + Tudjon meg többet a dátumformátumokról Unlock @@ -792,7 +792,7 @@ Enter password to unlock the drive - Írja be a jelszót a meghajtó feloldásához + Adja meg a jelszót a meghajtó feloldásához Password @@ -800,7 +800,7 @@ Please check the password and try again. - Ellenőrizze a jalszavat és próbálja újra. + Ellenőrizze a jelszót és próbálja újra. BitLocker error @@ -812,7 +812,7 @@ {0:#,##0} Files, {1:#,##0} Folders - {0:#,##0} Fájl, {1:#,##0} Mappa + {0:#,##0} fájl, {1:#,##0} mappa Run as another user @@ -820,7 +820,7 @@ All type of {0} - Minden típus {0}-ból/ból + {0} (mindegyik) Different types @@ -828,7 +828,7 @@ All in {0} - Minden {0}-ból/ből + {0} (mindegyik) Used space: @@ -848,11 +848,11 @@ Recent - Legutóbbi + Előzmények App Language - Program Nyelve + Alkalmazás nyelve Move tab here @@ -872,15 +872,15 @@ Always open a new instance - Mindig új ablakban nyíljon meg + Új ablakban Open folder in a new tab - Mappa megnyitása új lapon + Új lapon When launching an item from the jumplist - Elem megnyitásakor a listáról + Elem előzménylistáról megnyitása Windows default @@ -896,7 +896,7 @@ Move to {0} - Áthelyezés ide {0} + Áthelyezés ide: {0} The source and destination file names are the same. @@ -908,15 +908,15 @@ Copy to {0} - Másolás ide {0} + Másolás ide: {0} Create shortcut - Gyorsgomb létrehozása + Parancsikon létrehozása Open file location - Fájl tartalmazó mappa megnyitása + Fájlt tartalmazó mappa megnyitása Arguments: @@ -948,7 +948,7 @@ Web link - Web link + Internet parancsikon General @@ -956,19 +956,19 @@ Shortcut - Gyorsgomb + Parancsikon Shortcut - Gyorsgomb + Parancsikon Internet shortcut - Internet gyorsgomb + Internet parancsikon {0} - shortcut - {0} - gyorsgomb + {0} - parancsikon Open file location @@ -984,11 +984,11 @@ Files ran into a problem that the developers didn't prepare for yet. - Files egy problémába ütközött, amire a fejlesztők még nem készültek fel. + A Files egy problémába ütközött, amire a fejlesztők még nem készültek fel. Something went wrong! - Valami elromlott! + Valami hiba történt! Report this issue @@ -1004,7 +1004,7 @@ Release Notes - Verzió Jegyzet + Változások Find out what's new in Files @@ -1012,11 +1012,11 @@ The item referenced is either invalid or inaccessible.{0}Error message:{0}{1} - A hivatkozott elem helytelen vagy elérhetetlen.{0}Hibaüzenet:{0}{1} + A hivatkozott elem érvénytelen vagy nem elérhető.{0}Hibaüzenet:{0}{1} Invalid item - Helytelen fájl + Érvénytelen elem Version: @@ -1028,11 +1028,11 @@ The items you've selected will be shared - A kijelölt fájlok meg lesznek osztva + A kijelölt elemek meg lesznek osztva The selected item will be shared - A kijelölt fájl meg lesz osztva + A kijelölt elem meg lesz osztva Sharing {0} @@ -1044,31 +1044,31 @@ The item you're attempting to rename no longer exists. Please verify the correct location of the item you need to rename. - A fájl amit szeretne megnyitni már nem létezik. Ellenőrizze az átnevezendő fájl helyét. + Az elem, amit át szeretne nevezni már nem létezik. Item no longer exists - A fájl már nem létezik + Az elem már nem létezik The name specified was invalid. Please check the desired item name and try again. - A megadott fájlnév helytelen. Ellenőrizze és próbálja újra. + A megadott név helytelen. Ellenőrizze és próbálja újra! Invalid item name - Helytelen fájl név + Helytelen név The length of the item name specified exceeds the maximum limit. Please check the desired name and try again. - A fájlnév hossza elérte a maximumot. Ellenőrizze a nevet, és próbálja újra. + A név hosszabb, mint ami maximálisan megengedett. Kérjük válasszon rövidebb nevet! Item name was too long - Túl hosszú fájlnév + Túl hosszú név More - Több + Továbbiak No @@ -1080,7 +1080,7 @@ The application needs to be restarted in order to apply the language setting, would you like to restart the app? - A Files újraindítása szükséges a nyelv beállításához, szeretné újraindítani? + A Files újraindítása szükséges a nyelv beállítás érvénybe lépéséhez. Szeretné most újraindítani? Support us @@ -1092,11 +1092,11 @@ We weren't able to create this item - Nem tudtuk létrehozni a fájlt + Nem sikerült létrehozni a fájlt Access Denied - Hozzáférés Megtagadva + Hozzáférés megtagadva Cancel @@ -1104,11 +1104,11 @@ Are you sure you want to delete these {0} items? - Biztosan szeretné törölni ezt a(z) {0} fájlt? + Biztosan törölni szeretne {0} fájlt? Are you sure you want to delete this item? - Bizotsan törölné ezt az fájlt? + Bizotsan törölni szeretné a fájlt? Add tab @@ -1120,11 +1120,11 @@ Adaptive (Recommended) - Automatikus (Ajánlott) + Automatikus (ajánlott) Selects the best multitasking control based on how the app window is resized. When the window is small, you'll notice the horizontal tab strip is collapsed into a flyout on the navigation toolbar. - A legjobb lehetőség kiválasztása az ablak méretétől függően. Amikor az ablak kicsi, a vízszintes lap lánc egy menüvé alakul navigációs sávban. + A legjobb lehetőség kiválasztása az ablak méretétől függően. Amikor az ablak kicsi, a vízszintes lap sáv egy menüelemmé alakul át. Horizontal @@ -1132,7 +1132,7 @@ Always hides the vertical multitasking flyout from the navigation toolbar, and shows the traditional horizontal tabstrip on the app window. This is suited for users who need to keep track of every open app instance at all times. - Menü elrejtése a navigációs sávból, az eredeti vízszintes lap lánc használata. Felhasználóknak akik állandóan követnék az összes lapot. + Menüelem elrejtése, az eredeti vízszintes lap sáv használata. Olyan felhasználóknak, akik szeretik állandóan figyelemmel követni az összes megnyitott lapot. Multitasking @@ -1144,7 +1144,7 @@ Collapses the horizontal list of app instances into a vertical flyout on the navigation toolbar, designed for users who want a clean app interface with on-demand access to a multitasking experience. - A vízszintes lap lánc egy menüvé alakul navigációs sávban, azoknak a felhasználóknak tervezve, akik egy letisztult felhasználói felületet szeretnének igény szerint a multitaszkingal. + A vízszintes lap sáv egy menüelemmé alakul át, azoknak a felhasználóknak tervezve, akik egy letisztult felhasználói felületet szeretnének, de a multitaszking lehetőségével. Multitasking @@ -1156,7 +1156,7 @@ Copy location - Hely másolása + Elérési út másolása Cancel @@ -1164,11 +1164,11 @@ Create a New Item - Új elem készítése + Új elem létrehozása Choose a type for this new item below - Válasszon fájltípust az alábbiak közűl + Válasszon típust az alábbiak közül Folder @@ -1176,7 +1176,7 @@ Creates an empty folder - Új mappa készítése + Új mappa létrehozása Layout mode @@ -1184,11 +1184,11 @@ Navigate backwards - Navigálás hátra + Vissza navigálás Navigate forward - Navigálás előre + Előre navigálás Refresh the directory @@ -1196,27 +1196,27 @@ Go up one directory - Vissza egy mappával + Egy szinttel feljebb Vertical tab strip - Függőleges lap lánc + Függőleges lap lista App Language - Program Nyelve + Alkalmazás nyelve Terminal Applications - Parancssor Alkalmazások + Terminál alkalmazások Edit terminal applications - Parancssor alkalmazások szerkeztése + Terminál alkalmazások módosítása Edit terminal applications - Parancssor alkalmazások szerkeztése + Terminál alkalmazások módosítása View sample profiles @@ -1224,11 +1224,11 @@ App Language - App Nyelve + Alkalmazás nyelve Terminal Applications - Parancssor Programok + Terminál alkalmazások Pin Recycle Bin to the sidebar @@ -1240,11 +1240,11 @@ Terminal Applications - Parancssor Programok + Terminál alkalmazások More options - Több lehetőség + További lehetőségek Selection options @@ -1252,7 +1252,7 @@ Status center - Állapot központ + Állapotközpont Open items with a single click @@ -1260,7 +1260,7 @@ Move here - Ide + Áthelyezés ide Drives @@ -1268,11 +1268,11 @@ Show library cards on the home page - Könyvtárak megjelenítése a fő oldalon + Könyvtárak megjelenítése a kezdőoldalon Show library cards on the home page - Könyvtárak megjelenítése a fő oldalon + Könyvtárak megjelenítése a kezdőoldalon Widgets @@ -1284,19 +1284,19 @@ Show drives on the home page - Meghajtók megjelenítése a fő oldalon + Meghajtók megjelenítése a kezdőoldalon Show drives on the home page - Meghajtók megjelenítése a fő oldalon + Meghajtók megjelenítése a kezdőoldalon Show recent files on the home page - Legutóbb megnyitottak megjelenítése a fő oldalon + Előzmények megjelenítése a kezdőoldalon Show recent files on the home page - Legutóbbi megnyitottak megjelenítése a fő oldalon + Előzmények megjelenítése a kezdőoldalon File @@ -1312,7 +1312,7 @@ Shortcut item - Gyorsgomb elem + Parancsikon elem Show hidden files and folders @@ -1324,7 +1324,7 @@ Safe to remove hardware - A hardware eltávolítása biztonságos + Eszköz kiadása The device can now be safely removed from the computer. @@ -1332,11 +1332,11 @@ Problem Ejecting Device - Hiba az eszköz kiadása közben + Hiba történt az eszköz kiadása közben This device is currently in use. Close any programs, windows or tabs that might be using the device, and then try again. - Az eszköz jelenleg használatban van. Zárjon be minden programot, ablakot ami használhatja, majd próbálja újra. + Az eszköz jelenleg használatban van. Zárjon be minden programot, ablakot vagy oldalt, ami használhatja, majd próbálja újra. Eject @@ -1344,7 +1344,7 @@ Duplicate tab - Lap kettőzése + Lap megkettőzése Move tab to new window @@ -1360,7 +1360,7 @@ Read-only - Csak olvasható + Írásvédett Hidden @@ -1372,7 +1372,7 @@ Item Type - Elem típusa + Típus Title @@ -1380,7 +1380,7 @@ Subject - Téma + Tárgy Comment @@ -1428,35 +1428,35 @@ Longitude Decimal - Szélesség (egész) + GPS szélesség (egész) Latitude Decimal - Magasság (egész) + GPS magasság (egész) Latitude - Szélesség + GPS szélesség Longitude - Magasság + GPS magasság Latitude Ref - Szélesség Ref + GPS szélesség ref Longitude Ref - Magasság Ref + GPS magasság ref Altitude - Magasság + GPS magasság Date Taken - Létrehozás dátuma + Készítés dátuma Camera Manufacturer @@ -1480,7 +1480,7 @@ People Names - People Names + Megjelenő személyek Channel Count @@ -1492,11 +1492,11 @@ Sample Rate - Sample Rate + Mintavételi ráta Artist - Artist + Előadó Album Artist @@ -1512,7 +1512,7 @@ Beats Per Minute - Ütem Per Perc + Ütem / perc Composer @@ -1520,7 +1520,7 @@ Conductor - Zeneszerző + Karmester Disc Number @@ -1544,15 +1544,15 @@ Protection Type - Protection Type + Védelem típusa Author Url - Author Url + Szerző URL Content Distributor - Content Distributor + Tartalomszolgáltató Date Released @@ -1560,7 +1560,7 @@ Series Name - Adatsor neve + Sorozat Season Number @@ -1644,11 +1644,11 @@ Total Editing Time - Teljes szerkeztési idő + Teljes szerkesztési idő Template - Minta + Sablon Word Count @@ -1668,19 +1668,19 @@ Page Count - Lapok száma + Oldalak száma Slide Count - Slide Count + Diák száma Frame Rate - Képkockák sebessége + Képkockasebesség Encoding Bitrate - Bitráta kódolása + Kódolási bitráta Compression @@ -1700,7 +1700,7 @@ Core - Leírás + Alap információk Image @@ -1736,7 +1736,7 @@ Address - Elérhetőség + Cím Error @@ -1756,19 +1756,19 @@ There was an issue saving some properties. - Probléma adódott a tulajdonságok mentésekor. + Probléma adódott a tulajdonságok mentése közben. Some properties may contain personal information. - Pár tulajdonság tartalmazhat személyes információt. + Némelyik tulajdonság személyes adatokat tartalmazhat. Clear - Clear + Eltávolítás Clear All Properties - Összes tulajdonság törlése + Mindegyik tulajdonság eltávolítása sRGB @@ -1784,7 +1784,7 @@ Status Center - Állapotsor + Állapotközpont License @@ -1804,15 +1804,15 @@ Learn more about date formats - Tudjon meg többet a dátumokról + Tudjon meg többet a dátumformátumokról Drop here - Másolás ide + Engedje el itt Search results in - Keresés eredménye a következőben: + Keresés eredménye itt: Search results @@ -1848,7 +1848,7 @@ Do you want to download and install the latest version of Files? - Szeretné letőlteni és telepíteni a legújabb Files verziót? + Szeretné letölteni és telepíteni a Files legújabb verzióját? Yes @@ -1860,11 +1860,11 @@ Hide protected operating system files (Recommended) - Védett operációs rendszer fájlok elrejtése (Ajánlott) + Védett operációs rendszer fájlok elrejtése (ajánlott) Hide protected operating system files (Recommended) - Védett operációs rendszer fájlok elrejtése (Ajánlott) + Védett operációs rendszer fájlok elrejtése (ajánlott) File @@ -1876,23 +1876,23 @@ Creates an empty file - Létrehoz egy üres fájlt + Üres fájl létrehozása New File - Új Fájl + Új fájl Enable individual preferences for individual directories - Egyedi preferencia minden egyes mappához + Egyedi beállítások megjegyzése minden mappához Original path - Eredeti elérési út: + Eredeti elérési út Original path - Eredeti elérési út: + Eredeti elérési út Add @@ -1908,7 +1908,7 @@ Cache files and folders for better performance - Fájlok és mappák gyorsítótárba való helyezése a jobb teljesítményért + Fájlok és mappák gyorsítótárazása a jobb teljesítményért Cancel @@ -1924,15 +1924,15 @@ Always open new tabs in dual pane mode - Mindig kettős nézetben nyissa meg az új lapokat + Mindig osztott nézetben nyissa meg az új lapokat Enable dual pane view - Kettős panel bekapcsolása + Osztott nézet bekapcsolása Open in secondary pane - Megnyitás második panelben + Megnyitás a jobb oldali panelen New pane @@ -1940,11 +1940,11 @@ Open in secondary pane - Megnyitás második panelben + Megnyitás a jobb oldali panelen Dual Pane - Kettós panel + Osztott nézet Show unindexed items when searching for files and folders (searches may take longer) @@ -1952,7 +1952,7 @@ Show copy location menu item - Hely másolása elem megjelenítése + "Elérési út másolása" elem megjelenítése Move overflow items into a sub menu @@ -1960,11 +1960,11 @@ Customize the right click context menu - Menü testreszabása + Helyi menü testreszabása Show open in new tab menu item - Megnyitás új oldalon elem megjelenítése + "Megnyitás új oldalon" elem megjelenítése Folders @@ -2028,7 +2028,7 @@ Show file extensions - Fájlkiterjesztések mutatása + Fájl kiterjesztések megjelenítése Show hidden items @@ -2052,27 +2052,27 @@ When Launching Files - Files indulásakor + A Files indulásakor Item Path - Elem elérési útja + Elérési út Toggle the preview pane (Ctrl + P) - Váltás előnézetre (Ctrl + P) + Előnézet panel (Ctrl + P) Item Name - Elem neve + Név Confirm - Megerősítés + Létrehozás Bundle with the same name already exists! - Csomag ezzel a névvel már létezik! + Már létezik munkaterület ezzel a névvel! Input field cannot be empty! @@ -2080,11 +2080,11 @@ Enter Bundle name - Csomag neve + Munkaterület neve Enter Bundle name - Csomag neve + Munkaterület neve Cancel @@ -2092,19 +2092,19 @@ Desired name - Új név + Név Confirm - Megerősítés + Átnevezés Enter new name - Írja be az új nevet + Adja meg az új nevet Rename "{0}" - "{0} átnevezése" + "{0}" átnevezése Cancel @@ -2112,27 +2112,27 @@ Desired name - Csomag neve + Munkaterület neve Confirm - Megerősítés + Létrehozás Add Bundle - Új Csomag + Új munkaterület Export Bundles - Csomagok Exportálása + Munkaterületek exportálása Import Bundles - Csomagok Importálása + Munkaterületek importálása Create Bundle - Csomag létrehozása + Munkaterület létrehozása Open in new tab @@ -2144,15 +2144,15 @@ Remove from bundle - Eltávolítás a csomagból + Eltávolítás a munkaterületről Remove Bundle - Csomag eltávolítása + Munkaterület eltávolítása Bundles - Csomagok + Munkaterületek Drag and drop any file or folder here to quickly access it @@ -2160,27 +2160,27 @@ Confirm - Megerősítés + Létrehozás Enter Bundle name - Írja be az csomag nevét + Adja meg a munkaterület nevét Create Bundle - Csomag létrehozása + Munkaterület létrehozása Rename Bundle - Csomag átnevezése + Munkaterület átnevezése More options... - Több lehetőség... + További lehetőségek... Create Bundle - Csomag létrehozása + Munkaterület létrehozása Cloud Drives @@ -2192,31 +2192,31 @@ No details available - Nincs elérhető részlet + Nincsenek elérhető részletek Show Bundles on the home page - Csomagok megjelenítése a fő oldalon + Munkaterületek megjelenítése a kezdőoldalon Unpin directory from sidebar - Könyvtár levétele az oldalsávról + Levétel az oldalsávról Ongoing tasks flyout - Folyamatban lévő feladatok flyout + Folyamatban lévő műveletek panel Available when online - Online állapotban elérhető + Online elérhető Available offline - Offline állapotban is elérhető + Offline is elérhető Partially available offline - Részben elérhető offline módban + Offline részben elérhető Syncing @@ -2228,7 +2228,7 @@ Not calculated - Kiszámolatlan + Nem meghatározott Unknown @@ -2268,13 +2268,65 @@ Multiselect - Többszörös kijelölés + Több elem kijelölése - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) Többszörös kijelőlés (jelenleg lista és ikon nézetekben elérhető) + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + Ha a fájlnév kiterjesztését módosítja, akkor a fájl használhatatlanná válhat. Végrehajtja a módosítást? + + + CD ROM Drive + CD-RW-meghajtó + + + Cloud Drive + Felhőtárhely + + + Fixed Disk Drive + Helyi lemez + + + Floppy Disk Drive + Floppy Meghajtó + + + Network Drive + Hálózati meghajtó + + + Unmounted Drive + Objektumnév nélküli helyi lemez + + + RAM Disk Drive + RAM meghajtó + + + Removable Storage Device + Eltávolítható meghajtó + + + Unknown + Ismeretlen + + + Virtual Drive + Virtuális meghajtó + + + Date created + Létrehozás dátuma + + + Date created + Létrehozás dátuma + - \ No newline at end of file + diff --git a/Files/MultilingualResources/Files.it-IT.xlf b/Files/MultilingualResources/Files.it-IT.xlf index 0fac485dd264..7dbbcf0e668b 100644 --- a/Files/MultilingualResources/Files.it-IT.xlf +++ b/Files/MultilingualResources/Files.it-IT.xlf @@ -2272,8 +2272,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.ja-JP.xlf b/Files/MultilingualResources/Files.ja-JP.xlf index 71563d8aed4f..9a5a818008fb 100644 --- a/Files/MultilingualResources/Files.ja-JP.xlf +++ b/Files/MultilingualResources/Files.ja-JP.xlf @@ -1029,7 +1029,7 @@ The item you're attempting to rename no longer exists. Please verify the correct location of the item you need to rename. - 名前を変更しようとしている項目はもう存在しません。 名前を変更する必要がある項目の正しい場所を確認してください。 + 名前を変更しようとしている項目は既に存在しません。 名前を変更する必要がある項目の正しい場所を確認してください。 Item no longer exists @@ -1101,7 +1101,7 @@ Set as - に設定 + 背景に設定 Copy location @@ -1133,7 +1133,7 @@ Choose a type for this new item below - 以下でこの新しい項目の種類を選択してください + 以下で新しい項目の種類を選択してください Cancel @@ -1585,7 +1585,7 @@ Provider Style - Provider Style + プロバイダースタイル Publisher @@ -1837,7 +1837,7 @@ List and sort directories alongside files - List and sort directories alongside files + ファイルとディレクトリを一緒に並べ替える Details @@ -1929,7 +1929,7 @@ Always open new tabs in dual pane mode - Always open new tabs in dual pane mode + 新しいタブを常にデュアル ペイン表示で開く Enable dual pane view @@ -1953,11 +1953,11 @@ Show copy location menu item - Show copy location menu item + 「ファイルの場所をコピー」のメニューを表示 Move overflow items into a sub menu - Move overflow items into a sub menu + 右クリックメニューの一部をサブメニューに移動する Customize the right click context menu @@ -1965,7 +1965,7 @@ Show open in new tab menu item - Show open in new tab menu item + 「ファイルを新しいタブで開く」のメニューを表示 Folders @@ -1977,303 +1977,356 @@ Details View - Details View + 詳細ビュー Grid View (Large) - Grid View (Large) + グリッドビュー (大) Grid View (Medium) - Grid View (Medium) + グリッドビュー (中) Grid View (Small) - Grid View (Small) + グリッドビュー (小) Tiles View - Tiles View + タイルビュー Layout Mode - Layout Mode + レイアウトモード Display Options - Display Options + 表示オプション Display Options - Display Options + 表示オプション Display options - Display options + 表示オプション Grid View (Large) - Grid View (Large) + グリッドビュー (大) Grid View (Medium) - Grid View (Medium) + グリッドビュー (中) Grid View (Small) - Grid View (Small) + グリッドビュー (小) Tiles View - Tiles View + タイルビュー Show file extensions - Show file extensions + 拡張子を表示 Show hidden items - Show hidden items + 隠しファイルを表示 Details View - Details View + 詳細ビュー Date deleted - Date deleted + 削除した日時 Date deleted - Date deleted + 削除した日時 Tab Customization - Tab Customization + タブのカスタマイズ When Launching Files - When Launching Files + 起動時の設定 Confirm - Confirm + 確定 Bundle with the same name already exists! - Bundle with the same name already exists! + 同じ名前のバンドルが既に存在しています! Input field cannot be empty! - Input field cannot be empty! + 入力フィールドが空欄です! Enter Bundle name - Enter Bundle name + バンドル名を入力 Enter Bundle name - Enter Bundle name + バンドル名を入力 Cancel - Cancel + キャンセル Desired name - Desired name + 新しい名前 Confirm - Confirm + 確定 Enter new name - Enter new name + 新しい名前を入力 Rename "{0}" - Rename "{0}" + "{0}"の名前を変更 Cancel - Cancel + キャンセル Desired name - Desired name + 新しい名前 Confirm - Confirm + 確定 Add Bundle - Add Bundle + バンドルを追加 Export Bundles - Export Bundles + バンドルをエクスポート Import Bundles - Import Bundles + バンドルをインポート Create Bundle - Create Bundle + バンドルを作成 Open in new tab - Open in new tab + 新しいタブで開く Open item location - Open item location + ファイルの場所を開く Remove from bundle - Remove from bundle + バンドルから削除 Remove Bundle - Remove Bundle + バンドルを削除 Bundles - Bundles + バンドル Drag and drop any file or folder here to quickly access it - Drag and drop any file or folder here to quickly access it + ファイルやフォルダをここにドラッグして追加 Confirm - Confirm + 確定 Enter Bundle name - Enter Bundle name + バンドル名を入力 Create Bundle - Create Bundle + バンドルを作成 Rename Bundle - Rename Bundle + バンドル名を変更 More options... - More options... + 詳細設定... Create Bundle - Create Bundle + バンドルを作成 Item Path - Item Path + ファイルのパス Toggle the preview pane (Ctrl + P) - Toggle the preview pane (Ctrl + P) + プレビューペインの表示/非表示切替(Ctrl + P) Item Name - Item Name + ファイル名 Cloud Drives - Cloud Drives + クラウドドライブ No preview available - No preview available + プレビュー利用不可 No details available - No details available + 詳細利用不可 Show Bundles on the home page - Show Bundles on the home page + ホームにバンドルを表示 Unpin directory from sidebar - Unpin directory from sidebar + フォルダをサイドバーから外す Properties - Properties + プロパティ File details - File details + ファイルの詳細 File preview - File preview + ファイルのプレビュー Selected file preview pane - Selected file preview pane + 選択したファイルのプレビュー Documentation - Documentation + ドキュメンテーション Find tips & tricks and learn more about Files - Find tips & tricks and learn more about Files + Filesを使いこなす秘訣を学ぶ Visit the Files documentation website - Visit the Files documentation website + Filesの資料ページを表示 Ongoing tasks flyout - Ongoing tasks flyout + 進行中のタスクのフライアウト Available when online - Available when online + オンラインで利用可能 Available offline - Available offline + オフラインで利用可能 Partially available offline - Partially available offline + 部分的にオフラインで利用可能 Syncing - Syncing + 同期中 Excluded from sync - Excluded from sync + 同期から除外済 Not calculated - Not calculated + 未計測 Unknown - Unknown + 不明 Enable adaptive preview pane - Enable adaptive preview pane + アダプティブ プレビュー ペインを有効にする Multiselect - Multiselect + 複数選択 - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + 複数選択を有効にする(現在タイルビューとグリッドビューのみで利用可能) + Please verify the translation’s accuracy as the source string was updated after it was translated. + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.ko-KR.xlf b/Files/MultilingualResources/Files.ko-KR.xlf index d24276e89870..200ac32acff2 100644 --- a/Files/MultilingualResources/Files.ko-KR.xlf +++ b/Files/MultilingualResources/Files.ko-KR.xlf @@ -2266,6 +2266,67 @@ Unknown 알 수 없음 + + Multiselect + Multiselect + + + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Please verify the translation’s accuracy as the source string was updated after it was translated. + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created + diff --git a/Files/MultilingualResources/Files.nl-NL.xlf b/Files/MultilingualResources/Files.nl-NL.xlf index 70832c42a1a1..65dacc674aa3 100644 --- a/Files/MultilingualResources/Files.nl-NL.xlf +++ b/Files/MultilingualResources/Files.nl-NL.xlf @@ -2286,8 +2286,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.or-IN.xlf b/Files/MultilingualResources/Files.or-IN.xlf index 7bed2e22025f..ff660fc9b402 100644 --- a/Files/MultilingualResources/Files.or-IN.xlf +++ b/Files/MultilingualResources/Files.or-IN.xlf @@ -2284,8 +2284,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.pl-PL.xlf b/Files/MultilingualResources/Files.pl-PL.xlf index 03fcdf48f07c..5560d36da52b 100644 --- a/Files/MultilingualResources/Files.pl-PL.xlf +++ b/Files/MultilingualResources/Files.pl-PL.xlf @@ -127,8 +127,7 @@ Unpin from sidebar - Odepnij od paska bocznego - Please verify the translation’s accuracy as the source string was updated after it was translated. + Odepnij od paska bocznego Delete Item(s) @@ -276,8 +275,7 @@ QuickLook - Szybki podgląd - Please verify the translation’s accuracy as the source string was updated after it was translated. + QuickLook New Window @@ -286,7 +284,6 @@ Copy location Kopiuj ścieżkę - Please verify the translation’s accuracy as the source string was updated after it was translated. Paste @@ -355,7 +352,6 @@ To get started, you'll need to grant us permission to display your files. This will open a Settings page where you can grant us this permission. You'll need to reopen the app once you've completed this step. Przed rozpoczęciem, będziesz musiał przyznać uprawnienia do odczytu plików. Otworzymy dla Ciebie kartę z ustawieniami gdzie będziesz mógł przyznać te uprawnienia. Będzie wymagany restart aplikacji po wprowadzeniu zmian. - Please verify the translation’s accuracy as the source string was updated after it was translated. File folder @@ -716,8 +712,7 @@ Are you sure you want to permanently delete all these items? - Czy na pewno chcesz usunąć wszystkie elementy? - Please verify the translation’s accuracy as the source string was updated after it was translated. + Czy na pewno chcesz trwale usunąć wszystkie elementy? Empty recycle bin @@ -725,8 +720,7 @@ Yes - OK - Please verify the translation’s accuracy as the source string was updated after it was translated. + OK bytes @@ -1276,7 +1270,7 @@ Folder - Skoroszyt + Folder Recycle bin item @@ -1368,7 +1362,7 @@ Search - Wyszukaj + Wyszukaj Read-only @@ -1504,7 +1498,7 @@ Format - Formatuj + Formatuj Sample Rate @@ -1784,11 +1778,11 @@ sRGB - sRGB + sRGB Unspecified - Nieokreślone + Nieokreślone Check the status of file operations here @@ -1828,7 +1822,7 @@ Search results - Wyniki wyszukiwania + Wyniki wyszukiwania See who contributed to Files @@ -1904,11 +1898,11 @@ Original path - Oryginalna ścieżka: + Oryginalna ścieżka Original path - Oryginalna ścieżka: + Oryginalna ścieżka Add @@ -1928,7 +1922,7 @@ Cancel - Anuluj + Anuluj Ongoing Tasks @@ -2060,231 +2054,283 @@ Tab Customization - Tab Customization + Dostosowywanie kart When Launching Files - When Launching Files + Podczas uruchamiania Files Confirm - Confirm + Zatwierdź Bundle with the same name already exists! - Bundle with the same name already exists! + Paczka z tą samą nazwą już istnieje! Input field cannot be empty! - Input field cannot be empty! + Pole tekstowe nie może być puste! Enter Bundle name - Enter Bundle name + Wprowadź nazwę Paczki Enter Bundle name - Enter Bundle name + Wprowadź nazwę Paczki Cancel - Cancel + Anuluj Desired name - Desired name + Żądana nazwa Confirm - Confirm + Zatwierdź Enter new name - Enter new name + Wprowadź nową nazwę Rename "{0}" - Rename "{0}" + Zmień nazwę "{0}" Cancel - Cancel + Anuluj Desired name - Desired name + Żądana nazwa Confirm - Confirm + Zatwierdź Add Bundle - Add Bundle + Dodaj Paczkę Export Bundles - Export Bundles + Eksportuj Paczki Import Bundles - Import Bundles + Importuj Paczki Create Bundle - Create Bundle + Utwórz nową Paczkę Open in new tab - Open in new tab + Otwórz w nowej karcie Open item location - Open item location + Otwórz lokację pliku Remove from bundle - Remove from bundle + Usuń z Paczki Remove Bundle - Remove Bundle + Usuń Paczkę Bundles - Bundles + Paczki Drag and drop any file or folder here to quickly access it - Drag and drop any file or folder here to quickly access it + Przeciągnij dowolny plik lub folder, aby szybko uzyskać do niego dostęp Confirm - Confirm + Zatwierdź Enter Bundle name - Enter Bundle name + Wprowadź nazwę Paczki Create Bundle - Create Bundle + Utwórz nową Paczkę Rename Bundle - Rename Bundle + Zmień nazwę Paczki More options... - More options... + Więcej opcji... Create Bundle - Create Bundle + Utwórz nową Paczkę Item Path - Item Path + Ścieżka elementu Toggle the preview pane (Ctrl + P) - Toggle the preview pane (Ctrl + P) + Przełącz panel podglądu (Ctrl + P) Item Name - Item Name + Nazwa elementu Cloud Drives - Cloud Drives + Dyski w chmurze No preview available - No preview available + Podgląd niedostępny No details available - No details available + Brak dostępnych szczegółów Show Bundles on the home page - Show Bundles on the home page + Pokaż Paczki na strone głównej Unpin directory from sidebar - Unpin directory from sidebar + Odepnij katalog od paska bocznego Properties - Properties + Właściwości File details - File details + Szczegóły pliku File preview - File preview + Podgląd pliku Selected file preview pane - Selected file preview pane + Panel podglądu wybranego pliku Documentation - Documentation + Dokumentacja Find tips & tricks and learn more about Files - Find tips & tricks and learn more about Files + Znajdź wskazówki i dowiedz się więcej o Files Visit the Files documentation website - Visit the Files documentation website + Odwiedź witrynę z dokumentacją Files Ongoing tasks flyout - Ongoing tasks flyout + Menu bieżących zadań Available when online - Available when online + Dostępne w trybie Online Available offline - Available offline + Dostępne w trybie Offline Partially available offline - Partially available offline + Częściowo dostępne w trybie Offline Syncing - Syncing + Synchronizowanie Excluded from sync - Excluded from sync + Wykluczone z synchronizacji Not calculated - Not calculated + Nie obliczone Unknown - Unknown + Nieznane Enable adaptive preview pane - Enable adaptive preview pane + Włącz adaptacyjny panel podglądowy Multiselect - Multiselect + Wielokrotne zaznaczanie - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Włacz opcję wielokrotnego zaznaczania (obecnie dostępne tylko w trybach układu kafelek i siatki) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.pt-BR.xlf b/Files/MultilingualResources/Files.pt-BR.xlf index 0e69b8135caf..b74dea0f07b7 100644 --- a/Files/MultilingualResources/Files.pt-BR.xlf +++ b/Files/MultilingualResources/Files.pt-BR.xlf @@ -2274,8 +2274,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.ru-RU.xlf b/Files/MultilingualResources/Files.ru-RU.xlf index 60c88eb3755c..c348441b6083 100644 --- a/Files/MultilingualResources/Files.ru-RU.xlf +++ b/Files/MultilingualResources/Files.ru-RU.xlf @@ -2276,8 +2276,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.sv-SE.xlf b/Files/MultilingualResources/Files.sv-SE.xlf new file mode 100644 index 000000000000..942291ddb203 --- /dev/null +++ b/Files/MultilingualResources/Files.sv-SE.xlf @@ -0,0 +1,2332 @@ + + + +
+ +
+ + + + Delete Item(s) + Radera objekt + + + Cancel + Avbryt + + + Delete + Ta bort + + + Permanently delete + Ta bort permanent + + + Open in new tab + Öppna i ny flik + + + Open in new window + Öppna i nytt fönster + + + New Tab + Ny flik + + + New Window + Nytt fönster + + + Folder + Mapp + + + Bitmap Image + Bitmappsbild + + + Text Document + Textdokument + + + Copy location + Kopiera sökväg + + + Paste + Klistra in + + + Drives + Enheter + + + Name + Namn + + + Date modified + Senast ändrad + + + Type + Typ + + + Size + Storlek + + + Open in Terminal... + Öppna i Terminal... + + + Created: + Skapad: + + + Item Name + Filnamn + + + Path: + Sökväg: + + + Size: + Storlek: + + + This action cannot be done + Denna åtgärd kan inte utföras + + + The destination folder + Målmappen + + + is a subfolder of the source folder + är en undermapp till källmappen + + + Skip + Hoppa över + + + Cancel + Avbryt + + + Item type: + Objekttyp: + + + Select All + Markera alla + + + Invert Selection + Invertera markering + + + Clear Selection + Rensa markering + + + Details View + Detaljerad lista + + + Modified: + Ändrad: + + + Accessed: + Använd: + + + Owner: + Ägare: + + + Clear all items + Rensa alla objekt + + + Enter a path + Ange en sökväg + + + Search + Sök + + + Files you've previously accessed will show up here + Filer som du använt tidigare kommer att visas här + + + Open file location + Öppna filsökväg + + + Remove this item + Ta bort det här objektet + + + Recent items + Senaste objekt + + + Files + Files + + + Submit Feedback + Skicka feedback + + + Send the developers an issue report with detailed information + Skicka en felrapport med detaljerad information till utvecklarna + + + Third Party Licenses + Tredjepartslicenser + + + About + Om + + + Acrylic sidebar + Genomskinligt sidofält + + + Date format + Datumformat + + + App theme + Apptema + + + Appearance + Utseende + + + Show extensions for known file types + Visa filnamnstillägg för kända filtyper + + + Show hidden files and folders + Visa dolda filer och mappar + + + Show hidden files and folders + Visa dolda filer och mappar + + + Files and Folders + Filer och mappar + + + Experimental + Experimentellt + + + Settings + Senast ändrad + + + About + Om + + + Appearance + Utseende + + + Experimental + Experimentellt + + + Files and Folders + Filer och mappar + + + On Startup + Vid start + + + Preferences + Alternativ + + + WARNING: EXPERIMENTAL FEATURES AHEAD! + VARNING: FÖLJANDE FUNKTIONER ÄR EXPERIMENTELLA! + + + Continue where you left off + Fortsätt där du slutade + + + Open a new tab + Öppna en ny flik + + + Open a specific page or pages + Öppna en specifik sida eller specifika sidor + + + On Startup + Vid start + + + Show Owner in properties + Visa ägare i egenskaper + + + Preferences + Alternativ + + + Desktop + Skrivbord + + + Documents + Dokument + + + Downloads + Hämtade filer + + + Home + Startsida + + + Music + Musik + + + Pictures + Bilder + + + Unpin from sidebar + Lossa från sidofältet + + + Videos + Filmer + + + Sort by + Sortera efter + + + Name + Namn + + + Date modified + Senast ändrad + + + Type + Typ + + + Size + Storlek + + + Ascending + Stigande + + + Descending + Fallande + + + Refresh + Uppdatera + + + Paste + Klistra in + + + Open in Terminal... + Öppna i Terminal... + + + MD5Hash: + MD5Hash: + + + New + Nytt + + + Folder + Mapp + + + File + Fil + + + Properties + Egenskaper + + + Properties + Egenskaper + + + Extract + Extrahera + + + Open + Öppna + + + Open in new tab + Öppna i ny flik + + + Open in new window + Öppna i nytt fönster + + + Set as desktop background + Använd som skrivbordsbakgrund + + + Share + Dela + + + Cut + Klipp ut + + + Copy + Kopiera + + + Delete + Ta bort + + + Rename + Byt namn + + + Pin to sidebar + Fäst på sidofältet + + + Properties + Egenskaper + + + QuickLook + QuickLook + + + Welcome to Files! + Välkommen till Files! + + + Grant Permission + Bevilja behörighet + + + To get started, you'll need to grant us permission to display your files. This will open a Settings page where you can grant us this permission. You'll need to reopen the app once you've completed this step. + För att komma igång behöver du bevilja behörighet till oss att visa dina filer. En sida kommer att öppnas i Inställningar där du kan bevilja behörigheten. Du behöver starta om appen efter att du har gjort detta. + + + File folder + Filmapp + + + File + Fil + + + Enter an item name + Ange ett namn för objektet + + + Enter an item name + Ange ett namn för objektet + + + Set Name + Tillämpa namn + + + Cancel + Avbryt + + + New tab + Ny flik + + + Windows default + Windows-standard + + + Light + Ljust + + + Dark + Mörkt + + + Application + App + + + System + System + + + New Folder + Ny mapp + + + New File + Ny fil + + + This folder is empty. + Denna mapp är tom. + + + Back (Alt + Left Arrow) + Tillbaka (Alt + Vänsterpil) + + + Forward (Alt + Right Arrow) + Framåt (Alt + Högerpil) + + + Up (Alt + Up Arrow) + Upp en nivå (Alt + Uppåtpil) + + + Refresh (F5) + Uppdatera (F5) + + + Search + Sök + + + More options + Fler alternativ + + + Properties + Egenskaper + + + Attributes: + Attribut: + + + Properties + Egenskaper + + + View sample profiles + Visa exempelprofiler + + + An item with this name already exists in this directory. + Det finns redan ett objekt med samma namn på den här platsen. + + + Generate new name + Generera nytt namn + + + Replace existing item + Ersätt existerande objekt + + + Item already exists + Objektet finns redan. + + + Set as lockscreen background + Använd som låsskärmsbakgrund + + + Grid View (Large) + Rutnätsvy (Stor) + + + Grid View (Medium) + Rutnätsvy (Medel) + + + Grid View (Small) + Rutnätsvy (Liten) + + + Tiles View + Panelvy + + + OK + OK + + + We weren't able to delete this item + Vi kunde inte ta bort det här objektet + + + Access Denied + Åtkomst nekad + + + Please insert the necessary drive to access this item. + Vänligen sätt i enheten som krävs för att komma åt det här objektet. + + + Drive Unplugged + Enhet frånkopplad + + + The file you are attempting to access may have been moved or deleted. + Filen som du försöker komma åt kan ha flyttats eller tagits bort. + + + File Not Found + Filen hittades inte + + + The file you are attempting to preview may have been moved or deleted. + Filen som du försöker förhandsgranska kan ha flyttats eller tagits bort. + + + The folder you are attempting to access may have been moved or deleted. + Mappen som du försöker komma åt kan ha flyttats eller tagits bort. + + + Did you delete this folder? + Tog du bort den här mappen? + + + The file you're trying to delete is currently being used by an another application. + Filen som du försöker ta bort används av ett annat program. + + + File is in use + Filen används + + + Try again + Försök igen + + + OK + OK + + + Layout Mode + Layoutläge + + + Selection options + Markeringsalternativ + + + Read-only + Skrivskyddad + + + Hidden + Dold + + + Empty recycle bin + Töm papperskorgen + + + Restore + Återställ + + + {0} days ago + {0} dagar sedan + + + {0} day ago + {0} dag sedan + + + {0} hours ago + {0} timmar sedan + + + {0} hour ago + {0} timme sedan + + + {0} minutes ago + {0} minuter sedan + + + {0} minute ago + {0} minut sedan + + + {0} seconds ago + {0} sekunder sedan + + + New Tab + Ny flik + + + The requested operation is not supported + Den begärda åtgärden stöds inte. + + + {0} free of {1} + {0} ledigt av {1} + + + Open With + Öppna med + + + The item name must not contain the following characters: \ / : * ? " < > | + Filnamn kan inte innehålla något av följande tecken: \ / : * ? " < > | + + + OK + OK + + + The item name must not contain the following characters: \ / : * ? " < > | + Filnamn kan inte innehålla något av följande tecken: \ / : * ? " < > | + + + Open log location + Öppna loggplats + + + New tab (Ctrl + T) + Ny flik (Ctrl + T) + + + item selected + objekt markerat + + + items selected + objekt markerade + + + item + objekt + + + items + objekt + + + Deleting files + Tar bort filer + + + Pasting files + Klistrar in filer + + + Moving files to Recycle Bin + Flyttar filer till Papperskorgen + + + Pin directory to sidebar + Fäst mapp på sidofältet + + + Yes + Ja + + + Cancel + Avbryt + + + Are you sure you want to permanently delete all these items? + Vill du radera alla dessa objekt permanent? + + + Empty recycle bin + Töm papperskorgen + + + bytes + byte + + + KB + KB + + + MB + MB + + + GB + GB + + + TB + TB + + + PB + PB + + + B + B + + + Run as administrator + Kör som administratör + + + Learn more about date formats + Läs mer om datumformat + + + Unlock + Lås upp + + + Cancel + Avbryt + + + Enter password to unlock the drive + Ange lösenord för att låsa upp enheten + + + Password + Lösenord + + + Please check the password and try again. + Vänligen kontrollera lösenordet och försök igen. + + + BitLocker error + BitLocker-fel + + + Contains: + Innehåller: + + + {0:#,##0} Files, {1:#,##0} Folders + {0:#,##0} filer, {1:#,##0} mappar + + + Run as another user + Kör som en annan användare + + + All type of {0} + Allt med typen {0} + + + Different types + Olika typer + + + All in {0} + Allt i {0} + + + Used space: + Använt utrymme: + + + Free space: + Ledigt utrymme: + + + Capacity: + Kapacitet: + + + File system: + Filsystem: + + + Recent + Senaste + + + App Language + Appspråk + + + Move tab here + Flytta flik hit + + + Status + Status + + + Add a new page + Lägg till en ny sida + + + Pages: + Sidor: + + + Always open a new instance + Öppna alltid en ny instans + + + Open folder in a new tab + Öppna mapp i en ny flik + + + When launching an item from the jumplist + När ett objekt öppnas från Start-menyn eller aktivitetsfältet + + + Windows default + Windows-standard + + + No results + Inga sökresultat + + + Can't access any items to display + Kan inte komma åt några objekt att visa + + + Move to {0} + Flytta till {0} + + + The source and destination file names are the same. + Källa och mål har samma namn. + + + The destination folder is the same as the source folder. + Målmappen är samma som källmappen. + + + Copy to {0} + Kopiera till {0} + + + Create shortcut + Skapa genväg + + + Open file location + Öppna filsökväg + + + Arguments: + Argument: + + + Destination: + Mål + + + Shortcut type: + Genvägstyp: + + + Working directory: + Starta i: + + + Application + Program + + + File + Fil + + + Folder + Mapp + + + Web link + Webblänk + + + General + Allmänt + + + Shortcut + Genväg + + + Shortcut + Genväg + + + Internet shortcut + Internetgenväg + + + {0} - shortcut + {0} - genväg + + + Open file location + Öppna filsökväg + + + Unknown + Okänd + + + Open log location + Öppna loggplats + + + Files ran into a problem that the developers didn't prepare for yet. + Files stötte på ett problem som utvecklarna inte ännu var förberedda för. + + + Something went wrong! + Något gick fel! + + + Report this issue + Rapportera det här problemet + + + Contributors + Medarbetare + + + See who contributed to Files + Se vilka som bidragit till Files + + + Release Notes + Uppdateringslogg + + + Find out what's new in Files + Se vad som är nytt i Files + + + The item referenced is either invalid or inaccessible.{0}Error message:{0}{1} + Det hänvisade objektet är antingen ogiltigt eller oåtkomligt.{0}Felmeddelande:{0}{1} + + + Invalid item + Ogiltigt objekt + + + Version: + Version: + + + There's nothing to share right now... + Det finns inget att dela just nu... + + + The items you've selected will be shared + De valda objekten kommer att delas + + + The selected item will be shared + Det valda objektet kommer att delas + + + Sharing {0} + Delar {0} + + + Sharing {0} {1} + Delar {0} {1} + + + The item you're attempting to rename no longer exists. Please verify the correct location of the item you need to rename. + Objektet du försöker byta namn på finns inte längre. Kontrollera rätt plats för objektet du behöver byta namn på. + + + Item no longer exists + Objektet finns inte längre + + + The name specified was invalid. Please check the desired item name and try again. + Det angivna namnet var ogiltigt. Vänligen kontrollera önskat filnamn och försök igen. + + + Invalid item name + Ogiltigt filnamn + + + The length of the item name specified exceeds the maximum limit. Please check the desired name and try again. + Längden på det angivna filnamnet överskrider maxgränsen. Kontrollera önskat namn och försök igen. + + + Item name was too long + Filnamnet är för långt + + + More + Mer + + + No + Nej + + + Yes + Ja + + + The application needs to be restarted in order to apply the language setting, would you like to restart the app? + Appen måste startas om för att tillämpa språkinställningen. Vill du starta om appen? + + + Support us + Stöd oss + + + Support us on PayPal + Stöd oss på PayPal + + + We weren't able to create this item + Vi kunde inte skapa det här objektet + + + Access Denied + Åtkomst nekad + + + Cancel + Avbryt + + + Are you sure you want to delete these {0} items? + Vill du radera dessa {0} objekt? + + + Are you sure you want to delete this item? + Vill du radera det här objektet? + + + Add tab + Lägg till flik + + + Open tabs + Öppna flikar + + + Adaptive (Recommended) + Adaptiv (Rekommenderas) + + + Selects the best multitasking control based on how the app window is resized. When the window is small, you'll notice the horizontal tab strip is collapsed into a flyout on the navigation toolbar. + Väljer den bästa multitasking-kontrollen baserat på hur appfönstrets storlek. När fönstret är litet kommer det horisontella flikfältet kollapsas till ett popup-fönster i navigeringsfältet. + + + Horizontal + Horisontell + + + Always hides the vertical multitasking flyout from the navigation toolbar, and shows the traditional horizontal tabstrip on the app window. This is suited for users who need to keep track of every open app instance at all times. + Döljer alltid det vertikala popup-fönstret för multitasking från navigeringsfältet och visar det traditionella horisontella flikfältet i appfönstret. Detta är lämpligt för användare som alltid behöver hålla reda på alla öppna appinstanser. + + + Multitasking + Multitasking + + + Vertical + Vertikal + + + Collapses the horizontal list of app instances into a vertical flyout on the navigation toolbar, designed for users who want a clean app interface with on-demand access to a multitasking experience. + Komprimerar den horisontella listan över appinstanser till ett vertikalt popup-fönster i navigeringsfältet. Utformat för användare som vill ha ett rent appgränssnitt med tillgång till en multitasking-upplevelse på begäran. + + + Multitasking + Multitasking + + + Set as + Använd som + + + Copy location + Kopiera sökväg + + + Cancel + Avbryt + + + Create a New Item + Skapa ett nytt objekt + + + Choose a type for this new item below + Välj en objekttyp nedan + + + File + Fil + + + Creates an empty file + Skapar en tom fil + + + Folder + Mapp + + + Creates an empty folder + Skapar en tom mapp + + + Layout mode + Layoutläge + + + Navigate backwards + Navigera bakåt + + + Navigate forward + Navigera framåt + + + Refresh the directory + Uppdatera mappen + + + Go up one directory + Upp en nivå + + + Vertical tab strip + Vertikalt flikfält + + + App Language + Appspråk + + + Terminal Applications + Terminal-appar + + + Edit terminal applications + Redigera terminal-appar + + + Edit terminal applications + Redigera terminal-appar + + + View sample profiles + Visa exempelprofiler + + + App Language + Appspråk + + + Terminal Applications + Terminal-appar + + + Show copy location menu item + Visa menyalternativet 'kopiera sökväg' + + + Move overflow items into a sub menu + Flytta överflödesobjekt till en undermeny + + + Pin Recycle Bin to the sidebar + Fäst Papperskorgen på sidofältet + + + Show a confirmation dialog when deleting files or folders + Visa en bekräftelsedialog när du tar bort filer eller mappar + + + Terminal Applications + Terminal-appar + + + There was an issue saving some properties. + Det uppstod problem med att spara vissa egenskaper. + + + Error + Fel + + + Retry + Försök igen + + + Close anyway + Stäng ändå + + + Cancel + Avbryt + + + Rating + Klassificering + + + Item Path + Objektsökväg + + + Item Type + Objekttyp + + + Title + Titel + + + Subject + Ämne + + + Comment + Kommentar + + + Copyright + Copyright + + + Date Modified + Senast ändrad + + + Bit Depth + Bitdjup + + + Dimensions + Bildstorlek + + + Horizontal Size + Vågrät storlek + + + Vertical Size + Lodrät storlek + + + Horizontal Resolution + Vågrät upplösning + + + Vertical Resolution + Lodrät upplösning + + + Compression + Komprimering + + + Color Space + Färgrymd + + + sRGB + sRGB + + + Unspecified + Ej angivet + + + Longitude Decimal + Longitud decimal + + + Latitude Decimal + Latitud decimal + + + Latitude + Latitud + + + Longitude + Longitud + + + Latitude Ref + Latitud ref + + + Longitude Ref + Longitud ref + + + Altitude + Altitud + + + Date Taken + Fotodatum + + + Camera Manufacturer + Kameratillverkare + + + Camera Model + Kameramodell + + + Exposure Time + Exponeringstid + + + Focal Length + Brännvidd + + + Aperture + Bländartal + + + People Names + Personnamn + + + Channel Count + Antal kanaler + + + Format + Format + + + Sample Rate + Samplingshastighet + + + Artist + Artist + + + Album Artist + Albumartist + + + Album Title + Album + + + Artist + Artist + + + Beats Per Minute + Slag per minut + + + Composer + Kompositör + + + Conductor + Dirigent + + + Disc Number + Skivnummer + + + Genre + Genre + + + Track Number + Låtnummer + + + Duration + Längd + + + Frame Count + Antal bildrutor + + + Protection Type + Typ av skydd + + + Author Url + Författar-URL + + + Content Distributor + Innehållsdistributör + + + Date Released + Utgivningsdatum + + + Series Name + Serienamn + + + Season Number + Säsongsnummer + + + Episode Number + Avsnittsnummer + + + Producer + Producent + + + Promotion Url + Kampanj-URL + + + Provider Style + Leverantörsstil + + + Publisher + Utgivare + + + Thumbnail Large Path + Sökväg till stor miniatyr + + + Thumbnail Large Uri + URI för stor miniatyr + + + Thumbnail Small Path + Sökväg till liten miniatyr + + + Thumbnail Small Uri + URI för liten miniatyr + + + User Web Url + Användar-URL + + + Writer + Skribent + + + Year + År + + + Contributor + Medarbetare + + + Last Author + Senaste författare + + + Revision Number + Versionsnummer + + + Version + Version + + + Date Created + Skapad den + + + Date Saved + Sparad den + + + Date Printed + Tryckdatum + + + Total Editing Time + Total redigeringstid + + + Template + Mall + + + Word Count + Antal ord + + + Character Count + Antal tecken + + + Line Count + Antal rader + + + Paragraph Count + Antal stycken + + + Page Count + Antal sidor + + + Slide Count + Antal bilder + + + Frame Rate + Bildfrekvens + + + Encoding Bitrate + Bithastighet + + + Compression + Komprimering + + + Frame Width + Bildrutebredd + + + Frame Height + Bildrutehöjd + + + Orientation + Orientering + + + Core + Fil + + + Image + Bild + + + Photo + Foto + + + GPS + GPS + + + Media + Media + + + Audio + Ljud + + + Music + Musik + + + Video + Video + + + Document + Dokument + + + Address + Adress + + + More options + Fler alternativ + + + Selection options + Markeringsalternativ + + + Status center + Statuscenter + + + Open items with a single click + Öppna objekt med ett enda klick + + + File + Fil + + + Folder + Mapp + + + Recycle bin item + Objekt i Papperskorgen + + + Shortcut item + Genvägsobjekt + + + Drives + Enheter + + + Move here + Flytta hit + + + Widgets + Widgetar + + + Show drives on the home page + Visa enheter på startsidan + + + Show drives on the home page + Visa enheter på startsidan + + + Show library cards on the home page + Visa kort med biblioteksmappar på startsidan + + + Show library cards on the home page + Visa kort med biblioteksmappar på startsidan + + + Show recent files on the home page + Visa senaste filer på startsidan + + + Show recent files on the home page + Visa senaste filer på startsidan + + + Widgets + Widgetar + + + Safe to remove hardware + Säker att ta bort hårdvara + + + The device can now be safely removed from the computer. + Enheten kan nu säkert tas bort från datorn. + + + Problem Ejecting Device + Problem vid enhetsutmatning + + + This device is currently in use. Close any programs, windows or tabs that might be using the device, and then try again. + Enheten används för närvarande. Stäng alla program, fönster eller flikar som kan använda enheten och försök sedan igen. + + + Eject + Mata ut + + + Duplicate tab + Duplicera flik + + + Move tab to new window + Flytta flik till nytt fönster + + + New tab + Ny flik + + + Some properties may contain personal information. + Vissa egenskaper kan innehålla personlig information. + + + Clear + Rensa + + + Clear All Properties + Rensa alla egenskaper + + + Check the status of file operations here + Kontrollera status för filåtgärder här + + + Status Center + Statuscenter + + + License + Licens + + + License + Licens + + + Website + Webbplats + + + Website + Webbplats + + + Learn more about date formats + Läs mer om datumformat + + + Drop here + Släpp här + + + Search + Sök + + + Search results in + Sökresultat i + + + Search results + Sökresultat + + + See who contributed to Files + Se vilka som bidragit till Files + + + Find out what's new in Files + Se vad som är nytt i Files + + + Send the developers an issue report with more information + Skicka en felrapport med vidare information till utvecklarna + + + Support us on PayPal + Stöd oss på PayPal + + + List and sort directories alongside files + Visa och sortera mappar tillsammans med filer istället för avskilt + + + Details + Information + + + No + Nej + + + Do you want to download and install the latest version of Files? + Vill du ladda ner och installera den senaste versionen av Files? + + + Yes + Ja + + + Updates Available + Uppdateringar är tillgängliga + + + Hide protected operating system files (Recommended) + Dölj skyddade operativsystemfiler (rekommenderas) + + + Hide protected operating system files (Recommended) + Dölj skyddade operativsystemfiler (rekommenderas) + + + Enable adaptive preview pane + Aktivera flexibelt förhandsgranskningsfönster + + + Show unindexed items when searching for files and folders (searches may take longer) + Visa oindexerade objekt när du söker efter filer och mappar (sökningar kan ta längre tid) + + + Enable individual preferences for individual directories + Använd individuella inställningar för varje mapp + + + Customize the right click context menu + Anpassa högerklicksmenyn + + + Original path + Ursprunglig plats + + + Original path + Ursprunglig plats + + + Cache files and folders for better performance + Lagra filer och mappar i cache för bättre prestanda + + + Add + Lägg till + + + Edit + Redigera + + + Remove + Ta bort + + + Cancel + Avbryt + + + Ongoing Tasks + Pågående åtgärder + + + Ongoing Tasks + Pågående åtgärder + + + Always open new tabs in dual pane mode + Öppna alltid nya flikar med dubbla paneler + + + Enable dual pane view + Aktivera vy med dubbla paneler + + + Open in secondary pane + Öppna i sekundär panel + + + New pane + Ny panel + + + Open in secondary pane + Öppna i sekundär panel + + + Dual Pane + Dubbla paneler + + + Show open in new tab menu item + Visa menyalternativet 'öppna i ny flik' + + + Folders + Mappar + + + Enable animations when opening and closing the context menu + Aktivera animationer när högerklicksmenyn öppnas och stängs + + + Details View + Detaljvy + + + Details View + Detaljvy + + + Display Options + Visningsalternativ + + + Display Options + Visningsalternativ + + + Display options + Visningsalternativ + + + Grid View (Large) + Rutnätsvy (Stor) + + + Grid View (Large) + Rutnätsvy (Stor) + + + Grid View (Medium) + Rutnätsvy (Medel) + + + Grid View (Medium) + Rutnätsvy (Medel) + + + Grid View (Small) + Rutnätsvy (Liten) + + + Grid View (Small) + Rutnätsvy (Liten) + + + Tiles View + Panelvy + + + Tiles View + Panelvy + + + Show file extensions + Visa filnamnstillägg + + + Show hidden items + Visa dolda objekt + + + Date deleted + Borttagningsdatum + + + Date deleted + Borttagningsdatum + + + Tab Customization + Flikanpassning + + + When Launching Files + När Files startas + + + Cloud Drives + Molnenheter + + + More options... + Fler alternativ... + + + Confirm + Bekräfta + + + Export Bundles + Exportera samlingar + + + Import Bundles + Importera samlingar + + + Bundle with the same name already exists! + Det finns redan en samling med samma namn! + + + Input field cannot be empty! + Inmatningsfältet får inte vara tomt! + + + Create Bundle + Skapa samling + + + Enter Bundle name + Ange namn för samlingen + + + Enter Bundle name + Ange namn för samlingen + + + Open in new tab + Öppna i ny flik + + + Open item location + Öppna sökväg + + + Remove from bundle + Ta bort från samling + + + Remove Bundle + Ta bort samling + + + Bundles + Samlingar + + + Drag and drop any file or folder here to quickly access it + Dra och släpp valfri fil eller mapp hit för snabb åtkomst + + + Confirm + Bekräfta + + + Enter Bundle name + Ange namn för samlingen + + + Cancel + Avbryt + + + Desired name + Önskat namn + + + Confirm + Bekräfta + + + Enter new name + Ange ett nytt namn + + + Rename "{0}" + Byt namn på "{0}" + + + Create Bundle + Skapa samling + + + Cancel + Avbryt + + + Confirm + Bekräfta + + + Add Bundle + Lägg till samling + + + Create Bundle + Skapa samling + + + Rename Bundle + Byt namn på samling + + + Desired name + Önskat namn + + + Toggle the preview pane (Ctrl + P) + Växla förhandsgranskningsfönstret (Ctrl + P) + + + No preview available + Ingen förhandsgranskning tillgänglig + + + No details available + Ingen information tillgänglig + + + Item Name + Filnamn + + + Show Bundles on the home page + Visa samlingar på startsidan + + + Unpin directory from sidebar + Lossa mapp från sidofältet + + + File details + Filinformation + + + File preview + Filförhandsgranskning + + + Selected file preview pane + Förhandsgranskningsfönster för vald fil + + + Documentation + Dokumentation + + + Find tips & tricks and learn more about Files + Hitta tips & tricks och läs mer om Files + + + Visit the Files documentation website + Visa Files dokumentationssida + + + Ongoing tasks flyout + Popup-fönster för pågående åtgärder + + + Available when online + Tillgänglig när du är online + + + Available offline + Tillgänglig offline + + + Partially available offline + Delvis tillgänglig offline + + + Syncing + Synkroniserar + + + Excluded from sync + Undantagen från synkronisering + + + Not calculated + Inte beräknat + + + Unknown + Okänd + + + Multiselect + Markera flera + + + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Aktivera alternativ vid val av flera filer (för närvarande endast tillgängligt i panel- och rutnätsvyerna) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created + + + +
+
\ No newline at end of file diff --git a/Files/MultilingualResources/Files.ta.xlf b/Files/MultilingualResources/Files.ta.xlf index 73403a5c081f..beb6a8baf9b7 100644 --- a/Files/MultilingualResources/Files.ta.xlf +++ b/Files/MultilingualResources/Files.ta.xlf @@ -2279,8 +2279,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.tr-TR.xlf b/Files/MultilingualResources/Files.tr-TR.xlf index 894cbe5a5c21..66f3b1a06639 100644 --- a/Files/MultilingualResources/Files.tr-TR.xlf +++ b/Files/MultilingualResources/Files.tr-TR.xlf @@ -2281,8 +2281,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.uk-UA.xlf b/Files/MultilingualResources/Files.uk-UA.xlf index 3de951873d42..e3e23c662528 100644 --- a/Files/MultilingualResources/Files.uk-UA.xlf +++ b/Files/MultilingualResources/Files.uk-UA.xlf @@ -2276,8 +2276,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.zh-Hans.xlf b/Files/MultilingualResources/Files.zh-Hans.xlf index 6924bd51af6d..8548403942b2 100644 --- a/Files/MultilingualResources/Files.zh-Hans.xlf +++ b/Files/MultilingualResources/Files.zh-Hans.xlf @@ -2271,8 +2271,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/MultilingualResources/Files.zh-Hant.xlf b/Files/MultilingualResources/Files.zh-Hant.xlf index 90d532122a33..138013f17847 100644 --- a/Files/MultilingualResources/Files.zh-Hant.xlf +++ b/Files/MultilingualResources/Files.zh-Hant.xlf @@ -2281,8 +2281,60 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + CD ROM Drive + + + Cloud Drive + Cloud Drive + + + Fixed Disk Drive + Fixed Disk Drive + + + Floppy Disk Drive + Floppy Disk Drive + + + Network Drive + Network Drive + + + Unmounted Drive + Unmounted Drive + + + RAM Disk Drive + RAM Disk Drive + + + Removable Storage Device + Removable Storage Device + + + Unknown + Unknown + + + Virtual Drive + Virtual Drive + + + Date created + Date created + + + Date created + Date created diff --git a/Files/Strings/de-DE/Resources.resw b/Files/Strings/de-DE/Resources.resw index 8a613acea995..9298ea110e15 100644 --- a/Files/Strings/de-DE/Resources.resw +++ b/Files/Strings/de-DE/Resources.resw @@ -1381,7 +1381,7 @@ Unterstütze uns mit PayPal - List and sort directories alongside files + Dateien zusammen mit Ordnern sortieren und nicht voneinander trennen Details @@ -1468,7 +1468,7 @@ Geteilte Ansicht - Show copy location menu item + 'Speicherort kopieren' Menüeintrag anzeigen Einträge in ein Untermenü verschieben wenn das Menü überläuft @@ -1618,7 +1618,7 @@ Gruppen - Füge Dateien und Ordner hier durch Ziehen und Ablegen hinzu um schnell Zugriff auf sie zu haben + Füge Dateien und Ordner durch Ziehen und Ablegen hinzu Bestätigen @@ -1630,7 +1630,7 @@ Gruppe erstellen - Gruppe umbennen + Gruppe umbenennen Mehr Optionen... @@ -1704,4 +1704,10 @@ Adaptives Vorschaupanel aktivieren + + Mehrfachauswahl + + + Mehrfachauswahl aktivieren (derzeitig nur für Kachel- und Gridansicht) + \ No newline at end of file diff --git a/Files/Strings/en-US/Resources.resw b/Files/Strings/en-US/Resources.resw index 895aba21bfd8..485540a7fcf6 100644 --- a/Files/Strings/en-US/Resources.resw +++ b/Files/Strings/en-US/Resources.resw @@ -1819,7 +1819,46 @@ Multiselect - Enable multiselect options (currently only abailable in the tiles and grid view layout modes) + Enable multiselect options (currently only available in the tiles and grid view layout modes) + + + If you change a file extension, the file might become unusable. Are you sure you want to change it? + + + CD ROM Drive + + + Cloud Drive + + + Fixed Disk Drive + + + Floppy Disk Drive + + + Network Drive + + + Unmounted Drive + + + RAM Disk Drive + + + Removable Storage Device + + + Unknown + + + Virtual Drive + + + Date created + + + Date created Use preemptive cache (preload entries in child directories on navigation) diff --git a/Files/Strings/es-ES/Resources.resw b/Files/Strings/es-ES/Resources.resw index 4155b1449440..3e269c36bc8c 100644 --- a/Files/Strings/es-ES/Resources.resw +++ b/Files/Strings/es-ES/Resources.resw @@ -1695,4 +1695,49 @@ Habilitar el panel de vista previa adaptable + + Multiselección + + + Habilitar opción de selección múltiple (No disponible en el modo de vista "Detalles") + + + Si cambia la extensión de un archivo, el archivo puede quedar inutilizable. ¿Estás seguro de que quieres cambiarlo? + + + CD ROM + + + Unidad en la nube + + + Disco local + + + Disquete + + + Unidad de red + + + Unidad desmontada + + + Unidad de RAM (RAMDisk) + + + Unidad extraíble + + + Desconocido + + + Unidad virtual + + + Fecha de creación + + + Fecha de creación + \ No newline at end of file diff --git a/Files/Strings/fr-FR/Resources.resw b/Files/Strings/fr-FR/Resources.resw index 5ce7a53ff961..19e6a285ecfa 100644 --- a/Files/Strings/fr-FR/Resources.resw +++ b/Files/Strings/fr-FR/Resources.resw @@ -1623,4 +1623,10 @@ Activer le volet d'aperçu adaptatif + + Sélection Multiple + + + Active l'option de sélection multiple (uniquement disponible sur la vue en tuiles ou en grilles pour le moment) + \ No newline at end of file diff --git a/Files/Strings/hu-HU/Resources.resw b/Files/Strings/hu-HU/Resources.resw index 9200beb2f6f7..7758a198d96b 100644 --- a/Files/Strings/hu-HU/Resources.resw +++ b/Files/Strings/hu-HU/Resources.resw @@ -22,7 +22,7 @@ Törlés - Ideiglenes törlés + Végleges törlés Megnyitás új lapon @@ -31,22 +31,22 @@ Megnyitás új ablakban - Új Lap + Új lap - Új Ablak + Új ablak Mappa - Bitmap Kép + Bitmap kép - Szöveges Dokumentum + Szöveges dokumentum - Útvonal másolása + Elérési út másolása Beillesztés @@ -73,7 +73,7 @@ Létrehozva: - Fájlnév + Név Elérési út: @@ -82,25 +82,25 @@ Méret: - Az az a művelet nem elvégezhető + Ez a művelet nem hajtható végre - Az érkezési mappa + A célmappa - almappája az eredeti mappának + almappája a forrásmappának - Tovább + Kihagyás Mégse - Elem típusa: + Típus: - Mind kijelölése + Összes kijelölése Kijelölés megfordítása @@ -112,10 +112,10 @@ Részletek - Módosítás dátuma: + Módosítva: - Megnyitva: + Hozzáférés: Tulajdonos: @@ -130,7 +130,7 @@ Keresés - Előzőleg megtekintett fájlok helye + Itt fognak megjelenni a korábban megnyitott fájlok Fájlt tartalmazó mappa megnyitása @@ -139,7 +139,7 @@ Elem eltávolítása - Legutóbb megnyitott + Előzmények Files @@ -151,16 +151,16 @@ Visszajelzés küldése a fejlesztőknek - Harmadik személytől származó licenc-ek + Harmadik fél licencei - Rólunk + Névjegy Akril oldalsáv - Dátum formátuma + Dátumformátum Téma @@ -169,46 +169,46 @@ Megjelenés - Kiterjesztés mutatása ismert fájlformátumoknál + Kiterjesztés megjelenítése ismert fájltípusoknál - Fájlok és Mappák + Fájlok és mappák - Kísérleti + Kísérleti beállítások Beállítások - Rólunk + Névjegy Megjelenés - Kísérleti + Kísérleti beállítások - Fájlok és Mappák + Fájlok és mappák Induláskor - Preferencia + Működés VIGYÁZAT: Kísérleti beállítások! - Folytassa ahol abbahagyta + Folytassa ott, ahol bezárta a programot Új lap megnyitása - Megadott oldal(ak) megnyitása + Megadott mappák megnyitása Induláskor @@ -217,7 +217,7 @@ Tulajdonos mutatása a tulajdonságoknál - Preferencia + Működés Asztal @@ -229,7 +229,7 @@ Letöltések - Home + Kezdőoldal Zene @@ -238,7 +238,7 @@ Képek - Levétel az oldalsávról + Eltávolítás az oldalsávról Videók @@ -274,7 +274,7 @@ Megnyitás terminálban... - MD5Hash: + MD5 hash: Új @@ -328,10 +328,10 @@ Üdv a Files-ban! - Engedély Biztosítása + Engedély megadása - Kezdésként, engedély kell adnia a fájljai megjelenítéséhez. Ez meg fogja nyitni a Beállításokat ahol engedélyezheti. Amint befelyezte a lépést zárja be és nyissa meg újra a Files-t. + Kezdésként, engedélyt kell adnia a fájljai megjelenítéséhez. Ez meg fogja nyitni a Gépházat ahol ezt elvégezheti. Az engedély megadása és a Gépház bezárása után nyissa meg újra a Files-t. Fájlmappa @@ -340,13 +340,13 @@ Fájl - Írja be a fájl új nevét + Adja meg az elem új nevét - Írja be az új fájl nevét + Adja meg az elem új nevét - Név beállítása + Átnevezés Mégse @@ -370,10 +370,10 @@ Rendszer - Új Mappa + Új mappa - Üres mappa. + Ez a mappa üres. Vissza (Alt + Bal nyíl) @@ -391,10 +391,10 @@ Keresés - Több lehetpség + További lehetőségek - Tulajdonság + Tulajdonságok Attribútumok: @@ -406,19 +406,19 @@ Példa beállítások - Fájl ezzel a névvel már létezik ebben a mappában. + Ezzel a névvel már létezik elem ebben a mappában. - Új név készítése + Átnevezés - Fájl lecserélése + Felülírás/összefésülés - A fájl már létezik + Az elem már létezik - Beállítás zárolt háttérképként + Beállítás zárolási képernyő háttérként Nagy ikonok @@ -436,40 +436,40 @@ OK - Nem tudtuk törölni a fájlt + Nem sikerült törölni ezt az elemet - Hozzáférés Megtagadva + Hozzáférés megtagadva - Helyezze be a meghajtót a fájlhoz való hozzáfáráshez. + Helyezze be a meghajtót a fájlhoz való hozzáféréshez. Meghajtó leválasztva - Az elérni próbált fájl törölt, vagy át lett helyezve. + A fájl, amit próbál megnyitni, már nem található ezen a helyen. - A Fájl nem található + A fájl nem található - A fájl amit próbál megnézni, törölt, vagy át lett helyezve. + A fájl, amelynek az előnézetét próbálja betölteni, már nem található ezen a helyen. - A fájl amit próbál elérni, törölt, vagy át lett helyezve. + A mappa, amit próbál megnyitni, már nem található ezen a helyen. - Ön törölte a mappát? + Ön törölte ezt a mappát? - A fájl amelyet törölné jelenleg használatban van. + A törölni kívánt fájl jelenleg használatban van. A fájl használatban van - Próbálja újra + Újra OK @@ -508,22 +508,22 @@ Új lap - A kért művelet nem támogatott + Ez a művelet nem támogatott - {0} szabad a(z) {1}-ból/ből + Szabad hely: {0} / {1} Társítás - A fájlnév nem tartalmazhatja a következő karaktereket: \ / : * ? " < > | + A név nem tartalmazhatja a következő karaktereket: \ / : * ? " < > | OK - A fájlnév nem tartalmazhatja a következő karaktereket: \ / : * ? " < > | + A név nem tartalmazhatja a következő karaktereket: \ / : * ? " < > | Naplózás helyének megnyitása @@ -538,10 +538,10 @@ kijelölt elem - Elem + elem - Elem + elem Fájlok törlése @@ -556,19 +556,19 @@ Mappa kitűzése az oldalsávra - OK + Igen Mégse - Biztosan törölne minden elemet? + Biztosan véglegesen törölni szeretné ezeket az elemeket? Lomtár kiürítése - bit + bájt KB @@ -592,7 +592,7 @@ Futtatás rendszergazdaként - Tudjon meg többet a dátumok formátumáról + Tudjon meg többet a dátumformátumokról Feloldás @@ -601,13 +601,13 @@ Mégse - Írja be a jelszót a meghajtó feloldásához + Adja meg a jelszót a meghajtó feloldásához Jelszó - Ellenőrizze a jalszavat és próbálja újra. + Ellenőrizze a jelszót és próbálja újra. BitLocker hiba @@ -616,19 +616,19 @@ Tartalmaz: - {0:#,##0} Fájl, {1:#,##0} Mappa + {0:#,##0} fájl, {1:#,##0} mappa Futtatás másik felhasználóként - Minden típus {0}-ból/ból + {0} (mindegyik) Különböző típusok - Minden {0}-ból/ből + {0} (mindegyik) Foglalt: @@ -643,10 +643,10 @@ Fájlrendszer: - Legutóbbi + Előzmények - Program Nyelve + Alkalmazás nyelve Lap áthelyezése ide @@ -661,13 +661,13 @@ Oldalak: - Mindig új ablakban nyíljon meg + Új ablakban - Mappa megnyitása új lapon + Új lapon - Elem megnyitásakor a listáról + Elem előzménylistáról megnyitása Rendszer @@ -679,7 +679,7 @@ Egy megjeleníthető elem sem elérhető - Áthelyezés ide {0} + Áthelyezés ide: {0} A forrás- és a célfájlnév azonos. @@ -688,13 +688,13 @@ A forrás- és a célmappa azonos. - Másolás ide {0} + Másolás ide: {0} - Gyorsgomb létrehozása + Parancsikon létrehozása - Fájl tartalmazó mappa megnyitása + Fájlt tartalmazó mappa megnyitása Argumentumok: @@ -718,22 +718,22 @@ Mappa - Web link + Internet parancsikon Általános - Gyorsgomb + Parancsikon - Gyorsgomb + Parancsikon - Internet gyorsgomb + Internet parancsikon - {0} - gyorsgomb + {0} - parancsikon Fájlt tartalmazó mappa megnyitása @@ -745,10 +745,10 @@ Naplózás helyének megnyitása - Files egy problémába ütközött, amire a fejlesztők még nem készültek fel. + A Files egy problémába ütközött, amire a fejlesztők még nem készültek fel. - Valami elromlott! + Valami hiba történt! Hiba jelentése @@ -760,16 +760,16 @@ Akik hozzájárultak a Files-hoz - Verzió Jegyzet + Változások Újdonságok a Files-ban - A hivatkozott elem helytelen vagy elérhetetlen.{0}Hibaüzenet:{0}{1} + A hivatkozott elem érvénytelen vagy nem elérhető.{0}Hibaüzenet:{0}{1} - Helytelen fájl + Érvénytelen elem Verzió: @@ -778,10 +778,10 @@ Nincs mit megosztani... - A kijelölt fájlok meg lesznek osztva + A kijelölt elemek meg lesznek osztva - A kijelölt fájl meg lesz osztva + A kijelölt elem meg lesz osztva {0} megosztása @@ -790,25 +790,25 @@ {0} {1} megosztása - A fájl amit szeretne megnyitni már nem létezik. Ellenőrizze az átnevezendő fájl helyét. + Az elem, amit át szeretne nevezni már nem létezik. - A fájl már nem létezik + Az elem már nem létezik - A megadott fájlnév helytelen. Ellenőrizze és próbálja újra. + A megadott név helytelen. Ellenőrizze és próbálja újra! - Helytelen fájl név + Helytelen név - A fájlnév hossza elérte a maximumot. Ellenőrizze a nevet, és próbálja újra. + A név hosszabb, mint ami maximálisan megengedett. Kérjük válasszon rövidebb nevet! - Túl hosszú fájlnév + Túl hosszú név - Több + Továbbiak Nem @@ -817,7 +817,7 @@ Igen - A Files újraindítása szükséges a nyelv beállításához, szeretné újraindítani? + A Files újraindítása szükséges a nyelv beállítás érvénybe lépéséhez. Szeretné most újraindítani? Támogatás @@ -826,19 +826,19 @@ Támogatás PayPal-on - Nem tudtuk létrehozni a fájlt + Nem sikerült létrehozni a fájlt - Hozzáférés Megtagadva + Hozzáférés megtagadva Mégse - Biztosan szeretné törölni ezt a(z) {0} fájlt? + Biztosan törölni szeretne {0} fájlt? - Bizotsan törölné ezt az fájlt? + Bizotsan törölni szeretné a fájlt? Lap hozzáadása @@ -847,16 +847,16 @@ Lapok megnyitása - Automatikus (Ajánlott) + Automatikus (ajánlott) - A legjobb lehetőség kiválasztása az ablak méretétől függően. Amikor az ablak kicsi, a vízszintes lap lánc egy menüvé alakul navigációs sávban. + A legjobb lehetőség kiválasztása az ablak méretétől függően. Amikor az ablak kicsi, a vízszintes lap sáv egy menüelemmé alakul át. Vízszintes - Menü elrejtése a navigációs sávból, az eredeti vízszintes lap lánc használata. Felhasználóknak akik állandóan követnék az összes lapot. + Menüelem elrejtése, az eredeti vízszintes lap sáv használata. Olyan felhasználóknak, akik szeretik állandóan figyelemmel követni az összes megnyitott lapot. Multitaszking @@ -865,7 +865,7 @@ Függőleges - A vízszintes lap lánc egy menüvé alakul navigációs sávban, azoknak a felhasználóknak tervezve, akik egy letisztult felhasználói felületet szeretnének igény szerint a multitaszkingal. + A vízszintes lap sáv egy menüelemmé alakul át, azoknak a felhasználóknak tervezve, akik egy letisztult felhasználói felületet szeretnének, de a multitaszking lehetőségével. Multitaszking @@ -874,61 +874,61 @@ Beállítás mint - Hely másolása + Elérési út másolása Mégse - Új elem készítése + Új elem létrehozása - Válasszon fájltípust az alábbiak közűl + Válasszon típust az alábbiak közül Mappa - Új mappa készítése + Új mappa létrehozása Elrendezés - Navigálás hátra + Vissza navigálás - Navigálás előre + Előre navigálás Könyvtár frissítése - Vissza egy mappával + Egy szinttel feljebb - Függőleges lap lánc + Függőleges lap lista - Program Nyelve + Alkalmazás nyelve - Parancssor Alkalmazások + Terminál alkalmazások - Parancssor alkalmazások szerkeztése + Terminál alkalmazások módosítása - Parancssor alkalmazások szerkeztése + Terminál alkalmazások módosítása Példa beeállítások - App Nyelve + Alkalmazás nyelve - Parancssor Programok + Terminál alkalmazások Lomtár kitűzése az oldalsávra @@ -937,31 +937,31 @@ Megerősítő üzenet fájlok vagy mappák törlésekor - Parancssor Programok + Terminál alkalmazások - Több lehetőség + További lehetőségek Kijelölési lehetőségek - Állapot központ + Állapotközpont Elemek megnyitása egy kattintással - Ide + Áthelyezés ide Meghajtók - Könyvtárak megjelenítése a fő oldalon + Könyvtárak megjelenítése a kezdőoldalon - Könyvtárak megjelenítése a fő oldalon + Könyvtárak megjelenítése a kezdőoldalon Widgetek @@ -970,16 +970,16 @@ Widgetek - Meghajtók megjelenítése a fő oldalon + Meghajtók megjelenítése a kezdőoldalon - Meghajtók megjelenítése a fő oldalon + Meghajtók megjelenítése a kezdőoldalon - Legutóbb megnyitottak megjelenítése a fő oldalon + Előzmények megjelenítése a kezdőoldalon - Legutóbbi megnyitottak megjelenítése a fő oldalon + Előzmények megjelenítése a kezdőoldalon Fájl @@ -991,7 +991,7 @@ Lomtár elem - Gyorsgomb elem + Parancsikon elem Rejtett fájlok és mappák mutatása @@ -1000,22 +1000,22 @@ Rejtett fájlok és mappák mutatása - A hardware eltávolítása biztonságos + Eszköz kiadása Az eszköz biztonságosan eltávolítható. - Hiba az eszköz kiadása közben + Hiba történt az eszköz kiadása közben - Az eszköz jelenleg használatban van. Zárjon be minden programot, ablakot ami használhatja, majd próbálja újra. + Az eszköz jelenleg használatban van. Zárjon be minden programot, ablakot vagy oldalt, ami használhatja, majd próbálja újra. Kiadás - Lap kettőzése + Lap megkettőzése Lap áthelyezése új ablakba @@ -1027,7 +1027,7 @@ Keresés - Csak olvasható + Írásvédett Rejtett @@ -1036,13 +1036,13 @@ Minősítés - Elem típusa + Típus Cím - Téma + Tárgy Megjegyzés @@ -1078,28 +1078,28 @@ Színtér - Szélesség (egész) + GPS szélesség (egész) - Magasság (egész) + GPS magasság (egész) - Szélesség + GPS szélesség - Magasság + GPS magasság - Szélesség Ref + GPS szélesség ref - Magasság Ref + GPS magasság ref - Magasság + GPS magasság - Létrehozás dátuma + Készítés dátuma Fényképezőgép gyártója @@ -1116,12 +1116,21 @@ Rekesz + + Megjelenő személyek + Csatornák száma Formátum + + Mintavételi ráta + + + Előadó + Album előadója @@ -1132,13 +1141,13 @@ Előadó - Ütem Per Perc + Ütem / perc Zeneszerző - Zeneszerző + Karmester Lemez száma @@ -1155,11 +1164,20 @@ Képkockák száma + + Védelem típusa + + + Szerző URL + + + Tartalomszolgáltató + Megjelenés dátuma - Adatsor neve + Sorozat Évad @@ -1213,10 +1231,10 @@ Nyomtatás dátuma - Teljes szerkeztési idő + Teljes szerkesztési idő - Minta + Sablon Szavak száma @@ -1231,13 +1249,16 @@ Bekezdések száma - Lapok száma + Oldalak száma + + + Diák száma - Képkockák sebessége + Képkockasebesség - Bitráta kódolása + Kódolási bitráta Tömörítés @@ -1252,7 +1273,7 @@ Tájolás - Leírás + Alap információk Kép @@ -1279,7 +1300,7 @@ Dokumentum - Elérhetőség + Cím Hiba @@ -1294,16 +1315,16 @@ Mégse - Probléma adódott a tulajdonságok mentésekor. + Probléma adódott a tulajdonságok mentése közben. - Pár tulajdonság tartalmazhat személyes információt. + Némelyik tulajdonság személyes adatokat tartalmazhat. - Clear + Eltávolítás - Összes tulajdonság törlése + Mindegyik tulajdonság eltávolítása sRGB @@ -1315,7 +1336,7 @@ Itt ellenőrizheti a fájlműveletek állapotát - Állapotsor + Állapotközpont Licenc @@ -1330,13 +1351,13 @@ Weboldal - Tudjon meg többet a dátumokról + Tudjon meg többet a dátumformátumokról - Másolás ide + Engedje el itt - Keresés eredménye a következőben: + Keresés eredménye itt: Keresési eredmények @@ -1363,7 +1384,7 @@ Nem - Szeretné letőlteni és telepíteni a legújabb Files verziót? + Szeretné letölteni és telepíteni a Files legújabb verzióját? Igen @@ -1372,10 +1393,10 @@ Frissítés elérhető - Védett operációs rendszer fájlok elrejtése (Ajánlott) + Védett operációs rendszer fájlok elrejtése (ajánlott) - Védett operációs rendszer fájlok elrejtése (Ajánlott) + Védett operációs rendszer fájlok elrejtése (ajánlott) Fájl @@ -1384,19 +1405,19 @@ Fájl - Létrehoz egy üres fájlt + Üres fájl létrehozása - Új Fájl + Új fájl - Egyedi preferencia minden egyes mappához + Egyedi beállítások megjegyzése minden mappához - Eredeti elérési út: + Eredeti elérési út - Eredeti elérési út: + Eredeti elérési út Hozzáadás @@ -1408,49 +1429,49 @@ Törlés - Fájlok és mappák gyorsítótárba való helyezése a jobb teljesítményért + Fájlok és mappák gyorsítótárazása a jobb teljesítményért Mégse - Feladatok folyamatban + Folyamatban lévő műveletek - Feladatok folyamatban + Folyamatban lévő műveletek - Mindig kettős nézetben nyissa meg az új lapokat + Mindig osztott nézetben nyissa meg az új lapokat - Kettős panel bekapcsolása + Osztott nézet bekapcsolása - Megnyitás második panelben + Megnyitás a jobb oldali panelen Új panel - Megnyitás második panelben + Megnyitás a jobb oldali panelen - Kettós panel + Osztott nézet Nem indexelt elemek mutatása fájl és mappa keresésekor (hosszabb keresési idő) - Hely másolása elem megjelenítése + "Elérési út másolása" elem megjelenítése Ki nem férő elemek almenübe helyezése - Menü testreszabása + Helyi menü testreszabása - Megnyitás új oldalon elem megjelenítése + "Megnyitás új oldalon" elem megjelenítése Mappák @@ -1498,7 +1519,7 @@ Lista - Fájlkiterjesztések mutatása + Fájl kiterjesztések megjelenítése Rejtett fájlok megjelenítése @@ -1516,67 +1537,67 @@ Lap testreszabása - Files indulásakor + A Files indulásakor - Elem elérési útja + Elérési út - Váltás előnézetre (Ctrl + P) + Előnézet panel (Ctrl + P) - Elem neve + Név - Megerősítés + Létrehozás - Csomag ezzel a névvel már létezik! + Már létezik munkaterület ezzel a névvel! A mező nem lehet üres! - Csomag neve + Munkaterület neve - Csomag neve + Munkaterület neve Mégse - Új név + Név - Megerősítés + Átnevezés - Írja be az új nevet + Adja meg az új nevet - "{0} átnevezése" + "{0}" átnevezése Mégse - Csomag neve + Munkaterület neve - Megerősítés + Létrehozás - Új Csomag + Új munkaterület - Csomagok Exportálása + Munkaterületek exportálása - Csomagok Importálása + Munkaterületek importálása - Csomag létrehozása + Munkaterület létrehozása Megnyitás új lapon @@ -1585,34 +1606,34 @@ Elem helyének megnyitása - Eltávolítás a csomagból + Eltávolítás a munkaterületről - Csomag eltávolítása + Munkaterület eltávolítása - Csomagok + Munkaterületek Húzza ide a fájlokat és mappákat a gyors elérésükhöz - Megerősítés + Létrehozás - Írja be az csomag nevét + Adja meg a munkaterület nevét - Csomag létrehozása + Munkaterület létrehozása - Csomag átnevezése + Munkaterület átnevezése - Több lehetőség... + További lehetőségek... - Csomag létrehozása + Munkaterület létrehozása Felhőtárhely @@ -1621,23 +1642,35 @@ Nincs elérhető előnézet - Nincs elérhető részlet + Nincsenek elérhető részletek - Csomagok megjelenítése a fő oldalon + Munkaterületek megjelenítése a kezdőoldalon - Könyvtár levétele az oldalsávról + Levétel az oldalsávról + + + Folyamatban lévő műveletek panel - Online állapotban elérhető + Online elérhető - Offline állapotban is elérhető + Offline is elérhető + + + Offline részben elérhető Szinkronizálás + + Kizárva a szinkronizálásból + + + Nem meghatározott + Ismeretlen @@ -1665,4 +1698,13 @@ Adaptív előnézeti panel engedélyezése + + Több elem kijelölése + + + Többszörös kijelőlés (jelenleg lista és ikon nézetekben elérhető) + + + Ha a fájlnév kiterjesztését módosítja, akkor a fájl használhatatlanná válhat. Végrehajtja a módosítást? + \ No newline at end of file diff --git a/Files/Strings/ja-JP/Resources.resw b/Files/Strings/ja-JP/Resources.resw index 141198612b7a..a03a00bc726b 100644 --- a/Files/Strings/ja-JP/Resources.resw +++ b/Files/Strings/ja-JP/Resources.resw @@ -778,7 +778,7 @@ {0} {1} を共有しています - 名前を変更しようとしている項目はもう存在しません。 名前を変更する必要がある項目の正しい場所を確認してください。 + 名前を変更しようとしている項目は既に存在しません。 名前を変更する必要がある項目の正しい場所を確認してください。 項目はもうなくなりました @@ -832,7 +832,7 @@ マルチタスク - に設定 + 背景に設定 場所をコピーする @@ -856,7 +856,7 @@ 新しい項目の作成 - 以下でこの新しい項目の種類を選択してください + 以下で新しい項目の種類を選択してください キャンセル @@ -1182,6 +1182,9 @@ プロモーション URL + + プロバイダースタイル + 発行元 @@ -1365,6 +1368,9 @@ PayPal で私たちを支援してください + + ファイルとディレクトリを一緒に並べ替える + 詳細 @@ -1431,6 +1437,9 @@ 進行中の処理 + + 新しいタブを常にデュアル ペイン表示で開く + デュアル ペイン表示を有効にする @@ -1446,13 +1455,247 @@ デュアル ペイン + + 「ファイルの場所をコピー」のメニューを表示 + + + 右クリックメニューの一部をサブメニューに移動する + 右クリックメニューをカスタマイズする + + 「ファイルを新しいタブで開く」のメニューを表示 + フォルダ コンテキスト メニューを開いたり閉じたりするときのアニメーションを有効にする + + 詳細ビュー + + + グリッドビュー (大) + + + グリッドビュー (中) + + + グリッドビュー (小) + + + タイルビュー + + + レイアウトモード + + + 表示オプション + + + 表示オプション + + + 表示オプション + + + グリッドビュー (大) + + + グリッドビュー (中) + + + グリッドビュー (小) + + + タイルビュー + + + 拡張子を表示 + + + 隠しファイルを表示 + + + 詳細ビュー + + + 削除した日時 + + + 削除した日時 + + + タブのカスタマイズ + + + 起動時の設定 + + + 確定 + + + 同じ名前のバンドルが既に存在しています! + + + 入力フィールドが空欄です! + + + バンドル名を入力 + + + バンドル名を入力 + + + キャンセル + + + 新しい名前 + + + 確定 + + + 新しい名前を入力 + + + "{0}"の名前を変更 + + + キャンセル + + + 新しい名前 + + + 確定 + + + バンドルを追加 + + + バンドルをエクスポート + + + バンドルをインポート + + + バンドルを作成 + + + 新しいタブで開く + + + ファイルの場所を開く + + + バンドルから削除 + + + バンドルを削除 + + + バンドル + + + ファイルやフォルダをここにドラッグして追加 + + + 確定 + + + バンドル名を入力 + + + バンドルを作成 + + + バンドル名を変更 + + + 詳細設定... + + + バンドルを作成 + + + ファイルのパス + + + プレビューペインの表示/非表示切替(Ctrl + P) + + + ファイル名 + + + クラウドドライブ + + + プレビュー利用不可 + + + 詳細利用不可 + + + ホームにバンドルを表示 + + + フォルダをサイドバーから外す + + + プロパティ + + + ファイルの詳細 + + + ファイルのプレビュー + + + 選択したファイルのプレビュー + + + ドキュメンテーション + + + Filesを使いこなす秘訣を学ぶ + + + Filesの資料ページを表示 + + + 進行中のタスクのフライアウト + + + オンラインで利用可能 + + + オフラインで利用可能 + + + 部分的にオフラインで利用可能 + + + 同期中 + + + 同期から除外済 + + + 未計測 + + + 不明 + + + アダプティブ プレビュー ペインを有効にする + + + 複数選択 + + + 複数選択を有効にする(現在タイルビューとグリッドビューのみで利用可能) + \ No newline at end of file diff --git a/Files/Strings/pl-PL/Resources.resw b/Files/Strings/pl-PL/Resources.resw index d24c8b23b19d..24d3eeba465d 100644 --- a/Files/Strings/pl-PL/Resources.resw +++ b/Files/Strings/pl-PL/Resources.resw @@ -211,7 +211,7 @@ Właściwości - Szybki podgląd + QuickLook Nowe okno @@ -538,7 +538,7 @@ Anuluj - Czy na pewno chcesz usunąć wszystkie elementy? + Czy na pewno chcesz trwale usunąć wszystkie elementy? Opróżnij Kosz @@ -955,7 +955,7 @@ Plik - Skoroszyt + Folder Element Kosza @@ -1420,10 +1420,10 @@ Włącz indywidualne preferencje dla poszczególnych katalogów - Oryginalna ścieżka: + Oryginalna ścieżka - Oryginalna ścieżka: + Oryginalna ścieżka Dodaj @@ -1536,4 +1536,175 @@ Data usunięcia + + Dostosowywanie kart + + + Podczas uruchamiania Files + + + Zatwierdź + + + Paczka z tą samą nazwą już istnieje! + + + Pole tekstowe nie może być puste! + + + Wprowadź nazwę Paczki + + + Wprowadź nazwę Paczki + + + Anuluj + + + Żądana nazwa + + + Zatwierdź + + + Wprowadź nową nazwę + + + Zmień nazwę "{0}" + + + Anuluj + + + Żądana nazwa + + + Zatwierdź + + + Dodaj Paczkę + + + Eksportuj Paczki + + + Importuj Paczki + + + Utwórz nową Paczkę + + + Otwórz w nowej karcie + + + Otwórz lokację pliku + + + Usuń z Paczki + + + Usuń Paczkę + + + Paczki + + + Przeciągnij dowolny plik lub folder, aby szybko uzyskać do niego dostęp + + + Zatwierdź + + + Wprowadź nazwę Paczki + + + Utwórz nową Paczkę + + + Zmień nazwę Paczki + + + Więcej opcji... + + + Utwórz nową Paczkę + + + Ścieżka elementu + + + Przełącz panel podglądu (Ctrl + P) + + + Nazwa elementu + + + Dyski w chmurze + + + Podgląd niedostępny + + + Brak dostępnych szczegółów + + + Pokaż Paczki na strone głównej + + + Odepnij katalog od paska bocznego + + + Właściwości + + + Szczegóły pliku + + + Podgląd pliku + + + Panel podglądu wybranego pliku + + + Dokumentacja + + + Znajdź wskazówki i dowiedz się więcej o Files + + + Odwiedź witrynę z dokumentacją Files + + + Menu bieżących zadań + + + Dostępne w trybie Online + + + Dostępne w trybie Offline + + + Częściowo dostępne w trybie Offline + + + Synchronizowanie + + + Wykluczone z synchronizacji + + + Nie obliczone + + + Nieznane + + + Włącz adaptacyjny panel podglądowy + + + Wielokrotne zaznaczanie + + + Włacz opcję wielokrotnego zaznaczania (obecnie dostępne tylko w trybach układu kafelek i siatki) + \ No newline at end of file diff --git a/Files/Strings/sv-SE/Resources.resw b/Files/Strings/sv-SE/Resources.resw new file mode 100644 index 000000000000..b4a2e90f8607 --- /dev/null +++ b/Files/Strings/sv-SE/Resources.resw @@ -0,0 +1,1716 @@ + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Radera objekt + + + Avbryt + + + Ta bort + + + Ta bort permanent + + + Öppna i ny flik + + + Öppna i nytt fönster + + + Ny flik + + + Nytt fönster + + + Mapp + + + Bitmappsbild + + + Textdokument + + + Kopiera sökväg + + + Klistra in + + + Enheter + + + Namn + + + Senast ändrad + + + Typ + + + Storlek + + + Öppna i Terminal... + + + Skapad: + + + Filnamn + + + Sökväg: + + + Storlek: + + + Denna åtgärd kan inte utföras + + + Målmappen + + + är en undermapp till källmappen + + + Hoppa över + + + Avbryt + + + Objekttyp: + + + Markera alla + + + Invertera markering + + + Rensa markering + + + Detaljerad lista + + + Ändrad: + + + Använd: + + + Ägare: + + + Rensa alla objekt + + + Ange en sökväg + + + Sök + + + Filer som du använt tidigare kommer att visas här + + + Öppna filsökväg + + + Ta bort det här objektet + + + Senaste objekt + + + Files + + + Skicka feedback + + + Skicka en felrapport med detaljerad information till utvecklarna + + + Tredjepartslicenser + + + Om + + + Genomskinligt sidofält + + + Datumformat + + + Apptema + + + Utseende + + + Visa filnamnstillägg för kända filtyper + + + Visa dolda filer och mappar + + + Visa dolda filer och mappar + + + Filer och mappar + + + Experimentellt + + + Senast ändrad + + + Om + + + Utseende + + + Experimentellt + + + Filer och mappar + + + Vid start + + + Alternativ + + + VARNING: FÖLJANDE FUNKTIONER ÄR EXPERIMENTELLA! + + + Fortsätt där du slutade + + + Öppna en ny flik + + + Öppna en specifik sida eller specifika sidor + + + Vid start + + + Visa ägare i egenskaper + + + Alternativ + + + Skrivbord + + + Dokument + + + Hämtade filer + + + Startsida + + + Musik + + + Bilder + + + Lossa från sidofältet + + + Filmer + + + Sortera efter + + + Namn + + + Senast ändrad + + + Typ + + + Storlek + + + Stigande + + + Fallande + + + Uppdatera + + + Klistra in + + + Öppna i Terminal... + + + MD5Hash: + + + Nytt + + + Mapp + + + Fil + + + Egenskaper + + + Egenskaper + + + Extrahera + + + Öppna + + + Öppna i ny flik + + + Öppna i nytt fönster + + + Använd som skrivbordsbakgrund + + + Dela + + + Klipp ut + + + Kopiera + + + Ta bort + + + Byt namn + + + Fäst på sidofältet + + + Egenskaper + + + QuickLook + + + Välkommen till Files! + + + Bevilja behörighet + + + För att komma igång behöver du bevilja behörighet till oss att visa dina filer. En sida kommer att öppnas i Inställningar där du kan bevilja behörigheten. Du behöver starta om appen efter att du har gjort detta. + + + Filmapp + + + Fil + + + Ange ett namn för objektet + + + Ange ett namn för objektet + + + Tillämpa namn + + + Avbryt + + + Ny flik + + + Windows-standard + + + Ljust + + + Mörkt + + + App + + + System + + + Ny mapp + + + Ny fil + + + Denna mapp är tom. + + + Tillbaka (Alt + Vänsterpil) + + + Framåt (Alt + Högerpil) + + + Upp en nivå (Alt + Uppåtpil) + + + Uppdatera (F5) + + + Sök + + + Fler alternativ + + + Egenskaper + + + Attribut: + + + Egenskaper + + + Visa exempelprofiler + + + Det finns redan ett objekt med samma namn på den här platsen. + + + Generera nytt namn + + + Ersätt existerande objekt + + + Objektet finns redan. + + + Använd som låsskärmsbakgrund + + + Rutnätsvy (Stor) + + + Rutnätsvy (Medel) + + + Rutnätsvy (Liten) + + + Panelvy + + + OK + + + Vi kunde inte ta bort det här objektet + + + Åtkomst nekad + + + Vänligen sätt i enheten som krävs för att komma åt det här objektet. + + + Enhet frånkopplad + + + Filen som du försöker komma åt kan ha flyttats eller tagits bort. + + + Filen hittades inte + + + Filen som du försöker förhandsgranska kan ha flyttats eller tagits bort. + + + Mappen som du försöker komma åt kan ha flyttats eller tagits bort. + + + Tog du bort den här mappen? + + + Filen som du försöker ta bort används av ett annat program. + + + Filen används + + + Försök igen + + + OK + + + Layoutläge + + + Markeringsalternativ + + + Skrivskyddad + + + Dold + + + Töm papperskorgen + + + Återställ + + + {0} dagar sedan + + + {0} dag sedan + + + {0} timmar sedan + + + {0} timme sedan + + + {0} minuter sedan + + + {0} minut sedan + + + {0} sekunder sedan + + + Ny flik + + + Den begärda åtgärden stöds inte. + + + {0} ledigt av {1} + + + Öppna med + + + Filnamn kan inte innehålla något av följande tecken: \ / : * ? " < > | + + + OK + + + Filnamn kan inte innehålla något av följande tecken: \ / : * ? " < > | + + + Öppna loggplats + + + Ny flik (Ctrl + T) + + + objekt markerat + + + objekt markerade + + + objekt + + + objekt + + + Tar bort filer + + + Klistrar in filer + + + Flyttar filer till Papperskorgen + + + Fäst mapp på sidofältet + + + Ja + + + Avbryt + + + Vill du radera alla dessa objekt permanent? + + + Töm papperskorgen + + + byte + + + KB + + + MB + + + GB + + + TB + + + PB + + + B + + + Kör som administratör + + + Läs mer om datumformat + + + Lås upp + + + Avbryt + + + Ange lösenord för att låsa upp enheten + + + Lösenord + + + Vänligen kontrollera lösenordet och försök igen. + + + BitLocker-fel + + + Innehåller: + + + {0:#,##0} filer, {1:#,##0} mappar + + + Kör som en annan användare + + + Allt med typen {0} + + + Olika typer + + + Allt i {0} + + + Använt utrymme: + + + Ledigt utrymme: + + + Kapacitet: + + + Filsystem: + + + Senaste + + + Appspråk + + + Flytta flik hit + + + Status + + + Lägg till en ny sida + + + Sidor: + + + Öppna alltid en ny instans + + + Öppna mapp i en ny flik + + + När ett objekt öppnas från Start-menyn eller aktivitetsfältet + + + Windows-standard + + + Inga sökresultat + + + Kan inte komma åt några objekt att visa + + + Flytta till {0} + + + Källa och mål har samma namn. + + + Målmappen är samma som källmappen. + + + Kopiera till {0} + + + Skapa genväg + + + Öppna filsökväg + + + Argument: + + + Mål + + + Genvägstyp: + + + Starta i: + + + Program + + + Fil + + + Mapp + + + Webblänk + + + Allmänt + + + Genväg + + + Genväg + + + Internetgenväg + + + {0} - genväg + + + Öppna filsökväg + + + Okänd + + + Öppna loggplats + + + Files stötte på ett problem som utvecklarna inte ännu var förberedda för. + + + Något gick fel! + + + Rapportera det här problemet + + + Medarbetare + + + Se vilka som bidragit till Files + + + Uppdateringslogg + + + Se vad som är nytt i Files + + + Det hänvisade objektet är antingen ogiltigt eller oåtkomligt.{0}Felmeddelande:{0}{1} + + + Ogiltigt objekt + + + Version: + + + Det finns inget att dela just nu... + + + De valda objekten kommer att delas + + + Det valda objektet kommer att delas + + + Delar {0} + + + Delar {0} {1} + + + Objektet du försöker byta namn på finns inte längre. Kontrollera rätt plats för objektet du behöver byta namn på. + + + Objektet finns inte längre + + + Det angivna namnet var ogiltigt. Vänligen kontrollera önskat filnamn och försök igen. + + + Ogiltigt filnamn + + + Längden på det angivna filnamnet överskrider maxgränsen. Kontrollera önskat namn och försök igen. + + + Filnamnet är för långt + + + Mer + + + Nej + + + Ja + + + Appen måste startas om för att tillämpa språkinställningen. Vill du starta om appen? + + + Stöd oss + + + Stöd oss på PayPal + + + Vi kunde inte skapa det här objektet + + + Åtkomst nekad + + + Avbryt + + + Vill du radera dessa {0} objekt? + + + Vill du radera det här objektet? + + + Lägg till flik + + + Öppna flikar + + + Adaptiv (Rekommenderas) + + + Väljer den bästa multitasking-kontrollen baserat på hur appfönstrets storlek. När fönstret är litet kommer det horisontella flikfältet kollapsas till ett popup-fönster i navigeringsfältet. + + + Horisontell + + + Döljer alltid det vertikala popup-fönstret för multitasking från navigeringsfältet och visar det traditionella horisontella flikfältet i appfönstret. Detta är lämpligt för användare som alltid behöver hålla reda på alla öppna appinstanser. + + + Multitasking + + + Vertikal + + + Komprimerar den horisontella listan över appinstanser till ett vertikalt popup-fönster i navigeringsfältet. Utformat för användare som vill ha ett rent appgränssnitt med tillgång till en multitasking-upplevelse på begäran. + + + Multitasking + + + Använd som + + + Kopiera sökväg + + + Avbryt + + + Skapa ett nytt objekt + + + Välj en objekttyp nedan + + + Fil + + + Skapar en tom fil + + + Mapp + + + Skapar en tom mapp + + + Layoutläge + + + Navigera bakåt + + + Navigera framåt + + + Uppdatera mappen + + + Upp en nivå + + + Vertikalt flikfält + + + Appspråk + + + Terminal-appar + + + Redigera terminal-appar + + + Redigera terminal-appar + + + Visa exempelprofiler + + + Appspråk + + + Terminal-appar + + + Visa menyalternativet 'kopiera sökväg' + + + Flytta överflödesobjekt till en undermeny + + + Fäst Papperskorgen på sidofältet + + + Visa en bekräftelsedialog när du tar bort filer eller mappar + + + Terminal-appar + + + Det uppstod problem med att spara vissa egenskaper. + + + Fel + + + Försök igen + + + Stäng ändå + + + Avbryt + + + Klassificering + + + Objektsökväg + + + Objekttyp + + + Titel + + + Ämne + + + Kommentar + + + Copyright + + + Senast ändrad + + + Bitdjup + + + Bildstorlek + + + Vågrät storlek + + + Lodrät storlek + + + Vågrät upplösning + + + Lodrät upplösning + + + Komprimering + + + Färgrymd + + + sRGB + + + Ej angivet + + + Longitud decimal + + + Latitud decimal + + + Latitud + + + Longitud + + + Latitud ref + + + Longitud ref + + + Altitud + + + Fotodatum + + + Kameratillverkare + + + Kameramodell + + + Exponeringstid + + + Brännvidd + + + Bländartal + + + Personnamn + + + Antal kanaler + + + Format + + + Samplingshastighet + + + Artist + + + Albumartist + + + Album + + + Artist + + + Slag per minut + + + Kompositör + + + Dirigent + + + Skivnummer + + + Genre + + + Låtnummer + + + Längd + + + Antal bildrutor + + + Typ av skydd + + + Författar-URL + + + Innehållsdistributör + + + Utgivningsdatum + + + Serienamn + + + Säsongsnummer + + + Avsnittsnummer + + + Producent + + + Kampanj-URL + + + Leverantörsstil + + + Utgivare + + + Sökväg till stor miniatyr + + + URI för stor miniatyr + + + Sökväg till liten miniatyr + + + URI för liten miniatyr + + + Användar-URL + + + Skribent + + + År + + + Medarbetare + + + Senaste författare + + + Versionsnummer + + + Version + + + Skapad den + + + Sparad den + + + Tryckdatum + + + Total redigeringstid + + + Mall + + + Antal ord + + + Antal tecken + + + Antal rader + + + Antal stycken + + + Antal sidor + + + Antal bilder + + + Bildfrekvens + + + Bithastighet + + + Komprimering + + + Bildrutebredd + + + Bildrutehöjd + + + Orientering + + + Fil + + + Bild + + + Foto + + + GPS + + + Media + + + Ljud + + + Musik + + + Video + + + Dokument + + + Adress + + + Fler alternativ + + + Markeringsalternativ + + + Statuscenter + + + Öppna objekt med ett enda klick + + + Fil + + + Mapp + + + Objekt i Papperskorgen + + + Genvägsobjekt + + + Enheter + + + Flytta hit + + + Widgetar + + + Visa enheter på startsidan + + + Visa enheter på startsidan + + + Visa kort med biblioteksmappar på startsidan + + + Visa kort med biblioteksmappar på startsidan + + + Visa senaste filer på startsidan + + + Visa senaste filer på startsidan + + + Widgetar + + + Säker att ta bort hårdvara + + + Enheten kan nu säkert tas bort från datorn. + + + Problem vid enhetsutmatning + + + Enheten används för närvarande. Stäng alla program, fönster eller flikar som kan använda enheten och försök sedan igen. + + + Mata ut + + + Duplicera flik + + + Flytta flik till nytt fönster + + + Ny flik + + + Vissa egenskaper kan innehålla personlig information. + + + Rensa + + + Rensa alla egenskaper + + + Kontrollera status för filåtgärder här + + + Statuscenter + + + Licens + + + Licens + + + Webbplats + + + Webbplats + + + Läs mer om datumformat + + + Släpp här + + + Sök + + + Sökresultat i + + + Sökresultat + + + Se vilka som bidragit till Files + + + Se vad som är nytt i Files + + + Skicka en felrapport med vidare information till utvecklarna + + + Stöd oss på PayPal + + + Visa och sortera mappar tillsammans med filer istället för avskilt + + + Information + + + Nej + + + Vill du ladda ner och installera den senaste versionen av Files? + + + Ja + + + Uppdateringar är tillgängliga + + + Dölj skyddade operativsystemfiler (rekommenderas) + + + Dölj skyddade operativsystemfiler (rekommenderas) + + + Aktivera flexibelt förhandsgranskningsfönster + + + Visa oindexerade objekt när du söker efter filer och mappar (sökningar kan ta längre tid) + + + Använd individuella inställningar för varje mapp + + + Anpassa högerklicksmenyn + + + Ursprunglig plats + + + Ursprunglig plats + + + Lagra filer och mappar i cache för bättre prestanda + + + Lägg till + + + Redigera + + + Ta bort + + + Avbryt + + + Pågående åtgärder + + + Pågående åtgärder + + + Öppna alltid nya flikar med dubbla paneler + + + Aktivera vy med dubbla paneler + + + Öppna i sekundär panel + + + Ny panel + + + Öppna i sekundär panel + + + Dubbla paneler + + + Visa menyalternativet 'öppna i ny flik' + + + Mappar + + + Aktivera animationer när högerklicksmenyn öppnas och stängs + + + Detaljvy + + + Detaljvy + + + Visningsalternativ + + + Visningsalternativ + + + Visningsalternativ + + + Rutnätsvy (Stor) + + + Rutnätsvy (Stor) + + + Rutnätsvy (Medel) + + + Rutnätsvy (Medel) + + + Rutnätsvy (Liten) + + + Rutnätsvy (Liten) + + + Panelvy + + + Panelvy + + + Visa filnamnstillägg + + + Visa dolda objekt + + + Borttagningsdatum + + + Borttagningsdatum + + + Flikanpassning + + + När Files startas + + + Molnenheter + + + Fler alternativ... + + + Bekräfta + + + Exportera samlingar + + + Importera samlingar + + + Det finns redan en samling med samma namn! + + + Inmatningsfältet får inte vara tomt! + + + Skapa samling + + + Ange namn för samlingen + + + Ange namn för samlingen + + + Öppna i ny flik + + + Öppna sökväg + + + Ta bort från samling + + + Ta bort samling + + + Samlingar + + + Dra och släpp valfri fil eller mapp hit för snabb åtkomst + + + Bekräfta + + + Ange namn för samlingen + + + Avbryt + + + Önskat namn + + + Bekräfta + + + Ange ett nytt namn + + + Byt namn på "{0}" + + + Skapa samling + + + Avbryt + + + Bekräfta + + + Lägg till samling + + + Skapa samling + + + Byt namn på samling + + + Önskat namn + + + Växla förhandsgranskningsfönstret (Ctrl + P) + + + Ingen förhandsgranskning tillgänglig + + + Ingen information tillgänglig + + + Filnamn + + + Visa samlingar på startsidan + + + Lossa mapp från sidofältet + + + Filinformation + + + Filförhandsgranskning + + + Förhandsgranskningsfönster för vald fil + + + Dokumentation + + + Hitta tips & tricks och läs mer om Files + + + Visa Files dokumentationssida + + + Popup-fönster för pågående åtgärder + + + Tillgänglig när du är online + + + Tillgänglig offline + + + Delvis tillgänglig offline + + + Synkroniserar + + + Undantagen från synkronisering + + + Inte beräknat + + + Okänd + + + Markera flera + + + Aktivera alternativ vid val av flera filer (för närvarande endast tillgängligt i panel- och rutnätsvyerna) + + \ No newline at end of file diff --git a/Files/UserControls/FilePreviews/ImagePreview.xaml b/Files/UserControls/FilePreviews/ImagePreview.xaml index 5319c765411f..5f5fab73c98c 100644 --- a/Files/UserControls/FilePreviews/ImagePreview.xaml +++ b/Files/UserControls/FilePreviews/ImagePreview.xaml @@ -10,6 +10,8 @@ mc:Ignorable="d"> - + + + \ No newline at end of file diff --git a/Files/UserControls/NavigationToolbar.xaml.cs b/Files/UserControls/NavigationToolbar.xaml.cs index da2305ed35d9..f15f7bb50e27 100644 --- a/Files/UserControls/NavigationToolbar.xaml.cs +++ b/Files/UserControls/NavigationToolbar.xaml.cs @@ -645,7 +645,10 @@ private async void Button_PointerEntered(object sender, PointerRoutedEventArgs e await Task.Delay(1000); if (!cancelFlyoutOpen) { - (sender as Button).Flyout.ShowAt(sender as Button); + if (sender != null) + { + (sender as Button).Flyout.ShowAt(sender as Button); + } cancelFlyoutOpen = false; } else @@ -677,12 +680,18 @@ private void Button_Tapped(object sender, TappedRoutedEventArgs e) private void Flyout_Opened(object sender, object e) { - VisualStateManager.GoToState(VerticalTabStripInvokeButton, "PointerOver", false); + if (VerticalTabStripInvokeButton != null) + { + VisualStateManager.GoToState(VerticalTabStripInvokeButton, "PointerOver", false); + } } private void Flyout_Closed(object sender, object e) { - VisualStateManager.GoToState(VerticalTabStripInvokeButton, "Normal", false); + if (VerticalTabStripInvokeButton != null) + { + VisualStateManager.GoToState(VerticalTabStripInvokeButton, "Normal", false); + } } private void VerticalTabStripInvokeButton_DragEnter(object sender, DragEventArgs e) @@ -701,10 +710,13 @@ private async void VerticalTabs_PointerExited(object sender, PointerRoutedEventA cancelFlyoutAutoClose = false; VerticalTabs.PointerEntered += VerticalTabs_PointerEntered; await Task.Delay(1000); - VerticalTabs.PointerEntered -= VerticalTabs_PointerEntered; + if (VerticalTabs != null) + { + VerticalTabs.PointerEntered -= VerticalTabs_PointerEntered; + } if (!cancelFlyoutAutoClose) { - VerticalTabViewFlyout.Hide(); + VerticalTabViewFlyout?.Hide(); } cancelFlyoutAutoClose = false; } @@ -786,6 +798,13 @@ private async void PathBoxItem_DragOver(object sender, DragEventArgs e) deferral.Complete(); return; } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, ex.Message); + e.AcceptedOperation = DataPackageOperation.None; + deferral.Complete(); + return; + } if (!storageItems.Any(storageItem => storageItem.Path.Replace(pathBoxItem.Path, string.Empty). @@ -806,6 +825,8 @@ private async void PathBoxItem_DragOver(object sender, DragEventArgs e) private void PathBoxItem_Drop(object sender, DragEventArgs e) { + dragOverPath = null; // Reset dragged over pathbox item + if (!((sender as Grid).DataContext is PathBoxItem pathBoxItem) || pathBoxItem.Path == "Home" || pathBoxItem.Path == "NewTab".GetLocalized()) { diff --git a/Files/UserControls/Selection/RectangleSelection.cs b/Files/UserControls/Selection/RectangleSelection.cs index 573060d32ef7..c8e998657660 100644 --- a/Files/UserControls/Selection/RectangleSelection.cs +++ b/Files/UserControls/Selection/RectangleSelection.cs @@ -68,17 +68,18 @@ public enum SelectionState Active } - protected void DrawRectangle(PointerPoint currentPoint, Point originDragPointShifted) + protected void DrawRectangle(PointerPoint currentPoint, Point originDragPointShifted, UIElement uiElement) { // Redraw selection rectangle according to the new point if (currentPoint.Position.X >= originDragPointShifted.X) { + double maxWidth = uiElement.ActualSize.X - originDragPointShifted.X; if (currentPoint.Position.Y <= originDragPointShifted.Y) { // Pointer was moved up and right Canvas.SetLeft(selectionRectangle, Math.Max(0, originDragPointShifted.X)); Canvas.SetTop(selectionRectangle, Math.Max(0, currentPoint.Position.Y)); - selectionRectangle.Width = Math.Max(0, currentPoint.Position.X - Math.Max(0, originDragPointShifted.X)); + selectionRectangle.Width = Math.Max(0, Math.Min(currentPoint.Position.X - Math.Max(0, originDragPointShifted.X), maxWidth)); selectionRectangle.Height = Math.Max(0, originDragPointShifted.Y - Math.Max(0, currentPoint.Position.Y)); } else @@ -86,7 +87,7 @@ protected void DrawRectangle(PointerPoint currentPoint, Point originDragPointShi // Pointer was moved down and right Canvas.SetLeft(selectionRectangle, Math.Max(0, originDragPointShifted.X)); Canvas.SetTop(selectionRectangle, Math.Max(0, originDragPointShifted.Y)); - selectionRectangle.Width = Math.Max(0, currentPoint.Position.X - Math.Max(0, originDragPointShifted.X)); + selectionRectangle.Width = Math.Max(0, Math.Min(currentPoint.Position.X - Math.Max(0, originDragPointShifted.X), maxWidth)); selectionRectangle.Height = Math.Max(0, currentPoint.Position.Y - Math.Max(0, originDragPointShifted.Y)); } } diff --git a/Files/UserControls/Selection/RectangleSelection_DataGrid.cs b/Files/UserControls/Selection/RectangleSelection_DataGrid.cs index 7422f3b47369..9fbdff344333 100644 --- a/Files/UserControls/Selection/RectangleSelection_DataGrid.cs +++ b/Files/UserControls/Selection/RectangleSelection_DataGrid.cs @@ -57,7 +57,10 @@ private void RectangleSelection_PointerMoved(object sender, PointerRoutedEventAr return; } - uiElement.CancelEdit(); + if (uiElement.CurrentColumn != null) + { + uiElement.CancelEdit(); + } selectionStrategy.StartSelection(); OnSelectionStarted(); selectionState = SelectionState.Active; @@ -66,7 +69,7 @@ private void RectangleSelection_PointerMoved(object sender, PointerRoutedEventAr if (currentPoint.Properties.IsLeftButtonPressed) { var originDragPointShifted = new Point(originDragPoint.X, originDragPoint.Y - verticalOffset); // Initial drag point relative to the topleft corner - base.DrawRectangle(currentPoint, originDragPointShifted); + base.DrawRectangle(currentPoint, originDragPointShifted, uiElement); // Selected area considering scrolled offset var rect = new System.Drawing.Rectangle((int)Canvas.GetLeft(selectionRectangle), (int)Math.Min(originDragPoint.Y, currentPoint.Position.Y + verticalOffset), (int)selectionRectangle.Width, (int)Math.Abs(originDragPoint.Y - (currentPoint.Position.Y + verticalOffset))); var dataGridRowsPosition = new Dictionary(); @@ -186,7 +189,10 @@ private void RectangleSelection_PointerPressed(object sender, PointerRoutedEvent if (clickedRow == null) { // If user click outside, reset selection - uiElement.CancelEdit(); + if (uiElement.CurrentColumn != null) + { + uiElement.CancelEdit(); + } DeselectGridCell(); selectionStrategy.HandleNoItemSelected(); } diff --git a/Files/UserControls/Selection/RectangleSelection_ListViewBase.cs b/Files/UserControls/Selection/RectangleSelection_ListViewBase.cs index ded3362dd273..a5a4447b8f46 100644 --- a/Files/UserControls/Selection/RectangleSelection_ListViewBase.cs +++ b/Files/UserControls/Selection/RectangleSelection_ListViewBase.cs @@ -55,7 +55,7 @@ private void RectangleSelection_PointerMoved(object sender, PointerRoutedEventAr if (currentPoint.Properties.IsLeftButtonPressed) { var originDragPointShifted = new Point(originDragPoint.X, originDragPoint.Y - verticalOffset); // Initial drag point relative to the topleft corner - base.DrawRectangle(currentPoint, originDragPointShifted); + base.DrawRectangle(currentPoint, originDragPointShifted, uiElement); // Selected area considering scrolled offset var rect = new System.Drawing.Rectangle((int)Canvas.GetLeft(selectionRectangle), (int)Math.Min(originDragPoint.Y, currentPoint.Position.Y + verticalOffset), (int)selectionRectangle.Width, (int)Math.Abs(originDragPoint.Y - (currentPoint.Position.Y + verticalOffset))); foreach (var item in uiElement.Items.ToList().Except(itemsPosition.Keys)) diff --git a/Files/UserControls/SidebarControl.xaml.cs b/Files/UserControls/SidebarControl.xaml.cs index 70180b8ad4ac..4d0bfb8c5c17 100644 --- a/Files/UserControls/SidebarControl.xaml.cs +++ b/Files/UserControls/SidebarControl.xaml.cs @@ -346,6 +346,13 @@ private async void NavigationViewLocationItem_DragOver(object sender, DragEventA deferral.Complete(); return; } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, ex.Message); + e.AcceptedOperation = DataPackageOperation.None; + deferral.Complete(); + return; + } if (storageItems.Count == 0 || locationItem.Path.Equals(App.AppSettings.RecycleBinPath, StringComparison.OrdinalIgnoreCase) || @@ -402,6 +409,8 @@ private void NavigationViewLocationItem_DragOver_SetCaptions(LocationItem sender private void NavigationViewLocationItem_Drop(object sender, DragEventArgs e) { + dragOverItem = null; // Reset dragged over item + if (!((sender as Microsoft.UI.Xaml.Controls.NavigationViewItem).DataContext is LocationItem locationItem)) { return; @@ -451,6 +460,13 @@ private async void NavigationViewDriveItem_DragOver(object sender, DragEventArgs deferral.Complete(); return; } + catch (Exception ex) + { + NLog.LogManager.GetCurrentClassLogger().Warn(ex, ex.Message); + e.AcceptedOperation = DataPackageOperation.None; + deferral.Complete(); + return; + } if (storageItems.Count == 0 || "DriveCapacityUnknown".GetLocalized().Equals(driveItem.SpaceText, StringComparison.OrdinalIgnoreCase) || @@ -478,6 +494,8 @@ private async void NavigationViewDriveItem_DragOver(object sender, DragEventArgs private void NavigationViewDriveItem_Drop(object sender, DragEventArgs e) { + dragOverItem = null; // Reset dragged over item + if (!((sender as Microsoft.UI.Xaml.Controls.NavigationViewItem).DataContext is DriveItem driveItem)) { return; diff --git a/Files/ViewModels/Bundles/BundleContainerViewModel.cs b/Files/ViewModels/Bundles/BundleContainerViewModel.cs index 5f6818605eb8..f7ce6424d229 100644 --- a/Files/ViewModels/Bundles/BundleContainerViewModel.cs +++ b/Files/ViewModels/Bundles/BundleContainerViewModel.cs @@ -1,4 +1,5 @@ using Files.Dialogs; +using Files.Enums; using Files.SettingsInterfaces; using Files.ViewModels.Dialogs; using Microsoft.Toolkit.Mvvm.ComponentModel; @@ -138,7 +139,7 @@ private async void RenameBundle() vm.HideDialog(); } }, - DynamicButtons = DynamicButtons.Primary | DynamicButtons.Cancel + DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Cancel }); await dialog.ShowAsync(); } diff --git a/Files/ViewModels/Bundles/BundlesViewModel.cs b/Files/ViewModels/Bundles/BundlesViewModel.cs index 3e722214e7b6..a6b3c3905a86 100644 --- a/Files/ViewModels/Bundles/BundlesViewModel.cs +++ b/Files/ViewModels/Bundles/BundlesViewModel.cs @@ -1,4 +1,5 @@ using Files.Dialogs; +using Files.Enums; using Files.Helpers; using Files.SettingsInterfaces; using Files.ViewModels.Dialogs; @@ -141,7 +142,7 @@ private async void OpenAddBundleDialog() vm.HideDialog(); } }, - DynamicButtons = DynamicButtons.Primary | DynamicButtons.Cancel + DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Cancel }); await dialog.ShowAsync(); } diff --git a/Files/ViewModels/Dialogs/DynamicDialogViewModel.cs b/Files/ViewModels/Dialogs/DynamicDialogViewModel.cs index 6e514f7b5d56..9079247c212d 100644 --- a/Files/ViewModels/Dialogs/DynamicDialogViewModel.cs +++ b/Files/ViewModels/Dialogs/DynamicDialogViewModel.cs @@ -1,43 +1,58 @@ -using Microsoft.Toolkit.Mvvm.ComponentModel; +using System; +using Microsoft.Toolkit.Mvvm.ComponentModel; using Microsoft.Toolkit.Mvvm.Input; -using System; +using System.Diagnostics; using System.Windows.Input; using Windows.System; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; +using Files.Enums; namespace Files.ViewModels.Dialogs { - public enum DynamicResult - { - Primary = 0, - Secondary = 1, - Cancel = 2 - } - - public enum DynamicButtons - { - Primary = 0, - Secondary = 1, - Cancel = 2 - } - public class DynamicDialogViewModel : ObservableObject, IDisposable { #region Public Properties - public object displayControl; + /// + /// Stores any additional data that could be written to, read from. + /// + public object AdditionalData { get; set; } + public object displayControl; /// /// The control that is dynamically displayed. /// public object DisplayControl { get => displayControl; - set => SetProperty(ref displayControl, value); + set + { + if (SetProperty(ref displayControl, value)) + { + if (value == null) + { + DisplayControlLoad = false; + } + else + { + DisplayControlLoad = true; + } + } + } + } + + private bool displayControlLoad; + /// + /// Determines whether the is loaded, value of this property is automatically handled. + /// + public bool DisplayControlLoad + { + get => displayControlLoad; + set => SetProperty(ref displayControlLoad, value); } - private DynamicButtons dynamicButtons; + private DynamicDialogButtons dynamicButtons; /// /// Decides which buttons to show. @@ -48,22 +63,31 @@ public object DisplayControl /// Setting value to may override /// and/or and/or . /// - public DynamicButtons DynamicButtons + public DynamicDialogButtons DynamicButtons { get => dynamicButtons; set { if (SetProperty(ref dynamicButtons, value)) { - if (!value.HasFlag(DynamicButtons.Primary)) + if (value.HasFlag(DynamicDialogButtons.None)) + { + PrimaryButtonText = null; // Hides this option + SecondaryButtonText = null; // Hides this option + CloseButtonText = null; // Hides this option + + return; + } + + if (!value.HasFlag(DynamicDialogButtons.Primary)) { PrimaryButtonText = null; // Hides this option } - if (!value.HasFlag(DynamicButtons.Secondary)) + if (!value.HasFlag(DynamicDialogButtons.Secondary)) { SecondaryButtonText = null; // Hides this option } - if (!value.HasFlag(DynamicButtons.Cancel)) + if (!value.HasFlag(DynamicDialogButtons.Cancel)) { CloseButtonText = null; // Hides this option } @@ -72,7 +96,9 @@ public DynamicButtons DynamicButtons } private string titleText; - + /// + /// The Title text of the dialog. + /// public string TitleText { get => titleText; @@ -80,38 +106,151 @@ public string TitleText } private string subtitleText; - + /// + /// The subtitle of the dialog. + ///
+ /// (Can be null or empty) + ///
public string SubtitleText { get => subtitleText; - set => SetProperty(ref subtitleText, value); + set + { + if (SetProperty(ref subtitleText, value)) + { + if (!string.IsNullOrWhiteSpace(value)) + { + SubtitleLoad = true; + } + else + { + SubtitleLoad = false; + } + } + } } - private string primaryButtonText; + private bool subtitleLoad; + /// + /// Determines whether the is loaded, value of this property is automatically handled. + /// + public bool SubtitleLoad + { + get => subtitleLoad; + private set => SetProperty(ref subtitleLoad, value); + } + #region Primary Button + + private string primaryButtonText; + /// + /// The text content of the primary button. + /// public string PrimaryButtonText { get => primaryButtonText; set => SetProperty(ref primaryButtonText, value); } - private string secondaryButtonText; + private bool isPrimaryButtonEnabled; + /// + /// Determines whether Primary Button is enabled. + /// + public bool IsPrimaryButtonEnabled + { + get => isPrimaryButtonEnabled; + private set => SetProperty(ref isPrimaryButtonEnabled, value); + } + #endregion + + #region Secondary Button + + private string secondaryButtonText; + /// + /// The text of the secondary button. + /// public string SecondaryButtonText { get => secondaryButtonText; set => SetProperty(ref secondaryButtonText, value); } - private string closeButtonText; + private bool isSecondaryButtonEnabled; + /// + /// Determines whether Secondary Button is enabled. + /// + public bool IsSecondaryButtonEnabled + { + get => isSecondaryButtonEnabled; + private set => SetProperty(ref isSecondaryButtonEnabled, value); + } + + #endregion + + #region Close Button + private string closeButtonText; + /// + /// The text of the close button. + /// public string CloseButtonText { get => closeButtonText; set => SetProperty(ref closeButtonText, value); } - public DynamicResult DynamicResult { get; set; } + #endregion + + private DynamicDialogButtons dynamicButtonsEnabled; + /// + /// Determines which buttons should be enabled + /// + public DynamicDialogButtons DynamicButtonsEnabled + { + get => dynamicButtonsEnabled; + set + { + if (SetProperty(ref dynamicButtonsEnabled, value)) + { + if (!value.HasFlag(DynamicDialogButtons.Cancel)) + { + Debugger.Break(); // Cannot disable the Close button! + } + + if (value.HasFlag(DynamicDialogButtons.None)) + { + IsPrimaryButtonEnabled = false; // Hides this option + IsSecondaryButtonEnabled = false; // Hides this option + + return; + } + + if (!value.HasFlag(DynamicDialogButtons.Primary)) + { + IsPrimaryButtonEnabled = false; // Hides this option + } + else + { + IsPrimaryButtonEnabled = true; + } + + if (!value.HasFlag(DynamicDialogButtons.Secondary)) + { + IsSecondaryButtonEnabled = false; // Hides this option + } + else + { + IsSecondaryButtonEnabled = true; + } + } + } + } + + /// + /// The result of the dialog, value of this property is automatically handled. + /// + public DynamicDialogResult DynamicResult { get; set; } #endregion Public Properties @@ -123,12 +262,14 @@ public string CloseButtonText ///
/// Note: ///
- /// This action will always be overriden. + /// This action is assigned by default. ///
public Action HideDialog { get; set; } private Action primaryButtonAction; - + /// + /// OnPrimary action. + /// public Action PrimaryButtonAction { get => primaryButtonAction; @@ -138,7 +279,7 @@ public Action Primary { PrimaryButtonCommand = new RelayCommand((e) => { - DynamicResult = DynamicResult.Primary; + DynamicResult = DynamicDialogResult.Primary; PrimaryButtonAction(this, e); }); } @@ -146,7 +287,9 @@ public Action Primary } private Action secondaryButtonAction; - + /// + /// OnSecondary action. + /// public Action SecondaryButtonAction { get => secondaryButtonAction; @@ -156,7 +299,7 @@ public Action Seconda { SecondaryButtonCommand = new RelayCommand((e) => { - DynamicResult = DynamicResult.Secondary; + DynamicResult = DynamicDialogResult.Secondary; SecondaryButtonAction(this, e); }); } @@ -164,7 +307,9 @@ public Action Seconda } private Action closeButtonAction; - + /// + /// OnClose action. + /// public Action CloseButtonAction { get => closeButtonAction; @@ -174,7 +319,7 @@ public Action CloseBu { CloseButtonCommand = new RelayCommand((e) => { - DynamicResult = DynamicResult.Cancel; + DynamicResult = DynamicDialogResult.Cancel; CloseButtonAction(this, e); }); } @@ -182,7 +327,14 @@ public Action CloseBu } private Action keyDownAction; - + /// + /// The keydown action on the dialog. + ///
+ ///
+ /// Note: + ///
+ /// This action is assigned by default. + ///
public Action KeyDownAction { get => keyDownAction; @@ -192,7 +344,7 @@ public Action KeyDownAction { DynamicKeyDownCommand = new RelayCommand((e) => { - DynamicResult = DynamicResult.Cancel; + DynamicResult = DynamicDialogResult.Cancel; KeyDownAction(this, e); }); } @@ -219,16 +371,19 @@ public DynamicDialogViewModel() { // Create default implementation TitleText = "DynamicDialog"; - PrimaryButtonText = "OK"; + PrimaryButtonText = "Ok"; PrimaryButtonAction = (vm, e) => HideDialog(); + SecondaryButtonAction = (vm, e) => HideDialog(); + CloseButtonAction = (vm, e) => HideDialog(); KeyDownAction = (vm, e) => { - if (e.Key == VirtualKey.Enter || e.Key == VirtualKey.Escape) + if (e.Key == VirtualKey.Escape) { HideDialog(); } }; - DynamicButtons = DynamicButtons.Primary; + DynamicButtons = DynamicDialogButtons.Primary; + DynamicButtonsEnabled = DynamicDialogButtons.Primary | DynamicDialogButtons.Secondary | DynamicDialogButtons.Cancel; } #endregion Constructor diff --git a/Files/ViewModels/ItemViewModel.cs b/Files/ViewModels/ItemViewModel.cs index d35f29ef8313..5c1e624ceb87 100644 --- a/Files/ViewModels/ItemViewModel.cs +++ b/Files/ViewModels/ItemViewModel.cs @@ -177,6 +177,7 @@ public async void UpdateSortOptionStatus() NotifyPropertyChanged(nameof(IsSortedBySize)); NotifyPropertyChanged(nameof(IsSortedByOriginalPath)); NotifyPropertyChanged(nameof(IsSortedByDateDeleted)); + NotifyPropertyChanged(nameof(IsSortedByDateCreated)); await OrderFilesAndFoldersAsync(); await ApplyFilesAndFoldersChangesAsync(); } @@ -241,6 +242,19 @@ public bool IsSortedByDate } } + public bool IsSortedByDateCreated + { + get => FolderSettings.DirectorySortOption == SortOption.DateCreated; + set + { + if (value) + { + FolderSettings.DirectorySortOption = SortOption.DateCreated; + NotifyPropertyChanged(nameof(IsSortedByDateCreated)); + } + } + } + public bool IsSortedByType { get => FolderSettings.DirectorySortOption == SortOption.FileType; @@ -308,7 +322,7 @@ public string JumpString // use FilesAndFolders because only displayed entries should be jumped to var candidateItems = FilesAndFolders.Where(f => f.ItemName.Length >= value.Length && f.ItemName.Substring(0, value.Length).ToLower() == value); - if (AssociatedInstance.ContentPage.IsItemSelected) + if (AssociatedInstance.ContentPage != null && AssociatedInstance.ContentPage.IsItemSelected) { previouslySelectedItem = AssociatedInstance.ContentPage.SelectedItem; } @@ -466,6 +480,19 @@ public void CancelExtendedPropertiesLoading() loadPropsCTS = new CancellationTokenSource(); } + public async Task ApplySingleFileChangeAsync(ListedItem item) + { + var newIndex = filesAndFolders.IndexOf(item); + await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => + { + FilesAndFolders.Remove(item); + if (newIndex != -1) + { + FilesAndFolders.Insert(newIndex, item); + } + }); + } + // apply changes immediately after manipulating on filesAndFolders completed public async Task ApplyFilesAndFoldersChangesAsync() { @@ -476,7 +503,7 @@ public async Task ApplyFilesAndFoldersChangesAsync() await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => { FilesAndFolders.Clear(); - IsFolderEmptyTextDisplayed = FilesAndFolders.Count == 0; + IsFolderEmptyTextDisplayed = true; UpdateDirectoryInfo(); }); return; @@ -582,6 +609,10 @@ private Task OrderFilesAndFoldersAsync() orderFunc = item => item.ItemDateModifiedReal; break; + case SortOption.DateCreated: + orderFunc = item => item.ItemDateCreatedReal; + break; + case SortOption.FileType: orderFunc = item => item.ItemType; break; @@ -796,6 +827,20 @@ await CoreApplication.MainView.ExecuteOnUIThreadAsync(async () => StorageFolder matchingStorageItem = await GetFolderFromPathAsync(item.ItemPath); if (matchingStorageItem != null) { + if (matchingStorageItem.DisplayName != item.ItemName) + { + await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => + { + item.ItemName = matchingStorageItem.DisplayName; + }); + await fileListCache.SaveFileDisplayNameToCache(item.ItemPath, matchingStorageItem.DisplayName); + if (FolderSettings.DirectorySortOption == SortOption.Name && !isLoadingItems) + { + await OrderFilesAndFoldersAsync(); + await ApplySingleFileChangeAsync(item); + //await SaveCurrentListToCacheAsync(WorkingDirectory); + } + } var syncStatus = await CheckCloudDriveSyncStatusAsync(matchingStorageItem); await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => { @@ -880,8 +925,13 @@ public async void RapidAddItemsToCollectionAsync(string path, string previousDir semaphoreCTS = new CancellationTokenSource(); IsLoadingItems = true; + filesAndFolders.Clear(); - await ApplyFilesAndFoldersChangesAsync(); + await CoreApplication.MainView.ExecuteOnUIThreadAsync(() => + { + FilesAndFolders.Clear(); + }); + Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -1068,6 +1118,7 @@ public async Task EnumerateItemsFromSpecialFolderAsync(string path) ItemPropertiesInitialized = true, ItemName = ApplicationData.Current.LocalSettings.Values.Get("RecycleBin_Title", "Recycle Bin"), ItemDateModifiedReal = DateTimeOffset.Now, // Fake for now + ItemDateCreatedReal = DateTimeOffset.MinValue, // Fake for now ItemType = "FileFolderListItem".GetLocalized(), LoadFolderGlyph = true, FileImage = null, @@ -1129,6 +1180,10 @@ public async Task EnumerateItemsFromStandardFolderAsync(string path, Stora } else if (workingRoot != null) { + if (storageFolderForGivenPath == null) + { + return false; + } rootFolder = storageFolderForGivenPath.Folder; enumFromStorageFolder = true; } @@ -1199,12 +1254,14 @@ await DialogDisplayHelper.ShowDialogAsync( if (enumFromStorageFolder) { + var basicProps = await rootFolder.GetBasicPropertiesAsync(); + var extraProps = await basicProps.RetrievePropertiesAsync(new[] { "System.DateCreated" }); var currentFolder = new ListedItem(rootFolder.FolderRelativeId, returnformat) { PrimaryItemAttribute = StorageItemTypes.Folder, ItemPropertiesInitialized = true, - ItemName = rootFolder.Name, - ItemDateModifiedReal = (await rootFolder.GetBasicPropertiesAsync()).DateModified, + ItemName = rootFolder.DisplayName, + ItemDateModifiedReal = basicProps.DateModified, ItemType = rootFolder.DisplayType, LoadFolderGlyph = true, FileImage = null, @@ -1214,6 +1271,10 @@ await DialogDisplayHelper.ShowDialogAsync( FileSize = null, FileSizeBytes = 0 }; + if (DateTimeOffset.TryParse(extraProps["System.DateCreated"] as string, out var dateCreated)) + { + currentFolder.ItemDateCreatedReal = dateCreated; + } if (!cacheOnly) { CurrentFolder = currentFolder; @@ -1232,13 +1293,20 @@ await DialogDisplayHelper.ShowDialogAsync( return (hFileTsk, findDataTsk); }).WithTimeoutAsync(TimeSpan.FromSeconds(5)); - DateTime itemDate = DateTime.UtcNow; + var itemModifiedDate = DateTime.UtcNow; + var itemCreatedDate = DateTime.MinValue; try { - FileTimeToSystemTime(ref findData.ftLastWriteTime, out SYSTEMTIME systemTimeOutput); - itemDate = new DateTime( - systemTimeOutput.Year, systemTimeOutput.Month, systemTimeOutput.Day, - systemTimeOutput.Hour, systemTimeOutput.Minute, systemTimeOutput.Second, systemTimeOutput.Milliseconds, + FileTimeToSystemTime(ref findData.ftLastWriteTime, out var systemModifiedTimeOutput); + itemModifiedDate = new DateTime( + systemModifiedTimeOutput.Year, systemModifiedTimeOutput.Month, systemModifiedTimeOutput.Day, + systemModifiedTimeOutput.Hour, systemModifiedTimeOutput.Minute, systemModifiedTimeOutput.Second, systemModifiedTimeOutput.Milliseconds, + DateTimeKind.Utc); + + FileTimeToSystemTime(ref findData.ftCreationTime, out SYSTEMTIME systemCreatedTimeOutput); + itemCreatedDate = new DateTime( + systemCreatedTimeOutput.Year, systemCreatedTimeOutput.Month, systemCreatedTimeOutput.Day, + systemCreatedTimeOutput.Hour, systemCreatedTimeOutput.Minute, systemCreatedTimeOutput.Second, systemCreatedTimeOutput.Milliseconds, DateTimeKind.Utc); } catch (ArgumentException) { } @@ -1256,7 +1324,8 @@ await DialogDisplayHelper.ShowDialogAsync( PrimaryItemAttribute = StorageItemTypes.Folder, ItemPropertiesInitialized = true, ItemName = Path.GetFileName(path.TrimEnd('\\')), - ItemDateModifiedReal = itemDate, + ItemDateModifiedReal = itemModifiedDate, + ItemDateCreatedReal = itemCreatedDate, ItemType = "FileFolderListItem".GetLocalized(), LoadFolderGlyph = true, FileImage = null, @@ -1622,6 +1691,7 @@ public ListedItem AddFileOrFolderFromShellFile(ShellFileItem item, string dateRe PrimaryItemAttribute = StorageItemTypes.Folder, ItemName = item.FileName, ItemDateModifiedReal = item.ModifiedDate, + ItemDateCreatedReal = item.CreatedDate, ItemDateDeletedReal = item.RecycleDate, ItemType = item.FileType, IsHiddenItem = false, @@ -1674,6 +1744,7 @@ public ListedItem AddFileOrFolderFromShellFile(ShellFileItem item, string dateRe Opacity = 1, ItemName = itemName, ItemDateModifiedReal = item.ModifiedDate, + ItemDateCreatedReal = item.CreatedDate, ItemDateDeletedReal = item.RecycleDate, ItemType = item.FileType, ItemPath = item.RecyclePath, // this is the true path on disk so other stuff can work as is @@ -1706,10 +1777,10 @@ private async Task AddFileOrFolderAsync(string fileOrFolderPath, string dateRetu FindClose(hFile); - ListedItem listedItem = null; + ListedItem listedItem; if ((findData.dwFileAttributes & 0x10) > 0) // FILE_ATTRIBUTE_DIRECTORY { - listedItem = Win32StorageEnumerator.GetFolder(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, addFilesCTS.Token); + listedItem = await Win32StorageEnumerator.GetFolder(findData, Directory.GetParent(fileOrFolderPath).FullName, dateReturnFormat, addFilesCTS.Token); } else { @@ -1852,10 +1923,10 @@ private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") public void Dispose() { + CancelLoadAndClearFiles(); addFilesCTS?.Dispose(); semaphoreCTS?.Dispose(); loadPropsCTS?.Dispose(); - CloseWatcher(); } } diff --git a/Files/ViewModels/Properties/DriveProperties.cs b/Files/ViewModels/Properties/DriveProperties.cs index 1c344a6b6bcc..4855fb800499 100644 --- a/Files/ViewModels/Properties/DriveProperties.cs +++ b/Files/ViewModels/Properties/DriveProperties.cs @@ -1,4 +1,5 @@ using Files.Filesystem; +using Microsoft.Toolkit.Uwp.Extensions; using System; using System.Threading.Tasks; using Windows.Storage; @@ -26,7 +27,8 @@ public override void GetBaseProperties() ViewModel.LoadDriveItemGlyph = true; ViewModel.ItemName = Drive.Text; ViewModel.OriginalItemName = Drive.Text; - ViewModel.ItemType = Drive.Type.ToString(); + // Note: if DriveType enum changes, the corresponding resource keys should change too + ViewModel.ItemType = string.Format("DriveType{0}", Drive.Type).GetLocalized(); } } diff --git a/Files/ViewModels/Properties/FileProperties.cs b/Files/ViewModels/Properties/FileProperties.cs index 7b1f7269dc4d..e5d9255e378c 100644 --- a/Files/ViewModels/Properties/FileProperties.cs +++ b/Files/ViewModels/Properties/FileProperties.cs @@ -52,6 +52,7 @@ public override void GetBaseProperties() ViewModel.ItemPath = (Item as RecycleBinItem)?.ItemOriginalFolder ?? (Path.IsPathRooted(Item.ItemPath) ? Path.GetDirectoryName(Item.ItemPath) : Item.ItemPath); ViewModel.ItemModifiedTimestamp = Item.ItemDateModified; + ViewModel.ItemCreatedTimestamp = Item.ItemDateCreated; //ViewModel.FileIconSource = Item.FileImage; ViewModel.LoadFolderGlyph = Item.LoadFolderGlyph; ViewModel.LoadUnknownTypeGlyph = Item.LoadUnknownTypeGlyph; diff --git a/Files/ViewModels/Properties/FolderProperties.cs b/Files/ViewModels/Properties/FolderProperties.cs index 27056542a6c5..124a7c30e976 100644 --- a/Files/ViewModels/Properties/FolderProperties.cs +++ b/Files/ViewModels/Properties/FolderProperties.cs @@ -42,6 +42,7 @@ public override void GetBaseProperties() ViewModel.ItemPath = (Item as RecycleBinItem)?.ItemOriginalFolder ?? (Path.IsPathRooted(Item.ItemPath) ? Path.GetDirectoryName(Item.ItemPath) : Item.ItemPath); ViewModel.ItemModifiedTimestamp = Item.ItemDateModified; + ViewModel.ItemCreatedTimestamp = Item.ItemDateCreated; //ViewModel.FileIconSource = Item.FileImage; ViewModel.LoadFolderGlyph = Item.LoadFolderGlyph; ViewModel.LoadUnknownTypeGlyph = Item.LoadUnknownTypeGlyph; diff --git a/Files/ViewModels/SettingsViewModel.cs b/Files/ViewModels/SettingsViewModel.cs index 4dd9217ac0a7..be5130c22a96 100644 --- a/Files/ViewModels/SettingsViewModel.cs +++ b/Files/ViewModels/SettingsViewModel.cs @@ -17,6 +17,8 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; using Windows.ApplicationModel; +using Windows.ApplicationModel.AppService; +using Windows.Foundation.Collections; using Windows.Globalization; using Windows.Storage; using Windows.System; @@ -124,8 +126,18 @@ public async void DetectQuickLook() // Detect QuickLook try { - ApplicationData.Current.LocalSettings.Values["Arguments"] = "StartupTasks"; - await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync(); + var connection = await AppServiceConnectionHelper.Instance; + if (connection != null) + { + var (status, response) = await connection.SendMessageWithRetryAsync(new ValueSet() + { + { "Arguments", "DetectQuickLook" } + }, TimeSpan.FromSeconds(10)); + if (status == AppServiceResponseStatus.Success) + { + localSettings.Values["quicklook_enabled"] = response.Message.Get("IsAvailable", false); + } + } } catch (Exception ex) { @@ -269,6 +281,15 @@ public bool ShowDateColumn set => Set(value); } + /// + /// Gets or sets a value indicating whether or not the date created column should be visible. + /// + public bool ShowDateCreatedColumn + { + get => Get(false); + set => Set(value); + } + /// /// Gets or sets a value indicating whether or not the type column should be visible. /// @@ -778,7 +799,7 @@ public bool ResumeAfterRestart ThemeModeChanged?.Invoke(this, EventArgs.Empty); }); - public AcrylicTheme AcrylicTheme { get; set; } + public AcrylicTheme AcrylicTheme { get; set; } = new AcrylicTheme(); public FolderLayoutModes DefaultLayoutMode { diff --git a/Files/Views/LayoutModes/GenericFileBrowser.xaml b/Files/Views/LayoutModes/GenericFileBrowser.xaml index c41c16ca0ea4..eab18b73cd65 100644 --- a/Files/Views/LayoutModes/GenericFileBrowser.xaml +++ b/Files/Views/LayoutModes/GenericFileBrowser.xaml @@ -17,7 +17,7 @@ xmlns:muxc="using:Microsoft.UI.Xaml.Controls" xmlns:usercontrols="using:Files.UserControls" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" - NavigationCacheMode="Disabled" + NavigationCacheMode="Enabled" PointerWheelChanged="BaseLayout_PointerWheelChanged" mc:Ignorable="d"> @@ -59,6 +59,13 @@ IsChecked="{x:Bind ParentShellPageInstance.FilesystemViewModel.IsSortedByDate, Mode=TwoWay}" Tag="dateColumn" Text="Date modified" /> + + + Text="Date modified" /> + + + + + + + + +
- \ No newline at end of file + diff --git a/Files/Views/LayoutModes/GenericFileBrowser.xaml.cs b/Files/Views/LayoutModes/GenericFileBrowser.xaml.cs index 447029e59732..24595f5418d7 100644 --- a/Files/Views/LayoutModes/GenericFileBrowser.xaml.cs +++ b/Files/Views/LayoutModes/GenericFileBrowser.xaml.cs @@ -65,6 +65,10 @@ public DataGridColumn SortedColumn { FolderSettings.DirectorySortOption = SortOption.DateDeleted; } + else if (value == dateCreatedColumn) + { + FolderSettings.DirectorySortOption = SortOption.DateCreated; + } else { FolderSettings.DirectorySortOption = SortOption.Name; @@ -112,11 +116,14 @@ private void SelectionRectangle_SelectionEnded(object sender, EventArgs e) protected override void OnNavigatedTo(NavigationEventArgs eventArgs) { base.OnNavigatedTo(eventArgs); - AllView.ItemsSource = ParentShellPageInstance.FilesystemViewModel.FilesAndFolders; ParentShellPageInstance.FilesystemViewModel.PropertyChanged += ViewModel_PropertyChanged; AllView.LoadingRow += AllView_LoadingRow; AllView.UnloadingRow += AllView_UnloadingRow; AppSettings.ThemeModeChanged += AppSettings_ThemeModeChanged; + if (AllView.ItemsSource == null) + { + AllView.ItemsSource = ParentShellPageInstance.FilesystemViewModel.FilesAndFolders; + } ViewModel_PropertyChanged(null, new PropertyChangedEventArgs("DirectorySortOption")); var parameters = (NavigationArguments)eventArgs.Parameter; if (parameters.IsLayoutSwitch) @@ -127,7 +134,6 @@ protected override void OnNavigatedTo(NavigationEventArgs eventArgs) private void AllView_UnloadingRow(object sender, DataGridRowEventArgs e) { - e.Row.CanDrag = false; base.UninitializeDrag(e.Row); } @@ -154,8 +160,10 @@ protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) AllView.LoadingRow -= AllView_LoadingRow; AllView.UnloadingRow -= AllView_UnloadingRow; AppSettings.ThemeModeChanged -= AppSettings_ThemeModeChanged; - - AllView.ItemsSource = null; + if (e.SourcePageType != typeof(GenericFileBrowser)) + { + AllView.ItemsSource = null; + } } private void AppSettings_ThemeModeChanged(object sender, EventArgs e) @@ -214,11 +222,15 @@ public override void FocusSelectedItems() public override void StartRenameItem() { - if (AllView.SelectedIndex != -1) + try { AllView.CurrentColumn = AllView.Columns[1]; AllView.BeginEdit(); } + catch (InvalidOperationException) + { + // System.InvalidOperationException: There is no current row. Operation cannot be completed. + } } private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) @@ -250,6 +262,10 @@ private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e case SortOption.DateDeleted: SortedColumn = dateDeletedColumn; break; + + case SortOption.DateCreated: + SortedColumn = dateCreatedColumn; + break; } } else if (e.PropertyName == "DirectorySortDirection") @@ -479,7 +495,11 @@ private void HandleRightClick(object sender, RoutedEventArgs e) var rowPressed = Interaction.FindParent(e.OriginalSource as DependencyObject); if (rowPressed != null) { - var objectPressed = ((IList)AllView.ItemsSource)[rowPressed.GetIndex()]; + var objectPressed = ((IList)AllView.ItemsSource).ElementAtOrDefault(rowPressed.GetIndex()); + if (objectPressed == null) + { + return; + } // Check if RightTapped row is currently selected if (IsItemSelected) @@ -517,6 +537,7 @@ protected override void Page_CharacterReceived(CoreWindow sender, CharacterRecei private async void AllView_LoadingRow(object sender, DataGridRowEventArgs e) { + e.Row.CanDrag = false; InitializeDrag(e.Row); if (e.Row.DataContext is ListedItem item && !item.ItemPropertiesInitialized) @@ -561,6 +582,9 @@ private void RadioMenuSortColumn_Click(object sender, RoutedEventArgs e) case "dateDeletedColumn": args = new DataGridColumnEventArgs(dateDeletedColumn); break; + case "dateCreatedColumn": + args = new DataGridColumnEventArgs(dateCreatedColumn); + break; } if (args != null) diff --git a/Files/Views/LayoutModes/GridViewBrowser.xaml b/Files/Views/LayoutModes/GridViewBrowser.xaml index 81f9b90aa9cb..3aef6d654a57 100644 --- a/Files/Views/LayoutModes/GridViewBrowser.xaml +++ b/Files/Views/LayoutModes/GridViewBrowser.xaml @@ -15,7 +15,7 @@ xmlns:muxc="using:Microsoft.UI.Xaml.Controls" x:Name="PageRoot" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" - NavigationCacheMode="Disabled" + NavigationCacheMode="Enabled" PointerPressed="GridViewBrowserViewer_PointerPressed" PointerWheelChanged="BaseLayout_PointerWheelChanged" mc:Ignorable="d"> @@ -51,6 +51,11 @@ GroupName="SortGroup" IsChecked="{x:Bind ParentShellPageInstance.FilesystemViewModel.IsSortedByDate, Mode=TwoWay}" Text="Date modified" /> + + + ToolTipService.ToolTip="{x:Bind ItemName, Mode=OneWay}"> @@ -696,7 +706,7 @@ Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" - Text="{x:Bind ItemName}" + Text="{x:Bind ItemName, Mode=OneWay}" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" /> @@ -710,7 +720,7 @@ Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" - Text="{x:Bind ItemName}" + Text="{x:Bind ItemName, Mode=OneWay}" TextAlignment="Center" TextChanged="GridViewTextBoxItemName_TextChanged" TextWrapping="Wrap" /> @@ -729,7 +739,7 @@ Background="Transparent" IsRightTapEnabled="True" RightTapped="StackPanel_RightTapped" - ToolTipService.ToolTip="{x:Bind ItemName}"> + ToolTipService.ToolTip="{x:Bind ItemName, Mode=OneWay}"> @@ -835,7 +845,7 @@ Margin="0,0,10,0" HorizontalAlignment="Left" ScrollViewer.VerticalScrollBarVisibility="Auto" - Text="{x:Bind ItemName}" + Text="{x:Bind ItemName, Mode=OneWay}" TextAlignment="Left" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" /> @@ -846,7 +856,7 @@ Margin="0,0,10,0" HorizontalAlignment="Left" ScrollViewer.VerticalScrollBarVisibility="Auto" - Text="{x:Bind ItemName}" + Text="{x:Bind ItemName, Mode=OneWay}" TextAlignment="Left" TextWrapping="Wrap" Visibility="Collapsed" /> diff --git a/Files/Views/LayoutModes/GridViewBrowser.xaml.cs b/Files/Views/LayoutModes/GridViewBrowser.xaml.cs index 7df879649fc1..f7b326615a27 100644 --- a/Files/Views/LayoutModes/GridViewBrowser.xaml.cs +++ b/Files/Views/LayoutModes/GridViewBrowser.xaml.cs @@ -35,11 +35,14 @@ public GridViewBrowser() protected override void OnNavigatedTo(NavigationEventArgs eventArgs) { base.OnNavigatedTo(eventArgs); - FileList.ItemsSource = ParentShellPageInstance.FilesystemViewModel.FilesAndFolders; currentIconSize = GetIconSize(); FolderSettings.LayoutModeChangeRequested -= FolderSettings_LayoutModeChangeRequested; FolderSettings.LayoutModeChangeRequested += FolderSettings_LayoutModeChangeRequested; SetItemTemplate(); // Set ItemTemplate + if (FileList.ItemsSource == null) + { + FileList.ItemsSource = ParentShellPageInstance.FilesystemViewModel.FilesAndFolders; + } var parameters = (NavigationArguments)eventArgs.Parameter; if (parameters.IsLayoutSwitch) { @@ -60,8 +63,10 @@ protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) base.OnNavigatingFrom(e); FolderSettings.LayoutModeChangeRequested -= FolderSettings_LayoutModeChangeRequested; FolderSettings.GridViewSizeChangeRequested -= FolderSettings_GridViewSizeChangeRequested; - - FileList.ItemsSource = null; + if (e.SourcePageType != typeof(GridViewBrowser)) + { + FileList.ItemsSource = null; + } } private async void SelectionRectangle_SelectionEnded(object sender, EventArgs e) diff --git a/Files/Views/MainPage.xaml.cs b/Files/Views/MainPage.xaml.cs index 96d7a67cf743..943691cdd567 100644 --- a/Files/Views/MainPage.xaml.cs +++ b/Files/Views/MainPage.xaml.cs @@ -1,4 +1,5 @@ using Files.Common; +using Files.Enums; using Files.Filesystem; using Files.Helpers; using Files.UserControls.MultitaskingControl; @@ -11,6 +12,7 @@ using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using Windows.ApplicationModel.Core; using Windows.ApplicationModel.Resources.Core; @@ -19,6 +21,7 @@ using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; @@ -50,7 +53,8 @@ public TabItem SelectedTabItem } public static ObservableCollection AppInstances = new ObservableCollection(); - public static ObservableCollection SideBarItems = new ObservableCollection(); + public static BulkConcurrentObservableCollection SideBarItems = new BulkConcurrentObservableCollection(); + public static SemaphoreSlim SideBarItemsSemaphore = new SemaphoreSlim(1, 1); public MainPage() { @@ -73,6 +77,10 @@ protected override async void OnNavigatedTo(NavigationEventArgs eventArgs) { if (eventArgs.NavigationMode != NavigationMode.Back) { + //Initialize the static theme helper to capture a reference to this window + //to handle theme changes without restarting the app + ThemeHelper.Initialize(); + if (eventArgs.Parameter == null || (eventArgs.Parameter is string eventStr && string.IsNullOrEmpty(eventStr))) { try @@ -243,17 +251,14 @@ public static async Task AddNewTabByPathAsync(Type type, string path, int atInde NavigationArg = path }; tabItem.Control.ContentChanged += Control_ContentChanged; - await SetSelectedTabInfoAsync(tabItem, path); + await UpdateTabInfo(tabItem, path); AppInstances.Insert(atIndex == -1 ? AppInstances.Count : atIndex, tabItem); } - private static async Task SetSelectedTabInfoAsync(TabItem selectedTabItem, string currentPath, string tabHeader = null) + private static async Task<(string tabLocationHeader, Microsoft.UI.Xaml.Controls.IconSource tabIcon)> GetSelectedTabInfoAsync(string currentPath) { - selectedTabItem.AllowStorageItemDrop = true; - string tabLocationHeader; Microsoft.UI.Xaml.Controls.FontIconSource fontIconSource = new Microsoft.UI.Xaml.Controls.FontIconSource(); - Microsoft.UI.Xaml.Controls.IconSource tabIcon; fontIconSource.FontFamily = App.Current.Resources["FluentUIGlyphs"] as FontFamily; if (currentPath == null || currentPath == "SidebarSettings/Text".GetLocalized()) @@ -325,7 +330,7 @@ private static async Task SetSelectedTabInfoAsync(TabItem selectedTabItem, strin if (matchingDrive != null) { - //Go through types and set the icon according to type + // Go through types and set the icon according to type string type = GetDriveTypeIcon(matchingDrive); if (!string.IsNullOrWhiteSpace(type)) { @@ -352,15 +357,20 @@ private static async Task SetSelectedTabInfoAsync(TabItem selectedTabItem, strin { fontIconSource.Glyph = "\xea55"; //Folder icon tabLocationHeader = currentPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).Split('\\', StringSplitOptions.RemoveEmptyEntries).Last(); + + FilesystemResult rootItem = await FilesystemTasks.Wrap(() => DrivesManager.GetRootFromPathAsync(currentPath)); + if (rootItem) + { + StorageFolder currentFolder = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFolderFromPathAsync(currentPath, rootItem)); + if (currentFolder != null && !string.IsNullOrEmpty(currentFolder.DisplayName)) + { + tabLocationHeader = currentFolder.DisplayName; + } + } } } - if (tabHeader != null) - { - tabLocationHeader = tabHeader; - } - tabIcon = fontIconSource; - selectedTabItem.Header = tabLocationHeader; - selectedTabItem.IconSource = tabIcon; + + return (tabLocationHeader, fontIconSource); } private static async void Control_ContentChanged(object sender, TabItemArguments e) @@ -375,22 +385,24 @@ private static async void Control_ContentChanged(object sender, TabItemArguments private static async Task UpdateTabInfo(TabItem tabItem, object navigationArg) { + tabItem.AllowStorageItemDrop = true; if (navigationArg is PaneNavigationArguments paneArgs) { - var leftHeader = !string.IsNullOrEmpty(paneArgs.LeftPaneNavPathParam) ? new DirectoryInfo(paneArgs.LeftPaneNavPathParam).Name : null; - var rightHeader = !string.IsNullOrEmpty(paneArgs.RightPaneNavPathParam) ? new DirectoryInfo(paneArgs.RightPaneNavPathParam).Name : null; - if (leftHeader != null && rightHeader != null) + if (!string.IsNullOrEmpty(paneArgs.LeftPaneNavPathParam) && !string.IsNullOrEmpty(paneArgs.RightPaneNavPathParam)) { - await SetSelectedTabInfoAsync(tabItem, paneArgs.LeftPaneNavPathParam, $"{leftHeader} | {rightHeader}"); + var leftTabInfo = await GetSelectedTabInfoAsync(paneArgs.LeftPaneNavPathParam); + var rightTabInfo = await GetSelectedTabInfoAsync(paneArgs.RightPaneNavPathParam); + tabItem.Header = $"{leftTabInfo.tabLocationHeader} | {rightTabInfo.tabLocationHeader}"; + tabItem.IconSource = leftTabInfo.tabIcon; } else { - await SetSelectedTabInfoAsync(tabItem, paneArgs.LeftPaneNavPathParam); + (tabItem.Header, tabItem.IconSource) = await GetSelectedTabInfoAsync(paneArgs.LeftPaneNavPathParam); } } else if (navigationArg is string pathArgs) { - await SetSelectedTabInfoAsync(tabItem, pathArgs); + (tabItem.Header, tabItem.IconSource) = await GetSelectedTabInfoAsync(pathArgs); } } diff --git a/Files/Views/ModernShellPage.xaml.cs b/Files/Views/ModernShellPage.xaml.cs index 3fcdb0b259ea..ae4cdf373c9b 100644 --- a/Files/Views/ModernShellPage.xaml.cs +++ b/Files/Views/ModernShellPage.xaml.cs @@ -19,7 +19,6 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -using Windows.ApplicationModel; using Windows.ApplicationModel.AppService; using Windows.ApplicationModel.Core; using Windows.ApplicationModel.DataTransfer; @@ -31,7 +30,6 @@ using Windows.UI.Text; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Animation; @@ -224,6 +222,8 @@ public ModernShellPage() App.DrivesManager.PropertyChanged += DrivesManager_PropertyChanged; AppSettings.PropertyChanged += AppSettings_PropertyChanged; + + AppServiceConnectionHelper.ConnectionChanged += AppServiceConnectionHelper_ConnectionChanged; } private void AppSettings_PropertyChanged(object sender, PropertyChangedEventArgs e) @@ -434,13 +434,16 @@ private void AppSettings_SortOptionPreferenceUpdated(object sender, EventArgs e) private void CoreWindow_PointerPressed(CoreWindow sender, PointerEventArgs args) { - if (args.CurrentPoint.Properties.IsXButton1Pressed) - { - Back_Click(); - } - else if (args.CurrentPoint.Properties.IsXButton2Pressed) + if (IsCurrentInstance) { - Forward_Click(); + if (args.CurrentPoint.Properties.IsXButton1Pressed) + { + Back_Click(); + } + else if (args.CurrentPoint.Properties.IsXButton2Pressed) + { + Forward_Click(); + } } } @@ -471,7 +474,7 @@ private async void SetAddressBarSuggestions(AutoSuggestBox sender, int maxSugges suggestions = currPath.Select(x => new ListedItem(null) { ItemPath = x.Path, - ItemName = x.Folder.Name + ItemName = x.Folder.DisplayName }).ToList(); } else if (currPath.Any()) @@ -480,12 +483,12 @@ private async void SetAddressBarSuggestions(AutoSuggestBox sender, int maxSugges suggestions = currPath.Select(x => new ListedItem(null) { ItemPath = x.Path, - ItemName = x.Folder.Name + ItemName = x.Folder.DisplayName }).Concat( subPath.Select(x => new ListedItem(null) { ItemPath = x.Path, - ItemName = Path.Combine(currPath.First().Folder.Name, x.Folder.Name) + ItemName = Path.Combine(currPath.First().Folder.DisplayName, x.Folder.DisplayName) })).ToList(); } else @@ -784,8 +787,8 @@ private async void DisplayFilesystemConsentDialog() if (App.DrivesManager?.ShowUserConsentOnInit ?? false) { App.DrivesManager.ShowUserConsentOnInit = false; - var consentDialogDisplay = new ConsentDialog(); - await consentDialogDisplay.ShowAsync(ContentDialogPlacement.Popup); + DynamicDialog dialog = DynamicDialogFactory.GetFor_ConsentDialog(); + await dialog.ShowAsync(ContentDialogPlacement.Popup); } } @@ -906,33 +909,15 @@ private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") private async void Page_Loaded(object sender, RoutedEventArgs e) { - ServiceConnection = await AppServiceConnectionHelper.BuildConnection(); + ServiceConnection = await AppServiceConnectionHelper.Instance; FilesystemViewModel = new ItemViewModel(this); FilesystemViewModel.OnAppServiceConnectionChanged(); InteractionOperations = new Interaction(this); - App.Current.Suspending += Current_Suspending; - App.Current.LeavingBackground += OnLeavingBackground; FilesystemViewModel.WorkingDirectoryModified += ViewModel_WorkingDirectoryModified; OnNavigationParamsChanged(); this.Loaded -= Page_Loaded; } - private async void OnLeavingBackground(object sender, LeavingBackgroundEventArgs e) - { - if (this.ServiceConnection == null) - { - // Need to reinitialize AppService when app is resuming - ServiceConnection = await AppServiceConnectionHelper.BuildConnection(); - FilesystemViewModel?.OnAppServiceConnectionChanged(); - } - } - - private void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e) - { - ServiceConnection?.Dispose(); - ServiceConnection = null; - } - private void ViewModel_WorkingDirectoryModified(object sender, WorkingDirectoryModifiedEventArgs e) { string value = e.Path; @@ -1027,7 +1012,7 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo break; case (false, true, false, true, VirtualKey.Delete): // shift + delete, PermanentDelete - if (!NavigationToolbar.IsEditModeEnabled && !InstanceViewModel.IsPageTypeSearchResults) + if (ContentPage.IsItemSelected && !NavigationToolbar.IsEditModeEnabled && !InstanceViewModel.IsPageTypeSearchResults) { await FilesystemHelpers.DeleteItemsAsync( ContentPage.SelectedItems.Select((item) => StorageItemHelpers.FromPathAndType( @@ -1103,8 +1088,8 @@ await FilesystemHelpers.DeleteItemsAsync( } 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 + case (false, false, true, _, VirtualKey.D): // alt + d, select address bar (english) + case (true, false, false, _, VirtualKey.L): // ctrl + l, select address bar NavigationToolbar.IsEditModeEnabled = true; break; }; @@ -1129,7 +1114,7 @@ public async void Refresh_Click() await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var ContentOwnedViewModelInstance = FilesystemViewModel; - ContentOwnedViewModelInstance.RefreshItems(null, false); + ContentOwnedViewModelInstance?.RefreshItems(null, false); }); } @@ -1175,13 +1160,16 @@ public void Up_Click() { NavigationToolbar.CanNavigateToParent = false; Frame instanceContentFrame = ContentFrame; - var instance = FilesystemViewModel; - string parentDirectoryOfPath = instance.WorkingDirectory.TrimEnd('\\'); - var lastSlashIndex = parentDirectoryOfPath.LastIndexOf("\\"); + if (string.IsNullOrEmpty(FilesystemViewModel?.WorkingDirectory)) + { + return; + } + string parentDirectoryOfPath = FilesystemViewModel.WorkingDirectory.TrimEnd('\\'); + var lastSlashIndex = parentDirectoryOfPath.LastIndexOf("\\"); if (lastSlashIndex != -1) { - parentDirectoryOfPath = instance.WorkingDirectory.Remove(lastSlashIndex); + parentDirectoryOfPath = FilesystemViewModel.WorkingDirectory.Remove(lastSlashIndex); } SelectSidebarItemFromPath(); @@ -1212,8 +1200,6 @@ public void Dispose() { Window.Current.CoreWindow.PointerPressed -= CoreWindow_PointerPressed; SystemNavigationManager.GetForCurrentView().BackRequested -= ModernShellPage_BackRequested; - App.Current.Suspending -= Current_Suspending; - App.Current.LeavingBackground -= OnLeavingBackground; App.DrivesManager.PropertyChanged -= DrivesManager_PropertyChanged; AppSettings.PropertyChanged -= AppSettings_PropertyChanged; NavigationToolbar.EditModeEnabled -= NavigationToolbar_EditModeEnabled; @@ -1252,9 +1238,16 @@ public void Dispose() FilesystemViewModel.WorkingDirectoryModified -= ViewModel_WorkingDirectoryModified; FilesystemViewModel.Dispose(); } + AppServiceConnectionHelper.ConnectionChanged -= AppServiceConnectionHelper_ConnectionChanged; + } - ServiceConnection?.Dispose(); - ServiceConnection = null; + private async void AppServiceConnectionHelper_ConnectionChanged(object sender, Task e) + { + ServiceConnection = await e; + if (FilesystemViewModel != null) + { + FilesystemViewModel.OnAppServiceConnectionChanged(); + } } private void SidebarControl_Loaded(object sender, RoutedEventArgs e) @@ -1327,7 +1320,7 @@ private void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e) /// /// Call this function to update the positioning of the preview pane. - /// This is a workaround as the VisualStateManager causes problems. + /// This is a workaround as the VisualStateManager causes problems. /// private void UpdatePositioning(bool IsHome = false) { diff --git a/Files/Views/Pages/PropertiesDetails.xaml.cs b/Files/Views/Pages/PropertiesDetails.xaml.cs index 34e196d14c2a..8fa230855f75 100644 --- a/Files/Views/Pages/PropertiesDetails.xaml.cs +++ b/Files/Views/Pages/PropertiesDetails.xaml.cs @@ -1,4 +1,6 @@ using Files.Dialogs; +using Files.Enums; +using Files.Helpers; using Files.ViewModels.Properties; using System; using System.Diagnostics; @@ -36,7 +38,7 @@ public async Task SaveChangesAsync() { while (true) { - var dialog = new PropertySaveError(); + using DynamicDialog dialog = DynamicDialogFactory.GetFor_PropertySaveErrorDialog(); try { await (BaseProperties as FileProperties).SyncPropertyChangesAsync(); @@ -44,15 +46,16 @@ public async Task SaveChangesAsync() } catch { - switch (await dialog.ShowAsync()) + await dialog.ShowAsync(); + switch (dialog.DynamicResult) { - case ContentDialogResult.Primary: + case DynamicDialogResult.Primary: break; - case ContentDialogResult.Secondary: + case DynamicDialogResult.Secondary: return true; - default: + case DynamicDialogResult.Cancel: return false; } } diff --git a/Files/Views/YourHome.xaml.cs b/Files/Views/YourHome.xaml.cs index 95d88f62d112..df10a5555ba1 100644 --- a/Files/Views/YourHome.xaml.cs +++ b/Files/Views/YourHome.xaml.cs @@ -65,8 +65,8 @@ private async void RecentFilesWidget_RecentFileInvoked(object sender, UserContro } catch (UnauthorizedAccessException) { - var consentDialog = new ConsentDialog(); - await consentDialog.ShowAsync(); + DynamicDialog dialog = DynamicDialogFactory.GetFor_ConsentDialog(); + await dialog.ShowAsync(); } catch (ArgumentException) { diff --git a/MessageRelay/Files.MessageRelay.csproj b/MessageRelay/Files.MessageRelay.csproj index ccdaf3abf334..a363aad37de7 100644 --- a/MessageRelay/Files.MessageRelay.csproj +++ b/MessageRelay/Files.MessageRelay.csproj @@ -126,7 +126,7 @@ - 6.2.11 + 6.2.12 4.7.7 From 353e6f5db953f5df798c66fbe73195f86d0587d2 Mon Sep 17 00:00:00 2001 From: Marco Gavelli Date: Sun, 14 Feb 2021 19:03:31 +0100 Subject: [PATCH 16/19] [Missing: date created, localized name] Fix merge confict --- .../StorageEnumerators/Win32StorageEnumerator.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs index 1651b22aedba..38fff5410b34 100644 --- a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs @@ -1,6 +1,7 @@ using ByteSizeLib; using Files.Extensions; using Files.Helpers; +using Files.Helpers.FileListCache; using Microsoft.Toolkit.Uwp.Extensions; using System; using System.Collections.Generic; @@ -18,6 +19,8 @@ namespace Files.Filesystem.StorageEnumerators { public static class Win32StorageEnumerator { + private static IFileListCache fileListCache = FileListCacheController.GetInstance(); + public static async Task> ListEntries( string path, string returnformat, @@ -61,7 +64,7 @@ Func, Task> intermediateAction { if (findData.cFileName != "." && findData.cFileName != "..") { - var folder = GetFolder(findData, path, returnformat, cancellationToken); + var folder = await GetFolder(findData, path, returnformat, cancellationToken); if (folder != null) { if (skipItems?.Contains(folder.ItemPath) ?? false) @@ -96,7 +99,7 @@ Func, Task> intermediateAction return tempList; } - public static ListedItem GetFolder( + public static async Task GetFolder( WIN32_FIND_DATA findData, string pathRoot, string dateReturnFormat, @@ -123,7 +126,11 @@ CancellationToken cancellationToken return null; } var itemPath = Path.Combine(pathRoot, findData.cFileName); - + string itemName = await fileListCache.ReadFileDisplayNameFromCache(itemPath, cancellationToken); + if (string.IsNullOrEmpty(itemName)) + { + itemName = findData.cFileName; + } bool isHidden = (((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden); double opacity = 1; From 14f091b354f1e60a304c1cf9b37a4853f7547e75 Mon Sep 17 00:00:00 2001 From: Marco Gavelli Date: Sun, 14 Feb 2021 21:27:00 +0100 Subject: [PATCH 17/19] Add back creationdate --- .../UniversalStorageEnumerator.cs | 13 +++++++--- .../Win32StorageEnumerator.cs | 26 ++++++++++++------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs index 6018ade48701..ffcaf77ae952 100644 --- a/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs @@ -156,14 +156,16 @@ ex is UnauthorizedAccessException private static async Task AddFolderAsync(StorageFolder folder, StorageFolderWithPath currentStorageFolder, string dateReturnFormat, CancellationToken cancellationToken) { var basicProperties = await folder.GetBasicPropertiesAsync(); - + var extraProps = await basicProperties.RetrievePropertiesAsync(new[] { "System.DateCreated" }); + DateTimeOffset.TryParse(extraProps["System.DateCreated"] as string, out var dateCreated); if (!cancellationToken.IsCancellationRequested) { return new ListedItem(folder.FolderRelativeId, dateReturnFormat) { PrimaryItemAttribute = StorageItemTypes.Folder, - ItemName = folder.Name, + ItemName = folder.DisplayName, ItemDateModifiedReal = basicProperties.DateModified, + ItemDateCreatedReal = dateCreated, ItemType = folder.DisplayType, IsHiddenItem = false, Opacity = 1, @@ -190,10 +192,12 @@ CancellationToken cancellationToken ) { var basicProperties = await file.GetBasicPropertiesAsync(); + var extraProperties = await basicProperties.RetrievePropertiesAsync(new[] { "System.DateCreated" }); // Display name does not include extension var itemName = string.IsNullOrEmpty(file.DisplayName) || App.AppSettings.ShowFileExtensions ? file.Name : file.DisplayName; - var itemDate = basicProperties.DateModified; + var itemModifiedDate = basicProperties.DateModified; + DateTimeOffset.TryParse(extraProperties["System.DateCreated"] as string, out var itemCreatedDate); var itemPath = string.IsNullOrEmpty(file.Path) ? Path.Combine(currentStorageFolder.Path, file.Name) : file.Path; var itemSize = ByteSize.FromBytes(basicProperties.Size).ToBinaryString().ConvertSizeAbbreviation(); var itemSizeBytes = basicProperties.Size; @@ -281,7 +285,8 @@ CancellationToken cancellationToken LoadFileIcon = itemThumbnailImgVis, LoadFolderGlyph = itemFolderImgVis, ItemName = itemName, - ItemDateModifiedReal = itemDate, + ItemDateModifiedReal = itemModifiedDate, + ItemDateCreatedReal = itemCreatedDate, ItemType = itemType, ItemPath = itemPath, FileSize = itemSize, diff --git a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs index 38fff5410b34..f084b5702e63 100644 --- a/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs +++ b/Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs @@ -111,18 +111,25 @@ CancellationToken cancellationToken return null; } - DateTime itemDate; + DateTime itemModifiedDate; + DateTime itemCreatedDate; try { - FileTimeToSystemTime(ref findData.ftLastWriteTime, out SYSTEMTIME systemTimeOutput); - itemDate = new DateTime( - systemTimeOutput.Year, systemTimeOutput.Month, systemTimeOutput.Day, - systemTimeOutput.Hour, systemTimeOutput.Minute, systemTimeOutput.Second, systemTimeOutput.Milliseconds, + FileTimeToSystemTime(ref findData.ftLastWriteTime, out SYSTEMTIME systemModifiedTimeOutput); + itemModifiedDate = new DateTime( + systemModifiedTimeOutput.Year, systemModifiedTimeOutput.Month, systemModifiedTimeOutput.Day, + systemModifiedTimeOutput.Hour, systemModifiedTimeOutput.Minute, systemModifiedTimeOutput.Second, systemModifiedTimeOutput.Milliseconds, + DateTimeKind.Utc); + + FileTimeToSystemTime(ref findData.ftCreationTime, out SYSTEMTIME systemCreatedTimeOutput); + itemCreatedDate = new DateTime( + systemCreatedTimeOutput.Year, systemCreatedTimeOutput.Month, systemCreatedTimeOutput.Day, + systemCreatedTimeOutput.Hour, systemCreatedTimeOutput.Minute, systemCreatedTimeOutput.Second, systemCreatedTimeOutput.Milliseconds, DateTimeKind.Utc); } catch (ArgumentException) { - // Invalid date means invalid findData, do not add to list + // Invalid date means invalid findData, do not add to list return null; } var itemPath = Path.Combine(pathRoot, findData.cFileName); @@ -142,8 +149,9 @@ CancellationToken cancellationToken return new ListedItem(null, dateReturnFormat) { PrimaryItemAttribute = StorageItemTypes.Folder, - ItemName = findData.cFileName, - ItemDateModifiedReal = itemDate, + ItemName = itemName, + ItemDateModifiedReal = itemModifiedDate, + ItemDateCreatedReal = itemCreatedDate, ItemType = "FileFolderListItem".GetLocalized(), LoadFolderGlyph = true, FileImage = null, @@ -209,7 +217,7 @@ CancellationToken cancellationToken } catch (ArgumentException) { - // Invalid date means invalid findData, do not add to list + // Invalid date means invalid findData, do not add to list return null; } From 75f9a4266389ce64a2790801613b1d018af14571 Mon Sep 17 00:00:00 2001 From: Marco Gavelli Date: Sun, 14 Feb 2021 21:28:01 +0100 Subject: [PATCH 18/19] Turn off caching by default --- Files/ViewModels/SettingsViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Files/ViewModels/SettingsViewModel.cs b/Files/ViewModels/SettingsViewModel.cs index be5130c22a96..b94c648dc138 100644 --- a/Files/ViewModels/SettingsViewModel.cs +++ b/Files/ViewModels/SettingsViewModel.cs @@ -671,7 +671,7 @@ public bool ShowFileOwner /// public bool UseFileListCache { - get => Get(true); + get => Get(false); set => Set(value); } @@ -680,7 +680,7 @@ public bool UseFileListCache /// public bool UsePreemptiveCache { - get => Get(true); + get => Get(false); set => Set(value); } From f2e1f9a12f9371b6180b2518de703bdd080ce5b4 Mon Sep 17 00:00:00 2001 From: Marco Gavelli Date: Sun, 14 Feb 2021 21:49:46 +0100 Subject: [PATCH 19/19] Update Files/ViewModels/SettingsViewModel.cs Co-authored-by: Yair Aichenbaum <39923744+yaichenbaum@users.noreply.github.com> --- Files/ViewModels/SettingsViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Files/ViewModels/SettingsViewModel.cs b/Files/ViewModels/SettingsViewModel.cs index b94c648dc138..ae03c5189d75 100644 --- a/Files/ViewModels/SettingsViewModel.cs +++ b/Files/ViewModels/SettingsViewModel.cs @@ -671,7 +671,7 @@ public bool ShowFileOwner /// public bool UseFileListCache { - get => Get(false); + get => Get(true); set => Set(value); }