@capawesome/capacitor-screen-reader 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapawesomeCapacitorScreenReader.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +28 -0
- package/README.md +245 -0
- package/android/build.gradle +58 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/ScreenReader.java +93 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/ScreenReaderPlugin.java +122 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/classes/CustomException.java +20 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/classes/CustomExceptions.java +6 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/classes/events/StateChangeEvent.java +22 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/classes/options/AnnounceOptions.java +34 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/classes/results/IsEnabledResult.java +22 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/interfaces/Callback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/interfaces/EmptyCallback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/interfaces/NonEmptyResultCallback.java +7 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/screenreader/interfaces/Result.java +7 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +222 -0
- package/dist/esm/definitions.d.ts +92 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +11 -0
- package/dist/esm/web.js +42 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +56 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +59 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/Classes/Events/StateChangeEvent.swift +16 -0
- package/ios/Plugin/Classes/Options/AnnounceOptions.swift +15 -0
- package/ios/Plugin/Classes/Results/IsEnabledResult.swift +16 -0
- package/ios/Plugin/Enums/CustomError.swift +21 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/Protocols/Result.swift +5 -0
- package/ios/Plugin/ScreenReader.swift +71 -0
- package/ios/Plugin/ScreenReaderPlugin.swift +86 -0
- package/package.json +95 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
enum CustomError: Error {
|
|
4
|
+
case valueMissing
|
|
5
|
+
|
|
6
|
+
var code: String? {
|
|
7
|
+
switch self {
|
|
8
|
+
case .valueMissing:
|
|
9
|
+
return nil
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
extension CustomError: LocalizedError {
|
|
15
|
+
public var errorDescription: String? {
|
|
16
|
+
switch self {
|
|
17
|
+
case .valueMissing:
|
|
18
|
+
return NSLocalizedString("value must be provided.", comment: "valueMissing")
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
7
|
+
<key>CFBundleExecutable</key>
|
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
+
<key>CFBundleIdentifier</key>
|
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
12
|
+
<string>6.0</string>
|
|
13
|
+
<key>CFBundleName</key>
|
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>FMWK</string>
|
|
17
|
+
<key>CFBundleShortVersionString</key>
|
|
18
|
+
<string>1.0</string>
|
|
19
|
+
<key>CFBundleVersion</key>
|
|
20
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
21
|
+
<key>NSPrincipalClass</key>
|
|
22
|
+
<string></string>
|
|
23
|
+
</dict>
|
|
24
|
+
</plist>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
@objc public class ScreenReader: NSObject {
|
|
5
|
+
private let plugin: ScreenReaderPlugin
|
|
6
|
+
|
|
7
|
+
private var isObserving = false
|
|
8
|
+
|
|
9
|
+
private var lastEnabled = false
|
|
10
|
+
|
|
11
|
+
init(plugin: ScreenReaderPlugin) {
|
|
12
|
+
self.plugin = plugin
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
deinit {
|
|
16
|
+
NotificationCenter.default.removeObserver(self)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@objc public func announce(_ options: AnnounceOptions, completion: @escaping (Error?) -> Void) {
|
|
20
|
+
let value = options.value
|
|
21
|
+
DispatchQueue.main.async {
|
|
22
|
+
UIAccessibility.post(notification: .announcement, argument: value)
|
|
23
|
+
completion(nil)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@objc public func isEnabled(completion: @escaping (IsEnabledResult?, Error?) -> Void) {
|
|
28
|
+
DispatchQueue.main.async {
|
|
29
|
+
completion(IsEnabledResult(enabled: UIAccessibility.isVoiceOverRunning), nil)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func startObserving() {
|
|
34
|
+
DispatchQueue.main.async { [weak self] in
|
|
35
|
+
guard let self = self, !self.isObserving else {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
self.isObserving = true
|
|
39
|
+
self.lastEnabled = UIAccessibility.isVoiceOverRunning
|
|
40
|
+
NotificationCenter.default.addObserver(
|
|
41
|
+
self,
|
|
42
|
+
selector: #selector(self.handleVoiceOverStatusDidChange),
|
|
43
|
+
name: UIAccessibility.voiceOverStatusDidChangeNotification,
|
|
44
|
+
object: nil
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func stopObserving() {
|
|
50
|
+
DispatchQueue.main.async { [weak self] in
|
|
51
|
+
guard let self = self, self.isObserving else {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
self.isObserving = false
|
|
55
|
+
NotificationCenter.default.removeObserver(
|
|
56
|
+
self,
|
|
57
|
+
name: UIAccessibility.voiceOverStatusDidChangeNotification,
|
|
58
|
+
object: nil
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@objc private func handleVoiceOverStatusDidChange() {
|
|
64
|
+
let enabled = UIAccessibility.isVoiceOverRunning
|
|
65
|
+
guard enabled != lastEnabled else {
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
lastEnabled = enabled
|
|
69
|
+
plugin.notifyStateChangeListeners(StateChangeEvent(enabled: enabled))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@objc(ScreenReaderPlugin)
|
|
5
|
+
public class ScreenReaderPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
6
|
+
public let identifier = "ScreenReaderPlugin"
|
|
7
|
+
public let jsName = "ScreenReader"
|
|
8
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
9
|
+
CAPPluginMethod(name: "announce", returnType: CAPPluginReturnPromise),
|
|
10
|
+
CAPPluginMethod(name: "isEnabled", returnType: CAPPluginReturnPromise)
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
public static let eventStateChange = "stateChange"
|
|
14
|
+
|
|
15
|
+
public static let tag = "ScreenReaderPlugin"
|
|
16
|
+
|
|
17
|
+
private var implementation: ScreenReader?
|
|
18
|
+
|
|
19
|
+
override public func load() {
|
|
20
|
+
self.implementation = ScreenReader(plugin: self)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@objc override public func addListener(_ call: CAPPluginCall) {
|
|
24
|
+
super.addListener(call)
|
|
25
|
+
implementation?.startObserving()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@objc func announce(_ call: CAPPluginCall) {
|
|
29
|
+
do {
|
|
30
|
+
let options = try AnnounceOptions(call)
|
|
31
|
+
implementation?.announce(options) { error in
|
|
32
|
+
if let error = error {
|
|
33
|
+
self.rejectCall(call, error)
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
self.resolveCall(call)
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
rejectCall(call, error)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@objc func isEnabled(_ call: CAPPluginCall) {
|
|
44
|
+
implementation?.isEnabled { result, error in
|
|
45
|
+
if let error = error {
|
|
46
|
+
self.rejectCall(call, error)
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
self.resolveCall(call, result)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public func notifyStateChangeListeners(_ event: StateChangeEvent) {
|
|
54
|
+
self.notifyListeners(Self.eventStateChange, data: event.toJSObject() as? [String: Any])
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@objc override public func removeAllListeners(_ call: CAPPluginCall) {
|
|
58
|
+
super.removeAllListeners(call)
|
|
59
|
+
implementation?.stopObserving()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@objc override public func removeListener(_ call: CAPPluginCall) {
|
|
63
|
+
super.removeListener(call)
|
|
64
|
+
if !hasListeners(Self.eventStateChange) {
|
|
65
|
+
implementation?.stopObserving()
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private func rejectCall(_ call: CAPPluginCall, _ error: Error) {
|
|
70
|
+
CAPLog.print("[", ScreenReaderPlugin.tag, "] ", error)
|
|
71
|
+
let code = (error as? CustomError)?.code
|
|
72
|
+
call.reject(error.localizedDescription, code)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private func resolveCall(_ call: CAPPluginCall) {
|
|
76
|
+
call.resolve()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private func resolveCall(_ call: CAPPluginCall, _ result: Result?) {
|
|
80
|
+
if let result = result?.toJSObject() as? JSObject {
|
|
81
|
+
call.resolve(result)
|
|
82
|
+
} else {
|
|
83
|
+
call.resolve()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@capawesome/capacitor-screen-reader",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Capacitor plugin to interact with screen readers.",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Plugin/",
|
|
14
|
+
"CapawesomeCapacitorScreenReader.podspec",
|
|
15
|
+
"Package.swift"
|
|
16
|
+
],
|
|
17
|
+
"author": "Robin Genz <mail@robingenz.dev>",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/capawesome-team/capacitor-plugins.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/capawesome-team/capacitor-plugins/issues"
|
|
25
|
+
},
|
|
26
|
+
"funding": [
|
|
27
|
+
{
|
|
28
|
+
"type": "github",
|
|
29
|
+
"url": "https://github.com/sponsors/capawesome-team/"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "opencollective",
|
|
33
|
+
"url": "https://opencollective.com/capawesome"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"homepage": "https://capawesome.io/docs/sdks/capacitor/screen-reader/",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"capacitor",
|
|
39
|
+
"plugin",
|
|
40
|
+
"native",
|
|
41
|
+
"screen reader",
|
|
42
|
+
"accessibility",
|
|
43
|
+
"voiceover",
|
|
44
|
+
"talkback"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
48
|
+
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
|
|
49
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
50
|
+
"verify:web": "npm run build",
|
|
51
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
52
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
53
|
+
"eslint": "eslint . --ext ts",
|
|
54
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
|
55
|
+
"swiftlint": "node-swiftlint",
|
|
56
|
+
"docgen": "docgen --api ScreenReaderPlugin --output-readme README.md --output-json dist/docs.json",
|
|
57
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
58
|
+
"clean": "rimraf ./dist",
|
|
59
|
+
"watch": "tsc --watch",
|
|
60
|
+
"ios:pod:install": "cd ios && pod install --repo-update && cd ..",
|
|
61
|
+
"ios:spm:install": "cd ios && swift package resolve && cd ..",
|
|
62
|
+
"prepublishOnly": "npm run build"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@capacitor/android": "8.0.0",
|
|
66
|
+
"@capacitor/cli": "8.0.0",
|
|
67
|
+
"@capacitor/core": "8.0.0",
|
|
68
|
+
"@capacitor/docgen": "0.3.1",
|
|
69
|
+
"@capacitor/ios": "8.0.0",
|
|
70
|
+
"@ionic/eslint-config": "0.4.0",
|
|
71
|
+
"eslint": "8.57.0",
|
|
72
|
+
"prettier-plugin-java": "2.6.7",
|
|
73
|
+
"rimraf": "6.1.2",
|
|
74
|
+
"rollup": "4.53.3",
|
|
75
|
+
"swiftlint": "2.0.0",
|
|
76
|
+
"typescript": "5.9.3"
|
|
77
|
+
},
|
|
78
|
+
"peerDependencies": {
|
|
79
|
+
"@capacitor/core": ">=8.0.0"
|
|
80
|
+
},
|
|
81
|
+
"eslintConfig": {
|
|
82
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
83
|
+
},
|
|
84
|
+
"capacitor": {
|
|
85
|
+
"ios": {
|
|
86
|
+
"src": "ios"
|
|
87
|
+
},
|
|
88
|
+
"android": {
|
|
89
|
+
"src": "android"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"publishConfig": {
|
|
93
|
+
"access": "public"
|
|
94
|
+
}
|
|
95
|
+
}
|