Skip to content

Commit 11512fd

Browse files
Feature: Added support for reordering tags (#11306)
1 parent e1a80e1 commit 11512fd

File tree

5 files changed

+51
-14
lines changed

5 files changed

+51
-14
lines changed

src/Files.App/ServicesImplementation/Settings/FileTagsSettingsService.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ public FileTagsSettingsService()
3939
public IList<TagViewModel> FileTagList
4040
{
4141
get => Get<List<TagViewModel>>(DefaultFileTags);
42-
set => Set(value);
42+
set
43+
{
44+
Set(value);
45+
OnTagsUpdated.Invoke(this, EventArgs.Empty);
46+
}
4347
}
4448

4549
public TagViewModel GetTagById(string uid)
@@ -86,7 +90,6 @@ public void CreateNewTag(string newTagName, string color)
8690
var oldTags = FileTagList.ToList();
8791
oldTags.Add(newTag);
8892
FileTagList = oldTags;
89-
OnTagsUpdated.Invoke(this, EventArgs.Empty);
9093
}
9194

9295
public void EditTag(string uid, string name, string color)
@@ -102,7 +105,6 @@ public void EditTag(string uid, string name, string color)
102105
oldTags.RemoveAt(index);
103106
oldTags.Insert(index, tag);
104107
FileTagList = oldTags;
105-
OnTagsUpdated.Invoke(this, EventArgs.Empty);
106108
}
107109

108110
public void DeleteTag(string uid)
@@ -115,8 +117,6 @@ public void DeleteTag(string uid)
115117
oldTags.RemoveAt(index);
116118
FileTagList = oldTags;
117119
UntagAllFiles(uid);
118-
119-
OnTagsUpdated.Invoke(this, EventArgs.Empty);
120120
}
121121

122122
public override bool ImportSettings(object import)

src/Files.App/ViewModels/SettingsViewModels/AdvancedViewModel.cs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
using Files.Backend.Services.Settings;
1010
using Files.Backend.ViewModels.FileTags;
1111
using Files.Shared.Extensions;
12-
using Microsoft.UI.Xaml.Controls;
1312
using Microsoft.Win32;
1413
using SevenZip;
1514
using System;
1615
using System.Collections.ObjectModel;
1716
using System.Diagnostics;
1817
using System.IO;
18+
using System.Linq;
1919
using System.Text;
2020
using System.Threading.Tasks;
2121
using System.Windows.Input;
@@ -34,6 +34,10 @@ public class AdvancedViewModel : ObservableObject
3434

3535
private readonly IFileTagsSettingsService fileTagsSettingsService = Ioc.Default.GetRequiredService<IFileTagsSettingsService>();
3636

37+
private bool isBulkOperation = true;
38+
39+
private bool isDragStarting = true;
40+
3741
public ICommand SetAsDefaultExplorerCommand { get; }
3842
public ICommand SetAsOpenFileDialogCommand { get; }
3943
public ICommand ExportSettingsCommand { get; }
@@ -64,7 +68,28 @@ public AdvancedViewModel()
6468
CancelNewTagCommand = new RelayCommand(DoCancelNewTag);
6569

6670
Tags = new ObservableCollection<ListedTagViewModel>();
71+
Tags.CollectionChanged += Tags_CollectionChanged;
6772
fileTagsSettingsService.FileTagList?.ForEach(tag => Tags.Add(new ListedTagViewModel(tag)));
73+
74+
isBulkOperation = false;
75+
}
76+
77+
private void Tags_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
78+
{
79+
if (isBulkOperation)
80+
return;
81+
82+
// Reaordering ListView has no events, but its collection is updated twice,
83+
// first to remove the selected item, and second to add the item at the selected position.
84+
if (isDragStarting)
85+
{
86+
isDragStarting = false;
87+
return;
88+
}
89+
90+
isDragStarting = true;
91+
92+
fileTagsSettingsService.FileTagList = Tags.Select(tagVM => tagVM.Tag).ToList();
6893
}
6994

7095
private async Task OpenSettingsJson()
@@ -329,8 +354,11 @@ private void DoSaveNewTag()
329354
IsCreatingNewTag = false;
330355

331356
fileTagsSettingsService.CreateNewTag(NewTag.Name, NewTag.Color);
357+
358+
isBulkOperation = true;
332359
Tags.Clear();
333360
fileTagsSettingsService.FileTagList?.ForEach(tag => Tags.Add(new ListedTagViewModel(tag)));
361+
isBulkOperation = false;
334362
}
335363

336364
private void DoCancelNewTag()
@@ -341,13 +369,19 @@ private void DoCancelNewTag()
341369
public void EditExistingTag(ListedTagViewModel item, string newName, string color)
342370
{
343371
fileTagsSettingsService.EditTag(item.Tag.Uid, newName, color);
372+
373+
isBulkOperation = true;
344374
Tags.Clear();
345375
fileTagsSettingsService.FileTagList?.ForEach(tag => Tags.Add(new ListedTagViewModel(tag)));
376+
isBulkOperation = false;
346377
}
347378

348379
public void DeleteExistingTag(ListedTagViewModel item)
349380
{
381+
isBulkOperation = true;
350382
Tags.Remove(item);
383+
isBulkOperation = false;
384+
351385
fileTagsSettingsService.DeleteTag(item.Tag.Uid);
352386
}
353387
}

src/Files.App/Views/SettingsPages/Advanced.xaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,11 @@
228228
MaxHeight="300"
229229
Padding="12"
230230
HorizontalAlignment="Stretch"
231+
AllowDrop="True"
232+
CanReorderItems="True"
231233
IsItemClickEnabled="True"
232234
ItemsSource="{x:Bind ViewModel.Tags, Mode=TwoWay}"
235+
ReorderMode="Enabled"
233236
SelectionMode="None">
234237
<ListView.ItemTemplate>
235238
<DataTemplate xmlns:vm="using:Files.Backend.ViewModels.FileTags" x:DataType="vm:ListedTagViewModel">

src/Files.App/Views/SettingsPages/Advanced.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ private bool IsNameValid(string name)
103103
string.IsNullOrWhiteSpace(name) ||
104104
name.StartsWith('.') ||
105105
name.EndsWith('.') ||
106-
ViewModel.Tags.Any(tag => name == tag.Tag.Name)
106+
(name != editingTag.Tag.Name && ViewModel.Tags.Any(tag => name == tag.Tag.Name))
107107
);
108108
}
109109

tests/Files.InteractionTests/Tests/FolderTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private void CreateFolderTest()
6262
action.SendKeys(Keys.Enter).Perform();
6363

6464
// Wait for folder to be created
65-
Thread.Sleep(1000);
65+
Thread.Sleep(2000);
6666

6767
// Check for accessibility issues in the file area
6868
AxeHelper.AssertNoAccessibilityErrors();
@@ -85,7 +85,7 @@ private void RenameFolderTest()
8585
action.SendKeys(Keys.Enter).Perform();
8686

8787
// Wait for the folder to be renamed
88-
Thread.Sleep(1000);
88+
Thread.Sleep(2000);
8989
}
9090

9191
/// <summary>
@@ -97,13 +97,13 @@ private void CopyPasteFolderTest()
9797
TestHelper.InvokeButtonById("InnerNavigationToolbarCopyButton");
9898

9999
// Wait for folder to be copied
100-
Thread.Sleep(1000);
100+
Thread.Sleep(2000);
101101

102102
// Click the "paste" button on the toolbar
103103
TestHelper.InvokeButtonById("InnerNavigationToolbarPasteButton");
104104

105105
// Wait for folder to be pasted
106-
Thread.Sleep(1000);
106+
Thread.Sleep(2000);
107107
}
108108

109109
/// <summary>
@@ -116,7 +116,7 @@ private void DeleteFolderTest()
116116
TestHelper.InvokeButtonById("Delete");
117117

118118
// Wait for prompt to show
119-
Thread.Sleep(1000);
119+
Thread.Sleep(2000);
120120

121121
// Check for accessibility issues in the confirm delete prompt
122122
AxeHelper.AssertNoAccessibilityErrors();
@@ -131,7 +131,7 @@ private void DeleteFolderTest()
131131
TestHelper.InvokeButtonById("Delete");
132132

133133
// Wait for prompt to show
134-
Thread.Sleep(1000);
134+
Thread.Sleep(2000);
135135

136136
// Check for accessibility issues in the confirm delete prompt
137137
AxeHelper.AssertNoAccessibilityErrors();
@@ -141,7 +141,7 @@ private void DeleteFolderTest()
141141
action.SendKeys(Keys.Enter).Perform();
142142

143143
// Wait for items to finish being deleted
144-
Thread.Sleep(1000);
144+
Thread.Sleep(2000);
145145
}
146146
}
147147
}

0 commit comments

Comments
 (0)