@apexnative/navigation 1.0.0-alpha.1 → 1.0.0-alpha.10
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.
- package/ApexNavigation.podspec +2 -1
- package/CHANGELOG.md +120 -0
- package/README.md +147 -51
- package/android/CLAUDE.md +78 -25
- package/android/CORE.md +49 -25
- package/android/RECIPES.md +13 -6
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
- package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
- package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
- package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
- package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
- package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
- package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
- package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
- package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
- package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
- package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
- package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
- package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
- package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +10 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
- package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
- package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
- package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
- package/android/src/main/jni/ANNContentHeights.cpp +82 -0
- package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
- package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
- package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
- package/android/src/main/res/values/styles.xml +1 -1
- package/android/src/main/res/values-night/styles.xml +1 -1
- package/cli/app.js +1 -1
- package/cli/doctor/checks/app.js +77 -14
- package/cli/doctor/checks/splash.js +4 -22
- package/cli/migrate/native.js +18 -0
- package/cli/project.js +10 -2
- package/cli/setup/index.js +18 -0
- package/cli/setup/source.js +2 -1
- package/cli/setup/steps/appDelegate.js +66 -11
- package/cli/setup/steps/mainApplication.js +134 -19
- package/cli/setup/steps/metro.js +46 -0
- package/cli/setup/steps/sceneDelegate.js +108 -0
- package/cli/splash/index.js +3 -1
- package/docs-md/architecture/native-screens.md +4 -0
- package/docs-md/architecture/theme-and-context.md +131 -12
- package/docs-md/architecture/transitions.md +58 -12
- package/docs-md/containers/modals.md +8 -4
- package/docs-md/containers/overlays.md +3 -1
- package/docs-md/containers/side-menu.md +19 -2
- package/docs-md/containers/tabs.md +5 -1
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/flows/forms-in-a-modal.md +1 -1
- package/docs-md/fundamentals/screens-and-props.md +9 -1
- package/docs-md/fundamentals/starting-the-app.md +1 -1
- package/docs-md/guides/cli.md +4 -3
- package/docs-md/guides/deep-links.md +15 -33
- package/docs-md/help/glossary.md +4 -4
- package/docs-md/help/troubleshooting.md +44 -6
- package/docs-md/index.json +57 -1
- package/docs-md/migration/from-expo-router.md +1 -1
- package/docs-md/migration/from-react-native-navigation.md +9 -3
- package/docs-md/migration/from-react-navigation.md +2 -2
- package/docs-md/screen-ui/back-and-gestures.md +46 -2
- package/docs-md/screen-ui/bar-buttons.md +5 -5
- package/docs-md/screen-ui/search.md +1 -1
- package/docs-md/screen-ui/system-ui.md +17 -12
- package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
- package/docs-md/screen-ui/top-bar.md +8 -4
- package/docs-md/start/installation.md +21 -3
- package/ios/Animations/ANNFrameDriver.h +55 -15
- package/ios/Animations/ANNFrameDriver.mm +216 -60
- package/ios/Animations/ANNTransitionAnimator.h +26 -5
- package/ios/Animations/ANNTransitionAnimator.mm +61 -13
- package/ios/Animations/ANNTransitionPlan.h +2 -2
- package/ios/Animations/ANNTransitionPlan.mm +10 -0
- package/ios/Animations/ANNTransitionWait.mm +6 -7
- package/ios/Animations/Elements/ANNElementFinder.h +57 -0
- package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
- package/ios/Animations/Elements/ANNElementTransition.h +10 -8
- package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
- package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
- package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
- package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
- package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
- package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
- package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
- package/ios/CLAUDE.md +60 -24
- package/ios/CORE.md +44 -34
- package/ios/Contract/ANNCommandAnswer.h +13 -5
- package/ios/Contract/ANNCommandAnswer.mm +40 -32
- package/ios/Contract/ANNCommandContract.h +15 -0
- package/ios/Contract/ANNCommandContract.mm +78 -0
- package/ios/Contract/ANNCommandRunner.h +10 -9
- package/ios/Contract/ANNCommandRunner.mm +22 -28
- package/ios/Contract/ANNErrorTexts.h +6 -2
- package/ios/Contract/ANNErrorTexts.mm +18 -10
- package/ios/Contract/ANNLayoutNode.h +3 -3
- package/ios/Contract/ANNLayoutReader.h +3 -3
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNAppearanceDispatcher.h +5 -4
- package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
- package/ios/Core/ANNDeepLinkQueue.h +22 -2
- package/ios/Core/ANNDeepLinkQueue.mm +121 -14
- package/ios/Core/ANNErrorHandler.h +9 -4
- package/ios/Core/ANNErrorHandler.mm +20 -2
- package/ios/Core/ANNEventContract.h +246 -0
- package/ios/Core/ANNEventContract.mm +225 -0
- package/ios/Core/ANNEventEmitter.h +6 -2
- package/ios/Core/ANNEventEmitter.mm +117 -80
- package/ios/Core/ANNHinge.h +6 -0
- package/ios/Core/ANNHinge.mm +15 -4
- package/ios/Core/ANNJavaScriptCalls.h +33 -0
- package/ios/Core/ANNJavaScriptCalls.mm +52 -0
- package/ios/Core/ANNLayoutProtocol.h +5 -5
- package/ios/Core/ANNNavigationState.h +7 -5
- package/ios/Core/ANNNavigationState.mm +8 -7
- package/ios/Core/ANNNodeHelper.h +32 -12
- package/ios/Core/ANNNodeHelper.mm +100 -3
- package/ios/Core/ANNParking.h +5 -4
- package/ios/Core/ANNReloadCoordinator.mm +5 -12
- package/ios/Core/ANNRenderWait.h +20 -6
- package/ios/Core/ANNRenderWait.mm +143 -56
- package/ios/Core/ANNSceneDelegate.mm +25 -15
- package/ios/Core/ANNSystemUI.h +3 -2
- package/ios/Core/ANNSystemUI.mm +7 -0
- package/ios/Core/ANNUtils.h +7 -0
- package/ios/Core/ANNUtils.mm +10 -0
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- package/ios/Core/ApexNavigation.mm +7 -6
- package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
- package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
- package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
- package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +10 -8
- package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
- package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
- package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
- package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
- package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
- package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
- package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
- package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
- package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
- package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
- package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
- package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
- package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
- package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
- package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
- package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
- package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
- package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
- package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
- package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
- package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
- package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
- package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
- package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
- package/ios/Layouts/Screen/ANNScreenSettling.h +32 -0
- package/ios/Layouts/Screen/ANNScreenSettling.mm +137 -0
- package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
- package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
- package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
- package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
- package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
- package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
- package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
- package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
- package/ios/Layouts/Stack/ANNStackController.h +8 -0
- package/ios/Layouts/Stack/ANNStackController.mm +184 -16
- package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
- package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
- package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
- package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
- package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
- package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
- package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
- package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
- package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
- package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
- package/ios/Options/ANNAnimationOptions.h +2 -1
- package/ios/Options/ANNAnimationOptions.mm +1 -1
- package/ios/Options/ANNBottomTabsOptions.h +2 -0
- package/ios/Options/ANNBottomTabsOptions.mm +1 -0
- package/ios/Options/ANNOptions.h +25 -0
- package/ios/Options/ANNOptions.mm +157 -1
- package/ios/Options/ANNOptionsCache.h +7 -6
- package/ios/Options/ANNOptionsReader.mm +108 -0
- package/ios/Options/ANNSearchBarOptions.h +4 -3
- package/ios/Options/ANNSheetOptions.h +4 -1
- package/ios/Options/ANNSideMenuOptions.h +2 -0
- package/ios/Options/ANNSideMenuOptions.mm +2 -0
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/ANNUserChoice.h +57 -0
- package/ios/Options/ANNUserChoice.mm +44 -0
- package/ios/Options/Params/ANNImageSource.h +61 -0
- package/ios/Options/Params/ANNImageSource.mm +101 -0
- package/ios/Options/Params/ANNOptionImages.h +37 -0
- package/ios/Options/Params/ANNOptionImages.mm +284 -0
- package/ios/Options/Params/ANNParam.h +15 -0
- package/ios/Options/Params/ANNParam.mm +61 -0
- package/ios/Options/Params/Color.h +3 -0
- package/ios/Options/Params/Color.mm +21 -0
- package/ios/Options/Params/ColorParser.h +4 -3
- package/ios/Options/Params/ColorParser.mm +22 -4
- package/ios/Options/Params/Image.h +15 -2
- package/ios/Options/Params/Image.mm +35 -2
- package/ios/Options/Params/ImageParser.h +5 -5
- package/ios/Options/Params/ImageParser.mm +28 -46
- package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
- package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
- package/ios/RECIPES.md +13 -6
- package/ios/React/ANNReactView.mm +6 -25
- package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
- package/ios/React/ANNSurfaceHostingView.h +14 -0
- package/ios/React/ANNSurfaceHostingView.mm +144 -1
- package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
- package/ios/React/Slots/ANNSlotContainers.h +14 -6
- package/ios/React/Slots/ANNSlotContainers.mm +75 -2
- package/ios/React/Slots/ANNSlotHost.mm +1 -3
- package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
- package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
- package/ios/TopBar/ANNBarAppearance.h +2 -1
- package/ios/TopBar/ANNBarAppearance.mm +111 -30
- package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
- package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
- package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
- package/ios/TopBar/ANNBarButtons.h +14 -8
- package/ios/TopBar/ANNBarButtons.mm +397 -80
- package/ios/TopBar/ANNIconButtonImage.h +1 -0
- package/ios/TopBar/ANNIconButtonImage.mm +34 -1
- package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
- package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
- package/ios/TopBar/ANNMainList.h +3 -0
- package/ios/TopBar/ANNMainList.mm +4 -0
- package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
- package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
- package/ios/TopBar/ANNSearchPresenter.mm +172 -21
- package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
- package/ios/TopBar/ANNTopBarPresenter.h +8 -2
- package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
- package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
- package/ios/TurboModules/ANNTurboModule.mm +104 -33
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
- package/lib/module/ARCHITECTURE.md +40 -27
- package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
- package/lib/module/api/app/AppRegistry.js +14 -2
- package/lib/module/api/app/AppRegistry.js.map +1 -1
- package/lib/module/api/app/createNavigation.js +190 -66
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/commands/commands.js +54 -6
- package/lib/module/api/commands/commands.js.map +1 -1
- package/lib/module/api/events/navigationEvents.js +6 -2
- package/lib/module/api/events/navigationEvents.js.map +1 -1
- package/lib/module/api/hooks/useNavigation.js +8 -3
- package/lib/module/api/hooks/useNavigation.js.map +1 -1
- package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
- package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
- package/lib/module/api/linking/dispatchedLinks.js +23 -0
- package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
- package/lib/module/api/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.js.map +1 -1
- package/lib/module/api/navigation.js.map +1 -1
- package/lib/module/api/options/OptionsChain.js +2 -2
- package/lib/module/api/screens/defineScreen.js +45 -3
- package/lib/module/api/screens/defineScreen.js.map +1 -1
- package/lib/module/api/screens/nativeScreens.js +31 -6
- package/lib/module/api/screens/nativeScreens.js.map +1 -1
- package/lib/module/api/screens/registerScreens.js +193 -35
- package/lib/module/api/screens/registerScreens.js.map +1 -1
- package/lib/module/api/theme/theme.js +5 -0
- package/lib/module/api/theme/theme.js.map +1 -1
- package/lib/module/engine/commands.js +51 -9
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +20 -11
- package/lib/module/engine/layout.js.map +1 -1
- package/lib/module/engine/nativeScreens.js +9 -0
- package/lib/module/engine/nativeScreens.js.map +1 -1
- package/lib/module/engine/options.js +49 -15
- package/lib/module/engine/options.js.map +1 -1
- package/lib/module/engine/optionsChange.js +102 -0
- package/lib/module/engine/optionsChange.js.map +1 -0
- package/lib/module/engine/places.js +52 -7
- package/lib/module/engine/places.js.map +1 -1
- package/lib/module/engine/props.js +30 -1
- package/lib/module/engine/props.js.map +1 -1
- package/lib/module/engine/refresh.js +85 -0
- package/lib/module/engine/refresh.js.map +1 -0
- package/lib/module/engine/rememberedOptions.js +61 -1
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +77 -16
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/module/interfaces/contract/commands.json +101 -0
- package/lib/module/interfaces/contract/errors.json +275 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
- package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
- package/lib/typescript/api/app/createNavigation.d.ts +8 -3
- package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
- package/lib/typescript/api/commands/commands.d.ts.map +1 -1
- package/lib/typescript/api/commands/presentation.d.ts +4 -3
- package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
- package/lib/typescript/api/index.d.ts +1 -1
- package/lib/typescript/api/index.d.ts.map +1 -1
- package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
- package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
- package/lib/typescript/api/linking/linking.d.ts +8 -0
- package/lib/typescript/api/linking/linking.d.ts.map +1 -1
- package/lib/typescript/api/navigation.d.ts +4 -1
- package/lib/typescript/api/navigation.d.ts.map +1 -1
- package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
- package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
- package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
- package/lib/typescript/api/theme/theme.d.ts +2 -0
- package/lib/typescript/api/theme/theme.d.ts.map +1 -1
- package/lib/typescript/engine/commands.d.ts +5 -0
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/layout.d.ts.map +1 -1
- package/lib/typescript/engine/nativeScreens.d.ts +5 -0
- package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/engine/options.d.ts +5 -2
- package/lib/typescript/engine/options.d.ts.map +1 -1
- package/lib/typescript/engine/optionsChange.d.ts +28 -0
- package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
- package/lib/typescript/engine/places.d.ts +7 -2
- package/lib/typescript/engine/places.d.ts.map +1 -1
- package/lib/typescript/engine/props.d.ts +8 -1
- package/lib/typescript/engine/props.d.ts.map +1 -1
- package/lib/typescript/engine/refresh.d.ts +35 -0
- package/lib/typescript/engine/refresh.d.ts.map +1 -0
- package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
- package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts +27 -6
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
- package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
- package/lib/typescript/interfaces/Events.d.ts +28 -10
- package/lib/typescript/interfaces/Events.d.ts.map +1 -1
- package/lib/typescript/interfaces/Options.d.ts +1 -1
- package/lib/typescript/interfaces/Options.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +80 -22
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
- package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/modals.d.ts +34 -26
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
- package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +17 -3
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +18 -11
- package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
- package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/metro/acceptPlugin.js +57 -0
- package/metro/babelTransformer.js +45 -0
- package/metro/index.js +36 -0
- package/package.json +3 -1
- package/src/ARCHITECTURE.md +40 -27
- package/src/adapters/NativeANNTurboModule.ts +12 -2
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +203 -69
- package/src/api/commands/commands.ts +48 -7
- package/src/api/commands/presentation.ts +4 -3
- package/src/api/events/navigationEvents.ts +10 -4
- package/src/api/hooks/useNavigation.ts +9 -4
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/dispatchedLinks.ts +18 -0
- package/src/api/linking/linking.ts +22 -1
- package/src/api/navigation.ts +4 -1
- package/src/api/options/OptionsChain.ts +2 -2
- package/src/api/screens/defineScreen.ts +49 -5
- package/src/api/screens/nativeScreens.ts +40 -4
- package/src/api/screens/registerScreens.tsx +185 -42
- package/src/api/theme/theme.ts +5 -0
- package/src/engine/commands.ts +70 -13
- package/src/engine/layout.ts +27 -11
- package/src/engine/nativeScreens.ts +10 -1
- package/src/engine/options.ts +45 -19
- package/src/engine/optionsChange.ts +107 -0
- package/src/engine/places.ts +65 -7
- package/src/engine/props.ts +30 -1
- package/src/engine/refresh.ts +97 -0
- package/src/engine/rememberedOptions.ts +74 -1
- package/src/engine/screens.tsx +76 -21
- package/src/interfaces/ComponentEvents.ts +4 -4
- package/src/interfaces/Events.ts +29 -10
- package/src/interfaces/Options.ts +1 -0
- package/src/interfaces/contract/commands.json +101 -0
- package/src/interfaces/contract/errors.json +275 -0
- package/src/interfaces/options/animations.ts +81 -22
- package/src/interfaces/options/bottomTabs.ts +21 -7
- package/src/interfaces/options/buttons.ts +23 -15
- package/src/interfaces/options/modals.ts +34 -26
- package/src/interfaces/options/sideMenu.ts +24 -6
- package/src/interfaces/options/stack.ts +17 -3
- package/src/interfaces/options/system.ts +18 -11
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +68 -38
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
- package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
- package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
- package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
- package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
package dev.apexnative.navigation.react.events
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import dev.apexnative.navigation.react.ReloadCoordinator
|
|
6
|
+
import dev.apexnative.navigation.viewcontrollers.bottomtabs.BottomTabsController
|
|
7
|
+
import dev.apexnative.navigation.viewcontrollers.navigator.Navigators
|
|
8
|
+
import dev.apexnative.navigation.viewcontrollers.parent.ParentController
|
|
9
|
+
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The one place of the navigation state JavaScript hears (`ANN.NavigationStateChanged`): the screen the user sees and
|
|
13
|
+
* the selected tab, the last state sent, the update posted for a pass of the main loop and its holds. Every change of
|
|
14
|
+
* the screen the user sees comes with a screen appearing: a push, a pop, a modal, a tab, a menu.
|
|
15
|
+
*
|
|
16
|
+
* Two ways ask for it. The dispatcher asks for one update after the events of a pass ([setNeedsUpdate], coalesced and
|
|
17
|
+
* held while a `setRoot` shows the modals and the overlays of its layout). A command's answer sends it at once
|
|
18
|
+
* ([updateNow], never held), once per answer (`CommandAnswer.reportStateNow`): at the end of its transition, else
|
|
19
|
+
* right before its promise. Each goes only when the state differs from the last one sent, through the JavaScript that
|
|
20
|
+
* runs now. Main thread only.
|
|
21
|
+
*/
|
|
22
|
+
internal object NavigationState : AppearanceDispatcher.StateUpdates {
|
|
23
|
+
/** What JavaScript hears: the screen the user sees (`null` for none) and the selected tab (`null` out of tabs). */
|
|
24
|
+
data class State(val screenId: String?, val screenName: String?, val tab: Int?)
|
|
25
|
+
|
|
26
|
+
private val handler by lazy { Handler(Looper.getMainLooper()) }
|
|
27
|
+
|
|
28
|
+
// The last state sent to the JavaScript that runs now; none before its first.
|
|
29
|
+
private var sent: State? = null
|
|
30
|
+
|
|
31
|
+
// The one posted update of a pass of the main loop, which checks the holds when it runs.
|
|
32
|
+
private val updates = Updates(
|
|
33
|
+
post = { task -> handler.post(task) },
|
|
34
|
+
generation = { ReloadCoordinator.generation },
|
|
35
|
+
update = ::updateNow,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
override fun setNeedsUpdate() {
|
|
39
|
+
if (EventEmitter.current().canSend) updates.setNeedsUpdate()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun hold() = updates.hold()
|
|
43
|
+
|
|
44
|
+
override fun release() = updates.release()
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Sends the state at once when it differs from the last one sent. A command's answer calls it once, at the end of
|
|
48
|
+
* its transition or right before its promise: the event and the resolution reach JavaScript in that order, so the
|
|
49
|
+
* state is new when the `await` of the command goes on. The update posted for the pass then finds nothing new.
|
|
50
|
+
*/
|
|
51
|
+
override fun updateNow() {
|
|
52
|
+
val emitter = EventEmitter.current()
|
|
53
|
+
if (!emitter.canSend) return
|
|
54
|
+
// The navigation of the activity the commands run in (`Navigators.current`).
|
|
55
|
+
val navigator = Navigators.current()?.navigator ?: return
|
|
56
|
+
val next = stateOf(navigator.visibleLayout)
|
|
57
|
+
if (next == sent) return
|
|
58
|
+
sent = next
|
|
59
|
+
emitter.emitNavigationStateChanged(next.screenId, next.screenName, next.tab)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The new JavaScript has no state yet (`ANN.AppLaunched`): the next one goes to it whatever it is. */
|
|
63
|
+
fun reset() {
|
|
64
|
+
sent = null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The JavaScript went with its layouts: a hold its `setRoot` left, and an update wanted under it, go with it, so
|
|
69
|
+
* the new JavaScript's updates are never held by the old one's.
|
|
70
|
+
*/
|
|
71
|
+
fun javaScriptWent() = updates.dropHolds()
|
|
72
|
+
|
|
73
|
+
// The top modal, or the root ([layout]), down to the screen the user sees; overlays don't count. The tab is the
|
|
74
|
+
// selected one of the nearest tabs the screen is in, the last met on the way down, in a modal too: the tabs
|
|
75
|
+
// `selectTab` acts on from it. None for a screen out of tabs.
|
|
76
|
+
internal fun stateOf(layout: ViewController<*>?): State {
|
|
77
|
+
var tab: Int? = null
|
|
78
|
+
var current = layout ?: return State(null, null, null)
|
|
79
|
+
while (current is ParentController<*>) {
|
|
80
|
+
if (current is BottomTabsController) tab = current.selectedIndex
|
|
81
|
+
current = current.currentChild ?: return State(null, null, null)
|
|
82
|
+
}
|
|
83
|
+
return State(current.id, current.currentComponentName, tab)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The posted update and its holds. [setNeedsUpdate] posts one update ([post]), coalesced: the asks of one pass of
|
|
88
|
+
* the main loop make one, which runs [update] in a later pass. While held, an ask, or a posted update that runs
|
|
89
|
+
* while held (asked before the hold was taken), only marks one as wanted, and the last release posts it. Released
|
|
90
|
+
* right before the answer, that update finds nothing new: the state before the answer is sent at once, never
|
|
91
|
+
* held, and an identical state is never sent twice. Every [hold] has one [release]; a release without a hold does
|
|
92
|
+
* nothing, so the count never goes below zero. An update keeps the JavaScript it was asked for ([generation]): one
|
|
93
|
+
* asked by a JavaScript that went before it runs is dropped; a newer ask of the new JavaScript still goes.
|
|
94
|
+
*/
|
|
95
|
+
internal class Updates(
|
|
96
|
+
private val post: (() -> Unit) -> Unit,
|
|
97
|
+
private val generation: () -> Int = { 0 },
|
|
98
|
+
private val update: () -> Unit,
|
|
99
|
+
) {
|
|
100
|
+
/** The holds not released yet. */
|
|
101
|
+
var count = 0
|
|
102
|
+
private set
|
|
103
|
+
|
|
104
|
+
// An update was asked while held.
|
|
105
|
+
private var wanted = false
|
|
106
|
+
// An update is posted and hasn't run yet.
|
|
107
|
+
private var scheduled = false
|
|
108
|
+
// The JavaScript the last ask was for.
|
|
109
|
+
private var askedIn = 0
|
|
110
|
+
|
|
111
|
+
/** Asks for one update in a later pass of the main loop; while held, once the last hold is released. */
|
|
112
|
+
fun setNeedsUpdate() {
|
|
113
|
+
askedIn = generation()
|
|
114
|
+
if (count > 0) wanted = true else schedule()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The updates asked from now on, and those posted that run from now on, wait for as many [release]s. */
|
|
118
|
+
fun hold() {
|
|
119
|
+
count++
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** One hold ends; with the last, the update asked while held is posted now. */
|
|
123
|
+
fun release() {
|
|
124
|
+
if (count == 0) return
|
|
125
|
+
count--
|
|
126
|
+
if (count > 0 || !wanted) return
|
|
127
|
+
wanted = false
|
|
128
|
+
schedule()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The holds and the update wanted under them go, unreleased: the JavaScript that took them went. An update
|
|
133
|
+
* already posted stays; it runs only for the JavaScript it was asked for.
|
|
134
|
+
*/
|
|
135
|
+
fun dropHolds() {
|
|
136
|
+
count = 0
|
|
137
|
+
wanted = false
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private fun schedule() {
|
|
141
|
+
if (scheduled) return
|
|
142
|
+
scheduled = true
|
|
143
|
+
post {
|
|
144
|
+
scheduled = false
|
|
145
|
+
// A hold taken since it was posted: the update waits for the release. The JavaScript it was asked for
|
|
146
|
+
// went: nothing goes to the new one, which hears its first state after its own changes.
|
|
147
|
+
when {
|
|
148
|
+
count > 0 -> wanted = true
|
|
149
|
+
askedIn == generation() -> update()
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -45,12 +45,6 @@ internal class ScreenAppearance(
|
|
|
45
45
|
/** Cancels the hold limit running for [held]; none when nothing is held. */
|
|
46
46
|
internal var cancelLimit: (() -> Unit)? = null
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
* This appearance started without its WillAppear (`AppearanceDispatcher.withoutWillAppear`: a side menu's drawer
|
|
50
|
-
* that jumped open); its DidAppear is its first event. Cleared as it is hidden.
|
|
51
|
-
*/
|
|
52
|
-
internal var skippedWill = false
|
|
53
|
-
|
|
54
48
|
private var ready = content == null
|
|
55
49
|
private var waitsForContent = false
|
|
56
50
|
|
|
@@ -10,7 +10,7 @@ import com.facebook.react.uimanager.StateWrapper
|
|
|
10
10
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
11
11
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
12
12
|
import com.facebook.react.views.view.ReactViewGroup
|
|
13
|
-
import dev.apexnative.navigation.react.
|
|
13
|
+
import dev.apexnative.navigation.react.ScreenEnvironment
|
|
14
14
|
import dev.apexnative.navigation.viewcontrollers.component.ScreenReadiness
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -20,7 +20,7 @@ import dev.apexnative.navigation.viewcontrollers.component.ScreenReadiness
|
|
|
20
20
|
@SuppressLint("ViewConstructor")
|
|
21
21
|
class SafeAreaView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext) {
|
|
22
22
|
private var stopListening: (() -> Unit)? = null
|
|
23
|
-
private var applied:
|
|
23
|
+
private var applied: ScreenEnvironment.Insets? = null
|
|
24
24
|
private var readySent = false
|
|
25
25
|
private var contentSignalled = false
|
|
26
26
|
|
|
@@ -48,7 +48,7 @@ class SafeAreaView(reactContext: ThemedReactContext) : ReactViewGroup(reactConte
|
|
|
48
48
|
stopListening?.invoke()
|
|
49
49
|
field = value
|
|
50
50
|
applied = null
|
|
51
|
-
stopListening = value?.let { id ->
|
|
51
|
+
stopListening = value?.let { id -> ScreenEnvironment.listenToPadding(id) { applyPadding() } }
|
|
52
52
|
// The screen has a safe area view: it counts as rendered once this view says so.
|
|
53
53
|
value?.let(ScreenReadiness::wrapped)
|
|
54
54
|
applyPadding()
|
|
@@ -56,7 +56,7 @@ class SafeAreaView(reactContext: ThemedReactContext) : ReactViewGroup(reactConte
|
|
|
56
56
|
|
|
57
57
|
private fun applyPadding() {
|
|
58
58
|
val state = stateWrapper ?: return
|
|
59
|
-
val padding = screenId?.let(
|
|
59
|
+
val padding = screenId?.let(ScreenEnvironment::padding) ?: return
|
|
60
60
|
if (padding == applied) return
|
|
61
61
|
applied = padding
|
|
62
62
|
state.updateState(
|
|
@@ -69,9 +69,9 @@ class SafeAreaView(reactContext: ThemedReactContext) : ReactViewGroup(reactConte
|
|
|
69
69
|
)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
private fun paddingOf(data: ReadableMap):
|
|
72
|
+
private fun paddingOf(data: ReadableMap): ScreenEnvironment.Insets? {
|
|
73
73
|
if (!data.hasKey("top")) return null
|
|
74
|
-
return
|
|
74
|
+
return ScreenEnvironment.Insets(data.getDouble("top"), data.getDouble("right"), data.getDouble("bottom"),
|
|
75
75
|
data.getDouble("left"))
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -95,8 +95,9 @@ class SafeAreaView(reactContext: ThemedReactContext) : ReactViewGroup(reactConte
|
|
|
95
95
|
val reactContext = context as? ReactContext ?: return
|
|
96
96
|
val dispatcher = UIManagerHelper.getEventDispatcher(reactContext) ?: return
|
|
97
97
|
readySent = true
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
99
|
+
dispatcher.dispatchEvent(SafeAreaReadyEvent(surfaceId, id))
|
|
100
|
+
screenId?.let { ScreenReadiness.laidOut(it, surfaceId) }
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
// The navigation tells whether this view's screen waits: a component of a bar (title, button, background, tab)
|
|
@@ -111,12 +112,13 @@ class SafeAreaView(reactContext: ThemedReactContext) : ReactViewGroup(reactConte
|
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
// Once, by the screen's id: the container asks the screen's view for the layout React mounts the content without.
|
|
114
|
-
// On attach too: content added before this view was attached is signalled then.
|
|
115
|
+
// On attach too: content added before this view was attached is signalled then. The signal names this view's
|
|
116
|
+
// surface: only the root that shows it takes it as its own.
|
|
115
117
|
private fun signalContent() {
|
|
116
118
|
if (contentSignalled) return
|
|
117
119
|
val id = screenId ?: return
|
|
118
120
|
contentSignalled = true
|
|
119
|
-
ScreenReadiness.contentRendered(id)
|
|
121
|
+
ScreenReadiness.contentRendered(id, UIManagerHelper.getSurfaceId(this))
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
fun drop() {
|
|
@@ -9,14 +9,15 @@ interface SlotContainer {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* The native containers the slots of the app's React tree show their children in, by slot id
|
|
13
|
-
*
|
|
12
|
+
* The native containers the slots of the app's React tree show their children in, by slot id, and the slot views by
|
|
13
|
+
* the same id: a change of a container goes straight to the views of its id. A destroyed container and a collected
|
|
14
|
+
* view drop out on their own.
|
|
14
15
|
*/
|
|
15
16
|
object SlotContainers {
|
|
16
17
|
private class Entry(val view: WeakReference<ViewGroup>, val passThrough: Boolean)
|
|
17
18
|
|
|
18
19
|
private val containers = HashMap<String, Entry>()
|
|
19
|
-
private val slots =
|
|
20
|
+
private val slots = SlotViews<SlotView>()
|
|
20
21
|
|
|
21
22
|
/** `passThrough`: touches outside the slot's content go to the screens below, as in an overlay for a toast. */
|
|
22
23
|
fun put(slotId: String, container: ViewGroup, passThrough: Boolean = false) {
|
|
@@ -33,12 +34,14 @@ object SlotContainers {
|
|
|
33
34
|
changed(slotId)
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
/** The container of a slot appeared or changed its size. */
|
|
37
|
+
/** The container of a slot appeared or changed its size: the slot views under its id, and only they, hear it. */
|
|
37
38
|
fun changed(slotId: String) {
|
|
38
|
-
slots.
|
|
39
|
+
slots.views(slotId).forEach { it.containerChanged(slotId) }
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
/** The slot view goes under its slot id, and out from under the id it had. Main thread only. */
|
|
43
|
+
internal fun register(slotId: String, slot: SlotView) = slots.register(slotId, slot)
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
/** The slot view unmounted or lost its slot id: no container change reaches it. Main thread only. */
|
|
46
|
+
internal fun unregister(slot: SlotView) = slots.unregister(slot)
|
|
44
47
|
}
|
|
@@ -2,9 +2,13 @@ package dev.apexnative.navigation.slots
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
|
+
import android.util.Size
|
|
5
6
|
import android.view.MotionEvent
|
|
6
7
|
import android.view.ViewGroup
|
|
7
8
|
import android.widget.FrameLayout
|
|
9
|
+
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
10
|
+
import dev.apexnative.navigation.react.ContentHeights
|
|
11
|
+
import dev.apexnative.navigation.react.ContentMounts
|
|
8
12
|
import dev.apexnative.navigation.react.events.AppearanceDispatcher
|
|
9
13
|
import dev.apexnative.navigation.react.events.ComponentType
|
|
10
14
|
import dev.apexnative.navigation.react.events.ScreenAppearance
|
|
@@ -16,9 +20,10 @@ import dev.apexnative.navigation.viewcontrollers.viewcontroller.ScrollEventListe
|
|
|
16
20
|
* What a slot screen (`slot:<Name>`) shows: the empty container its slot of the app's React tree moves its children
|
|
17
21
|
* into, under the screen's id ([SlotContainers]), told of each change of its size. It is the screen's content for the
|
|
18
22
|
* core: ready once the slot's content has mounted into it and, when the screen has a safe area view, the screen
|
|
19
|
-
* rendered into that view; its mounted handlers run at each mount
|
|
20
|
-
*
|
|
21
|
-
*
|
|
23
|
+
* rendered into that view; its mounted handlers run at each mount of Fabric and as the content mounts into it. Its
|
|
24
|
+
* content measures without a height limit in the slot's own layout ([contentSize]). Its appearance events go through
|
|
25
|
+
* its record to the core's dispatcher (`AppearanceDispatcher`), which holds them until it is ready or the hold limit.
|
|
26
|
+
* Destroyed while the id is still its own, it tells JavaScript to take the slot's content away (`ANN.SlotDestroyed`).
|
|
22
27
|
*/
|
|
23
28
|
@SuppressLint("ViewConstructor")
|
|
24
29
|
class SlotScreenView(
|
|
@@ -30,8 +35,13 @@ class SlotScreenView(
|
|
|
30
35
|
private val scrollEventListener = ScrollEventListener()
|
|
31
36
|
private val whenMounted = mutableListOf<Runnable>()
|
|
32
37
|
private val whenRendered = mutableListOf<Runnable>()
|
|
33
|
-
private val
|
|
34
|
-
private var
|
|
38
|
+
private val mounts = ContentMounts { !destroyed && isAttachedToWindow }
|
|
39
|
+
private var listening = false
|
|
40
|
+
|
|
41
|
+
// The safe area view of a slot renders in the app's one React tree: every signal of the id is the screen's.
|
|
42
|
+
private val readiness = object : ScreenReadiness.Listener {
|
|
43
|
+
override fun onContentRendered() = checkReadiness()
|
|
44
|
+
}
|
|
35
45
|
private var mounted = false
|
|
36
46
|
private var readyTold = false
|
|
37
47
|
private var destroyed = false
|
|
@@ -79,10 +89,11 @@ class SlotScreenView(
|
|
|
79
89
|
destroyed = true
|
|
80
90
|
whenMounted.clear()
|
|
81
91
|
whenRendered.clear()
|
|
82
|
-
|
|
92
|
+
mounts.clear()
|
|
83
93
|
stopListening()
|
|
84
94
|
// A later screen with the same id keeps the slot.
|
|
85
95
|
if (SlotContainers.get(componentId) !== this) return
|
|
96
|
+
ContentHeights.forgetSlot(componentId)
|
|
86
97
|
SlotContainers.remove(componentId)
|
|
87
98
|
if (!isPreparedPush) AppearanceDispatcher.slotDestroyed(componentId, appearance.generation)
|
|
88
99
|
}
|
|
@@ -105,14 +116,9 @@ class SlotScreenView(
|
|
|
105
116
|
if (readyTold) return listener.run()
|
|
106
117
|
whenRendered += listener
|
|
107
118
|
if (isReady()) return checkReadiness()
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
override fun onContentRendered() = checkReadiness()
|
|
113
|
-
}
|
|
114
|
-
readinessListener = readiness
|
|
115
|
-
ScreenReadiness.setListener(componentId, readiness)
|
|
119
|
+
if (listening) return
|
|
120
|
+
listening = true
|
|
121
|
+
ScreenReadiness.addListener(componentId, this, readiness)
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
override fun whenSlotContentMounted(listener: Runnable) {
|
|
@@ -120,7 +126,21 @@ class SlotScreenView(
|
|
|
120
126
|
}
|
|
121
127
|
|
|
122
128
|
override fun setOnContentMounted(key: String, handler: Runnable?) {
|
|
123
|
-
if (
|
|
129
|
+
if (!destroyed) mounts.set(key, handler)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// The slot measures its content in its own layout: the first question asks for it and lays the slot out again; the
|
|
133
|
+
// height comes with that layout, before the mount the handlers hear. The width is the container's, at which the
|
|
134
|
+
// slot lays its content out.
|
|
135
|
+
override fun contentSize(maxWidth: Int): Size? {
|
|
136
|
+
if (destroyed) return null
|
|
137
|
+
if (!ContentHeights.isSlotRequested(componentId)) {
|
|
138
|
+
ContentHeights.requestSlot(componentId)
|
|
139
|
+
SlotContainers.changed(componentId)
|
|
140
|
+
return null
|
|
141
|
+
}
|
|
142
|
+
val height = ContentHeights.slotHeight(componentId)?.takeIf { it > 0f } ?: return null
|
|
143
|
+
return Size(if (width > 0) width else maxWidth, Math.round(height.dpToPx()))
|
|
124
144
|
}
|
|
125
145
|
|
|
126
146
|
// Only the container that holds the slot of the id: a destroyed one, or one a later screen replaced, takes no
|
|
@@ -136,7 +156,7 @@ class SlotScreenView(
|
|
|
136
156
|
val waiting = whenMounted.toList()
|
|
137
157
|
whenMounted.clear()
|
|
138
158
|
waiting.forEach { it.run() }
|
|
139
|
-
|
|
159
|
+
mounts.run()
|
|
140
160
|
checkReadiness()
|
|
141
161
|
}
|
|
142
162
|
|
|
@@ -151,8 +171,8 @@ class SlotScreenView(
|
|
|
151
171
|
}
|
|
152
172
|
|
|
153
173
|
private fun stopListening() {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
ScreenReadiness.removeListener(componentId,
|
|
174
|
+
if (!listening) return
|
|
175
|
+
listening = false
|
|
176
|
+
ScreenReadiness.removeListener(componentId, this)
|
|
157
177
|
}
|
|
158
178
|
}
|
|
@@ -15,6 +15,7 @@ import com.facebook.react.uimanager.ThemedReactContext
|
|
|
15
15
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
16
16
|
import com.facebook.react.uimanager.events.EventDispatcher
|
|
17
17
|
import com.facebook.react.views.view.ReactViewGroup
|
|
18
|
+
import dev.apexnative.navigation.react.ContentHeights
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* The React children of a slot. They live outside the views of the host's surface, in the container of a screen, so
|
|
@@ -79,6 +80,8 @@ class SlotView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext)
|
|
|
79
80
|
}
|
|
80
81
|
private var lastWidth = -1f
|
|
81
82
|
private var lastHeight = -1f
|
|
83
|
+
// The slot was laid out once more, at the same size, for the measure of its content (`ContentHeights`).
|
|
84
|
+
private var measureAsked = false
|
|
82
85
|
|
|
83
86
|
private val slotId: String?
|
|
84
87
|
get() = getTag(R.id.view_tag_native_id) as? String
|
|
@@ -86,7 +89,6 @@ class SlotView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext)
|
|
|
86
89
|
init {
|
|
87
90
|
content.visibility = INVISIBLE
|
|
88
91
|
addView(content)
|
|
89
|
-
SlotContainers.listen(this)
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
override fun setId(id: Int) {
|
|
@@ -100,7 +102,9 @@ class SlotView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext)
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
fun attachContent() {
|
|
103
|
-
|
|
105
|
+
// The view hears the changes of the container under the id it has now, and no other.
|
|
106
|
+
val id = slotId ?: return SlotContainers.unregister(this)
|
|
107
|
+
SlotContainers.register(id, this)
|
|
104
108
|
val container = SlotContainers.get(id)
|
|
105
109
|
val target: ViewGroup = container ?: this
|
|
106
110
|
if (content.parent !== target) {
|
|
@@ -115,7 +119,14 @@ class SlotView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext)
|
|
|
115
119
|
if (container != null && state != null && container.width > 0 && container.height > 0) {
|
|
116
120
|
val width = container.width.toFloat().pxToDp()
|
|
117
121
|
val height = container.height.toFloat().pxToDp()
|
|
118
|
-
|
|
122
|
+
// A container that measures the content gets one layout more for it, with the same size, until the height
|
|
123
|
+
// came.
|
|
124
|
+
val requested = ContentHeights.isSlotRequested(id)
|
|
125
|
+
// A request that went (its screen did) and comes again gets its layout again.
|
|
126
|
+
if (!requested) measureAsked = false
|
|
127
|
+
val measures = !measureAsked && requested && ContentHeights.slotHeight(id) == null
|
|
128
|
+
if (width != lastWidth || height != lastHeight || measures) {
|
|
129
|
+
measureAsked = measureAsked || measures
|
|
119
130
|
lastWidth = width
|
|
120
131
|
lastHeight = height
|
|
121
132
|
state.updateState(
|
|
@@ -135,7 +146,8 @@ class SlotView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext)
|
|
|
135
146
|
}
|
|
136
147
|
|
|
137
148
|
fun drop() {
|
|
138
|
-
|
|
149
|
+
measureAsked = false
|
|
150
|
+
SlotContainers.unregister(this)
|
|
139
151
|
(content.parent as? ViewGroup)?.removeView(content)
|
|
140
152
|
}
|
|
141
153
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package dev.apexnative.navigation.slots
|
|
2
|
+
|
|
3
|
+
import java.lang.ref.WeakReference
|
|
4
|
+
import java.util.WeakHashMap
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The slot views by their slot id, held weakly, so a change of a container reaches only the views of its id. A view is
|
|
8
|
+
* under one id at a time: registering it under a new one (its `nativeID` changed, or Fabric reused it) takes it out
|
|
9
|
+
* from under the old one. Two live views under one id both stay, in the order they came, and both hear the change, as
|
|
10
|
+
* every view with that id did when the change went to all of them. Main thread only.
|
|
11
|
+
*/
|
|
12
|
+
internal class SlotViews<T : Any> {
|
|
13
|
+
private val byId = HashMap<String, MutableList<WeakReference<T>>>()
|
|
14
|
+
private val idOf = WeakHashMap<T, String>()
|
|
15
|
+
|
|
16
|
+
fun register(slotId: String, view: T) {
|
|
17
|
+
if (idOf[view] == slotId) return
|
|
18
|
+
unregister(view)
|
|
19
|
+
idOf[view] = slotId
|
|
20
|
+
byId.getOrPut(slotId) { ArrayList(1) }.add(WeakReference(view))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fun unregister(view: T) {
|
|
24
|
+
val slotId = idOf.remove(view) ?: return
|
|
25
|
+
prune(slotId) { it === view }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The live views under [slotId], a copy: a view may register or leave while it hears the change. */
|
|
29
|
+
fun views(slotId: String): List<T> {
|
|
30
|
+
prune(slotId) { false }
|
|
31
|
+
return byId[slotId]?.mapNotNull { it.get() }.orEmpty()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Drops the collected views under the id and the ones `drop` picks; an id with no views left goes.
|
|
35
|
+
private fun prune(slotId: String, drop: (T) -> Boolean) {
|
|
36
|
+
val views = byId[slotId] ?: return
|
|
37
|
+
views.removeAll { reference -> reference.get()?.let(drop) ?: true }
|
|
38
|
+
if (views.isEmpty()) byId.remove(slotId)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
package dev.apexnative.navigation.utils
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.res.Configuration
|
|
5
|
+
import android.view.View
|
|
6
|
+
import java.io.File
|
|
7
|
+
import java.net.URI
|
|
8
|
+
import java.net.URISyntaxException
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* What an image of the options is cached by: its [uri] and what changes the decoded result for the same uri, the
|
|
12
|
+
* screen's density (a drawable of the app picks its density's file, a decoded file is scaled to it), light or dark
|
|
13
|
+
* (`drawable-night`) and the layout direction (`drawable-ldrtl`, auto-mirrored drawables). For a `file:` uri also the
|
|
14
|
+
* file's [modified] time and [size]: a file the app writes again at the same path is another image. The loader bakes
|
|
15
|
+
* no tint and no size into an image, so neither is part of it.
|
|
16
|
+
*/
|
|
17
|
+
internal data class ImageKey(
|
|
18
|
+
val uri: String,
|
|
19
|
+
val densityDpi: Int,
|
|
20
|
+
val night: Boolean,
|
|
21
|
+
val rightToLeft: Boolean,
|
|
22
|
+
/** When the file of a `file:` uri last changed, in milliseconds; 0 for any other uri or a file that isn't there. */
|
|
23
|
+
val modified: Long = 0,
|
|
24
|
+
/** The bytes of the file of a `file:` uri; 0 for any other uri or a file that isn't there. */
|
|
25
|
+
val size: Long = 0,
|
|
26
|
+
) {
|
|
27
|
+
companion object {
|
|
28
|
+
private const val FILE_SCHEME = "file:"
|
|
29
|
+
private const val FILE_PREFIX = "file://"
|
|
30
|
+
|
|
31
|
+
/** The key of [uri] in the current configuration of [context]. Any thread. */
|
|
32
|
+
fun of(context: Context, uri: String): ImageKey {
|
|
33
|
+
val configuration = context.resources.configuration
|
|
34
|
+
return of(uri, configuration.densityDpi, configuration.uiMode, configuration.layoutDirection)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The key of [uri] for a configuration's density, `uiMode` (only its night bits count) and layout direction;
|
|
39
|
+
* a `file:` uri reads its file's modification time and size. Any thread.
|
|
40
|
+
*/
|
|
41
|
+
fun of(uri: String, densityDpi: Int, uiMode: Int, layoutDirection: Int): ImageKey {
|
|
42
|
+
val file = filePath(uri)?.let(::File)
|
|
43
|
+
return ImageKey(
|
|
44
|
+
uri = uri,
|
|
45
|
+
densityDpi = densityDpi,
|
|
46
|
+
night = uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES,
|
|
47
|
+
rightToLeft = layoutDirection == View.LAYOUT_DIRECTION_RTL,
|
|
48
|
+
// Both 0 when the file isn't there or can't be read.
|
|
49
|
+
modified = file?.lastModified() ?: 0,
|
|
50
|
+
size = file?.length() ?: 0,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// The path of a `file:` uri, decoded as the loader's `Uri.getPath` decodes it; none for any other uri. A uri
|
|
55
|
+
// that `URI` can't parse (an unescaped space) is taken as it is after its scheme.
|
|
56
|
+
private fun filePath(uri: String): String? {
|
|
57
|
+
if (!uri.startsWith(FILE_SCHEME)) return null
|
|
58
|
+
val path = try {
|
|
59
|
+
URI(uri).path
|
|
60
|
+
} catch (e: URISyntaxException) {
|
|
61
|
+
null
|
|
62
|
+
}
|
|
63
|
+
return path ?: uri.removePrefix(FILE_PREFIX).removePrefix(FILE_SCHEME).ifEmpty { null }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|