Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ internal sealed partial class CompressIntoSevenZipAction : BaseCompressArchiveAc
{
public override string Label
=> string.Format(Strings.CreateNamedArchive.GetLocalizedResource(), $"{StorageArchiveService.GenerateArchiveNameFromItems(context.SelectedItems)}.7z");

public override string ExtendedLabel
=> Strings.CompressIntoSevenZip.GetLocalizedResource();

public override string Description
=> Strings.CompressIntoSevenZipDescription.GetLocalizedFormatResource(context.SelectedItems.Count);

Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Data/Contracts/IGeneralSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ public interface IGeneralSettingsService : IBaseSettingsService, INotifyProperty
/// Gets or sets the thumbnail cache size limit in MB.
/// </summary>
double ThumbnailCacheSizeLimit { get; set; }

/// Gets or sets a value indicating whether smooth scrolling is enabled.
/// </summary>
bool EnableSmoothScrolling { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public static ObservableCollection<NavigationViewItemButtonStyleItem> Initialize
var detailsItemEnabled = !(isFolder && !listedItem.IsArchive) && !isLibrary && !listedItem.IsRecycleBinItem;
var customizationItemEnabled = !isLibrary && (isFolder && !listedItem.IsArchive || isShortcut);
var compatibilityItemEnabled = FileExtensionHelpers.IsExecutableFile(listedItem is IShortcutItem sht ? sht.TargetPath : fileExt, true);
var signaturesItemEnabled =
var signaturesItemEnabled =
!isFolder &&
!isLibrary &&
!listedItem.IsRecycleBinItem &&
Expand Down
1 change: 1 addition & 0 deletions src/Files.App/Dialogs/FilesystemOperationDialog.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
xmlns:vm="using:Files.App.ViewModels.Dialogs.FileSystemDialog"
x:Name="RootDialog"
Title="{x:Bind ViewModel.Title, Mode=OneWay}"
CloseButtonText="{x:Bind ViewModel.CloseButtonText, Mode=OneWay}"
Closing="RootDialog_Closing"
CornerRadius="{StaticResource OverlayCornerRadius}"
DefaultButton="Primary"
Expand Down
5 changes: 3 additions & 2 deletions src/Files.App/Helpers/Dialog/DynamicDialogFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,9 @@ public static DynamicDialog GetFor_FileInUseDialog(List<Win32Process> lockingPro
TitleText = Strings.FileInUseDialog_Title.GetLocalizedResource(),
SubtitleText = lockingProcess.IsEmpty() ? Strings.FileInUseDialog_Text.GetLocalizedResource() :
string.Format(Strings.FileInUseByDialog_Text.GetLocalizedResource(), string.Join(", ", lockingProcess.Select(x => $"{x.AppName ?? x.Name} (PID: {x.Pid})"))),
PrimaryButtonText = "OK",
DynamicButtons = DynamicDialogButtons.Primary
PrimaryButtonText = Strings.Retry.GetLocalizedResource(),
SecondaryButtonText = Strings.Skip.GetLocalizedResource(),
DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Secondary | DynamicDialogButtons.Cancel
});
return dialog;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Files.App.Services.PreviewPopupProviders
internal sealed partial class PreviewPopupService : ObservableObject, IPreviewPopupService
{
public async Task<IPreviewPopupProvider?> GetProviderAsync()
{
{
if (await QuickLookProvider.Instance.DetectAvailability())
return await Task.FromResult<IPreviewPopupProvider>(QuickLookProvider.Instance);
if (await SeerProProvider.Instance.DetectAvailability())
Expand Down
8 changes: 4 additions & 4 deletions src/Files.App/Services/Windows/WindowsDialogService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[]
{
using ComPtr<IFileOpenDialog> pDialog = default;
HRESULT hr = pDialog.CoCreateInstance(CLSID.CLSID_FileOpenDialog, null, CLSCTX.CLSCTX_INPROC_SERVER);

// Handle COM creation failure gracefully
if (hr.Failed)
{
Expand Down Expand Up @@ -60,7 +60,7 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[]
null,
IID.IID_IShellItem,
(void**)pDefaultFolderShellItem.GetAddressOf());

// Handle shell item creation failure gracefully
if (hr.Failed)
{
Expand Down Expand Up @@ -123,7 +123,7 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[]
{
using ComPtr<IFileSaveDialog> pDialog = default;
HRESULT hr = pDialog.CoCreateInstance(CLSID.CLSID_FileSaveDialog, null, CLSCTX.CLSCTX_INPROC_SERVER);

// Handle COM creation failure gracefully
if (hr.Failed)
{
Expand Down Expand Up @@ -159,7 +159,7 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[]
null,
IID.IID_IShellItem,
(void**)pDefaultFolderShellItem.GetAddressOf());

// Handle shell item creation failure gracefully
if (hr.Failed)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public IReadOnlyList<RecentItem> RecentFolders
public WindowsRecentItemsService()
{
var automaticDestinationsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Recent), "AutomaticDestinations");

// Only create the file system watcher if the AutomaticDestinations directory exists
if (Directory.Exists(automaticDestinationsPath))
{
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Utils/Global/QuickAccessManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public QuickAccessManager()
public void Initialize()
{
var automaticDestinationsPath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Microsoft", "Windows", "Recent", "AutomaticDestinations");

// Only initialize FileSystemWatcher if the directory exists
// This handles cases where AppData is redirected to network locations that don't contain Windows system directories
if (Directory.Exists(automaticDestinationsPath))
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Utils/Shell/LaunchHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private static async Task<bool> HandleApplicationLaunch(string application, stri
string key = (string)ent.Key;

// Skip USERNAME to avoid issues where files were executed as SYSTEM user (#12139)
if (string.Equals(key, "USERNAME", StringComparison.OrdinalIgnoreCase))
if (string.Equals(key, "USERNAME", StringComparison.OrdinalIgnoreCase))
continue;

process.StartInfo.EnvironmentVariables[key] = (string)ent.Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ public static bool SetLinkIcon(string filePath, string? iconFile, int iconIndex)
filePath = filePath.Replace("'", "''");
iconFile = iconFile.Replace("'", "''");

if(ext == ".url")
if (ext == ".url")
{
psScript = $@"
$path = '{filePath}'
Expand Down Expand Up @@ -901,10 +901,10 @@ private static bool TrySetUrlShortcutIcon(string filePath, string iconFile, int

int index = 0;
int insertedIndex = 0;
foreach(var line in lines)
foreach (var line in lines)
{
var isInternetShortcutHeader = line.Trim().Equals("[InternetShortcut]", StringComparison.OrdinalIgnoreCase);
if(isInternetShortcutHeader)
if (isInternetShortcutHeader)
{
insertedIndex = index + 1;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -857,10 +857,17 @@ private Task<DialogResult> GetFileInUseDialog(IEnumerable<string> source, IEnume
? Strings.FileInUseDialog_Text.GetLocalizedResource()
: string.Format(Strings.FileInUseByDialog_Text.GetLocalizedResource(), string.Join(", ", lockingProcess.Select(x => $"{x.AppName ?? x.Name} (PID: {x.Pid})")));

return GetFileListDialog(source, titleText, subtitleText, Strings.Retry.GetLocalizedResource(), Strings.Cancel.GetLocalizedResource());
var sourceCount = source.Count();

return GetFileListDialog(
source,
titleText,
subtitleText,
Strings.Retry.GetLocalizedResource(),
sourceCount > 1 ? Strings.Skip.GetLocalizedResource() : Strings.Cancel.GetLocalizedResource());
}

private async Task<DialogResult> GetFileListDialog(IEnumerable<string> source, string titleText, string descriptionText = null, string primaryButtonText = null, string secondaryButtonText = null)
private async Task<DialogResult> GetFileListDialog(IEnumerable<string> source, string titleText, string descriptionText = null, string primaryButtonText = null, string secondaryButtonText = null, string closeButtonText = null)
{
var incomingItems = new List<BaseFileSystemDialogItemViewModel>();
List<ShellFileItem> binItems = null;
Expand All @@ -886,7 +893,7 @@ private async Task<DialogResult> GetFileListDialog(IEnumerable<string> source, s
}

var dialogViewModel = FileSystemDialogViewModel.GetDialogViewModel(
incomingItems, titleText, descriptionText, primaryButtonText, secondaryButtonText);
incomingItems, titleText, descriptionText, primaryButtonText, secondaryButtonText, closeButtonText);

var dialogService = Ioc.Default.GetRequiredService<IDialogService>();

Expand Down
6 changes: 3 additions & 3 deletions src/Files.App/Utils/Storage/StorageItems/NativeStorageFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private unsafe string GetDisplayTypeFromShell()
{
SHFILEINFOW shfi = default;
var flags = SHGFI_FLAGS.SHGFI_TYPENAME | SHGFI_FLAGS.SHGFI_USEFILEATTRIBUTES;

fixed (char* pExtension = extension)
{
var result = PInvoke.SHGetFileInfo(
Expand All @@ -64,7 +64,7 @@ private unsafe string GetDisplayTypeFromShell()
&shfi,
(uint)sizeof(SHFILEINFOW),
flags);

if (result != 0 && shfi.szTypeName.Value[0] != '\0')
{
var typeName = shfi.szTypeName.ToString();
Expand All @@ -78,7 +78,7 @@ private unsafe string GetDisplayTypeFromShell()
var itemType = Strings.File.GetLocalizedResource();
if (Name.Contains('.', StringComparison.Ordinal))
itemType = extension?.Trim('.') + " " + itemType;

return itemType;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ public static FileSystemDialogViewModel GetDialogViewModel(FileSystemDialogMode
return viewModel;
}

public static FileSystemDialogViewModel GetDialogViewModel(List<BaseFileSystemDialogItemViewModel> nonConflictingItems, string titleText, string descriptionText, string primaryButtonText, string secondaryButtonText)
public static FileSystemDialogViewModel GetDialogViewModel(List<BaseFileSystemDialogItemViewModel> nonConflictingItems, string titleText, string descriptionText, string primaryButtonText, string secondaryButtonText, string closeButtonText = null)
{
var viewModel = new FileSystemDialogViewModel(
new()
Expand All @@ -230,6 +230,7 @@ public static FileSystemDialogViewModel GetDialogViewModel(List<BaseFileSystemDi
Description = descriptionText,
PrimaryButtonText = primaryButtonText,
SecondaryButtonText = secondaryButtonText,
CloseButtonText = closeButtonText,
DeletePermanently = false,
IsDeletePermanentlyEnabled = false
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public override async Task GetSpecialPropertiesAsync()
allNotCompressed &= !isCompressed;
anyCanCompress |= Win32Helper.CanCompressContent(x.ItemPath);
}

if (allFiles)
{
if (allReadOnly)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
PropertiesNavigationViewItemType.Security => typeof(SecurityPage),
PropertiesNavigationViewItemType.Customization => typeof(CustomizationPage),
PropertiesNavigationViewItemType.Compatibility => typeof(CompatibilityPage),
PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
_ => typeof(GeneralPage),
};

Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/ViewModels/Settings/GeneralViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ public bool ShowPinToStart
}
}
}

public bool ShowEditTagsMenu
{
get => UserSettingsService.GeneralSettingsService.ShowEditTagsMenu;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1030,12 +1030,12 @@ public async Task PopulateOmnibarSuggestionsForPathMode()
void AddNoResultsItem()
{
PathModeSuggestionItems.Clear();

// Use null-safe access to avoid NullReferenceException during app lifecycle transitions
var workingDirectory = string.IsNullOrEmpty(ContentPageContext.ShellPage?.ShellViewModel?.WorkingDirectory)
? Constants.UserEnvironmentPaths.HomePath
: ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory;

PathModeSuggestionItems.Add(new(
workingDirectory,
Strings.NavigationToolbarVisiblePathNoResults.GetLocalizedResource()));
Expand All @@ -1062,7 +1062,7 @@ public async Task PopulateOmnibarSuggestionsForCommandPaletteMode()
int processedCount = 0;

foreach (var command in commandsToProcess)
{
{
if (!command.IsExecutable)
{
processedCount++;
Expand Down
94 changes: 47 additions & 47 deletions src/Files.App/ViewModels/UserControls/ShelfViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,49 +48,49 @@ private async void Items_CollectionChanged(object? sender, NotifyCollectionChang
switch (e.Action)
{
case NotifyCollectionChangedAction.Add when e.NewItems is not null:
{
if (e.NewItems[0] is not ShelfItem shelfItem)
return;

var parentPath = SystemIO.Path.GetDirectoryName(shelfItem.Inner.Id) ?? string.Empty;
if (_watchers.TryGetValue(parentPath, out var reference))
{
// Only increase the reference count if the watcher already exists
reference.ReferenceCount += 1;
return;
if (e.NewItems[0] is not ShelfItem shelfItem)
return;

var parentPath = SystemIO.Path.GetDirectoryName(shelfItem.Inner.Id) ?? string.Empty;
if (_watchers.TryGetValue(parentPath, out var reference))
{
// Only increase the reference count if the watcher already exists
reference.ReferenceCount += 1;
return;
}

if (await shelfItem.Inner.GetParentAsync() is not IMutableFolder mutableFolder)
return;

// Register new watcher
var watcher = await mutableFolder.GetFolderWatcherAsync();
watcher.CollectionChanged += Watcher_CollectionChanged;

_watchers.Add(parentPath, new(watcher, 1));
break;
}

if (await shelfItem.Inner.GetParentAsync() is not IMutableFolder mutableFolder)
return;

// Register new watcher
var watcher = await mutableFolder.GetFolderWatcherAsync();
watcher.CollectionChanged += Watcher_CollectionChanged;

_watchers.Add(parentPath, new(watcher, 1));
break;
}

case NotifyCollectionChangedAction.Remove when e.OldItems is not null:
{
if (e.OldItems[0] is not ShelfItem shelfItem)
return;

var parentPath = SystemIO.Path.GetDirectoryName(shelfItem.Inner.Id) ?? string.Empty;
if (!_watchers.TryGetValue(parentPath, out var reference))
return;

// Decrease the reference count and remove the watcher if no references are present
reference.ReferenceCount -= 1;
if (reference.ReferenceCount < 1)
{
reference.FolderWatcher.CollectionChanged -= Watcher_CollectionChanged;
reference.FolderWatcher.Dispose();
_watchers.Remove(parentPath);
if (e.OldItems[0] is not ShelfItem shelfItem)
return;

var parentPath = SystemIO.Path.GetDirectoryName(shelfItem.Inner.Id) ?? string.Empty;
if (!_watchers.TryGetValue(parentPath, out var reference))
return;

// Decrease the reference count and remove the watcher if no references are present
reference.ReferenceCount -= 1;
if (reference.ReferenceCount < 1)
{
reference.FolderWatcher.CollectionChanged -= Watcher_CollectionChanged;
reference.FolderWatcher.Dispose();
_watchers.Remove(parentPath);
}

break;
}

break;
}
}
}

Expand All @@ -99,16 +99,16 @@ private async void Watcher_CollectionChanged(object? sender, NotifyCollectionCha
switch (e.Action)
{
case NotifyCollectionChangedAction.Remove when e.OldItems is not null:
{
// Remove the matching item notified from the watcher
var item = e.OldItems.Cast<IStorable>().ElementAt(0);
var itemToRemove = Items.FirstOrDefault(x => x.Inner.Id == item.Id);
if (itemToRemove is null)
return;

await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => Items.Remove(itemToRemove));
break;
}
{
// Remove the matching item notified from the watcher
var item = e.OldItems.Cast<IStorable>().ElementAt(0);
var itemToRemove = Items.FirstOrDefault(x => x.Inner.Id == item.Id);
if (itemToRemove is null)
return;

await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => Items.Remove(itemToRemove));
break;
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Views/Layouts/DetailsLayoutPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ private void FileList_Loaded(object sender, RoutedEventArgs e)
return;
void OnZoomScrolled(object? s, ScrollViewerViewChangedEventArgs ve)
{
scroller.ViewChanged -= OnZoomScrolled;
scroller.ViewChanged -= OnZoomScrolled;
scroller.ChangeView(0, Math.Max(0, scroller.VerticalOffset - OffsetCorrection), null, true);
}
scroller.ViewChanged += OnZoomScrolled;
Expand Down