Skip to content

fix(GiniInternalPaymentSDK): Done button and landscape scroll for documentCollection#1179

Open
zladzeyka wants to merge 12 commits into
release/liquid_glass_health_sdkfrom
fix/HEAL-508_done_btn
Open

fix(GiniInternalPaymentSDK): Done button and landscape scroll for documentCollection#1179
zladzeyka wants to merge 12 commits into
release/liquid_glass_health_sdkfrom
fix/HEAL-508_done_btn

Conversation

@zladzeyka

@zladzeyka zladzeyka commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

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:

  • Landscape documentCollection: tap each field; content scrolls to show it above the keyboard; no layout jump when switching between IBAN ↔ amount
  • Done button landscape iOS <26: full-width bar attached to keyboard; no glitch when leaving the amount field
  • Done button landscape iOS 26: Liquid Glass floating button, correctly positioned
  • Done button portrait / landscape-bottomSheet iOS <26: custom bar appears above keyboard inside the sheet
  • Done button portrait / landscape-bottomSheet iOS 26: Liquid Glass button, content does not overlap it
  • Rotation in bottomSheet: open keyboard → rotate portrait → landscape → portrait; keyboard reopens on the same field
  • Sheet grabber dismiss: dismiss sheet while a field is focused; reopen — no field appears focused

zladzeyka and others added 5 commits June 17, 2026 10:18
…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>
@zladzeyka zladzeyka had a problem deploying to firebase-manual-deploy June 17, 2026 17:21 — with GitHub Actions Error
- 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>
@zladzeyka zladzeyka had a problem deploying to firebase-manual-deploy June 17, 2026 17:28 — with GitHub Actions Error
@zladzeyka zladzeyka changed the base branch from main to release/liquid_glass_health_sdk June 17, 2026 17:28
@zladzeyka zladzeyka changed the base branch from release/liquid_glass_health_sdk to main June 17, 2026 17:38
…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>
@zladzeyka zladzeyka had a problem deploying to firebase-manual-deploy June 18, 2026 14:32 — with GitHub Actions Error
@zladzeyka zladzeyka changed the base branch from main to release/liquid_glass_health_sdk June 18, 2026 14:34
@sonarqubecloud

Copy link
Copy Markdown

…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>
@zladzeyka zladzeyka had a problem deploying to firebase-manual-deploy June 18, 2026 14:54 — with GitHub Actions Error
… 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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 documentCollection keyboard avoidance with a manual keyboard-height spacer and ScrollViewReader auto-scrolling to the focused field.
  • Refactors rotation/focus restoration and introduces a Transaction.withoutAnimation helper 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>
@zladzeyka zladzeyka had a problem deploying to firebase-manual-deploy June 22, 2026 14:14 — with GitHub Actions Error
@zladzeyka zladzeyka requested a review from Copilot June 22, 2026 14:20
@zladzeyka zladzeyka marked this pull request as ready for review June 22, 2026 14:20
@zladzeyka zladzeyka had a problem deploying to firebase-manual-deploy June 22, 2026 14:20 — with GitHub Actions Error
@zladzeyka zladzeyka requested a review from qnaveed87 June 22, 2026 14:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

@zladzeyka zladzeyka requested a deployment to firebase-manual-deploy June 22, 2026 15:16 — with GitHub Actions Waiting
@sonarqubecloud

Copy link
Copy Markdown

@qnaveed87 qnaveed87 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @zladzeyka for the great work

I have left some minor comments

/**
The localized title for the keyboard Done button.
*/
var keyboardDoneButtonTitle: String {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Can we please add the doc comment back
/** The localized title for the keyboard Done button. */

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants