pythonnative 0.20.0__py3-none-any.whl → 0.22.0__py3-none-any.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.
Files changed (33) hide show
  1. pythonnative/__init__.py +14 -3
  2. pythonnative/animated.py +420 -135
  3. pythonnative/cli/pn.py +450 -956
  4. pythonnative/components.py +519 -235
  5. pythonnative/events.py +210 -0
  6. pythonnative/gestures.py +875 -0
  7. pythonnative/layout.py +463 -149
  8. pythonnative/mutations.py +130 -0
  9. pythonnative/native_views/__init__.py +161 -97
  10. pythonnative/native_views/android.py +1050 -1124
  11. pythonnative/native_views/base.py +108 -18
  12. pythonnative/native_views/desktop.py +460 -417
  13. pythonnative/native_views/ios.py +1918 -1916
  14. pythonnative/project/__init__.py +68 -0
  15. pythonnative/project/android.py +504 -0
  16. pythonnative/project/builder.py +555 -0
  17. pythonnative/project/config.py +642 -0
  18. pythonnative/project/doctor.py +233 -0
  19. pythonnative/project/icons.py +247 -0
  20. pythonnative/project/ios.py +344 -0
  21. pythonnative/project/permissions.py +343 -0
  22. pythonnative/project/runtime_assets.py +272 -0
  23. pythonnative/reconciler.py +540 -470
  24. pythonnative/screen.py +5 -2
  25. pythonnative/sdk/_components.py +2 -2
  26. pythonnative/templates/android_template/app/build.gradle +2 -0
  27. {pythonnative-0.20.0.dist-info → pythonnative-0.22.0.dist-info}/METADATA +10 -2
  28. {pythonnative-0.20.0.dist-info → pythonnative-0.22.0.dist-info}/RECORD +32 -21
  29. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PNVirtualListView.java +0 -129
  30. {pythonnative-0.20.0.dist-info → pythonnative-0.22.0.dist-info}/WHEEL +0 -0
  31. {pythonnative-0.20.0.dist-info → pythonnative-0.22.0.dist-info}/entry_points.txt +0 -0
  32. {pythonnative-0.20.0.dist-info → pythonnative-0.22.0.dist-info}/licenses/LICENSE +0 -0
  33. {pythonnative-0.20.0.dist-info → pythonnative-0.22.0.dist-info}/top_level.txt +0 -0
pythonnative/screen.py CHANGED
@@ -555,8 +555,11 @@ def _full_remount(host: Any, reloaded_modules: Sequence[str]) -> None:
555
555
  finally:
556
556
  host._is_rendering = False
557
557
 
558
- if old_reconciler is not None and old_reconciler._tree is not None:
559
- old_reconciler._destroy_tree(old_reconciler._tree)
558
+ if old_reconciler is not None:
559
+ # ``unmount`` queues the DestroyOps *and* flushes them to the
560
+ # backend in one batch (releasing native views and their event
561
+ # registrations).
562
+ old_reconciler.unmount()
560
563
  if old_root is not None:
561
564
  host._detach_root(old_root)
562
565
 
@@ -41,7 +41,7 @@ Example:
41
41
 
42
42
  @native_component("Badge", props=BadgeProps, platforms=("ios",))
43
43
  class IOSBadgeHandler(ViewHandler):
44
- def create(self, props):
44
+ def create(self, tag, props):
45
45
  ...
46
46
 
47
47
  def update(self, view, changed):
@@ -162,7 +162,7 @@ def native_component(
162
162
 
163
163
  @native_component("Badge", props=BadgeProps, platforms=("ios",))
164
164
  class IOSBadgeHandler(ViewHandler):
165
- def create(self, props):
165
+ def create(self, tag, props):
166
166
  ...
167
167
  ```
168
168
  """
@@ -49,6 +49,8 @@ dependencies {
49
49
  implementation 'com.google.android.material:material:1.5.0'
50
50
  implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
51
51
  implementation 'androidx.recyclerview:recyclerview:1.3.2'
52
+ // Pull-to-refresh (ScrollView's refresh_control prop)
53
+ implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
52
54
  // AndroidX Navigation for Fragment-based navigation
53
55
  implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
54
56
  implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonnative
3
- Version: 0.20.0
3
+ Version: 0.22.0
4
4
  Summary: Cross-platform native UI toolkit for Android and iOS
5
5
  Author: Owen Carey
6
6
  License: MIT License
@@ -42,8 +42,11 @@ Requires-Python: >=3.10
42
42
  Description-Content-Type: text/markdown
43
43
  License-File: LICENSE
44
44
  Requires-Dist: requests>=2.31.0
45
+ Requires-Dist: tomli>=2.0; python_version < "3.11"
45
46
  Provides-Extra: ios
46
47
  Requires-Dist: rubicon-objc<0.5.0,>=0.4.6; extra == "ios"
48
+ Provides-Extra: build
49
+ Requires-Dist: Pillow>=10.0; extra == "build"
47
50
  Provides-Extra: docs
48
51
  Requires-Dist: mkdocs>=1.5; extra == "docs"
49
52
  Requires-Dist: mkdocs-material[imaging]>=9.5; extra == "docs"
@@ -56,12 +59,14 @@ Requires-Dist: ruff>=0.5; extra == "dev"
56
59
  Requires-Dist: mypy>=1.10; extra == "dev"
57
60
  Requires-Dist: pytest>=8.0; extra == "dev"
58
61
  Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
62
+ Requires-Dist: Pillow>=10.0; extra == "dev"
59
63
  Provides-Extra: ci
60
64
  Requires-Dist: black>=24.0; extra == "ci"
61
65
  Requires-Dist: ruff>=0.5; extra == "ci"
62
66
  Requires-Dist: mypy>=1.10; extra == "ci"
63
67
  Requires-Dist: pytest>=8.0; extra == "ci"
64
68
  Requires-Dist: pytest-asyncio>=0.23; extra == "ci"
69
+ Requires-Dist: Pillow>=10.0; extra == "ci"
65
70
  Dynamic: license-file
66
71
 
67
72
  <p align="center">
@@ -102,7 +107,10 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
102
107
  - **Hooks and function components:** Manage state with `use_state`, side effects with `use_effect`, and navigation with `use_navigation`, all through one consistent pattern.
103
108
  - **Typed `style` prop:** Pass all visual and layout properties through a single `style` dict, fully described by the `pn.Style` `TypedDict` and the ergonomic `pn.style(...)` helper for IDE autocomplete and static checking. Compose reusable styles with `StyleSheet`.
104
109
  - **Cross-platform flexbox engine:** A pure-Python, Yoga-style layout engine computes frames once and applies them to native views, so `flex`, `padding`, `aspect_ratio`, and `position: "absolute"` produce the same geometry on Android and iOS.
105
- - **Virtual view tree + reconciler:** Element trees are diffed and patched with minimal native mutations, similar to React's reconciliation. State updates re-render **locally** — only the component whose state changed (and its subtree) re-runs, and unchanged leaves reuse cached intrinsic measurements — so deep UIs stay responsive instead of re-rendering the whole app from the root on every tap.
110
+ - **Virtual view tree + reconciler:** Element trees are diffed and patched with minimal native mutations, similar to React's reconciliation. Each commit lands as **one batched transaction** of mutation ops, and event callbacks are routed through a tag-based registry so re-renders that only change closures cost zero native calls. State updates re-render **locally** — only the component whose state changed (and its subtree) re-runs, and unchanged leaves reuse cached intrinsic measurements — so deep UIs stay responsive instead of re-rendering the whole app from the root on every tap.
111
+ - **Native-driven animations:** The `Animated` API (timing / spring / decay, awaitable or fire-and-forget) hands animations to Core Animation and `ViewPropertyAnimator` whenever possible, so no Python code runs per frame; a pure-Python ticker covers the rest.
112
+ - **Native gesture system:** Attach `Tap`, `LongPress`, `Pan`, `Swipe`, `Pinch`, and `Rotation` recognizers to any view via the `gestures=` prop — backed by `UIGestureRecognizer` on iOS and a unit-testable pure-Python arbiter on Android and desktop.
113
+ - **Virtualized lists:** `FlatList` / `SectionList` window their rows in Python over the platform scroll view — uniform, exact, or measured variable heights, grids, headers/footers, infinite scroll, and an imperative scroll controller, identical on every platform.
106
114
  - **Direct native bindings:** Python calls platform APIs directly through Chaquopy and rubicon-objc, with no JavaScript bridge.
107
115
  - **Custom-component SDK:** Wrap any platform widget as a first-class element with type-checked props via `pythonnative.sdk` (`Props`, `@native_component`, `element_factory`). Plugins distributed on PyPI auto-register through the `pythonnative.handlers` entry-point group.
108
116
  - **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app.
@@ -1,25 +1,28 @@
1
- pythonnative/__init__.py,sha256=tfRm60oMZNS2TXgluc8QfIi2uV3fHncDYVNB9ir8voY,8042
1
+ pythonnative/__init__.py,sha256=O7ILJvQ_oo1Bw3Ckz0SfnBF1Wr1C06M4jFOkbvzInrQ,8551
2
2
  pythonnative/_ios_log.py,sha256=Oi7V28VxcVoZyrpAirvLeEmUW18McqnU87V4d37Zzlw,2582
3
3
  pythonnative/alerts.py,sha256=mIANysFlaHwL5EqKnvNcyiJN9rGiZi9XDrD9Jpz1RFM,9340
4
- pythonnative/animated.py,sha256=bAgG_sGODAdl5eVQjX_vryaKI1hyjI92QH1PNx7Tqyg,24491
5
- pythonnative/components.py,sha256=7vkoMaKVTVKZNBut1UKET3xawnJzuIc-Zt7m__3w9X8,72503
4
+ pythonnative/animated.py,sha256=1rvF-uQtQjrYN6Wgl4CaAZzJzuYMjbLsmKMNlR8R7tc,36251
5
+ pythonnative/components.py,sha256=s0Y18qqRJeBs0x7Yn0hGvTtHwzGPgzw5-jROZdDWiCY,85284
6
6
  pythonnative/element.py,sha256=W9varJj0Cl9HpckL8BcsC1u4ryUQOPVMrvetro4ilAE,2725
7
+ pythonnative/events.py,sha256=wM3c3I3X9DTV9sUqcPBZGd4nlYudYKaVHXw0cAlNzEk,7646
8
+ pythonnative/gestures.py,sha256=15tq6CF0n_WoPFZkR5f3gyoxI6x5rapQL1Zh_s4Tmcg,29949
7
9
  pythonnative/hooks.py,sha256=_XkoyK0aTqu3A7BiiXalN3R-qXTiOh1UbL_ZmUcIaDA,38996
8
10
  pythonnative/hot_reload.py,sha256=j7z2c7o2Hdoyd-p4nQY15LTW7CBH_1z0TSAzLCer-aA,25036
9
- pythonnative/layout.py,sha256=siU7PeVOjL_G1f-1q31ssrKWlxz2UBmvMwNXtmqyOxw,36586
11
+ pythonnative/layout.py,sha256=R5WFbEBMBK48zBX1nS2CAaDabvysO-mM_mfQVyyG5l8,49086
12
+ pythonnative/mutations.py,sha256=Aub3igru5rMPL--D4o1gAetzIIi48gX0Vo2zdfykCsU,4024
10
13
  pythonnative/navigation.py,sha256=skMZFh3AXEJgTU6qQpATFN1Lp4GB94K_ACNNXZjEOEE,35579
11
14
  pythonnative/net.py,sha256=UI-39-BmGYWLE_vMAFoAbkzWZvfhIFj9yX_gexp1loc,8091
12
15
  pythonnative/platform.py,sha256=cqG37hPY1fh6QzgO_AfHObg8R1fiMZmDeMu_2TIXqO0,4997
13
16
  pythonnative/platform_metrics.py,sha256=m2u8M8x52n5THNsYdspcaI9mlWWMbfSJWai1svjD0NM,8976
14
17
  pythonnative/preview.py,sha256=ZtDupXfQdW07i2JD-fnoikAd3zHKVPYoPSMob1K8KQs,16990
15
- pythonnative/reconciler.py,sha256=cy6OtPXlxHzMafpNuMUfTMqIVobrxCnkwYd2MaiqOXw,56815
18
+ pythonnative/reconciler.py,sha256=P6TrAy9ooX0YvA2aaer92nqKLzNrVplsq8Gdo5_v6gE,57109
16
19
  pythonnative/runtime.py,sha256=8xQvhZvMQJYJ0eozWTwKvC-H1GN5vikl6OCxt8f5uI0,18267
17
- pythonnative/screen.py,sha256=Vm6tdc9YM9P1eORmEo-6clODeaTf6rF0aVFDgSxg6NE,64745
20
+ pythonnative/screen.py,sha256=YxXzVXfEY7Q6imhQnN6Y3HGDqPsMmW9JRVtZPQ1JJD8,64849
18
21
  pythonnative/storage.py,sha256=hLgSI44ADq6wj29eeYbHaAUNpxYPzJ2ZLn1L7AHkPZY,12010
19
22
  pythonnative/style.py,sha256=yDJv-G6iZIgrscpc-IZS_cbEQvY2o7R02PTQZ4BV8RA,15162
20
23
  pythonnative/utils.py,sha256=-hwe_YS19ebpjeygdl3dGeVsYzO4G74rYD53svSi0rI,7593
21
24
  pythonnative/cli/__init__.py,sha256=NM1psvKe8jT0vzp8Ak4MMoygZz4P_msk5g-YEsY8xLk,232
22
- pythonnative/cli/pn.py,sha256=wd6mpPxO5nMzt_jJWbw_Vp4Rz-BceQZHHu2o3CaE6KE,53795
25
+ pythonnative/cli/pn.py,sha256=dkFEQDV167j6s-AEsFHorjgaQ6XOW2y-yzz1SyBpE2E,28194
23
26
  pythonnative/native_modules/__init__.py,sha256=pgigpHuzT-rqwcjlwJvu93_4L8Nozal1HJid0S_JlmM,2636
24
27
  pythonnative/native_modules/app_state.py,sha256=EnfChi_YWEgUpZosUiBQh0CmblBZFw8ZGaW1NKIJ4WM,2666
25
28
  pythonnative/native_modules/battery.py,sha256=gOU9aN5fCmWfHgTXPD-BgvatdQnyUjfVfsJM7PQ_ARA,4317
@@ -35,25 +38,33 @@ pythonnative/native_modules/notifications.py,sha256=WVtzdimc_aGfnxU6syCFPkjHF9YR
35
38
  pythonnative/native_modules/permissions.py,sha256=adRiO_LGxZ1PSJaCoJx_3nheuh9lLWNrPIb47O_A6-Y,6710
36
39
  pythonnative/native_modules/secure_store.py,sha256=YC25T2n2Nkfgks_qrCM1CR232AeSkh1_78NOJEBQ800,5956
37
40
  pythonnative/native_modules/share.py,sha256=B9ovknmnjeQvGQ8MQ14Hmq6E1x-JA469APMburJ0KUg,4727
38
- pythonnative/native_views/__init__.py,sha256=PCb2twVEIwEgMS5NZxsjoe4DeZwm1LRh0Q4QKYHS--A,12347
39
- pythonnative/native_views/android.py,sha256=z2ypAqMcgL9WNjVcTw-oINgbcFZJR27awC2jS_cWqJ0,114036
40
- pythonnative/native_views/base.py,sha256=LXDQYRM8wJa3MmGPwslkVyvlu36_s1_J6aO7wwhwYpA,6173
41
- pythonnative/native_views/desktop.py,sha256=Z4r-72B3zbuvnqbJ5um35UqPM_iTj8wrEz61qcg0SZA,54931
42
- pythonnative/native_views/ios.py,sha256=F-DTStyva9fsESHAR5qZkNwrQKH_q2BoSGzgKPKJCBA,142727
41
+ pythonnative/native_views/__init__.py,sha256=8RK0o8pixuqyHhiT5HMWDiya2vHBRJhntjjXzB2HB-U,15638
42
+ pythonnative/native_views/android.py,sha256=nYcgl5PWx68N5yBIomgkU649BPfw8l6MBMOrVEeZsLI,109856
43
+ pythonnative/native_views/base.py,sha256=FmbV9WzS_9PPOnGb0VTExdukfxXrmDQ1VbBIKjL4NpU,9677
44
+ pythonnative/native_views/desktop.py,sha256=66uVoj7GgRiWdJCgZMBmk_wSnHNfUux5WGjLp3Qbahc,57134
45
+ pythonnative/native_views/ios.py,sha256=0aIH4vldnO-_u6Ldh_g21bB5h6b72YJaUGYDG5fth-o,141570
46
+ pythonnative/project/__init__.py,sha256=kAhWLONs53H1L7xVtczLmzYcQSOOkdRZTAJnIMhpBts,2064
47
+ pythonnative/project/android.py,sha256=SX0uu4-tz4WdYAf9sbycQPSmoQ8fbtAADeUWk9G8ybM,19127
48
+ pythonnative/project/builder.py,sha256=ZubKkKy8NpdkCMypiRFAxDrvL2pgrFxF4TYBdp-ecnk,19098
49
+ pythonnative/project/config.py,sha256=BvBkeY0GB7PNRHnLzIoOGD3Fop-Fh248d_zoggm1WQc,24221
50
+ pythonnative/project/doctor.py,sha256=4z-IhalZ-SoSshgJHX7lEsDIrIlVeaOgR0CmiuDuJyk,7949
51
+ pythonnative/project/icons.py,sha256=edoi8RyztkoNJ_FIhkw6POGP2CIHA5Qg0AxLH3jiCGM,7948
52
+ pythonnative/project/ios.py,sha256=6-hCA6QT9sOXUSuAZryokS6HYGmOucn6qkxW_dNQFz8,14007
53
+ pythonnative/project/permissions.py,sha256=v4wGnfWMwnJ6U13KPKg9R9nq8Q4cDIIYFQ5QIVpMIXc,13236
54
+ pythonnative/project/runtime_assets.py,sha256=xX46O3-XKNlkOqEmWVudq55EsTtCUSXklHHX0G1wonQ,10168
43
55
  pythonnative/sdk/__init__.py,sha256=btIRfW2yy2d2LzjdpFnlc6ym-G3iJj9sVUbb2IlFMOI,3384
44
- pythonnative/sdk/_components.py,sha256=Hw0cqiyJ1NEzUrhOIT8zsC_mnVtf0jgpPUsireQG2qM,14644
56
+ pythonnative/sdk/_components.py,sha256=nhV1WytgcVRI6GlS4WRgNSTQLSJpYs5lARju-Ry8PV0,14654
45
57
  pythonnative/templates/android_template/build.gradle,sha256=4gE6CRS6RuBu9kp-_e_uYYU9mBgHVZrqQg9caSxgyuc,352
46
58
  pythonnative/templates/android_template/gradle.properties,sha256=REPaKLRfQiiVfIV8wYmgwzPWvF1f3bhh_kAMV9p4HME,1358
47
59
  pythonnative/templates/android_template/gradlew,sha256=YxNShxF6Hm0SyEWA8fScYdG6AiGOzShmBgXpf5dufWU,5766
48
60
  pythonnative/templates/android_template/gradlew.bat,sha256=xGonx5AHdG3lkisXq7YjDWStixujrRWF7lxlQ8KpsSk,2674
49
61
  pythonnative/templates/android_template/settings.gradle,sha256=GKZiYUYWsaXxaiKOB65xnOs4jLmf0rhvI_3f8x0ic-o,333
50
- pythonnative/templates/android_template/app/build.gradle,sha256=hfYe04a9ngJXplrHkZOgKO6kyKJV0m0HgTbVdEZMqo8,1731
62
+ pythonnative/templates/android_template/app/build.gradle,sha256=zHYbYXjKUiW-ZSYXT2GfveyVnjOCNLXvXpPxI76O5t4,1864
51
63
  pythonnative/templates/android_template/app/proguard-rules.pro,sha256=Vv2WDPIl9spA-YKxOl27DYvD394T_3ZCKCXGBw0KGJA,750
52
64
  pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt,sha256=Am8Yla3i1eR_ac5FVgPU_RsuMrCbyT79h1BcajGE-zI,693
53
65
  pythonnative/templates/android_template/app/src/main/AndroidManifest.xml,sha256=MdWrXxOrwUjnqtDbV952NI4nVF2dTUX9xwSS8chhd9I,940
54
66
  pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt,sha256=1dSBEX-AB2aUPxFFDnWwcmVHRi00T-iwbXi4yt4RQk8,1481
55
67
  pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt,sha256=mDfzKTTXRP-zbSnfIPxAYyjtr9_IyyQwXM-dovcfVbg,1723
56
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PNVirtualListView.java,sha256=zVo7foI-58BmIgEuyfUdLQ9Q1dllwAG_1hVrev-c0vg,4245
57
68
  pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt,sha256=lSxWYH6cGDpGalo0kDzTAT5H3NuhJVLT7BQYcfCydOc,5138
58
69
  pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml,sha256=7UI8c6b0Ck0pCfCQHmBSezqAfNWeG1WTvKrhgIscYyE,5606
59
70
  pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml,sha256=AdGmpsEjTrf-Jw0JfrKD1yucla5RGIhvG2VzqtKA8fc,1702
@@ -94,9 +105,9 @@ pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/x
94
105
  pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift,sha256=YnwzZx7yXB13xKAXEGNgz17VuhWeqkHTRTtBJ2Vu3_E,1238
95
106
  pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift,sha256=l2Pwa50F_rv-qPu2go6e4bQernM6PTQJeNPFl_c4ivY,1387
96
107
  pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift,sha256=f5JrG0uVtLMeJQy26Yyz7Om-JUkT220osqcbeIVkj2g,815
97
- pythonnative-0.20.0.dist-info/licenses/LICENSE,sha256=A69iG7TIAe6KkGQf6xoVHkc5JSZtOr5eRSvC5iuivnI,1067
98
- pythonnative-0.20.0.dist-info/METADATA,sha256=XlOYAungaXEGKHMhG9xRQV2IUCcWrgKoHCci7hwou54,9233
99
- pythonnative-0.20.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
100
- pythonnative-0.20.0.dist-info/entry_points.txt,sha256=iUtDawWSAJAEyWTycpZxDuYz73ol31butpzDIEAgPO0,48
101
- pythonnative-0.20.0.dist-info/top_level.txt,sha256=kT4SEATY2ywzrZ2Pgea6_zxyym44Q_PbOsUoOYjJLFE,13
102
- pythonnative-0.20.0.dist-info/RECORD,,
108
+ pythonnative-0.22.0.dist-info/licenses/LICENSE,sha256=A69iG7TIAe6KkGQf6xoVHkc5JSZtOr5eRSvC5iuivnI,1067
109
+ pythonnative-0.22.0.dist-info/METADATA,sha256=UO33N8eFODdiQVv5nNmozkMeGC0okaFlkSiuvdBpNOw,10408
110
+ pythonnative-0.22.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
111
+ pythonnative-0.22.0.dist-info/entry_points.txt,sha256=iUtDawWSAJAEyWTycpZxDuYz73ol31butpzDIEAgPO0,48
112
+ pythonnative-0.22.0.dist-info/top_level.txt,sha256=kT4SEATY2ywzrZ2Pgea6_zxyym44Q_PbOsUoOYjJLFE,13
113
+ pythonnative-0.22.0.dist-info/RECORD,,
@@ -1,129 +0,0 @@
1
- package com.pythonnative.android_template;
2
-
3
- import android.content.Context;
4
- import android.util.TypedValue;
5
- import android.view.ViewGroup;
6
- import android.widget.FrameLayout;
7
-
8
- import androidx.annotation.NonNull;
9
- import androidx.recyclerview.widget.LinearLayoutManager;
10
- import androidx.recyclerview.widget.RecyclerView;
11
-
12
- /**
13
- * RecyclerView-backed fixed-height list used by PythonNative's Android bridge.
14
- *
15
- * <p>Chaquopy can proxy Java interfaces from Python, but it can't subclass Java
16
- * abstract classes such as RecyclerView.Adapter or RecyclerView.ViewHolder. This
17
- * helper owns those abstract-class implementations in Java and delegates row
18
- * content back to Python through the small Delegate interface below.</p>
19
- */
20
- public class PNVirtualListView extends RecyclerView {
21
- public interface Delegate {
22
- int getCount();
23
-
24
- float getRowHeightDp();
25
-
26
- void mountRow(int position, FrameLayout container, float widthDp, float heightDp);
27
-
28
- void onRowPress(int position);
29
- }
30
-
31
- private final float density;
32
- private final RowAdapter rowAdapter;
33
- private Delegate delegate;
34
-
35
- public PNVirtualListView(@NonNull Context context, @NonNull Delegate delegate) {
36
- super(context);
37
- this.delegate = delegate;
38
- this.density = context.getResources().getDisplayMetrics().density;
39
- setLayoutManager(new LinearLayoutManager(context));
40
- setHasFixedSize(true);
41
- rowAdapter = new RowAdapter();
42
- setAdapter(rowAdapter);
43
- }
44
-
45
- public void setDelegate(@NonNull Delegate delegate) {
46
- this.delegate = delegate;
47
- rowAdapter.notifyDataSetChanged();
48
- }
49
-
50
- public void notifyDataChanged() {
51
- rowAdapter.notifyDataSetChanged();
52
- }
53
-
54
- private int rowHeightPx() {
55
- return Math.max(
56
- 1,
57
- Math.round(TypedValue.applyDimension(
58
- TypedValue.COMPLEX_UNIT_DIP,
59
- delegate.getRowHeightDp(),
60
- getResources().getDisplayMetrics()
61
- ))
62
- );
63
- }
64
-
65
- private float currentWidthDp(FrameLayout container) {
66
- int widthPx = container.getWidth();
67
- if (widthPx <= 0) {
68
- widthPx = getWidth();
69
- }
70
- if (widthPx <= 0) {
71
- widthPx = getResources().getDisplayMetrics().widthPixels;
72
- }
73
- return widthPx / density;
74
- }
75
-
76
- private class RowHolder extends RecyclerView.ViewHolder {
77
- final FrameLayout container;
78
-
79
- RowHolder(@NonNull FrameLayout container) {
80
- super(container);
81
- this.container = container;
82
- }
83
- }
84
-
85
- private class RowAdapter extends RecyclerView.Adapter<RowHolder> {
86
- @Override
87
- public int getItemCount() {
88
- return delegate.getCount();
89
- }
90
-
91
- @NonNull
92
- @Override
93
- public RowHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
94
- FrameLayout container = new FrameLayout(parent.getContext());
95
- container.setLayoutParams(
96
- new RecyclerView.LayoutParams(
97
- ViewGroup.LayoutParams.MATCH_PARENT,
98
- rowHeightPx()
99
- )
100
- );
101
- return new RowHolder(container);
102
- }
103
-
104
- @Override
105
- public void onBindViewHolder(@NonNull RowHolder holder, int position) {
106
- RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) holder.container.getLayoutParams();
107
- int heightPx = rowHeightPx();
108
- if (params.height != heightPx) {
109
- params.height = heightPx;
110
- holder.container.setLayoutParams(params);
111
- }
112
- holder.container.removeAllViews();
113
- holder.container.setOnClickListener(v -> delegate.onRowPress(holder.getBindingAdapterPosition()));
114
- delegate.mountRow(
115
- position,
116
- holder.container,
117
- currentWidthDp(holder.container),
118
- delegate.getRowHeightDp()
119
- );
120
- }
121
-
122
- @Override
123
- public void onViewRecycled(@NonNull RowHolder holder) {
124
- holder.container.removeAllViews();
125
- holder.container.setOnClickListener(null);
126
- super.onViewRecycled(holder);
127
- }
128
- }
129
- }