Skip to content

Add SliderStyle support #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ let openSwiftUITarget = Target.target(
],
swiftSettings: [
.enableExperimentalFeature("AccessLevelOnImport"),
.define("OPENSWIFTUI_SUPPRESS_DEPRECATED_WARNINGS")
],
linkerSettings: [
.unsafeFlags(
Expand All @@ -36,13 +37,15 @@ let openSwiftUITestTarget = Target.testTarget(
name: "OpenSwiftUITests",
dependencies: [
"OpenSwiftUI",
]
],
exclude: ["README.md"]
)
let openSwiftUICompatibilityTestTarget = Target.testTarget(
name: "OpenSwiftUICompatibilityTests",
dependencies: [
"OpenSwiftUI",
]
],
exclude: ["README.md"]
)

let package = Package(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@
// Status: WIP
// ID: 0D3243EDC3DD4D641848661DCC354D4B

struct AccessibilityButtonShapeModifier<V: View>: AccessibilityConfigurationModifier {
typealias Configuration = Never
typealias Content = V

// deleted method
var configuration: Never { fatalError() }

func body(content: V) -> some View {
struct AccessibilityButtonShapeModifier<Content: View>: AccessibilityConfigurationModifier {
func body(content: Content) -> some View {
content.modifier(Child())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
// Status: Complete

protocol AccessibilityConfigurationModifier {
associatedtype Configuration
associatedtype Configuration = Never
associatedtype Body
associatedtype Content

var configuration: Configuration { get }
func body(content: Self.Content) -> Self.Body
}

extension AccessibilityConfigurationModifier where Configuration == Never {
var configuration: Configuration { fatalError() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
struct AccessibilityLabelModifier<Content: View>: AccessibilityConfigurationModifier {
func body(content: Content) -> some View {
content.modifier(ChildModifier())
}

private struct ChildModifier: PrimitiveViewModifier {}
}

extension View {
func accessibilityLabel() -> some View {
AccessibilityLabelModifier().body(content: self)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// AccessibilityBoundedNumber.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/12/2.
// Lastest Version: iOS 15.5
// Status: Complete

import Foundation

struct AccessibilityBoundedNumber {
var number: AccessibilityNumber
var lowerBound: AccessibilityNumber?
var upperBound: AccessibilityNumber?
var stride: AccessibilityNumber?

init?<S: Strideable>(for value: S, in range: ClosedRange<S>?, by strideValue: S.Stride?) {
let clampedValue = range.map { value.clamped(to: $0) }
let newValue = clampedValue ?? value
guard let numericValue = newValue as? AccessibilityNumeric,
let numberValue = numericValue.asNumber() else {
return nil
}
number = numberValue
if let range {
lowerBound = range.minimumValue?.asNumber()
upperBound = range.maximumValue?.asNumber()
}
if let strideValue,
let numericStride = strideValue as? AccessibilityNumeric {
stride = numericStride.asNumber()
}
}
}

extension AccessibilityBoundedNumber: AccessibilityValue {
// This kind of description logic is very strange
// But that's how Apple's implementation even on iOS 17 :)
// eg.
// For 1.5 and [1.0, 2.0], the accessiblity output would be 150%
// For 1.5 and [1.3, 2.3], the accessiblity output would be 1.5
var localizedDescription: String? {
let range: Double = if let lowerBound, let upperBound {
upperBound.base.doubleValue - lowerBound.base.doubleValue
} else {
.zero
}
if abs(range - 100) >= .ulpOfOne {
let style: NumberFormatter.Style = (abs(range - 1.0) < .ulpOfOne) ? .percent : .decimal
return NumberFormatter.localizedString(from: number.base, number: style)
} else {
return NumberFormatter.localizedString(from: NSNumber(value: number.base.doubleValue / 100), number: .percent)
}
}

var displayDescription: String? {
localizedDescription
}

var value: NSNumber { number.value }
var minValue: NSNumber? { lowerBound?.value }
var maxValue: NSNumber? { upperBound?.value }
static var type: AnyAccessibilityValueType { .boundedNumber }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// AccessibilityNumber.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/12/2.
// Lastest Version: iOS 15.5
// Status: Complete

import Foundation

struct AccessibilityNumber {
var base: NSNumber
}

extension AccessibilityNumber: AccessibilityValue {
var localizedDescription: String? {
NumberFormatter.localizedString(from: value, number: .decimal)
}
var displayDescription: String? { localizedDescription }
var value: NSNumber { base }
var minValue: NSNumber? { nil }
var maxValue: NSNumber? { nil }
static var type: AnyAccessibilityValueType { .number }
}

extension AccessibilityNumber: ExpressibleByFloatLiteral {
init(floatLiteral value: Double) {
base = NSNumber(floatLiteral: value)
}
}

extension AccessibilityNumber: ExpressibleByIntegerLiteral {
init(integerLiteral value: Int) {
base = NSNumber(integerLiteral: value)
}
}

extension AccessibilityNumber: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let data = try container.decode(Data.self)
self.base = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSNumber.self, from: data)!
}

func encode(to encoder: Encoder) throws {
let data = try NSKeyedArchiver.archivedData(withRootObject: base, requiringSecureCoding: true)
var container = encoder.singleValueContainer()
try container.encode(data)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// AccessibilityNumber.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/12/3.
// Lastest Version: iOS 15.5
// Status: Complete

import Foundation

protocol AccessibilityNumeric {
var isValidMinValue: Bool { get }
var isValidMaxValue: Bool { get }
func asNumber() -> AccessibilityNumber?
}

extension AccessibilityNumeric where Self: FixedWidthInteger {
var isValidMinValue: Bool {
// TODO: Add Unit Test and check usage
if Self.bitWidth == 8 || !Self.isSigned {
true
} else {
self != .min
}
}

var isValidMaxValue: Bool { self != .max }
}

extension Int: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension Int8: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension Int16: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension Int32: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension Int64: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension UInt: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension UInt8: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension UInt16: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension UInt32: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension UInt64: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension AccessibilityNumeric where Self: BinaryFloatingPoint {
var isValidMinValue: Bool {
isFinite && self > -Self.greatestFiniteMagnitude
}

var isValidMaxValue: Bool {
isFinite && self < Self.greatestFiniteMagnitude
}
}

extension Float: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}

extension Double: AccessibilityNumeric {
func asNumber() -> AccessibilityNumber? { AccessibilityNumber(base: .init(value: self)) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// AccessibilityPlatformSafe.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/12/2.
// Lastest Version: iOS 15.5
// Status: Complete

import Foundation

protocol AccessibilityPlatformSafe {}

extension String: AccessibilityPlatformSafe {}
extension Double: AccessibilityPlatformSafe {}
extension Int: AccessibilityPlatformSafe {}
extension UInt: AccessibilityPlatformSafe {}
extension UInt8: AccessibilityPlatformSafe {}
extension Bool: AccessibilityPlatformSafe {}
extension NSNumber: AccessibilityPlatformSafe {}
extension Optional: AccessibilityPlatformSafe where Wrapped: AccessibilityPlatformSafe {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// AccessibilitySliderValue.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/12/16.
// Lastest Version: iOS 15.5
// Status: Complete

struct AccessibilitySliderValue: AccessibilityValueByProxy {
var base: AccessibilityBoundedNumber
static var type: AnyAccessibilityValueType { .slider }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// AccessibilityValue.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/12/2.
// Lastest Version: iOS 15.5
// Status: Complete

import Foundation

protocol AccessibilityValue: Equatable {
associatedtype PlatformValue: AccessibilityPlatformSafe
var localizedDescription: String? { get }
var displayDescription: String? { get }
var value: PlatformValue { get }
var minValue: PlatformValue? { get }
var maxValue: PlatformValue? { get }
var step: PlatformValue? { get }
static var type: AnyAccessibilityValueType { get }
}

extension AccessibilityValue {
var minValue: PlatformValue? { nil }
var maxValue: PlatformValue? { nil }
var step: PlatformValue? { nil }
}

extension AccessibilityValue where PlatformValue: CustomStringConvertible {
var localizedDescription: String? { value.description }
var displayDescription: String? { value.description }
}

extension AccessibilityValue where Self == Self.PlatformValue {
var value: PlatformValue { self }
}

extension Int: AccessibilityValue {
typealias PlatformValue = Int
static var type: AnyAccessibilityValueType { .int }
}

extension Double: AccessibilityValue {
typealias PlatformValue = Double
static var type: AnyAccessibilityValueType { .number }
}

extension Bool: AccessibilityValue {
typealias PlatformValue = Bool
static var type: AnyAccessibilityValueType { .bool }
}

extension String: AccessibilityValue {
typealias PlatformValue = String
static var type: AnyAccessibilityValueType { .string }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// AccessibilityValueByProxy.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/12/16.
// Lastest Version: iOS 15.5
// Status: Complete

protocol AccessibilityValueByProxy: AccessibilityValue {
associatedtype Base: AccessibilityValue
var base: Base { get }
}

extension AccessibilityValueByProxy {
var localizedDescription: String? { base.localizedDescription }
var displayDescription: String? { base.displayDescription }
var value: Base.PlatformValue { base.value }
var minValue: Base.PlatformValue? { base.minValue }
var maxValue: Base.PlatformValue? { base.maxValue }
var step: Base.PlatformValue? { base.step }
}
Loading