fix(GiniInternalPaymentSDK): Done button and landscape scroll for documentCollection#1179
fix(GiniInternalPaymentSDK): Done button and landscape scroll for documentCollection#1179zladzeyka wants to merge 12 commits into
Conversation
…l pad keyboard on iOS 26 On iOS 26+, use ToolbarItemGroup(placement: .keyboard) so the Done button renders natively with Liquid Glass. iOS <26 retains the doneButtonBar via safeAreaInset for portrait/landscape-bottomSheet and PaymentReviewContentView.toolbar for landscape documentCollection. - Extract dismissAmountKeyboard() to deduplicate shared action in doneButtonBar and the iOS 26 ToolbarItemGroup - Extract Transaction.withoutAnimation to replace the repeated disablesAnimations boilerplate across PaymentReviewPaymentInformationView and PaymentReviewContentView HEAL-508
…andscape bottomSheet mode The keyboard height spacer in safeAreaInset was applied whenever giniLayout.isLandscape, which is true for any iPhone in landscape (verticalSizeClass == .compact). In bottomSheet mode the form is inside a sheet that repositions above the keyboard naturally — adding keyboardHeight spacer collapsed the visible scroll area and pushed doneButtonBar toward the top of the sheet instead of above the keyboard. Guard the spacer with !isBottomSheetMode so it only applies to the inline landscape documentCollection layout where it is actually needed. HEAL-508
…cape documentCollection on iOS <26 ToolbarItemGroup(placement: .keyboard) places the Done button as a native full-width keyboard accessory, matching the original behaviour. The toolbar is guarded with #unavailable(iOS 26) and the landscape documentCollection condition so it only fires where needed; iOS 26+ is handled by the inner view's ToolbarItemGroup added in the previous commit. Also extends the doneButtonBar safeAreaInset condition to cover landscape bottomSheet mode (previously portrait-only on iOS <26). HEAL-508
… and Done button for documentCollection - Replace manual keyboardHeight spacer approach with native GeometryReader avoidance in landscape documentCollection; use ScrollViewReader to explicitly scroll focused fields into view since UIKit-backed text fields do not auto-scroll - Track maximum keyboard height (max() + keyboardHideToken debounce) to prevent layout jumps when switching between keyboard types with different heights (decimalPad+toolbar vs default+toolbar) - Animate spacer growth in landscape to smooth the first transition when a larger keyboard appears; use minimum-scroll anchor to avoid unnecessary scroll between adjacent fields (IBAN/amount row) - ContentView: always-registered ToolbarItemGroup for iOS <26 landscape keeps the toolbar bar permanently attached, eliminating the detach glitch when leaving the amount field - iOS 26: Liquid Glass Done button via ToolbarItemGroup for landscape documentCollection; doneButtonBar in safeAreaInset for portrait and landscape-bottomSheet (keyboard toolbar overlaps sheet content there) - Exclude landscape-bottomSheet from iOS 26 ToolbarItemGroup to fix TUIKeyplane height constraint conflict and incorrect button positioning - Apply .toolbar modifier only on iOS 26+ to avoid zero-width _UIToolbarContentView UIKit constraint warning on iOS <26 - Clear focusedField when keyboard truly dismisses (keyboardHideToken guard distinguishes true dismiss from keyboard-type switch) - Clear viewModel.activeField when sheet is dismissed normally so text fields do not appear focused on sheet reopen - Promote isDocCollection and isSheetContext to computed properties; inline doneButtonBar at its single call site; refactor scrollView branching; shorten all comments to single-line WHY notes HEAL-508 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…et modes and fix rotation focus - Restore ToolbarItemGroup (Liquid Glass) for iOS 26 in portrait and landscape-bottomSheet; use a Color.clear safeAreaInset spacer (doneButtonBarHeight) to prevent the floating button from overlapping the last content row at the sheet/keyboard boundary - Remove focusedField = nil from keyboardWillHide deferred block which was triggering handleFocusedFieldChange during rotation while isViewVisible was still true, causing activeField to be cleared and breaking keyboard restoration after rotation in bottomSheet mode HEAL-508 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove isSheetContext (exact inverse of isDocCollection); replace all usages with !isDocCollection to eliminate the two-property sync risk - Extract iOS 26 keyboard toolbar conditional into keyboardToolbarIfNeeded(_:) @ViewBuilder helper, removing the let-binding pattern in body - Inline doneButtonBar (single call site) and remove the property HEAL-508 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… into fix/HEAL-508_done_btn
…ch found in review - Fix onChange(of: keyboardHeight) guard from giniLayout.isLandscape to isDocCollection: the old guard also fired in landscape-bottomSheet mode (isDocCollection==false), causing spurious proxy.scrollTo calls inside the sheet's scroll view which has no keyboard-height spacer, potentially leaving the focused field obscured by the keyboard - Move iOS 26 ToolbarItemGroup condition inside the group (always-registered) matching the iOS <26 ContentView pattern: condition-outside removes and re-registers the toolbar mid-transition when switching fields, causing the same Liquid Glass button detach glitch the always-registered approach was introduced to prevent - Simplify keyboardToolbarIfNeeded<V: View> to use 'some View' parameter (Swift 5.7+ primary associated types make the explicit generic unnecessary) HEAL-508 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
…l views for readability - Extract onReceive keyboard notification closures into private funcs handleKeyboardWillShow(_:) and handleKeyboardWillHide() to keep body readable without deep inline logic - Split scrollView into sheetScrollView and docCollectionScrollView named @ViewBuilder properties so each layout path is self-describing - Restore doneButtonBar as a named @ViewBuilder property (sheet path references it clearly rather than inlining 10 lines anonymously) - Add // MARK: Private keyboard handlers section to separate concerns HEAL-508 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… warning for bottom sheet on iOS 26 - sheetScrollView.safeAreaInset: add Color.clear spacer (doneButtonBarHeight) on iOS 26 so content has breathing room above the Liquid Glass button which floats at the keyboard/sheet boundary - keyboardToolbarIfNeeded: condition stays inside ToolbarItemGroup (always- registered) for all modes — moving it outside switches view identity when the keyboard appears, causing the view to be destroyed and recreated which breaks keyboard presentation and causes a jump HEAL-508 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Internal Payment SDK’s Payment Review UI to improve keyboard UX across presentation modes, adding the iOS 26 “Liquid Glass” Done button behavior and fixing landscape documentCollection scrolling/keyboard avoidance.
Changes:
- Adds iOS 26 keyboard toolbar Done button support (and avoids content overlap in sheet contexts).
- Reworks landscape
documentCollectionkeyboard avoidance with a manual keyboard-height spacer andScrollViewReaderauto-scrolling to the focused field. - Refactors rotation/focus restoration and introduces a
Transaction.withoutAnimationhelper for sheet restoration without animation.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| GiniComponents/InternalPaymentSDK/GiniInternalPaymentSDK/Tests/GiniInternalPaymentSDKTests/PaymentReviewObservableModelTests.swift | Removes an outdated inline comment in the Done title default-string test. |
| GiniComponents/InternalPaymentSDK/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/Views/PaymentReviewContentView.swift | Updates landscape toolbar handling for iOS <26 and refines rotation sheet restoration using Transaction.withoutAnimation. |
| GiniComponents/InternalPaymentSDK/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/Views/PaymentInformation/PaymentReviewPaymentInformationView.swift | Implements iOS 26 keyboard toolbar, manual keyboard spacing for doc-collection landscape, and ScrollViewReader focus scrolling. |
| GiniComponents/InternalPaymentSDK/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/Views/PaymentInformation/PaymentReviewPaymentInformationObservableModel.swift | Changes ActivePaymentField conformance to Hashable to support use as ScrollViewReader IDs. |
| GiniComponents/InternalPaymentSDK/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewObservableModel.swift | Keeps keyboard-dismiss validation behavior, but adjusts related inline documentation (style nits noted). |
| GiniComponents/InternalPaymentSDK/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/Extensions/Transaction+Extensions.swift | Adds Transaction.withoutAnimation helper used to restore the sheet without inheriting ambient UIKit animations. |
…est coverage - Convert // comments to /** */ on isAmountFieldFocused, validateAmountFieldOnKeyboardDismiss, and Transaction.withoutAnimation to match the file's declaration-doc house style - Add ActivePaymentFieldTests and TransactionExtensionsTests to cover new Hashable conformance and Transaction.withoutAnimation (resolves SonarQube coverage gate failure) HEAL-508 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
qnaveed87
left a comment
There was a problem hiding this comment.
Thank you @zladzeyka for the great work
I have left some minor comments
| /** | ||
| The localized title for the keyboard Done button. | ||
| */ | ||
| var keyboardDoneButtonTitle: String { |
There was a problem hiding this comment.
[Suggestion] Can we please add the doc comment back
/** The localized title for the keyboard Done button. */



Pull Request Description
Adds the iOS 26 Liquid Glass Done button for the decimal pad keyboard across all PaymentReview presentation modes, and fixes landscape documentCollection keyboard avoidance and scroll position behaviour.
HEAL-508
Notes for Reviewers
Tested on iPhone simulator — iOS 18.6 and iOS 26.1.
Manual checks: