Skip to content

Commit

Permalink
Fix Task Dropdown Crash (#1956)
Browse files Browse the repository at this point in the history
### Description

- Fixes a crash when opening the task dropdown menu.
- Improves accessibility in the activity viewer, dropdowns, and workspace settings window.
- Adds UI tests for the dropdown menu and the entire task creation workflow.

### Related Issues

- N/A

### Checklist

<!--- Add things that are not yet implemented above -->

- [x] I read and understood the [contributing guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md) as well as the [code of conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md)
- [x] The issues this PR addresses are related to each other
- [x] My changes generate no new warnings
- [x] My code builds and runs on my machine
- [x] My changes are all related to the related issue above
- [x] I documented my code

### Screenshots

One of the new UI Tests

https://github.com/user-attachments/assets/de6ce034-92b9-475d-b0d2-ddcf05e2518d
  • Loading branch information
thecoolwinter authored Jan 8, 2025
1 parent ca35a5d commit 580b249
Show file tree
Hide file tree
Showing 21 changed files with 330 additions and 78 deletions.
44 changes: 38 additions & 6 deletions CodeEdit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@
6C05A8AF284D0CA3007F4EAA /* WorkspaceDocument+Listeners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C05A8AE284D0CA3007F4EAA /* WorkspaceDocument+Listeners.swift */; };
6C05CF9E2CDE8699006AAECD /* CodeEditSourceEditor in Frameworks */ = {isa = PBXBuildFile; productRef = 6C05CF9D2CDE8699006AAECD /* CodeEditSourceEditor */; };
6C0617D62BDB4432008C9C42 /* LogStream in Frameworks */ = {isa = PBXBuildFile; productRef = 6C0617D52BDB4432008C9C42 /* LogStream */; };
6C07383B2D284ECA0025CBE3 /* TasksMenuUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C07383A2D284ECA0025CBE3 /* TasksMenuUITests.swift */; };
6C08249C2C556F7400A0751E /* TerminalCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C08249B2C556F7400A0751E /* TerminalCache.swift */; };
6C08249E2C55768400A0751E /* UtilityAreaTerminal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C08249D2C55768400A0751E /* UtilityAreaTerminal.swift */; };
6C0824A12C5C0C9700A0751E /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = 6C0824A02C5C0C9700A0751E /* SwiftTerm */; };
Expand Down Expand Up @@ -402,6 +403,7 @@
6C48D8F72972E5F300D6D205 /* WindowObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48D8F62972E5F300D6D205 /* WindowObserver.swift */; };
6C4E37F62C73DA5200AEE7B5 /* UtilityAreaTerminalSidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4E37F52C73DA5200AEE7B5 /* UtilityAreaTerminalSidebar.swift */; };
6C4E37FC2C73E00700AEE7B5 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = 6C4E37FB2C73E00700AEE7B5 /* SwiftTerm */; };
6C510CB82D2E4639006EBE85 /* XCUITest+waitForNonExistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C510CB72D2E4639006EBE85 /* XCUITest+waitForNonExistence.swift */; };
6C5228B529A868BD00AC48F6 /* Environment+ContentInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C5228B429A868BD00AC48F6 /* Environment+ContentInsets.swift */; };
6C53AAD829A6C4FD00EE9ED6 /* SplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C53AAD729A6C4FD00EE9ED6 /* SplitView.swift */; };
6C578D8129CD294800DC73B2 /* ExtensionActivatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C578D8029CD294800DC73B2 /* ExtensionActivatorView.swift */; };
Expand Down Expand Up @@ -1052,6 +1054,7 @@
66F370332BEE537B00D3B823 /* NonTextFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonTextFileView.swift; sourceTree = "<group>"; };
6C049A362A49E2DB00D42923 /* DirectoryEventStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoryEventStream.swift; sourceTree = "<group>"; };
6C05A8AE284D0CA3007F4EAA /* WorkspaceDocument+Listeners.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WorkspaceDocument+Listeners.swift"; sourceTree = "<group>"; };
6C07383A2D284ECA0025CBE3 /* TasksMenuUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksMenuUITests.swift; sourceTree = "<group>"; };
6C08249B2C556F7400A0751E /* TerminalCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalCache.swift; sourceTree = "<group>"; };
6C08249D2C55768400A0751E /* UtilityAreaTerminal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilityAreaTerminal.swift; sourceTree = "<group>"; };
6C092ED92A53A58600489202 /* EditorLayout+StateRestoration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EditorLayout+StateRestoration.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1094,6 +1097,7 @@
6C48D8F32972DB1A00D6D205 /* Env+Window.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Env+Window.swift"; sourceTree = "<group>"; };
6C48D8F62972E5F300D6D205 /* WindowObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowObserver.swift; sourceTree = "<group>"; };
6C4E37F52C73DA5200AEE7B5 /* UtilityAreaTerminalSidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilityAreaTerminalSidebar.swift; sourceTree = "<group>"; };
6C510CB72D2E4639006EBE85 /* XCUITest+waitForNonExistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCUITest+waitForNonExistence.swift"; sourceTree = "<group>"; };
6C5228B429A868BD00AC48F6 /* Environment+ContentInsets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Environment+ContentInsets.swift"; sourceTree = "<group>"; };
6C53AAD729A6C4FD00EE9ED6 /* SplitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitView.swift; sourceTree = "<group>"; };
6C578D8029CD294800DC73B2 /* ExtensionActivatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionActivatorView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2708,14 +2712,14 @@
618725A22C29EFE200987354 /* Tasks */ = {
isa = PBXGroup;
children = (
B69D3EE22C5F536B005CF43A /* ActiveTaskView.swift */,
618725A52C29F02500987354 /* DropdownMenuItemStyleModifier.swift */,
618725A72C29F05500987354 /* OptionMenuItemView.swift */,
618725A02C29EFCC00987354 /* SchemeDropDownView.swift */,
618725AA2C29F2C000987354 /* TaskDropDownView.swift */,
B69D3EE02C5F5357005CF43A /* TaskView.swift */,
B69D3EE22C5F536B005CF43A /* ActiveTaskView.swift */,
B69D3EE42C5F54B3005CF43A /* TasksPopoverMenuItem.swift */,
B69D3EE02C5F5357005CF43A /* TaskView.swift */,
618725A32C29F00400987354 /* WorkspaceMenuItemView.swift */,
618725A72C29F05500987354 /* OptionMenuItemView.swift */,
618725A52C29F02500987354 /* DropdownMenuItemStyleModifier.swift */,
);
path = Tasks;
sourceTree = "<group>";
Expand Down Expand Up @@ -2841,6 +2845,22 @@
name = "Recovered References";
sourceTree = "<group>";
};
6C0738382D284EA20025CBE3 /* ActivityViewer */ = {
isa = PBXGroup;
children = (
6C0738392D284EAE0025CBE3 /* Tasks */,
);
path = ActivityViewer;
sourceTree = "<group>";
};
6C0738392D284EAE0025CBE3 /* Tasks */ = {
isa = PBXGroup;
children = (
6C07383A2D284ECA0025CBE3 /* TasksMenuUITests.swift */,
);
path = Tasks;
sourceTree = "<group>";
};
6C092EDC2A53A63E00489202 /* Views */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2951,6 +2971,14 @@
path = Environment;
sourceTree = "<group>";
};
6C510CB62D2E462D006EBE85 /* Extensions */ = {
isa = PBXGroup;
children = (
6C510CB72D2E4639006EBE85 /* XCUITest+waitForNonExistence.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
6C6BD6ED29CD123000235D17 /* Extensions */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3007,6 +3035,7 @@
6C96191E2C3F27E3009733CE /* Features */ = {
isa = PBXGroup;
children = (
6C0738382D284EA20025CBE3 /* ActivityViewer */,
6C96191D2C3F27E3009733CE /* NavigatorArea */,
);
path = Features;
Expand All @@ -3016,10 +3045,11 @@
isa = PBXGroup;
children = (
6CFBA54A2C4E168A00E3A914 /* App.swift */,
6C9619232C3F2809009733CE /* ProjectPath.swift */,
6C9619212C3F27F1009733CE /* Query.swift */,
6C510CB62D2E462D006EBE85 /* Extensions */,
6C96191E2C3F27E3009733CE /* Features */,
6CFBA54E2C4E182100E3A914 /* Other Tests */,
6C9619232C3F2809009733CE /* ProjectPath.swift */,
6C9619212C3F27F1009733CE /* Query.swift */,
);
path = CodeEditUITests;
sourceTree = "<group>";
Expand Down Expand Up @@ -4581,10 +4611,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6C510CB82D2E4639006EBE85 /* XCUITest+waitForNonExistence.swift in Sources */,
6C9619242C3F2809009733CE /* ProjectPath.swift in Sources */,
6CFBA54B2C4E168A00E3A914 /* App.swift in Sources */,
6CFBA54D2C4E16C900E3A914 /* WindowCloseCommandTests.swift in Sources */,
6C9619222C3F27F1009733CE /* Query.swift in Sources */,
6C07383B2D284ECA0025CBE3 /* TasksMenuUITests.swift in Sources */,
6C9619202C3F27E3009733CE /* ProjectNavigatorUITests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
2 changes: 2 additions & 0 deletions CodeEdit/Features/ActivityViewer/ActivityViewer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,7 @@ struct ActivityViewer: View {
.opacity(0.1)
}
}
.accessibilityElement(children: .contain)
.accessibilityLabel("Activity Viewer")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ struct CECircularProgressView: View {
.font(.caption)
}
}
.accessibilityElement()
.accessibilityAddTraits(.updatesFrequently)
.accessibilityValue(
progress != nil ? Text(progress!, format: .percent) : Text("working")
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ struct TaskNotificationView: View {
.padding(.trailing, 3)
.popover(isPresented: $isPresented, arrowEdge: .bottom) {
TaskNotificationsDetailView(taskNotificationHandler: taskNotificationHandler)
}.onTapGesture {
}
.onTapGesture {
self.isPresented.toggle()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SwiftUI
struct OptionMenuItemView: View {
var label: String
var action: () -> Void

var body: some View {
HStack {
Text(label)
Expand All @@ -22,6 +23,11 @@ struct OptionMenuItemView: View {
.onTapGesture {
action()
}
.accessibilityElement()
.accessibilityAction {
action()
}
.accessibilityLabel(label)
}
}

Expand Down
73 changes: 45 additions & 28 deletions CodeEdit/Features/ActivityViewer/Tasks/SchemeDropDownView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ struct SchemeDropDownView: View {
workspaceSettingsManager.settings.project.projectName
}

/// Resolves the name one step further than `workspaceName`.
var workspaceDisplayName: String {
workspaceName.isEmpty
? (workspaceFileManager?.workspaceItem.fileName() ?? "No Project found")
: workspaceName
}

var body: some View {
HStack(spacing: 6) {
Image(systemName: "folder.badge.gearshape")
.imageScale(.medium)
Text(
workspaceName.isEmpty
? (workspaceFileManager?.workspaceItem.fileName() ?? "No Project found")
: workspaceName
)
Text(workspaceDisplayName)
}
.font(.subheadline)
.padding(.trailing, 11.5)
Expand All @@ -54,31 +57,19 @@ struct SchemeDropDownView: View {
self.isHoveringScheme = hovering
})
.instantPopover(isPresented: $isSchemePopOverPresented, arrowEdge: .bottom) {
VStack(alignment: .leading, spacing: 0) {
WorkspaceMenuItemView(
workspaceFileManager: workspaceFileManager,
item: workspaceFileManager?.workspaceItem
)
Divider()
.padding(.vertical, 5)
Group {
OptionMenuItemView(label: "Add Folder...") {
// TODO: Implment Add Folder
print("NOT IMPLEMENTED")
}
OptionMenuItemView(label: "Workspace Settings...") {
NSApp.sendAction(
#selector(CodeEditWindowController.openWorkspaceSettings(_:)), to: nil, from: nil
)
}
}
}
.font(.subheadline)
.padding(5)
.frame(minWidth: 215)
popoverContent
}
.onTapGesture {
self.isSchemePopOverPresented.toggle()
isSchemePopOverPresented.toggle()
}
.accessibilityElement(children: .combine)
.accessibilityAddTraits(.isButton)
.accessibilityIdentifier("SchemeDropdown")
.accessibilityValue(workspaceDisplayName)
.accessibilityLabel("Active Scheme")
.accessibilityHint("Open the active scheme menu")
.accessibilityAction {
isSchemePopOverPresented.toggle()
}
}

Expand All @@ -97,6 +88,32 @@ struct SchemeDropDownView: View {
.font(.system(size: 8, weight: .semibold, design: .default))
.padding(.top, 0.5)
}

@ViewBuilder var popoverContent: some View {
VStack(alignment: .leading, spacing: 0) {
WorkspaceMenuItemView(
workspaceFileManager: workspaceFileManager,
item: workspaceFileManager?.workspaceItem
)
Divider()
.padding(.vertical, 5)
Group {
OptionMenuItemView(label: "Add Folder...") {
// TODO: Implment Add Folder
print("NOT IMPLEMENTED")
}
.disabled(true)
OptionMenuItemView(label: "Workspace Settings...") {
NSApp.sendAction(
#selector(CodeEditWindowController.openWorkspaceSettings(_:)), to: nil, from: nil
)
}
}
}
.font(.subheadline)
.padding(5)
.frame(minWidth: 215)
}
}

// #Preview {
Expand Down
15 changes: 13 additions & 2 deletions CodeEdit/Features/ActivityViewer/Tasks/TaskDropDownView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,21 @@ struct TaskDropDownView: View {
.onHover { hovering in
self.isHoveringTasks = hovering
}
.instantPopover(isPresented: $isTaskPopOverPresented, arrowEdge: .bottom) {
.instantPopover(isPresented: $isTaskPopOverPresented, arrowEdge: .top) {
taskPopoverContent
}
.onTapGesture {
self.isTaskPopOverPresented.toggle()
}
.accessibilityElement(children: .combine)
.accessibilityAddTraits(.isButton)
.accessibilityIdentifier("TaskDropdown")
.accessibilityValue(taskManager.selectedTask?.name ?? "Create Tasks")
.accessibilityLabel("Active Task")
.accessibilityHint("Open the active task menu")
.accessibilityAction {
isTaskPopOverPresented = true
}
}

private var backgroundColor: some View {
Expand Down Expand Up @@ -71,7 +80,9 @@ struct TaskDropDownView: View {
VStack(alignment: .leading, spacing: 0) {
if !taskManager.availableTasks.isEmpty {
ForEach(taskManager.availableTasks, id: \.id) { task in
TasksPopoverMenuItem(taskManager: taskManager, task: task)
TasksPopoverMenuItem(taskManager: taskManager, task: task) {
isTaskPopOverPresented = false
}
}
Divider()
.padding(.vertical, 5)
Expand Down
2 changes: 2 additions & 0 deletions CodeEdit/Features/ActivityViewer/Tasks/TaskView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ struct TaskView: View {
.frame(width: 5, height: 5)
.padding(.trailing, 2.5)
}
.accessibilityElement()
.accessibilityLabel(task.name)
}
}
21 changes: 14 additions & 7 deletions CodeEdit/Features/ActivityViewer/Tasks/TasksPopoverMenuItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

import SwiftUI

/// - Note: This view **cannot** use the `dismiss` environment value to dismiss the sheet. It has to negate the boolean
/// value that presented it initially.
/// See ``SwiftUI/View/instantPopover(isPresented:arrowEdge:content:)``
struct TasksPopoverMenuItem: View {
@Environment(\.dismiss)
private var dismiss

@ObservedObject var taskManager: TaskManager
var task: CETask
var dismiss: () -> Void

var body: some View {
HStack(spacing: 5) {
Expand All @@ -22,11 +23,12 @@ struct TasksPopoverMenuItem: View {
.padding(.vertical, 4)
.padding(.horizontal, 8)
.modifier(DropdownMenuItemStyleModifier())
.onTapGesture {
taskManager.selectedTaskID = task.id
dismiss()
}
.onTapGesture(perform: selectAction)
.clipShape(RoundedRectangle(cornerRadius: 5))
.accessibilityElement()
.accessibilityLabel(task.name)
.accessibilityAction(.default, selectAction)
.accessibilityAddTraits(taskManager.selectedTaskID == task.id ? [.isSelected] : [])
}

private var selectionIndicator: some View {
Expand All @@ -52,4 +54,9 @@ struct TasksPopoverMenuItem: View {
}
}
}

private func selectAction() {
taskManager.selectedTaskID = task.id
dismiss()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ struct WorkspaceMenuItemView: View {
.padding(.vertical, 4)
.padding(.horizontal, 8)
.modifier(DropdownMenuItemStyleModifier())
.onTapGesture { }
.onTapGesture { } // add accessibility action when this is filled in
.clipShape(RoundedRectangle(cornerRadius: 5))
.accessibilityElement()
.accessibilityLabel(item?.name ?? "")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct AddCETaskView: View {
}
.padding()
}
.accessibilityIdentifier("AddTaskView")
}

}
Expand Down
Loading

0 comments on commit 580b249

Please sign in to comment.