Yep. AI rewrote the whole thing.
This commit is contained in:
271
Downterm/CommandNotch/Views/WorkspacesSettingsView.swift
Normal file
271
Downterm/CommandNotch/Views/WorkspacesSettingsView.swift
Normal file
@@ -0,0 +1,271 @@
|
||||
import SwiftUI
|
||||
|
||||
struct WorkspacesSettingsView: View {
|
||||
@ObservedObject private var workspaceRegistry = WorkspaceRegistry.shared
|
||||
@ObservedObject private var screenRegistry = ScreenRegistry.shared
|
||||
|
||||
@State private var selectedWorkspaceID: WorkspaceID?
|
||||
@State private var renameDraft = ""
|
||||
@State private var isDeleteAlertPresented = false
|
||||
|
||||
private var effectiveSelectedWorkspaceID: WorkspaceID? {
|
||||
selectedWorkspaceID ?? workspaceRegistry.workspaceSummaries.first?.id
|
||||
}
|
||||
|
||||
private var selectedSummary: WorkspaceSummary? {
|
||||
guard let effectiveSelectedWorkspaceID else { return nil }
|
||||
return workspaceRegistry.summary(for: effectiveSelectedWorkspaceID)
|
||||
}
|
||||
|
||||
private var selectedController: WorkspaceController? {
|
||||
guard let effectiveSelectedWorkspaceID else { return nil }
|
||||
return workspaceRegistry.controller(for: effectiveSelectedWorkspaceID)
|
||||
}
|
||||
|
||||
private var selectedAssignedScreenIDs: [ScreenID] {
|
||||
guard let effectiveSelectedWorkspaceID else { return [] }
|
||||
return screenRegistry.assignedScreenIDs(to: effectiveSelectedWorkspaceID)
|
||||
}
|
||||
|
||||
private var connectedScreenSummaries: [ConnectedScreenSummary] {
|
||||
screenRegistry.connectedScreenSummaries()
|
||||
}
|
||||
|
||||
private var activeConnectedScreenSummary: ConnectedScreenSummary? {
|
||||
connectedScreenSummaries.first(where: \.isActive)
|
||||
}
|
||||
|
||||
private var deletionFallbackSummary: WorkspaceSummary? {
|
||||
guard let effectiveSelectedWorkspaceID,
|
||||
let fallbackID = workspaceRegistry.deletionFallbackWorkspaceID(
|
||||
forDeleting: effectiveSelectedWorkspaceID,
|
||||
preferredFallback: workspaceRegistry.defaultWorkspaceID
|
||||
) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return workspaceRegistry.summary(for: fallbackID)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 20) {
|
||||
List(selection: $selectedWorkspaceID) {
|
||||
ForEach(workspaceRegistry.workspaceSummaries) { summary in
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(summary.name)
|
||||
.font(.headline)
|
||||
|
||||
Text(usageDescription(for: summary))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.tag(summary.id)
|
||||
.accessibilityIdentifier("settings.workspace.row.\(summary.id.uuidString)")
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier("settings.workspaces.list")
|
||||
.frame(minWidth: 220, idealWidth: 240, maxWidth: 260, maxHeight: .infinity)
|
||||
|
||||
if let summary = selectedSummary {
|
||||
Form {
|
||||
Section("Identity") {
|
||||
TextField("Workspace name", text: $renameDraft)
|
||||
.accessibilityIdentifier("settings.workspaces.name-field")
|
||||
.onSubmit {
|
||||
renameSelectedWorkspace()
|
||||
}
|
||||
|
||||
HStack {
|
||||
Button("Save Name") {
|
||||
renameSelectedWorkspace()
|
||||
}
|
||||
.accessibilityIdentifier("settings.workspaces.save-name")
|
||||
|
||||
Button("New Workspace") {
|
||||
createWorkspace()
|
||||
}
|
||||
.accessibilityIdentifier("settings.workspaces.new")
|
||||
}
|
||||
}
|
||||
|
||||
Section("Usage") {
|
||||
LabeledContent("Assigned screens") {
|
||||
Text("\(selectedAssignedScreenIDs.count)")
|
||||
.accessibilityIdentifier("settings.workspaces.assigned-count")
|
||||
}
|
||||
|
||||
LabeledContent("Open tabs") {
|
||||
Text("\(selectedController?.tabs.count ?? 0)")
|
||||
}
|
||||
|
||||
if selectedAssignedScreenIDs.isEmpty {
|
||||
Text("No screens are currently assigned to this workspace.")
|
||||
.foregroundStyle(.secondary)
|
||||
} else {
|
||||
ForEach(selectedAssignedScreenIDs, id: \.self) { screenID in
|
||||
LabeledContent("Screen") {
|
||||
Text(screenID)
|
||||
.font(.caption.monospaced())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section("Shared Workspace Rules") {
|
||||
Text(sharedWorkspaceDescription(for: selectedAssignedScreenIDs.count))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section("Connected Screens") {
|
||||
if let activeScreen = activeConnectedScreenSummary {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(activeScreen.displayName)
|
||||
Text(activeScreen.id)
|
||||
.font(.caption.monospaced())
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(activeScreen.assignedWorkspaceID == summary.id ? "Assigned Here" : "Assign Current Screen") {
|
||||
screenRegistry.assignWorkspace(summary.id, to: activeScreen.id)
|
||||
}
|
||||
.accessibilityIdentifier("settings.workspaces.assign-current")
|
||||
.disabled(activeScreen.assignedWorkspaceID == summary.id)
|
||||
}
|
||||
} else {
|
||||
Text("No connected screens are currently available.")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
ForEach(connectedScreenSummaries.filter { !$0.isActive }) { screen in
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(screen.displayName)
|
||||
Text(screen.id)
|
||||
.font(.caption.monospaced())
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(screen.assignedWorkspaceID == summary.id ? "Assigned Here" : "Assign Here") {
|
||||
screenRegistry.assignWorkspace(summary.id, to: screen.id)
|
||||
}
|
||||
.accessibilityIdentifier("settings.workspaces.assign.\(screen.id)")
|
||||
.disabled(screen.assignedWorkspaceID == summary.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section("Danger Zone") {
|
||||
Button("Delete Workspace", role: .destructive) {
|
||||
isDeleteAlertPresented = true
|
||||
}
|
||||
.accessibilityIdentifier("settings.workspaces.delete")
|
||||
.disabled(!workspaceRegistry.canDeleteWorkspace(id: summary.id))
|
||||
|
||||
if !workspaceRegistry.canDeleteWorkspace(id: summary.id) {
|
||||
Text("At least one workspace must remain.")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
} else {
|
||||
ContentUnavailableView(
|
||||
"No Workspaces",
|
||||
systemImage: "rectangle.3.group",
|
||||
description: Text("Create a workspace to start grouping tabs across screens.")
|
||||
)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
selectInitialWorkspaceIfNeeded()
|
||||
}
|
||||
.onChange(of: workspaceRegistry.workspaceSummaries) { _, _ in
|
||||
synchronizeSelectionWithRegistry()
|
||||
}
|
||||
.onChange(of: selectedWorkspaceID) { _, _ in
|
||||
renameDraft = selectedSummary?.name ?? ""
|
||||
}
|
||||
.alert("Delete Workspace", isPresented: $isDeleteAlertPresented) {
|
||||
Button("Cancel", role: .cancel) {}
|
||||
Button("Delete", role: .destructive) {
|
||||
deleteSelectedWorkspace()
|
||||
}
|
||||
} message: {
|
||||
if let summary = selectedSummary, let fallback = deletionFallbackSummary {
|
||||
Text(
|
||||
"Deleting \(summary.name) reassigns its screens to \(fallback.name) and closes the workspace."
|
||||
)
|
||||
} else {
|
||||
Text("At least one workspace must remain.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func usageDescription(for summary: WorkspaceSummary) -> String {
|
||||
let screenCount = screenRegistry.assignedScreenCount(to: summary.id)
|
||||
let tabCount = workspaceRegistry.controller(for: summary.id)?.tabs.count ?? 0
|
||||
return "\(screenCount) screen\(screenCount == 1 ? "" : "s") · \(tabCount) tab\(tabCount == 1 ? "" : "s")"
|
||||
}
|
||||
|
||||
private func sharedWorkspaceDescription(for screenCount: Int) -> String {
|
||||
if screenCount > 1 {
|
||||
return "This workspace is shared across \(screenCount) screens. Tab changes stay in sync across each assigned screen."
|
||||
}
|
||||
|
||||
if screenCount == 1 {
|
||||
return "This workspace is assigned to one screen. You can assign additional screens to share the same tabs."
|
||||
}
|
||||
|
||||
return "Unassigned workspaces keep their tabs and can be attached to any screen later."
|
||||
}
|
||||
|
||||
private func selectInitialWorkspaceIfNeeded() {
|
||||
if selectedWorkspaceID == nil {
|
||||
selectedWorkspaceID = workspaceRegistry.workspaceSummaries.first?.id
|
||||
}
|
||||
renameDraft = selectedSummary?.name ?? ""
|
||||
}
|
||||
|
||||
private func synchronizeSelectionWithRegistry() {
|
||||
guard let selectedWorkspaceID else {
|
||||
selectInitialWorkspaceIfNeeded()
|
||||
return
|
||||
}
|
||||
|
||||
if workspaceRegistry.summary(for: selectedWorkspaceID) == nil {
|
||||
self.selectedWorkspaceID = workspaceRegistry.workspaceSummaries.first?.id
|
||||
}
|
||||
|
||||
renameDraft = selectedSummary?.name ?? ""
|
||||
}
|
||||
|
||||
private func renameSelectedWorkspace() {
|
||||
guard let effectiveSelectedWorkspaceID else { return }
|
||||
workspaceRegistry.renameWorkspace(id: effectiveSelectedWorkspaceID, to: renameDraft)
|
||||
renameDraft = selectedSummary?.name ?? renameDraft
|
||||
}
|
||||
|
||||
private func createWorkspace() {
|
||||
let workspaceID = workspaceRegistry.createWorkspace()
|
||||
selectedWorkspaceID = workspaceID
|
||||
renameDraft = workspaceRegistry.summary(for: workspaceID)?.name ?? ""
|
||||
}
|
||||
|
||||
private func deleteSelectedWorkspace() {
|
||||
guard let effectiveSelectedWorkspaceID,
|
||||
let fallbackWorkspaceID = screenRegistry.deleteWorkspace(
|
||||
effectiveSelectedWorkspaceID,
|
||||
preferredFallback: workspaceRegistry.defaultWorkspaceID
|
||||
) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.selectedWorkspaceID = fallbackWorkspaceID
|
||||
renameDraft = workspaceRegistry.summary(for: fallbackWorkspaceID)?.name ?? ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user