From f46781e87820d752458478bc2b8ec6d747e6528a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Tue, 27 Jan 2026 14:59:43 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Fix:=20=ED=83=88=ED=87=B4=ED=95=98=EA=B8=B0?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC=20enabled=20=EC=88=98=EC=A0=95=20(#T3-206?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Common/Component/PrimaryButton.swift | 1 + .../Withdraw/View/WithdrawViewController.swift | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Projects/Presentation/Sources/Common/Component/PrimaryButton.swift b/Projects/Presentation/Sources/Common/Component/PrimaryButton.swift index c4aeef81..d7b4ffad 100644 --- a/Projects/Presentation/Sources/Common/Component/PrimaryButton.swift +++ b/Projects/Presentation/Sources/Common/Component/PrimaryButton.swift @@ -43,6 +43,7 @@ final class PrimaryButton: UIButton { self.buttonState = buttonState super.init(frame: .zero) configureAttribute(buttonTitle: buttonTitle) + self.isEnabled = buttonState != .disabled } required init?(coder: NSCoder) { diff --git a/Projects/Presentation/Sources/Withdraw/View/WithdrawViewController.swift b/Projects/Presentation/Sources/Withdraw/View/WithdrawViewController.swift index d2f7dcc1..6bba097c 100644 --- a/Projects/Presentation/Sources/Withdraw/View/WithdrawViewController.swift +++ b/Projects/Presentation/Sources/Withdraw/View/WithdrawViewController.swift @@ -40,7 +40,7 @@ final class WithdrawViewController: BaseViewController { private let withdrawReasonView = UIView() private let withdrawReasonLabel = UILabel() private let withdrawReasonStackView = UIStackView() - private var withdrawButtons: [WithdrawReason: BitnagilChoiceButton] = [:] + private var withdrawReasonButtons: [WithdrawReason: BitnagilChoiceButton] = [:] private let withdrawReasonTextBackgroundView = UIView() private let withdrawReasonTextViewPlaceholder = UILabel() private let withdrawReasonTextView = UITextView() @@ -121,7 +121,7 @@ final class WithdrawViewController: BaseViewController { make.height.equalTo(Layout.withdrawChoiceButtonHeight) } withdrawReasonStackView.addArrangedSubview(withdrawChoiceButton) - withdrawButtons[withdrawReason] = withdrawChoiceButton + withdrawReasonButtons[withdrawReason] = withdrawChoiceButton } withdrawReasonTextBackgroundView.backgroundColor = BitnagilColor.gray99 @@ -147,6 +147,10 @@ final class WithdrawViewController: BaseViewController { self?.viewModel.action(input: .withdrawService) }, for: .touchUpInside) + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) + tapGesture.cancelsTouchesInView = false + view.addGestureRecognizer(tapGesture) } override func configureLayout() { @@ -284,7 +288,7 @@ final class WithdrawViewController: BaseViewController { } private func updateWithdrawReason(selectedWithdrawReason: WithdrawReason?) { - withdrawButtons.forEach { withdrawReason in + withdrawReasonButtons.forEach { withdrawReason in let isSelected = withdrawReason.key == selectedWithdrawReason withdrawReason.value.updateButtonState(isChecked: isSelected) } @@ -296,6 +300,10 @@ final class WithdrawViewController: BaseViewController { withdrawReasonMaxLengthLabel.isHidden = true } } + + @objc private func dismissKeyboard() { + view.endEditing(true) + } } extension WithdrawViewController: UITextViewDelegate { From e2f8f4c51ab11231519d94fcfcbfa0b57e528e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Tue, 27 Jan 2026 15:57:13 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Fix:=20=ED=83=88=ED=87=B4=20=EC=82=AC?= =?UTF-8?q?=EC=9C=A0=20=EC=9E=91=EC=84=B1=20=EC=8B=9C,=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20offset=20=EC=A1=B0=EC=A0=95=20(#T3-206)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WithdrawViewController.swift | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Projects/Presentation/Sources/Withdraw/View/WithdrawViewController.swift b/Projects/Presentation/Sources/Withdraw/View/WithdrawViewController.swift index 6bba097c..bd1d7cd3 100644 --- a/Projects/Presentation/Sources/Withdraw/View/WithdrawViewController.swift +++ b/Projects/Presentation/Sources/Withdraw/View/WithdrawViewController.swift @@ -63,6 +63,11 @@ final class WithdrawViewController: BaseViewController { } } + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + removeKeyboardNotification() + } + private func updateConstraint() { let height = view.bounds.height if height <= 667 { @@ -151,6 +156,8 @@ final class WithdrawViewController: BaseViewController { let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) tapGesture.cancelsTouchesInView = false view.addGestureRecognizer(tapGesture) + + configureKeyboardNotification() } override func configureLayout() { @@ -301,14 +308,73 @@ final class WithdrawViewController: BaseViewController { } } + private func configureKeyboardNotification() { + NotificationCenter.default.addObserver( + self, + selector: #selector(keyboardWillAppear), + name: UIResponder.keyboardWillShowNotification, + object: nil) + + NotificationCenter.default.addObserver( + self, + selector: #selector(keyboardWillDisappear), + name: UIResponder.keyboardWillHideNotification, + object: nil) + } + + private func removeKeyboardNotification() { + NotificationCenter.default.removeObserver( + self, + name: UIResponder.keyboardWillShowNotification, + object: nil) + + NotificationCenter.default.removeObserver( + self, + name: UIResponder.keyboardWillHideNotification, + object: nil) + } + @objc private func dismissKeyboard() { view.endEditing(true) } + + @objc private func keyboardWillAppear(_ sender: Notification) { + guard + let keyboardFrame = sender.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, + let duration = sender.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double + else { return } + + let keyboardHeight = keyboardFrame.height + let buttonFrame = withdrawButton.convert(withdrawButton.bounds, to: view) + let buttonBottom = buttonFrame.maxY + let visibleHeight = view.frame.height - keyboardHeight + + if buttonBottom > visibleHeight { + let offset = buttonBottom - visibleHeight + 50 + + UIView.animate(withDuration: duration) { + self.view.frame.origin.y = -offset + } + } + } + + @objc private func keyboardWillDisappear(_ sender: Notification) { + guard let duration = sender.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double + else { return } + + UIView.animate(withDuration: duration) { + self.view.frame.origin.y = 0 + } + } } extension WithdrawViewController: UITextViewDelegate { func textViewDidBeginEditing(_ textView: UITextView) { viewModel.action(input: .choiceWithdrawReason(reason: nil)) + + if !textView.text.isEmpty { + viewModel.action(input: .inputWithdrawReason(reason: textView.text)) + } } func textViewDidChange(_ textView: UITextView) { From c44c0259a5939d0e03783f4739ecfa6dd9538936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Tue, 27 Jan 2026 16:36:11 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Fix:=20test.yml=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_test.yml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 1b60d6d5..b57d5999 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -16,12 +16,10 @@ jobs: - name: Set Xcode version run: sudo xcode-select -s /Applications/Xcode_16.4.app - - name: Install Mise and Tuist + - name: Install Tuist run: | - curl -fsSL https://mise.jdx.dev/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - mise install tuist - mise use -g tuist + curl -Ls https://install.tuist.io | bash + echo "$HOME/.tuist/bin" >> $GITHUB_PATH - name: Generate xcconfig run: | @@ -32,9 +30,8 @@ jobs: - name: Generate Xcode project with Tuist run: | - export PATH="$HOME/.local/bin:$PATH" - mise exec -- tuist install - mise exec -- tuist generate --no-open + tuist install + tuist generate --no-open - name: Build with xcodebuild run: | @@ -45,4 +42,3 @@ jobs: -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.4' \ clean build | xcpretty - From 930012aa346079ef7a2594274d1a33b91ed11145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=A5=E1=86=BC=E1=84=8B?= =?UTF-8?q?=E1=85=B5=E1=86=AB?= Date: Tue, 27 Jan 2026 17:18:37 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Fix:=20build=5Ftest.yml=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20mise=20=EC=82=AD=EC=A0=9C=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_test.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index b57d5999..10343a72 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -17,9 +17,7 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.4.app - name: Install Tuist - run: | - curl -Ls https://install.tuist.io | bash - echo "$HOME/.tuist/bin" >> $GITHUB_PATH + run: brew install tuist - name: Generate xcconfig run: | @@ -40,5 +38,5 @@ jobs: -workspace Bitnagil.xcworkspace \ -scheme App \ -sdk iphonesimulator \ - -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.4' \ - clean build | xcpretty + -destination 'generic/platform=iOS Simulator' \ + clean build