Skip to content

Commit cb2717d

Browse files
committed
Refactor folder state to be managed by a service
1 parent a78a13c commit cb2717d

File tree

19 files changed

+216
-111
lines changed

19 files changed

+216
-111
lines changed

app/Celbridge.Tests/ResourceRegistryTests.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
using Celbridge.Explorer.Services;
12
using Celbridge.Messaging.Services;
23
using Celbridge.Resources.Models;
34
using Celbridge.Resources.Services;
45
using Celbridge.UserInterface.Services;
6+
using Celbridge.Workspace;
57

68
namespace Celbridge.Tests;
79

@@ -109,23 +111,23 @@ public void ICanExpandAFolderResource()
109111
var resourceRegistry = new ResourceRegistry(messengerService, fileIconService);
110112
resourceRegistry.ProjectFolderPath = _resourceFolderPath;
111113

112-
resourceRegistry.SetFolderIsExpanded(FolderNameA, true);
114+
var workspaceWrapper = Substitute.For<IWorkspaceWrapper>();
115+
var folderStateService = new FolderStateService(workspaceWrapper);
116+
folderStateService.SetExpanded(FolderNameA, true);
113117

114118
var updateResult = resourceRegistry.UpdateResourceRegistry();
115119
updateResult.IsSuccess.Should().BeTrue();
116120

117121
//
118-
// Check that the folder resource is expanded.
122+
// Check that the folder resource expanded state is tracked correctly.
119123
//
120124

121-
var folderResource = (resourceRegistry.RootFolder.Children[0] as FolderResource)!;
122-
folderResource.IsExpanded.Should().BeTrue();
123-
124-
var expandedFoldersOut = resourceRegistry.ExpandedFolders;
125+
var expandedFoldersOut = folderStateService.ExpandedFolders;
125126
expandedFoldersOut.Count.Should().Be(1);
126127
expandedFoldersOut[0].Should().Be(FolderNameA);
127128

129+
var folderResource = (resourceRegistry.RootFolder.Children[0] as FolderResource)!;
128130
var folderPath = resourceRegistry.GetResourceKey(folderResource);
129-
resourceRegistry.IsFolderExpanded(folderPath).Should().BeTrue();
131+
folderStateService.IsExpanded(folderPath).Should().BeTrue();
130132
}
131133
}

app/Core/Celbridge.Foundation/Explorer/IExplorerService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ public interface IExplorerService
1717
/// </summary>
1818
IResourceTreeView ResourceTreeView { get; }
1919

20+
/// <summary>
21+
/// Returns the Folder State Service that manages folder expanded state in the resource tree.
22+
/// </summary>
23+
IFolderStateService FolderStateService { get; }
24+
2025
/// <summary>
2126
/// The currenlty selected resource in the Explorer Panel.
2227
/// </summary>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
namespace Celbridge.Explorer;
2+
3+
/// <summary>
4+
/// Manages the expanded folder state in the resource tree.
5+
/// </summary>
6+
public interface IFolderStateService
7+
{
8+
/// <summary>
9+
/// Returns the list of expanded folders in the resource tree.
10+
/// </summary>
11+
List<string> ExpandedFolders { get; }
12+
13+
/// <summary>
14+
/// Mark a folder resource as expanded or collapsed in the resource tree.
15+
/// </summary>
16+
void SetExpanded(ResourceKey folderResource, bool isExpanded);
17+
18+
/// <summary>
19+
/// Returns true if the folder with the specified resource key is expanded.
20+
/// </summary>
21+
bool IsExpanded(ResourceKey folderResource);
22+
23+
/// <summary>
24+
/// Removes expanded folder entries that no longer exist in the resource registry.
25+
/// </summary>
26+
void Cleanup();
27+
28+
/// <summary>
29+
/// Loads the folder state from workspace settings.
30+
/// </summary>
31+
Task LoadAsync();
32+
33+
/// <summary>
34+
/// Saves the folder state to workspace settings.
35+
/// </summary>
36+
Task SaveAsync();
37+
}

app/Core/Celbridge.Foundation/Resources/IResourceRegistry.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,6 @@ public interface IResourceRegistry
7777
/// </summary>
7878
Result UpdateResourceRegistry();
7979

80-
/// <summary>
81-
/// Returns the list of expanded folders in the resource tree.
82-
/// </summary>
83-
List<string> ExpandedFolders { get; }
84-
85-
/// <summary>
86-
/// Mark a folder resource as expanded or collapsed in the resource tree.
87-
/// This does not affect the IsExpanded property of the folder resource itself.
88-
/// </summary>
89-
void SetFolderIsExpanded(ResourceKey folderResource, bool isExpanded);
90-
91-
/// <summary>
92-
/// Returns true if the folder with the specified resource key is expanded.
93-
/// </summary>
94-
bool IsFolderExpanded(ResourceKey folderResource);
95-
9680
/// <summary>
9781
/// Returns all file resources in the registry with their resource keys and absolute paths.
9882
/// The results are sorted by path for stable ordering.

app/Workspace/Celbridge.Explorer/Commands/DuplicateResourceDialogCommand.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ private async Task<Result> ShowDuplicateResourceDialogAsync()
9191
bool isFolderResource = resource is IFolderResource;
9292

9393
// Maintain the expanded state of folders after rename
94+
var folderStateService = _workspaceWrapper.WorkspaceService.ExplorerService.FolderStateService;
9495
bool isExpandedFolder = isFolderResource &&
95-
resourceRegistry.IsFolderExpanded(Resource);
96+
folderStateService.IsExpanded(Resource);
9697

9798
// Execute a command to move the folder resource to perform the rename
9899
_commandService.Execute<ICopyResourceCommand>(command =>

app/Workspace/Celbridge.Explorer/Commands/ExpandFolderCommand.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ public class ExpandFolderCommand : CommandBase, IExpandFolderCommand
1111
public ResourceKey FolderResource { get; set; }
1212
public bool Expanded { get; set; } = true;
1313

14-
public ExpandFolderCommand(IWorkspaceWrapper workspaceWrapper)
14+
public ExpandFolderCommand(
15+
IWorkspaceWrapper workspaceWrapper)
1516
{
1617
_workspaceWrapper = workspaceWrapper;
1718
}
@@ -33,9 +34,11 @@ public override async Task<Result> ExecuteAsync()
3334
return Result.Fail($"Resource is not a folder. {FolderResource}");
3435
}
3536

36-
if (resourceRegistry.IsFolderExpanded(FolderResource) != Expanded)
37+
var folderStateService = _workspaceWrapper.WorkspaceService.ExplorerService.FolderStateService;
38+
39+
if (folderStateService.IsExpanded(FolderResource) != Expanded)
3740
{
38-
resourceRegistry.SetFolderIsExpanded(FolderResource, Expanded);
41+
folderStateService.SetExpanded(FolderResource, Expanded);
3942
}
4043

4144
if (folderResource.IsExpanded != Expanded)

app/Workspace/Celbridge.Explorer/Commands/RenameResourceDialogCommand.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ private async Task<Result> ShowRenameResourceDialogAsync()
8686
bool isFolderResource = resource is IFolderResource;
8787

8888
// Maintain the expanded state of folders after rename
89+
var folderStateService = _workspaceWrapper.WorkspaceService.ExplorerService.FolderStateService;
8990
bool isExpandedFolder = isFolderResource &&
90-
resourceRegistry.IsFolderExpanded(Resource);
91+
folderStateService.IsExpanded(Resource);
9192

9293
// Execute a command to move the resource to perform the rename
9394
_commandService.Execute<ICopyResourceCommand>(command =>

app/Workspace/Celbridge.Explorer/ServiceConfiguration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public static void ConfigureServices(IServiceCollection services)
1414
//
1515

1616
services.AddTransient<IExplorerService, ExplorerService>();
17+
services.AddTransient<IFolderStateService, FolderStateService>();
1718

1819
//
1920
// Register views

app/Workspace/Celbridge.Explorer/Services/ExplorerService.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Celbridge.Commands;
2+
using Celbridge.Logging;
23
using Celbridge.UserInterface;
34
using Celbridge.Workspace;
4-
using Celbridge.Logging;
55

66
namespace Celbridge.Explorer.Services;
77

@@ -17,25 +17,27 @@ public class ExplorerService : IExplorerService, IDisposable
1717
private readonly IWorkspaceWrapper _workspaceWrapper;
1818

1919
private IResourceRegistry? _resourceRegistry;
20-
private IResourceRegistry ResourceRegistry =>
20+
private IResourceRegistry ResourceRegistry =>
2121
_resourceRegistry ??= _workspaceWrapper.WorkspaceService.ResourceService.Registry;
2222

2323
private IExplorerPanel? _explorerPanel;
2424
public IExplorerPanel ExplorerPanel => _explorerPanel!;
2525

2626
private IResourceTreeView? _resourceTreeView;
27-
public IResourceTreeView ResourceTreeView
27+
public IResourceTreeView ResourceTreeView
2828
{
2929
get
3030
{
3131
return _resourceTreeView ?? throw new NullReferenceException("ResourceTreeView is null.");
3232
}
33-
set
34-
{
35-
_resourceTreeView = value;
33+
set
34+
{
35+
_resourceTreeView = value;
3636
}
3737
}
3838

39+
public IFolderStateService FolderStateService { get; }
40+
3941
public ResourceKey SelectedResource { get; private set; }
4042

4143
private bool _isWorkspaceLoaded;
@@ -58,6 +60,8 @@ public ExplorerService(
5860
_fileIconService = fileIconService;
5961
_workspaceWrapper = workspaceWrapper;
6062

63+
FolderStateService = serviceProvider.GetRequiredService<IFolderStateService>();
64+
6165
_messengerService.Register<WorkspaceWillPopulatePanelsMessage>(this, OnWorkspaceWillPopulatePanelsMessage);
6266
_messengerService.Register<WorkspaceLoadedMessage>(this, OnWorkspaceLoadedMessage);
6367
_messengerService.Register<SelectedResourceChangedMessage>(this, OnSelectedResourceChangedMessage);
@@ -82,12 +86,15 @@ private void OnSelectedResourceChangedMessage(object recipient, SelectedResource
8286
if (_isWorkspaceLoaded)
8387
{
8488
// Ignore change events that happen while loading the workspace
85-
_ = StoreSelectedResource();
89+
_ = StoreSelectedResource();
8690
}
8791
}
8892

8993
private async void OnResourceRegistryUpdatedMessage(object recipient, ResourceRegistryUpdatedMessage message)
9094
{
95+
// Clean up expanded folders that no longer exist in the registry
96+
FolderStateService.Cleanup();
97+
9198
var result = await PopulateTreeViewAsync();
9299
if (result.IsFailure)
93100
{
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using Celbridge.Workspace;
2+
3+
namespace Celbridge.Explorer.Services;
4+
5+
/// <summary>
6+
/// Manages folder UI state, such as expanded folder state in the resource tree.
7+
/// </summary>
8+
public class FolderStateService : IFolderStateService
9+
{
10+
private const string ExpandedFoldersKey = "ExpandedFolders";
11+
12+
private readonly IWorkspaceWrapper _workspaceWrapper;
13+
14+
public List<string> ExpandedFolders { get; } = [];
15+
16+
public FolderStateService(IWorkspaceWrapper workspaceWrapper)
17+
{
18+
_workspaceWrapper = workspaceWrapper;
19+
}
20+
21+
public void SetExpanded(ResourceKey folderResource, bool isExpanded)
22+
{
23+
if (isExpanded)
24+
{
25+
if (!folderResource.IsEmpty &&
26+
!ExpandedFolders.Contains(folderResource))
27+
{
28+
ExpandedFolders.Add(folderResource);
29+
ExpandedFolders.Sort();
30+
}
31+
}
32+
else
33+
{
34+
ExpandedFolders.Remove(folderResource);
35+
}
36+
}
37+
38+
public bool IsExpanded(ResourceKey folderResource)
39+
{
40+
return ExpandedFolders.Contains(folderResource);
41+
}
42+
43+
public void Cleanup()
44+
{
45+
var resourceRegistry = _workspaceWrapper.WorkspaceService.ResourceService.Registry;
46+
ExpandedFolders.Remove(string.Empty);
47+
ExpandedFolders.RemoveAll(expandedFolder => resourceRegistry.GetResource(expandedFolder).IsFailure);
48+
}
49+
50+
public async Task LoadAsync()
51+
{
52+
var workspaceSettings = _workspaceWrapper.WorkspaceService.WorkspaceSettings;
53+
var expandedFolders = await workspaceSettings.GetPropertyAsync<List<string>>(ExpandedFoldersKey);
54+
if (expandedFolders is not null &&
55+
expandedFolders.Count > 0)
56+
{
57+
foreach (var expandedFolder in expandedFolders)
58+
{
59+
SetExpanded(expandedFolder, true);
60+
}
61+
}
62+
}
63+
64+
public async Task SaveAsync()
65+
{
66+
var workspaceSettings = _workspaceWrapper.WorkspaceService.WorkspaceSettings;
67+
await workspaceSettings.SetPropertyAsync(ExpandedFoldersKey, ExpandedFolders);
68+
}
69+
}

0 commit comments

Comments
 (0)