pythonnative 0.40.0__cp313-cp313-win_amd64.whl
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.
- pythonnative/__init__.py +411 -0
- pythonnative/_ios_log.py +92 -0
- pythonnative/_yoga.cp313-win_amd64.pyd +0 -0
- pythonnative/alerts.py +236 -0
- pythonnative/animated.py +1687 -0
- pythonnative/animation_graph.py +78 -0
- pythonnative/appearance.py +124 -0
- pythonnative/bootstrap.py +100 -0
- pythonnative/bridge/__init__.py +302 -0
- pythonnative/bridge/android.py +78 -0
- pythonnative/bridge/codec.py +170 -0
- pythonnative/bridge/commits.py +114 -0
- pythonnative/bridge/fake.py +243 -0
- pythonnative/bridge/ios.py +138 -0
- pythonnative/bridge/web.py +489 -0
- pythonnative/cli/__init__.py +7 -0
- pythonnative/cli/pn.py +1214 -0
- pythonnative/component.py +271 -0
- pythonnative/components/__init__.py +111 -0
- pythonnative/components/_base.py +166 -0
- pythonnative/components/controls.py +521 -0
- pythonnative/components/layout.py +518 -0
- pythonnative/components/lists.py +785 -0
- pythonnative/components/media.py +204 -0
- pythonnative/components/overlays.py +107 -0
- pythonnative/components/pressable.py +252 -0
- pythonnative/components/structural.py +167 -0
- pythonnative/components/text.py +291 -0
- pythonnative/devclient.py +824 -0
- pythonnative/devserver/__init__.py +34 -0
- pythonnative/devserver/server.py +718 -0
- pythonnative/devserver/static/animation_graph.js +82 -0
- pythonnative/devserver/static/bridge.js +147 -0
- pythonnative/devserver/static/colors.js +70 -0
- pythonnative/devserver/static/host.js +552 -0
- pythonnative/devserver/static/index.html +60 -0
- pythonnative/devserver/static/layout.js +85 -0
- pythonnative/devserver/static/preview.css +415 -0
- pythonnative/devserver/static/renderer.js +1994 -0
- pythonnative/devserver/static/shell.js +345 -0
- pythonnative/devserver/static/yoga/LICENSE +21 -0
- pythonnative/devserver/static/yoga/binaries/yoga-wasm-base64-esm.js +75 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.d.ts +189 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js +211 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js.map +1 -0
- pythonnative/devserver/static/yoga/src/index.d.ts +12 -0
- pythonnative/devserver/static/yoga/src/index.js +16 -0
- pythonnative/devserver/static/yoga/src/index.js.map +1 -0
- pythonnative/devserver/static/yoga/src/load.d.ts +11 -0
- pythonnative/devserver/static/yoga/src/load.js +17 -0
- pythonnative/devserver/static/yoga/src/load.js.map +1 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.d.ts +155 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js +125 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js.map +1 -0
- pythonnative/devserver/watcher.py +267 -0
- pythonnative/devserver/ws.py +421 -0
- pythonnative/diagnostics.py +241 -0
- pythonnative/element.py +159 -0
- pythonnative/equality.py +19 -0
- pythonnative/events.py +231 -0
- pythonnative/gestures.py +1333 -0
- pythonnative/hooks.py +1621 -0
- pythonnative/hosts/__init__.py +63 -0
- pythonnative/hosts/base.py +596 -0
- pythonnative/hosts/native.py +302 -0
- pythonnative/hot_reload.py +585 -0
- pythonnative/layout.py +328 -0
- pythonnative/mutations.py +142 -0
- pythonnative/native/android/build.gradle +52 -0
- pythonnative/native/android/gradle.properties +3 -0
- pythonnative/native/android/settings.gradle +12 -0
- pythonnative/native/android/src/main/AndroidManifest.xml +11 -0
- pythonnative/native/android/src/main/cpp/CMakeLists.txt +9 -0
- pythonnative/native/android/src/main/cpp/yoga_jni.cpp +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeModules.kt +5 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeProps.kt +3705 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/PNContracts.kt +129 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PNBridge.kt +261 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationGraph.kt +108 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +257 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/CommitState.kt +106 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +40 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +117 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +37 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +32 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +162 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +86 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScreenStackManager.kt +110 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +250 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +159 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/NativeLayout.kt +145 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/YogaNode.kt +29 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +61 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +158 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +99 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +188 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt +48 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNBorderDrawable.kt +76 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNFrameLayout.kt +49 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PromiseTest.kt +89 -0
- pythonnative/native/ios/Package.swift +23 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimationGraph.swift +199 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimator.swift +312 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNBridge.swift +255 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNCommit.swift +104 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNRegistry.swift +142 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNTransaction.swift +166 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNButtonManagers.swift +207 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNImageManager.swift +222 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScreenStackManager.swift +107 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextInputManager.swift +297 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +155 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeModules.swift +1 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeProps.swift +3775 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/PNContracts.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Layout/PNLayout.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/HostModule.swift +80 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PNNativeModule.swift +168 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PermissionModules.swift +266 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNViewController.swift +237 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNAnimationGraphTests.swift +26 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNCommitTests.swift +86 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNManagerTests.swift +126 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNModuleTests.swift +111 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
- pythonnative/native/yoga/LICENSE +21 -0
- pythonnative/native/yoga/Package.swift +9 -0
- pythonnative/native/yoga/VENDORED.md +2 -0
- pythonnative/native/yoga/include/PNStyle.h +10 -0
- pythonnative/native/yoga/include/module.modulemap +5 -0
- pythonnative/native/yoga/include/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/include/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/include/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/include/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/include/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/include/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/include/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/include/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/include/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/python.cpp +16 -0
- pythonnative/native/yoga/style.cpp +272 -0
- pythonnative/native/yoga/yoga/CMakeLists.txt +41 -0
- pythonnative/native/yoga/yoga/YGConfig.cpp +92 -0
- pythonnative/native/yoga/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/yoga/YGEnums.cpp +262 -0
- pythonnative/native/yoga/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/yoga/YGNode.cpp +366 -0
- pythonnative/native/yoga/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.cpp +92 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.cpp +405 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.cpp +22 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/YGValue.cpp +20 -0
- pythonnative/native/yoga/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.cpp +563 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.h +41 -0
- pythonnative/native/yoga/yoga/algorithm/Align.h +72 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.cpp +78 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/BoundAxis.h +79 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.cpp +121 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.h +30 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.cpp +2428 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.h +38 -0
- pythonnative/native/yoga/yoga/algorithm/FlexDirection.h +120 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.cpp +124 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.h +75 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.cpp +132 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/algorithm/SizingMode.h +73 -0
- pythonnative/native/yoga/yoga/algorithm/TrailingPosition.h +44 -0
- pythonnative/native/yoga/yoga/config/Config.cpp +135 -0
- pythonnative/native/yoga/yoga/config/Config.h +92 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.cpp +53 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.h +29 -0
- pythonnative/native/yoga/yoga/debug/Log.cpp +107 -0
- pythonnative/native/yoga/yoga/debug/Log.h +34 -0
- pythonnative/native/yoga/yoga/enums/Align.h +47 -0
- pythonnative/native/yoga/yoga/enums/BoxSizing.h +40 -0
- pythonnative/native/yoga/yoga/enums/Dimension.h +40 -0
- pythonnative/native/yoga/yoga/enums/Direction.h +41 -0
- pythonnative/native/yoga/yoga/enums/Display.h +41 -0
- pythonnative/native/yoga/yoga/enums/Edge.h +47 -0
- pythonnative/native/yoga/yoga/enums/Errata.h +41 -0
- pythonnative/native/yoga/yoga/enums/ExperimentalFeature.h +39 -0
- pythonnative/native/yoga/yoga/enums/FlexDirection.h +42 -0
- pythonnative/native/yoga/yoga/enums/Gutter.h +41 -0
- pythonnative/native/yoga/yoga/enums/Justify.h +44 -0
- pythonnative/native/yoga/yoga/enums/LogLevel.h +44 -0
- pythonnative/native/yoga/yoga/enums/MeasureMode.h +41 -0
- pythonnative/native/yoga/yoga/enums/NodeType.h +40 -0
- pythonnative/native/yoga/yoga/enums/Overflow.h +41 -0
- pythonnative/native/yoga/yoga/enums/PhysicalEdge.h +21 -0
- pythonnative/native/yoga/yoga/enums/PositionType.h +41 -0
- pythonnative/native/yoga/yoga/enums/Unit.h +42 -0
- pythonnative/native/yoga/yoga/enums/Wrap.h +41 -0
- pythonnative/native/yoga/yoga/enums/YogaEnums.h +85 -0
- pythonnative/native/yoga/yoga/event/event.cpp +87 -0
- pythonnative/native/yoga/yoga/event/event.h +130 -0
- pythonnative/native/yoga/yoga/module.modulemap +21 -0
- pythonnative/native/yoga/yoga/node/CachedMeasurement.h +53 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.cpp +48 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.h +122 -0
- pythonnative/native/yoga/yoga/node/LayoutableChildren.h +148 -0
- pythonnative/native/yoga/yoga/node/Node.cpp +443 -0
- pythonnative/native/yoga/yoga/node/Node.h +337 -0
- pythonnative/native/yoga/yoga/numeric/Comparison.h +81 -0
- pythonnative/native/yoga/yoga/numeric/FloatOptional.h +93 -0
- pythonnative/native/yoga/yoga/style/SmallValueBuffer.h +133 -0
- pythonnative/native/yoga/yoga/style/Style.h +757 -0
- pythonnative/native/yoga/yoga/style/StyleLength.h +107 -0
- pythonnative/native/yoga/yoga/style/StyleValueHandle.h +98 -0
- pythonnative/native/yoga/yoga/style/StyleValuePool.h +127 -0
- pythonnative/native_modules/__init__.py +124 -0
- pythonnative/native_modules/app_state.py +99 -0
- pythonnative/native_modules/battery.py +75 -0
- pythonnative/native_modules/biometrics.py +42 -0
- pythonnative/native_modules/camera.py +65 -0
- pythonnative/native_modules/clipboard.py +46 -0
- pythonnative/native_modules/fallback.py +324 -0
- pythonnative/native_modules/file_system.py +145 -0
- pythonnative/native_modules/haptics.py +75 -0
- pythonnative/native_modules/linking.py +123 -0
- pythonnative/native_modules/location.py +75 -0
- pythonnative/native_modules/net_info.py +112 -0
- pythonnative/native_modules/notifications.py +129 -0
- pythonnative/native_modules/permissions.py +108 -0
- pythonnative/native_modules/registry.py +526 -0
- pythonnative/native_modules/secure_store.py +52 -0
- pythonnative/native_modules/share.py +51 -0
- pythonnative/native_views/__init__.py +375 -0
- pythonnative/native_views/base.py +316 -0
- pythonnative/native_views/bridge_backend.py +277 -0
- pythonnative/navigation/__init__.py +103 -0
- pythonnative/navigation/container.py +154 -0
- pythonnative/navigation/handle.py +540 -0
- pythonnative/navigation/hooks.py +133 -0
- pythonnative/navigation/host.py +58 -0
- pythonnative/navigation/linking.py +200 -0
- pythonnative/navigation/navigators.py +659 -0
- pythonnative/navigation/screen.py +149 -0
- pythonnative/navigation/state.py +269 -0
- pythonnative/net.py +248 -0
- pythonnative/platform.py +166 -0
- pythonnative/platform_metrics.py +252 -0
- pythonnative/preview.py +287 -0
- pythonnative/profiling.py +101 -0
- pythonnative/project/__init__.py +68 -0
- pythonnative/project/android.py +557 -0
- pythonnative/project/builder.py +817 -0
- pythonnative/project/config.py +773 -0
- pythonnative/project/deps.py +719 -0
- pythonnative/project/devices.py +304 -0
- pythonnative/project/doctor.py +283 -0
- pythonnative/project/fingerprint.py +171 -0
- pythonnative/project/icons.py +247 -0
- pythonnative/project/ios.py +325 -0
- pythonnative/project/lockfile.py +100 -0
- pythonnative/project/permissions.py +361 -0
- pythonnative/project/plugins.py +519 -0
- pythonnative/project/runtime_assets.py +183 -0
- pythonnative/py.typed +0 -0
- pythonnative/query.py +153 -0
- pythonnative/reconciler/__init__.py +29 -0
- pythonnative/reconciler/boundaries.py +375 -0
- pythonnative/reconciler/children.py +88 -0
- pythonnative/reconciler/core.py +1165 -0
- pythonnative/reconciler/layout_pass.py +393 -0
- pythonnative/reconciler/vnode.py +266 -0
- pythonnative/refresh.py +55 -0
- pythonnative/runtime.py +306 -0
- pythonnative/scheduler.py +159 -0
- pythonnative/sdk/__init__.py +153 -0
- pythonnative/sdk/_components.py +427 -0
- pythonnative/sdk/builtins.py +91 -0
- pythonnative/sdk/codegen.py +149 -0
- pythonnative/sdk/module_codegen.py +184 -0
- pythonnative/sdk/schema.py +224 -0
- pythonnative/sdk/templates/contracts.kt +46 -0
- pythonnative/sdk/templates/contracts.swift +46 -0
- pythonnative/storage.py +184 -0
- pythonnative/style.py +841 -0
- pythonnative/suspense.py +183 -0
- pythonnative/templates/android_template/app/build.gradle +75 -0
- pythonnative/templates/android_template/app/proguard-rules.pro +21 -0
- pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +24 -0
- pythonnative/templates/android_template/app/src/debug/AndroidManifest.xml +7 -0
- pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +32 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +130 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -0
- pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
- pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
- pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +10 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +22 -0
- pythonnative/templates/android_template/app/src/main/res/values/colors.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/strings.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/themes.xml +9 -0
- pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +7 -0
- pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +13 -0
- pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
- pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +17 -0
- pythonnative/templates/android_template/build.gradle +10 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +6 -0
- pythonnative/templates/android_template/gradle.properties +23 -0
- pythonnative/templates/android_template/gradlew +185 -0
- pythonnative/templates/android_template/gradlew.bat +89 -0
- pythonnative/templates/android_template/settings.gradle +17 -0
- pythonnative/templates/ios_template/ios_template/AppDelegate.swift +51 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +6 -0
- pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +25 -0
- pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
- pythonnative/templates/ios_template/ios_template/Info.plist +28 -0
- pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +390 -0
- pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +61 -0
- pythonnative/templates/ios_template/ios_template/ViewController.swift +23 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +745 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +36 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +41 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +32 -0
- pythonnative/testing/__init__.py +53 -0
- pythonnative/testing/backend.py +276 -0
- pythonnative/testing/harness.py +369 -0
- pythonnative/utils.py +145 -0
- pythonnative-0.40.0.dist-info/DELVEWHEEL +2 -0
- pythonnative-0.40.0.dist-info/METADATA +150 -0
- pythonnative-0.40.0.dist-info/RECORD +418 -0
- pythonnative-0.40.0.dist-info/WHEEL +5 -0
- pythonnative-0.40.0.dist-info/entry_points.txt +2 -0
- pythonnative-0.40.0.dist-info/licenses/LICENSE +21 -0
- pythonnative-0.40.0.dist-info/top_level.txt +1 -0
- pythonnative.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
"""Stack, tab, and drawer navigators built on one shared core.
|
|
2
|
+
|
|
3
|
+
All three navigators are ordinary components. Each owns a
|
|
4
|
+
[`NavigationState`][pythonnative.navigation.NavigationState] in
|
|
5
|
+
``use_state``, wraps it in a
|
|
6
|
+
[`NavigatorCore`][pythonnative.navigation.handle.NavigatorCore], and
|
|
7
|
+
renders its screens under a
|
|
8
|
+
[`Navigation`][pythonnative.Navigation] provider. Only the *rendering*
|
|
9
|
+
differs:
|
|
10
|
+
|
|
11
|
+
- **Stack**: keeps every route mounted (hidden below the top one) so
|
|
12
|
+
popping back restores the previous screen's state, and draws a
|
|
13
|
+
header with a back button. When the stack is the root of a native
|
|
14
|
+
host it pushes real native screens instead and lets the host draw
|
|
15
|
+
the navigation bar.
|
|
16
|
+
- **Tabs**: keeps visited tabs alive and hidden (``lazy`` mounts them
|
|
17
|
+
on first focus; ``unmount_on_blur`` opts out), and renders the
|
|
18
|
+
native ``TabBar``.
|
|
19
|
+
- **Drawer**: like tabs, with a slide-in menu instead of a tab bar.
|
|
20
|
+
|
|
21
|
+
Inactive screens read ``False`` from
|
|
22
|
+
[`use_is_focused`][pythonnative.use_is_focused]; ``focus`` and ``blur``
|
|
23
|
+
listeners fire as the active route changes.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple
|
|
29
|
+
|
|
30
|
+
from ..component import component
|
|
31
|
+
from ..element import Element, Node
|
|
32
|
+
from ..hooks import use_back_handler, use_context, use_effect, use_memo, use_ref, use_state
|
|
33
|
+
from .container import ContainerContext
|
|
34
|
+
from .handle import FocusContext, Navigation, NavigationContext, NavigatorCore
|
|
35
|
+
from .host import HostContext
|
|
36
|
+
from .screen import ScreenDef, ScreenOptions, Unpack
|
|
37
|
+
from .state import NavigationState, Route
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"DrawerNavigator",
|
|
41
|
+
"StackNavigator",
|
|
42
|
+
"TabNavigator",
|
|
43
|
+
"create_drawer_navigator",
|
|
44
|
+
"create_stack_navigator",
|
|
45
|
+
"create_tab_navigator",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
NavigatorKind = Literal["stack", "tab", "drawer"]
|
|
49
|
+
|
|
50
|
+
_HEADER_HEIGHT = 44.0
|
|
51
|
+
_DRAWER_WIDTH = 280.0
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# ======================================================================
|
|
55
|
+
# Shared core hook
|
|
56
|
+
# ======================================================================
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _use_navigator(
|
|
60
|
+
kind: NavigatorKind,
|
|
61
|
+
screens: Sequence[ScreenDef],
|
|
62
|
+
initial_route: Optional[str],
|
|
63
|
+
) -> Tuple[NavigatorCore, NavigationState, bool]:
|
|
64
|
+
"""Create (once) and refresh the navigator core for the calling component.
|
|
65
|
+
|
|
66
|
+
Returns ``(core, state, parent_focused)``.
|
|
67
|
+
"""
|
|
68
|
+
screen_map: Dict[str, ScreenDef] = {s.name: s for s in screens}
|
|
69
|
+
parent = use_context(NavigationContext)
|
|
70
|
+
host = use_context(HostContext)
|
|
71
|
+
parent_focused = use_context(FocusContext)
|
|
72
|
+
container = use_context(ContainerContext) if parent is None else None
|
|
73
|
+
is_native_root = kind == "stack" and parent is None and host is not None
|
|
74
|
+
first = initial_route if initial_route in screen_map else next(iter(screen_map))
|
|
75
|
+
|
|
76
|
+
def default_state() -> NavigationState:
|
|
77
|
+
if kind == "stack":
|
|
78
|
+
return NavigationState([Route(first, screen_map[first].initial_params)])
|
|
79
|
+
routes = [Route(s.name, s.initial_params) for s in screens]
|
|
80
|
+
return NavigationState(routes, [s.name for s in screens].index(first))
|
|
81
|
+
|
|
82
|
+
def initial_state() -> NavigationState:
|
|
83
|
+
if is_native_root:
|
|
84
|
+
serialized = host.initial_navigation_state()
|
|
85
|
+
if serialized:
|
|
86
|
+
try:
|
|
87
|
+
restored = NavigationState.from_dict(serialized)
|
|
88
|
+
except Exception:
|
|
89
|
+
restored = None
|
|
90
|
+
if restored is not None and all(r.name in screen_map for r in restored.routes):
|
|
91
|
+
return restored
|
|
92
|
+
seed = parent.route.state if parent is not None else (container.initial_state if container else None)
|
|
93
|
+
if seed is not None:
|
|
94
|
+
seeded = _apply_seed(kind, screen_map, default_state(), seed)
|
|
95
|
+
if seeded is not None:
|
|
96
|
+
return seeded
|
|
97
|
+
return default_state()
|
|
98
|
+
|
|
99
|
+
state, set_state = use_state(initial_state)
|
|
100
|
+
_version, set_version = use_state(0)
|
|
101
|
+
core: NavigatorCore = use_memo(
|
|
102
|
+
lambda: NavigatorCore(
|
|
103
|
+
kind,
|
|
104
|
+
screen_map,
|
|
105
|
+
state,
|
|
106
|
+
set_state,
|
|
107
|
+
parent,
|
|
108
|
+
host,
|
|
109
|
+
request_render=lambda: set_version(lambda v: v + 1),
|
|
110
|
+
),
|
|
111
|
+
[],
|
|
112
|
+
)
|
|
113
|
+
core.update(screen_map, state, set_state, parent, host)
|
|
114
|
+
_use_focus_events(core, state, parent_focused)
|
|
115
|
+
_use_seed_updates(core, parent)
|
|
116
|
+
_use_container(core, state, container)
|
|
117
|
+
return core, state, parent_focused
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _apply_seed(
|
|
121
|
+
kind: NavigatorKind,
|
|
122
|
+
screen_map: Dict[str, ScreenDef],
|
|
123
|
+
base: NavigationState,
|
|
124
|
+
seed: NavigationState,
|
|
125
|
+
) -> Optional[NavigationState]:
|
|
126
|
+
"""Merge a seed state (deep link, ``navigate(screen=...)``) into ``base``.
|
|
127
|
+
|
|
128
|
+
Stacks keep their initial route underneath so back works; tabs and
|
|
129
|
+
drawers switch to the seeded route and merge its params. Unknown
|
|
130
|
+
route names make the seed invalid (``None``).
|
|
131
|
+
"""
|
|
132
|
+
if any(r.name not in screen_map for r in seed.routes):
|
|
133
|
+
return None
|
|
134
|
+
if kind == "stack":
|
|
135
|
+
routes = list(seed.routes)
|
|
136
|
+
if routes[0].name != base.routes[0].name:
|
|
137
|
+
routes.insert(0, base.routes[0])
|
|
138
|
+
return NavigationState(routes)
|
|
139
|
+
target = seed.current
|
|
140
|
+
return base.jump_to(target.name, target.params, target.state)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _use_seed_updates(core: NavigatorCore, parent: Optional[Navigation]) -> None:
|
|
144
|
+
"""Follow later ``navigate("Nested", screen=...)`` calls made on the parent."""
|
|
145
|
+
seed = parent.route.state if parent is not None else None
|
|
146
|
+
applied: Any = use_ref(seed)
|
|
147
|
+
|
|
148
|
+
def run() -> None:
|
|
149
|
+
if seed is None or seed is applied.current:
|
|
150
|
+
return
|
|
151
|
+
applied.current = seed
|
|
152
|
+
target = seed.current
|
|
153
|
+
if target.name in core.screens:
|
|
154
|
+
core.navigate(target.name, target.params, target.state)
|
|
155
|
+
|
|
156
|
+
use_effect(run, [seed])
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _use_container(core: NavigatorCore, state: NavigationState, container: Any) -> None:
|
|
160
|
+
"""Attach a root navigator to its container (deep links, ``on_state_change``)."""
|
|
161
|
+
|
|
162
|
+
def attach() -> Any:
|
|
163
|
+
return container.attach_root(core) if container is not None else None
|
|
164
|
+
|
|
165
|
+
use_effect(attach, [container])
|
|
166
|
+
|
|
167
|
+
def report() -> None:
|
|
168
|
+
if container is not None and container.on_state_change is not None:
|
|
169
|
+
container.on_state_change(state)
|
|
170
|
+
|
|
171
|
+
use_effect(report, [state])
|
|
172
|
+
|
|
173
|
+
def cache() -> None:
|
|
174
|
+
publish = getattr(core.host, "cache_navigation_state", None)
|
|
175
|
+
if core.is_native_root and publish is not None:
|
|
176
|
+
publish(state.to_dict())
|
|
177
|
+
|
|
178
|
+
use_effect(cache, [state])
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _use_focus_events(core: NavigatorCore, state: NavigationState, parent_focused: bool) -> None:
|
|
182
|
+
"""Emit ``blur`` / ``focus`` / ``state`` as the active route or focus changes."""
|
|
183
|
+
last: Any = use_ref(None)
|
|
184
|
+
|
|
185
|
+
def run() -> None:
|
|
186
|
+
active: Optional[Route] = state.current if parent_focused else None
|
|
187
|
+
prev: Optional[Route] = last.current
|
|
188
|
+
if (prev.key if prev else None) == (active.key if active else None):
|
|
189
|
+
return
|
|
190
|
+
if prev is not None:
|
|
191
|
+
core.emit(prev, "blur")
|
|
192
|
+
if active is not None:
|
|
193
|
+
core.emit(active, "focus")
|
|
194
|
+
last.current = active
|
|
195
|
+
|
|
196
|
+
use_effect(run, [state.current.key, parent_focused])
|
|
197
|
+
|
|
198
|
+
def emit_state() -> None:
|
|
199
|
+
core.emit(state.current, "state", {"state": state})
|
|
200
|
+
|
|
201
|
+
use_effect(emit_state, [state])
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _use_host_options(core: NavigatorCore, state: NavigationState) -> None:
|
|
205
|
+
"""Push the active route's header options to the native host (root stacks only)."""
|
|
206
|
+
options = core.options_for(state.current) if core.is_native_root else None
|
|
207
|
+
signature = _options_signature(options)
|
|
208
|
+
|
|
209
|
+
def apply() -> None:
|
|
210
|
+
if options is None or core.host is None:
|
|
211
|
+
return
|
|
212
|
+
try:
|
|
213
|
+
core.host.set_screen_options(options)
|
|
214
|
+
except Exception:
|
|
215
|
+
pass
|
|
216
|
+
|
|
217
|
+
use_effect(apply, [signature, state.current.key])
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _options_signature(options: Optional[Dict[str, Any]]) -> Any:
|
|
221
|
+
if options is None:
|
|
222
|
+
return None
|
|
223
|
+
out = []
|
|
224
|
+
for key in sorted(options):
|
|
225
|
+
value = options[key]
|
|
226
|
+
out.append((key, value if isinstance(value, (str, int, float, bool, type(None))) else id(value)))
|
|
227
|
+
return tuple(out)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _screen_element(
|
|
231
|
+
core: NavigatorCore,
|
|
232
|
+
route: Route,
|
|
233
|
+
*,
|
|
234
|
+
active: bool,
|
|
235
|
+
parent_focused: bool,
|
|
236
|
+
) -> Element:
|
|
237
|
+
"""Render ``route``'s component under its navigation and focus providers."""
|
|
238
|
+
screen = core.screens.get(route.name)
|
|
239
|
+
if screen is None:
|
|
240
|
+
from ..components import Text
|
|
241
|
+
|
|
242
|
+
body: Node = Text(f"Unknown route: {route.name}")
|
|
243
|
+
else:
|
|
244
|
+
body = screen.component()
|
|
245
|
+
handle = core.handle_for(route)
|
|
246
|
+
return NavigationContext.Provider(handle, FocusContext.Provider(parent_focused and active, body), key=route.key)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _hidden_style(active: bool) -> Dict[str, Any]:
|
|
250
|
+
return {"flex": 1, "display": "flex" if active else "none"}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# ======================================================================
|
|
254
|
+
# Stack
|
|
255
|
+
# ======================================================================
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@component
|
|
259
|
+
def _StackHeader(*, core: NavigatorCore, route: Route, options: Dict[str, Any]) -> Optional[Element]:
|
|
260
|
+
from ..components import Pressable, Text, View
|
|
261
|
+
|
|
262
|
+
if options.get("header_shown", True) is False:
|
|
263
|
+
return None
|
|
264
|
+
handle = core.handle_for(route)
|
|
265
|
+
style = {
|
|
266
|
+
"height": _HEADER_HEIGHT,
|
|
267
|
+
"flex_direction": "row",
|
|
268
|
+
"align_items": "center",
|
|
269
|
+
"padding_horizontal": 8,
|
|
270
|
+
"background_color": "#F8F8F8",
|
|
271
|
+
"border_bottom_width": 0.5,
|
|
272
|
+
"border_color": "#C7C7CC",
|
|
273
|
+
**(options.get("header_style") or {}),
|
|
274
|
+
}
|
|
275
|
+
tint = options.get("header_tint_color", "#007AFF")
|
|
276
|
+
title_style = {
|
|
277
|
+
"font_size": 17,
|
|
278
|
+
"bold": True,
|
|
279
|
+
"flex": 1,
|
|
280
|
+
"text_align": "center",
|
|
281
|
+
**(options.get("header_title_style") or {}),
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
def slot(value: Any) -> Optional[Element]:
|
|
285
|
+
if value is None:
|
|
286
|
+
return None
|
|
287
|
+
return value() if callable(value) and not isinstance(value, Element) else value
|
|
288
|
+
|
|
289
|
+
left = slot(options.get("header_left"))
|
|
290
|
+
if left is None and handle.can_go_back() and options.get("header_back_visible", True):
|
|
291
|
+
back_title = options.get("header_back_title") or "Back"
|
|
292
|
+
left = Pressable(
|
|
293
|
+
Text(f"\u2039 {back_title}", style={"color": tint, "font_size": 17}),
|
|
294
|
+
on_press=handle.go_back,
|
|
295
|
+
accessibility_label="Back",
|
|
296
|
+
)
|
|
297
|
+
right = slot(options.get("header_right"))
|
|
298
|
+
return View(
|
|
299
|
+
View(left, style={"min_width": 60, "align_items": "flex_start"}),
|
|
300
|
+
Text(str(options.get("title", route.name)), style=title_style),
|
|
301
|
+
View(right, style={"min_width": 60, "align_items": "flex_end"}),
|
|
302
|
+
style=style,
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
@component
|
|
307
|
+
def _StackNavigatorImpl(*, screens: Tuple[ScreenDef, ...], initial_route: Optional[str] = None) -> Element:
|
|
308
|
+
from ..components import View
|
|
309
|
+
|
|
310
|
+
if not screens:
|
|
311
|
+
return View(style={"flex": 1})
|
|
312
|
+
core, state, parent_focused = _use_navigator("stack", screens, initial_route)
|
|
313
|
+
|
|
314
|
+
def on_back() -> bool:
|
|
315
|
+
if len(state) > 1:
|
|
316
|
+
return core.pop(1, source="back")
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
use_back_handler(on_back)
|
|
320
|
+
|
|
321
|
+
current = state.current
|
|
322
|
+
stack_ref = use_ref(None)
|
|
323
|
+
if core.is_native_root:
|
|
324
|
+
|
|
325
|
+
def native_back(count: int = 1) -> None:
|
|
326
|
+
if not core.pop(count, source="back") and stack_ref.current is not None:
|
|
327
|
+
from ..native_views import get_registry
|
|
328
|
+
|
|
329
|
+
get_registry().command(stack_ref.current.tag, "restore_stack")
|
|
330
|
+
|
|
331
|
+
return Element(
|
|
332
|
+
"ScreenStack",
|
|
333
|
+
{"flex": 1, "on_native_back": native_back, "ref": stack_ref},
|
|
334
|
+
[
|
|
335
|
+
Element(
|
|
336
|
+
"Screen",
|
|
337
|
+
{"flex": 1, "active": route is current, "route_key": route.key, **core.options_for(route)},
|
|
338
|
+
[_screen_element(core, route, active=route is current, parent_focused=parent_focused)],
|
|
339
|
+
key=route.key,
|
|
340
|
+
)
|
|
341
|
+
for route in state.routes
|
|
342
|
+
],
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
layers: List[Element] = []
|
|
346
|
+
for route in state.routes:
|
|
347
|
+
active = route is current
|
|
348
|
+
header = _StackHeader(core=core, route=route, options=core.options_for(route))
|
|
349
|
+
layers.append(
|
|
350
|
+
View(
|
|
351
|
+
header,
|
|
352
|
+
View(_screen_element(core, route, active=active, parent_focused=parent_focused), style={"flex": 1}),
|
|
353
|
+
style=_hidden_style(active),
|
|
354
|
+
key=route.key,
|
|
355
|
+
)
|
|
356
|
+
)
|
|
357
|
+
return View(*layers, style={"flex": 1})
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class StackNavigator:
|
|
361
|
+
"""Factory returned by [`create_stack_navigator`][pythonnative.create_stack_navigator]."""
|
|
362
|
+
|
|
363
|
+
__slots__ = ()
|
|
364
|
+
|
|
365
|
+
@staticmethod
|
|
366
|
+
def Screen(
|
|
367
|
+
name: str,
|
|
368
|
+
component: Callable[[], Any],
|
|
369
|
+
*,
|
|
370
|
+
options: Any = None,
|
|
371
|
+
initial_params: Optional[Dict[str, Any]] = None,
|
|
372
|
+
**option_kwargs: Unpack[ScreenOptions],
|
|
373
|
+
) -> ScreenDef:
|
|
374
|
+
"""Define a screen. ``options`` may be a dict or ``(route) -> dict``; keywords merge on top."""
|
|
375
|
+
return ScreenDef(name, component, options=options, initial_params=initial_params, **option_kwargs)
|
|
376
|
+
|
|
377
|
+
@staticmethod
|
|
378
|
+
def Navigator(*screens: ScreenDef, initial_route: Optional[str] = None, key: Optional[str] = None) -> Element:
|
|
379
|
+
"""Render the stack with the given screens (the first, or ``initial_route``, shows first)."""
|
|
380
|
+
return _StackNavigatorImpl(screens=tuple(screens), initial_route=initial_route).with_key(key)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def create_stack_navigator() -> StackNavigator:
|
|
384
|
+
"""Create a stack navigator: push and pop screens with history.
|
|
385
|
+
|
|
386
|
+
At the root of a native host the stack pushes real native screens
|
|
387
|
+
(``UINavigationController`` on iOS, fragments on Android), so users
|
|
388
|
+
get system transitions and swipe-back for free. Nested stacks are
|
|
389
|
+
drawn in Python with their own header.
|
|
390
|
+
|
|
391
|
+
Example:
|
|
392
|
+
```python
|
|
393
|
+
import pythonnative as pn
|
|
394
|
+
|
|
395
|
+
Stack = pn.create_stack_navigator()
|
|
396
|
+
|
|
397
|
+
@pn.component
|
|
398
|
+
def App():
|
|
399
|
+
return pn.NavigationContainer(
|
|
400
|
+
Stack.Navigator(
|
|
401
|
+
Stack.Screen("Home", HomeScreen, title="Home"),
|
|
402
|
+
Stack.Screen("Detail", DetailScreen, title="Detail"),
|
|
403
|
+
)
|
|
404
|
+
)
|
|
405
|
+
```
|
|
406
|
+
"""
|
|
407
|
+
return StackNavigator()
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
# ======================================================================
|
|
411
|
+
# Keep-alive helpers shared by tabs and drawers
|
|
412
|
+
# ======================================================================
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def _use_visited(state: NavigationState) -> Any:
|
|
416
|
+
"""Track which route keys have been active at least once (for ``lazy``)."""
|
|
417
|
+
visited: Any = use_ref(None)
|
|
418
|
+
if visited.current is None:
|
|
419
|
+
visited.current = set()
|
|
420
|
+
visited.current.add(state.current.key)
|
|
421
|
+
live = {r.key for r in state.routes}
|
|
422
|
+
visited.current.intersection_update(live)
|
|
423
|
+
return visited.current
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _render_keep_alive(
|
|
427
|
+
core: NavigatorCore, state: NavigationState, parent_focused: bool, visited: Any
|
|
428
|
+
) -> List[Element]:
|
|
429
|
+
from ..components import View
|
|
430
|
+
|
|
431
|
+
out: List[Element] = []
|
|
432
|
+
for route in state.routes:
|
|
433
|
+
active = route is state.current
|
|
434
|
+
options = core.options_for(route)
|
|
435
|
+
if not active:
|
|
436
|
+
if options.get("unmount_on_blur", False):
|
|
437
|
+
continue
|
|
438
|
+
if options.get("lazy", True) and route.key not in visited:
|
|
439
|
+
continue
|
|
440
|
+
out.append(
|
|
441
|
+
View(
|
|
442
|
+
_screen_element(core, route, active=active, parent_focused=parent_focused),
|
|
443
|
+
style=_hidden_style(active),
|
|
444
|
+
key=route.key,
|
|
445
|
+
)
|
|
446
|
+
)
|
|
447
|
+
return out
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
# ======================================================================
|
|
451
|
+
# Tabs
|
|
452
|
+
# ======================================================================
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
@component
|
|
456
|
+
def _TabNavigatorImpl(*, screens: Tuple[ScreenDef, ...], initial_route: Optional[str] = None) -> Element:
|
|
457
|
+
from ..components import View
|
|
458
|
+
|
|
459
|
+
if not screens:
|
|
460
|
+
return View(style={"flex": 1})
|
|
461
|
+
core, state, parent_focused = _use_navigator("tab", screens, initial_route)
|
|
462
|
+
visited = _use_visited(state)
|
|
463
|
+
|
|
464
|
+
items: List[Dict[str, Any]] = []
|
|
465
|
+
for route in state.routes:
|
|
466
|
+
options = core.options_for(route)
|
|
467
|
+
item: Dict[str, Any] = {
|
|
468
|
+
"name": route.name,
|
|
469
|
+
"title": options.get("tab_bar_label") or options.get("title", route.name),
|
|
470
|
+
}
|
|
471
|
+
icon = options.get("tab_bar_icon")
|
|
472
|
+
if icon is not None:
|
|
473
|
+
item["icon"] = icon
|
|
474
|
+
badge = options.get("tab_bar_badge")
|
|
475
|
+
if badge is not None:
|
|
476
|
+
item["badge"] = str(badge)
|
|
477
|
+
items.append(item)
|
|
478
|
+
|
|
479
|
+
def on_tab_select(name: str) -> None:
|
|
480
|
+
core.navigate(name, {})
|
|
481
|
+
|
|
482
|
+
tab_bar = Element(
|
|
483
|
+
"TabBar",
|
|
484
|
+
{"items": items, "active_tab": state.current.name, "on_tab_select": on_tab_select},
|
|
485
|
+
[],
|
|
486
|
+
key="__tab_bar__",
|
|
487
|
+
)
|
|
488
|
+
return View(
|
|
489
|
+
View(*_render_keep_alive(core, state, parent_focused, visited), style={"flex": 1}),
|
|
490
|
+
tab_bar,
|
|
491
|
+
style={"flex": 1, "flex_direction": "column"},
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
class TabNavigator:
|
|
496
|
+
"""Factory returned by [`create_tab_navigator`][pythonnative.create_tab_navigator]."""
|
|
497
|
+
|
|
498
|
+
__slots__ = ()
|
|
499
|
+
|
|
500
|
+
@staticmethod
|
|
501
|
+
def Screen(
|
|
502
|
+
name: str,
|
|
503
|
+
component: Callable[[], Any],
|
|
504
|
+
*,
|
|
505
|
+
options: Any = None,
|
|
506
|
+
initial_params: Optional[Dict[str, Any]] = None,
|
|
507
|
+
**option_kwargs: Unpack[ScreenOptions],
|
|
508
|
+
) -> ScreenDef:
|
|
509
|
+
"""Define a tab. ``options`` may be a dict or ``(route) -> dict``; keywords merge on top."""
|
|
510
|
+
return ScreenDef(name, component, options=options, initial_params=initial_params, **option_kwargs)
|
|
511
|
+
|
|
512
|
+
@staticmethod
|
|
513
|
+
def Navigator(*screens: ScreenDef, initial_route: Optional[str] = None, key: Optional[str] = None) -> Element:
|
|
514
|
+
"""Render the tab bar with the given screens (the first, or ``initial_route``, is selected first)."""
|
|
515
|
+
return _TabNavigatorImpl(screens=tuple(screens), initial_route=initial_route).with_key(key)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def create_tab_navigator() -> TabNavigator:
|
|
519
|
+
"""Create a tab navigator with a native tab bar.
|
|
520
|
+
|
|
521
|
+
Tabs stay mounted once visited (hidden while inactive) so switching
|
|
522
|
+
back restores scroll position and state. Use ``lazy=False`` on a
|
|
523
|
+
screen to mount it eagerly, or ``unmount_on_blur=True`` to tear it
|
|
524
|
+
down when it loses focus.
|
|
525
|
+
|
|
526
|
+
Example:
|
|
527
|
+
```python
|
|
528
|
+
Tab = pn.create_tab_navigator()
|
|
529
|
+
|
|
530
|
+
Tab.Navigator(
|
|
531
|
+
Tab.Screen("Home", HomeScreen, title="Home", tab_bar_icon="house.fill"),
|
|
532
|
+
Tab.Screen("Settings", SettingsScreen, title="Settings"),
|
|
533
|
+
)
|
|
534
|
+
```
|
|
535
|
+
"""
|
|
536
|
+
return TabNavigator()
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
# ======================================================================
|
|
540
|
+
# Drawer
|
|
541
|
+
# ======================================================================
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
@component
|
|
545
|
+
def _DrawerNavigatorImpl(
|
|
546
|
+
*,
|
|
547
|
+
screens: Tuple[ScreenDef, ...],
|
|
548
|
+
initial_route: Optional[str] = None,
|
|
549
|
+
drawer_width: float = _DRAWER_WIDTH,
|
|
550
|
+
) -> Element:
|
|
551
|
+
from ..components import Pressable, Text, View
|
|
552
|
+
|
|
553
|
+
if not screens:
|
|
554
|
+
return View(style={"flex": 1})
|
|
555
|
+
core, state, parent_focused = _use_navigator("drawer", screens, initial_route)
|
|
556
|
+
visited = _use_visited(state)
|
|
557
|
+
drawer_open, set_drawer_open = use_state(False)
|
|
558
|
+
core.drawer_open = drawer_open
|
|
559
|
+
core._set_drawer_open = set_drawer_open
|
|
560
|
+
|
|
561
|
+
def on_back() -> bool:
|
|
562
|
+
if drawer_open:
|
|
563
|
+
set_drawer_open(False)
|
|
564
|
+
return True
|
|
565
|
+
return False
|
|
566
|
+
|
|
567
|
+
use_back_handler(on_back)
|
|
568
|
+
|
|
569
|
+
content = View(*_render_keep_alive(core, state, parent_focused, visited), style={"flex": 1})
|
|
570
|
+
if not drawer_open:
|
|
571
|
+
return View(content, style={"flex": 1})
|
|
572
|
+
|
|
573
|
+
def select(name: str) -> Callable[[], None]:
|
|
574
|
+
def _select() -> None:
|
|
575
|
+
core.navigate(name, {})
|
|
576
|
+
set_drawer_open(False)
|
|
577
|
+
|
|
578
|
+
return _select
|
|
579
|
+
|
|
580
|
+
rows: List[Element] = []
|
|
581
|
+
for route in state.routes:
|
|
582
|
+
options = core.options_for(route)
|
|
583
|
+
active = route is state.current
|
|
584
|
+
rows.append(
|
|
585
|
+
Pressable(
|
|
586
|
+
Text(
|
|
587
|
+
str(options.get("title", route.name)),
|
|
588
|
+
style={"font_size": 16, "color": "#007AFF" if active else "#1C1C1E", "bold": active},
|
|
589
|
+
),
|
|
590
|
+
on_press=select(route.name),
|
|
591
|
+
style={
|
|
592
|
+
"padding_vertical": 14,
|
|
593
|
+
"padding_horizontal": 20,
|
|
594
|
+
"background_color": "#EEF3FF" if active else "#00000000",
|
|
595
|
+
},
|
|
596
|
+
key=f"__drawer_{route.key}",
|
|
597
|
+
)
|
|
598
|
+
)
|
|
599
|
+
panel = View(
|
|
600
|
+
*rows,
|
|
601
|
+
style={
|
|
602
|
+
"width": drawer_width,
|
|
603
|
+
"background_color": "#FFFFFF",
|
|
604
|
+
"padding_top": 24,
|
|
605
|
+
"border_right_width": 0.5,
|
|
606
|
+
"border_color": "#C7C7CC",
|
|
607
|
+
},
|
|
608
|
+
)
|
|
609
|
+
scrim = Pressable(on_press=lambda: set_drawer_open(False), style={"flex": 1, "background_color": "#00000040"})
|
|
610
|
+
return View(
|
|
611
|
+
content,
|
|
612
|
+
View(
|
|
613
|
+
panel,
|
|
614
|
+
scrim,
|
|
615
|
+
style={"position": "absolute", "top": 0, "left": 0, "right": 0, "bottom": 0, "flex_direction": "row"},
|
|
616
|
+
),
|
|
617
|
+
style={"flex": 1},
|
|
618
|
+
)
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
class DrawerNavigator:
|
|
622
|
+
"""Factory returned by [`create_drawer_navigator`][pythonnative.create_drawer_navigator]."""
|
|
623
|
+
|
|
624
|
+
__slots__ = ()
|
|
625
|
+
|
|
626
|
+
@staticmethod
|
|
627
|
+
def Screen(
|
|
628
|
+
name: str,
|
|
629
|
+
component: Callable[[], Any],
|
|
630
|
+
*,
|
|
631
|
+
options: Any = None,
|
|
632
|
+
initial_params: Optional[Dict[str, Any]] = None,
|
|
633
|
+
**option_kwargs: Unpack[ScreenOptions],
|
|
634
|
+
) -> ScreenDef:
|
|
635
|
+
"""Define a drawer screen. ``options`` may be a dict or ``(route) -> dict``; keywords merge on top."""
|
|
636
|
+
return ScreenDef(name, component, options=options, initial_params=initial_params, **option_kwargs)
|
|
637
|
+
|
|
638
|
+
@staticmethod
|
|
639
|
+
def Navigator(
|
|
640
|
+
*screens: ScreenDef,
|
|
641
|
+
initial_route: Optional[str] = None,
|
|
642
|
+
drawer_width: float = _DRAWER_WIDTH,
|
|
643
|
+
key: Optional[str] = None,
|
|
644
|
+
) -> Element:
|
|
645
|
+
"""Render the drawer with the given screens (the first, or ``initial_route``, shows first)."""
|
|
646
|
+
return _DrawerNavigatorImpl(
|
|
647
|
+
screens=tuple(screens), initial_route=initial_route, drawer_width=drawer_width
|
|
648
|
+
).with_key(key)
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def create_drawer_navigator() -> DrawerNavigator:
|
|
652
|
+
"""Create a drawer navigator: sibling screens behind a slide-in menu.
|
|
653
|
+
|
|
654
|
+
The handle returned by [`use_navigation`][pythonnative.use_navigation]
|
|
655
|
+
inside a drawer screen is a
|
|
656
|
+
[`DrawerNavigation`][pythonnative.navigation.DrawerNavigation] with
|
|
657
|
+
``open_drawer()``, ``close_drawer()``, and ``toggle_drawer()``.
|
|
658
|
+
"""
|
|
659
|
+
return DrawerNavigator()
|