Skip to content

Commit

Permalink
feat: accessibility improvements (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
omaralbeik authored May 14, 2021
1 parent 1df4409 commit fb3d029
Show file tree
Hide file tree
Showing 16 changed files with 490 additions and 44 deletions.
2 changes: 1 addition & 1 deletion Drops.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Drops'
s.version = '1.1.0'
s.version = '1.2.0'
s.summary = 'A µFramework for showing iOS 13 like system alerts'
s.description = <<-DESC
A µFramework for showing alerts like the one used when copying from pasteboard or connecting Apple pencil.
Expand Down
4 changes: 2 additions & 2 deletions Drops.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 1.1.0;
MARKETING_VERSION = 1.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.omaralbeik.drops;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
Expand Down Expand Up @@ -803,7 +803,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 1.1.0;
MARKETING_VERSION = 1.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.omaralbeik.drops;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
Expand Down
48 changes: 46 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,60 @@ A µFramework for showing alerts like the one used when copying from pasteboard

1. Create a drop:

```swift
let drop: Drop = "Title Only"
```

```swift
let drop = Drop(title: "Title Only")
```

```swift
let drop = Drop(title: "Title", subtitle: "Subtitle")
```

```swift
let drop = Drop(title: "Title", subtitle: "Subtitle", duration: 5.0)
```

```swift
let drop = Drop(
title: "Title",
subtitle: "Subtitle",
icon: UIImage(systemName: "star.fill"),
action: .init {
print("Drop tapped")
Drops.hideCurrent()
},
position: .bottom,
duration: 5.0,
accessibility: "Alert: Title, Subtitle"
)
```

2. Show it:

```swift
Drops.show("Title")
```

```swift
Drops.show(drop)
```

```swift
import UIKit
import Drops

class ViewController: UIViewController {
let drops = Drops(delayBetweenDrops: 1.0)

func showDrop() {
drops.show(drop)
}
}
```

Read the [docs](https://omaralbeik.github.io/Drops) for more usage options.

---
Expand All @@ -60,7 +104,7 @@ The [Swift Package Manager](https://swift.org/package-manager/) is a tool for ma

```swift
dependencies: [
.package(url: "https://github.com/omaralbeik/Drops.git", from: "1.1.0")
.package(url: "https://github.com/omaralbeik/Drops.git", from: "1.2.0")
]
```

Expand All @@ -75,7 +119,7 @@ $ swift build
To integrate Drops into your Xcode project using [CocoaPods](https://cocoapods.org), specify it in your Podfile:

```rb
pod 'Drops', :git => 'https://github.com/omaralbeik/Drops.git', :tag => '1.1.0'
pod 'Drops', :git => 'https://github.com/omaralbeik/Drops.git', :tag => '1.2.0'
```

### Carthage
Expand Down
48 changes: 45 additions & 3 deletions Sources/Drop.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import UIKit

/// An object representing a drop.
public struct Drop {
public struct Drop: ExpressibleByStringLiteral {
/// Create a new drop.
/// - Parameters:
/// - title: Title.
Expand All @@ -33,13 +33,15 @@ public struct Drop {
/// - action: Optional action.
/// - position: Position. Defaults to `Drop.Position.top`.
/// - duration: Duration. Defaults to `Drop.Duration.recommended`.
/// - accessibility: Accessibility options. Defaults to `nil` which will use "title, subtitle" as its message.
public init(
title: String,
subtitle: String? = nil,
icon: UIImage? = nil,
action: Action? = nil,
position: Position = .top,
duration: Duration = .recommended
duration: Duration = .recommended,
accessibility: Accessibility? = nil
) {
self.title = title.trimmingCharacters(in: .whitespacesAndNewlines)
if let subtitle = subtitle?.trimmingCharacters(in: .whitespacesAndNewlines), !subtitle.isEmpty {
Expand All @@ -49,6 +51,17 @@ public struct Drop {
self.action = action
self.position = position
self.duration = duration
self.accessibility = accessibility
?? .init(message: [title, subtitle].compactMap({ $0 }).joined(separator: ", "))
}

/// Create a new accessibility object.
/// - Parameter message: Message to be announced when the drop is shown. Defaults to drop's "title, subtitle"
public init(stringLiteral title: String) {
self.title = title
self.position = .top
self.duration = .recommended
self.accessibility = .init(message: title)
}

/// Title.
Expand All @@ -68,6 +81,9 @@ public struct Drop {

/// Duration.
public var duration: Duration

/// Accessibility.
public var accessibility: Accessibility
}

extension Drop {
Expand All @@ -82,12 +98,18 @@ extension Drop {

extension Drop {
/// An enum representing a drop duration on screen.
public enum Duration: Equatable {
public enum Duration: Equatable, ExpressibleByFloatLiteral {
/// Hides the drop after 2.0 seconds.
case recommended
/// Hides the drop after the specified number of seconds.
case seconds(TimeInterval)

/// Create a new duration object.
/// - Parameter value: Duration in seconds
public init(floatLiteral value: TimeInterval) {
self = .seconds(value)
}

internal var value: TimeInterval {
switch self {
case .recommended:
Expand Down Expand Up @@ -118,3 +140,23 @@ extension Drop {
public var handler: () -> Void
}
}

extension Drop {
/// An object representing accessibility options.
public struct Accessibility: ExpressibleByStringLiteral {
/// Create a new accessibility object.
/// - Parameter message: Message to be announced when the drop is shown. Defaults to drop's "title, subtitle"
public init(message: String) {
self.message = message
}

/// Create a new accessibility object.
/// - Parameter message: Message to be announced when the drop is shown. Defaults to drop's "title, subtitle"
public init(stringLiteral message: String) {
self.message = message
}

/// Accessibility message to be announced when the drop is shown.
public let message: String
}
}
8 changes: 4 additions & 4 deletions Sources/DropView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ internal final class DropView: UIView {
label.numberOfLines = 1
label.textAlignment = .center
if #available(iOS 13.0, *) {
label.textColor = .secondaryLabel
label.textColor = UIAccessibility.isDarkerSystemColorsEnabled ? .label : .secondaryLabel
} else {
label.textColor = .darkGray
label.textColor = UIAccessibility.isDarkerSystemColorsEnabled ? .black : .darkGray
}
label.font = UIFont.preferredFont(forTextStyle: .subheadline)
label.adjustsFontForContentSizeCategory = true
Expand All @@ -172,9 +172,9 @@ internal final class DropView: UIView {
view.contentMode = .scaleAspectFit
view.clipsToBounds = true
if #available(iOS 13.0, *) {
view.tintColor = .secondaryLabel
view.tintColor = UIAccessibility.isDarkerSystemColorsEnabled ? .label : .secondaryLabel
} else {
view.tintColor = .darkGray
view.tintColor = UIAccessibility.isDarkerSystemColorsEnabled ? .black : .darkGray
}
return view
}()
Expand Down
8 changes: 4 additions & 4 deletions Sources/Presenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ final class Presenter: NSObject {
}

func announcementAccessibilityMessage(for drop: Drop) {
let message = [drop.title, drop.subtitle]
.compactMap { $0 }
.joined(separator: "\n")
UIAccessibility.post(notification: UIAccessibility.Notification.announcement, argument: message)
UIAccessibility.post(
notification: UIAccessibility.Notification.announcement,
argument: drop.accessibility.message
)
}
}
8 changes: 5 additions & 3 deletions SwiftUIExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct ContentView: View {
@State var title: String = "Hello There!"
@State var subtitle: String = "Use Drops to show alerts"
@State var positionIndex: Int = 0
@State var duration: Float = 2.0
@State var duration: TimeInterval = 2.0
@State var hasIcon: Bool = false
@State var hasActionIcon: Bool = false

Expand Down Expand Up @@ -75,7 +75,10 @@ struct ContentView: View {
Button(action: {
showDrop()
}, label: {
Text("Show Drop").foregroundColor(.white).padding(10)
Text("Show Drop")
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding(10)
})
.frame(maxWidth: .infinity)
.background(Color.blue)
Expand All @@ -96,7 +99,6 @@ struct ContentView: View {
let title = title.trimmingCharacters(in: .whitespacesAndNewlines)
let subtitle = subtitle.trimmingCharacters(in: .whitespacesAndNewlines)
let position: Drop.Position = positionIndex == 0 ? .top : .bottom
let duration = Double(duration)

let icon = hasIcon ? UIImage(systemName: "star.fill") : nil
let buttonIcon = hasActionIcon ? UIImage(systemName: "arrowshape.turn.up.left") : nil
Expand Down
15 changes: 15 additions & 0 deletions Tests/DropTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ final class DropTests: XCTestCase {
XCTAssertNil(drop.action)
XCTAssertEqual(drop.position, .top)
XCTAssertEqual(drop.duration, .recommended)
XCTAssertEqual(drop.accessibility.message, "Hello world")
}

func testExpressiblesInitializer() {
let drop1: Drop = "Hello world"
XCTAssertEqual(drop1.title, "Hello world")
XCTAssertEqual(drop1.position, .top)
XCTAssertEqual(drop1.duration, .recommended)
XCTAssertEqual(drop1.accessibility.message, "Hello world")

let drop2 = Drop(title: "Hello world", duration: 5.0, accessibility: "Alert: Hello world")
XCTAssertEqual(drop2.title, "Hello world")
XCTAssertEqual(drop2.duration.value, 5.0)
XCTAssertEqual(drop2.accessibility.message, "Alert: Hello world")
}

@available(iOS 13.0, *)
Expand All @@ -54,6 +68,7 @@ final class DropTests: XCTestCase {
XCTAssertEqual(drop.action?.icon, dismissIcon)
XCTAssertEqual(drop.position, .bottom)
XCTAssertEqual(drop.duration, .seconds(1))
XCTAssertEqual(drop.accessibility.message, "Hello world, I'm a drop!")
}

func testDurationValue() {
Expand Down
2 changes: 1 addition & 1 deletion UIKitExample/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ final class ViewController: UIViewController {
let title = titleTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
let subtitle = subtitleTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines)
let position: Drop.Position = positionSegmentedControl.selectedSegmentIndex == 0 ? .top : .bottom
let duration = Double(durationSlider.value)
let duration = TimeInterval(durationSlider.value)

let icon = iconSwitch.isOn ? UIImage(systemName: "star.fill") : nil
let buttonIcon = buttonSwitch.isOn ? UIImage(systemName: "arrowshape.turn.up.left") : nil
Expand Down
Loading

0 comments on commit fb3d029

Please sign in to comment.