diff --git a/Common/ShellFileItem.cs b/Common/ShellFileItem.cs index 16db53a786fd..c6901be1e5d4 100644 --- a/Common/ShellFileItem.cs +++ b/Common/ShellFileItem.cs @@ -10,14 +10,16 @@ public class ShellFileItem public string FilePath; public DateTime RecycleDate; public string FileSize; - public long FileSizeBytes; + public ulong FileSizeBytes; public string FileType; public ShellFileItem() { } - public ShellFileItem(bool isFolder, string recyclePath, string fileName, string filePath, DateTime recycleDate, string fileSize, long fileSizeBytes, string fileType) + public ShellFileItem( + bool isFolder, string recyclePath, string fileName, string filePath, + DateTime recycleDate, string fileSize, ulong fileSizeBytes, string fileType) { this.IsFolder = isFolder; this.RecyclePath = recyclePath; diff --git a/Files.Launcher/Program.cs b/Files.Launcher/Program.cs index ba60fcb36f28..2a8dbc03930e 100644 --- a/Files.Launcher/Program.cs +++ b/Files.Launcher/Program.cs @@ -1,6 +1,5 @@ using Files.Common; using Newtonsoft.Json; -using NLog; using System; using System.Collections.Generic; using System.ComponentModel; @@ -15,6 +14,7 @@ using Windows.ApplicationModel.AppService; using Windows.Foundation.Collections; using Windows.Storage; +using static Vanara.PInvoke.Shell32; namespace FilesFullTrust { @@ -25,7 +25,7 @@ internal class Program [STAThread] private static void Main(string[] args) { - Windows.Storage.StorageFolder storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder; + StorageFolder storageFolder = ApplicationData.Current.LocalFolder; NLog.LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "NLog.config")); NLog.LogManager.Configuration.Variables["LogPath"] = storageFolder.Path; @@ -45,14 +45,31 @@ private static void Main(string[] args) try { // Create shell COM object and get recycle bin folder - recycler = new ShellFolder(Vanara.PInvoke.Shell32.KNOWNFOLDERID.FOLDERID_RecycleBinFolder); - Windows.Storage.ApplicationData.Current.LocalSettings.Values["RecycleBin_Title"] = recycler.Name; - - // Create shell watcher to monitor recycle bin folder - watcher = new ShellItemChangeWatcher(recycler, false); - watcher.NotifyFilter = ChangeFilters.AllDiskEvents; - watcher.Changed += Watcher_Changed; - //watcher.EnableRaisingEvents = true; // TODO: uncomment this when updated library is released + recycler = new ShellFolder(KNOWNFOLDERID.FOLDERID_RecycleBinFolder); + ApplicationData.Current.LocalSettings.Values["RecycleBin_Title"] = recycler.Name; + + // Create filesystem watcher to monitor recycle bin folder(s) + // SHChangeNotifyRegister only works if recycle bin is open in explorer :( + watchers = new List(); + var sid = System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString(); + foreach (var drive in DriveInfo.GetDrives()) + { + var recycle_path = Path.Combine(drive.Name, "$Recycle.Bin", sid); + if (!Directory.Exists(recycle_path)) + { + continue; + } + var watcher = new FileSystemWatcher(); + watcher.Path = recycle_path; + watcher.Filter = "*.*"; + watcher.NotifyFilter = NotifyFilters.LastWrite + | NotifyFilters.FileName + | NotifyFilters.DirectoryName; + watcher.Created += Watcher_Changed; + watcher.Deleted += Watcher_Changed; + watcher.EnableRaisingEvents = true; + watchers.Add(watcher); + } // Connect to app service and wait until the connection gets closed appServiceExit = new AutoResetEvent(false); @@ -62,7 +79,10 @@ private static void Main(string[] args) finally { connection?.Dispose(); - watcher?.Dispose(); + foreach (var watcher in watchers) + { + watcher.Dispose(); + } recycler?.Dispose(); appServiceExit?.Dispose(); mutex?.ReleaseMutex(); @@ -75,20 +95,24 @@ private static void UnhandledExceptionTrapper(object sender, UnhandledExceptionE Logger.Error(exception, exception.Message); } - private static async void Watcher_Changed(object sender, ShellItemChangeWatcher.ShellItemChangeEventArgs e) + private static async void Watcher_Changed(object sender, FileSystemEventArgs e) { - Console.WriteLine($"File: {e.ChangedItems.FirstOrDefault()?.FileSystemPath} {e.ChangeType}"); + Debug.WriteLine("Reycle bin event: {0}, {1}", e.ChangeType, e.FullPath); if (connection != null) { // Send message to UWP app to refresh items - await connection.SendMessageAsync(new ValueSet() { { "FileSystem", @"Shell:RecycleBinFolder" }, { "Path", e.ChangedItems.FirstOrDefault()?.FileSystemPath }, { "Type", e.ChangeType.ToString() } }); + await connection.SendMessageAsync(new ValueSet() { + { "FileSystem", @"Shell:RecycleBinFolder" }, + { "Path", e.FullPath }, + { "Type", e.ChangeType.ToString() } + }); } } private static AppServiceConnection connection; private static AutoResetEvent appServiceExit; private static ShellFolder recycler; - private static ShellItemChangeWatcher watcher; + private static IList watchers; private static async void InitializeAppServiceConnection() { @@ -126,7 +150,7 @@ private static async void Connection_RequestReceived(AppServiceConnection sender // Instead a single instance of the process is running // Requests from UWP app are sent via AppService connection var arguments = (string)args.Request.Message["Arguments"]; - var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; + var localSettings = ApplicationData.Current.LocalSettings; Logger.Info($"Argument: {arguments}"); await parseArguments(args, messageDeferral, arguments, localSettings); @@ -180,8 +204,8 @@ private static async Task parseArguments(AppServiceRequestReceivedEventArgs args #if DEBUG // In debug mode this kills this process too?? #else - var pid = (int)args.Request.Message["pid"]; - Process.GetProcessById(pid).Kill(); + var pid = (int)args.Request.Message["pid"]; + Process.GetProcessById(pid).Kill(); #endif Process process = new Process(); @@ -201,7 +225,7 @@ private static async Task parseArguments(AppServiceRequestReceivedEventArgs args case "ParseAguments": var responseArray = new ValueSet(); var resultArgument = Win32API.CommandLineToArgs((string)args.Request.Message["Command"]); - responseArray.Add("ParsedArguments", Newtonsoft.Json.JsonConvert.SerializeObject(resultArgument)); + responseArray.Add("ParsedArguments", JsonConvert.SerializeObject(resultArgument)); await args.Request.SendResponseAsync(responseArray); break; @@ -236,23 +260,27 @@ private static async Task parseRecycleBinAction(AppServiceRequestReceivedEventAr { case "Empty": // Shell function to empty recyclebin - Vanara.PInvoke.Shell32.SHEmptyRecycleBin(IntPtr.Zero, null, Vanara.PInvoke.Shell32.SHERB.SHERB_NOCONFIRMATION | Vanara.PInvoke.Shell32.SHERB.SHERB_NOPROGRESSUI); + SHEmptyRecycleBin(IntPtr.Zero, null, SHERB.SHERB_NOCONFIRMATION | SHERB.SHERB_NOPROGRESSUI); break; case "Query": var responseQuery = new ValueSet(); - Win32API.SHQUERYRBINFO queryBinInfo = new Win32API.SHQUERYRBINFO(); - queryBinInfo.cbSize = (uint)Marshal.SizeOf(typeof(Win32API.SHQUERYRBINFO)); - var res = Win32API.SHQueryRecycleBin("", ref queryBinInfo); - // TODO: use this when updated library is released - //Vanara.PInvoke.Shell32.SHQUERYRBINFO queryBinInfo = new Vanara.PInvoke.Shell32.SHQUERYRBINFO(); - //Vanara.PInvoke.Shell32.SHQueryRecycleBin(null, ref queryBinInfo); + SHQUERYRBINFO queryBinInfo = new SHQUERYRBINFO(); + queryBinInfo.cbSize = (uint)Marshal.SizeOf(queryBinInfo); + var res = SHQueryRecycleBin(null, ref queryBinInfo); if (res == Vanara.PInvoke.HRESULT.S_OK) { var numItems = queryBinInfo.i64NumItems; var binSize = queryBinInfo.i64Size; responseQuery.Add("NumItems", numItems); responseQuery.Add("BinSize", binSize); + responseQuery.Add("FileOwner", (string)recycler.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.FileOwner]); + if (watchers.Any()) + { + var info = new DirectoryInfo(watchers.First().Path); + responseQuery.Add("DateAccessed", info.LastAccessTime.ToBinary()); + responseQuery.Add("DateCreated", info.CreationTime.ToBinary()); + } await args.Request.SendResponseAsync(responseQuery); } break; @@ -265,20 +293,26 @@ private static async Task parseRecycleBinAction(AppServiceRequestReceivedEventAr { try { - folderItem.Properties.ReadOnly = true; - folderItem.Properties.NoInheritedProperties = false; string recyclePath = folderItem.FileSystemPath; // True path on disk string fileName = Path.GetFileName(folderItem.Name); // Original file name string filePath = folderItem.Name; // Original file path + name - var dt = (System.Runtime.InteropServices.ComTypes.FILETIME)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.DateCreated]; - var recycleDate = dt.ToDateTime().ToLocalTime(); // This is LocalTime - string fileSize = folderItem.Properties.GetPropertyString(Vanara.PInvoke.Ole32.PROPERTYKEY.System.Size); - long fileSizeBytes = (long)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.Size]; - string fileType = (string)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.ItemTypeText]; bool isFolder = folderItem.IsFolder && Path.GetExtension(folderItem.Name) != ".zip"; - folderContentsList.Add(new ShellFileItem(isFolder, recyclePath, fileName, filePath, recycleDate, fileSize, fileSizeBytes, fileType)); + if (folderItem.Properties == null) + { + folderContentsList.Add(new ShellFileItem(isFolder, recyclePath, fileName, filePath, DateTime.Now, null, 0, null)); + continue; + } + folderItem.Properties.TryGetValue( + Vanara.PInvoke.Ole32.PROPERTYKEY.System.DateCreated, out var fileTime); + var recycleDate = fileTime?.ToDateTime().ToLocalTime() ?? DateTime.Now; // This is LocalTime + string fileSize = folderItem.Properties.TryGetValue( + Vanara.PInvoke.Ole32.PROPERTYKEY.System.Size, out var fileSizeBytes) ? + folderItem.Properties.GetPropertyString(Vanara.PInvoke.Ole32.PROPERTYKEY.System.Size) : null; + folderItem.Properties.TryGetValue( + Vanara.PInvoke.Ole32.PROPERTYKEY.System.ItemTypeText, out var fileType); + folderContentsList.Add(new ShellFileItem(isFolder, recyclePath, fileName, filePath, recycleDate, fileSize, fileSizeBytes ?? 0, fileType)); } - catch (System.IO.FileNotFoundException) + catch (FileNotFoundException) { // Happens if files are being deleted } @@ -287,7 +321,7 @@ private static async Task parseRecycleBinAction(AppServiceRequestReceivedEventAr folderItem.Dispose(); } } - responseEnum.Add("Enumerate", Newtonsoft.Json.JsonConvert.SerializeObject(folderContentsList)); + responseEnum.Add("Enumerate", JsonConvert.SerializeObject(folderContentsList)); await args.Request.SendResponseAsync(responseEnum); break; @@ -377,13 +411,13 @@ private static void HandleApplicationLaunch(string application, AppServiceReques if (!group.Any()) continue; var files = group.Select(x => new ShellItem(x)); using var sf = files.First().Parent; - Vanara.PInvoke.Shell32.IContextMenu menu = null; + IContextMenu menu = null; try { - menu = sf.GetChildrenUIObjects(null, files.ToArray()); - menu.QueryContextMenu(Vanara.PInvoke.HMENU.NULL, 0, 0, 0, Vanara.PInvoke.Shell32.CMF.CMF_DEFAULTONLY); - var pici = new Vanara.PInvoke.Shell32.CMINVOKECOMMANDINFOEX(); - pici.lpVerb = Vanara.PInvoke.Shell32.CMDSTR_OPEN; + menu = sf.GetChildrenUIObjects(null, files.ToArray()); + menu.QueryContextMenu(Vanara.PInvoke.HMENU.NULL, 0, 0, 0, CMF.CMF_DEFAULTONLY); + var pici = new CMINVOKECOMMANDINFOEX(); + pici.lpVerb = CMDSTR_OPEN; pici.nShow = Vanara.PInvoke.ShowWindowCommand.SW_SHOW; pici.cbSize = (uint)Marshal.SizeOf(pici); menu.InvokeCommand(pici); @@ -412,7 +446,7 @@ private static void HandleApplicationLaunch(string application, AppServiceReques private static bool HandleCommandLineArgs() { - var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; + var localSettings = ApplicationData.Current.LocalSettings; var arguments = (string)localSettings.Values["Arguments"]; if (!string.IsNullOrWhiteSpace(arguments)) { diff --git a/Files.Launcher/Win32API.cs b/Files.Launcher/Win32API.cs index 063b3cdf8870..37b835093513 100644 --- a/Files.Launcher/Win32API.cs +++ b/Files.Launcher/Win32API.cs @@ -6,35 +6,43 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; +using System.Threading; +using System.Threading.Tasks; using Vanara.Windows.Shell; namespace FilesFullTrust { internal class Win32API { - // TODO: remove this when updated library is released - [DllImport("shell32.dll")] - public static extern Vanara.PInvoke.HRESULT SHQueryRecycleBin(string pszRootPath, ref SHQUERYRBINFO pSHQueryRBInfo); - - // TODO: remove this when updated library is released - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] - public struct SHQUERYRBINFO + public static Task StartSTATask(Func func) { - public uint cbSize; - public long i64Size; - public long i64NumItems; + var tcs = new TaskCompletionSource(); + Thread thread = new Thread(() => + { + try + { + tcs.SetResult(func()); + } + catch (Exception e) + { + tcs.SetException(e); + } + }); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + return tcs.Task; } [DllImport("shell32.dll", CharSet = CharSet.Ansi)] - public static extern IntPtr FindExecutable(string lpFile, string lpDirectory, [Out] System.Text.StringBuilder lpResult); + public static extern IntPtr FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult); - public static async System.Threading.Tasks.Task GetFileAssociation(string filename) + public static async Task GetFileAssociation(string filename) { // Find UWP apps var uwp_apps = await Windows.System.Launcher.FindFileHandlersAsync(System.IO.Path.GetExtension(filename)); if (uwp_apps.Any()) return uwp_apps.First().PackageFamilyName; // Find desktop apps - var lpResult = new System.Text.StringBuilder(); + var lpResult = new StringBuilder(); var hResult = FindExecutable(filename, null, lpResult); if (hResult.ToInt64() > 32) return lpResult.ToString(); return null; diff --git a/Files/BaseLayout.cs b/Files/BaseLayout.cs index 2c6e249a06ea..9433a8063750 100644 --- a/Files/BaseLayout.cs +++ b/Files/BaseLayout.cs @@ -320,23 +320,7 @@ private async void MenuLayoutItem_Click(object sender, RoutedEventArgs e) } } - public void RightClickContextMenu_Opening(object sender, object e) - { - if (App.CurrentInstance.FilesystemViewModel.WorkingDirectory.StartsWith(AppSettings.RecycleBinPath)) - { - (this.FindName("EmptyRecycleBin") as MenuFlyoutItemBase).Visibility = Visibility.Visible; - (this.FindName("OpenTerminal") as MenuFlyoutItemBase).IsEnabled = false; - UnloadMenuFlyoutItemByName("NewEmptySpace"); - } - else - { - UnloadMenuFlyoutItemByName("EmptyRecycleBin"); - (this.FindName("OpenTerminal") as MenuFlyoutItemBase).IsEnabled = true; - (this.FindName("NewEmptySpace") as MenuFlyoutItemBase).Visibility = Visibility.Visible; - } - } - - public async void RightClickItemContextMenu_Opening(object sender, object e) + public void RightClickItemContextMenu_Opening(object sender, object e) { SetShellContextmenu(); diff --git a/Files/DataModels/SidebarPinnedModel.cs b/Files/DataModels/SidebarPinnedModel.cs index d6faef716efe..8678fb22eb45 100644 --- a/Files/DataModels/SidebarPinnedModel.cs +++ b/Files/DataModels/SidebarPinnedModel.cs @@ -70,7 +70,8 @@ public async void AddItemToSidebar(string path) try { StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(path); - int insertIndex = App.sideBarItems.IndexOf(App.sideBarItems.Last(x => x.ItemType == NavigationControlItemType.Location)) + 1; + int insertIndex = App.sideBarItems.IndexOf(App.sideBarItems.Last(x => x.ItemType == NavigationControlItemType.Location + && !x.Path.Equals(App.AppSettings.RecycleBinPath))) + 1; var locationItem = new LocationItem { Path = path, @@ -84,6 +85,11 @@ public async void AddItemToSidebar(string path) { Debug.WriteLine(ex.Message); } + catch (ArgumentException ex) + { + Debug.WriteLine("Pinned item was invalid and will be removed from the file lines list soon: " + ex.Message); + RemoveItem(path); + } catch (FileNotFoundException ex) { Debug.WriteLine("Pinned item was deleted and will be removed from the file lines list soon: " + ex.Message); diff --git a/Files/Interacts/Interaction.cs b/Files/Interacts/Interaction.cs index cde8e180795e..a59d9bdc4f56 100644 --- a/Files/Interacts/Interaction.cs +++ b/Files/Interacts/Interaction.cs @@ -680,7 +680,11 @@ public async void DeleteItem_Click(object sender, RoutedEventArgs e) } catch (IOException) { - if (await DialogDisplayHelper.ShowDialog(ResourceController.GetTranslation("FileInUseDeleteDialog.Title"), ResourceController.GetTranslation("FileInUseDeleteDialog.Text"), ResourceController.GetTranslation("FileInUseDeleteDialog.PrimaryButtonText"), ResourceController.GetTranslation("FileInUseDeleteDialog.SecondaryButtonText"))) + if (await DialogDisplayHelper.ShowDialog( + ResourceController.GetTranslation("FileInUseDeleteDialog/Title"), + ResourceController.GetTranslation("FileInUseDeleteDialog/Text"), + ResourceController.GetTranslation("FileInUseDeleteDialog/PrimaryButtonText"), + ResourceController.GetTranslation("FileInUseDeleteDialog/SecondaryButtonText"))) { DeleteItem_Click(null, null); } @@ -972,13 +976,26 @@ private enum ImpossibleActionResponseTypes public async void EmptyRecycleBin_ClickAsync(object sender, RoutedEventArgs e) { - if (App.Connection != null) + var ConfirmEmptyBinDialog = new ContentDialog() { - var value = new ValueSet(); - value.Add("Arguments", "RecycleBin"); - value.Add("action", "Empty"); - // Send request to fulltrust process to empty recyclebin - await App.Connection.SendMessageAsync(value); + Title = ResourceController.GetTranslation("ConfirmEmptyBinDialogTitle"), + Content = ResourceController.GetTranslation("ConfirmEmptyBinDialogContent"), + PrimaryButtonText = ResourceController.GetTranslation("ConfirmEmptyBinDialog/PrimaryButtonText"), + SecondaryButtonText = ResourceController.GetTranslation("ConfirmEmptyBinDialog/SecondaryButtonText") + }; + + ContentDialogResult result = await ConfirmEmptyBinDialog.ShowAsync(); + + if (result == ContentDialogResult.Primary) + { + if (App.Connection != null) + { + var value = new ValueSet(); + value.Add("Arguments", "RecycleBin"); + value.Add("action", "Empty"); + // Send request to fulltrust process to empty recyclebin + await App.Connection.SendMessageAsync(value); + } } } @@ -1006,6 +1023,7 @@ public async Task PasteItems(DataPackageView packageView, string destinationPath } itemsToPaste = await packageView.GetStorageItemsAsync(); + HashSet pastedSourceItems = new HashSet(); HashSet pastedItems = new HashSet(); itemsPasted = 0; if (itemsToPaste.Count > 3) @@ -1049,6 +1067,7 @@ public async Task PasteItems(DataPackageView packageView, string destinationPath try { StorageFolder pastedFolder = await CloneDirectoryAsync(item.Path, destinationPath, item.Name, false); + pastedSourceItems.Add(item); pastedItems.Add(pastedFolder); } catch (FileNotFoundException) @@ -1068,6 +1087,7 @@ public async Task PasteItems(DataPackageView packageView, string destinationPath { StorageFile clipboardFile = await StorageFile.GetFileFromPathAsync(item.Path); StorageFile pastedFile = await clipboardFile.CopyAsync(await StorageFolder.GetFolderFromPathAsync(destinationPath), item.Name, NameCollisionOption.GenerateUniqueName); + pastedSourceItems.Add(item); pastedItems.Add(pastedFile); } catch (FileNotFoundException) @@ -1080,19 +1100,19 @@ public async Task PasteItems(DataPackageView packageView, string destinationPath if (acceptedOperation == DataPackageOperation.Move) { - foreach (IStorageItem item in itemsToPaste) + foreach (IStorageItem item in pastedSourceItems) { try { if (item.IsOfType(StorageItemTypes.File)) { StorageFile file = await StorageFile.GetFileFromPathAsync(item.Path); - await file.DeleteAsync(); + await file.DeleteAsync(StorageDeleteOption.PermanentDelete); } else if (item.IsOfType(StorageItemTypes.Folder)) { StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(item.Path); - await folder.DeleteAsync(); + await folder.DeleteAsync(StorageDeleteOption.PermanentDelete); } } catch (FileNotFoundException) diff --git a/Files/MultilingualResources/Files.de-DE.xlf b/Files/MultilingualResources/Files.de-DE.xlf index 567479e02bb4..886fc783d13f 100644 --- a/Files/MultilingualResources/Files.de-DE.xlf +++ b/Files/MultilingualResources/Files.de-DE.xlf @@ -829,6 +829,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.es-ES.xlf b/Files/MultilingualResources/Files.es-ES.xlf index 0faab8c2b983..2bee3297c77d 100644 --- a/Files/MultilingualResources/Files.es-ES.xlf +++ b/Files/MultilingualResources/Files.es-ES.xlf @@ -822,6 +822,22 @@ Show Owner in properties Mostrar propietario de archivo en propiedades + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.fr-FR.xlf b/Files/MultilingualResources/Files.fr-FR.xlf index dd6f5e02293d..36fc0927316f 100644 --- a/Files/MultilingualResources/Files.fr-FR.xlf +++ b/Files/MultilingualResources/Files.fr-FR.xlf @@ -825,6 +825,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.it-IT.xlf b/Files/MultilingualResources/Files.it-IT.xlf index 1b4cd524ed43..b282649e26d6 100644 --- a/Files/MultilingualResources/Files.it-IT.xlf +++ b/Files/MultilingualResources/Files.it-IT.xlf @@ -830,6 +830,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.ja-JP.xlf b/Files/MultilingualResources/Files.ja-JP.xlf index 80c175923e01..b854b8978707 100644 --- a/Files/MultilingualResources/Files.ja-JP.xlf +++ b/Files/MultilingualResources/Files.ja-JP.xlf @@ -823,6 +823,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.nl-NL.xlf b/Files/MultilingualResources/Files.nl-NL.xlf index 4863051bf68d..4c9c1aa1bf50 100644 --- a/Files/MultilingualResources/Files.nl-NL.xlf +++ b/Files/MultilingualResources/Files.nl-NL.xlf @@ -825,6 +825,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.pl-PL.xlf b/Files/MultilingualResources/Files.pl-PL.xlf index 6b7fa9f0e4c5..c64df77c4a39 100644 --- a/Files/MultilingualResources/Files.pl-PL.xlf +++ b/Files/MultilingualResources/Files.pl-PL.xlf @@ -825,6 +825,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.ru-RU.xlf b/Files/MultilingualResources/Files.ru-RU.xlf index 3096eac30d34..7400624dcf8f 100644 --- a/Files/MultilingualResources/Files.ru-RU.xlf +++ b/Files/MultilingualResources/Files.ru-RU.xlf @@ -828,6 +828,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes байт diff --git a/Files/MultilingualResources/Files.ta.xlf b/Files/MultilingualResources/Files.ta.xlf index 2b8c155e9cee..0e40142d0ae8 100644 --- a/Files/MultilingualResources/Files.ta.xlf +++ b/Files/MultilingualResources/Files.ta.xlf @@ -828,6 +828,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.tr-TR.xlf b/Files/MultilingualResources/Files.tr-TR.xlf index 0ba15ea8a8f1..4e93d97c36e0 100644 --- a/Files/MultilingualResources/Files.tr-TR.xlf +++ b/Files/MultilingualResources/Files.tr-TR.xlf @@ -825,6 +825,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/MultilingualResources/Files.uk-UA.xlf b/Files/MultilingualResources/Files.uk-UA.xlf index b1c0e4af67b7..0b61db184e06 100644 --- a/Files/MultilingualResources/Files.uk-UA.xlf +++ b/Files/MultilingualResources/Files.uk-UA.xlf @@ -828,6 +828,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes байт diff --git a/Files/MultilingualResources/Files.zh-Hans.xlf b/Files/MultilingualResources/Files.zh-Hans.xlf index a582ef6de16f..6779f1b3201e 100644 --- a/Files/MultilingualResources/Files.zh-Hans.xlf +++ b/Files/MultilingualResources/Files.zh-Hans.xlf @@ -823,6 +823,22 @@ Show Owner in properties Show Owner in properties + + Cancel + Cancel + + + Are you sure you want to delete all items? + Are you sure you want to delete all items? + + + Empty recycle bin + Empty recycle bin + + + OK + OK + bytes bytes diff --git a/Files/Strings/en-US/Resources.resw b/Files/Strings/en-US/Resources.resw index 18a5710232a1..1cc0b8abe808 100644 --- a/Files/Strings/en-US/Resources.resw +++ b/Files/Strings/en-US/Resources.resw @@ -729,6 +729,18 @@ Pin directory to sidebar + + OK + + + Cancel + + + Are you sure you want to delete all items? + + + Empty recycle bin + bytes diff --git a/Files/UserControls/YourHome.xaml.cs b/Files/UserControls/YourHome.xaml.cs index 6c4edbfa3a0a..8be490d32f3b 100644 --- a/Files/UserControls/YourHome.xaml.cs +++ b/Files/UserControls/YourHome.xaml.cs @@ -185,7 +185,9 @@ private async void RecentsView_ItemClick(object sender, ItemClickEventArgs e) } catch (COMException) { - await DialogDisplayHelper.ShowDialog(ResourceController.GetTranslation("DriveUnpluggedDialog.Title"), ResourceController.GetTranslation("DriveUnpluggedDialog.Text")); + await DialogDisplayHelper.ShowDialog( + ResourceController.GetTranslation("DriveUnpluggedDialog/Title"), + ResourceController.GetTranslation("DriveUnpluggedDialog/Text")); } } diff --git a/Files/View Models/ItemViewModel.cs b/Files/View Models/ItemViewModel.cs index f6ec5404f80f..20b4ebc29933 100644 --- a/Files/View Models/ItemViewModel.cs +++ b/Files/View Models/ItemViewModel.cs @@ -691,6 +691,7 @@ public async Task EnumerateItemsFromSpecialFolder(string path) { CurrentFolder = new ListedItem(null) { + PrimaryItemAttribute = StorageItemTypes.Folder, ItemPropertiesInitialized = true, ItemName = ApplicationData.Current.LocalSettings.Values.Get("RecycleBin_Title", "Recycle Bin"), ItemDateModifiedReal = DateTimeOffset.Now, // Fake for now @@ -773,7 +774,7 @@ public async Task EnumerateItemsFromSpecialFolder(string path) ItemPath = item.RecyclePath, // this is the true path on disk so other stuff can work as is ItemOriginalPath = item.FilePath, FileSize = item.FileSize, - FileSizeBytes = item.FileSizeBytes + FileSizeBytes = (long)item.FileSizeBytes }); } if (count % 64 == 0) @@ -837,7 +838,9 @@ public async Task EnumerateItemsFromStandardFolder(string path) } catch (FileNotFoundException) { - await DialogDisplayHelper.ShowDialog(ResourceController.GetTranslation("FolderNotFoundDialog/Title"), ResourceController.GetTranslation("FolderNotFoundDialog/Text")); + await DialogDisplayHelper.ShowDialog( + ResourceController.GetTranslation("FolderNotFoundDialog/Title"), + ResourceController.GetTranslation("FolderNotFoundDialog/Text")); IsLoadingItems = false; return; } diff --git a/Files/View Models/SelectedItemsPropertiesViewModel.cs b/Files/View Models/SelectedItemsPropertiesViewModel.cs index 66f55f097ecc..5d57ac622e2c 100644 --- a/Files/View Models/SelectedItemsPropertiesViewModel.cs +++ b/Files/View Models/SelectedItemsPropertiesViewModel.cs @@ -502,7 +502,7 @@ public SelectedItemsPropertiesViewModel(ListedItem item) { ItemName = Item.ItemName; ItemType = Item.ItemType; - ItemPath = Path.GetDirectoryName(Item.ItemPath); + ItemPath = Path.IsPathRooted(Item.ItemPath) ? Path.GetDirectoryName(Item.ItemPath) : Item.ItemPath; ItemModifiedTimestamp = Item.ItemDateModified; FileIconSource = Item.FileImage; LoadFolderGlyph = Item.LoadFolderGlyph; diff --git a/Files/Views/LayoutModes/GenericFileBrowser.xaml b/Files/Views/LayoutModes/GenericFileBrowser.xaml index 967d091867aa..9c63c31dd1f3 100644 --- a/Files/Views/LayoutModes/GenericFileBrowser.xaml +++ b/Files/Views/LayoutModes/GenericFileBrowser.xaml @@ -19,7 +19,7 @@ mc:Ignorable="d"> - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Background="Transparent"> + + + + + + + + - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VerticalAlignment="Stretch"> + + + + + + + +