1e8ce36184
Native module:
- Add `fullHeight` prop to BottomSheetView on Android and iOS
- iOS: fullHeight sets detent to .large, skips content observation
- Android: fullHeight uses isFitToContents=false with expandedOffset=statusBarHeight
Android bottom sheet behavior overhaul:
- Switch normal sheets to isFitToContents=false with expandedOffset, enabling
proper 3-state snapping (half-expanded ↔ expanded ↔ hidden). Previously
isFitToContents=true prevented settling at half-expanded during gestures,
making it impossible to swipe back down from expanded.
- preventExpansion sheets keep isFitToContents=true with maxHeight cap, plus
a state callback safety net that bounces EXPANDED→HALF_EXPANDED. This
catches an edge case where rapid content resizes during opening can invert
the expanded/half-expanded offsets, causing the sheet to dismiss.
- Add requestLayout() after maxHeight changes in updateLayout() so the
FrameLayout actually re-measures (fixes keyboard padding not resizing sheet)
- Set backgroundTint=transparent in the theme to remove Material3 surface
tint that was visible in gaps between sheet and screen edge
Keyboard handling:
- Remove native keyboard expansion logic (insets listener, isKeyboardVisible
tracking, manual STATE_EXPANDED on keyboard show)
- Replace with JS-side keyboard padding: ScrollableInner listens for RN
Keyboard events and adds bottom padding equal to keyboard height
- Generalize useOnKeyboardDidShow → useOnKeyboard(eventName, cb)
Callers:
- Replace minHeight: screenHeight hack with fullHeight: true in EditProfile,
ChangeHandle, AddAppPassword, ImageAltText, GifAltText, LanguageSelect,
FollowDialog, GifSelect, StarterPack, Select, NewChat, ShareViaChat,
DraftsList, WizardEditList, ListAddRemoveUsers, CreateOrEditList
- Remove unused useWindowDimensions imports
- ServerInput: simplify to just preventExpansion (was platform-specific)
- ImageAltTextDialog: remove old {height: 300} keyboard spacer hack
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
109 lines
3.0 KiB
Swift
109 lines
3.0 KiB
Swift
//
|
|
// SheetViewController.swift
|
|
// Pods
|
|
//
|
|
// Created by Hailey on 9/30/24.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
|
|
class SheetViewController: UIViewController {
|
|
init() {
|
|
super.init(nibName: nil, bundle: nil)
|
|
|
|
self.modalPresentationStyle = .formSheet
|
|
self.isModalInPresentation = false
|
|
|
|
if let sheet = self.sheetPresentationController {
|
|
sheet.prefersGrabberVisible = false
|
|
}
|
|
}
|
|
|
|
func setDetents(contentHeight: CGFloat, preventExpansion: Bool, fullHeight: Bool = false) {
|
|
guard let sheet = self.sheetPresentationController,
|
|
let screenHeight = Util.getScreenHeight()
|
|
else {
|
|
return
|
|
}
|
|
|
|
if fullHeight {
|
|
sheet.detents = [.large()]
|
|
sheet.selectedDetentIdentifier = .large
|
|
return
|
|
}
|
|
|
|
// On iOS 26, the floaty sheet presentation adds the device bottom safe area
|
|
// on top of the custom detent value, creating visible padding inside the pill.
|
|
// Subtract it so the pill height matches our actual content.
|
|
var bottomSafeAreaAdjustment: CGFloat = 0
|
|
if #available(iOS 26.0, *) {
|
|
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
|
let window = windowScene.windows.first {
|
|
bottomSafeAreaAdjustment = window.safeAreaInsets.bottom
|
|
}
|
|
}
|
|
|
|
let adjustedHeight = contentHeight - bottomSafeAreaAdjustment
|
|
|
|
if #available(iOS 16.0, *) {
|
|
if contentHeight > screenHeight - 100 {
|
|
sheet.detents = [
|
|
.large()
|
|
]
|
|
sheet.selectedDetentIdentifier = .large
|
|
} else {
|
|
sheet.detents = [
|
|
.custom { _ in
|
|
return adjustedHeight
|
|
}
|
|
]
|
|
if !preventExpansion {
|
|
sheet.detents.append(.large())
|
|
}
|
|
sheet.selectedDetentIdentifier = .medium
|
|
}
|
|
} else {
|
|
if contentHeight > screenHeight / 2 {
|
|
sheet.detents = [
|
|
.large()
|
|
]
|
|
sheet.selectedDetentIdentifier = .large
|
|
} else {
|
|
sheet.detents = [
|
|
.medium()
|
|
]
|
|
if !preventExpansion {
|
|
sheet.detents.append(.large())
|
|
}
|
|
sheet.selectedDetentIdentifier = .medium
|
|
}
|
|
}
|
|
}
|
|
|
|
func updateDetents(contentHeight: CGFloat, preventExpansion: Bool) {
|
|
if let sheet = self.sheetPresentationController {
|
|
// Capture `self` weakly to prevent retain cycles.
|
|
// Also, capture `sheet` weakly to avoid potential strong references held by animateChanges.
|
|
sheet.animateChanges { [weak self, weak sheet] in
|
|
guard let weakSelf = self, let weakSheet = sheet else { return }
|
|
weakSelf.setDetents(contentHeight: contentHeight, preventExpansion: preventExpansion)
|
|
if #available(iOS 16.0, *) {
|
|
weakSheet.invalidateDetents()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func getCurrentDetentIdentifier() -> UISheetPresentationController.Detent.Identifier? {
|
|
guard let sheet = self.sheetPresentationController else {
|
|
return nil
|
|
}
|
|
return sheet.selectedDetentIdentifier
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
}
|