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
@@ -12,176 +12,32 @@ import com.swmansion.rnscreens.stack.header.getResizedDrawable
12
12
  import com.swmansion.rnscreens.stack.header.toolbar.model.StackHeaderToolbarMenuConfig
13
13
  import com.swmansion.rnscreens.stack.header.toolbar.model.StackHeaderToolbarMenuElementConfig
14
14
  import com.swmansion.rnscreens.stack.header.toolbar.model.StackHeaderToolbarMenuGroupConfig
15
- import com.swmansion.rnscreens.stack.header.toolbar.model.StackHeaderToolbarMenuGroupMetadata
16
- import com.swmansion.rnscreens.stack.header.toolbar.model.StackHeaderToolbarMenuItemConfig
17
- import com.swmansion.rnscreens.stack.header.toolbar.model.StackHeaderToolbarMenuItemType
15
+ import com.swmansion.rnscreens.stack.header.toolbar.model.StackHeaderToolbarMenuModel
18
16
  import com.swmansion.rnscreens.stack.header.toolbar.update.StackHeaderToolbarFieldUpdate
19
17
  import com.swmansion.rnscreens.stack.header.toolbar.update.StackHeaderToolbarMenuElementOptions
20
18
  import com.swmansion.rnscreens.stack.header.toolbar.update.valueOrNull
21
19
 
22
20
  /**
23
- * Builds the toolbar menu from its config and applies in-place element updates
24
- * (options, checkability, icon tint).
21
+ * Writes onto the android Menu: builds the toolbar menu from its model and
22
+ * applies in-place element updates (options, checkability, icon tint).
25
23
  */
26
24
  internal object StackHeaderToolbarMenuApplicator {
27
- // region Mappings & metadata
28
-
29
- internal fun generateToolbarMenuItemMappings(menuConfig: StackHeaderToolbarMenuConfig): Pair<Map<String, Int>, Map<Int, String>> {
30
- val forwardIdMap = mutableMapOf<String, Int>()
31
- val reverseIdMap = mutableMapOf<Int, String>()
32
- var counter = 1
33
- assignElementIds(menuConfig.children, forwardIdMap, reverseIdMap) { counter++ }
34
- return Pair(forwardIdMap.toMap(), reverseIdMap.toMap())
35
- }
36
-
37
- internal fun generateToolbarMenuGroupMappings(menuConfig: StackHeaderToolbarMenuConfig): Map<String, Int> {
38
- val forwardGroupIdMap = mutableMapOf<String, Int>()
39
- var counter = 1
40
- assignGroupIds(menuConfig, forwardGroupIdMap) { counter++ }
41
- return forwardGroupIdMap.toMap()
42
- }
43
-
44
- internal fun computeGroupMetadata(menuConfig: StackHeaderToolbarMenuConfig): StackHeaderToolbarMenuGroupMetadata {
45
- val itemGroupMap = mutableMapOf<String, String>()
46
- val groupSingleSelection = mutableMapOf<String, Boolean>()
47
- val groupMemberItems = mutableMapOf<String, MutableList<String>>()
48
- collectGroupMetadata(menuConfig, itemGroupMap, groupSingleSelection, groupMemberItems)
49
- return StackHeaderToolbarMenuGroupMetadata(
50
- itemGroupMap,
51
- groupSingleSelection,
52
- groupMemberItems.mapValues { it.value.toList() },
53
- )
54
- }
55
-
56
- internal fun validateRadioInitialSelection(menuConfig: StackHeaderToolbarMenuConfig) {
57
- for (group in menuConfig.groups) {
58
- if (!group.singleSelection) continue
59
- var count = 0
60
- for (element in menuConfig.children) {
61
- if (element.item.groupId == group.groupId && element.item.initialToggleState) {
62
- count++
63
- }
64
- }
65
- require(count <= 1) {
66
- "[RNScreens] Radio group '${group.groupId}' has $count items with " +
67
- "initialToggleState=true. At most 1 is allowed for single-selection groups."
68
- }
69
- }
70
- for (element in menuConfig.children) {
71
- if (element is StackHeaderToolbarMenuElementConfig.Submenu) {
72
- validateRadioInitialSelection(element.menu)
73
- }
74
- }
75
- }
76
-
77
- /**
78
- * Recursively traverses menu elements and maps user-friendly string item IDs to integers
79
- * expected by Android.
80
- *
81
- * @param elements List of menu elements.
82
- * @param forwardIdMap Reference to String->Int ID map to which ID entries will be added.
83
- * @param reverseIdMap Reference to Int->String ID map to which ID entries will be added.
84
- * @param nextId Function that returns next ID integer. New unique integer should be returned
85
- * each time the function is called. The function is used to handle recursive
86
- * element traversal.
87
- */
88
- private fun assignElementIds(
89
- elements: List<StackHeaderToolbarMenuElementConfig>,
90
- forwardIdMap: MutableMap<String, Int>,
91
- reverseIdMap: MutableMap<Int, String>,
92
- nextId: () -> Int,
93
- ) {
94
- for (element in elements) {
95
- require(element.item.id !in forwardIdMap) {
96
- "[RNScreens] Duplicate toolbar menu item id: '${element.item.id}'. Item IDs must be unique across the entire menu."
97
- }
98
- val nativeId = nextId()
99
- forwardIdMap[element.item.id] = nativeId
100
- reverseIdMap[nativeId] = element.item.id
101
- if (element is StackHeaderToolbarMenuElementConfig.Submenu) {
102
- assignElementIds(element.menu.children, forwardIdMap, reverseIdMap, nextId)
103
- }
104
- }
105
- }
106
-
107
- /**
108
- * Recursively traverses menu groups and maps user-friendly string group IDs to integers
109
- * expected by Android.
110
- *
111
- * @param menuConfig Menu whose groups — and those of its submenus — will be mapped.
112
- * @param forwardMap Reference to String->Int group ID map to which entries will be added.
113
- * @param nextId Function that returns next ID integer. New unique integer should be returned
114
- * each time the function is called. The function is used to handle recursive
115
- * element traversal.
116
- */
117
- private fun assignGroupIds(
118
- menuConfig: StackHeaderToolbarMenuConfig,
119
- forwardMap: MutableMap<String, Int>,
120
- nextId: () -> Int,
121
- ) {
122
- for (group in menuConfig.groups) {
123
- require(group.groupId !in forwardMap) {
124
- "[RNScreens] Duplicate toolbar menu group id: '${group.groupId}'. Group IDs must be unique across the entire menu."
125
- }
126
- forwardMap[group.groupId] = nextId()
127
- }
128
- for (element in menuConfig.children) {
129
- if (element is StackHeaderToolbarMenuElementConfig.Submenu) {
130
- assignGroupIds(element.menu, forwardMap, nextId)
131
- }
132
- }
133
- }
134
-
135
- private fun collectGroupMetadata(
136
- config: StackHeaderToolbarMenuConfig,
137
- itemGroupMap: MutableMap<String, String>,
138
- groupSingleSelection: MutableMap<String, Boolean>,
139
- groupMemberItems: MutableMap<String, MutableList<String>>,
140
- ) {
141
- val localGroupIds = config.groups.map { it.groupId }.toSet()
142
- for (group in config.groups) {
143
- groupSingleSelection[group.groupId] = group.singleSelection
144
- groupMemberItems.getOrPut(group.groupId) { mutableListOf() }
145
- }
146
- for (element in config.children) {
147
- element.item.groupId?.let { gid ->
148
- require(gid in localGroupIds) {
149
- "[RNScreens] Menu item '${element.item.id}' references group '$gid' " +
150
- "which is not defined at the same menu level. " +
151
- "Groups cannot span submenus."
152
- }
153
- itemGroupMap[element.item.id] = gid
154
- groupMemberItems[gid]!!.add(element.item.id)
155
- }
156
- if (element is StackHeaderToolbarMenuElementConfig.Submenu) {
157
- collectGroupMetadata(element.menu, itemGroupMap, groupSingleSelection, groupMemberItems)
158
- }
159
- }
160
- }
161
-
162
- // endregion
163
-
164
25
  // region Menu build
165
26
 
166
27
  internal fun rebuildToolbarMenu(
167
28
  toolbar: MaterialToolbar,
168
- menuConfig: StackHeaderToolbarMenuConfig,
169
- forwardIdMap: Map<String, Int>,
170
- reverseIdMap: Map<Int, String>,
171
- forwardGroupIdMap: Map<String, Int>,
29
+ model: StackHeaderToolbarMenuModel,
172
30
  groupDividerEnabled: Boolean,
173
- onItemClicked: (id: String, menuItem: MenuItem) -> Unit,
31
+ optionsForItem: (id: String) -> StackHeaderToolbarMenuElementOptions,
32
+ onItemClicked: (id: String) -> Unit,
174
33
  ) {
175
34
  toolbar.menu.clear()
176
- addElements(toolbar, toolbar.menu, menuConfig, forwardIdMap, forwardGroupIdMap)
35
+ addElements(toolbar, toolbar.menu, model.config, model.forwardIdMap, model.forwardGroupIdMap, optionsForItem)
177
36
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
178
37
  toolbar.menu.setGroupDividerEnabled(groupDividerEnabled)
179
38
  }
180
39
  toolbar.setOnMenuItemClickListener { menuItem ->
181
- val stringId = reverseIdMap[menuItem.itemId]
182
- if (stringId != null) {
183
- onItemClicked(stringId, menuItem)
184
- }
40
+ model.reverseIdMap[menuItem.itemId]?.let(onItemClicked)
185
41
  true
186
42
  }
187
43
  }
@@ -192,6 +48,7 @@ internal object StackHeaderToolbarMenuApplicator {
192
48
  menuConfig: StackHeaderToolbarMenuConfig,
193
49
  forwardIdMap: Map<String, Int>,
194
50
  forwardGroupIdMap: Map<String, Int>,
51
+ optionsForItem: (id: String) -> StackHeaderToolbarMenuElementOptions,
195
52
  ) {
196
53
  menuConfig.children.forEachIndexed { index, element ->
197
54
  val itemId =
@@ -205,20 +62,21 @@ internal object StackHeaderToolbarMenuApplicator {
205
62
  when (element) {
206
63
  is StackHeaderToolbarMenuElementConfig.MenuItem -> {
207
64
  val menuItem = menu.add(groupIntId, itemId, index, null)
208
- applyMenuElementOptions(toolbar, menuItem, element.item.toOptions())
209
- applyCheckability(menuItem, element.item)
65
+ applyMenuElementOptions(toolbar, menuItem, optionsForItem(element.item.id))
210
66
  }
211
67
  is StackHeaderToolbarMenuElementConfig.Submenu -> {
212
68
  val subMenu = menu.addSubMenu(groupIntId, itemId, index, null)
213
- applyMenuElementOptions(toolbar, subMenu.item, element.item.toOptions())
214
- element.menuTitle?.let { subMenu.setHeaderTitle(it) }
215
- addElements(toolbar, subMenu, element.menu, forwardIdMap, forwardGroupIdMap)
69
+ applyMenuElementOptions(toolbar, subMenu.item, optionsForItem(element.item.id))
70
+ addElements(toolbar, subMenu, element.menu, forwardIdMap, forwardGroupIdMap, optionsForItem)
216
71
  }
217
72
  }
218
73
  }
219
74
  configureGroupCheckability(menu, menuConfig.groups, forwardGroupIdMap)
220
75
  }
221
76
 
77
+ // Group membership is the only source of checkability (configs are validated
78
+ // up front, see StackHeaderToolbarMenuModel); checked state belongs to the
79
+ // controller, which projects it right after the rebuild.
222
80
  private fun configureGroupCheckability(
223
81
  menu: Menu,
224
82
  groups: List<StackHeaderToolbarMenuGroupConfig>,
@@ -230,34 +88,6 @@ internal object StackHeaderToolbarMenuApplicator {
230
88
  }
231
89
  }
232
90
 
233
- private fun applyCheckability(
234
- menuItem: MenuItem,
235
- itemConfig: StackHeaderToolbarMenuItemConfig,
236
- ) {
237
- val shouldBeCheckable =
238
- when (itemConfig.itemType) {
239
- StackHeaderToolbarMenuItemType.TOGGLE -> {
240
- require(itemConfig.groupId != null) {
241
- "[RNScreens] Menu item '${itemConfig.id}' has itemType=TOGGLE but no groupId. " +
242
- "Toggle items must belong to a group."
243
- }
244
- true
245
- }
246
- StackHeaderToolbarMenuItemType.AUTOMATIC -> itemConfig.groupId != null
247
- StackHeaderToolbarMenuItemType.ACTION -> {
248
- require(itemConfig.groupId == null) {
249
- "[RNScreens] Menu item '${itemConfig.id}' has itemType=ACTION " +
250
- "and belongs to a group. Action items cannot belong to groups."
251
- }
252
- false
253
- }
254
- }
255
- if (shouldBeCheckable) {
256
- menuItem.isCheckable = true
257
- menuItem.isChecked = itemConfig.initialToggleState
258
- }
259
- }
260
-
261
91
  // endregion
262
92
 
263
93
  // region Element updates
@@ -291,11 +121,6 @@ internal object StackHeaderToolbarMenuApplicator {
291
121
  }
292
122
  options.hidden?.let { menuItem.isVisible = !it }
293
123
  options.disabled?.let { menuItem.isEnabled = !it }
294
- options.showAsAction?.let { menuItem.setShowAsAction(it.toNativeShowAsAction()) }
295
-
296
- // checked is intentionally not handled here. The coordinator layout manages it in
297
- // applyGroupItemStateChange because toggling checked state requires group metadata
298
- // (radio vs checkbox) and may emit onGroupSelectionChanged events.
299
124
 
300
125
  options.icon?.let {
301
126
  when (it) {
@@ -305,8 +130,11 @@ internal object StackHeaderToolbarMenuApplicator {
305
130
  }
306
131
  }
307
132
 
133
+ // The tint list is built absolutely from the given fields, so whenever
134
+ // this branch runs the caller must pass all four tint slots resolved
135
+ // (Set/Reset) — see StackHeaderToolbarMenuController.effectiveOptions.
308
136
  if (options.requiresIconTintColorUpdate || options.icon != null) {
309
- MenuItemCompat.setIconTintList(menuItem, getResolvedIconTintList(menuItem, options))
137
+ MenuItemCompat.setIconTintList(menuItem, buildIconTintList(options))
310
138
  }
311
139
 
312
140
  options.menuTitle?.let { update ->
@@ -321,95 +149,35 @@ internal object StackHeaderToolbarMenuApplicator {
321
149
  Log.w(TAG, "[RNScreens] menuTitle ignored: target is not a submenu.")
322
150
  }
323
151
  }
324
- }
325
152
 
326
- private fun StackHeaderToolbarMenuItemConfig.toOptions() =
327
- StackHeaderToolbarMenuElementOptions(
328
- title = StackHeaderToolbarFieldUpdate.from(title),
329
- titleCondensed = StackHeaderToolbarFieldUpdate.from(titleCondensed),
330
- tooltipText = StackHeaderToolbarFieldUpdate.from(tooltipText),
331
- accessibilityLabel = StackHeaderToolbarFieldUpdate.from(accessibilityLabel),
332
- hidden = hidden,
333
- disabled = disabled,
334
- showAsAction = showAsAction,
335
- icon = StackHeaderToolbarFieldUpdate.from(icon),
336
- iconTintColorNormal = StackHeaderToolbarFieldUpdate.from(iconTintColorNormal),
337
- iconTintColorPressed = StackHeaderToolbarFieldUpdate.from(iconTintColorPressed),
338
- iconTintColorFocused = StackHeaderToolbarFieldUpdate.from(iconTintColorFocused),
339
- iconTintColorDisabled = StackHeaderToolbarFieldUpdate.from(iconTintColorDisabled),
340
- )
153
+ // Apply showAsAction property after icon is set to ensure correct overflow behavior.
154
+ options.showAsAction?.let { menuItem.setShowAsAction(it.toNativeShowAsAction()) }
155
+ }
341
156
 
342
157
  // endregion
343
158
 
344
159
  // region Icon tint
345
160
 
346
- private fun getResolvedIconTintList(
347
- menuItem: MenuItem,
348
- options: StackHeaderToolbarMenuElementOptions,
349
- ): ColorStateList? {
350
- val currentTintList = MenuItemCompat.getIconTintList(menuItem)
351
- // The currently-applied normal (catch-all) color, if any. Used both as the "leave
352
- // unchanged" value for normal and to dedup read-back overrides: when a normal entry
353
- // exists every override probe also matches it, so an override equal to the current
354
- // normal is the catch-all leaking through rather than an explicit override.
355
- val currentNormal = currentTintList?.resolvedColorOrNull(intArrayOf(android.R.attr.state_enabled))
356
-
357
- val finalNormal =
358
- when (val update = options.iconTintColorNormal) {
359
- StackHeaderToolbarFieldUpdate.Reset -> null
360
- is StackHeaderToolbarFieldUpdate.Set -> update.value
361
- null -> currentNormal
362
- }
363
-
364
- val finalDisabled =
365
- when (val update = options.iconTintColorDisabled) {
366
- StackHeaderToolbarFieldUpdate.Reset -> null
367
- is StackHeaderToolbarFieldUpdate.Set -> update.value
368
- null ->
369
- currentTintList
370
- ?.resolvedColorOrNull(intArrayOf(-android.R.attr.state_enabled))
371
- ?.takeIf { it != currentNormal }
372
- }
373
-
374
- val finalPressed =
375
- when (val update = options.iconTintColorPressed) {
376
- StackHeaderToolbarFieldUpdate.Reset -> null
377
- is StackHeaderToolbarFieldUpdate.Set -> update.value
378
- null ->
379
- currentTintList
380
- ?.resolvedColorOrNull(intArrayOf(android.R.attr.state_enabled, android.R.attr.state_pressed))
381
- ?.takeIf { it != currentNormal }
382
- }
383
-
384
- val finalFocused =
385
- when (val update = options.iconTintColorFocused) {
386
- StackHeaderToolbarFieldUpdate.Reset -> null
387
- is StackHeaderToolbarFieldUpdate.Set -> update.value
388
- null ->
389
- currentTintList
390
- ?.resolvedColorOrNull(intArrayOf(android.R.attr.state_enabled, android.R.attr.state_focused))
391
- ?.takeIf { it != currentNormal }
392
- }
393
-
161
+ private fun buildIconTintList(options: StackHeaderToolbarMenuElementOptions): ColorStateList? {
394
162
  val states = mutableListOf<IntArray>()
395
163
  val colors = mutableListOf<Int>()
396
164
 
397
- finalDisabled?.let {
165
+ options.iconTintColorDisabled?.valueOrNull()?.let {
398
166
  states.add(intArrayOf(-android.R.attr.state_enabled))
399
167
  colors.add(it)
400
168
  }
401
169
 
402
- finalPressed?.let {
170
+ options.iconTintColorPressed?.valueOrNull()?.let {
403
171
  states.add(intArrayOf(android.R.attr.state_pressed))
404
172
  colors.add(it)
405
173
  }
406
174
 
407
- finalFocused?.let {
175
+ options.iconTintColorFocused?.valueOrNull()?.let {
408
176
  states.add(intArrayOf(android.R.attr.state_focused))
409
177
  colors.add(it)
410
178
  }
411
179
 
412
- finalNormal?.let {
180
+ options.iconTintColorNormal?.valueOrNull()?.let {
413
181
  states.add(intArrayOf())
414
182
  colors.add(it)
415
183
  }
@@ -421,28 +189,7 @@ internal object StackHeaderToolbarMenuApplicator {
421
189
  }
422
190
  }
423
191
 
424
- /**
425
- * Resolves the color the receiver applies to [stateSet], or `null` when no state spec
426
- * matches it.
427
- *
428
- * `getColorForState` returns the caller-supplied fallback when nothing matches, so we
429
- * probe twice with two distinct sentinels: equal results mean a real spec matched (the
430
- * actual color), differing results mean the slot is absent. This is robust for any color
431
- * value and keeps the read-back stateless — see [getResolvedIconTintList].
432
- */
433
- private fun ColorStateList.resolvedColorOrNull(stateSet: IntArray): Int? {
434
- val a = getColorForState(stateSet, SENTINEL_A)
435
- val b = getColorForState(stateSet, SENTINEL_B)
436
- return if (a == b) a else null
437
- }
438
-
439
192
  // endregion
440
193
 
441
194
  private const val TAG = "StackHeaderToolbarMenuApplicator"
442
-
443
- // Two distinct sentinel fallbacks used to detect whether a ColorStateList actually
444
- // defines a color for a given state. Their concrete values are irrelevant as long as
445
- // they differ — see resolvedColorOrNull.
446
- private const val SENTINEL_A = 0x00000001
447
- private const val SENTINEL_B = 0x00000002
448
195
  }