Skip to content

Commit 12f65b5

Browse files
committed
Add AbstractAnyAccessibilityValue
1 parent 5e8382c commit 12f65b5

File tree

5 files changed

+230
-8
lines changed

5 files changed

+230
-8
lines changed

Sources/OpenSwiftUI/Accessibility/internal/AccessibilityBoundedNumber.swift

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,90 @@
99

1010
import Foundation
1111

12+
// MARK: - AbstractAnyAccessibilityValue
13+
14+
private protocol AbstractAnyAccessibilityValue: Codable {
15+
var localizedDescription: String? { get }
16+
var displayDescription: String? { get }
17+
var value: Any { get }
18+
var minValue: Any? { get }
19+
var maxValue: Any? { get }
20+
var step: Any? { get }
21+
var type: AnyAccessibilityValueType { get }
22+
func `as`<Value: AccessibilityValue>(_ type: Value.Type) -> Value?
23+
func isEqual(to value: AbstractAnyAccessibilityValue) -> Bool
24+
}
25+
26+
// MARK: - AnyAccessibilityValue
27+
28+
struct AnyAccessibilityValue/*: AbstractAnyAccessibilityValue*/ {
29+
private var base: AbstractAnyAccessibilityValue
30+
31+
init<Value: Codable & AccessibilityValue>(_ base: Value) {
32+
self.base = ConcreteBase(base: base)
33+
}
34+
}
35+
36+
extension AnyAccessibilityValue: Equatable {
37+
static func == (lhs: AnyAccessibilityValue, rhs: AnyAccessibilityValue) -> Bool {
38+
lhs.base.isEqual(to: rhs.base)
39+
}
40+
}
41+
42+
extension AnyAccessibilityValue: Codable {
43+
private enum Keys: CodingKey {
44+
case type
45+
case value
46+
}
47+
48+
init(from decoder: Decoder) throws {
49+
let container = try decoder.container(keyedBy: Keys.self)
50+
let type = try container.decode(AnyAccessibilityValueType.self, forKey: .type)
51+
switch type {
52+
case .int: base = try container.decode(ConcreteBase<Int>.self, forKey: .value)
53+
case .double: base = try container.decode(ConcreteBase<Double>.self, forKey: .value)
54+
case .bool: base = try container.decode(ConcreteBase<Bool>.self, forKey: .value)
55+
case .string: base = try container.decode(ConcreteBase<String>.self, forKey: .value)
56+
case .boundedNumber: base = try container.decode(ConcreteBase<AccessibilityBoundedNumber>.self, forKey: .value)
57+
case .number: base = try container.decode(ConcreteBase<AccessibilityNumber>.self, forKey: .value)
58+
}
59+
}
60+
61+
func encode(to encoder: Encoder) throws {
62+
var container = encoder.container(keyedBy: Keys.self)
63+
try container.encode(base.type, forKey: .type)
64+
try base.encode(to: container.superEncoder(forKey: .value))
65+
}
66+
}
67+
68+
// MARK: AnyAccessibilityValue.ConcreateBase
69+
70+
extension AnyAccessibilityValue {
71+
fileprivate struct ConcreteBase<Base> where Base: Codable, Base: AccessibilityValue {
72+
var base: Base
73+
}
74+
}
75+
76+
extension AnyAccessibilityValue.ConcreteBase: Codable {}
77+
extension AnyAccessibilityValue.ConcreteBase: Equatable {}
78+
extension AnyAccessibilityValue.ConcreteBase: AbstractAnyAccessibilityValue {
79+
var localizedDescription: String? { base.localizedDescription }
80+
var displayDescription: String? { base.displayDescription }
81+
var value: Any { base.value }
82+
var minValue: Any? { base.minValue }
83+
var maxValue: Any? { base.maxValue }
84+
var step: Any? { base.step }
85+
var type: AnyAccessibilityValueType { Base.type }
86+
func `as`<Value>(_ type: Value.Type) -> Value? where Value : AccessibilityValue {
87+
base as? Value
88+
}
89+
func isEqual(to value: AbstractAnyAccessibilityValue) -> Bool {
90+
base == (value as? Self)?.base
91+
}
92+
}
93+
94+
// MARK: - AccessibilityBoundedNumber
95+
1296
struct AccessibilityBoundedNumber {
1397
var number: AccessibilityNumber
1498
var lowerBound: AccessibilityNumber?
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//
2+
// AccessibilityNumber.swift
3+
// OpenSwiftUI
4+
//
5+
// Created by Kyle on 2023/12/3.
6+
// Lastest Version: iOS 15.5
7+
// Status: Complete
8+
9+
import Foundation
10+
11+
protocol AccessibilityNumeric {
12+
var isValidMinValue: Bool { get }
13+
var isValidMaxValue: Bool { get }
14+
func asNumber() -> AccessibilityNumber?
15+
}
16+
17+
extension AccessibilityNumeric where Self: FixedWidthInteger {
18+
var isValidMinValue: Bool {
19+
// TODO: Add Unit Test and check usage
20+
if Self.bitWidth == 8 || !Self.isSigned {
21+
true
22+
} else {
23+
self != .min
24+
}
25+
}
26+
27+
var isValidMaxValue: Bool { self != .max }
28+
}
29+
30+
extension Int: AccessibilityNumeric {
31+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
32+
}
33+
34+
extension Int8: AccessibilityNumeric {
35+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
36+
}
37+
38+
extension Int16: AccessibilityNumeric {
39+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
40+
}
41+
42+
extension Int32: AccessibilityNumeric {
43+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
44+
}
45+
46+
extension Int64: AccessibilityNumeric {
47+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
48+
}
49+
50+
extension UInt: AccessibilityNumeric {
51+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
52+
}
53+
54+
extension UInt8: AccessibilityNumeric {
55+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
56+
}
57+
58+
extension UInt16: AccessibilityNumeric {
59+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
60+
}
61+
62+
extension UInt32: AccessibilityNumeric {
63+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
64+
}
65+
66+
extension UInt64: AccessibilityNumeric {
67+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
68+
}
69+
70+
extension AccessibilityNumeric where Self: BinaryFloatingPoint {
71+
var isValidMinValue: Bool {
72+
isFinite && self > -Self.greatestFiniteMagnitude
73+
}
74+
75+
var isValidMaxValue: Bool {
76+
isFinite && self < Self.greatestFiniteMagnitude
77+
}
78+
}
79+
80+
extension Float: AccessibilityNumeric {
81+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
82+
}
83+
84+
extension Double: AccessibilityNumeric {
85+
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
86+
}

Sources/OpenSwiftUI/Accessibility/internal/AccessibilityValue.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,36 @@ protocol AccessibilityValue: Equatable {
2020
}
2121

2222
extension AccessibilityValue {
23-
var step: NSNumber? { nil }
23+
var minValue: PlatformValue? { nil }
24+
var maxValue: PlatformValue? { nil }
25+
var step: PlatformValue? { nil }
26+
}
27+
28+
extension AccessibilityValue where PlatformValue: CustomStringConvertible {
29+
var localizedDescription: String? { value.description }
30+
var displayDescription: String? { value.description }
31+
}
32+
33+
extension AccessibilityValue where Self == Self.PlatformValue {
34+
var value: PlatformValue { self }
35+
}
36+
37+
extension Int: AccessibilityValue {
38+
typealias PlatformValue = Int
39+
static var type: AnyAccessibilityValueType { .int }
40+
}
41+
42+
extension Double: AccessibilityValue {
43+
typealias PlatformValue = Double
44+
static var type: AnyAccessibilityValueType { .number }
45+
}
46+
47+
extension Bool: AccessibilityValue {
48+
typealias PlatformValue = Bool
49+
static var type: AnyAccessibilityValueType { .bool }
50+
}
51+
52+
extension String: AccessibilityValue {
53+
typealias PlatformValue = String
54+
static var type: AnyAccessibilityValueType { .string }
2455
}

Sources/OpenSwiftUI/Accessibility/internal/AnyAccessibilityValueType.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
// Lastest Version: iOS 15.5
77
// Status: Complete
88

9-
enum AnyAccessibilityValueType: UInt {
9+
enum AnyAccessibilityValueType: UInt, Codable {
1010
case int
1111
case double
1212
case bool
1313
case string
14-
case disclosure
15-
case toggle
16-
case slider
17-
case stepper
18-
case progress
14+
// case disclosure
15+
// case toggle
16+
// case slider
17+
// case stepper
18+
// case progress
1919
case boundedNumber
20-
case headingLevel
20+
// case headingLevel
2121
case number
2222
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
extension Comparable {
2+
func clamped(to range: ClosedRange<Self>) -> Self {
3+
var value = self
4+
value.clamp(to: range)
5+
return value
6+
}
7+
8+
mutating func clamp(to range: ClosedRange<Self>) {
9+
self = OpenSwiftUI.clamp(self, min: range.lowerBound, max: range.upperBound)
10+
}
11+
}
12+
13+
func clamp<Value: Comparable>(_ value: Value, min minValue: Value, max maxValue: Value) -> Value {
14+
if value < minValue {
15+
minValue
16+
} else if value > maxValue {
17+
maxValue
18+
} else {
19+
value
20+
}
21+
}

0 commit comments

Comments
 (0)