diff --git a/.github/workflows/core-tests.yml b/.github/workflows/core-tests.yml index b9263bb7..01bc2764 100644 --- a/.github/workflows/core-tests.yml +++ b/.github/workflows/core-tests.yml @@ -1,4 +1,4 @@ -name: VisuStructCore tests +name: CI on: push: @@ -17,3 +17,17 @@ jobs: run: swift --version - name: Build and test run: swift test + + app-build: + runs-on: macos-15 + steps: + - uses: actions/checkout@v4 + - name: Xcode version + run: xcodebuild -version + - name: Build app for iOS Simulator + run: | + xcodebuild build \ + -project VisuStruct-iOS/VisuStructXcodeOpen/VisuStruct.xcodeproj \ + -scheme VisuStruct \ + -destination 'generic/platform=iOS Simulator' \ + CODE_SIGNING_ALLOWED=NO diff --git a/VisuStruct-iOS/VisuStructXcodeOpen/VisuStruct/Canvas/DiagramCanvasView.swift b/VisuStruct-iOS/VisuStructXcodeOpen/VisuStruct/Canvas/DiagramCanvasView.swift index ec37350b..9d1525d8 100644 --- a/VisuStruct-iOS/VisuStructXcodeOpen/VisuStruct/Canvas/DiagramCanvasView.swift +++ b/VisuStruct-iOS/VisuStructXcodeOpen/VisuStruct/Canvas/DiagramCanvasView.swift @@ -267,6 +267,7 @@ struct DiagramCanvasView: View { Color.clear .frame(width: cw, height: ch) .contentShape(Rectangle()) + .accessibilityHidden(true) .onTapGesture { selectedPath = nil // iPhone: Einfügemarke durch Tap auf leeren Bereich löschen. @@ -291,6 +292,8 @@ struct DiagramCanvasView: View { canvasView(layout: layout, cw: cw, ch: ch) .allowsHitTesting(false) + // Gezeichnete Fläche; VoiceOver liest stattdessen die Blöcke darüber. + .accessibilityHidden(true) if let firstRoot = layout.elements.first { rootInsertBeforeFirstStrip( @@ -298,6 +301,7 @@ struct DiagramCanvasView: View { canvasWidth: cw, canvasHeight: ch ) + .accessibilityHidden(true) } ForEach(flat, id: \.pathKey) { node in @@ -408,6 +412,13 @@ struct DiagramCanvasView: View { .draggable(DiagramDragPayload(raw: ElementPalette.moveDragIdentifier(path: node.idPath))) { nodeDragPreview(for: node) } + // VoiceOver: ein Element pro Block (statt der unbeschrifteten Drop-Streifen darin). + .accessibilityElement(children: .ignore) + .accessibilityLabel(accessibilityLabel(for: node)) + .accessibilityAddTraits(selectedPath == node.idPath ? [.isButton, .isSelected] : .isButton) + .accessibilityAction { + selectedPath = node.idPath + } .accessibilityHint( isPlaceholderNode ? lang.tr("a11y_placeholder_drop") @@ -415,6 +426,16 @@ struct DiagramCanvasView: View { ) } + /// Vorgelesener Name eines Blocks: Elementart und Text, z. B. „Anweisung: int x = 5“. + private func accessibilityLabel(for node: VisuStructLayout.Node) -> String { + // Schlüssel wie in der Palette: element_anweisung, element_verzweigung, … + let kind = lang.tr("element_\(node.element.type)") + let text = node.element.textLines + .joined(separator: " ") + .trimmingCharacters(in: .whitespacesAndNewlines) + return text.isEmpty ? kind : "\(kind): \(text)" + } + private func copyElement(at path: [Int]) { guard let el = try? VisuStructDocumentEditing.element(at: path, in: document) else { return } elementClipboard = el