Skip to content

Commit

Permalink
Added a Custom Voice Over Rotor
Browse files Browse the repository at this point in the history
below committed Jul 29, 2022
1 parent 1ac3525 commit 65c2225
Showing 3 changed files with 77 additions and 3 deletions.
8 changes: 6 additions & 2 deletions GeofenceTester.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@
CBE71233286C7E00008F51C4 /* AppCenterCrashes in Frameworks */ = {isa = PBXBuildFile; productRef = CBE71232286C7E00008F51C4 /* AppCenterCrashes */; };
CBE71235286C7E00008F51C4 /* AppCenterDistribute in Frameworks */ = {isa = PBXBuildFile; productRef = CBE71234286C7E00008F51C4 /* AppCenterDistribute */; };
CBE71237286C7E7A008F51C4 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBE71236286C7E7A008F51C4 /* Keys.swift */; };
CBF30A55287823A700A0D173 /* RegionsListVC+CustomRotor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF30A54287823A700A0D173 /* RegionsListVC+CustomRotor.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
@@ -49,6 +50,7 @@
CBE711F0286915A8008F51C4 /* EventRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventRecord.swift; sourceTree = "<group>"; };
CBE711F2286920FD008F51C4 /* EventsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventsTableViewController.swift; sourceTree = "<group>"; };
CBE71236286C7E7A008F51C4 /* Keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keys.swift; sourceTree = "<group>"; };
CBF30A54287823A700A0D173 /* RegionsListVC+CustomRotor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RegionsListVC+CustomRotor.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
@@ -90,6 +92,7 @@
CB50E6082872480A00A98D8C /* Protocols.swift */,
CB655F7D2856A43B00EBCABA /* RegionsListViewController.swift */,
CB97AE3E286DC6410067B1BF /* RegionsListVC+CoreLocationsDelegate.swift */,
CBF30A54287823A700A0D173 /* RegionsListVC+CustomRotor.swift */,
CBE711EE2868EE36008F51C4 /* RegionDetailViewController.swift */,
CBE711F2286920FD008F51C4 /* EventsTableViewController.swift */,
CB0BAA5D287301BF0029E523 /* SettingsViewController.swift */,
@@ -197,6 +200,7 @@
CB655F6828534E2600EBCABA /* SceneDelegate.swift in Sources */,
CB655F7E2856A43B00EBCABA /* RegionsListViewController.swift in Sources */,
CBE711F3286920FD008F51C4 /* EventsTableViewController.swift in Sources */,
CBF30A55287823A700A0D173 /* RegionsListVC+CustomRotor.swift in Sources */,
CB268BA0285A19DC00B16C3A /* PersistantStorage.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -379,7 +383,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.1.1;
MARKETING_VERSION = 1.1.2;
PRODUCT_BUNDLE_IDENTIFIER = com.telekom.below.GeofenceTester;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -410,7 +414,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.1.1;
MARKETING_VERSION = 1.1.2;
PRODUCT_BUNDLE_IDENTIFIER = com.telekom.below.GeofenceTester;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
70 changes: 70 additions & 0 deletions GeofenceTester/RegionsListVC+CustomRotor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// RegionsListVC+CustomRotor.swift
// GeofenceTester
//
// Created by Alexander von Below on 08.07.22.
//

import UIKit
import MapKit

extension RegionsListViewController {
func setupCustomRotor () {
// https://stackoverflow.com/questions/42170870/create-a-custom-voiceover-rotor-to-navigate-mkannotationviews

let markerRotor = UIAccessibilityCustomRotor(name: NSLocalizedString("Markers",
comment: "Rotor Title"))
{ predicate in
let forward = (predicate.searchDirection == .next)

// which element is currently highlighted
if (predicate.currentItem.targetElement == nil) {
self.logger.info("Current Item Target Element is nil")
}
let currentAnnotationView = predicate.currentItem.targetElement as? MKAnnotationView
if (currentAnnotationView == nil) {
self.logger.error("Target Element is \(predicate.currentItem.targetElement.debugDescription)")
}
let currentAnnotation = (currentAnnotationView?.annotation as? MKAnnotation)

// easy reference to all possible annotations
let allAnnotations = self.mapView.annotations

// we'll start our index either 1 less or 1 more, so we enter at either 0 or last element
var currentIndex = forward ? -1 : allAnnotations.count

// set our index to currentAnnotation's index if we can find it in allAnnotations
if let currentAnnotation = currentAnnotation {
if let index = allAnnotations.firstIndex(where: { (annotation) -> Bool in
return (annotation.coordinate.latitude == currentAnnotation.coordinate.latitude) &&
(annotation.coordinate.longitude == currentAnnotation.coordinate.longitude)
}) {
currentIndex = index
}
}

// now that we have our currentIndex, here's a helper to give us the next element
// the user is requesting
let nextIndex = {(index:Int) -> Int in forward ? index + 1 : index - 1}

currentIndex = nextIndex(currentIndex)

while currentIndex >= 0 && currentIndex < allAnnotations.count {
let requestedAnnotation = allAnnotations[currentIndex]

// i can't stress how important it is to have animated set to false. save yourself the 10 hours i burnt, and just go with it. if you set it to true, the map starts moving to the annotation, but there's no guarantee the annotation has an associated view yet, because it could still be animating. in which case the line below this one will be nil, and you'll have a whole bunch of annotations that can't be navigated to
self.mapView.setCenter(requestedAnnotation.coordinate, animated: false)
if let annotationView = self.mapView.view(for: requestedAnnotation) {
let title: String = (requestedAnnotation.title ?? "Unknown") ?? "Unknown"
self.logger.info("We want to be returning \(title) Index \(currentIndex)")
return UIAccessibilityCustomRotorItemResult(targetElement: annotationView, targetRange: nil)
}

currentIndex = nextIndex(currentIndex)
}
self.logger.info("We have nothing")
return nil
}
self.mapView.accessibilityCustomRotors = [markerRotor]
}
}
2 changes: 1 addition & 1 deletion GeofenceTester/RegionsListViewController.swift
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ class RegionsListViewController: UIViewController {

var locationManager: CLLocationManager = CLLocationManager()
var storage = PersistantStorage<EventRecord>()
private var logger = os.Logger()
internal var logger = os.Logger()

@IBOutlet var mapView: MKMapView!
@IBOutlet var addButton: UIBarButtonItem!

0 comments on commit 65c2225

Please sign in to comment.