react-native-screens 5.0.0-alpha.2 → 5.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/Package.swift +87 -0
  2. package/README.md +0 -7
  3. package/android/src/main/cpp/NativeProxy.cpp +30 -6
  4. package/android/src/main/cpp/NativeProxy.h +7 -1
  5. package/android/src/main/java/com/swmansion/rnscreens/common/container/Container.kt +8 -0
  6. package/android/src/main/java/com/swmansion/rnscreens/common/container/ContainerItem.kt +13 -1
  7. package/android/src/main/java/com/swmansion/rnscreens/common/text/ReactTextAppearance.kt +62 -0
  8. package/android/src/main/java/com/swmansion/rnscreens/common/text/TextAppearance.kt +20 -0
  9. package/android/src/main/java/com/swmansion/rnscreens/common/text/TextAppearanceDefaults.kt +65 -0
  10. package/android/src/main/java/com/swmansion/rnscreens/helpers/PropIconResolver.kt +17 -23
  11. package/android/src/main/java/com/swmansion/rnscreens/legacy/Screen.kt +3 -1
  12. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenStack.kt +2 -0
  13. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetBehaviorController.kt +49 -18
  14. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetDimensionsCoordinator.kt +65 -40
  15. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetKeyboardCoordinator.kt +101 -0
  16. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetNativeDismissCoordinator.kt +0 -6
  17. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetAvailableHeightProvider.kt +44 -0
  18. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetDialog.kt +35 -3
  19. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetDialogManager.kt +33 -106
  20. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/interfaces/FormSheetDialogEventEmitter.kt +2 -0
  21. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/model/FormSheetDetents.kt +61 -15
  22. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetAnimatorFactory.kt +8 -9
  23. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetDimmingManager.kt +115 -0
  24. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetDismissalOrigin.kt +22 -0
  25. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetPresentation.kt +173 -0
  26. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetPresentationManager.kt +141 -49
  27. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetPresentationState.kt +1 -1
  28. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetStackRegistry.kt +28 -0
  29. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/react/event/FormSheetDismissEvent.kt +29 -0
  30. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/react/host/FormSheetHostEventEmitter.kt +7 -0
  31. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/react/host/FormSheetHostViewManager.kt +2 -0
  32. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderApplicator.kt +369 -58
  33. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderBackPressHandler.kt +11 -0
  34. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderCoordinatorLayout.kt +143 -98
  35. package/android/src/main/java/com/swmansion/rnscreens/stack/header/appbar/StackHeaderAppBarLayout.kt +155 -23
  36. package/android/src/main/java/com/swmansion/rnscreens/stack/header/appbar/StackHeaderContentScrimDrawable.kt +36 -0
  37. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderCollapsedTitleGravityMode.kt +6 -0
  38. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfig.kt +170 -167
  39. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigViewManager.kt +385 -12
  40. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigurationObserver.kt +0 -4
  41. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigurationProviding.kt +32 -3
  42. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderDelegate.kt +0 -7
  43. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderInvalidationFlags.kt +7 -2
  44. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuApplicator.kt +27 -280
  45. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuController.kt +448 -0
  46. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuDelegate.kt +10 -0
  47. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuMapper.kt +28 -20
  48. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuConfig.kt +3 -55
  49. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuGroupMetadata.kt +1 -10
  50. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuItemConfig.kt +1 -3
  51. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuModel.kt +180 -0
  52. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementOptions.kt +57 -6
  53. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementRawUpdate.kt +3 -1
  54. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementUpdate.kt +1 -0
  55. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuIconResolver.kt +4 -3
  56. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuUpdateQueue.kt +23 -9
  57. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackContainer.kt +103 -3
  58. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackHost.kt +13 -0
  59. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackHostViewManager.kt +14 -0
  60. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreen.kt +4 -0
  61. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreenFragment.kt +20 -1
  62. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreenFragmentDelegate.kt +12 -0
  63. package/android/src/main/java/com/swmansion/rnscreens/tabs/appearance/TabsAppearanceCoordinator.kt +2 -4
  64. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/MenuHelpers.kt +5 -23
  65. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/TabsContainer.kt +46 -25
  66. package/android/src/main/java/com/swmansion/rnscreens/tabs/host/TabsHost.kt +10 -0
  67. package/android/src/main/java/com/swmansion/rnscreens/tabs/host/TabsHostA11yCoordinator.kt +23 -2
  68. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreen.kt +17 -0
  69. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreenFragment.kt +3 -0
  70. package/android/src/main/java/com/swmansion/rnscreens/utils/DimensionUtils.kt +7 -0
  71. package/android/src/main/java/com/swmansion/rnscreens/utils/StyleUtils.kt +22 -0
  72. package/android/src/main/res/base/layout/rns_collapsing_toolbar_large_available_space.xml +8 -0
  73. package/android/src/main/res/base/layout/rns_collapsing_toolbar_large_entire_space.xml +8 -0
  74. package/android/src/main/res/base/layout/rns_collapsing_toolbar_medium_available_space.xml +8 -0
  75. package/android/src/main/res/base/layout/rns_collapsing_toolbar_medium_entire_space.xml +8 -0
  76. package/cpp/legacy/RNSScreenRemovalListener.cpp +31 -1
  77. package/cpp/legacy/RNSScreenRemovalListener.h +18 -3
  78. package/ios/RNSEnums.h +2 -0
  79. package/ios/conversion/RNSConversions.h +7 -108
  80. package/ios/legacy/RNSFullWindowOverlay.mm +1 -1
  81. package/ios/legacy/RNSModalScreen.mm +1 -1
  82. package/ios/legacy/RNSScreen.mm +8 -19
  83. package/ios/legacy/RNSScreenStackHeaderConfig.mm +3 -1
  84. package/ios/legacy/RNSScreenStackHeaderSubview.mm +1 -1
  85. package/ios/legacy/RNSScreenWindowTraits.mm +5 -13
  86. package/ios/modals/form-sheet/RNSFormSheetConfigurationApplicator.h +1 -3
  87. package/ios/modals/form-sheet/RNSFormSheetConfigurationApplicator.mm +11 -22
  88. package/ios/modals/form-sheet/RNSFormSheetContentController.h +1 -1
  89. package/ios/modals/form-sheet/RNSFormSheetContentController.mm +7 -18
  90. package/ios/modals/form-sheet/RNSFormSheetHostComponentView.mm +4 -4
  91. package/ios/modals/form-sheet/RNSFormSheetHostShadowStateProxy.mm +2 -2
  92. package/ios/modals/form-sheet/RNSFormSheetUpdateFlags.h +3 -0
  93. package/ios/safe-area/RNSSafeAreaViewComponentView.mm +2 -2
  94. package/ios/{conversion → scroll-view-marker/conversion}/RNSConversions-ScrollViewMarker.mm +2 -3
  95. package/ios/split/RNSSplitAppearanceApplicator.h +4 -4
  96. package/ios/split/RNSSplitAppearanceApplicator.mm +53 -56
  97. package/ios/split/RNSSplitHostComponentEventEmitter.h +1 -0
  98. package/ios/split/RNSSplitHostComponentEventEmitter.mm +1 -1
  99. package/ios/split/RNSSplitHostComponentView.h +5 -15
  100. package/ios/split/RNSSplitHostComponentView.mm +55 -6
  101. package/ios/split/RNSSplitHostController.h +25 -6
  102. package/ios/split/RNSSplitHostController.mm +24 -92
  103. package/ios/split/RNSSplitHostProviders.h +67 -0
  104. package/ios/split/RNSSplitScreenComponentView.h +0 -39
  105. package/ios/split/RNSSplitScreenComponentView.mm +27 -10
  106. package/ios/split/RNSSplitScreenController.h +26 -3
  107. package/ios/split/RNSSplitScreenController.mm +13 -30
  108. package/ios/split/RNSSplitScreenShadowStateProxy.h +1 -40
  109. package/ios/split/RNSSplitScreenShadowStateProxy.mm +1 -26
  110. package/ios/split/conversion/RNSConversions-SplitView.h +56 -0
  111. package/ios/{conversion → split/conversion}/RNSConversions-SplitView.mm +4 -1
  112. package/ios/stack/conversion/RNSConversions-Stack.h +32 -0
  113. package/ios/stack/conversion/RNSConversions-Stack.mm +55 -0
  114. package/ios/stack/header/RNSStackHeaderAppearanceMapper.h +26 -0
  115. package/ios/stack/header/RNSStackHeaderAppearanceMapper.mm +88 -0
  116. package/ios/stack/header/RNSStackHeaderConfigComponentView.h +10 -1
  117. package/ios/stack/header/RNSStackHeaderConfigComponentView.mm +67 -35
  118. package/ios/stack/header/RNSStackHeaderConfigDataProviding.h +6 -0
  119. package/ios/stack/header/RNSStackHeaderConfigShadowStateProxy.mm +1 -1
  120. package/ios/stack/header/RNSStackHeaderIconResolver.mm +7 -0
  121. package/ios/stack/header/RNSStackHeaderItemComponentView.h +3 -1
  122. package/ios/stack/header/RNSStackHeaderItemComponentView.mm +15 -2
  123. package/ios/stack/header/RNSStackHeaderItemDataProviding.h +2 -0
  124. package/ios/stack/header/RNSStackHeaderItemShadowStateProxy.mm +1 -1
  125. package/ios/stack/header/RNSStackHeaderItemSpacerComponentView.mm +2 -1
  126. package/ios/stack/header/RNSStackHeaderMenuMapper.mm +4 -0
  127. package/ios/stack/host/RNSStackNavigationBar.h +25 -0
  128. package/ios/stack/host/RNSStackNavigationBar.mm +80 -0
  129. package/ios/stack/host/RNSStackNavigationBarCoordinator.h +8 -0
  130. package/ios/stack/host/RNSStackNavigationBarCoordinator.mm +11 -0
  131. package/ios/stack/host/RNSStackNavigationController.mm +13 -5
  132. package/ios/stack/host/RNSStackOperation.h +0 -2
  133. package/ios/stack/screen/RNSStackScreenComponentView.mm +9 -2
  134. package/ios/stack/screen/RNSStackScreenController.mm +12 -0
  135. package/ios/stack/screen/RNSStackScreenHeaderCoordinator.h +8 -0
  136. package/ios/stack/screen/RNSStackScreenHeaderCoordinator.mm +98 -16
  137. package/ios/tabs/RNSTabBarAppearanceCoordinator.mm +40 -9
  138. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryComponentView.h +1 -1
  139. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryComponentView.mm +1 -1
  140. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryContentComponentView.mm +1 -1
  141. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryEventEmitter.mm +1 -1
  142. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryShadowStateProxy.mm +1 -1
  143. package/ios/tabs/conversion/RNSConversions-Tabs.h +78 -0
  144. package/ios/{conversion → tabs/conversion}/RNSConversions-Tabs.mm +8 -71
  145. package/ios/tabs/extensions/RNSTabsHostComponentView+RNSImageLoader.h +1 -1
  146. package/ios/tabs/host/RNSTabsHostComponentView.h +2 -0
  147. package/ios/tabs/host/RNSTabsHostComponentView.mm +10 -3
  148. package/ios/tabs/host/RNSTabsHostEventEmitter.mm +1 -1
  149. package/ios/tabs/screen/RNSTabsScreenComponentView.mm +20 -5
  150. package/ios/utils/RNSDefines.h +3 -0
  151. package/lib/commonjs/components/stack/header/StackHeaderConfig.android.js +34 -19
  152. package/lib/commonjs/components/stack/header/StackHeaderConfig.android.js.map +1 -1
  153. package/lib/commonjs/components/stack/header/StackHeaderConfig.ios.js +33 -1
  154. package/lib/commonjs/components/stack/header/StackHeaderConfig.ios.js.map +1 -1
  155. package/lib/commonjs/components/stack/host/StackHost.js +9 -6
  156. package/lib/commonjs/components/stack/host/StackHost.js.map +1 -1
  157. package/lib/commonjs/components/stack/index.js.map +1 -1
  158. package/lib/commonjs/components/tabs/host/TabsHost.ios.js +1 -0
  159. package/lib/commonjs/components/tabs/host/TabsHost.ios.js.map +1 -1
  160. package/lib/commonjs/fabric/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
  161. package/lib/commonjs/fabric/stack/StackHeaderConfigIOSNativeComponent.js.map +1 -1
  162. package/lib/commonjs/fabric/stack/StackHeaderItemIOSNativeComponent.js.map +1 -1
  163. package/lib/commonjs/fabric/stack/StackHostNativeComponent.js.map +1 -1
  164. package/lib/commonjs/fabric/tabs/TabsHostIOSNativeComponent.js.map +1 -1
  165. package/lib/module/components/stack/header/StackHeaderConfig.android.js +35 -20
  166. package/lib/module/components/stack/header/StackHeaderConfig.android.js.map +1 -1
  167. package/lib/module/components/stack/header/StackHeaderConfig.ios.js +34 -2
  168. package/lib/module/components/stack/header/StackHeaderConfig.ios.js.map +1 -1
  169. package/lib/module/components/stack/host/StackHost.js +9 -6
  170. package/lib/module/components/stack/host/StackHost.js.map +1 -1
  171. package/lib/module/components/stack/index.js.map +1 -1
  172. package/lib/module/components/tabs/host/TabsHost.ios.js +1 -0
  173. package/lib/module/components/tabs/host/TabsHost.ios.js.map +1 -1
  174. package/lib/module/fabric/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
  175. package/lib/module/fabric/stack/StackHeaderConfigIOSNativeComponent.js.map +1 -1
  176. package/lib/module/fabric/stack/StackHeaderItemIOSNativeComponent.js.map +1 -1
  177. package/lib/module/fabric/stack/StackHostNativeComponent.js.map +1 -1
  178. package/lib/module/fabric/tabs/TabsHostIOSNativeComponent.js.map +1 -1
  179. package/lib/typescript/components/modals/form-sheet/FormSheet.types.d.ts +1 -1
  180. package/lib/typescript/components/stack/header/StackHeaderConfig.android.d.ts.map +1 -1
  181. package/lib/typescript/components/stack/header/StackHeaderConfig.android.types.d.ts +616 -21
  182. package/lib/typescript/components/stack/header/StackHeaderConfig.android.types.d.ts.map +1 -1
  183. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.d.ts.map +1 -1
  184. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.types.d.ts +226 -2
  185. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.types.d.ts.map +1 -1
  186. package/lib/typescript/components/stack/header/StackHeaderConfig.types.d.ts +2 -2
  187. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.types.d.ts +2 -0
  188. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.types.d.ts.map +1 -1
  189. package/lib/typescript/components/stack/host/StackHost.d.ts +1 -1
  190. package/lib/typescript/components/stack/host/StackHost.d.ts.map +1 -1
  191. package/lib/typescript/components/stack/host/StackHost.types.d.ts +24 -0
  192. package/lib/typescript/components/stack/host/StackHost.types.d.ts.map +1 -1
  193. package/lib/typescript/components/stack/index.d.ts +2 -2
  194. package/lib/typescript/components/stack/index.d.ts.map +1 -1
  195. package/lib/typescript/components/tabs/host/TabsHost.ios.d.ts.map +1 -1
  196. package/lib/typescript/components/tabs/host/TabsHost.ios.types.d.ts +16 -0
  197. package/lib/typescript/components/tabs/host/TabsHost.ios.types.d.ts.map +1 -1
  198. package/lib/typescript/components/tabs/host/TabsHost.types.d.ts +3 -0
  199. package/lib/typescript/components/tabs/host/TabsHost.types.d.ts.map +1 -1
  200. package/lib/typescript/fabric/stack/StackHeaderConfigAndroidNativeComponent.d.ts +52 -0
  201. package/lib/typescript/fabric/stack/StackHeaderConfigAndroidNativeComponent.d.ts.map +1 -1
  202. package/lib/typescript/fabric/stack/StackHeaderConfigIOSNativeComponent.d.ts +25 -1
  203. package/lib/typescript/fabric/stack/StackHeaderConfigIOSNativeComponent.d.ts.map +1 -1
  204. package/lib/typescript/fabric/stack/StackHeaderItemIOSNativeComponent.d.ts +2 -0
  205. package/lib/typescript/fabric/stack/StackHeaderItemIOSNativeComponent.d.ts.map +1 -1
  206. package/lib/typescript/fabric/stack/StackHostNativeComponent.d.ts +3 -1
  207. package/lib/typescript/fabric/stack/StackHostNativeComponent.d.ts.map +1 -1
  208. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts +1 -0
  209. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts.map +1 -1
  210. package/package.json +8 -7
  211. package/react-native.config.js +3 -0
  212. package/src/components/modals/form-sheet/FormSheet.types.ts +1 -1
  213. package/src/components/stack/header/StackHeaderConfig.android.tsx +48 -23
  214. package/src/components/stack/header/StackHeaderConfig.android.types.ts +637 -21
  215. package/src/components/stack/header/StackHeaderConfig.ios.tsx +45 -1
  216. package/src/components/stack/header/StackHeaderConfig.ios.types.ts +238 -2
  217. package/src/components/stack/header/StackHeaderConfig.types.ts +2 -2
  218. package/src/components/stack/header/ios/StackHeaderItem.ios.types.ts +2 -0
  219. package/src/components/stack/host/StackHost.tsx +4 -2
  220. package/src/components/stack/host/StackHost.types.ts +26 -0
  221. package/src/components/stack/index.ts +6 -1
  222. package/src/components/tabs/host/TabsHost.ios.tsx +1 -0
  223. package/src/components/tabs/host/TabsHost.ios.types.ts +16 -0
  224. package/src/components/tabs/host/TabsHost.types.ts +3 -0
  225. package/src/fabric/stack/StackHeaderConfigAndroidNativeComponent.ts +78 -0
  226. package/src/fabric/stack/StackHeaderConfigIOSNativeComponent.ts +32 -0
  227. package/src/fabric/stack/StackHeaderItemIOSNativeComponent.ts +2 -0
  228. package/src/fabric/stack/StackHostNativeComponent.ts +11 -2
  229. package/src/fabric/tabs/TabsHostIOSNativeComponent.ts +1 -0
  230. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingView.kt +0 -83
  231. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingViewManager.kt +0 -89
  232. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingViewPointerEvents.kt +0 -18
  233. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuSelectionController.kt +0 -83
  234. package/ios/conversion/RNSConversions-Stack.h +0 -32
  235. package/ios/conversion/RNSConversions-Stack.mm +0 -41
  236. package/ios/conversion/always_false.h +0 -31
  237. /package/ios/{conversion → scroll-view-marker/conversion}/RNSConversions-ScrollViewMarker.h +0 -0
@@ -4,63 +4,56 @@ import android.view.ViewGroup
4
4
  import android.widget.FrameLayout
5
5
  import androidx.core.view.ViewCompat
6
6
  import androidx.core.view.WindowInsetsCompat
7
- import androidx.core.view.doOnLayout
8
- import com.google.android.material.bottomsheet.BottomSheetDialog
7
+ import com.swmansion.rnscreens.modals.formsheet.native.core.FormSheetAvailableHeightProvider
9
8
  import com.swmansion.rnscreens.modals.formsheet.native.core.FormSheetContainer
9
+ import com.swmansion.rnscreens.modals.formsheet.native.core.FormSheetDialog
10
10
  import com.swmansion.rnscreens.modals.formsheet.native.interfaces.FormSheetContentSizeChangeDelegate
11
11
  import com.swmansion.rnscreens.modals.formsheet.native.model.FormSheetDetents
12
12
 
13
13
  internal class FormSheetDimensionsCoordinator(
14
- private val dialog: BottomSheetDialog,
14
+ private val dialog: FormSheetDialog,
15
15
  private val container: FormSheetContainer,
16
- private val bottomSheetView: FrameLayout?,
17
16
  private val behaviorController: FormSheetBehaviorController?,
18
- ) : FormSheetContentSizeChangeDelegate {
17
+ ) : FormSheetContentSizeChangeDelegate,
18
+ FormSheetAvailableHeightProvider.OnAvailableHeightMeasuredListener {
19
19
  private var lastTopInset = 0
20
20
  private var lastBottomInset = 0
21
+ private var lastImeInset = 0
21
22
  private var currentDetents: FormSheetDetents? = null
22
23
  private var currentInitialDetentIndex: Int = 0
23
24
  private var shouldApplyInitialDetent: Boolean = false
24
25
 
25
26
  private var currentContentHeight: Int = 0
26
27
 
28
+ // Height the metrics were last resolved against. Any other value reported by the measure pass
29
+ // means the window has been resized and metrics have to be recomputed.
30
+ private var resolvedAvailableSpace: Int = 0
31
+ private var isGeometryDirty: Boolean = false
32
+
27
33
  internal fun setup() {
34
+ dialog.availableHeightProvider.availableHeightListener = this
28
35
  setupWindowInsetsListener()
29
-
30
- bottomSheetView?.let { view ->
31
- disableMaterialInsetsAnimationCallback(view)
32
- }
33
36
  }
34
37
 
35
38
  private fun setupWindowInsetsListener() {
36
39
  ViewCompat.setOnApplyWindowInsetsListener(container) { _, insets ->
37
- lastTopInset = getTopInset(insets)
38
- lastBottomInset = getBottomInset(insets)
39
- updateNativeContainerHeight()
40
+ val topInset = getTopInset(insets)
41
+ val bottomInset = getBottomInset(insets)
42
+ val imeInset = getImeInset(insets)
43
+ if (topInset != lastTopInset || bottomInset != lastBottomInset || imeInset != lastImeInset) {
44
+ lastTopInset = topInset
45
+ lastBottomInset = bottomInset
46
+ lastImeInset = imeInset
47
+ invalidateGeometry()
48
+ }
40
49
  insets
41
50
  }
42
51
  }
43
52
 
44
- /**
45
- * BottomSheetBehavior registers an internal `WindowInsetsAnimationCallback` on the
46
- * sheet view during its first `onLayoutChild`. That callback drives `translationY` to follow
47
- * animated inset changes, what interferes with our slide-in custom animation.
48
- *
49
- * We manage insets ourselves by setting a fixed height for FormSheetContainer, so we can
50
- * clear the Material's callback to remove the conflict entirely.
51
- *
52
- * This method must run after the first layout pass.
53
- */
54
- private fun disableMaterialInsetsAnimationCallback(view: FrameLayout) {
55
- view.doOnLayout {
56
- ViewCompat.setWindowInsetsAnimationCallback(it, null)
57
- }
58
- }
59
-
60
53
  override fun onContentHeightChanged(newHeight: Int) {
61
54
  if (currentContentHeight != newHeight) {
62
55
  currentContentHeight = newHeight
63
- updateNativeContainerHeight()
56
+ invalidateGeometry()
64
57
  }
65
58
  }
66
59
 
@@ -72,7 +65,25 @@ internal class FormSheetDimensionsCoordinator(
72
65
  currentDetents = detents
73
66
  currentInitialDetentIndex = initialDetentIndex
74
67
  shouldApplyInitialDetent = applyInitialDetent
75
- updateNativeContainerHeight()
68
+ invalidateGeometry()
69
+ }
70
+
71
+ // Schedules a measure pass; the metrics are resolved from there. The provider is a sibling of the sheet
72
+ // subtree, not an ancestor, so it has to be asked for a re-measure explicitly. No-op while the dialog
73
+ // is not shown - the first traversal after `show()` measures everything anyway.
74
+ private fun invalidateGeometry() {
75
+ isGeometryDirty = true
76
+ dialog.availableHeightProvider.requestLayout()
77
+ container.requestLayout()
78
+ }
79
+
80
+ override fun onAvailableHeightMeasured(height: Int) {
81
+ if (!isGeometryDirty && height == resolvedAvailableSpace) {
82
+ return
83
+ }
84
+ isGeometryDirty = false
85
+ resolvedAvailableSpace = height
86
+ resolveGeometry(height)
76
87
  }
77
88
 
78
89
  /**
@@ -81,20 +92,18 @@ internal class FormSheetDimensionsCoordinator(
81
92
  * status bar or display cutout. This causes Yoga to recalculate the layout, resulting in UI flickering
82
93
  * during the drag gesture. By calculating and enforcing a static height that explicitly subtracts
83
94
  * the system insets, we completely bypass these redundant layout passes.
95
+ *
96
+ * Runs inside the measure pass of `FormSheetAvailableHeightProvider`, i.e. before Material's container, the sheet and
97
+ * our container are measured, so the values applied here are picked up by the very same traversal.
84
98
  */
85
- private fun updateNativeContainerHeight() {
86
- val dialogDecorHeight = dialog.window?.decorView?.height ?: 0
87
-
88
- if (dialogDecorHeight <= 0) {
89
- return
90
- }
91
-
99
+ private fun resolveGeometry(sheetAvailableSpace: Int) {
92
100
  currentDetents?.let { detents ->
93
101
  behaviorController?.updateSheetBehavior(
94
102
  detents = detents,
95
- sheetAvailableSpace = dialogDecorHeight,
103
+ sheetAvailableSpace = sheetAvailableSpace,
96
104
  contentHeightForFitToContents = currentContentHeight,
97
105
  nativeContainerPaddingBottom = lastBottomInset,
106
+ keyboardLift = keyboardLift,
98
107
  initialDetentIndex = currentInitialDetentIndex,
99
108
  applyInitialDetent = shouldApplyInitialDetent,
100
109
  )
@@ -102,8 +111,13 @@ internal class FormSheetDimensionsCoordinator(
102
111
  }
103
112
 
104
113
  val sheetContainerHeight =
105
- currentDetents?.sheetContainerHeight(dialogDecorHeight, lastTopInset, lastBottomInset, currentContentHeight)
106
- ?: (dialogDecorHeight - lastTopInset - lastBottomInset).coerceAtLeast(0)
114
+ currentDetents?.sheetContainerHeight(
115
+ sheetAvailableSpace,
116
+ lastTopInset,
117
+ lastBottomInset,
118
+ currentContentHeight,
119
+ keyboardLift,
120
+ ) ?: (sheetAvailableSpace - lastTopInset - lastBottomInset - keyboardLift).coerceAtLeast(0)
107
121
 
108
122
  val layoutParams =
109
123
  container.layoutParams
@@ -116,6 +130,16 @@ internal class FormSheetDimensionsCoordinator(
116
130
  }
117
131
  }
118
132
 
133
+ /**
134
+ * The part of the keyboard inset that sticks out above the bottom system inset. Material pads the sheet by
135
+ * the larger of the two, so this is exactly how much the sheet has to be extended to keep its detent-sized
136
+ * part above the keyboard.
137
+ */
138
+ private val keyboardLift: Int
139
+ get() = (lastImeInset - lastBottomInset).coerceAtLeast(0)
140
+
141
+ private fun getImeInset(insetsCompat: WindowInsetsCompat): Int = insetsCompat.getInsets(WindowInsetsCompat.Type.ime()).bottom
142
+
119
143
  private fun getTopInset(insetsCompat: WindowInsetsCompat): Int =
120
144
  insetsCompat
121
145
  .getInsets(
@@ -129,6 +153,7 @@ internal class FormSheetDimensionsCoordinator(
129
153
  ).bottom
130
154
 
131
155
  internal fun destroy() {
156
+ dialog.availableHeightProvider.availableHeightListener = null
132
157
  ViewCompat.setOnApplyWindowInsetsListener(container, null)
133
158
  }
134
159
  }
@@ -0,0 +1,101 @@
1
+ package com.swmansion.rnscreens.modals.formsheet.native.coordinator
2
+
3
+ import android.widget.FrameLayout
4
+ import androidx.core.view.ViewCompat
5
+ import androidx.core.view.WindowInsetsAnimationCompat
6
+ import androidx.core.view.WindowInsetsCompat
7
+ import androidx.core.view.doOnLayout
8
+
9
+ internal class FormSheetKeyboardCoordinator(
10
+ private val bottomSheetView: FrameLayout,
11
+ ) {
12
+ /**
13
+ * Whether the sheet should track the keyboard animation. Kept `false` while an enter / exit
14
+ * transition owns `translationY`. Tracking the keyboard (`true`) should be allowed only when
15
+ * the sheet is in PRESENTED state.
16
+ */
17
+ internal var isTrackingEnabled: Boolean = false
18
+
19
+ private val insetsAnimationCallback = KeyboardInsetsAnimationCallback()
20
+
21
+ internal fun setup() {
22
+ // BottomSheetBehavior registers an internal `WindowInsetsAnimationCallback` on the
23
+ // sheet view during its first `onLayoutChild`. That callback drives `translationY` to track
24
+ // animated inset changes, what interferes with our slide-in custom animation.
25
+ //
26
+ // We manage insets ourselves by setting a fixed height for FormSheetContainer, so we can
27
+ // clear the Material's callback to remove the conflict entirely.
28
+ //
29
+ // This method must run after the first layout pass.
30
+ bottomSheetView.doOnLayout {
31
+ ViewCompat.setWindowInsetsAnimationCallback(it, insetsAnimationCallback)
32
+ }
33
+ }
34
+
35
+ internal fun destroy() {
36
+ ViewCompat.setWindowInsetsAnimationCallback(bottomSheetView, null)
37
+ }
38
+
39
+ private inner class KeyboardInsetsAnimationCallback : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {
40
+ private var startTop = 0
41
+ private var startTranslationY = 0f
42
+
43
+ // Decided once per keyboard animation, in `onPrepare`. Tracking can't be picked up mid-animation
44
+ // because of no start position to translate from.
45
+ private var isTracking = false
46
+
47
+ private val isActive: Boolean
48
+ get() = isTracking && isTrackingEnabled
49
+
50
+ override fun onPrepare(animation: WindowInsetsAnimationCompat) {
51
+ if (!animation.isKeyboardAnimation() || !isTrackingEnabled) {
52
+ return
53
+ }
54
+
55
+ // Saving sheet's position before applying keyboard insets.
56
+ startTop = bottomSheetView.top
57
+ isTracking = true
58
+ }
59
+
60
+ override fun onStart(
61
+ animation: WindowInsetsAnimationCompat,
62
+ bounds: WindowInsetsAnimationCompat.BoundsCompat,
63
+ ): WindowInsetsAnimationCompat.BoundsCompat {
64
+ if (!animation.isKeyboardAnimation() || !isActive) {
65
+ return bounds
66
+ }
67
+
68
+ // The end sheet position is known - move the sheet and let the animation progress
69
+ // bring it to the new position.
70
+ startTranslationY = (startTop - bottomSheetView.top).toFloat()
71
+ bottomSheetView.translationY = startTranslationY
72
+ return bounds
73
+ }
74
+
75
+ override fun onProgress(
76
+ insets: WindowInsetsCompat,
77
+ runningAnimations: List<WindowInsetsAnimationCompat>,
78
+ ): WindowInsetsCompat {
79
+ if (!isActive) {
80
+ return insets
81
+ }
82
+
83
+ val keyboardAnimation = runningAnimations.firstOrNull { it.isKeyboardAnimation() } ?: return insets
84
+ bottomSheetView.translationY = startTranslationY * (1f - keyboardAnimation.interpolatedFraction)
85
+ return insets
86
+ }
87
+
88
+ override fun onEnd(animation: WindowInsetsAnimationCompat) {
89
+ if (!animation.isKeyboardAnimation()) {
90
+ return
91
+ }
92
+
93
+ if (isActive) {
94
+ bottomSheetView.translationY = 0f
95
+ }
96
+ isTracking = false
97
+ }
98
+
99
+ private fun WindowInsetsAnimationCompat.isKeyboardAnimation(): Boolean = typeMask and WindowInsetsCompat.Type.ime() != 0
100
+ }
101
+ }
@@ -1,13 +1,11 @@
1
1
  package com.swmansion.rnscreens.modals.formsheet.native.coordinator
2
2
 
3
3
  import androidx.activity.OnBackPressedCallback
4
- import com.swmansion.rnscreens.modals.dimmingview.DimmingViewManager
5
4
  import com.swmansion.rnscreens.modals.formsheet.native.core.FormSheetDialog
6
5
 
7
6
  internal class FormSheetNativeDismissCoordinator(
8
7
  private val dialog: FormSheetDialog,
9
8
  private val behaviorController: FormSheetBehaviorController?,
10
- private val dimmingManager: DimmingViewManager,
11
9
  private val onDismissAllowed: () -> Unit,
12
10
  private val onDismissPrevented: () -> Unit,
13
11
  ) : FormSheetDialog.CancelRequestInterceptor {
@@ -27,15 +25,11 @@ internal class FormSheetNativeDismissCoordinator(
27
25
  internal fun setup() {
28
26
  dialog.cancelRequestInterceptor = this
29
27
  dialog.onBackPressedDispatcher.addCallback(preventNativeDismissBackPressCallback)
30
- // Backdrop taps go through `cancel()` rather than dismissing directly, so that they are
31
- // subject to the very same interception as the back press and the swipe down.
32
- dimmingManager.setOnBackdropClickListener { dialog.cancel() }
33
28
  }
34
29
 
35
30
  internal fun destroy() {
36
31
  dialog.cancelRequestInterceptor = null
37
32
  preventNativeDismissBackPressCallback.remove()
38
- dimmingManager.setOnBackdropClickListener(null)
39
33
  }
40
34
 
41
35
  override fun handleCancelRequest() {
@@ -0,0 +1,44 @@
1
+ package com.swmansion.rnscreens.modals.formsheet.native.core
2
+
3
+ import android.content.Context
4
+ import android.view.View
5
+
6
+ /**
7
+ * View installed as the first child of the window's `android.R.id.content`, as a sibling
8
+ * of Material's dialog `container` - nothing in Material's hierarchy is moved.
9
+ *
10
+ * Every metric we hand to `BottomSheetBehavior` and the height of [FormSheetContainer] is derived from
11
+ * the height the sheet is measured against. The measure pass is the only point where that height is known
12
+ * *before* the sheet gets measured. `FrameLayout` measures its children in index order, so the provider reports
13
+ * the height right before Material's `container`, the coordinator and the sheet are measured in the same
14
+ * traversal, keeping those values in sync with window resizes, e.g. orientation change.
15
+ */
16
+ internal class FormSheetAvailableHeightProvider(
17
+ context: Context,
18
+ ) : View(context) {
19
+ internal fun interface OnAvailableHeightMeasuredListener {
20
+ /**
21
+ * Invoked at the beginning of every measure pass with the height the sheet is about
22
+ * to be measured against.
23
+ */
24
+ fun onAvailableHeightMeasured(height: Int)
25
+ }
26
+
27
+ internal var availableHeightListener: OnAvailableHeightMeasuredListener? = null
28
+
29
+ init {
30
+ visibility = INVISIBLE
31
+ importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO
32
+ }
33
+
34
+ override fun onMeasure(
35
+ widthMeasureSpec: Int,
36
+ heightMeasureSpec: Int,
37
+ ) {
38
+ val height = MeasureSpec.getSize(heightMeasureSpec)
39
+ if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.UNSPECIFIED && height > 0) {
40
+ availableHeightListener?.onAvailableHeightMeasured(height)
41
+ }
42
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
43
+ }
44
+ }
@@ -2,6 +2,7 @@ package com.swmansion.rnscreens.modals.formsheet.native.core
2
2
 
3
3
  import android.content.Context
4
4
  import android.os.Bundle
5
+ import android.util.Log
5
6
  import android.view.View
6
7
  import android.view.ViewGroup
7
8
  import android.view.Window
@@ -14,8 +15,8 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
14
15
  * A custom BottomSheetDialog override used to render the FormSheet native component.
15
16
  *
16
17
  * We enforce edge-to-edge rendering, bypassing standard Material checks.
17
- * This enforcement is required because our custom dimming view must span the entire screen.
18
- * The FormSheetContainer is sized manually against the system insets.
18
+ * This is required because our custom dimming logic needs the Dialog to span
19
+ * the entire screen. The FormSheetContainer is sized manually against the system insets.
19
20
  */
20
21
  internal class FormSheetDialog(
21
22
  context: Context,
@@ -33,6 +34,12 @@ internal class FormSheetDialog(
33
34
 
34
35
  internal var cancelRequestInterceptor: CancelRequestInterceptor? = null
35
36
 
37
+ /**
38
+ * Installed next to Material's content once the dialog is created. Reports the height the sheet
39
+ * is measured against so the sheet metrics can be resolved before the sheet itself is measured.
40
+ */
41
+ internal val availableHeightProvider = FormSheetAvailableHeightProvider(context)
42
+
36
43
  override fun onCreate(savedInstanceState: Bundle?) {
37
44
  super.onCreate(savedInstanceState)
38
45
 
@@ -40,6 +47,7 @@ internal class FormSheetDialog(
40
47
  disableNativeWindowAnimation(window)
41
48
 
42
49
  setupBottomSheetHeight()
50
+ installAvailableHeightProvider()
43
51
  }
44
52
 
45
53
  override fun onAttachedToWindow() {
@@ -63,7 +71,8 @@ internal class FormSheetDialog(
63
71
  * `enableEdgeToEdge` attribute AND the navigation bar is translucent (see
64
72
  * `BottomSheetDialog#onAttachedToWindow`).
65
73
  *
66
- * We force edge-to-edge on every API level so the custom dimming view covers the whole screen.
74
+ * We force edge-to-edge on every API level so the window content always spans the whole
75
+ * screen.
67
76
  */
68
77
  private fun forceEdgeToEdge() {
69
78
  val window = window ?: return
@@ -80,4 +89,27 @@ internal class FormSheetDialog(
80
89
  val bottomSheetView = findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
81
90
  bottomSheetView?.layoutParams?.height = ViewGroup.LayoutParams.MATCH_PARENT
82
91
  }
92
+
93
+ private fun installAvailableHeightProvider() {
94
+ if (availableHeightProvider.parent != null) {
95
+ return
96
+ }
97
+
98
+ val contentParent = findViewById<ViewGroup>(android.R.id.content)
99
+ if (contentParent == null) {
100
+ Log.e(TAG, "[RNScreens] Window content view not found; the sheet dimensions won't be resolved.")
101
+ return
102
+ }
103
+
104
+ // FrameLayout measures its children in order, so the provider reports the height before Material's container
105
+ contentParent.addView(
106
+ availableHeightProvider,
107
+ 0,
108
+ FrameLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT),
109
+ )
110
+ }
111
+
112
+ companion object {
113
+ private const val TAG = "FormSheetDialog"
114
+ }
83
115
  }
@@ -1,19 +1,13 @@
1
1
  package com.swmansion.rnscreens.modals.formsheet.native.core
2
2
 
3
3
  import android.content.Context
4
- import android.util.Log
5
4
  import android.view.ContextThemeWrapper
6
5
  import android.view.View
7
- import android.widget.FrameLayout
8
- import com.swmansion.rnscreens.modals.dimmingview.DimmingViewManager
9
- import com.swmansion.rnscreens.modals.formsheet.native.coordinator.FormSheetAppearanceCoordinator
10
- import com.swmansion.rnscreens.modals.formsheet.native.coordinator.FormSheetBehaviorController
11
- import com.swmansion.rnscreens.modals.formsheet.native.coordinator.FormSheetDimensionsCoordinator
12
- import com.swmansion.rnscreens.modals.formsheet.native.coordinator.FormSheetNativeDismissCoordinator
13
6
  import com.swmansion.rnscreens.modals.formsheet.native.interfaces.FormSheetContentSizeChangeDelegate
14
7
  import com.swmansion.rnscreens.modals.formsheet.native.interfaces.FormSheetDialogEventEmitter
15
8
  import com.swmansion.rnscreens.modals.formsheet.native.model.FormSheetConfig
16
- import com.swmansion.rnscreens.modals.formsheet.native.model.FormSheetDetents
9
+ import com.swmansion.rnscreens.modals.formsheet.native.presentation.FormSheetDimmingManager
10
+ import com.swmansion.rnscreens.modals.formsheet.native.presentation.FormSheetPresentation
17
11
  import com.swmansion.rnscreens.modals.formsheet.native.presentation.FormSheetPresentationManager
18
12
  import kotlin.properties.Delegates
19
13
 
@@ -32,131 +26,64 @@ class FormSheetDialogManager(
32
26
  // Eagerly create the container so it's always ready for the provided content view
33
27
  private val container = FormSheetContainer(themedContext, contentView)
34
28
 
35
- // Eagerly create the dialog and attach the container
36
- private val dialog =
37
- FormSheetDialog(themedContext).apply {
38
- setContentView(container)
39
- setCanceledOnTouchOutside(false)
40
- }
41
-
42
- private val bottomSheetView = dialog.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
29
+ // The React content only reports height changes, so a new presentation is seeded with the
30
+ // last known value.
31
+ private var lastContentHeight = 0
43
32
 
44
- private val behaviorController =
45
- bottomSheetView?.let {
46
- FormSheetBehaviorController(it) { index -> eventEmitter?.emitOnDetentChanged(index) }
47
- }
33
+ private val presentationCallbacks =
34
+ object : FormSheetPresentation.Callbacks {
35
+ override fun onDetentChanged(index: Int) {
36
+ eventEmitter?.emitOnDetentChanged(index)
37
+ }
48
38
 
49
- private val dimmingManager = DimmingViewManager(context, dialog)
39
+ override fun onNativeDismissAllowed() {
40
+ presentationManager.handleNativeDismiss()
41
+ }
50
42
 
51
- private val appearanceCoordinator =
52
- FormSheetAppearanceCoordinator(
53
- bottomSheetView = bottomSheetView,
54
- )
43
+ override fun onNativeDismissPrevented() {
44
+ eventEmitter?.emitOnNativeDismissPreventedEvent()
45
+ }
46
+ }
55
47
 
56
- private val dimensionsCoordinator =
57
- FormSheetDimensionsCoordinator(
58
- dialog = dialog,
59
- container = container,
60
- bottomSheetView = bottomSheetView,
61
- behaviorController = behaviorController,
62
- )
48
+ private val dimmingManager = FormSheetDimmingManager(context)
63
49
 
64
50
  private val presentationManager =
65
51
  FormSheetPresentationManager(
66
- dialog = dialog,
67
- bottomSheetView = bottomSheetView,
52
+ presentationFactory = ::createPresentation,
68
53
  dimmingManager = dimmingManager,
69
54
  onNativeDismiss = { eventEmitter?.emitOnNativeDismissEvent() },
70
- )
71
-
72
- private val nativeDismissCoordinator =
73
- FormSheetNativeDismissCoordinator(
74
- dialog = dialog,
75
- behaviorController = behaviorController,
76
- dimmingManager = dimmingManager,
77
- onDismissAllowed = { presentationManager.handleNativeDismiss() },
78
- onDismissPrevented = { eventEmitter?.emitOnNativeDismissPreventedEvent() },
55
+ onDismiss = { eventEmitter?.emitOnDismissEvent() },
79
56
  )
80
57
 
81
58
  internal var eventEmitter: FormSheetDialogEventEmitter? by Delegates.observable(null) { _, _, newValue ->
82
59
  presentationManager.appearanceEventEmitter = newValue
83
60
  }
84
61
 
85
- internal val contentSizeChangeDelegate: FormSheetContentSizeChangeDelegate
86
- get() = dimensionsCoordinator
62
+ internal val contentSizeChangeDelegate: FormSheetContentSizeChangeDelegate =
63
+ object : FormSheetContentSizeChangeDelegate {
64
+ override fun onContentHeightChanged(newHeight: Int) {
65
+ lastContentHeight = newHeight
66
+ presentationManager.currentPresentation?.onContentHeightChanged(newHeight)
67
+ }
68
+ }
87
69
 
88
- init {
89
- presentationManager.setup()
90
- nativeDismissCoordinator.setup()
91
- appearanceCoordinator.setup()
92
- dimensionsCoordinator.setup()
93
- behaviorController?.setup()
94
- }
70
+ private fun createPresentation(): FormSheetPresentation =
71
+ FormSheetPresentation(themedContext, container, presentationCallbacks).also {
72
+ it.applyInitialConfig(formSheetConfig, lastContentHeight)
73
+ }
95
74
 
96
75
  internal fun applyConfig(newConfig: FormSheetConfig) {
97
76
  val oldConfig = formSheetConfig
98
77
  formSheetConfig = newConfig
99
78
 
100
- val reopened = !oldConfig.isOpen && newConfig.isOpen
101
-
102
- // ALWAYS refresh dimensions when reopening to ensure that BottomSheet
103
- // state and layout are synchronized with native behavior.
104
- val dimensionsChanged = oldConfig.detents != newConfig.detents
105
- if (dimensionsChanged || reopened) {
106
- dimensionsCoordinator.updateFormSheetDimensions(
107
- resolveDetents(newConfig.detents),
108
- newConfig.initialDetentIndex,
109
- reopened,
110
- )
111
- }
112
-
113
- if (oldConfig.prefersGrabberVisible != newConfig.prefersGrabberVisible) {
114
- container.setGrabberVisible(newConfig.prefersGrabberVisible)
115
- }
116
-
117
- if (oldConfig.preferredCornerRadius != newConfig.preferredCornerRadius) {
118
- appearanceCoordinator.updateCornerRadius(newConfig.preferredCornerRadius)
119
- }
120
-
121
- if (oldConfig.nativeContainerBackgroundColor != newConfig.nativeContainerBackgroundColor) {
122
- appearanceCoordinator.updateBackgroundColor(newConfig.nativeContainerBackgroundColor)
123
- }
124
-
125
- if (oldConfig.shouldPreventNativeDismiss != newConfig.shouldPreventNativeDismiss) {
126
- nativeDismissCoordinator.shouldPreventDismiss = newConfig.shouldPreventNativeDismiss
127
- }
79
+ presentationManager.currentPresentation?.applyConfigUpdate(oldConfig, newConfig)
128
80
 
129
81
  if (oldConfig.isOpen != newConfig.isOpen) {
130
- presentationManager.updatePresentationState(newConfig.isOpen)
131
- }
132
- }
133
-
134
- private fun resolveDetents(rawDetents: List<Double>): FormSheetDetents {
135
- if (rawDetents.isEmpty()) {
136
- return FormSheetDetents(listOf(LARGE_DETENT_FRACTION))
137
- }
138
-
139
- return try {
140
- FormSheetDetents(rawDetents)
141
- } catch (e: IllegalArgumentException) {
142
- Log.e(
143
- "[RNScreens]",
144
- "Invalid FormSheet detents: $rawDetents. Falling back to large detent.",
145
- e,
146
- )
147
- FormSheetDetents(listOf(LARGE_DETENT_FRACTION))
82
+ presentationManager.requestProgrammaticStateUpdate(newConfig.isOpen)
148
83
  }
149
84
  }
150
85
 
151
86
  internal fun destroy() {
152
- behaviorController?.destroy()
153
- nativeDismissCoordinator.destroy()
154
87
  presentationManager.destroy()
155
- dimensionsCoordinator.destroy()
156
- dialog.dismiss()
157
- }
158
-
159
- companion object {
160
- private const val LARGE_DETENT_FRACTION = 1.0
161
88
  }
162
89
  }
@@ -3,6 +3,8 @@ package com.swmansion.rnscreens.modals.formsheet.native.interfaces
3
3
  import com.swmansion.rnscreens.common.event.ViewAppearanceEventEmitter
4
4
 
5
5
  internal interface FormSheetDialogEventEmitter : ViewAppearanceEventEmitter {
6
+ fun emitOnDismissEvent()
7
+
6
8
  fun emitOnNativeDismissEvent()
7
9
 
8
10
  fun emitOnNativeDismissPreventedEvent()