fix(workspace): refresh expanded folder contents
This commit is contained in:
parent
3b9b165464
commit
bfedd11186
2 changed files with 38 additions and 14 deletions
|
|
@ -62,6 +62,7 @@ private final class SaplingAppModel: ObservableObject {
|
||||||
@Published var workspace: Workspace?
|
@Published var workspace: Workspace?
|
||||||
@Published var workspaceChildren: [URL: [WorkspaceItem]] = [:]
|
@Published var workspaceChildren: [URL: [WorkspaceItem]] = [:]
|
||||||
@Published var loadingTreeItemURLs: Set<URL> = []
|
@Published var loadingTreeItemURLs: Set<URL> = []
|
||||||
|
@Published var workspaceTreeRevision = 0
|
||||||
@Published var workspaceSelection: WorkspaceTreeSelection?
|
@Published var workspaceSelection: WorkspaceTreeSelection?
|
||||||
@Published var selectedProject: Project?
|
@Published var selectedProject: Project?
|
||||||
@Published var selectedDocument: MarkdownDocument?
|
@Published var selectedDocument: MarkdownDocument?
|
||||||
|
|
@ -133,6 +134,7 @@ private final class SaplingAppModel: ObservableObject {
|
||||||
self.workspace = workspace
|
self.workspace = workspace
|
||||||
workspaceChildren = [:]
|
workspaceChildren = [:]
|
||||||
loadingTreeItemURLs = []
|
loadingTreeItemURLs = []
|
||||||
|
invalidateWorkspaceTree()
|
||||||
workspaceSelection = nil
|
workspaceSelection = nil
|
||||||
selectedProject = nil
|
selectedProject = nil
|
||||||
selectedDocument = nil
|
selectedDocument = nil
|
||||||
|
|
@ -167,6 +169,7 @@ private final class SaplingAppModel: ObservableObject {
|
||||||
var loadingURLs = loadingTreeItemURLs
|
var loadingURLs = loadingTreeItemURLs
|
||||||
loadingURLs.insert(url)
|
loadingURLs.insert(url)
|
||||||
loadingTreeItemURLs = loadingURLs
|
loadingTreeItemURLs = loadingURLs
|
||||||
|
invalidateWorkspaceTree()
|
||||||
let workspaceManager = self.workspaceManager
|
let workspaceManager = self.workspaceManager
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
|
|
@ -176,6 +179,7 @@ private final class SaplingAppModel: ObservableObject {
|
||||||
var loadedChildren = workspaceChildren
|
var loadedChildren = workspaceChildren
|
||||||
loadedChildren[url] = children
|
loadedChildren[url] = children
|
||||||
workspaceChildren = loadedChildren
|
workspaceChildren = loadedChildren
|
||||||
|
invalidateWorkspaceTree()
|
||||||
} catch {
|
} catch {
|
||||||
editorErrorMessage = "Unable to load \(item.displayName): \(error.localizedDescription)"
|
editorErrorMessage = "Unable to load \(item.displayName): \(error.localizedDescription)"
|
||||||
logger.error("Failed to load workspace tree item: \(error)", category: .workspace)
|
logger.error("Failed to load workspace tree item: \(error)", category: .workspace)
|
||||||
|
|
@ -183,6 +187,7 @@ private final class SaplingAppModel: ObservableObject {
|
||||||
var loadingURLs = loadingTreeItemURLs
|
var loadingURLs = loadingTreeItemURLs
|
||||||
loadingURLs.remove(url)
|
loadingURLs.remove(url)
|
||||||
loadingTreeItemURLs = loadingURLs
|
loadingTreeItemURLs = loadingURLs
|
||||||
|
invalidateWorkspaceTree()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,6 +258,10 @@ private final class SaplingAppModel: ObservableObject {
|
||||||
configuration.recentWorkspaceURLs = Array(configuration.recentWorkspaceURLs.prefix(10))
|
configuration.recentWorkspaceURLs = Array(configuration.recentWorkspaceURLs.prefix(10))
|
||||||
save(configuration: configuration)
|
save(configuration: configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func invalidateWorkspaceTree() {
|
||||||
|
workspaceTreeRevision &+= 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct MainWindow: View {
|
private struct MainWindow: View {
|
||||||
|
|
@ -265,6 +274,7 @@ private struct MainWindow: View {
|
||||||
WorkspaceTreeView(
|
WorkspaceTreeView(
|
||||||
workspace: model.workspace,
|
workspace: model.workspace,
|
||||||
isLoadingWorkspace: model.isLoadingWorkspace,
|
isLoadingWorkspace: model.isLoadingWorkspace,
|
||||||
|
treeContentRevision: model.workspaceTreeRevision,
|
||||||
selection: $model.workspaceSelection,
|
selection: $model.workspaceSelection,
|
||||||
childrenFor: model.children(for:),
|
childrenFor: model.children(for:),
|
||||||
isLoadingChildren: model.isLoadingChildren(for:),
|
isLoadingChildren: model.isLoadingChildren(for:),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ public enum WorkspaceTreeSelection: Hashable, Sendable {
|
||||||
public struct WorkspaceTreeView: View {
|
public struct WorkspaceTreeView: View {
|
||||||
private let workspace: Workspace?
|
private let workspace: Workspace?
|
||||||
private let isLoadingWorkspace: Bool
|
private let isLoadingWorkspace: Bool
|
||||||
|
private let treeContentRevision: Int
|
||||||
@Binding private var selection: WorkspaceTreeSelection?
|
@Binding private var selection: WorkspaceTreeSelection?
|
||||||
private let childrenFor: (WorkspaceItem) -> [WorkspaceItem]
|
private let childrenFor: (WorkspaceItem) -> [WorkspaceItem]
|
||||||
private let isLoadingChildren: (WorkspaceItem) -> Bool
|
private let isLoadingChildren: (WorkspaceItem) -> Bool
|
||||||
|
|
@ -22,6 +23,7 @@ public struct WorkspaceTreeView: View {
|
||||||
public init(
|
public init(
|
||||||
workspace: Workspace?,
|
workspace: Workspace?,
|
||||||
isLoadingWorkspace: Bool = false,
|
isLoadingWorkspace: Bool = false,
|
||||||
|
treeContentRevision: Int = 0,
|
||||||
selection: Binding<WorkspaceTreeSelection?>,
|
selection: Binding<WorkspaceTreeSelection?>,
|
||||||
childrenFor: @escaping (WorkspaceItem) -> [WorkspaceItem] = { $0.children ?? [] },
|
childrenFor: @escaping (WorkspaceItem) -> [WorkspaceItem] = { $0.children ?? [] },
|
||||||
isLoadingChildren: @escaping (WorkspaceItem) -> Bool = { _ in false },
|
isLoadingChildren: @escaping (WorkspaceItem) -> Bool = { _ in false },
|
||||||
|
|
@ -32,6 +34,7 @@ public struct WorkspaceTreeView: View {
|
||||||
) {
|
) {
|
||||||
self.workspace = workspace
|
self.workspace = workspace
|
||||||
self.isLoadingWorkspace = isLoadingWorkspace
|
self.isLoadingWorkspace = isLoadingWorkspace
|
||||||
|
self.treeContentRevision = treeContentRevision
|
||||||
self._selection = selection
|
self._selection = selection
|
||||||
self.childrenFor = childrenFor
|
self.childrenFor = childrenFor
|
||||||
self.isLoadingChildren = isLoadingChildren
|
self.isLoadingChildren = isLoadingChildren
|
||||||
|
|
@ -53,6 +56,7 @@ public struct WorkspaceTreeView: View {
|
||||||
ForEach(workspace.items, id: \.stableTreeID) { item in
|
ForEach(workspace.items, id: \.stableTreeID) { item in
|
||||||
WorkspaceItemRow(
|
WorkspaceItemRow(
|
||||||
item: item,
|
item: item,
|
||||||
|
treeContentRevision: treeContentRevision,
|
||||||
selection: $selection,
|
selection: $selection,
|
||||||
childrenFor: childrenFor,
|
childrenFor: childrenFor,
|
||||||
isLoadingChildren: isLoadingChildren,
|
isLoadingChildren: isLoadingChildren,
|
||||||
|
|
@ -87,6 +91,7 @@ public struct WorkspaceTreeView: View {
|
||||||
|
|
||||||
private struct WorkspaceItemRow: View {
|
private struct WorkspaceItemRow: View {
|
||||||
let item: WorkspaceItem
|
let item: WorkspaceItem
|
||||||
|
let treeContentRevision: Int
|
||||||
@Binding var selection: WorkspaceTreeSelection?
|
@Binding var selection: WorkspaceTreeSelection?
|
||||||
let childrenFor: (WorkspaceItem) -> [WorkspaceItem]
|
let childrenFor: (WorkspaceItem) -> [WorkspaceItem]
|
||||||
let isLoadingChildren: (WorkspaceItem) -> Bool
|
let isLoadingChildren: (WorkspaceItem) -> Bool
|
||||||
|
|
@ -159,6 +164,7 @@ private struct WorkspaceItemRow: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var children: some View {
|
private var children: some View {
|
||||||
|
Group {
|
||||||
if isLoadingChildren(item) {
|
if isLoadingChildren(item) {
|
||||||
Label("Loading...", systemImage: "progress.indicator")
|
Label("Loading...", systemImage: "progress.indicator")
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
|
|
@ -166,6 +172,7 @@ private struct WorkspaceItemRow: View {
|
||||||
ForEach(childrenFor(item), id: \.stableTreeID) { child in
|
ForEach(childrenFor(item), id: \.stableTreeID) { child in
|
||||||
WorkspaceItemRow(
|
WorkspaceItemRow(
|
||||||
item: child,
|
item: child,
|
||||||
|
treeContentRevision: treeContentRevision,
|
||||||
selection: $selection,
|
selection: $selection,
|
||||||
childrenFor: childrenFor,
|
childrenFor: childrenFor,
|
||||||
isLoadingChildren: isLoadingChildren,
|
isLoadingChildren: isLoadingChildren,
|
||||||
|
|
@ -176,6 +183,8 @@ private struct WorkspaceItemRow: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.id(WorkspaceChildrenContentID(itemURL: item.stableTreeID, revision: treeContentRevision))
|
||||||
|
}
|
||||||
|
|
||||||
private func iconName(for kind: WorkspaceFileKind) -> String {
|
private func iconName(for kind: WorkspaceFileKind) -> String {
|
||||||
switch kind {
|
switch kind {
|
||||||
|
|
@ -186,6 +195,11 @@ private struct WorkspaceItemRow: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct WorkspaceChildrenContentID: Hashable {
|
||||||
|
var itemURL: URL
|
||||||
|
var revision: Int
|
||||||
|
}
|
||||||
|
|
||||||
private extension WorkspaceItem {
|
private extension WorkspaceItem {
|
||||||
var stableTreeID: URL {
|
var stableTreeID: URL {
|
||||||
switch self {
|
switch self {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue