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,171 @@
|
|
|
1
|
+
"""Native build fingerprints: know when ``pn run`` can skip the toolchain.
|
|
2
|
+
|
|
3
|
+
A debug build only has to be rebuilt when one of its *native inputs*
|
|
4
|
+
changes: ``pythonnative.toml``, the bundled native template, the
|
|
5
|
+
``pythonnative`` package itself, project-local native plugins, or the
|
|
6
|
+
build flavor (platform, SDK, release). Edits under ``app/`` don't count;
|
|
7
|
+
the dev server syncs those into the running app and Fast Refresh applies
|
|
8
|
+
them, exactly as Metro does for a React Native debug build.
|
|
9
|
+
|
|
10
|
+
[`compute`][pythonnative.project.fingerprint.compute] hashes those
|
|
11
|
+
inputs into one hex digest. ``pn run`` writes it next to the build
|
|
12
|
+
after a successful toolchain run (see
|
|
13
|
+
[`write_stamp`][pythonnative.project.fingerprint.write_stamp]) and, when
|
|
14
|
+
the digest is unchanged and a dev server is running to deliver the
|
|
15
|
+
latest sources, reinstalls the previous artifact instead of staging and
|
|
16
|
+
compiling again.
|
|
17
|
+
|
|
18
|
+
The hash covers file *contents*, not mtimes, so touching a file or
|
|
19
|
+
re-cloning the repository doesn't invalidate a build.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import hashlib
|
|
25
|
+
import json
|
|
26
|
+
import os
|
|
27
|
+
import sys
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
from typing import Dict, Iterable, Optional, Sequence
|
|
30
|
+
|
|
31
|
+
from .config import CONFIG_FILENAME, AppConfig
|
|
32
|
+
|
|
33
|
+
__all__ = ["STAMP_NAME", "compute", "hash_tree", "read_stamp", "write_stamp"]
|
|
34
|
+
|
|
35
|
+
STAMP_NAME = ".pn-native-fingerprint.json"
|
|
36
|
+
"""File written into ``build/<platform>/`` after a successful native build."""
|
|
37
|
+
|
|
38
|
+
_IGNORED_DIRS = {
|
|
39
|
+
"__pycache__",
|
|
40
|
+
".git",
|
|
41
|
+
".gradle",
|
|
42
|
+
".build",
|
|
43
|
+
".swiftpm",
|
|
44
|
+
"build",
|
|
45
|
+
"DerivedData",
|
|
46
|
+
"xcuserdata",
|
|
47
|
+
"node_modules",
|
|
48
|
+
".venv",
|
|
49
|
+
}
|
|
50
|
+
_IGNORED_SUFFIXES = (".pyc", ".pyo", ".DS_Store")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def hash_tree(root: Path, *, into: Optional["hashlib._Hash"] = None) -> str:
|
|
54
|
+
"""Hash every file under ``root`` (relative path + contents), deterministically.
|
|
55
|
+
|
|
56
|
+
Build outputs, caches, and bytecode are skipped so a checkout that
|
|
57
|
+
has been built hashes the same as a fresh one.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
root: Directory (or single file) to hash. A missing path hashes
|
|
61
|
+
as the empty tree.
|
|
62
|
+
into: An existing hasher to feed instead of creating one.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
The hex digest (of ``into`` when given).
|
|
66
|
+
"""
|
|
67
|
+
hasher = into or hashlib.sha256()
|
|
68
|
+
if root.is_file():
|
|
69
|
+
_feed_file(hasher, root.name, root)
|
|
70
|
+
return hasher.hexdigest()
|
|
71
|
+
if not root.is_dir():
|
|
72
|
+
return hasher.hexdigest()
|
|
73
|
+
for dirpath, dirnames, filenames in os.walk(root):
|
|
74
|
+
dirnames[:] = sorted(d for d in dirnames if d not in _IGNORED_DIRS and not d.startswith("."))
|
|
75
|
+
for name in sorted(filenames):
|
|
76
|
+
if name.endswith(_IGNORED_SUFFIXES):
|
|
77
|
+
continue
|
|
78
|
+
path = Path(dirpath) / name
|
|
79
|
+
if path.is_symlink() and not path.exists():
|
|
80
|
+
continue
|
|
81
|
+
_feed_file(hasher, str(path.relative_to(root)).replace(os.sep, "/"), path)
|
|
82
|
+
return hasher.hexdigest()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _feed_file(hasher: "hashlib._Hash", rel: str, path: Path) -> None:
|
|
86
|
+
hasher.update(rel.encode("utf-8"))
|
|
87
|
+
hasher.update(b"\0")
|
|
88
|
+
try:
|
|
89
|
+
with open(path, "rb") as handle:
|
|
90
|
+
for chunk in iter(lambda: handle.read(1 << 16), b""):
|
|
91
|
+
hasher.update(chunk)
|
|
92
|
+
except OSError:
|
|
93
|
+
hasher.update(b"<unreadable>")
|
|
94
|
+
hasher.update(b"\0")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def compute(
|
|
98
|
+
config: AppConfig,
|
|
99
|
+
platform: str,
|
|
100
|
+
*,
|
|
101
|
+
template_root: Path,
|
|
102
|
+
lib_root: Path,
|
|
103
|
+
release: bool = False,
|
|
104
|
+
ios_sdks: Sequence[str] = (),
|
|
105
|
+
extra: Optional[Dict[str, str]] = None,
|
|
106
|
+
) -> str:
|
|
107
|
+
"""Digest every native input of a build.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
config: The loaded project configuration (its file is hashed).
|
|
111
|
+
platform: ``"android"`` or ``"ios"``.
|
|
112
|
+
template_root: The bundled native template directory.
|
|
113
|
+
lib_root: The ``pythonnative`` package directory that gets bundled.
|
|
114
|
+
release: Release builds are distinct from debug builds.
|
|
115
|
+
ios_sdks: The iOS SDK slices being staged.
|
|
116
|
+
extra: Additional key/value inputs (host arch, tool versions).
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
A hex SHA-256 digest.
|
|
120
|
+
"""
|
|
121
|
+
hasher = hashlib.sha256()
|
|
122
|
+
header = {
|
|
123
|
+
"platform": platform,
|
|
124
|
+
"release": bool(release),
|
|
125
|
+
"ios_sdks": sorted(ios_sdks),
|
|
126
|
+
"python": f"{sys.version_info[0]}.{sys.version_info[1]}",
|
|
127
|
+
"extra": dict(sorted((extra or {}).items())),
|
|
128
|
+
}
|
|
129
|
+
hasher.update(json.dumps(header, sort_keys=True).encode("utf-8"))
|
|
130
|
+
hasher.update(b"\0config\0")
|
|
131
|
+
hash_tree(config.project_root / CONFIG_FILENAME, into=hasher)
|
|
132
|
+
hasher.update(b"\0template\0")
|
|
133
|
+
hash_tree(template_root, into=hasher)
|
|
134
|
+
hasher.update(b"\0lib\0")
|
|
135
|
+
hash_tree(lib_root, into=hasher)
|
|
136
|
+
hash_tree(config.project_root / "pn.lock", into=hasher)
|
|
137
|
+
for plugin_path in _plugin_paths(config):
|
|
138
|
+
hasher.update(b"\0plugin:" + str(plugin_path).encode("utf-8") + b"\0")
|
|
139
|
+
hash_tree(plugin_path, into=hasher)
|
|
140
|
+
return hasher.hexdigest()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _plugin_paths(config: AppConfig) -> Iterable[Path]:
|
|
144
|
+
for raw in getattr(config, "plugin_paths", ()) or ():
|
|
145
|
+
try:
|
|
146
|
+
yield config.resolve_path(raw)
|
|
147
|
+
except Exception:
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def read_stamp(build_dir: Path) -> Optional[Dict[str, str]]:
|
|
152
|
+
"""Return the stamp written by the last successful build, or ``None``."""
|
|
153
|
+
path = build_dir / STAMP_NAME
|
|
154
|
+
try:
|
|
155
|
+
with open(path, "r", encoding="utf-8") as handle:
|
|
156
|
+
data = json.load(handle)
|
|
157
|
+
except (OSError, ValueError):
|
|
158
|
+
return None
|
|
159
|
+
if not isinstance(data, dict) or "fingerprint" not in data:
|
|
160
|
+
return None
|
|
161
|
+
return {str(k): str(v) for k, v in data.items()}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def write_stamp(build_dir: Path, fingerprint: str, *, artifact: Optional[Path] = None) -> None:
|
|
165
|
+
"""Record ``fingerprint`` (and the artifact it produced) for the next ``pn run``."""
|
|
166
|
+
build_dir.mkdir(parents=True, exist_ok=True)
|
|
167
|
+
payload: Dict[str, str] = {"fingerprint": fingerprint}
|
|
168
|
+
if artifact is not None:
|
|
169
|
+
payload["artifact"] = str(artifact)
|
|
170
|
+
with open(build_dir / STAMP_NAME, "w", encoding="utf-8") as handle:
|
|
171
|
+
json.dump(payload, handle, indent=2)
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""App icon and splash image generation.
|
|
2
|
+
|
|
3
|
+
Given a single high-resolution source image per asset (a 1024x1024 icon
|
|
4
|
+
and an optional splash image), this module renders the per-platform,
|
|
5
|
+
per-density variants each toolchain expects:
|
|
6
|
+
|
|
7
|
+
- iOS: a single-size ``AppIcon.appiconset`` (Xcode resizes at build time)
|
|
8
|
+
and a ``Splash`` image set referenced by the generated launch screen.
|
|
9
|
+
- Android: ``mipmap-*`` launcher PNGs at every density (mdpi…xxxhdpi),
|
|
10
|
+
a circular round-icon variant, and a centered splash icon used by the
|
|
11
|
+
Android 12+ splash screen.
|
|
12
|
+
|
|
13
|
+
Image resizing uses [Pillow](https://python-pillow.org/), declared as the
|
|
14
|
+
``[build]`` optional dependency. When Pillow isn't installed every
|
|
15
|
+
function degrades gracefully: it returns ``False`` (and the caller keeps
|
|
16
|
+
the template's default assets) so a missing optional dependency never
|
|
17
|
+
breaks a build. ``pn doctor`` reports whether Pillow is available.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
import shutil
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Dict, List, Optional, Tuple
|
|
27
|
+
|
|
28
|
+
# Android launcher icon sizes (px) per density bucket.
|
|
29
|
+
ANDROID_LAUNCHER_DENSITIES: Dict[str, int] = {
|
|
30
|
+
"mdpi": 48,
|
|
31
|
+
"hdpi": 72,
|
|
32
|
+
"xhdpi": 96,
|
|
33
|
+
"xxhdpi": 144,
|
|
34
|
+
"xxxhdpi": 192,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def pillow_available() -> bool:
|
|
39
|
+
"""Return whether Pillow can be imported.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
``True`` if ``PIL.Image`` imports, else ``False``.
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
import PIL.Image # noqa: F401
|
|
46
|
+
except Exception:
|
|
47
|
+
return False
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _open_rgba(source: Path) -> "object":
|
|
52
|
+
from PIL import Image
|
|
53
|
+
|
|
54
|
+
img = Image.open(source).convert("RGBA")
|
|
55
|
+
return img
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _resized(img: "object", size: int) -> "object":
|
|
59
|
+
from PIL import Image
|
|
60
|
+
|
|
61
|
+
return img.resize((size, size), Image.LANCZOS)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _circular(img: "object") -> "object":
|
|
65
|
+
"""Return a copy of a square image masked to a circle."""
|
|
66
|
+
from PIL import Image, ImageDraw
|
|
67
|
+
|
|
68
|
+
size = img.size[0]
|
|
69
|
+
mask = Image.new("L", (size, size), 0)
|
|
70
|
+
draw = ImageDraw.Draw(mask)
|
|
71
|
+
draw.ellipse((0, 0, size, size), fill=255)
|
|
72
|
+
out = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
|
73
|
+
out.paste(img, (0, 0), mask) # type: ignore[arg-type]
|
|
74
|
+
return out
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def generate_ios_icons(source: Path, appiconset_dir: Path) -> bool:
|
|
78
|
+
"""Generate a single-size iOS ``AppIcon.appiconset``.
|
|
79
|
+
|
|
80
|
+
Writes ``icon-1024.png`` (a flattened, opaque 1024x1024 image; the
|
|
81
|
+
App Store rejects icons with alpha) and a ``Contents.json`` that
|
|
82
|
+
declares it as the universal iOS app icon. Xcode derives every other
|
|
83
|
+
size at build time.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
source: Path to the source icon image.
|
|
87
|
+
appiconset_dir: The ``AppIcon.appiconset`` directory to populate.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
``True`` if icons were written, ``False`` if Pillow is missing.
|
|
91
|
+
"""
|
|
92
|
+
if not pillow_available():
|
|
93
|
+
return False
|
|
94
|
+
from PIL import Image
|
|
95
|
+
|
|
96
|
+
appiconset_dir.mkdir(parents=True, exist_ok=True)
|
|
97
|
+
img = _open_rgba(source)
|
|
98
|
+
icon = _resized(img, 1024)
|
|
99
|
+
flattened = Image.new("RGB", (1024, 1024), (255, 255, 255))
|
|
100
|
+
flattened.paste(icon, (0, 0), icon) # type: ignore[arg-type]
|
|
101
|
+
flattened.save(appiconset_dir / "icon-1024.png", format="PNG")
|
|
102
|
+
|
|
103
|
+
contents = {
|
|
104
|
+
"images": [
|
|
105
|
+
{
|
|
106
|
+
"idiom": "universal",
|
|
107
|
+
"platform": "ios",
|
|
108
|
+
"size": "1024x1024",
|
|
109
|
+
"filename": "icon-1024.png",
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
"info": {"author": "pythonnative", "version": 1},
|
|
113
|
+
}
|
|
114
|
+
(appiconset_dir / "Contents.json").write_text(json.dumps(contents, indent=2) + "\n", encoding="utf-8")
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def generate_android_icons(source: Path, res_dir: Path) -> bool:
|
|
119
|
+
"""Generate Android launcher icons at every density.
|
|
120
|
+
|
|
121
|
+
Writes ``mipmap-<density>/ic_launcher.png`` and a circular
|
|
122
|
+
``ic_launcher_round.png`` for each density bucket, and removes the
|
|
123
|
+
adaptive ``mipmap-anydpi-v26`` definitions so the generated PNGs are
|
|
124
|
+
used directly (otherwise the template's vector adaptive icon would
|
|
125
|
+
win on API 26+).
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
source: Path to the source icon image.
|
|
129
|
+
res_dir: The Android ``res`` directory.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
``True`` if icons were written, ``False`` if Pillow is missing.
|
|
133
|
+
"""
|
|
134
|
+
if not pillow_available():
|
|
135
|
+
return False
|
|
136
|
+
|
|
137
|
+
img = _open_rgba(source)
|
|
138
|
+
for density, size in ANDROID_LAUNCHER_DENSITIES.items():
|
|
139
|
+
mip_dir = res_dir / f"mipmap-{density}"
|
|
140
|
+
mip_dir.mkdir(parents=True, exist_ok=True)
|
|
141
|
+
square = _resized(img, size)
|
|
142
|
+
square.save(mip_dir / "ic_launcher.png", format="PNG")
|
|
143
|
+
round_icon = _circular(square)
|
|
144
|
+
round_icon.save(mip_dir / "ic_launcher_round.png", format="PNG")
|
|
145
|
+
|
|
146
|
+
# Drop adaptive XML icons so the raster mipmaps above are authoritative.
|
|
147
|
+
anydpi = res_dir / "mipmap-anydpi-v26"
|
|
148
|
+
if anydpi.is_dir():
|
|
149
|
+
shutil.rmtree(anydpi, ignore_errors=True)
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def generate_ios_splash(source: Path, imageset_dir: Path) -> bool:
|
|
154
|
+
"""Generate an iOS ``Splash`` image set from a source image.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
source: Path to the splash image.
|
|
158
|
+
imageset_dir: The ``Splash.imageset`` directory to populate.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
``True`` if the image set was written, ``False`` if Pillow is
|
|
162
|
+
missing.
|
|
163
|
+
"""
|
|
164
|
+
if not pillow_available():
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
imageset_dir.mkdir(parents=True, exist_ok=True)
|
|
168
|
+
img = _open_rgba(source)
|
|
169
|
+
img.save(imageset_dir / "splash.png", format="PNG")
|
|
170
|
+
contents = {
|
|
171
|
+
"images": [{"idiom": "universal", "filename": "splash.png"}],
|
|
172
|
+
"info": {"author": "pythonnative", "version": 1},
|
|
173
|
+
}
|
|
174
|
+
(imageset_dir / "Contents.json").write_text(json.dumps(contents, indent=2) + "\n", encoding="utf-8")
|
|
175
|
+
return True
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def generate_android_splash_icon(source: Path, dest: Path, size: int = 288) -> bool:
|
|
179
|
+
"""Render the centered icon used by the Android 12+ splash screen.
|
|
180
|
+
|
|
181
|
+
The Android splash screen draws this image centered on the splash
|
|
182
|
+
background color. A transparent square is recommended; the default
|
|
183
|
+
size (288 dp at xxxhdpi → ~864 px) matches Google's guidance.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
source: Path to the source splash (or icon) image.
|
|
187
|
+
dest: Destination PNG path.
|
|
188
|
+
size: Output edge length in pixels.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
``True`` if the image was written, ``False`` if Pillow is missing.
|
|
192
|
+
"""
|
|
193
|
+
if not pillow_available():
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
197
|
+
img = _open_rgba(source)
|
|
198
|
+
_resized(img, size).save(dest, format="PNG")
|
|
199
|
+
return True
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def dominant_background_color(source: Path) -> Optional[str]:
|
|
203
|
+
"""Best-effort estimate of a splash background color from an image.
|
|
204
|
+
|
|
205
|
+
Samples the image's corner pixels and returns the most common one as
|
|
206
|
+
a ``#RRGGBB`` hex string. Used as a default splash background when the
|
|
207
|
+
config doesn't specify one.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
source: Path to the splash image.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
A hex color string, or ``None`` if Pillow is missing or the
|
|
214
|
+
sampling fails.
|
|
215
|
+
"""
|
|
216
|
+
if not pillow_available():
|
|
217
|
+
return None
|
|
218
|
+
try:
|
|
219
|
+
img = _open_rgba(source)
|
|
220
|
+
width, height = img.size
|
|
221
|
+
corners: List[Tuple[int, int]] = [
|
|
222
|
+
(0, 0),
|
|
223
|
+
(width - 1, 0),
|
|
224
|
+
(0, height - 1),
|
|
225
|
+
(width - 1, height - 1),
|
|
226
|
+
]
|
|
227
|
+
counts: Dict[Tuple[int, int, int], int] = {}
|
|
228
|
+
for x, y in corners:
|
|
229
|
+
r, g, b, _a = img.getpixel((x, y))
|
|
230
|
+
key = (r, g, b)
|
|
231
|
+
counts[key] = counts.get(key, 0) + 1
|
|
232
|
+
r, g, b = max(counts, key=lambda k: counts[k])
|
|
233
|
+
return f"#{r:02X}{g:02X}{b:02X}"
|
|
234
|
+
except Exception:
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def has_source(path: Optional[Path]) -> bool:
|
|
239
|
+
"""Return whether ``path`` is a readable existing file.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
path: A candidate asset path, or ``None``.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
``True`` when the path is a file that exists on disk.
|
|
246
|
+
"""
|
|
247
|
+
return bool(path and os.path.isfile(path))
|