@apexnative/navigation 1.0.0-alpha.4 → 1.0.0-alpha.6
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/CHANGELOG.md +38 -0
- package/README.md +1 -1
- package/android/CLAUDE.md +23 -14
- package/android/CORE.md +32 -19
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +60 -13
- package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
- package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
- package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +28 -13
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +39 -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 -51
- 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 +30 -39
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +34 -7
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +12 -12
- 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/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +22 -21
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
- 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 +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/ModalCoordinator.kt +20 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +119 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +7 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -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 +45 -14
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +25 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +3 -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 +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +3 -0
- 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 +2 -5
- 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/TopBarPresenter.kt +4 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
- package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
- 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/ElementTransitions.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +11 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +318 -25
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +18 -20
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +17 -25
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +15 -22
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +12 -9
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +84 -35
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +49 -40
- package/cli/doctor/checks/splash.js +4 -22
- package/cli/splash/index.js +3 -1
- package/docs-md/architecture/transitions.md +4 -2
- package/docs-md/containers/modals.md +4 -2
- package/docs-md/containers/overlays.md +1 -1
- package/docs-md/containers/side-menu.md +1 -1
- package/docs-md/containers/tabs.md +2 -0
- package/docs-md/flows/bottom-sheets.md +1 -1
- package/docs-md/fundamentals/starting-the-app.md +1 -1
- package/docs-md/guides/cli.md +1 -2
- package/docs-md/help/glossary.md +2 -2
- package/docs-md/help/troubleshooting.md +23 -2
- package/docs-md/index.json +12 -0
- package/docs-md/migration/from-expo-router.md +1 -1
- package/docs-md/migration/from-react-native-navigation.md +1 -1
- package/docs-md/migration/from-react-navigation.md +2 -2
- package/docs-md/screen-ui/back-and-gestures.md +36 -0
- package/docs-md/screen-ui/bar-buttons.md +4 -4
- package/docs-md/screen-ui/search.md +1 -1
- package/docs-md/screen-ui/system-ui.md +16 -11
- package/docs-md/screen-ui/toolbar-and-fab.md +2 -2
- package/docs-md/screen-ui/top-bar.md +8 -4
- package/docs-md/start/installation.md +1 -1
- package/ios/Animations/ANNFrameDriver.mm +2 -0
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +70 -4
- 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 +6 -4
- package/ios/Animations/Interpolators/ANNViewTracks.mm +49 -9
- package/ios/CLAUDE.md +17 -15
- package/ios/CORE.md +30 -26
- package/ios/Contract/ANNCommandAnswer.h +9 -2
- package/ios/Contract/ANNCommandAnswer.mm +25 -12
- package/ios/Contract/ANNCommandRunner.h +8 -7
- package/ios/Contract/ANNCommandRunner.mm +21 -27
- package/ios/Contract/ANNLayoutNode.h +3 -3
- package/ios/Contract/ANNLayoutReader.h +3 -3
- package/ios/Core/ANNAppearanceDispatcher.h +5 -4
- package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
- package/ios/Core/ANNJavaScriptCalls.h +11 -12
- package/ios/Core/ANNJavaScriptCalls.mm +7 -16
- package/ios/Core/ANNNavigationState.h +4 -6
- package/ios/Core/ANNNavigationState.mm +0 -4
- package/ios/Core/ANNReloadCoordinator.mm +4 -8
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
- package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +4 -4
- package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
- package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
- package/ios/Layouts/Screen/ANNComponentViewController.h +2 -2
- package/ios/Layouts/Screen/ANNComponentViewController.mm +9 -22
- 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/ANNScreenRegions.h +3 -18
- package/ios/Layouts/Screen/ANNScreenRegions.mm +0 -38
- package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
- package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
- package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
- package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +2 -1
- package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +123 -36
- 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/ANNBottomTabsOptions.h +2 -0
- package/ios/Options/ANNBottomTabsOptions.mm +1 -0
- package/ios/Options/ANNOptions.h +18 -0
- package/ios/Options/ANNOptions.mm +112 -1
- package/ios/Options/ANNOptionsReader.mm +110 -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/Image.h +4 -0
- package/ios/Options/Params/Image.mm +20 -0
- package/ios/React/ANNReactView.mm +6 -25
- package/ios/React/ANNSafeAreaViewComponentView.mm +26 -15
- package/ios/React/ANNSurfaceHostingView.h +6 -0
- package/ios/React/ANNSurfaceHostingView.mm +116 -0
- 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 +5 -3
- package/ios/TopBar/ANNBarButtons.mm +186 -17
- package/ios/TopBar/ANNLargeTitlePresenter.mm +24 -4
- 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 +2 -2
- package/ios/TopBar/ANNSearchResultsViewController.mm +5 -5
- package/ios/TopBar/ANNTopBarPresenter.h +3 -2
- package/ios/TopBar/ANNTopBarPresenter.mm +95 -22
- package/ios/TurboModules/ANNTurboModule.mm +20 -16
- package/lib/module/ARCHITECTURE.md +8 -4
- package/lib/module/api/commands/commands.js +54 -6
- package/lib/module/api/commands/commands.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/options/OptionsChain.js +2 -2
- package/lib/module/engine/commands.js +21 -1
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/places.js +8 -0
- package/lib/module/engine/places.js.map +1 -1
- package/lib/module/engine/screens.js +29 -4
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/typescript/api/app/createNavigation.d.ts +3 -3
- 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/hooks/useSafeAreaInsets.d.ts +4 -3
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
- package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/places.d.ts +2 -0
- package/lib/typescript/engine/places.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts +20 -6
- package/lib/typescript/engine/screens.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 +30 -9
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +18 -5
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +8 -8
- package/lib/typescript/interfaces/options/stack.d.ts +9 -0
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +8 -5
- 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 +32 -29
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ARCHITECTURE.md +8 -4
- package/src/api/app/createNavigation.ts +3 -3
- package/src/api/commands/commands.ts +48 -7
- package/src/api/commands/presentation.ts +4 -3
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/options/OptionsChain.ts +2 -2
- package/src/engine/commands.ts +30 -6
- package/src/engine/places.ts +9 -0
- package/src/engine/screens.tsx +29 -8
- package/src/interfaces/Options.ts +1 -0
- package/src/interfaces/options/animations.ts +31 -9
- package/src/interfaces/options/bottomTabs.ts +18 -5
- package/src/interfaces/options/buttons.ts +8 -8
- package/src/interfaces/options/stack.ts +9 -0
- package/src/interfaces/options/system.ts +8 -5
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +32 -29
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -42
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -70
- 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/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -70
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.react.events
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The navigation state's posted update and its hold. [setNeedsUpdate] posts one update ([post]), coalesced: the asks of
|
|
5
|
-
* one pass of the main loop make one, which runs [update] in a later pass. While a `setRoot` shows the modals and the
|
|
6
|
-
* overlays of its layout the updates are held: an ask, or a posted update that runs while held (asked before the hold
|
|
7
|
-
* was taken), only marks one as wanted, and the last release posts it. Released right before the answer, that update
|
|
8
|
-
* finds nothing new: the state before the answer is sent at once, never held, and an identical state is never sent
|
|
9
|
-
* twice. Every [hold] has one [release]; a release without a hold does nothing, so the count never goes below zero. An
|
|
10
|
-
* update keeps the JavaScript it was asked for ([generation]): one asked by a JavaScript that went before it runs is
|
|
11
|
-
* dropped; a newer ask of the new JavaScript still goes. Main thread only.
|
|
12
|
-
*/
|
|
13
|
-
internal class StateHold(
|
|
14
|
-
private val post: (() -> Unit) -> Unit,
|
|
15
|
-
private val generation: () -> Int = { 0 },
|
|
16
|
-
private val update: () -> Unit,
|
|
17
|
-
) {
|
|
18
|
-
/** The holds not released yet. */
|
|
19
|
-
var count = 0
|
|
20
|
-
private set
|
|
21
|
-
|
|
22
|
-
// An update was asked while held.
|
|
23
|
-
private var wanted = false
|
|
24
|
-
// An update is posted and hasn't run yet.
|
|
25
|
-
private var scheduled = false
|
|
26
|
-
// The JavaScript the last ask was for.
|
|
27
|
-
private var askedIn = 0
|
|
28
|
-
|
|
29
|
-
/** Asks for one update in a later pass of the main loop; while held, once the last hold is released. */
|
|
30
|
-
fun setNeedsUpdate() {
|
|
31
|
-
askedIn = generation()
|
|
32
|
-
if (count > 0) wanted = true else schedule()
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** The updates asked from now on, and those posted that run from now on, wait for as many [release]s. */
|
|
36
|
-
fun hold() {
|
|
37
|
-
count++
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** One hold ends; with the last, the update asked while held is posted now. */
|
|
41
|
-
fun release() {
|
|
42
|
-
if (count == 0) return
|
|
43
|
-
count--
|
|
44
|
-
if (count > 0 || !wanted) return
|
|
45
|
-
wanted = false
|
|
46
|
-
schedule()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private fun schedule() {
|
|
50
|
-
if (scheduled) return
|
|
51
|
-
scheduled = true
|
|
52
|
-
post {
|
|
53
|
-
scheduled = false
|
|
54
|
-
// A hold taken since it was posted: the update waits for the release. The JavaScript it was asked for
|
|
55
|
-
// went: nothing goes to the new one, which hears its first state after its own changes.
|
|
56
|
-
when {
|
|
57
|
-
count > 0 -> wanted = true
|
|
58
|
-
askedIn == generation() -> update()
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.viewcontrollers.bottomtabs
|
|
2
|
-
|
|
3
|
-
import android.app.Activity
|
|
4
|
-
import android.app.Application
|
|
5
|
-
import android.os.Bundle
|
|
6
|
-
import android.view.View
|
|
7
|
-
import android.view.ViewGroup
|
|
8
|
-
import android.view.ViewTreeObserver
|
|
9
|
-
import androidx.core.view.ViewCompat
|
|
10
|
-
import androidx.core.view.WindowInsetsCompat
|
|
11
|
-
import dev.apexnative.navigation.NavigationActivity
|
|
12
|
-
import dev.apexnative.navigation.utils.UiUtils
|
|
13
|
-
import dev.apexnative.navigation.viewcontrollers.modal.ModalContainer
|
|
14
|
-
import dev.apexnative.navigation.views.bottomtabs.BottomTabsLayout
|
|
15
|
-
import dev.apexnative.navigation.views.bottomtabs.CustomTabRow
|
|
16
|
-
import java.util.WeakHashMap
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Puts the custom rows of the tabs in their place, as it works now: an observer of every activity of the process that
|
|
20
|
-
* touches only the navigation's activities; on each layout pass of such a window it finds the tabs with a row through
|
|
21
|
-
* the view tree, and puts each row in the window's content right above the layer holding its tabs (after the rows
|
|
22
|
-
* already there) — tabs in a modal: in the modal's own view, right above its root's view (or its sheet), so the row
|
|
23
|
-
* moves with the modal and newer modals cover it —, over the bar as [CustomTabRowGeometry] says — applied only when it
|
|
24
|
-
* changed, so UI tests reach idle. A row whose tabs left the window leaves it too, and comes back to its place as they
|
|
25
|
-
* do. Before each frame the row takes its tabs' alpha (a root that waits under the old one is transparent) and the
|
|
26
|
-
* motion of the bar's container, and stays out of accessibility and touches while they wait. Main thread only.
|
|
27
|
-
*/
|
|
28
|
-
internal object CustomTabRowPlacer : Application.ActivityLifecycleCallbacks {
|
|
29
|
-
private var registered = false
|
|
30
|
-
// The listeners of each observed activity's window.
|
|
31
|
-
private val observed = WeakHashMap<Activity, Listeners>()
|
|
32
|
-
// The rows placed at the last layout pass of each activity, with their tabs.
|
|
33
|
-
private val rows = WeakHashMap<CustomTabRow, BottomTabsLayout>()
|
|
34
|
-
|
|
35
|
-
private class Listeners(
|
|
36
|
-
val observer: ViewTreeObserver,
|
|
37
|
-
val layout: ViewTreeObserver.OnGlobalLayoutListener,
|
|
38
|
-
val draw: ViewTreeObserver.OnPreDrawListener,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
/** [activity] has tabs with a row: its window is observed from now on, and the process's later activities. */
|
|
42
|
-
fun track(activity: Activity) {
|
|
43
|
-
if (!registered) {
|
|
44
|
-
registered = true
|
|
45
|
-
activity.application?.registerActivityLifecycleCallbacks(this)
|
|
46
|
-
}
|
|
47
|
-
observe(activity)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** The tabs of [row] go: the row leaves the window. */
|
|
51
|
-
fun forget(row: CustomTabRow) {
|
|
52
|
-
rows.remove(row)
|
|
53
|
-
(row.parent as? ViewGroup)?.removeView(row)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
override fun onActivityResumed(activity: Activity) = observe(activity)
|
|
57
|
-
|
|
58
|
-
override fun onActivityDestroyed(activity: Activity) {
|
|
59
|
-
val listeners = observed.remove(activity) ?: return
|
|
60
|
-
if (!listeners.observer.isAlive) return
|
|
61
|
-
listeners.observer.removeOnGlobalLayoutListener(listeners.layout)
|
|
62
|
-
listeners.observer.removeOnPreDrawListener(listeners.draw)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit
|
|
66
|
-
|
|
67
|
-
override fun onActivityStarted(activity: Activity) = Unit
|
|
68
|
-
|
|
69
|
-
override fun onActivityPaused(activity: Activity) = Unit
|
|
70
|
-
|
|
71
|
-
override fun onActivityStopped(activity: Activity) = Unit
|
|
72
|
-
|
|
73
|
-
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
|
|
74
|
-
|
|
75
|
-
// Only the navigation's activities: another activity's views are never looked for.
|
|
76
|
-
private fun observe(activity: Activity) {
|
|
77
|
-
if (activity !is NavigationActivity || observed.containsKey(activity)) return
|
|
78
|
-
val decor = activity.window?.decorView ?: return
|
|
79
|
-
val observer = decor.viewTreeObserver
|
|
80
|
-
val layout = ViewTreeObserver.OnGlobalLayoutListener { place(activity) }
|
|
81
|
-
val draw = ViewTreeObserver.OnPreDrawListener {
|
|
82
|
-
follow(activity)
|
|
83
|
-
true
|
|
84
|
-
}
|
|
85
|
-
observer.addOnGlobalLayoutListener(layout)
|
|
86
|
-
observer.addOnPreDrawListener(draw)
|
|
87
|
-
observed[activity] = Listeners(observer, layout, draw)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private fun contentOf(activity: Activity): ViewGroup? =
|
|
91
|
-
activity.window?.decorView?.findViewById(android.R.id.content)
|
|
92
|
-
|
|
93
|
-
// Each layout pass: the tabs with a row in the content, and the rows in their places.
|
|
94
|
-
private fun place(activity: NavigationActivity) {
|
|
95
|
-
val content = contentOf(activity) ?: return
|
|
96
|
-
val found = ArrayList<BottomTabsLayout>()
|
|
97
|
-
collect(content, found)
|
|
98
|
-
val placed = found.mapNotNull { tabs -> tabs.row?.also { place(activity, content, tabs, it) } }.toSet()
|
|
99
|
-
// A row whose tabs left the window leaves it too.
|
|
100
|
-
rows.entries.filter { (row, tabs) -> row !in placed && tabs.context === activity }.forEach { (row, _) ->
|
|
101
|
-
(row.parent as? ViewGroup)?.removeView(row)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
private fun collect(view: View, found: MutableList<BottomTabsLayout>) {
|
|
106
|
-
if (view is CustomTabRow) return
|
|
107
|
-
if (view is BottomTabsLayout && view.row != null) found += view
|
|
108
|
-
if (view is ViewGroup) for (index in 0 until view.childCount) collect(view.getChildAt(index), found)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private fun place(activity: NavigationActivity, content: ViewGroup, tabs: BottomTabsLayout, row: CustomTabRow) {
|
|
112
|
-
rows[row] = tabs
|
|
113
|
-
val (host, layer) = placeIn(content, tabs) ?: return
|
|
114
|
-
if (row.parent !== host) {
|
|
115
|
-
(row.parent as? ViewGroup)?.removeView(row)
|
|
116
|
-
// Margins of the host's own kind: the host converts them (a frame or a coordinator layout).
|
|
117
|
-
host.addView(row, indexAbove(host, layer, row), ViewGroup.MarginLayoutParams(0, 0))
|
|
118
|
-
row.place = null
|
|
119
|
-
} else if (host.indexOfChild(row) != indexAbove(host, layer, row)) {
|
|
120
|
-
val params = row.layoutParams
|
|
121
|
-
host.removeView(row)
|
|
122
|
-
host.addView(row, indexAbove(host, layer, row), params)
|
|
123
|
-
}
|
|
124
|
-
row.showWith(tabs.bar)
|
|
125
|
-
if (tabs.bar.visibility == View.GONE || tabs.bar.width == 0) return
|
|
126
|
-
val place = placeOf(activity, host, tabs, row)
|
|
127
|
-
if (!CustomTabRowGeometry.needsPlacing(row.place, place)) return
|
|
128
|
-
row.place = place
|
|
129
|
-
val params = row.layoutParams as? ViewGroup.MarginLayoutParams ?: return
|
|
130
|
-
params.width = place.right - place.left
|
|
131
|
-
params.height = place.bottom - place.top
|
|
132
|
-
params.leftMargin = place.left
|
|
133
|
-
params.topMargin = place.top
|
|
134
|
-
row.layoutParams = params
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Over the bar: its edges less the margins, its bottom, the height of the content and the margin below it, in the
|
|
138
|
-
// coordinates of the row's [host].
|
|
139
|
-
private fun placeOf(
|
|
140
|
-
activity: Activity,
|
|
141
|
-
host: ViewGroup,
|
|
142
|
-
tabs: BottomTabsLayout,
|
|
143
|
-
row: CustomTabRow,
|
|
144
|
-
): CustomTabRowGeometry.Place {
|
|
145
|
-
val bar = IntArray(2).also(tabs.bar::getLocationInWindow)
|
|
146
|
-
val origin = IntArray(2).also(host::getLocationInWindow)
|
|
147
|
-
val options = row.options
|
|
148
|
-
val margin = UiUtils.dpToPixels(
|
|
149
|
-
activity,
|
|
150
|
-
options.horizontalMargin.get(CustomTabRowGeometry.HORIZONTAL_MARGIN_DP.toDouble()),
|
|
151
|
-
)
|
|
152
|
-
val height = options.height.get(null)?.let { UiUtils.dpToPixels(activity, it) }
|
|
153
|
-
val extra = UiUtils.dpToPixels(activity, CustomTabRowGeometry.EXTRA_HEIGHT_DP.toDouble())
|
|
154
|
-
// Where the bar rests: its container's motion (a ride, a slide, the hide on scroll) the row takes before each
|
|
155
|
-
// frame as its own translation.
|
|
156
|
-
val left = bar[0] - origin[0] - tabs.container.translationX.toInt()
|
|
157
|
-
val top = bar[1] - origin[1] - tabs.container.translationY.toInt()
|
|
158
|
-
// Never over the navigation bar's buttons: the bar is above them, and so is the row.
|
|
159
|
-
val navigationBar = if ((activity as? NavigationActivity)?.isEdgeToEdge == true) navigationBarOf(host) else 0
|
|
160
|
-
return CustomTabRowGeometry.place(
|
|
161
|
-
barLeft = left,
|
|
162
|
-
barRight = left + tabs.bar.width,
|
|
163
|
-
barBottom = minOf(top + tabs.bar.height, host.height - navigationBar),
|
|
164
|
-
margin = margin,
|
|
165
|
-
content = CustomTabRowGeometry.content(tabs.bar.height, height, extra),
|
|
166
|
-
bottomMargin = UiUtils.dpToPixels(activity, options.bottomMargin.get(0.0)),
|
|
167
|
-
)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// The navigation bar at the bottom of the window, through the compat insets on every version.
|
|
171
|
-
private fun navigationBarOf(view: View): Int =
|
|
172
|
-
ViewCompat.getRootWindowInsets(view)?.getInsets(WindowInsetsCompat.Type.navigationBars())?.bottom ?: 0
|
|
173
|
-
|
|
174
|
-
// Where the row of [tabs] goes, and the child there it goes right above: tabs in a modal, the modal's own view and
|
|
175
|
-
// the view in it that holds them (its root's, or its sheet's container); else the content and the layer of the
|
|
176
|
-
// root or of the overlays. A sheet's drag moves it without a layout: the row doesn't follow a drag.
|
|
177
|
-
private fun placeIn(content: ViewGroup, tabs: View): Pair<ViewGroup, View>? {
|
|
178
|
-
var current: View = tabs
|
|
179
|
-
while (true) {
|
|
180
|
-
val parent = current.parent as? ViewGroup ?: return null
|
|
181
|
-
if (parent is ModalContainer || parent === content) return parent to current
|
|
182
|
-
current = parent
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Right above [layer], after the rows already there.
|
|
187
|
-
private fun indexAbove(host: ViewGroup, layer: View, row: CustomTabRow): Int {
|
|
188
|
-
var index = host.indexOfChild(layer) + 1
|
|
189
|
-
while (index < host.childCount) {
|
|
190
|
-
val child = host.getChildAt(index)
|
|
191
|
-
if (child !is CustomTabRow || child === row) break
|
|
192
|
-
index++
|
|
193
|
-
}
|
|
194
|
-
return index
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Before each frame: the row takes the alpha of its tabs up to the view it is in and the container's translation,
|
|
198
|
-
// and leaves accessibility while they wait to show.
|
|
199
|
-
private fun follow(activity: Activity) {
|
|
200
|
-
val content = contentOf(activity) ?: return
|
|
201
|
-
for ((row, tabs) in rows) {
|
|
202
|
-
val host = row.parent as? View ?: continue
|
|
203
|
-
if (host !== content && host !is ModalContainer) continue
|
|
204
|
-
var alpha = tabs.container.alpha
|
|
205
|
-
var current: View? = tabs
|
|
206
|
-
while (current != null && current !== host) {
|
|
207
|
-
alpha *= current.alpha
|
|
208
|
-
current = current.parent as? View
|
|
209
|
-
}
|
|
210
|
-
if (row.alpha != alpha) row.alpha = alpha
|
|
211
|
-
// The row goes with the bar's container: a ride, a slide, the hide on scroll.
|
|
212
|
-
val container = tabs.container
|
|
213
|
-
if (row.translationX != container.translationX) row.translationX = container.translationX
|
|
214
|
-
if (row.translationY != container.translationY) row.translationY = container.translationY
|
|
215
|
-
val mode = if (row.hiddenFromAccessibility()) {
|
|
216
|
-
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
|
217
|
-
} else {
|
|
218
|
-
View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
|
|
219
|
-
}
|
|
220
|
-
if (row.importantForAccessibility != mode) row.importantForAccessibility = mode
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
#import "ANNEventEmitter.h"
|
|
2
|
-
#import <UIKit/UIKit.h>
|
|
3
|
-
|
|
4
|
-
NS_ASSUME_NONNULL_BEGIN
|
|
5
|
-
|
|
6
|
-
/// Posted on the main queue when the padding of a screen's safe area view changed; the object is the screen id.
|
|
7
|
-
extern NSNotificationName const ANNScreenSafeAreaPaddingDidChangeNotification;
|
|
8
|
-
|
|
9
|
-
/// The safe area of each screen: how much of its content the bars and the system cover on each side. The padding is
|
|
10
|
-
/// the part of it the screen's safe area view keeps its content out of: the insets on the edges the screen's options
|
|
11
|
-
/// give. JavaScript gets the rest, what still covers the content (0 on a padded edge): it reads it from its own thread
|
|
12
|
-
/// for a screen's first render, and gets every change as `ANN.ScreenInsetsChanged`. Main queue, but the reads.
|
|
13
|
-
@interface ANNScreenInsets : NSObject
|
|
14
|
-
|
|
15
|
-
/// Keeps the screen's insets and padding, and tells when they changed.
|
|
16
|
-
+ (void)setInsets:(UIEdgeInsets)insets
|
|
17
|
-
padding:(UIEdgeInsets)padding
|
|
18
|
-
forScreenId:(NSString *)screenId
|
|
19
|
-
eventEmitter:(ANNEventEmitter *)eventEmitter;
|
|
20
|
-
/// The padding of the screen's safe area view; none before the screen was laid out. Main queue.
|
|
21
|
-
+ (UIEdgeInsets)paddingForScreenId:(NSString *)screenId;
|
|
22
|
-
/// `{ top, right, bottom, left }`, or nil before the screen was laid out. Any thread.
|
|
23
|
-
+ (nullable NSDictionary<NSString *, NSNumber *> *)insetsForScreenId:(NSString *)screenId;
|
|
24
|
-
+ (void)removeScreenId:(NSString *)screenId;
|
|
25
|
-
/// Forgets every screen: after a reload the new JavaScript counts its ids anew. Main queue.
|
|
26
|
-
+ (void)removeAll;
|
|
27
|
-
|
|
28
|
-
@end
|
|
29
|
-
|
|
30
|
-
NS_ASSUME_NONNULL_END
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
#import "ANNScreenInsets.h"
|
|
2
|
-
#import "ANNEventContract.h"
|
|
3
|
-
|
|
4
|
-
NSNotificationName const ANNScreenSafeAreaPaddingDidChangeNotification = @"ANNScreenSafeAreaPaddingDidChange";
|
|
5
|
-
|
|
6
|
-
static NSMutableDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *ANNScreenInsetsById;
|
|
7
|
-
// Main queue only.
|
|
8
|
-
static NSMutableDictionary<NSString *, NSValue *> *ANNScreenPaddingById;
|
|
9
|
-
|
|
10
|
-
@implementation ANNScreenInsets
|
|
11
|
-
|
|
12
|
-
+ (void)initialize {
|
|
13
|
-
if (self == ANNScreenInsets.class) {
|
|
14
|
-
ANNScreenInsetsById = [NSMutableDictionary new];
|
|
15
|
-
ANNScreenPaddingById = [NSMutableDictionary new];
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
+ (void)setInsets:(UIEdgeInsets)insets
|
|
20
|
-
padding:(UIEdgeInsets)padding
|
|
21
|
-
forScreenId:(NSString *)screenId
|
|
22
|
-
eventEmitter:(ANNEventEmitter *)eventEmitter {
|
|
23
|
-
NSValue *paddingValue = [NSValue valueWithUIEdgeInsets:padding];
|
|
24
|
-
if (![ANNScreenPaddingById[screenId] isEqualToValue:paddingValue]) {
|
|
25
|
-
ANNScreenPaddingById[screenId] = paddingValue;
|
|
26
|
-
[NSNotificationCenter.defaultCenter postNotificationName:ANNScreenSafeAreaPaddingDidChangeNotification
|
|
27
|
-
object:screenId];
|
|
28
|
-
}
|
|
29
|
-
// JavaScript gets what still covers the content: the edges the safe area view keeps it off are 0.
|
|
30
|
-
const auto &keys = ANNEventContract.ScreenInsetsChanged;
|
|
31
|
-
NSDictionary<NSString *, NSNumber *> *value = @{
|
|
32
|
-
keys.top : @(MAX(insets.top - padding.top, 0)),
|
|
33
|
-
keys.right : @(MAX(insets.right - padding.right, 0)),
|
|
34
|
-
keys.bottom : @(MAX(insets.bottom - padding.bottom, 0)),
|
|
35
|
-
keys.left : @(MAX(insets.left - padding.left, 0)),
|
|
36
|
-
};
|
|
37
|
-
@synchronized(ANNScreenInsetsById) {
|
|
38
|
-
if ([ANNScreenInsetsById[screenId] isEqualToDictionary:value]) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
ANNScreenInsetsById[screenId] = value;
|
|
42
|
-
}
|
|
43
|
-
[eventEmitter sendScreenInsetsChanged:screenId insets:value];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
+ (NSDictionary<NSString *, NSNumber *> *)insetsForScreenId:(NSString *)screenId {
|
|
47
|
-
@synchronized(ANNScreenInsetsById) {
|
|
48
|
-
return ANNScreenInsetsById[screenId];
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
+ (UIEdgeInsets)paddingForScreenId:(NSString *)screenId {
|
|
53
|
-
return ANNScreenPaddingById[screenId].UIEdgeInsetsValue;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
+ (void)removeScreenId:(NSString *)screenId {
|
|
57
|
-
[ANNScreenPaddingById removeObjectForKey:screenId];
|
|
58
|
-
@synchronized(ANNScreenInsetsById) {
|
|
59
|
-
[ANNScreenInsetsById removeObjectForKey:screenId];
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
+ (void)removeAll {
|
|
64
|
-
[ANNScreenPaddingById removeAllObjects];
|
|
65
|
-
@synchronized(ANNScreenInsetsById) {
|
|
66
|
-
[ANNScreenInsetsById removeAllObjects];
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@end
|