Skip to content

Commit

Permalink
Workspace Panel View (#1960)
Browse files Browse the repository at this point in the history
* Abstracted shared logic from NavigatorAreaView, InspectorAreaView, and UtilityAreaView into reusable view called WorkspacePanelView.

* Updated to latest
  • Loading branch information
austincondiff authored Jan 8, 2025
1 parent e760191 commit ca35a5d
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 164 deletions.
20 changes: 12 additions & 8 deletions CodeEdit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
30CB648D2C12680F00CC8A9E /* LSPService+Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CB648C2C12680F00CC8A9E /* LSPService+Events.swift */; };
30CB64912C16CA8100CC8A9E /* LanguageServerProtocol in Frameworks */ = {isa = PBXBuildFile; productRef = 30CB64902C16CA8100CC8A9E /* LanguageServerProtocol */; };
30CB64942C16CA9100CC8A9E /* LanguageClient in Frameworks */ = {isa = PBXBuildFile; productRef = 30CB64932C16CA9100CC8A9E /* LanguageClient */; };
30E6D0012A6E505200A58B20 /* NavigatorSidebarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E6D0002A6E505200A58B20 /* NavigatorSidebarViewModel.swift */; };
30E6D0012A6E505200A58B20 /* NavigatorAreaViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E6D0002A6E505200A58B20 /* NavigatorAreaViewModel.swift */; };
3E0196732A3921AC002648D8 /* codeedit_shell_integration_rc.zsh in Resources */ = {isa = PBXBuildFile; fileRef = 3E0196722A3921AC002648D8 /* codeedit_shell_integration_rc.zsh */; };
3E01967A2A392B45002648D8 /* codeedit_shell_integration.bash in Resources */ = {isa = PBXBuildFile; fileRef = 3E0196792A392B45002648D8 /* codeedit_shell_integration.bash */; };
4A6F0DB52CBA462B00499627 /* ProjectNavigatorMenuActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A6F0DB42CBA462B00499627 /* ProjectNavigatorMenuActions.swift */; };
Expand Down Expand Up @@ -524,7 +524,7 @@
B62423302C21EE280096668B /* ThemeModel+CRUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = B624232F2C21EE280096668B /* ThemeModel+CRUD.swift */; };
B628B7932B18369800F9775A /* GitClient+Validate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B628B7922B18369800F9775A /* GitClient+Validate.swift */; };
B628B7B72B223BAD00F9775A /* FindModePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B628B7B62B223BAD00F9775A /* FindModePicker.swift */; };
B62AEDAA2A1FCBE5009A9F52 /* AreaTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62AEDA92A1FCBE5009A9F52 /* AreaTabBar.swift */; };
B62AEDAA2A1FCBE5009A9F52 /* WorkspacePanelTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62AEDA92A1FCBE5009A9F52 /* WorkspacePanelTabBar.swift */; };
B62AEDB32A1FD95B009A9F52 /* UtilityAreaTerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62AEDB22A1FD95B009A9F52 /* UtilityAreaTerminalView.swift */; };
B62AEDB52A1FE295009A9F52 /* UtilityAreaDebugView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62AEDB42A1FE295009A9F52 /* UtilityAreaDebugView.swift */; };
B62AEDB82A1FE2DC009A9F52 /* UtilityAreaOutputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62AEDB72A1FE2DC009A9F52 /* UtilityAreaOutputView.swift */; };
Expand Down Expand Up @@ -558,6 +558,7 @@
B66A4E5329C91831004573B4 /* CodeEditCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66A4E5229C91831004573B4 /* CodeEditCommands.swift */; };
B66A4E5629C918A0004573B4 /* SceneID.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66A4E5529C918A0004573B4 /* SceneID.swift */; };
B67431CC2C3E45F30047FCA6 /* SourceControlSwitchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67431CB2C3E45F30047FCA6 /* SourceControlSwitchView.swift */; };
B67700F92D2A2662004FD61F /* WorkspacePanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67700F82D2A2662004FD61F /* WorkspacePanelView.swift */; };
B67DB0EF2AF3E381002DC647 /* PaneTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67DB0EE2AF3E381002DC647 /* PaneTextField.swift */; };
B67DB0F62AFC2A7A002DC647 /* FindNavigatorToolbarBottom.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67DB0F52AFC2A7A002DC647 /* FindNavigatorToolbarBottom.swift */; };
B67DB0F92AFDF638002DC647 /* IconButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67DB0F82AFDF638002DC647 /* IconButtonStyle.swift */; };
Expand Down Expand Up @@ -789,7 +790,7 @@
30B087F82C0D53080063A882 /* LSPService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LSPService.swift; sourceTree = "<group>"; };
30B087FA2C0D53080063A882 /* LSPUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LSPUtil.swift; sourceTree = "<group>"; };
30CB648C2C12680F00CC8A9E /* LSPService+Events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LSPService+Events.swift"; sourceTree = "<group>"; };
30E6D0002A6E505200A58B20 /* NavigatorSidebarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigatorSidebarViewModel.swift; sourceTree = "<group>"; };
30E6D0002A6E505200A58B20 /* NavigatorAreaViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigatorAreaViewModel.swift; sourceTree = "<group>"; };
3E0196722A3921AC002648D8 /* codeedit_shell_integration_rc.zsh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = codeedit_shell_integration_rc.zsh; sourceTree = "<group>"; };
3E0196792A392B45002648D8 /* codeedit_shell_integration.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = codeedit_shell_integration.bash; sourceTree = "<group>"; };
4A6F0DB42CBA462B00499627 /* ProjectNavigatorMenuActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectNavigatorMenuActions.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1200,7 +1201,7 @@
B624232F2C21EE280096668B /* ThemeModel+CRUD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThemeModel+CRUD.swift"; sourceTree = "<group>"; };
B628B7922B18369800F9775A /* GitClient+Validate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GitClient+Validate.swift"; sourceTree = "<group>"; };
B628B7B62B223BAD00F9775A /* FindModePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindModePicker.swift; sourceTree = "<group>"; };
B62AEDA92A1FCBE5009A9F52 /* AreaTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AreaTabBar.swift; sourceTree = "<group>"; };
B62AEDA92A1FCBE5009A9F52 /* WorkspacePanelTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspacePanelTabBar.swift; sourceTree = "<group>"; };
B62AEDB22A1FD95B009A9F52 /* UtilityAreaTerminalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilityAreaTerminalView.swift; sourceTree = "<group>"; };
B62AEDB42A1FE295009A9F52 /* UtilityAreaDebugView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilityAreaDebugView.swift; sourceTree = "<group>"; };
B62AEDB72A1FE2DC009A9F52 /* UtilityAreaOutputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilityAreaOutputView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1239,6 +1240,7 @@
B66A4E5229C91831004573B4 /* CodeEditCommands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeEditCommands.swift; sourceTree = "<group>"; };
B66A4E5529C918A0004573B4 /* SceneID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneID.swift; sourceTree = "<group>"; };
B67431CB2C3E45F30047FCA6 /* SourceControlSwitchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceControlSwitchView.swift; sourceTree = "<group>"; };
B67700F82D2A2662004FD61F /* WorkspacePanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspacePanelView.swift; sourceTree = "<group>"; };
B67DB0EE2AF3E381002DC647 /* PaneTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaneTextField.swift; sourceTree = "<group>"; };
B67DB0F52AFC2A7A002DC647 /* FindNavigatorToolbarBottom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindNavigatorToolbarBottom.swift; sourceTree = "<group>"; };
B67DB0F82AFDF638002DC647 /* IconButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconButtonStyle.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1572,7 +1574,7 @@
307AC4CB2ABABD9800163376 /* ViewModels */ = {
isa = PBXGroup;
children = (
30E6D0002A6E505200A58B20 /* NavigatorSidebarViewModel.swift */,
30E6D0002A6E505200A58B20 /* NavigatorAreaViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
Expand Down Expand Up @@ -2087,8 +2089,9 @@
587B9D8629300ABD00AC7927 /* Views */ = {
isa = PBXGroup;
children = (
B67700F82D2A2662004FD61F /* WorkspacePanelView.swift */,
B62AEDA92A1FCBE5009A9F52 /* WorkspacePanelTabBar.swift */,
30AB4EC12BF7253200ED4431 /* KeyValueTable.swift */,
B62AEDA92A1FCBE5009A9F52 /* AreaTabBar.swift */,
B65B10EB2B073913002852CF /* CEContentUnavailableView.swift */,
B65B10FA2B08B054002852CF /* Divided.swift */,
587B9D8B29300ABD00AC7927 /* EffectView.swift */,
Expand Down Expand Up @@ -4322,6 +4325,7 @@
77EF6C052C57DE4B00984B69 /* URL+ResouceValues.swift in Sources */,
B640A9A129E2188F00715F20 /* View+NavigationBarBackButtonVisible.swift in Sources */,
587B9E7929301D8F00AC7927 /* GitHubIssueRouter.swift in Sources */,
B67700F92D2A2662004FD61F /* WorkspacePanelView.swift in Sources */,
587B9E8029301D8F00AC7927 /* GitHubConfiguration.swift in Sources */,
58822524292C280D00E83CDE /* StatusBarView.swift in Sources */,
581550D429FBD37D00684881 /* ProjectNavigatorToolbarBottom.swift in Sources */,
Expand Down Expand Up @@ -4377,7 +4381,7 @@
4A6F0DB52CBA462B00499627 /* ProjectNavigatorMenuActions.swift in Sources */,
58F2EB05292FB2B0004A9BDE /* Settings.swift in Sources */,
6CBD1BC62978DE53006639D5 /* Font+Caption3.swift in Sources */,
30E6D0012A6E505200A58B20 /* NavigatorSidebarViewModel.swift in Sources */,
30E6D0012A6E505200A58B20 /* NavigatorAreaViewModel.swift in Sources */,
6CD26C7B2C8EA8A500ADBA38 /* LSPCache+Data.swift in Sources */,
B6E41C9429DEAE260088F9F4 /* SourceControlAccount.swift in Sources */,
2806E9022979588B000040F4 /* Contributor.swift in Sources */,
Expand Down Expand Up @@ -4467,7 +4471,7 @@
58D01C9A293167DC00C5B6B4 /* CodeEditKeychain.swift in Sources */,
6CB94CFE2C9F1C9A00E8651C /* TextView+LSPRange.swift in Sources */,
B6966A2E2C3056AD00259C2D /* SourceControlCommands.swift in Sources */,
B62AEDAA2A1FCBE5009A9F52 /* AreaTabBar.swift in Sources */,
B62AEDAA2A1FCBE5009A9F52 /* WorkspacePanelTabBar.swift in Sources */,
20D839AB280DEB2900B27357 /* NoSelectionInspectorView.swift in Sources */,
30B0880F2C0D53080063A882 /* LanguageServer+SelectionRange.swift in Sources */,
30B0880C2C0D53080063A882 /* LanguageServer+InlayHint.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
//
// AreaTabBar.swift
// WorkspacePanelTabBar.swift
// CodeEdit
//
// Created by Austin Condiff on 5/25/23.
//

import SwiftUI

protocol AreaTab: View, Identifiable, Hashable {
protocol WorkspacePanelTab: View, Identifiable, Hashable {
var title: String { get }
var systemImage: String { get }
}

struct AreaTabBar<Tab: AreaTab>: View {
struct WorkspacePanelTabBar<Tab: WorkspacePanelTab>: View {
@Binding var items: [Tab]
@Binding var selection: Tab?

Expand Down Expand Up @@ -113,7 +113,7 @@ struct AreaTabBar<Tab: AreaTab>: View {
)
)
.focusable(false)
.accessibilityIdentifier("TabAreaTab-\(tab.title)")
.accessibilityIdentifier("WorkspacePanelTab-\(tab.title)")
.accessibilityLabel(tab.title)
}

Expand Down
64 changes: 64 additions & 0 deletions CodeEdit/Features/CodeEditUI/Views/WorkspacePanelView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// WorkspacePanelView.swift
// CodeEdit
//
// Created by Austin Condiff on 1/4/25.
//

import SwiftUI

struct WorkspacePanelView<Tab: WorkspacePanelTab, ViewModel: ObservableObject>: View {
@ObservedObject var viewModel: ViewModel
@Binding var selectedTab: Tab?
@Binding var tabItems: [Tab]

@Environment(\.colorScheme)
private var colorScheme

var sidebarPosition: SettingsData.SidebarTabBarPosition
var darkDivider: Bool

init(
viewModel: ViewModel,
selectedTab: Binding<Tab?>,
tabItems: Binding<[Tab]>,
sidebarPosition: SettingsData.SidebarTabBarPosition,
darkDivider: Bool = false
) {
self.viewModel = viewModel
self._selectedTab = selectedTab
self._tabItems = tabItems
self.sidebarPosition = sidebarPosition
self.darkDivider = darkDivider
}

var body: some View {
VStack(spacing: 0) {
if let selection = selectedTab {
selection
} else {
CEContentUnavailableView("No Selection")
}
}
.safeAreaInset(edge: .leading, spacing: 0) {
if sidebarPosition == .side {
HStack(spacing: 0) {
WorkspacePanelTabBar(items: $tabItems, selection: $selectedTab, position: sidebarPosition)
Divider()
.overlay(Color(nsColor: darkDivider && colorScheme == .dark ? .black : .clear))
}
}
}
.safeAreaInset(edge: .top, spacing: 0) {
if sidebarPosition == .top {
VStack(spacing: 0) {
Divider()
WorkspacePanelTabBar(items: $tabItems, selection: $selectedTab, position: sidebarPosition)
Divider()
}
} else if !darkDivider {
Divider()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ final class CodeEditSplitViewController: NSSplitViewController {
static let minSnapWidth: CGFloat = snapWidth - 10

private weak var workspace: WorkspaceDocument?
private weak var navigatorViewModel: NavigatorSidebarViewModel?
private weak var navigatorViewModel: NavigatorAreaViewModel?
private weak var windowRef: NSWindow?
private unowned var hapticPerformer: NSHapticFeedbackPerformer

// MARK: - Initialization

init(
workspace: WorkspaceDocument,
navigatorViewModel: NavigatorSidebarViewModel,
navigatorViewModel: NavigatorAreaViewModel,
windowRef: NSWindow,
hapticPerformer: NSHapticFeedbackPerformer = NSHapticFeedbackManager.defaultPerformer
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs
var workspaceSettingsWindow: NSWindow?
var quickOpenPanel: SearchPanel?
var commandPalettePanel: SearchPanel?
var navigatorSidebarViewModel: NavigatorSidebarViewModel?
var navigatorSidebarViewModel: NavigatorAreaViewModel?

internal var cancellables = [AnyCancellable]()

Expand Down Expand Up @@ -86,7 +86,7 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs
return nil
}

let navigatorModel = NavigatorSidebarViewModel()
let navigatorModel = NavigatorAreaViewModel()
navigatorSidebarViewModel = navigatorModel
self.listenToDocumentEdited(workspace: workspace)
return CodeEditSplitViewController(
Expand Down
2 changes: 1 addition & 1 deletion CodeEdit/Features/InspectorArea/Models/InspectorTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import SwiftUI
import CodeEditKit
import ExtensionFoundation

enum InspectorTab: AreaTab {
enum InspectorTab: WorkspacePanelTab {
case file
case gitHistory
case uiExtension(endpoint: AppExtensionIdentity, data: ResolvedSidebar.SidebarStore)
Expand Down
75 changes: 16 additions & 59 deletions CodeEdit/Features/InspectorArea/Views/InspectorAreaView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,82 +9,39 @@ import SwiftUI

struct InspectorAreaView: View {
@EnvironmentObject private var workspace: WorkspaceDocument
@EnvironmentObject private var editorManager: EditorManager
@ObservedObject private var extensionManager = ExtensionManager.shared
@ObservedObject public var viewModel: InspectorAreaViewModel

@EnvironmentObject private var editorManager: EditorManager

@AppSettings(\.sourceControl.general.sourceControlIsEnabled)
private var sourceControlIsEnabled: Bool

@AppSettings(\.general.inspectorTabBarPosition)
var sidebarPosition: SettingsData.SidebarTabBarPosition

@State private var selection: InspectorTab? = .file

init(viewModel: InspectorAreaViewModel) {
self.viewModel = viewModel
updateTabItems()
}

func getExtension(_ id: String) -> ExtensionInfo? {
return extensionManager.extensions.first(
where: { $0.endpoint.bundleIdentifier == id }
)
}

var body: some View {
VStack {
if let selection {
selection
} else {
NoSelectionInspectorView()
}
}
.safeAreaInset(edge: .trailing, spacing: 0) {
if sidebarPosition == .side {
HStack(spacing: 0) {
Divider()
AreaTabBar(items: $viewModel.tabItems, selection: $selection, position: sidebarPosition)
}
}
}
.safeAreaInset(edge: .top, spacing: 0) {
if sidebarPosition == .top {
VStack(spacing: 0) {
Divider()
AreaTabBar(items: $viewModel.tabItems, selection: $selection, position: sidebarPosition)
Divider()
}
} else {
Divider()
}
}
.formStyle(.grouped)
.accessibilityElement(children: .contain)
.accessibilityLabel("inspector")
.onChange(of: sourceControlIsEnabled) { _ in
updateTabItems()
}
}

private func updateTabItems() {
viewModel.tabItems = [.file] +
(sourceControlIsEnabled ? [.gitHistory] : []) +
viewModel.tabItems = [.file, .gitHistory] +
extensionManager
.extensions
.flatMap { ext in
.map { ext in
ext.availableFeatures.compactMap {
if case .sidebarItem(let data) = $0, data.kind == .inspector {
return InspectorTab.uiExtension(endpoint: ext.endpoint, data: data)
}
return nil
}
}
if let selectedTab = selection,
!viewModel.tabItems.isEmpty &&
!viewModel.tabItems.contains(selectedTab) {
selection = viewModel.tabItems[0]
}
.joined()
}

var body: some View {
WorkspacePanelView(
viewModel: viewModel,
selectedTab: $viewModel.selectedTab,
tabItems: $viewModel.tabItems,
sidebarPosition: sidebarPosition
)
.formStyle(.grouped)
.accessibilityElement(children: .contain)
.accessibilityLabel("inspector")
}
}
2 changes: 1 addition & 1 deletion CodeEdit/Features/NavigatorArea/Models/NavigatorTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import SwiftUI
import CodeEditKit
import ExtensionFoundation

enum NavigatorTab: AreaTab {
enum NavigatorTab: WorkspacePanelTab {
case project
case sourceControl
case search
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//
// NavigatorSidebarViewModel.swift
// NavigatorAreaViewModel.swift
// CodeEdit
//
// Created by Abe Malla on 7/23/23.
//

import Foundation

class NavigatorSidebarViewModel: ObservableObject {
class NavigatorAreaViewModel: ObservableObject {
@Published var selectedTab: NavigatorTab? = .project
/// The tab bar items in the Navigator
@Published var tabItems: [NavigatorTab] = []
Expand Down
Loading

0 comments on commit ca35a5d

Please sign in to comment.