diff --git a/src/Files.Launcher/Files.Launcher.csproj b/src/Files.Launcher/Files.Launcher.csproj index fbb6926ad298..c398e1c4538c 100644 --- a/src/Files.Launcher/Files.Launcher.csproj +++ b/src/Files.Launcher/Files.Launcher.csproj @@ -39,13 +39,13 @@ false - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest diff --git a/src/Files.Uwp/BaseLayout.cs b/src/Files.Uwp/BaseLayout.cs index f75e9d56ddd0..254b9a637d32 100644 --- a/src/Files.Uwp/BaseLayout.cs +++ b/src/Files.Uwp/BaseLayout.cs @@ -39,6 +39,9 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Navigation; using static Files.Uwp.Helpers.PathNormalization; +using System.Collections.Specialized; +using System.Runtime.InteropServices; +using Windows.Storage.FileProperties; namespace Files.Uwp { @@ -376,7 +379,7 @@ public virtual void ResetItemOpacity() } } - protected ListedItem GetItemFromElement(object element) + protected ListedItem GetItemFromElement(object element) { var item = element as ContentControl; if (item == null || !CanGetItemFromElement(element)) @@ -858,95 +861,21 @@ protected virtual void Page_CharacterReceived(CoreWindow sender, CharacterReceiv protected async void FileList_DragItemsStarting(object sender, DragItemsStartingEventArgs e) { - ConcurrentBag selectedStorageItems = new ConcurrentBag(); - + // Only support IStorageItem capable paths e.Items.OfType().ForEach(item => SelectedItems.Add(item)); - var itemsCount = e.Items.Count; - PostedStatusBanner banner = itemsCount > 50 ? App.OngoingTasksViewModel.PostOperationBanner( - string.Empty, - string.Format("StatusPreparingItemsDetails_Plural".GetLocalized(), itemsCount), - 0, - ReturnResult.InProgress, - FileOperationType.Prepare, new CancellationTokenSource()) : null; - try { - await e.Items.OfType().ParallelForEachAsync(async item => - { - if (banner != null) - { - ((IProgress)banner.Progress).Report(selectedStorageItems.Count / (float)itemsCount * 100); - } - - if (item is FtpItem ftpItem) - { - if (item.PrimaryItemAttribute is StorageItemTypes.File or StorageItemTypes.Folder) - { - selectedStorageItems.Add(await ftpItem.ToStorageItem()); - } - } - else if (item.PrimaryItemAttribute == StorageItemTypes.File || item is ZipItem) - { - var result = await ParentShellPageInstance.FilesystemViewModel.GetFileFromPathAsync(item.ItemPath) - .OnSuccess(t => selectedStorageItems.Add(t)); - if (!result) - { - throw new IOException($"Failed to process {item.ItemPath}.", (int)result.ErrorCode); - } - } - else if (item.PrimaryItemAttribute == StorageItemTypes.Folder) - { - var result = await ParentShellPageInstance.FilesystemViewModel.GetFolderFromPathAsync(item.ItemPath) - .OnSuccess(t => selectedStorageItems.Add(t)); - if (!result) - { - throw new IOException($"Failed to process {item.ItemPath}.", (int)result.ErrorCode); - } - } - }, 10, banner?.CancellationToken ?? default); - } - catch (Exception ex) - { - if (ex.HResult == (int)FileSystemStatusCode.Unauthorized) - { - var itemList = e.Items.OfType().Select(x => StorageHelpers.FromPathAndType( - x.ItemPath, x.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)); - e.Data.Properties["FileDrop"] = itemList.ToList(); - } - else - { - e.Cancel = true; - } - banner?.Remove(); - return; - } - - banner?.Remove(); - - var onlyStandard = selectedStorageItems.All(x => x is StorageFile || x is StorageFolder || x is SystemStorageFile || x is SystemStorageFolder); - if (onlyStandard) - { - selectedStorageItems = new ConcurrentBag(await selectedStorageItems.ToStandardStorageItemsAsync()); + // Get the log file to use its properties. For some reason the drag and drop operation + // requires a BasicProperties object even though does not seem to be used. + // We supply it regardless for every VirtualStorageItem because it is checked for + var fakeFilePropsItem = await StorageFile.GetFileFromPathAsync(Path.Combine(ApplicationData.Current.LocalFolder.Path, "debug.log")); + var props = await fakeFilePropsItem.GetBasicPropertiesAsync(); + var itemList = e.Items.OfType().Where(x => !(x.IsHiddenItem && x.IsLinkItem && x.IsRecycleBinItem && x.IsShortcutItem)).Select(x => new VirtualStorageItem(x, props)); + e.Data.SetStorageItems(itemList, false); + //e.Data.RequestedOperation = DataPackageOperation.Move; } - if (selectedStorageItems.Count == 1) - { - if (selectedStorageItems.Single() is IStorageFile file) - { - var itemExtension = Path.GetExtension(file.Name); - if (ImagePreviewViewModel.Extensions.Any((ext) => ext.Equals(itemExtension, StringComparison.OrdinalIgnoreCase))) - { - var streamRef = Windows.Storage.Streams.RandomAccessStreamReference.CreateFromFile(file); - e.Data.SetBitmap(streamRef); - } - } - e.Data.SetStorageItems(selectedStorageItems, false); - } - else if (selectedStorageItems.Count > 1) - { - e.Data.SetStorageItems(selectedStorageItems, false); - } - else + catch (Exception) { e.Cancel = true; } diff --git a/src/Files.Uwp/Files.Uwp.csproj b/src/Files.Uwp/Files.Uwp.csproj index 3a201a8c643e..699fcd80f915 100644 --- a/src/Files.Uwp/Files.Uwp.csproj +++ b/src/Files.Uwp/Files.Uwp.csproj @@ -179,6 +179,7 @@ + diff --git a/src/Files.Uwp/Filesystem/StorageItems/VirtualStorageItem.cs b/src/Files.Uwp/Filesystem/StorageItems/VirtualStorageItem.cs new file mode 100644 index 000000000000..972017331270 --- /dev/null +++ b/src/Files.Uwp/Filesystem/StorageItems/VirtualStorageItem.cs @@ -0,0 +1,63 @@ +using System; +using System.Threading.Tasks; +using Windows.Foundation; +using Windows.Storage; +using Windows.Storage.FileProperties; + +namespace Files.Uwp.Filesystem.StorageItems +{ + /// + /// Implements IStorageItem, allowing us to get an instance of IStorageItem for a ListedItem + /// representing a standard filesystem item. As such, VirtualStorageItem does not support hidden, + /// shortcut, or link items. + /// + public class VirtualStorageItem : IStorageItem + { + private readonly ListedItem item; + private readonly BasicProperties props; + + public VirtualStorageItem(ListedItem item, BasicProperties props) + { + this.item = item; + this.props = props; + } + + public IAsyncAction RenameAsync(string desiredName) + { + throw new NotImplementedException(); + } + + public IAsyncAction RenameAsync(string desiredName, NameCollisionOption option) + { + throw new NotImplementedException(); + } + + public IAsyncAction DeleteAsync() + { + throw new NotImplementedException(); + } + + public IAsyncAction DeleteAsync(StorageDeleteOption option) + { + throw new NotImplementedException(); + } + + public IAsyncOperation GetBasicPropertiesAsync() + { + return Task.FromResult(props).AsAsyncOperation(); + } + + public bool IsOfType(StorageItemTypes type) + { + return item.PrimaryItemAttribute == type; + } + + public FileAttributes Attributes => item.PrimaryItemAttribute == StorageItemTypes.File ? FileAttributes.Normal : FileAttributes.Directory; + + public DateTimeOffset DateCreated => item.ItemDateCreatedReal; + + public string Name => item.ItemName; + + public string Path => item.ItemPath; + } +}