Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue-13] Add option to disable dismiss UI. #14

Merged
merged 4 commits into from
Mar 22, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 27 additions & 0 deletions Sources/YBottomSheet/BottomSheetController+Animation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// BottomSheetController+Animation.swift
// YBottomSheet
//
// Created by Dev Karan on 22/03/23.
// Copyright 漏 2023 Y Media Labs. All rights reserved.
//

import UIKit

extension BottomSheetController: UIViewControllerTransitioningDelegate {
/// Returns the animator for presenting a bottom sheet
public func animationController(
forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
BottomSheetPresentAnimator(sheetViewController: self)
}

/// Returns the animator for dismissing a bottom sheet
public func animationController(
forDismissed dismissed: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
BottomSheetDismissAnimator(sheetViewController: self)
}
}
9 changes: 8 additions & 1 deletion Sources/YBottomSheet/BottomSheetController+Appearance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ extension BottomSheetController {
///
/// Only applicable for resizable sheets. `nil` means to use the content view's intrinsic height as the minimum.
public var minimumContentHeight: CGFloat?
/// Whether the sheet can be dismissed by swiping down or tapping on the dimmer. Default is `true`.
///
/// The user can always dismiss the sheet from the close button if it is visible.
public var isDismissAllowed: Bool

/// Default appearance (fixed size sheet)
public static let `default` = Appearance()
Expand All @@ -49,6 +53,7 @@ extension BottomSheetController {
/// - presentAnimationCurve: Animaiton during presenting.
/// - dismissAnimationCurve: Animation during dismiss.
/// - minimumContentHeight: Optional) Minimum content view height.
/// - isDismissAllowed: Whether the sheet can be dismissed by swiping down or tapping on the dimmer.
public init(
indicatorAppearance: DragIndicatorView.Appearance? = nil,
headerAppearance: SheetHeaderView.Appearance? = .default,
Expand All @@ -58,7 +63,8 @@ extension BottomSheetController {
animationDuration: TimeInterval = 0.3,
presentAnimationCurve: UIView.AnimationOptions = .curveEaseIn,
dismissAnimationCurve: UIView.AnimationOptions = .curveEaseOut,
minimumContentHeight: CGFloat? = nil
minimumContentHeight: CGFloat? = nil,
isDismissAllowed: Bool = true
) {
self.indicatorAppearance = indicatorAppearance
self.headerAppearance = headerAppearance
Expand All @@ -69,6 +75,7 @@ extension BottomSheetController {
self.presentAnimationCurve = presentAnimationCurve
self.dismissAnimationCurve = dismissAnimationCurve
self.minimumContentHeight = minimumContentHeight
self.isDismissAllowed = isDismissAllowed
}
}
}
34 changes: 13 additions & 21 deletions Sources/YBottomSheet/BottomSheetController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ public class BottomSheetController: UIViewController {
didDismiss()
return true
}

/// Dismisses the bottom sheet if allowed.
///
/// This method is not called when the header's close button is tapped.
func didDismiss() {
if appearance.isDismissAllowed {
onDismiss()
}
}
}

private extension BottomSheetController {
Expand Down Expand Up @@ -308,7 +317,8 @@ private extension BottomSheetController {

extension BottomSheetController: SheetHeaderViewDelegate {
@objc
func didDismiss() {
func didTapCloseButton() {
// Directly dismiss the sheet without considering `isDismissAllowed`.
onDismiss()
}
}
Expand Down Expand Up @@ -352,24 +362,6 @@ private extension BottomSheetController {
}
}

extension BottomSheetController: UIViewControllerTransitioningDelegate {
/// Returns the animator for presenting a bottom sheet
public func animationController(
forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
BottomSheetPresentAnimator(sheetViewController: self)
}

/// Returns the animator for dismissing a bottom sheet
public func animationController(
forDismissed dismissed: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
BottomSheetDismissAnimator(sheetViewController: self)
}
}

// Methods for unit testing
internal extension BottomSheetController {
@objc
Expand All @@ -391,7 +383,7 @@ internal extension BottomSheetController {
}

@objc
func simulateDismiss() {
didDismiss()
func simulateTapCloseButton() {
didTapCloseButton()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
import Foundation

internal protocol SheetHeaderViewDelegate: AnyObject {
func didDismiss()
func didTapCloseButton()
}
2 changes: 1 addition & 1 deletion Sources/YBottomSheet/SheetHeaderView/SheetHeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ open class SheetHeaderView: UIView {
required public init?(coder: NSCoder) { nil }

@objc private func closeButtonAction() {
delegate?.didDismiss()
delegate?.didTapCloseButton()
}

// For unit testing
Expand Down
106 changes: 69 additions & 37 deletions Tests/YBottomSheetTests/BottomSheetControllerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import YMatterType

// OK to have lots of test cases
// swiftlint:disable file_length
// swiftlint:disable type_body_length

final class BottomSheetControllerTests: XCTestCase {
var window: UIWindow!
Expand Down Expand Up @@ -130,40 +131,6 @@ final class BottomSheetControllerTests: XCTestCase {
XCTAssertTrue(sut.indicatorContainer.isHidden)
XCTAssertFalse(sut.isResizable)
}

func test_onDimmer() {
let sut = SpyBottomSheetController(title: "", childView: UIView())

XCTAssertFalse(sut.onDimmerTapped)
XCTAssertFalse(sut.isDismissed)

sut.simulateOnDimmerTap()

XCTAssertTrue(sut.onDimmerTapped)
XCTAssertTrue(sut.isDismissed)
}

func test_onSwipeDown() {
let sut = SpyBottomSheetController(title: "", childView: UIView())

XCTAssertFalse(sut.onSwipeDown)
XCTAssertFalse(sut.isDismissed)

sut.simulateOnSwipeDown()

XCTAssertTrue(sut.onSwipeDown)
XCTAssertTrue(sut.isDismissed)
}

func test_onDidDismiss() {
let sut = SpyBottomSheetController(title: "", childView: UIView())

XCTAssertFalse(sut.isDismissed)

sut.simulateDismiss()

XCTAssertTrue(sut.isDismissed)
}

func test_dragging_worksIfResizable() {
let sut = SpyBottomSheetController(title: "", childView: ChildView(), appearance: .defaultResizable)
Expand Down Expand Up @@ -322,6 +289,60 @@ final class BottomSheetControllerTests: XCTestCase {
let sut = makeSUT(viewController: UINavigationController(rootViewController: UIViewController()))
XCTAssertFalse(sut.hasHeader)
}

func test_onDimmer() {
let sut = SpyBottomSheetController(title: "", childView: UIView())

XCTAssertFalse(sut.onDimmerTapped)
XCTAssertFalse(sut.isDismissed)

sut.simulateOnDimmerTap()

XCTAssertTrue(sut.onDimmerTapped)
XCTAssertTrue(sut.isDismissed)
}

func test_onSwipeDown() {
let sut = SpyBottomSheetController(title: "", childView: UIView())

XCTAssertFalse(sut.onSwipeDown)
XCTAssertFalse(sut.isDismissed)

sut.simulateOnSwipeDown()

XCTAssertTrue(sut.onSwipeDown)
XCTAssertTrue(sut.isDismissed)
}

func test_dismissOnCloseButtonTapped() {
let sut = SpyBottomSheetController(title: "", childView: UIView())

XCTAssertFalse(sut.isDismissed)

sut.simulateTapCloseButton()

XCTAssertTrue(sut.isDismissed)
}

func test_forbidDismiss() {
let sut = SpyBottomSheetController(title: "", childView: UIView())
sut.appearance.isDismissAllowed = false

XCTAssertFalse(sut.onSwipeDown)
XCTAssertFalse(sut.onDimmerTapped)
XCTAssertFalse(sut.isDismissed)

sut.simulateOnDimmerTap()
sut.simulateOnSwipeDown()
mpospese marked this conversation as resolved.
Show resolved Hide resolved
_ = sut.accessibilityPerformEscape()

XCTAssertFalse(sut.onSwipeDown)
XCTAssertFalse(sut.onDimmerTapped)

// tap close button always dismisses
sut.simulateTapCloseButton()
XCTAssertTrue(sut.isDismissed)
}
}

private extension BottomSheetControllerTests {
Expand Down Expand Up @@ -367,20 +388,31 @@ final class SpyBottomSheetController: BottomSheetController {
var onSwipeDown = false
var onDimmerTapped = false
var onDragging = false

override func simulateTapCloseButton() {
super.simulateTapCloseButton()
isDismissed = true
}

override func didDismiss() {
super.didDismiss()
isDismissed = true
if appearance.isDismissAllowed {
isDismissed = true
}
}

override func simulateOnSwipeDown() {
super.simulateOnSwipeDown()
onSwipeDown = true
if appearance.isDismissAllowed {
onSwipeDown = true
}
}

override func simulateOnDimmerTap() {
super.simulateOnDimmerTap()
onDimmerTapped = true
if appearance.isDismissAllowed {
onDimmerTapped = true
}
}

@discardableResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ private extension SheetHeaderViewTests {
}

extension SheetHeaderViewTests: SheetHeaderViewDelegate {
func didDismiss() {
func didTapCloseButton() {
isDismissed = true
}
}