Yep. AI rewrote the whole thing.
This commit is contained in:
161
Downterm/CommandNotch/Views/WorkspaceSwitcherView.swift
Normal file
161
Downterm/CommandNotch/Views/WorkspaceSwitcherView.swift
Normal file
@@ -0,0 +1,161 @@
|
||||
import SwiftUI
|
||||
|
||||
struct WorkspaceSwitcherView: View {
|
||||
@ObservedObject var screen: ScreenContext
|
||||
let orchestrator: NotchOrchestrator
|
||||
@ObservedObject private var screenRegistry = ScreenRegistry.shared
|
||||
@ObservedObject private var workspaceRegistry = WorkspaceRegistry.shared
|
||||
|
||||
@State private var isRenameAlertPresented = false
|
||||
@State private var isDeleteConfirmationPresented = false
|
||||
@State private var renameDraft = ""
|
||||
|
||||
private var currentWorkspaceSummary: WorkspaceSummary {
|
||||
workspaceRegistry.summary(for: screen.workspaceID)
|
||||
?? workspaceRegistry.allWorkspaceSummaries().first
|
||||
?? WorkspaceSummary(id: screen.workspaceID, name: "Workspace")
|
||||
}
|
||||
|
||||
private var deletionFallbackSummary: WorkspaceSummary? {
|
||||
guard let fallbackWorkspaceID = workspaceRegistry.deletionFallbackWorkspaceID(
|
||||
forDeleting: screen.workspaceID,
|
||||
preferredFallback: workspaceRegistry.defaultWorkspaceID
|
||||
) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return workspaceRegistry.summary(for: fallbackWorkspaceID)
|
||||
}
|
||||
|
||||
private var assignedScreenCount: Int {
|
||||
screenRegistry.assignedScreenCount(to: screen.workspaceID)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Menu {
|
||||
ForEach(workspaceRegistry.workspaceSummaries) { summary in
|
||||
Button {
|
||||
selectWorkspace(summary.id)
|
||||
} label: {
|
||||
if summary.id == screen.workspaceID {
|
||||
Label(summary.name, systemImage: "checkmark")
|
||||
} else {
|
||||
Text(summary.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
Button("New Workspace") {
|
||||
let workspaceID = workspaceRegistry.createWorkspace()
|
||||
selectWorkspace(workspaceID)
|
||||
}
|
||||
|
||||
Button("Rename Current Workspace") {
|
||||
renameDraft = currentWorkspaceSummary.name
|
||||
syncFocusLossSuppression(renamePresented: true, deletePresented: isDeleteConfirmationPresented)
|
||||
isRenameAlertPresented = true
|
||||
}
|
||||
|
||||
Button("Delete Current Workspace", role: .destructive) {
|
||||
syncFocusLossSuppression(renamePresented: isRenameAlertPresented, deletePresented: true)
|
||||
isDeleteConfirmationPresented = true
|
||||
}
|
||||
.disabled(!workspaceRegistry.canDeleteWorkspace(id: screen.workspaceID))
|
||||
} label: {
|
||||
switcherLabel
|
||||
}
|
||||
.menuStyle(.borderlessButton)
|
||||
.accessibilityIdentifier("notch.workspace-switcher")
|
||||
.accessibilityLabel("Workspace Switcher")
|
||||
.accessibilityValue(currentWorkspaceSummary.name)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.help("Switch workspace for this screen")
|
||||
.alert("Rename Workspace", isPresented: $isRenameAlertPresented) {
|
||||
TextField("Workspace name", text: $renameDraft)
|
||||
Button("Cancel", role: .cancel) {}
|
||||
Button("Save") {
|
||||
workspaceRegistry.renameWorkspace(id: screen.workspaceID, to: renameDraft)
|
||||
}
|
||||
} message: {
|
||||
Text("This only renames the shared workspace. Screens assigned to it keep following the new name.")
|
||||
}
|
||||
.confirmationDialog("Delete Workspace", isPresented: $isDeleteConfirmationPresented, titleVisibility: .visible) {
|
||||
Button("Delete Workspace", role: .destructive) {
|
||||
deleteCurrentWorkspace()
|
||||
}
|
||||
} message: {
|
||||
Text(deleteMessage)
|
||||
}
|
||||
.onChange(of: isRenameAlertPresented) { _, isPresented in
|
||||
syncFocusLossSuppression(renamePresented: isPresented, deletePresented: isDeleteConfirmationPresented)
|
||||
}
|
||||
.onChange(of: isDeleteConfirmationPresented) { _, isPresented in
|
||||
syncFocusLossSuppression(renamePresented: isRenameAlertPresented, deletePresented: isPresented)
|
||||
}
|
||||
.onDisappear {
|
||||
screen.setCloseOnFocusLossSuppressed(false)
|
||||
}
|
||||
}
|
||||
|
||||
private var deleteMessage: String {
|
||||
if let fallback = deletionFallbackSummary {
|
||||
return "This reassigns \(assignedScreenCount) screen\(assignedScreenCount == 1 ? "" : "s") to \(fallback.name) and closes this workspace."
|
||||
}
|
||||
|
||||
return "At least one workspace must remain."
|
||||
}
|
||||
|
||||
private var switcherLabel: some View {
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "rectangle.3.group")
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
Text(currentWorkspaceSummary.name)
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.lineLimit(1)
|
||||
Image(systemName: "chevron.down")
|
||||
.font(.system(size: 9, weight: .semibold))
|
||||
}
|
||||
.foregroundStyle(.white.opacity(0.7))
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 4)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(Color.white.opacity(0.08))
|
||||
)
|
||||
.contentShape(Rectangle())
|
||||
.accessibilityElement(children: .ignore)
|
||||
.accessibilityLabel("Workspace Switcher")
|
||||
.accessibilityValue(currentWorkspaceSummary.name)
|
||||
.accessibilityIdentifier("notch.workspace-switcher")
|
||||
}
|
||||
|
||||
private func selectWorkspace(_ workspaceID: WorkspaceID) {
|
||||
screenRegistry.assignWorkspace(workspaceID, to: screen.id)
|
||||
|
||||
if screen.notchState == .open {
|
||||
orchestrator.open(screenID: screen.id)
|
||||
}
|
||||
}
|
||||
|
||||
private func deleteCurrentWorkspace() {
|
||||
guard let fallback = screenRegistry.deleteWorkspace(
|
||||
screen.workspaceID,
|
||||
preferredFallback: workspaceRegistry.defaultWorkspaceID
|
||||
) else {
|
||||
return
|
||||
}
|
||||
|
||||
screenRegistry.assignWorkspace(fallback, to: screen.id)
|
||||
if screen.notchState == .open {
|
||||
orchestrator.open(screenID: screen.id)
|
||||
} else {
|
||||
screen.requestTerminalFocus?()
|
||||
}
|
||||
}
|
||||
|
||||
private func syncFocusLossSuppression(renamePresented: Bool, deletePresented: Bool) {
|
||||
screen.setCloseOnFocusLossSuppressed(renamePresented || deletePresented)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user