-
Notifications
You must be signed in to change notification settings - Fork 1
[Fix-T3-206] 탈퇴하기 기능 QA 이슈 수정 #77
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’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,7 +40,7 @@ final class WithdrawViewController: BaseViewController<WithdrawViewModel> { | |
| 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() | ||
|
|
@@ -63,6 +63,11 @@ final class WithdrawViewController: BaseViewController<WithdrawViewModel> { | |
| } | ||
| } | ||
|
|
||
| override func viewWillDisappear(_ animated: Bool) { | ||
| super.viewWillDisappear(animated) | ||
| removeKeyboardNotification() | ||
| } | ||
|
Comment on lines
+66
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 키보드 알림 등록/해제 시점 불일치 가능성
탈퇴 플로우 특성상 화면을 벗어났다가 다시 돌아오는 경우가 드물지만, 일관성을 위해 제안하는 수정 방법+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ configureKeyboardNotification()
+ }
+
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
removeKeyboardNotification()
}그리고 Also applies to: 160-160, 311-323 🤖 Prompt for AI Agents |
||
|
|
||
| private func updateConstraint() { | ||
| let height = view.bounds.height | ||
| if height <= 667 { | ||
|
|
@@ -121,7 +126,7 @@ final class WithdrawViewController: BaseViewController<WithdrawViewModel> { | |
| make.height.equalTo(Layout.withdrawChoiceButtonHeight) | ||
| } | ||
| withdrawReasonStackView.addArrangedSubview(withdrawChoiceButton) | ||
| withdrawButtons[withdrawReason] = withdrawChoiceButton | ||
| withdrawReasonButtons[withdrawReason] = withdrawChoiceButton | ||
| } | ||
|
|
||
| withdrawReasonTextBackgroundView.backgroundColor = BitnagilColor.gray99 | ||
|
|
@@ -147,6 +152,12 @@ final class WithdrawViewController: BaseViewController<WithdrawViewModel> { | |
| self?.viewModel.action(input: .withdrawService) | ||
| }, | ||
| for: .touchUpInside) | ||
|
|
||
| let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) | ||
| tapGesture.cancelsTouchesInView = false | ||
| view.addGestureRecognizer(tapGesture) | ||
|
|
||
| configureKeyboardNotification() | ||
| } | ||
|
|
||
| override func configureLayout() { | ||
|
|
@@ -284,7 +295,7 @@ final class WithdrawViewController: BaseViewController<WithdrawViewModel> { | |
| } | ||
|
|
||
| private func updateWithdrawReason(selectedWithdrawReason: WithdrawReason?) { | ||
| withdrawButtons.forEach { withdrawReason in | ||
| withdrawReasonButtons.forEach { withdrawReason in | ||
| let isSelected = withdrawReason.key == selectedWithdrawReason | ||
| withdrawReason.value.updateButtonState(isChecked: isSelected) | ||
| } | ||
|
|
@@ -296,11 +307,74 @@ final class WithdrawViewController: BaseViewController<WithdrawViewModel> { | |
| withdrawReasonMaxLengthLabel.isHidden = true | ||
| } | ||
| } | ||
|
|
||
| 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) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: YAPP-Github/Bitnagil-iOS
Length of output: 1476
🏁 Script executed:
Repository: YAPP-Github/Bitnagil-iOS
Length of output: 50
🏁 Script executed:
Repository: YAPP-Github/Bitnagil-iOS
Length of output: 50
🌐 Web query:
Tuist lockfile deterministic dependency resolution CI reproducibility💡 Result:
Tuist’s dependency “lockfile” story is essentially SwiftPM’s
Package.resolved:Package.resolvedto pin the exact versions (including transitive dependencies). EnsurePackage.resolvedis committed (not gitignored), otherwise CI/dev machines may pick up newer transitive releases and break builds. [1]tuist install --force-resolved-versionsThis forces resolution to the exact versions in
Package.resolvedto avoid non-determinism in resolution. [2]tuist installeffectively runsswift package resolve(generally respectingPackage.resolved), whiletuist install --updaterunsswift package updateand can move versions forward within the ranges inPackage.swift. [3].build) and keying it off thePackage.resolvedpath used by Xcode/SwiftPM; you can also pass-clonedSourcePackagesDirPath .buildvia Tuist config /xcodebuildto keep clones in a predictable location for caching. [4]Practical checklist for reproducible CI
Package.resolved.tuist install --force-resolved-versionsin CI.tuist install --updatein a dedicated “deps update” workflow/PR)..build(or your configured clone dir) keyed byPackage.resolved. [1][2][4]Sources: Tuist best practices (CI flag) [2], Tuist community threads on transitive locking & install/update behavior [1][3], Tuist registry CI/caching guide [4].
🏁 Script executed:
Repository: YAPP-Github/Bitnagil-iOS
Length of output: 90
🏁 Script executed:
Repository: YAPP-Github/Bitnagil-iOS
Length of output: 87
tuist install시--force-resolved-versions플래그 추가 필요리포지토리에
Tuist/Package.resolved파일이 있으므로 의존성 버전이 잠금되어 있습니다. 다만, 현재 CI 워크플로우의tuist install명령어는 플래그 없이 실행되어 매번 해상도 과정을 거칠 수 있습니다.CI 재현성을 보장하려면 다음과 같이 수정하세요:
이 플래그는
Package.resolved의 정확한 버전(이행 의존성 포함)을 강제하여 CI의 결정적 동작을 보장합니다.🤖 Prompt for AI Agents