Skip to content

Commit d3f06b0

Browse files
authored
Feature: Added option to prioritize files when sorting (#14253)
1 parent 5e9113a commit d3f06b0

File tree

20 files changed

+248
-54
lines changed

20 files changed

+248
-54
lines changed

src/Files.App/Actions/Display/ToggleSortDirectoriesAlongsideFilesAction.cs renamed to src/Files.App/Actions/Display/SortFilesAndFoldersTogetherAction.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@
33

44
namespace Files.App.Actions
55
{
6-
internal class ToggleSortDirectoriesAlongsideFilesAction : ObservableObject, IToggleAction
6+
internal class SortFilesAndFoldersTogetherAction : ObservableObject, IToggleAction
77
{
88
private readonly IDisplayPageContext context;
99

1010
public string Label
11-
=> "SettingsListAndSortDirectoriesAlongsideFiles".GetLocalizedResource();
11+
=> "SortFilesAndFoldersTogether".GetLocalizedResource();
1212

1313
public string Description
14-
=> "ToggleSortDirectoriesAlongsideFilesDescription".GetLocalizedResource();
14+
=> "SortFilesAndFoldersTogetherDescription".GetLocalizedResource();
1515

1616
public bool IsOn
1717
=> context.SortDirectoriesAlongsideFiles;
1818

19-
public ToggleSortDirectoriesAlongsideFilesAction()
19+
public SortFilesAndFoldersTogetherAction()
2020
{
2121
context = Ioc.Default.GetRequiredService<IDisplayPageContext>();
2222

@@ -25,7 +25,7 @@ public ToggleSortDirectoriesAlongsideFilesAction()
2525

2626
public Task ExecuteAsync()
2727
{
28-
context.SortDirectoriesAlongsideFiles = !IsOn;
28+
context.SortDirectoriesAlongsideFiles = true;
2929

3030
return Task.CompletedTask;
3131
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2023 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
namespace Files.App.Actions
5+
{
6+
internal class SortFilesFirstAction : ObservableObject, IToggleAction
7+
{
8+
private readonly IDisplayPageContext context;
9+
10+
public string Label
11+
=> "SortFilesFirst".GetLocalizedResource();
12+
13+
public string Description
14+
=> "SortFilesFirstDescription".GetLocalizedResource();
15+
16+
public bool IsOn
17+
=> context.SortFilesFirst && !context.SortDirectoriesAlongsideFiles;
18+
19+
public SortFilesFirstAction()
20+
{
21+
context = Ioc.Default.GetRequiredService<IDisplayPageContext>();
22+
23+
context.PropertyChanged += Context_PropertyChanged;
24+
}
25+
26+
public Task ExecuteAsync()
27+
{
28+
context.SortFilesFirst = true;
29+
context.SortDirectoriesAlongsideFiles = false;
30+
31+
return Task.CompletedTask;
32+
}
33+
34+
private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
35+
{
36+
if (e.PropertyName is nameof(IDisplayPageContext.SortFilesFirst) or nameof(IDisplayPageContext.SortDirectoriesAlongsideFiles))
37+
OnPropertyChanged(nameof(IsOn));
38+
}
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2023 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
namespace Files.App.Actions
5+
{
6+
internal class SortFoldersFirstAction : ObservableObject, IToggleAction
7+
{
8+
private readonly IDisplayPageContext context;
9+
10+
public string Label
11+
=> "SortFoldersFirst".GetLocalizedResource();
12+
13+
public string Description
14+
=> "SortFoldersFirstDescription".GetLocalizedResource();
15+
16+
public bool IsOn
17+
=> !context.SortFilesFirst && !context.SortDirectoriesAlongsideFiles;
18+
19+
public SortFoldersFirstAction()
20+
{
21+
context = Ioc.Default.GetRequiredService<IDisplayPageContext>();
22+
23+
context.PropertyChanged += Context_PropertyChanged;
24+
}
25+
26+
public Task ExecuteAsync()
27+
{
28+
context.SortFilesFirst = false;
29+
context.SortDirectoriesAlongsideFiles = false;
30+
31+
return Task.CompletedTask;
32+
}
33+
34+
private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
35+
{
36+
if (e.PropertyName is nameof(IDisplayPageContext.SortFilesFirst) or nameof(IDisplayPageContext.SortDirectoriesAlongsideFiles))
37+
OnPropertyChanged(nameof(IsOn));
38+
}
39+
}
40+
}

src/Files.App/Data/Commands/CommandCodes.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ public enum CommandCodes
133133
SortAscending,
134134
SortDescending,
135135
ToggleSortDirection,
136-
ToggleSortDirectoriesAlongsideFiles,
136+
SortFoldersFirst,
137+
SortFilesFirst,
138+
SortFilesAndFoldersTogether,
137139

138140
// Group by
139141
GroupByNone,

src/Files.App/Data/Commands/Manager/CommandManager.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ public IRichCommand this[HotKey hotKey]
131131
public IRichCommand SortAscending => commands[CommandCodes.SortAscending];
132132
public IRichCommand SortDescending => commands[CommandCodes.SortDescending];
133133
public IRichCommand ToggleSortDirection => commands[CommandCodes.ToggleSortDirection];
134-
public IRichCommand ToggleSortDirectoriesAlongsideFiles => commands[CommandCodes.ToggleSortDirectoriesAlongsideFiles];
134+
public IRichCommand SortFoldersFirst => commands[CommandCodes.SortFoldersFirst];
135+
public IRichCommand SortFilesFirst => commands[CommandCodes.SortFilesFirst];
136+
public IRichCommand SortFilesAndFoldersTogether => commands[CommandCodes.SortFilesAndFoldersTogether];
135137
public IRichCommand GroupByNone => commands[CommandCodes.GroupByNone];
136138
public IRichCommand GroupByName => commands[CommandCodes.GroupByName];
137139
public IRichCommand GroupByDateModified => commands[CommandCodes.GroupByDateModified];
@@ -296,7 +298,9 @@ public CommandManager()
296298
[CommandCodes.SortAscending] = new SortAscendingAction(),
297299
[CommandCodes.SortDescending] = new SortDescendingAction(),
298300
[CommandCodes.ToggleSortDirection] = new ToggleSortDirectionAction(),
299-
[CommandCodes.ToggleSortDirectoriesAlongsideFiles] = new ToggleSortDirectoriesAlongsideFilesAction(),
301+
[CommandCodes.SortFoldersFirst] = new SortFoldersFirstAction(),
302+
[CommandCodes.SortFilesFirst] = new SortFilesFirstAction(),
303+
[CommandCodes.SortFilesAndFoldersTogether] = new SortFilesAndFoldersTogetherAction(),
300304
[CommandCodes.GroupByNone] = new GroupByNoneAction(),
301305
[CommandCodes.GroupByName] = new GroupByNameAction(),
302306
[CommandCodes.GroupByDateModified] = new GroupByDateModifiedAction(),

src/Files.App/Data/Commands/Manager/ICommandManager.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ public interface ICommandManager : IEnumerable<IRichCommand>
118118
IRichCommand SortAscending { get; }
119119
IRichCommand SortDescending { get; }
120120
IRichCommand ToggleSortDirection { get; }
121-
IRichCommand ToggleSortDirectoriesAlongsideFiles { get; }
121+
IRichCommand SortFoldersFirst { get; }
122+
IRichCommand SortFilesFirst { get; }
123+
IRichCommand SortFilesAndFoldersTogether { get; }
122124

123125
IRichCommand GroupByNone { get; }
124126
IRichCommand GroupByName { get; }

src/Files.App/Data/Contexts/DisplayPage/DisplayPageContext.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,17 @@ public bool SortDirectoriesAlongsideFiles
115115
}
116116
}
117117

118+
private bool _SortFilesFirst = false;
119+
public bool SortFilesFirst
120+
{
121+
get => _SortFilesFirst;
122+
set
123+
{
124+
if (FolderSettings is LayoutPreferencesManager viewModel)
125+
viewModel.SortFilesFirst = value;
126+
}
127+
}
128+
118129
private LayoutPreferencesManager? FolderSettings => context.PaneOrColumn?.InstanceViewModel?.FolderSettings;
119130

120131
public DisplayPageContext()
@@ -181,6 +192,9 @@ private void FolderSettings_PropertyChanged(object? sender, PropertyChangedEvent
181192
case nameof(LayoutPreferencesManager.SortDirectoriesAlongsideFiles):
182193
SetProperty(ref _SortDirectoriesAlongsideFiles, viewModel.SortDirectoriesAlongsideFiles, nameof(SortDirectoriesAlongsideFiles));
183194
break;
195+
case nameof(LayoutPreferencesManager.SortFilesFirst):
196+
SetProperty(ref _SortFilesFirst, viewModel.SortFilesFirst, nameof(SortFilesFirst));
197+
break;
184198
}
185199
}
186200

@@ -214,6 +228,7 @@ private void Update()
214228
SetProperty(ref _GroupDirection, viewModel.DirectoryGroupDirection, nameof(GroupDirection));
215229
SetProperty(ref _GroupByDateUnit, viewModel.DirectoryGroupByDateUnit, nameof(GroupByDateUnit));
216230
SetProperty(ref _SortDirectoriesAlongsideFiles, viewModel.SortDirectoriesAlongsideFiles, nameof(SortDirectoriesAlongsideFiles));
231+
SetProperty(ref _SortFilesFirst, viewModel.SortFilesFirst, nameof(SortFilesFirst));
217232
}
218233
}
219234

src/Files.App/Data/Contexts/DisplayPage/IDisplayPageContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public interface IDisplayPageContext : INotifyPropertyChanging, INotifyPropertyC
1616
GroupByDateUnit GroupByDateUnit { get; set; }
1717

1818
bool SortDirectoriesAlongsideFiles { get; set; }
19+
bool SortFilesFirst { get; set; }
1920

2021
void DecreaseLayoutSize();
2122
void IncreaseLayoutSize();

src/Files.App/Data/Models/ItemViewModel.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,14 @@ public async Task UpdateSortDirectoriesAlongsideFilesAsync()
221221
await ApplyFilesAndFoldersChangesAsync();
222222
}
223223

224+
public async Task UpdateSortFilesFirstAsync()
225+
{
226+
OnPropertyChanged(nameof(AreFilesSortedFirst));
227+
228+
await OrderFilesAndFoldersAsync();
229+
await ApplyFilesAndFoldersChangesAsync();
230+
}
231+
224232
private void UpdateSortAndGroupOptions()
225233
{
226234
OnPropertyChanged(nameof(IsSortedByName));
@@ -236,6 +244,7 @@ private void UpdateSortAndGroupOptions()
236244
OnPropertyChanged(nameof(IsSortedAscending));
237245
OnPropertyChanged(nameof(IsSortedDescending));
238246
OnPropertyChanged(nameof(AreDirectoriesSortedAlongsideFiles));
247+
OnPropertyChanged(nameof(AreFilesSortedFirst));
239248
}
240249

241250
public bool IsSortedByName
@@ -406,6 +415,16 @@ public bool AreDirectoriesSortedAlongsideFiles
406415
}
407416
}
408417

418+
public bool AreFilesSortedFirst
419+
{
420+
get => folderSettings.SortFilesFirst;
421+
set
422+
{
423+
folderSettings.SortFilesFirst = value;
424+
OnPropertyChanged(nameof(AreFilesSortedFirst));
425+
}
426+
}
427+
409428
public bool HasNoWatcher { get; private set; }
410429

411430
public ItemViewModel(LayoutPreferencesManager folderSettingsViewModel)
@@ -547,6 +566,7 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
547566
case nameof(UserSettingsService.FoldersSettingsService.DefaultSortOption):
548567
case nameof(UserSettingsService.FoldersSettingsService.DefaultGroupOption):
549568
case nameof(UserSettingsService.FoldersSettingsService.DefaultSortDirectoriesAlongsideFiles):
569+
case nameof(UserSettingsService.FoldersSettingsService.DefaultSortFilesFirst):
550570
case nameof(UserSettingsService.FoldersSettingsService.SyncFolderPreferencesAcrossDirectories):
551571
case nameof(UserSettingsService.FoldersSettingsService.DefaultGroupByDateUnit):
552572
await dispatcherQueue.EnqueueOrInvokeAsync(() =>
@@ -602,7 +622,8 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
602622
{
603623
var key = FilesAndFolders.ItemGroupKeySelector?.Invoke(item);
604624
var group = FilesAndFolders.GroupedCollection?.FirstOrDefault(x => x.Model.Key == key);
605-
group?.OrderOne(list => SortingHelper.OrderFileList(list, folderSettings.DirectorySortOption, folderSettings.DirectorySortDirection, folderSettings.SortDirectoriesAlongsideFiles), item);
625+
group?.OrderOne(list => SortingHelper.OrderFileList(list, folderSettings.DirectorySortOption, folderSettings.DirectorySortDirection,
626+
folderSettings.SortDirectoriesAlongsideFiles, folderSettings.SortFilesFirst), item);
606627
}
607628

608629
UpdateEmptyTextType();
@@ -753,7 +774,8 @@ void OrderEntries()
753774
if (filesAndFolders.Count == 0)
754775
return;
755776

756-
filesAndFolders = new ConcurrentCollection<ListedItem>(SortingHelper.OrderFileList(filesAndFolders.ToList(), folderSettings.DirectorySortOption, folderSettings.DirectorySortDirection, folderSettings.SortDirectoriesAlongsideFiles));
777+
filesAndFolders = new ConcurrentCollection<ListedItem>(SortingHelper.OrderFileList(filesAndFolders.ToList(), folderSettings.DirectorySortOption, folderSettings.DirectorySortDirection,
778+
folderSettings.SortDirectoriesAlongsideFiles, folderSettings.SortFilesFirst));
757779
}
758780

759781
if (NativeWinApiHelper.IsHasThreadAccessPropertyPresent && dispatcherQueue.HasThreadAccess)
@@ -775,7 +797,8 @@ private void OrderGroups(CancellationToken token = default)
775797
if (token.IsCancellationRequested)
776798
return;
777799

778-
gp.Order(list => SortingHelper.OrderFileList(list, folderSettings.DirectorySortOption, folderSettings.DirectorySortDirection, folderSettings.SortDirectoriesAlongsideFiles));
800+
gp.Order(list => SortingHelper.OrderFileList(list, folderSettings.DirectorySortOption, folderSettings.DirectorySortDirection,
801+
folderSettings.SortDirectoriesAlongsideFiles, folderSettings.SortFilesFirst));
779802
}
780803

781804
if (FilesAndFolders.GroupedCollection is null || FilesAndFolders.GroupedCollection.IsSorted)

src/Files.App/Helpers/Layout/LayoutPreferencesItem.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class LayoutPreferencesItem
1717
public ColumnsViewModel ColumnsViewModel;
1818

1919
public bool SortDirectoriesAlongsideFiles;
20+
public bool SortFilesFirst;
2021
public bool IsAdaptiveLayoutOverridden;
2122
public int GridViewSize;
2223

@@ -43,6 +44,7 @@ public LayoutPreferencesItem()
4344
DirectoryGroupDirection = UserSettingsService.FoldersSettingsService.DefaultDirectoryGroupDirection;
4445
DirectoryGroupByDateUnit = UserSettingsService.FoldersSettingsService.DefaultGroupByDateUnit;
4546
SortDirectoriesAlongsideFiles = UserSettingsService.FoldersSettingsService.DefaultSortDirectoriesAlongsideFiles;
47+
SortFilesFirst = UserSettingsService.FoldersSettingsService.DefaultSortFilesFirst;
4648
IsAdaptiveLayoutOverridden = defaultLayout is not FolderLayoutModes.Adaptive;
4749

4850
ColumnsViewModel = new ColumnsViewModel();
@@ -99,6 +101,7 @@ public override bool Equals(object? obj)
99101
item.DirectoryGroupDirection == DirectoryGroupDirection &&
100102
item.DirectoryGroupByDateUnit == DirectoryGroupByDateUnit &&
101103
item.SortDirectoriesAlongsideFiles == SortDirectoriesAlongsideFiles &&
104+
item.SortFilesFirst == SortFilesFirst &&
102105
item.IsAdaptiveLayoutOverridden == IsAdaptiveLayoutOverridden &&
103106
item.ColumnsViewModel.Equals(ColumnsViewModel));
104107
}
@@ -117,6 +120,7 @@ public override int GetHashCode()
117120
hash.Add(DirectoryGroupDirection);
118121
hash.Add(DirectoryGroupByDateUnit);
119122
hash.Add(SortDirectoriesAlongsideFiles);
123+
hash.Add(SortFilesFirst);
120124
hash.Add(IsAdaptiveLayoutOverridden);
121125
hash.Add(ColumnsViewModel);
122126

src/Files.App/Helpers/Layout/LayoutPreferencesManager.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,19 @@ public bool SortDirectoriesAlongsideFiles
221221
}
222222
}
223223

224+
public bool SortFilesFirst
225+
{
226+
get => LayoutPreferencesItem.SortFilesFirst;
227+
set
228+
{
229+
if (SetProperty(ref LayoutPreferencesItem.SortFilesFirst, value, nameof(SortFilesFirst)))
230+
{
231+
LayoutPreferencesUpdateRequired?.Invoke(this, new LayoutPreferenceEventArgs(LayoutPreferencesItem));
232+
SortFilesFirstPreferenceUpdated?.Invoke(this, SortFilesFirst);
233+
}
234+
}
235+
}
236+
224237
public ColumnsViewModel ColumnsViewModel
225238
{
226239
get => LayoutPreferencesItem.ColumnsViewModel;
@@ -256,6 +269,7 @@ private set
256269
OnPropertyChanged(nameof(DirectoryGroupDirection));
257270
OnPropertyChanged(nameof(DirectoryGroupByDateUnit));
258271
OnPropertyChanged(nameof(SortDirectoriesAlongsideFiles));
272+
OnPropertyChanged(nameof(SortFilesFirst));
259273
OnPropertyChanged(nameof(ColumnsViewModel));
260274
}
261275
}
@@ -270,6 +284,7 @@ private set
270284
public event EventHandler<SortDirection>? GroupDirectionPreferenceUpdated;
271285
public event EventHandler<GroupByDateUnit>? GroupByDateUnitPreferenceUpdated;
272286
public event EventHandler<bool>? SortDirectoriesAlongsideFilesPreferenceUpdated;
287+
public event EventHandler<bool>? SortFilesFirstPreferenceUpdated;
273288
public event EventHandler<LayoutModeEventArgs>? LayoutModeChangeRequested;
274289
public event EventHandler? GridViewSizeChangeRequested;
275290

@@ -429,6 +444,9 @@ public void OnDefaultPreferencesChanged(string path, string settingsName)
429444
case nameof(UserSettingsService.FoldersSettingsService.DefaultSortDirectoriesAlongsideFiles):
430445
SortDirectoriesAlongsideFiles = preferencesItem.SortDirectoriesAlongsideFiles;
431446
break;
447+
case nameof(UserSettingsService.FoldersSettingsService.DefaultSortFilesFirst):
448+
SortFilesFirst = preferencesItem.SortFilesFirst;
449+
break;
432450
case nameof(UserSettingsService.FoldersSettingsService.SyncFolderPreferencesAcrossDirectories):
433451
LayoutPreferencesItem = preferencesItem;
434452
// TODO: Update layout
@@ -512,6 +530,7 @@ public static void SetLayoutPreferencesForPath(string path, LayoutPreferencesIte
512530
UserSettingsService.FoldersSettingsService.DefaultDirectoryGroupDirection = preferencesItem.DirectoryGroupDirection;
513531
UserSettingsService.FoldersSettingsService.DefaultGroupByDateUnit = preferencesItem.DirectoryGroupByDateUnit;
514532
UserSettingsService.FoldersSettingsService.DefaultSortDirectoriesAlongsideFiles = preferencesItem.SortDirectoriesAlongsideFiles;
533+
UserSettingsService.FoldersSettingsService.DefaultSortFilesFirst = preferencesItem.SortFilesFirst;
515534

516535
UserSettingsService.FoldersSettingsService.NameColumnWidth = preferencesItem.ColumnsViewModel.NameColumn.UserLengthPixels;
517536

src/Files.App/Helpers/MenuFlyout/ContextFlyoutItemHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public static List<ContextMenuFlyoutItemViewModel> GetBaseItemMenuItems(
211211
},
212212
new ContextMenuFlyoutItemViewModel()
213213
{
214-
Text = "NavToolbarGroupByRadioButtons/Text".GetLocalizedResource(),
214+
Text = "GroupBy".GetLocalizedResource(),
215215
Glyph = "\uF168",
216216
ShowItem = !itemsSelected,
217217
ShowInRecycleBin = true,

src/Files.App/Services/Settings/FoldersSettingsService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ public bool DefaultSortDirectoriesAlongsideFiles
339339
set => Set(value);
340340
}
341341

342+
public bool DefaultSortFilesFirst
343+
{
344+
get => Get(false);
345+
set => Set(value);
346+
}
347+
342348
public bool ShowFileExtensions
343349
{
344350
get => Get(true);

0 commit comments

Comments
 (0)