Skip to content

Commit

Permalink
Merge pull request #48 from WeTransfer/feature/action
Browse files Browse the repository at this point in the history
Add Support for Button
  • Loading branch information
Boris-Em authored Mar 17, 2020
2 parents 43fc7d9 + c2081cc commit 0477a58
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 34 deletions.
Binary file added Assets/button_notification.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 61 additions & 29 deletions Example/UINotifications-Example/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions Example/UINotifications-Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ final class ViewController: UIViewController {

@IBOutlet private weak var automaticallyDismissSwitch: UISwitch!
@IBOutlet private weak var addActionSwitch: UISwitch!
@IBOutlet private weak var addButtonSwitch: UISwitch!
@IBOutlet private weak var showsImageSwitch: UISwitch!
@IBOutlet private weak var successStyleSwitch: UISwitch!

Expand Down Expand Up @@ -110,6 +111,17 @@ final class ViewController: UIViewController {

let notification = UINotification(content: UINotificationContent(title: title, subtitle: subtitle, image: image), style: style, action: action)

if addButtonSwitch.isOn {
let button = UIButton(type: .system)
button.setTitle("Button", for: .normal)
button.addTarget(self, action: #selector(handleTapNotificationButton), for: .touchUpInside)
notification.button = button
}

UINotificationCenter.current.show(notification: notification, dismissTrigger: dismissTrigger)
}

@objc func handleTapNotificationButton() {
print("Tapped the button!")
}
}
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ manualDismissTrigger.trigger() // Dismiss
UINotificationCenter.current.notificationViewType = MyCustomNotificationView.self
```

### Use a custom UIButton
By setting the `button` property on `UINotification`, you can simply add a button to the notification.

```swift
notification.button = UIButton(type: .system)
```

![Button](Assets/button_notification.png?)

### Create a custom presenter
Create a custom presenter to manage presentation and dismiss animations.

Expand Down
13 changes: 12 additions & 1 deletion Sources/UINotification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ public protocol UINotificationStyle {

/// Handles changes in UINotification
protocol UINotificationDelegate: class {
// Called when Notification is updated
// Called when Notification is updated.
func didUpdateContent(in notificaiton: UINotification)

/// Called when the button is set.
func didUpdateButton(in notificaiton: UINotification)
}

/// An UINotification which can be showed on top of the `UINavigationBar` and `UIStatusBar`
Expand Down Expand Up @@ -68,6 +71,14 @@ public final class UINotification: Equatable {
/// The style of the notification which applies on the notification view.
public let style: UINotificationStyle

/// The button to display on the right side of the notification, if any.
/// Setting this property will add the button, even if the notification is already visible.
public var button: UIButton? {
didSet {
delegate?.didUpdateButton(in: self)
}
}

/// The action which will be triggered on tap.
public let action: UINotificationAction?

Expand Down
47 changes: 43 additions & 4 deletions Sources/UINotificationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ open class UINotificationView: UIView {
private let containerStackViewDefaultSpacing: CGFloat = 14

private lazy var containerStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [self.imageView, self.titlesStackView, self.chevronImageView])
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.spacing = self.containerStackViewDefaultSpacing
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.alignment = .center

return stackView
}()

Expand Down Expand Up @@ -71,6 +72,13 @@ open class UINotificationView: UIView {
return imageView
}()

var button: UIButton? {
let button = self.notification.button
button?.translatesAutoresizingMaskIntoConstraints = false

return button
}

// MARK: Gestures
internal fileprivate(set) lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in
let gesture = UIPanGestureRecognizer()
Expand Down Expand Up @@ -104,6 +112,7 @@ open class UINotificationView: UIView {

layoutMargins = UIEdgeInsets(top: 4, left: 0, bottom: 4, right: 0)

addArrangedSubviewsForContainerStackView()
addSubview(containerStackView)

setupConstraints()
Expand All @@ -124,9 +133,6 @@ open class UINotificationView: UIView {
imageView.image = notification.content.image
imageView.isHidden = notification.content.image == nil

let chevronImageWidth = chevronImageView.image?.size.width ?? 0
containerStackView.spacing = imageView.isHidden ? -chevronImageWidth : containerStackViewDefaultSpacing

backgroundColor = notification.style.backgroundColor

chevronImageView.tintColor = notification.style.titleTextColor
Expand All @@ -136,6 +142,15 @@ open class UINotificationView: UIView {
tapGestureRecognizer.isEnabled = notification.style.interactive
}

open func updateForButton() {
guard !subviews.isEmpty else { return }
subviews.forEach { subview in
subview.removeFromSuperview()
}

setupView()
}

/// Called when all constraints should be setup for the notification. Can be overwritten to set your own constraints.
/// When setting your own constraints, you should not be calling super.
open func setupConstraints() {
Expand All @@ -150,10 +165,28 @@ open class UINotificationView: UIView {
imageView.widthAnchor.constraint(equalToConstant: 31),
imageView.heightAnchor.constraint(equalToConstant: 31)
]

button?.setContentHuggingPriority(.defaultHigh, for: .horizontal)

NSLayoutConstraint.activate(constraints)
}

private func addArrangedSubviewsForContainerStackView() {
var arrangedSubviews = [self.imageView, self.titlesStackView, self.chevronImageView]

if let button = self.button {
arrangedSubviews.insert(button, at: arrangedSubviews.count - 1)
}

containerStackView.arrangedSubviews.forEach { (view) in
containerStackView.removeArrangedSubview(view)
}

arrangedSubviews.forEach { (view) in
containerStackView.addArrangedSubview(view)
}
}

@objc internal func handleTapGestureRecognizer() {
guard let presenter = presenter, presenter.state == UINotificationPresenterState.presented else { return }
notification.action?.execute()
Expand Down Expand Up @@ -184,9 +217,15 @@ open class UINotificationView: UIView {
}

extension UINotificationView: UINotificationDelegate {

func didUpdateContent(in notificaiton: UINotification) {
updateForNotificationData()
}

func didUpdateButton(in notificaiton: UINotification) {
updateForButton()
}

}

extension NSLayoutConstraint {
Expand Down
24 changes: 24 additions & 0 deletions UINotificationsTests/UINotificationDefaultViewTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,30 @@ final class UINotificationViewTests: UINotificationTestCase {
XCTAssert(notificationView.subtitleLabel.text == updatedContent.subtitle, "Subtitle of the notification view should update accordingly")
XCTAssert(notificationView.imageView.image == updatedContent.image, "Image of the notification view should update accordingly")
}

/// It should add the button as a subview when set.
func testButton() {
let notificationView = UINotificationView(notification: notification)

XCTAssertNil(notificationView.button)

notification.button = UIButton(type: .system)
XCTAssertNotNil(notificationView.button)
XCTAssertNotNil(notificationView.button?.superview)
}

/// It should add the button as a subview when set, even after the notification is shown.
func testButtonAfterShow() {
let notificationView = UINotificationView(notification: notification)

UINotificationCenter.current.show(notification: notification, dismissTrigger: nil)

XCTAssertNil(notificationView.button)
notification.button = UIButton(type: .system)
XCTAssertNotNil(notificationView.button)
XCTAssertNotNil(notificationView.button?.superview)
}

}

private struct LargeChevronStyle: UINotificationStyle {
Expand Down

0 comments on commit 0477a58

Please sign in to comment.