Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f25b39e
Add robocopy support for move and copy operations
DarkEden-coding Sep 18, 2025
3b4bc2e
Add robocopy perminant remove support
DarkEden-coding Sep 18, 2025
e504f89
Add batch size setting
DarkEden-coding Sep 18, 2025
efc459c
fix formatting in ShellFilesystemOperations.cs
DarkEden-coding Sep 19, 2025
6c448a6
Fix folder and file transfer seperation issues, fix folder not moving…
DarkEden-coding Sep 19, 2025
7808c6c
Fix issue where empty folders are erroneously removed
DarkEden-coding Sep 19, 2025
248c65f
Make rename file conflicts go to shell functions
DarkEden-coding Sep 23, 2025
985a8c8
Make file operations with 20 or under files use shell only for less r…
DarkEden-coding Sep 23, 2025
5b86fd0
Make threads setting styling consistant with standards
DarkEden-coding Sep 24, 2025
93702e0
Add finer progress reporting
DarkEden-coding Sep 24, 2025
1ce4c41
reduce robocopy output overhead
DarkEden-coding Sep 24, 2025
37885e3
Fix robocopy bugs
DarkEden-coding Feb 28, 2026
427d1bb
Merge remote-tracking branch 'main/main' into Robocopy-Support
DarkEden-coding Jun 16, 2026
164f954
Fix merge issue
DarkEden-coding Jul 17, 2026
f2d6c9d
Preformance improvements
DarkEden-coding Jul 17, 2026
b566a99
Code Quality: Align Robocopy paths with upstream style and reduce dup…
DarkEden-coding Jul 19, 2026
c9f59cb
Code Quality: Format AdvancedPage.xaml with XamlStyler
DarkEden-coding Jul 19, 2026
15aa51c
Merge branch 'files-community:main' into Robocopy-Support
DarkEden-coding Jul 20, 2026
93beac1
Convert settings to use SettingsCard for thread count
DarkEden-coding Jul 26, 2026
62fc4d8
Show folder-in-use errors and others for Robocopy deletes
DarkEden-coding Aug 11, 2026
945041b
Cache the Robocopy settings service
DarkEden-coding Aug 17, 2026
7c81658
Use arrays for fixed operation snapshots
DarkEden-coding Aug 17, 2026
a84bedc
Expose Status Center paths as arrays
DarkEden-coding Aug 17, 2026
814be55
Fix nullable settings service cache
DarkEden-coding Aug 24, 2026
100b27f
Fix Robocopy nullable contracts
DarkEden-coding Aug 24, 2026
69bcc2e
Code Quality: Detect cloud drives progressively so a slow provider do…
yair100 Sep 7, 2026
85347d2
Code Quality: Fix sidebar dpi icons
yair100 Sep 7, 2026
78964ba
Update Package.appxmanifest
yair100 Sep 7, 2026
59bb0b2
Code Quality: Fixed stale Google Drive accounts
yair100 Sep 7, 2026
ecaba8e
Keep permanent deletion on the shell path
DarkEden-coding Sep 7, 2026
de15712
Resolve Robocopy settings lazily
DarkEden-coding Sep 7, 2026
ad280d8
Route eligible transfers through Robocopy safely
DarkEden-coding Sep 7, 2026
bdbe556
Quote Robocopy paths with the process argument list
DarkEden-coding Sep 7, 2026
aa31886
Remove the transfer deadline and log cancellation failures
DarkEden-coding Sep 7, 2026
9e7281c
Preserve Robocopy permission errors for elevation retries
DarkEden-coding Sep 7, 2026
4287630
Verify Robocopy batches with directory enumeration
DarkEden-coding Sep 7, 2026
1502049
Retry parent folder deletion after a locked child is released
DarkEden-coding Sep 7, 2026
563d09f
Merge upstream main and preserve folder deletion retry
DarkEden-coding Sep 7, 2026
4d505ea
Code Quality: Fixed stale Google Drive accounts
yair100 Sep 7, 2026
a5bbce7
Build: v4.2.30
yair100 Sep 7, 2026
722d81d
Merge branch 'main' into Robocopy-Support
DarkEden-coding Sep 7, 2026
59f701d
Merge main and retain Google Drive executable detection
DarkEden-coding Sep 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/Files.App/Data/Contracts/IDevToolsSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,15 @@ public interface IDevToolsSettingsService : IBaseSettingsService, INotifyPropert
/// Gets or sets the name of the chosen IDE.
/// </summary>
string IDEName { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to use Robocopy for file operations.
/// </summary>
bool UseRobocopyForFileOperations { get; set; }

/// <summary>
/// Gets or sets the number of threads to use with Robocopy.
/// </summary>
int RobocopyThreads { get; set; }
}
}
2 changes: 2 additions & 0 deletions src/Files.App/Data/Contracts/IUserSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ public interface IUserSettingsService : IBaseSettingsService
ILayoutSettingsService LayoutSettingsService { get; }

IAppSettingsService AppSettingsService { get; }

IDevToolsSettingsService DevToolsSettingsService { get; }
}
}
5 changes: 5 additions & 0 deletions src/Files.App/Data/Contracts/IWindowsJumpListService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ public interface IWindowsJumpListService

Task RemoveFolderAsync(string path);

/// <summary>
/// Removes multiple folders using a single Jump List update.
/// </summary>
Task RemoveFoldersAsync(IEnumerable<string> paths);

Task<IEnumerable<string>> GetFoldersAsync();
}
}
3 changes: 3 additions & 0 deletions src/Files.App/Data/Enums/CopyEngineResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public struct CopyEngineResult
public const int COPYENGINE_E_ACCESS_DENIED_SRC = -2144927711;
public const int COPYENGINE_E_ACCESS_DENIED_DEST = -2144927710;
public const int COPYENGINE_E_REQUIRES_ELEVATION = -2144927742;
public const int HRESULT_ERROR_ACCESS_DENIED = -2147024891;
// Path too long
public const int COPYENGINE_E_PATH_TOO_DEEP_SRC = -2144927715;
public const int COPYENGINE_E_PATH_TOO_DEEP_DEST = -2144927714;
Expand Down Expand Up @@ -63,8 +64,10 @@ public static FileSystemStatusCode Convert(int? hres)
{
CopyEngineResult.S_OK => FileSystemStatusCode.Success,
CopyEngineResult.COPYENGINE_E_ACCESS_DENIED_SRC => FileSystemStatusCode.Unauthorized,
CopyEngineResult.COPYENGINE_E_USER_CANCELLED => FileSystemStatusCode.Generic,
CopyEngineResult.COPYENGINE_E_ACCESS_DENIED_DEST => FileSystemStatusCode.Unauthorized,
CopyEngineResult.COPYENGINE_E_REQUIRES_ELEVATION => FileSystemStatusCode.Unauthorized,
CopyEngineResult.HRESULT_ERROR_ACCESS_DENIED => FileSystemStatusCode.Unauthorized,
CopyEngineResult.COPYENGINE_E_RECYCLE_PATH_TOO_LONG => FileSystemStatusCode.NameTooLong,
CopyEngineResult.COPYENGINE_E_NEWFILE_NAME_TOO_LONG => FileSystemStatusCode.NameTooLong,
CopyEngineResult.COPYENGINE_E_NEWFOLDER_NAME_TOO_LONG => FileSystemStatusCode.NameTooLong,
Expand Down
14 changes: 14 additions & 0 deletions src/Files.App/Services/Settings/DevToolsSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ public string IDEName
set => Set(value);
}

/// <inheritdoc/>
public bool UseRobocopyForFileOperations
{
get => Get(false);
set => Set(value);
}

/// <inheritdoc/>
public int RobocopyThreads
{
get => Get(8);
set => Set(value);
}

protected override void RaiseOnSettingChangedEvent(object sender, SettingChangedEventArgs e)
{
base.RaiseOnSettingChangedEvent(sender, e);
Expand Down
6 changes: 6 additions & 0 deletions src/Files.App/Services/Settings/UserSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ public IAppSettingsService AppSettingsService
get => GetSettingsService(ref _AppSettingsService);
}

private IDevToolsSettingsService? _DevToolsSettingsService;
public IDevToolsSettingsService DevToolsSettingsService
{
get => GetSettingsService(ref _DevToolsSettingsService);
}

public UserSettingsService()
{
var settingsSerializer = new DefaultSettingsSerializer();
Expand Down
38 changes: 28 additions & 10 deletions src/Files.App/Services/Windows/WindowsJumpListService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,37 @@ public async Task RefreshPinnedFoldersAsync()

public async Task RemoveFolderAsync(string path)
{
if (JumpList.IsSupported())
await RemoveFoldersAsync([path]);
}

/// <inheritdoc/>
public async Task RemoveFoldersAsync(IEnumerable<string> paths)
{
if (!JumpList.IsSupported())
return;

try
{
try
{
var instance = await JumpList.LoadCurrentAsync();
// Disable automatic jumplist. It doesn't work.
instance.SystemGroupKind = JumpListSystemGroupKind.None;
var pathsToRemove = paths.ToHashSet(StringComparer.OrdinalIgnoreCase);
if (pathsToRemove.Count == 0)
return;

var instance = await JumpList.LoadCurrentAsync();
// Disable automatic jumplist. It doesn't work.
instance.SystemGroupKind = JumpListSystemGroupKind.None;

var itemToRemove = instance.Items.Where(x => x.Arguments == path).Select(x => x).FirstOrDefault();
instance.Items.Remove(itemToRemove);
var itemsToRemove = instance.Items
.Where(item => pathsToRemove.Contains(item.Arguments))
.ToArray();
foreach (var item in itemsToRemove)
instance.Items.Remove(item);

if (itemsToRemove.Length > 0)
await instance.SaveAsync();
}
catch { }
}
catch (Exception ex)
{
App.Logger.LogWarning(ex, ex.Message);
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2186,6 +2186,15 @@
<data name="ShowFlattenOptions" xml:space="preserve">
<value>Show flatten options</value>
</data>
<data name="UseRobocopyForFileOperations" xml:space="preserve">
<value>Use Robocopy for file operations</value>
</data>
<data name="UseRobocopyForFileOperationsDescription" xml:space="preserve">
<value>Use multi-threaded Robocopy engine for large copy and move operations</value>
</data>
<data name="RobocopyThreads" xml:space="preserve">
<value>Threads</value>
</data>
<data name="SelectFilesAndFoldersOnHover" xml:space="preserve">
<value>Select files and folders when hovering over them</value>
</data>
Expand Down
10 changes: 6 additions & 4 deletions src/Files.App/Utils/StatusCenter/StatusCenterItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ public StatusCenterItemProgressModel Progress

public bool IsDiscovering { get; private set; } = true;

public IEnumerable<string>? Source { get; private set; }
public string[]? Source { get; private set; }

public IEnumerable<string>? Destination { get; private set; }
public string[]? Destination { get; private set; }

public string? HeaderStringResource { get; private set; }

Expand Down Expand Up @@ -204,8 +204,10 @@ public StatusCenterItem(
SpeedGraphValues = [];
CancelCommand = new RelayCommand(ExecuteCancelCommand);
Message = Strings.DiscoveringItems.GetLocalizedResource();
Source = source;
Destination = destination;
// Status text only uses the first path. Retaining every path keeps large completed
// operations and their source storage objects alive for the lifetime of the card.
Source = source?.Take(1).ToArray();
Destination = destination?.Take(1).ToArray();

if (Operation is FileOperationType.Git)
{
Expand Down
Loading