pydrud 1.0.0__tar.gz
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.
- pydrud-1.0.0/LICENSE +21 -0
- pydrud-1.0.0/PKG-INFO +502 -0
- pydrud-1.0.0/README.md +469 -0
- pydrud-1.0.0/pydrud/__init__.py +61 -0
- pydrud-1.0.0/pydrud/android/templates/android/AndroidManifest.xml.j2 +24 -0
- pydrud-1.0.0/pydrud/android/templates/android/BridgeService.java.j2 +173 -0
- pydrud-1.0.0/pydrud/android/templates/android/EventDispatcher.java.j2 +71 -0
- pydrud-1.0.0/pydrud/android/templates/android/MainActivity.java.j2 +93 -0
- pydrud-1.0.0/pydrud/android/templates/android/ViewFactory.java.j2 +565 -0
- pydrud-1.0.0/pydrud/android/templates/android/app/build.gradle.kts.j2 +59 -0
- pydrud-1.0.0/pydrud/android/templates/android/build.gradle.kts.j2 +5 -0
- pydrud-1.0.0/pydrud/android/templates/android/gradle/wrapper/gradle-wrapper.properties.j2 +7 -0
- pydrud-1.0.0/pydrud/android/templates/android/gradle.properties.j2 +6 -0
- pydrud-1.0.0/pydrud/android/templates/android/gradlew.bat.j2 +19 -0
- pydrud-1.0.0/pydrud/android/templates/android/gradlew.j2 +72 -0
- pydrud-1.0.0/pydrud/android/templates/android/local.properties.j2 +2 -0
- pydrud-1.0.0/pydrud/android/templates/android/settings.gradle.kts.j2 +20 -0
- pydrud-1.0.0/pydrud/android/templates/android/themes.xml.j2 +12 -0
- pydrud-1.0.0/pydrud/android/templates/dot.gitignore.j2 +26 -0
- pydrud-1.0.0/pydrud/android/templates/pydrud.yaml.j2 +8 -0
- pydrud-1.0.0/pydrud/android/templates/python/app.py.j2 +1 -0
- pydrud-1.0.0/pydrud/android/templates/python/main.py.j2 +328 -0
- pydrud-1.0.0/pydrud/android/templates/python/pydrud_config.py.j2 +14 -0
- pydrud-1.0.0/pydrud/android/templates/python/run.py.j2 +16 -0
- pydrud-1.0.0/pydrud/android/templates/python/setup.py.j2 +11 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-hdpi/ic_launcher.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-hdpi/ic_launcher_adaptive_back.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-hdpi/ic_launcher_adaptive_fore.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-mdpi/ic_launcher.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-mdpi/ic_launcher_adaptive_back.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-mdpi/ic_launcher_adaptive_fore.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xhdpi/ic_launcher.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xhdpi/ic_launcher_adaptive_back.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png +0 -0
- pydrud-1.0.0/pydrud/android/templates/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png +0 -0
- pydrud-1.0.0/pydrud/commands/__init__.py +1 -0
- pydrud-1.0.0/pydrud/commands/builder.py +440 -0
- pydrud-1.0.0/pydrud/commands/cli.py +131 -0
- pydrud-1.0.0/pydrud/commands/doctor.py +162 -0
- pydrud-1.0.0/pydrud/commands/project.py +282 -0
- pydrud-1.0.0/pydrud/core/__init__.py +1 -0
- pydrud-1.0.0/pydrud/core/bridge.py +66 -0
- pydrud-1.0.0/pydrud/core/diff.py +151 -0
- pydrud-1.0.0/pydrud/core/events.py +68 -0
- pydrud-1.0.0/pydrud/core/responsive.py +116 -0
- pydrud-1.0.0/pydrud/core/state.py +96 -0
- pydrud-1.0.0/pydrud/main.py +289 -0
- pydrud-1.0.0/pydrud/utils/__init__.py +1 -0
- pydrud-1.0.0/pydrud/utils/colors.py +40 -0
- pydrud-1.0.0/pydrud/widgets/__init__.py +28 -0
- pydrud-1.0.0/pydrud/widgets/base.py +131 -0
- pydrud-1.0.0/pydrud/widgets/basic.py +308 -0
- pydrud-1.0.0/pydrud/widgets/layout.py +182 -0
- pydrud-1.0.0/pydrud/widgets/styling.py +304 -0
- pydrud-1.0.0/pydrud.egg-info/PKG-INFO +502 -0
- pydrud-1.0.0/pydrud.egg-info/SOURCES.txt +74 -0
- pydrud-1.0.0/pydrud.egg-info/dependency_links.txt +1 -0
- pydrud-1.0.0/pydrud.egg-info/entry_points.txt +2 -0
- pydrud-1.0.0/pydrud.egg-info/requires.txt +3 -0
- pydrud-1.0.0/pydrud.egg-info/top_level.txt +1 -0
- pydrud-1.0.0/pyproject.toml +57 -0
- pydrud-1.0.0/setup.cfg +4 -0
- pydrud-1.0.0/tests/test_app.py +109 -0
- pydrud-1.0.0/tests/test_bridge.py +50 -0
- pydrud-1.0.0/tests/test_diff.py +104 -0
- pydrud-1.0.0/tests/test_events.py +62 -0
- pydrud-1.0.0/tests/test_responsive.py +88 -0
- pydrud-1.0.0/tests/test_state.py +87 -0
- pydrud-1.0.0/tests/test_styling.py +137 -0
- pydrud-1.0.0/tests/test_widgets.py +188 -0
pydrud-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Pydrud Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pydrud-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pydrud
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A lightweight Python framework for building native Android apps โ Flutter-inspired, radically simpler.
|
|
5
|
+
Author: Pydrud Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/MurShidM01/Pydrud
|
|
8
|
+
Project-URL: Repository, https://github.com/MurShidM01/Pydrud
|
|
9
|
+
Project-URL: Documentation, https://github.com/MurShidM01/Pydrud#readme
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/MurShidM01/Pydrud/issues
|
|
11
|
+
Keywords: android,framework,ui,mobile,python,native,app-development
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Java
|
|
21
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
22
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
23
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
24
|
+
Classifier: Framework :: Setuptools Plugin
|
|
25
|
+
Classifier: Natural Language :: English
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: click>=8.0
|
|
30
|
+
Requires-Dist: Jinja2>=3.0
|
|
31
|
+
Requires-Dist: Pillow>=10.0
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
<p align="center">
|
|
35
|
+
<img src="https://img.shields.io/pypi/v/pydrud?color=6366F1&style=flat-square" alt="PyPI" />
|
|
36
|
+
<img src="https://img.shields.io/pypi/pyversions/pydrud?style=flat-square" alt="Python" />
|
|
37
|
+
<img src="https://img.shields.io/badge/android-native-brightgreen?style=flat-square" alt="Android Native" />
|
|
38
|
+
<img src="https://img.shields.io/github/license/MurShidM01/Pydrud?style=flat-square" alt="License" />
|
|
39
|
+
<img src="https://img.shields.io/pypi/dm/pydrud?style=flat-square" alt="Downloads" />
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<h1 align="center">โก Pydrud</h1>
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<strong>Build native Android apps with Python.<br>
|
|
46
|
+
No XML layouts. No Kotlin UI code. Just Python.</strong>
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
A Flutter-inspired framework that converts declarative Python widget trees<br>
|
|
51
|
+
into <strong>real native Android Views</strong> at runtime โ via Chaquopy + a lightweight TCP bridge.
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
<br>
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## โจ Quick Start
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install pydrud # Install the framework
|
|
62
|
+
pydrud init my_app --org com.example # Scaffold a new project
|
|
63
|
+
cd my_app
|
|
64
|
+
pydrud run # Build โ install โ launch
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**First APK in ~2 minutes.** Connect your Android device via USB (or ADB over TCP), and `pydrud run` does the rest.
|
|
68
|
+
|
|
69
|
+
<br>
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## ๐ฑ What You Get
|
|
74
|
+
|
|
75
|
+
| | |
|
|
76
|
+
|---|---|
|
|
77
|
+
| **๐งฑ Declarative UI** | Compose screens with Python โ `Container`, `Column`, `Row`, `Text`, `Button`, and more |
|
|
78
|
+
| **โก Reactive State** | `State<T>` auto-triggers UI re-renders on value change |
|
|
79
|
+
| **๐จ Full Styling** | Colors, padding, margin, borders, fonts, elevation, alignment |
|
|
80
|
+
| **๐ฒ Native Rendering** | Every widget becomes a real Android `View` โ not a WebView or canvas |
|
|
81
|
+
| **๐ CLI Toolchain** | `init` / `build` / `run` / `clean` / `doctor` โ one command to ship |
|
|
82
|
+
| **๐ Responsive** | `Responsive.text()` auto-scales UI to any screen size |
|
|
83
|
+
| **๐ TCP Bridge** | Clean NDJSON protocol over port 8595 โ debuggable with any JSON tool |
|
|
84
|
+
|
|
85
|
+
<br>
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ๐ Example App
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from pydrud import App, Text, Container, Column, Row, Button, Center
|
|
93
|
+
from pydrud import State, EdgeInsets, Alignment
|
|
94
|
+
|
|
95
|
+
counter = State(0)
|
|
96
|
+
|
|
97
|
+
def main(page):
|
|
98
|
+
page.title = "Pydrud Demo"
|
|
99
|
+
page.bgcolor = "#FFF9FAFB"
|
|
100
|
+
|
|
101
|
+
def on_pressed(data):
|
|
102
|
+
counter.value += 1
|
|
103
|
+
page.update()
|
|
104
|
+
|
|
105
|
+
page.add(
|
|
106
|
+
Column(scroll=True, children=[
|
|
107
|
+
|
|
108
|
+
Container(
|
|
109
|
+
bg="#FF6366F1", padding=EdgeInsets.symmetric(horizontal=20, vertical=16),
|
|
110
|
+
child=Text("Pydrud", size=20, weight=700, color="#FFFFFFFF"),
|
|
111
|
+
),
|
|
112
|
+
|
|
113
|
+
Spacer(expand=2),
|
|
114
|
+
Center(child=Text(str(counter.value), size=72, weight=200, color="#FF6366F1")),
|
|
115
|
+
Center(child=Text("Tap the button", size=14, color="#FF9CA3AF")),
|
|
116
|
+
Spacer(expand=3),
|
|
117
|
+
|
|
118
|
+
Center(
|
|
119
|
+
child=Button(
|
|
120
|
+
"+", bg_color="#FF6366F1", color="#FFFFFFFF",
|
|
121
|
+
style={"borderRadius": 28, "width": 56, "height": 56},
|
|
122
|
+
).on_click(on_pressed),
|
|
123
|
+
),
|
|
124
|
+
Spacer(expand=1),
|
|
125
|
+
|
|
126
|
+
]),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
app = App(target=main)
|
|
130
|
+
app.run()
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
> ๐ก **State lives outside `main()`** so it persists across re-renders.
|
|
134
|
+
> Update โ `page.update()` โ tree rebuilds โ Android re-renders.
|
|
135
|
+
|
|
136
|
+
<br>
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## ๐ง Installation
|
|
141
|
+
|
|
142
|
+
### From PyPI (recommended)
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
pip install pydrud
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### From source
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
git clone https://github.com/MurShidM01/Pydrud.git
|
|
152
|
+
cd Pydrud
|
|
153
|
+
pip install -e .
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Corporate / proxy networks
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
export http_proxy=http://proxy:port
|
|
160
|
+
export https_proxy=http://proxy:port
|
|
161
|
+
pydrud build # proxy forwarded to Gradle automatically
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
<br>
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## ๐งฑ Widget Reference
|
|
169
|
+
|
|
170
|
+
### Layout
|
|
171
|
+
|
|
172
|
+
| Widget | Description | Key Props |
|
|
173
|
+
|--------|-------------|-----------|
|
|
174
|
+
| `Container` | Box with padding, margin, bg, border-radius | `child`, `padding`, `margin`, `bg`, `border_radius`, `width`, `height`, `alignment`, `expand` |
|
|
175
|
+
| `Column` | Vertical flex layout | `children`, `spacing`, `horizontal_alignment`, `scroll`, `expand` |
|
|
176
|
+
| `Row` | Horizontal flex layout | `children`, `spacing`, `vertical_alignment`, `expand` |
|
|
177
|
+
| `Center` | Centres its child | `child`, `expand` |
|
|
178
|
+
| `Spacer` | Flexible empty space | `expand` (default 1) |
|
|
179
|
+
| `Divider` | Horizontal / vertical line | `color`, `thickness` |
|
|
180
|
+
|
|
181
|
+
### Basic
|
|
182
|
+
|
|
183
|
+
| Widget | Description | Key Props |
|
|
184
|
+
|--------|-------------|-----------|
|
|
185
|
+
| `Text` | Readable text | `value`, `size`, `color`, `weight` (100โ900), `italic`, `text_align` |
|
|
186
|
+
| `Button` | Clickable button | `text`, `variant` (filled / outlined / text), `icon`, `bg_color`, `color`, `disabled` |
|
|
187
|
+
| `TextField` | Text input | `value`, `hint`, `multiline`, `password` |
|
|
188
|
+
| `Image` | Display image | `src` (asset or URL), `fit` |
|
|
189
|
+
| `Icon` | Material icon | `name` (star, home, search, โฆ), `size`, `color` |
|
|
190
|
+
| `Checkbox` | Checkable box | `label`, `checked` |
|
|
191
|
+
| `Switch` | Toggle switch | `label`, `active` |
|
|
192
|
+
|
|
193
|
+
### Events
|
|
194
|
+
|
|
195
|
+
All interactive widgets support callback chaining:
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
widget.on_click(callback) # callback(data) โ data is a dict
|
|
199
|
+
widget.on_change(callback) # TextField, Checkbox, Switch
|
|
200
|
+
widget.on_submit(callback) # TextField (IME action)
|
|
201
|
+
widget.on_focus(callback) # Focus gain / loss
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Styling
|
|
205
|
+
|
|
206
|
+
Use the `Style` builder or pass dicts inline:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
Style().bg("#FFFFFF").padding(EdgeInsets.all(16)).border_radius(8).elevation(4).build()
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**All style properties:**
|
|
213
|
+
|
|
214
|
+
| Prop | Type | Example |
|
|
215
|
+
|------|------|---------|
|
|
216
|
+
| `bg` | Hex color | `"#FF6366F1"` |
|
|
217
|
+
| `opacity` | float 0โ1 | `0.5` |
|
|
218
|
+
| `width` / `height` | int or `"match"` | `200` or `"match"` |
|
|
219
|
+
| `padding` / `margin` | `EdgeInsets` | `EdgeInsets.all(16)` |
|
|
220
|
+
| `borderRadius` | int | `12` |
|
|
221
|
+
| `font.size` | int (sp) | `16` |
|
|
222
|
+
| `font.color` | Hex color | `"#FF1F2937"` |
|
|
223
|
+
| `font.weight` | int 100โ900 | `700` |
|
|
224
|
+
| `font.italic` | bool | `true` |
|
|
225
|
+
| `alignment` | `Alignment` constant | `Alignment.center` |
|
|
226
|
+
| `elevation` | int (dp) | `4` |
|
|
227
|
+
| `visible` | bool | `true` / `false` |
|
|
228
|
+
| `tooltip` | string | `"Save changes"` |
|
|
229
|
+
|
|
230
|
+
<br>
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## ๐ Responsive Scaling
|
|
235
|
+
|
|
236
|
+
Pydrud includes a built-in responsive system that **auto-scales** your UI to the device screen width.
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
from pydrud import Responsive
|
|
240
|
+
|
|
241
|
+
Responsive.text(16) # Font size โ scales proportionally
|
|
242
|
+
Responsive.w(48) # Width โ scales proportionally
|
|
243
|
+
Responsive.h(48) # Height
|
|
244
|
+
Responsive.padding(24) # Padding / margin
|
|
245
|
+
Responsive.spacing(12) # Gaps between widgets
|
|
246
|
+
Responsive.radius(12) # Border radius
|
|
247
|
+
Responsive.icon(24) # Icon size
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**How it works:**
|
|
251
|
+
|
|
252
|
+
1. Android sends the screen dimensions (width, height, density) to Python via the bridge `"ready"` event
|
|
253
|
+
2. Python's `Responsive` class computes a scale factor: `screen_width_dp / 360`
|
|
254
|
+
3. All sizes are multiplied by this factor โ on a 720dp tablet, everything is **2ร larger**
|
|
255
|
+
4. Baseline `360dp` matches the typical phone width
|
|
256
|
+
|
|
257
|
+
> โ
No device info available? Defaults to factor `1.0` (no scaling) โ safe fallback.
|
|
258
|
+
|
|
259
|
+
<br>
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## ๐ Architecture
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
267
|
+
โ Python Layer โ
|
|
268
|
+
โ โโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
269
|
+
โ โWidgets โ โ EventDispatcher โ โ
|
|
270
|
+
โ โ Tree โโโโค (user callbacks) โ โ
|
|
271
|
+
โ โโโโโฌโโโโโ โโโโโโโโโโโโฌโโโโโโโโโโโโ โ
|
|
272
|
+
โ โ โ โ
|
|
273
|
+
โ โโโโโผโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโ โ
|
|
274
|
+
โ โ TreeDiff โ Patches โ Bridge.encodeโ โ
|
|
275
|
+
โ โโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโ โ
|
|
276
|
+
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโ
|
|
277
|
+
โ TCP / NDJSON :8595
|
|
278
|
+
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโ
|
|
279
|
+
โ Android Layer โ โ
|
|
280
|
+
โ โโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ โ
|
|
281
|
+
โ โ BridgeService (TCP server) โ โ
|
|
282
|
+
โ โโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโ โ
|
|
283
|
+
โ โโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ โ
|
|
284
|
+
โ โ ViewFactory โ native Views โ โ
|
|
285
|
+
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
286
|
+
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
287
|
+
โ โ EventDispatcher โ Python โ โ
|
|
288
|
+
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
289
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Data Flow
|
|
293
|
+
|
|
294
|
+
1. **`App(target=main)`** โ calls your builder โ produces a Widget tree
|
|
295
|
+
2. **`page.update()`** โ rebuilds the tree โ sends full render command to Android
|
|
296
|
+
3. **`BridgeService`** โ receives the JSON tree โ `ViewFactory` creates native Views
|
|
297
|
+
4. **User taps a Button** โ Java sends `{"type":"click","key":"..."}` over the socket
|
|
298
|
+
5. **Python EventDispatcher** โ routes the event to your callback
|
|
299
|
+
6. **Callback mutates `State`** โ triggers `page.update()` โ goto step 2
|
|
300
|
+
|
|
301
|
+
> ๐ For V1, every state change sends a **full tree re-render**. Incremental patch support is planned for V2.
|
|
302
|
+
|
|
303
|
+
<br>
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## ๐ CLI Reference
|
|
308
|
+
|
|
309
|
+
| Command | Description |
|
|
310
|
+
|---------|-------------|
|
|
311
|
+
| `pydrud init <name>` | Create a new project |
|
|
312
|
+
| `pydrud init <name> --org com.example` | With custom package |
|
|
313
|
+
| `pydrud build` | Build debug APK |
|
|
314
|
+
| `pydrud build --release` | Build release APK |
|
|
315
|
+
| `pydrud run` | Build + install + launch + live logcat |
|
|
316
|
+
| `pydrud run --device <id>` | Target specific device |
|
|
317
|
+
| `pydrud clean` | Clean build artifacts |
|
|
318
|
+
| `pydrud doctor` | Check environment requirements |
|
|
319
|
+
|
|
320
|
+
### Environment
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
pydrud doctor
|
|
324
|
+
|
|
325
|
+
# Expected output:
|
|
326
|
+
# โ Python โฅ 3.10 โ 3.12.3
|
|
327
|
+
# โ Java 17+ โ OpenJDK 17
|
|
328
|
+
# โ Android SDK โ /path/to/sdk (API 35)
|
|
329
|
+
# โ Gradle โ gradlew wrapper found
|
|
330
|
+
# โ ADB โ Android Debug Bridge 2.x
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
<br>
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## โ๏ธ Requirements
|
|
338
|
+
|
|
339
|
+
### Development machine
|
|
340
|
+
|
|
341
|
+
| Tool | Version | Notes |
|
|
342
|
+
|------|---------|-------|
|
|
343
|
+
| Python | โฅ 3.10, โค 3.12 | 3.12 recommended for Chaquopy compatibility |
|
|
344
|
+
| Java (JDK) | 17+ | OpenJDK 17 LTS recommended |
|
|
345
|
+
| Android SDK | API 33+ | Set `ANDROID_HOME` or `ANDROID_SDK_ROOT` |
|
|
346
|
+
| Android NDK | r29+ | Required for Chaquopy native libraries |
|
|
347
|
+
| Gradle | 8.x | Bundled via wrapper in generated projects |
|
|
348
|
+
|
|
349
|
+
### Android device
|
|
350
|
+
|
|
351
|
+
| Requirement | Notes |
|
|
352
|
+
|-------------|-------|
|
|
353
|
+
| API 24+ (Android 7.0+) | Minimum supported |
|
|
354
|
+
| ARM64 / x86_64 | Both supported |
|
|
355
|
+
| USB Debugging enabled | Or ADB over TCP |
|
|
356
|
+
|
|
357
|
+
### Setting up Android SDK
|
|
358
|
+
|
|
359
|
+
<details>
|
|
360
|
+
<summary><b>Windows</b></summary>
|
|
361
|
+
|
|
362
|
+
```powershell
|
|
363
|
+
# Set environment variables
|
|
364
|
+
[System.Environment]::SetEnvironmentVariable('ANDROID_HOME', 'C:\Android\Sdk', 'User')
|
|
365
|
+
[System.Environment]::SetEnvironmentVariable('ANDROID_SDK_ROOT', 'C:\Android\Sdk', 'User')
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Restart your terminal and verify:
|
|
369
|
+
```powershell
|
|
370
|
+
pydrud doctor
|
|
371
|
+
```
|
|
372
|
+
</details>
|
|
373
|
+
|
|
374
|
+
<details>
|
|
375
|
+
<summary><b>Linux / macOS</b></summary>
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
export ANDROID_HOME=$HOME/Android/Sdk
|
|
379
|
+
export ANDROID_SDK_ROOT=$HOME/Android/Sdk
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Add to your `~/.bashrc` or `~/.zshrc`:
|
|
383
|
+
```bash
|
|
384
|
+
echo 'export ANDROID_HOME=$HOME/Android/Sdk' >> ~/.bashrc
|
|
385
|
+
echo 'export ANDROID_SDK_ROOT=$HOME/Android/Sdk' >> ~/.bashrc
|
|
386
|
+
```
|
|
387
|
+
</details>
|
|
388
|
+
|
|
389
|
+
<br>
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## ๐งช Development
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
git clone https://github.com/MurShidM01/Pydrud.git
|
|
397
|
+
cd Pydrud
|
|
398
|
+
pip install -e ".[dev]"
|
|
399
|
+
python -m pytest tests/ -v
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Current test count: **96 tests** (widgets, state, diffing, events, styling, bridge, responsive).
|
|
403
|
+
|
|
404
|
+
### Project Structure
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
pydrud/
|
|
408
|
+
โโโ pydrud/
|
|
409
|
+
โ โโโ main.py # App + Page + bridge event loop
|
|
410
|
+
โ โโโ widgets/
|
|
411
|
+
โ โ โโโ base.py # Widget base class
|
|
412
|
+
โ โ โโโ layout.py # Container, Column, Row, Center, Spacer, Divider
|
|
413
|
+
โ โ โโโ basic.py # Text, Button, TextField, Image, Icon, Checkbox, Switch
|
|
414
|
+
โ โ โโโ styling.py # Style, EdgeInsets, Alignment, FontStyle
|
|
415
|
+
โ โโโ core/
|
|
416
|
+
โ โ โโโ state.py # State[T], ReactiveDict
|
|
417
|
+
โ โ โโโ diff.py # TreeDiff โ Patch list
|
|
418
|
+
โ โ โโโ events.py # Event dispatcher
|
|
419
|
+
โ โ โโโ bridge.py # Protocol encoding / decoding
|
|
420
|
+
โ โ โโโ responsive.py # Responsive scaling
|
|
421
|
+
โ โโโ commands/
|
|
422
|
+
โ โ โโโ cli.py # Click CLI
|
|
423
|
+
โ โ โโโ project.py # Jinja2 project scaffold
|
|
424
|
+
โ โ โโโ builder.py # Gradle + ADB
|
|
425
|
+
โ โ โโโ doctor.py # Environment check
|
|
426
|
+
โ โโโ android/templates/ # Jinja2 โ Android project
|
|
427
|
+
โโโ tests/ # pytest test suite
|
|
428
|
+
โโโ pyproject.toml
|
|
429
|
+
โโโ README.md
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Adding a New Widget
|
|
433
|
+
|
|
434
|
+
1. Create Python class in `pydrud/widgets/` (extend `Widget`, set `_widget_type`, implement `_serialise_props()`)
|
|
435
|
+
2. Export in `pydrud/widgets/__init__.py` and `pydrud/__init__.py`
|
|
436
|
+
3. Add a creator method in `pydrud/android/templates/android/ViewFactory.java.j2`
|
|
437
|
+
4. Add style handling in `applyStyle()`
|
|
438
|
+
5. Write tests in `tests/`
|
|
439
|
+
6. Run `python -m pytest tests/ -v`
|
|
440
|
+
|
|
441
|
+
<br>
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## ๐ฆ Publishing to PyPI
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
# Install build tools
|
|
449
|
+
pip install build twine
|
|
450
|
+
|
|
451
|
+
# Build source distribution and wheel
|
|
452
|
+
python -m build
|
|
453
|
+
|
|
454
|
+
# Upload to PyPI
|
|
455
|
+
twine upload dist/*
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
> ๐ก Update the version number in `pyproject.toml` before publishing.
|
|
459
|
+
|
|
460
|
+
<br>
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## ๐บ Roadmap
|
|
465
|
+
|
|
466
|
+
| Version | Focus |
|
|
467
|
+
|---------|-------|
|
|
468
|
+
| **V1** โ
| Core widgets, state, diffing, CLI, APK generation, responsive scaling |
|
|
469
|
+
| **V2** ๐ | Hot reload, Material theme, ListView / GridView, Navigation, Animations, Snackbar / Dialog |
|
|
470
|
+
| **V3** ๐ | Canvas / CustomPaint, Camera / GPS, Plugins, Database (SQLite), i18n |
|
|
471
|
+
| **V4** ๐ | iOS backend (SwiftUI), Web (WASM), macOS desktop |
|
|
472
|
+
|
|
473
|
+
<br>
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## ๐ค Contributing
|
|
478
|
+
|
|
479
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
480
|
+
|
|
481
|
+
1. Fork the repository
|
|
482
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
483
|
+
3. Commit your changes (`git commit -am 'Add amazing feature'`)
|
|
484
|
+
4. Push (`git push origin feature/amazing-feature`)
|
|
485
|
+
5. Open a Pull Request
|
|
486
|
+
|
|
487
|
+
<br>
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## ๐ License
|
|
492
|
+
|
|
493
|
+
MIT ยฉ Pydrud Contributors. See [LICENSE](LICENSE) for details.
|
|
494
|
+
|
|
495
|
+
<br>
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
<p align="center">
|
|
500
|
+
<strong>Pydrud</strong> โ <em>Pythonic. Native. Simple.</em><br>
|
|
501
|
+
Built with โค๏ธ for Python developers who love native mobile.
|
|
502
|
+
</p>
|