Skip to content
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
6 changes: 6 additions & 0 deletions Example/TSAlertController.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -545,9 +545,12 @@
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_STRICT_CONCURRENCY = minimal;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
Expand All @@ -569,9 +572,12 @@
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_STRICT_CONCURRENCY = minimal;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
Expand Down
35 changes: 32 additions & 3 deletions Example/Tests/TSAlertControllerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import XCTest

final class TSAlertControllerTests: XCTestCase {

// MARK: - Verifies that TSAlertController initializes with correct title, message, and preferredStyle

func testTSAlertController_WhenInitialized_ShouldSetTitleMessageAndPreferredStyle() {
// given
let alertController = TSAlertController(
Expand All @@ -22,6 +24,9 @@ final class TSAlertControllerTests: XCTestCase {
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}


// MARK: - Verifies that TSAlertController initializes with correct textfields

func testTSAlertController_WhenIntializedWithTextFields_ShouldSetTextFields() {
// given
let alertController = TSAlertController(
Expand All @@ -41,6 +46,10 @@ final class TSAlertControllerTests: XCTestCase {
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}



// MARK: - Verifies that TSAlertController initializes with the correct actions order and count

func testTSAlertController_WhenInitializedWithTwoButtonsAndAutomaticAxis_ShouldSetCorrectActionsOrderAndCount() {
// given
let alertController = TSAlertController(
Expand Down Expand Up @@ -95,6 +104,9 @@ final class TSAlertControllerTests: XCTestCase {
}





func testTSAlertController_WhenIntlaizedWithAlertStyle_ShouldSetDefaultConfiguration() {
// given
let alertController = TSAlertController(
Expand Down Expand Up @@ -205,12 +217,11 @@ final class TSAlertControllerTests: XCTestCase {
// then
let config = alertController.configuration
XCTAssertFalse(alertController.options.contains(.stretchyDragging))
XCTAssertEqual(config.prefersGrabberVisible, true)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenIntializedWithActionSheetStyle_ShouldSetDefaultCconfiguration() {
func testTSAlertController_WhenIntializedWithActionSheetStyle_ShouldSetDefaultConfiguration() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
Expand Down Expand Up @@ -263,8 +274,26 @@ final class TSAlertControllerTests: XCTestCase {
// then
let config = alertController.configuration
XCTAssertFalse(alertController.options.contains(.interactiveScaleAndDrag))
XCTAssertEqual(config.prefersGrabberVisible, true)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenIntializedWithActionSheetStyle_ShouldSetCorrectViewConfigurationForcibly() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .actionSheet
)
let mockViewController = MockViewController()

// when
alertController.viewConfiguration.cornerRadius = 25.0

mockViewController.present(alertController, animated: true)

// then
let viewConfig = alertController.viewConfiguration
XCTAssertEqual(viewConfig.cornerRadius.bottomLeft, 0.0)
XCTAssertEqual(viewConfig.cornerRadius.bottomRight, 0.0)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

Expand Down
92 changes: 39 additions & 53 deletions Sources/TSAlert/TSAlertController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ public final class TSAlertController: UIViewController {
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

initialViewTopY = view.frame.origin.y
view.applyRoundCorners(viewConfiguration.cornerRadius)
}

Expand Down Expand Up @@ -413,14 +414,12 @@ public final class TSAlertController: UIViewController {

// Registers notifications to handle keyboard appearance and disappearance.
private func registerKeyboardNotifications() {
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow(_:)),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide(_:)),
name: UIResponder.keyboardWillHideNotification,
object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillChangeFrame(_:)),
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil
)
}

// Registers notifications to handle keyboard appearance and disappearance.
Expand Down Expand Up @@ -691,7 +690,6 @@ private extension TSAlertController {
}
}

///
@objc private func handleStretchyDragging(_ gesture: UIPanGestureRecognizer) {

let interpolationFactor: CGFloat = 0.025
Expand Down Expand Up @@ -729,57 +727,45 @@ private extension TSAlertController {

private extension TSAlertController {

// Adjusts the alert’s position when the keyboard appears.
@objc func keyboardWillShow(_ notification: Notification) {
// If this method is not blocked, the alert view's position may animate incorrectly
// when the keyboard suggestion bar appears or disappears.
guard !isKeyboardShown else { return }
@objc func keyboardWillChangeFrame(_ notification: Notification) {

guard let userInfo = notification.userInfo,
let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect,
let keyboardAnimationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber else {
return
}

let viewHeight = view.frame.height
let keyboardTopY = keyboardFrame.origin.y

let duration = keyboardAnimationDuration.doubleValue
let adjustedViewTopY = keyboardTopY - viewConfiguration.spacing.keyboardSpacing - viewHeight

// Move the alert up only if the spacing is smaller than the configured value.
// If the space between the alert and the keyboard is greater than the configured value, the alert will not move.
if adjustedViewTopY < initialViewTopY {
UIView.animate(withDuration: duration,
delay: 0,
options: .curveEaseIn) {
self.view.frame.origin.y = adjustedViewTopY
}
}
let keyboardAnimationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber
else { return }

isKeyboardShown = true
}

// Resets the alert’s position when the keyboard disappears.
@objc func keyboardWillHide(_ notification: Notification) {
// If this method is not blocked, the alert view's position may animate incorrectly
// when the keyboard suggestion bar appears or disappears.
guard isKeyboardShown else { return }
let alertViewHeight = view.frame.height // Alert 뷰의 전체 높이
let keyboardOriginY = keyboardFrame.origin.y // 상위 뷰 기준, 키보드의 상단 y 좌표

guard let userInfo = notification.userInfo,
let keyboardAnimationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber else {
return
}
let duration = keyboardAnimationDuration.doubleValue

// Ensure the software keyboard is enabled for proper testing (Command + K).
UIView.animate(withDuration: duration,
delay: 0,
options: .curveEaseIn) {
self.view.frame.origin.y = self.initialViewTopY
let adjustedViewTopY = keyboardOriginY - viewConfiguration.spacing.keyboardSpacing - alertViewHeight
// 키보드 상단 y 좌표에서 지정된 간격(keyboardSpacing)을 뺀 뒤,
// Alert 뷰의 전체 높이를 빼면 Alert 뷰의 새로운 y 좌표를 구할 수 있음

// 키보드가 나타난 상태일 때 실행
if isKeyboardShown {
UIView.animate(
withDuration: duration,
delay: 0,
options: .curveEaseIn
) {
self.view.frame.origin.y = self.initialViewTopY
} completion: { _ in
self.isKeyboardShown = false
}
} else if adjustedViewTopY < initialViewTopY && !isKeyboardShown {
// Move the alert up only if the spacing is smaller than the configured value.
// If the space between the alert and the keyboard is greater than the configured value, the alert will not move.
UIView.animate(
withDuration: duration,
delay: 0,
options: .curveEaseIn
) {
self.view.frame.origin.y = adjustedViewTopY
} completion: { _ in
self.isKeyboardShown = true
}
}

isKeyboardShown = false
}
}

Expand Down
Loading