@apexnative/navigation 1.0.0-alpha.6 → 1.0.0-alpha.8
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 +15 -0
- package/android/CLAUDE.md +19 -10
- package/android/CORE.md +3 -2
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +1 -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/SheetOptions.kt +7 -4
- 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/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/NavigationTurboModule.kt +4 -0
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +41 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +16 -1
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +12 -1
- package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +329 -55
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +26 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +60 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +8 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +32 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +46 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +15 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +7 -4
- 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 +215 -43
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +25 -26
- 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/TopBarPresenter.kt +86 -39
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +124 -181
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +8 -1
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +56 -3
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +170 -153
- 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 +55 -45
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/{TextChangeAnimator.kt → TextMorph.kt} +79 -129
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
- 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 -24
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +51 -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 +121 -175
- 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/doctor/checks/app.js +16 -1
- package/cli/project.js +4 -0
- package/cli/setup/index.js +5 -0
- package/cli/setup/steps/metro.js +46 -0
- 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 +43 -4
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/fundamentals/screens-and-props.md +9 -1
- package/docs-md/guides/cli.md +3 -1
- package/docs-md/help/troubleshooting.md +1 -1
- package/docs-md/index.json +29 -1
- package/docs-md/screen-ui/back-and-gestures.md +3 -1
- package/docs-md/screen-ui/bar-buttons.md +1 -1
- package/docs-md/screen-ui/toolbar-and-fab.md +2 -0
- package/docs-md/start/installation.md +16 -1
- package/ios/Animations/ANNFrameDriver.h +55 -15
- package/ios/Animations/ANNFrameDriver.mm +214 -60
- package/ios/Animations/ANNTransitionAnimator.h +26 -5
- package/ios/Animations/ANNTransitionAnimator.mm +49 -3
- package/ios/Animations/ANNTransitionPlan.h +2 -2
- package/ios/Animations/ANNTransitionPlan.mm +10 -0
- package/ios/Animations/Elements/ANNElementFinder.h +2 -2
- package/ios/Animations/Elements/ANNElementFinder.mm +2 -2
- package/ios/Animations/Elements/ANNElementTransition.h +3 -3
- package/ios/Animations/Elements/ANNElementTransition.mm +2 -2
- package/ios/Animations/Elements/ANNSharedElementFlight.h +3 -3
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +181 -43
- package/ios/Animations/Interpolators/ANNViewTracks.h +6 -5
- package/ios/Animations/Interpolators/ANNViewTracks.mm +51 -21
- package/ios/CLAUDE.md +19 -8
- package/ios/CORE.md +1 -1
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNDeepLinkQueue.h +6 -5
- package/ios/Core/ANNDeepLinkQueue.mm +22 -10
- package/ios/Core/ANNSceneDelegate.mm +2 -2
- package/ios/Core/ANNUtils.h +7 -0
- package/ios/Core/ANNUtils.mm +10 -0
- package/ios/Core/ApexNavigation.mm +6 -2
- package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +1 -7
- package/ios/Layouts/Root/ANNRootCoordinator.mm +45 -15
- package/ios/Layouts/Screen/ANNComponentViewController.mm +4 -1
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
- package/ios/Layouts/Stack/ANNStackController.h +8 -0
- package/ios/Layouts/Stack/ANNStackController.mm +153 -11
- 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/Tabs/ANNTabsPreloadWindow.mm +2 -4
- package/ios/Options/ANNAnimationOptions.h +2 -1
- package/ios/Options/ANNAnimationOptions.mm +1 -1
- package/ios/Options/ANNOptions.h +7 -0
- package/ios/Options/ANNOptions.mm +45 -0
- package/ios/Options/ANNOptionsReader.mm +2 -4
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/Params/ColorParser.h +4 -3
- package/ios/Options/Params/ColorParser.mm +22 -4
- package/ios/React/ANNSurfaceHostingView.h +8 -0
- package/ios/React/ANNSurfaceHostingView.mm +28 -1
- package/ios/React/Slots/ANNSlotHost.mm +1 -3
- package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
- package/ios/TurboModules/ANNTurboModule.mm +46 -0
- 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 +9 -3
- 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 +188 -66
- package/lib/module/api/app/createNavigation.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/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.js.map +1 -1
- 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 +21 -1
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +7 -2
- 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 +5 -4
- 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/refresh.js +85 -0
- package/lib/module/engine/refresh.js.map +1 -0
- package/lib/module/engine/rememberedOptions.js +60 -0
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +26 -0
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +7 -0
- 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 +5 -0
- package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +2 -2
- package/lib/typescript/api/events/navigationEvents.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/linking.d.ts +8 -0
- package/lib/typescript/api/linking/linking.d.ts.map +1 -1
- 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/optionsChange.d.ts +28 -0
- package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
- 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 +7 -0
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
- package/lib/typescript/interfaces/options/animations.d.ts +40 -15
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +2 -2
- package/lib/typescript/interfaces/options/buttons.d.ts +2 -2
- package/lib/typescript/interfaces/options/modals.d.ts +6 -7
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +8 -3
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/topBar.d.ts +14 -0
- 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 +9 -3
- package/src/adapters/NativeANNTurboModule.ts +7 -0
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +198 -66
- package/src/api/events/navigationEvents.ts +9 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/linking.ts +22 -1
- 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 +21 -0
- package/src/engine/layout.ts +11 -2
- package/src/engine/nativeScreens.ts +10 -1
- package/src/engine/options.ts +6 -8
- package/src/engine/optionsChange.ts +107 -0
- package/src/engine/refresh.ts +97 -0
- package/src/engine/rememberedOptions.ts +70 -0
- package/src/engine/screens.tsx +24 -0
- package/src/interfaces/ComponentEvents.ts +2 -2
- package/src/interfaces/options/animations.ts +40 -15
- package/src/interfaces/options/bottomTabs.ts +2 -2
- package/src/interfaces/options/buttons.ts +2 -2
- package/src/interfaces/options/modals.ts +6 -7
- package/src/interfaces/options/stack.ts +8 -3
- package/src/interfaces/options/topBar.ts +14 -0
- 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 -134
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -78
- 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 -57
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -146
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
package dev.apexnative.navigation.react
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
5
|
import com.facebook.react.bridge.ReadableMap
|
|
6
|
+
import com.facebook.react.bridge.ReadableType
|
|
5
7
|
import dev.apexnative.navigation.options.DefaultOptions
|
|
8
|
+
import dev.apexnative.navigation.options.OptionPaths
|
|
6
9
|
import dev.apexnative.navigation.options.Options
|
|
7
10
|
import dev.apexnative.navigation.options.OptionsReader
|
|
8
11
|
import dev.apexnative.navigation.system.AppDirection
|
|
@@ -10,9 +13,9 @@ import dev.apexnative.navigation.viewcontrollers.navigator.Navigators
|
|
|
10
13
|
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
|
-
* The commands of the options, `setDefaultOptions` and `
|
|
14
|
-
* on the module thread, in the runner's step before the main task; the main task stores
|
|
15
|
-
* read is logged (`[ApexNavigation] <method>: <text>`); the app goes on.
|
|
16
|
+
* The commands of the options, `setDefaultOptions`, `mergeOptions` and `clearOptions`: all without a promise. Their
|
|
17
|
+
* options and paths are read on the module thread, in the runner's step before the main task; the main task stores
|
|
18
|
+
* and applies them. What can't be read is logged (`[ApexNavigation] <method>: <text>`); the app goes on.
|
|
16
19
|
*/
|
|
17
20
|
internal class OptionsCommands(
|
|
18
21
|
private val runner: CommandRunner,
|
|
@@ -30,6 +33,11 @@ internal class OptionsCommands(
|
|
|
30
33
|
* system UI follows (`Navigator.optionsMerged`, `mergeOptions` step 5). Main thread.
|
|
31
34
|
*/
|
|
32
35
|
private val merged: (ViewController<*>, Options) -> Unit = { _, _ -> },
|
|
36
|
+
/**
|
|
37
|
+
* Repaints what shows in the current navigation activity, as [repaint] does without new default options
|
|
38
|
+
* (`Navigator.repaint`), after `clearOptions`. Main thread.
|
|
39
|
+
*/
|
|
40
|
+
private val repaintCurrent: () -> Unit = {},
|
|
33
41
|
) {
|
|
34
42
|
constructor(runner: CommandRunner, context: () -> Context?) : this(
|
|
35
43
|
runner = runner,
|
|
@@ -40,6 +48,7 @@ internal class OptionsCommands(
|
|
|
40
48
|
Navigators.all().forEach { it.navigator?.defaultOptionsChanged(direction) }
|
|
41
49
|
},
|
|
42
50
|
merged = { node, options -> Navigators.current()?.navigator?.optionsMerged(node, options) },
|
|
51
|
+
repaintCurrent = { Navigators.current()?.navigator?.repaint() },
|
|
43
52
|
)
|
|
44
53
|
|
|
45
54
|
/**
|
|
@@ -82,8 +91,37 @@ internal class OptionsCommands(
|
|
|
82
91
|
merged(node, read.options)
|
|
83
92
|
}
|
|
84
93
|
|
|
94
|
+
/**
|
|
95
|
+
* `clearOptions` (development: Fast Refresh, after an edit took options out of a screen that shows): the values at
|
|
96
|
+
* [paths] (`topBar.subtitle`; a group's path for the whole group) leave the own options of the node [componentId]
|
|
97
|
+
* names, through `ViewController.changeOptions` ([OptionPaths.clear]), so it resolves to what the layouts around it
|
|
98
|
+
* and the defaults give there; the user layer stays. The stack it is in writes its back arrow's visibility into
|
|
99
|
+
* them again (`StackController.ownOptionsCleared`), then what shows is repainted as after `setDefaultOptions`. No
|
|
100
|
+
* node with that id, or no path that names an option: nothing, not even a log line. Without an activity: one log
|
|
101
|
+
* line, as `mergeOptions`.
|
|
102
|
+
*/
|
|
103
|
+
fun clearOptions(componentId: String, paths: ReadableArray) = runner.runVoid(
|
|
104
|
+
name = CLEAR_OPTIONS,
|
|
105
|
+
what = "clear the options of the screen '$componentId'",
|
|
106
|
+
prepare = {
|
|
107
|
+
(0 until paths.size()).filter { paths.getType(it) == ReadableType.String }.mapNotNull(paths::getString)
|
|
108
|
+
},
|
|
109
|
+
) { read ->
|
|
110
|
+
if (!runner.hasActivity()) {
|
|
111
|
+
runner.logFailure(CLEAR_OPTIONS, ErrorTexts.nowhereToShow())
|
|
112
|
+
return@runVoid
|
|
113
|
+
}
|
|
114
|
+
val node = findNode(componentId) ?: return@runVoid
|
|
115
|
+
val known = read.filter { OptionPaths.find(node.options, it) != null }
|
|
116
|
+
if (known.isEmpty()) return@runVoid
|
|
117
|
+
node.changeOptions { own -> known.forEach { OptionPaths.clear(own, it) } }
|
|
118
|
+
node.findParentStack()?.ownOptionsCleared(node)
|
|
119
|
+
repaintCurrent()
|
|
120
|
+
}
|
|
121
|
+
|
|
85
122
|
private companion object {
|
|
86
123
|
const val SET_DEFAULT_OPTIONS = "setDefaultOptions"
|
|
87
124
|
const val MERGE_OPTIONS = "mergeOptions"
|
|
125
|
+
const val CLEAR_OPTIONS = "clearOptions"
|
|
88
126
|
}
|
|
89
127
|
}
|
|
@@ -3,6 +3,7 @@ package dev.apexnative.navigation.react
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.os.Bundle
|
|
6
|
+
import android.util.Size
|
|
6
7
|
import android.view.MotionEvent
|
|
7
8
|
import android.view.ViewGroup
|
|
8
9
|
import android.widget.FrameLayout
|
|
@@ -28,7 +29,9 @@ import dev.apexnative.navigation.viewcontrollers.viewcontroller.ScrollEventListe
|
|
|
28
29
|
* never makes this one ready. A screen without a safe area view (no view ever told anything of its id) is ready once
|
|
29
30
|
* the root view of its surface has children, read on this view's own layout passes. A root that renders at once
|
|
30
31
|
* ([rendersAtOnce]: a component of a bar, a tab's cell) marks its id so from before its surface starts until it stops.
|
|
31
|
-
* Ready once, ready for good; what waits for it ([whenReady]) runs then, once.
|
|
32
|
+
* Ready once, ready for good; what waits for it ([whenReady]) runs then, once. Its content measures without a height
|
|
33
|
+
* limit ([contentSize], `ContentHeights`), and the handlers of [setOnContentMounted] hear each mount of Fabric while
|
|
34
|
+
* the view is in a window.
|
|
32
35
|
* Without a signal or children, the limits of what waits decide: the view has no timer of its own. It owns the
|
|
33
36
|
* record of its appearance, which the dispatcher of the appearance events holds until the content is ready
|
|
34
37
|
* (`AppearanceDispatcher`).
|
|
@@ -51,6 +54,7 @@ class ReactView @JvmOverloads constructor(
|
|
|
51
54
|
private var readyTold = false
|
|
52
55
|
private val readyListeners = mutableListOf<Runnable>()
|
|
53
56
|
private var listening = false
|
|
57
|
+
private val mounts = ContentMounts { !destroyed && isAttachedToWindow }
|
|
54
58
|
|
|
55
59
|
// What this root hears of its id: only the signals of its own surface.
|
|
56
60
|
private val readiness = object : ScreenReadiness.Listener {
|
|
@@ -112,6 +116,16 @@ class ReactView @JvmOverloads constructor(
|
|
|
112
116
|
override val touchRoot: ViewGroup?
|
|
113
117
|
get() = surface?.view as? ViewGroup
|
|
114
118
|
|
|
119
|
+
override fun contentSize(maxWidth: Int): Size? {
|
|
120
|
+
val surface = surface ?: return null
|
|
121
|
+
val height = ContentHeights.surfaceHeight(context, surface, maxWidth) ?: return null
|
|
122
|
+
return Size(maxWidth, height)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
override fun setOnContentMounted(key: String, handler: Runnable?) {
|
|
126
|
+
if (!destroyed) mounts.set(key, handler)
|
|
127
|
+
}
|
|
128
|
+
|
|
115
129
|
override fun isReady(): Boolean {
|
|
116
130
|
if (!ready && hasRendered()) ready = true
|
|
117
131
|
return ready
|
|
@@ -167,6 +181,7 @@ class ReactView @JvmOverloads constructor(
|
|
|
167
181
|
AppearanceDispatcher.didDisappear(appearance)
|
|
168
182
|
destroyed = true
|
|
169
183
|
readyListeners.clear()
|
|
184
|
+
mounts.clear()
|
|
170
185
|
stopListening()
|
|
171
186
|
if (rendersAtOnce) ScreenReadiness.setRendersAtOnce(componentId, this, false)
|
|
172
187
|
val surface = surface ?: return
|
|
@@ -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,7 +35,7 @@ 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
|
|
38
|
+
private val mounts = ContentMounts { !destroyed && isAttachedToWindow }
|
|
34
39
|
private var listening = false
|
|
35
40
|
|
|
36
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.
|
|
@@ -84,10 +89,11 @@ class SlotScreenView(
|
|
|
84
89
|
destroyed = true
|
|
85
90
|
whenMounted.clear()
|
|
86
91
|
whenRendered.clear()
|
|
87
|
-
|
|
92
|
+
mounts.clear()
|
|
88
93
|
stopListening()
|
|
89
94
|
// A later screen with the same id keeps the slot.
|
|
90
95
|
if (SlotContainers.get(componentId) !== this) return
|
|
96
|
+
ContentHeights.forgetSlot(componentId)
|
|
91
97
|
SlotContainers.remove(componentId)
|
|
92
98
|
if (!isPreparedPush) AppearanceDispatcher.slotDestroyed(componentId, appearance.generation)
|
|
93
99
|
}
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -116,7 +119,14 @@ class SlotView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext)
|
|
|
116
119
|
if (container != null && state != null && container.width > 0 && container.height > 0) {
|
|
117
120
|
val width = container.width.toFloat().pxToDp()
|
|
118
121
|
val height = container.height.toFloat().pxToDp()
|
|
119
|
-
|
|
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
|
|
120
130
|
lastWidth = width
|
|
121
131
|
lastHeight = height
|
|
122
132
|
state.updateState(
|
|
@@ -136,6 +146,7 @@ class SlotView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext)
|
|
|
136
146
|
}
|
|
137
147
|
|
|
138
148
|
fun drop() {
|
|
149
|
+
measureAsked = false
|
|
139
150
|
SlotContainers.unregister(this)
|
|
140
151
|
(content.parent as? ViewGroup)?.removeView(content)
|
|
141
152
|
}
|
|
@@ -28,7 +28,7 @@ internal object MaterialTheme {
|
|
|
28
28
|
private val wrappers = WeakHashMap<Context, WeakReference<Context>>()
|
|
29
29
|
// Themes of the navigation's own views, each made once over the activity's with a style of its own.
|
|
30
30
|
private val followers = WeakHashMap<Context, Int>()
|
|
31
|
-
// The popup theme of the bar's
|
|
31
|
+
// The popup theme of the bar's "⋮" per activity: the app's theme doesn't change while the activity lives.
|
|
32
32
|
private val popupThemes = WeakHashMap<Activity, Int>()
|
|
33
33
|
|
|
34
34
|
fun context(context: Context): Context {
|
|
@@ -38,11 +38,10 @@ internal object MaterialTheme {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* The popup theme of the top bar's
|
|
42
|
-
* theme follows light and dark: the menu takes the bar's own theme, which [rebase]
|
|
43
|
-
* the app's colors. With a Material 3 theme fixed to light or to dark, a day/night
|
|
44
|
-
* current mode's colors where the theme shows the other mode.
|
|
45
|
-
* first opening, in the mode of that moment, and no public API makes it again for a later switch.
|
|
41
|
+
* The popup theme of the top bar's "⋮", over the bar's theme at each opening of its popup, in the mode of that
|
|
42
|
+
* moment. None when the app's theme follows light and dark: the menu takes the bar's own theme, which [rebase]
|
|
43
|
+
* keeps in the current mode, with the app's colors. With a Material 3 theme fixed to light or to dark, a day/night
|
|
44
|
+
* overlay that gives the menu the current mode's colors where the theme shows the other mode.
|
|
46
45
|
*/
|
|
47
46
|
fun popupTheme(context: Context): Int {
|
|
48
47
|
val activity = activityOf(context) ?: return 0
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package dev.apexnative.navigation.utils
|
|
2
|
+
|
|
3
|
+
import android.animation.ValueAnimator
|
|
4
|
+
import android.annotation.SuppressLint
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.os.Build
|
|
7
|
+
import android.provider.Settings
|
|
8
|
+
import dev.apexnative.navigation.NavigationApplication
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Whether the system plays no animations: "Remove animations" in the accessibility settings, or the animator duration
|
|
12
|
+
* scale at 0 in the developer options. Then a transition doesn't wait for its elements' targets and images and moves no
|
|
13
|
+
* element, and the side menu opens and closes at once. Any thread.
|
|
14
|
+
*/
|
|
15
|
+
internal object SystemAnimations {
|
|
16
|
+
/**
|
|
17
|
+
* The animations are off now; [context] reads the scale below Android 8, else the application's. Lint can't see
|
|
18
|
+
* that the decision calls `areAnimatorsEnabled` (API 26) only from Android 8.
|
|
19
|
+
*/
|
|
20
|
+
@SuppressLint("NewApi")
|
|
21
|
+
fun areOff(context: Context? = null): Boolean =
|
|
22
|
+
areOff(Build.VERSION.SDK_INT, { ValueAnimator.areAnimatorsEnabled() }) { durationScaleOf(context) }
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The decision: from Android 8 the animator's own answer ([animatorsEnabled]), which follows both settings;
|
|
26
|
+
* below it the duration scale ([durationScale]) at 0.
|
|
27
|
+
*/
|
|
28
|
+
fun areOff(sdk: Int, animatorsEnabled: () -> Boolean, durationScale: () -> Float): Boolean =
|
|
29
|
+
if (sdk >= Build.VERSION_CODES.O) !animatorsEnabled() else durationScale() == 0f
|
|
30
|
+
|
|
31
|
+
// Without a context and before the application started (the unit tests), the animations play.
|
|
32
|
+
private fun durationScaleOf(context: Context?): Float {
|
|
33
|
+
val resolver = (context ?: NavigationApplication.instanceOrNull)?.contentResolver ?: return 1f
|
|
34
|
+
return Settings.Global.getFloat(resolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f)
|
|
35
|
+
}
|
|
36
|
+
}
|