Skip to content

Commit f0c383f

Browse files
authored
Merge pull request #4 from TBA5854/dev
feat: added json support and flutter to sdui widget support
2 parents 66b2b93 + 6793dbb commit f0c383f

File tree

9 files changed

+2210
-96
lines changed

9 files changed

+2210
-96
lines changed

ADDING_WIDGET.md

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# Adding a New Widget to the SDUI Package
2+
3+
This guide explains how to add support for a new widget to the Flutter SDUI package, including JSON and proto (gRPC) support. The process ensures your widget can be described by the server, parsed on the client, and rendered as a real Flutter widget.
4+
5+
---
6+
7+
## 1. Create the SDUI Widget Class
8+
9+
- **Where:** `lib/src/widgets/`
10+
- **What:** Create a Dart class (e.g., `SduiMyWidget`) that extends `SduiWidget`.
11+
- **Why:** This class acts as the runtime representation of your widget in the SDUI system. It bridges the data-driven world (JSON/proto) and the actual Flutter widget tree.
12+
- **How:**
13+
- Add all properties your widget needs (e.g., text, color, children).
14+
- Implement the `toFlutterWidget()` method to convert your SDUI widget to a real Flutter widget.
15+
- If your widget has children, make sure to recursively call `toFlutterWidget()` on them.
16+
17+
**Example:**
18+
```dart
19+
import 'package:flutter/widgets.dart';
20+
import 'sdui_widget.dart';
21+
22+
class SduiMyWidget extends SduiWidget {
23+
final String title;
24+
final Color? color;
25+
final List<SduiWidget> children;
26+
// Add other properties as needed
27+
28+
SduiMyWidget({
29+
required this.title,
30+
this.color,
31+
this.children = const [],
32+
});
33+
34+
@override
35+
Widget toFlutterWidget() {
36+
return MyWidget(
37+
title: title,
38+
color: color,
39+
children: children.map((c) => c.toFlutterWidget()).toList(),
40+
);
41+
}
42+
}
43+
```
44+
*Tip: Look at existing SDUI widgets for structure and naming conventions. Try to keep your API as close as possible to the real Flutter widget for familiarity.*
45+
46+
---
47+
48+
## 2. Update the Parser(s)
49+
50+
### a. JSON Parsing
51+
52+
- **Where:** `lib/src/parser/sdui_proto_parser.dart`
53+
- **What:** Add logic to parse your widget from JSON and serialize it back.
54+
- **Why:** This allows the SDUI system to construct your widget from server-provided JSON, and to serialize it back for debugging or round-tripping.
55+
- **How:**
56+
- Add a case for your widget in the `parseJSON` method (e.g., `case 'my_widget': return _parseJsonMyWidget(data);`).
57+
- Implement a `_parseJsonMyWidget(Map<String, dynamic> data)` method to extract all properties from the JSON map and construct your SDUI widget.
58+
- Update the `toJson` and `_toJsonMyWidget` methods to support serialization (convert your SDUI widget back to a JSON map).
59+
- If your widget has enums or complex types, add helper methods for parsing/serializing them.
60+
61+
**Example:**
62+
```dart
63+
static SduiMyWidget _parseJsonMyWidget(Map<String, dynamic> data) {
64+
return SduiMyWidget(
65+
title: data['title'] ?? '',
66+
color: _parseJsonColor(data['color']),
67+
children: (data['children'] as List<dynamic>? ?? [])
68+
.map((child) => parseJSON(child as Map<String, dynamic>))
69+
.toList(),
70+
);
71+
}
72+
```
73+
74+
### b. Proto Parsing
75+
76+
- **Where:** `lib/src/parser/sdui_proto_parser.dart`
77+
- **What:** Add logic to parse your widget from proto and serialize it back.
78+
- **Why:** This allows the SDUI system to construct your widget from gRPC/proto data, and to serialize it back for server communication or round-tripping.
79+
- **How:**
80+
- Add a case for your widget in the `parseProto` and `fromProto` methods.
81+
- Implement `_parseProtoMyWidget(SduiWidgetData data)` and `myWidgetFromProto` to extract all properties from the proto message and construct your SDUI widget.
82+
- Add `myWidgetToProto` for proto serialization (convert your SDUI widget to a proto message).
83+
- Use helper methods for enums, colors, and nested children as needed.
84+
85+
**Example:**
86+
```dart
87+
static SduiMyWidget myWidgetFromProto(SduiWidgetData data) {
88+
return SduiMyWidget(
89+
title: data.stringAttributes['title'] ?? '',
90+
color: data.hasColor() ? _parseProtoColor(data.color) : null,
91+
children: data.children.map((c) => SduiParser.parseProto(c)).toList(),
92+
);
93+
}
94+
```
95+
96+
*Tip: Use the helpers and patterns from other widgets to handle enums, colors, and nested children. Consistency makes the codebase easier to maintain.*
97+
98+
---
99+
100+
## 3. Update the Widget Type Enum
101+
102+
- **Where:** `sdui.proto` (your proto definitions)
103+
- **What:** Add your widget to the `WidgetType` enum.
104+
- **Why:** This allows the server and client to communicate about your new widget type in a type-safe way.
105+
- **How:**
106+
- Add a new value (e.g., `MY_WIDGET`) to the `WidgetType` enum in your proto file.
107+
- Regenerate Dart code from your proto files (see README for instructions, usually a script in `tool/`).
108+
109+
**Example:**
110+
```protobuf
111+
enum WidgetType {
112+
// ... existing types ...
113+
MY_WIDGET = 42;
114+
}
115+
```
116+
117+
*Tip: Make sure the enum value is unique and does not conflict with existing types.*
118+
119+
---
120+
121+
## 4. Add to Flutter-to-SDUI Converter
122+
123+
- **Where:** `lib/src/parser/flutter_to_sdui.dart`
124+
- **What:** Add a case to convert a real Flutter widget to your SDUI widget.
125+
- **Why:** This enables tools and tests to convert existing Flutter code to SDUI format, and helps with migration or round-trip testing.
126+
- **How:**
127+
- Add an `else if` block for your widget type.
128+
- Map all relevant properties from the Flutter widget to your SDUI widget.
129+
- If your widget is not supported for conversion, throw an `UnimplementedError` with a clear message.
130+
131+
**Example:**
132+
```dart
133+
else if (widget is MyWidget) {
134+
return SduiMyWidget(
135+
title: widget.title,
136+
color: widget.color,
137+
children: widget.children.map(flutterToSdui).toList(),
138+
);
139+
}
140+
```
141+
142+
---
143+
144+
## 5. Test
145+
146+
- **What:** Ensure your widget works end-to-end and is robust.
147+
- **Why:** Testing catches bugs early and ensures your widget behaves as expected in all supported formats.
148+
- **How:**
149+
- Add unit tests for JSON and proto parsing/serialization.
150+
- Add tests for Flutter-to-SDUI conversion.
151+
- Create sample JSON and proto definitions for your widget and verify they render correctly in a demo app or test harness.
152+
- Test edge cases (missing properties, nulls, invalid values).
153+
154+
*Tip: Use the sample files and test cases for existing widgets as a template. Automated tests are preferred, but manual testing in a demo app is also valuable.*
155+
156+
---
157+
158+
## 6. Document
159+
160+
- **What:** Make your widget discoverable and easy to use for others.
161+
- **Why:** Good documentation helps others understand and use your widget, and encourages contributions.
162+
- **How:**
163+
- Update the main `README.md` to mention your new widget and its supported properties.
164+
- Optionally, add usage examples or sample JSON/proto snippets.
165+
- Document any limitations or special behaviors.
166+
167+
---
168+
169+
## Example Checklist
170+
171+
- [ ] Widget class in `lib/src/widgets/`
172+
- [ ] JSON parse/serialize in `sdui_proto_parser.dart`
173+
- [ ] Proto parse/serialize in `sdui_proto_parser.dart`
174+
- [ ] Enum in proto and regenerated Dart code
175+
- [ ] Flutter-to-SDUI conversion
176+
- [ ] Tests and sample data
177+
- [ ] Documentation
178+
179+
---
180+
181+
**Tips & Best Practices:**
182+
- Follow the structure and naming conventions of existing widgets for consistency.
183+
- Keep your widget’s API as close as possible to the real Flutter widget for familiarity.
184+
- Only map properties that are supported by both SDUI and the underlying Flutter widget.
185+
- If your widget has complex properties (e.g., enums, nested objects), add helper methods for parsing/serialization.
186+
- If you’re unsure, look at how similar widgets are implemented in the codebase.
187+
- Use clear error messages for unsupported or unimplemented features.
188+
- Test with both minimal and maximal property sets.
189+
190+
---
191+
192+
If you have questions, check the code for similar widgets or open an issue!

README.md

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,33 @@ SduiGrpcRenderer(
8686

8787
### 2. Using JSON
8888

89-
For simpler implementation with standard HTTP requests (coming soon).
89+
For simpler implementation with standard HTTP requests:
90+
91+
```dart
92+
// Parse SDUI JSON to widget
93+
dynamic json = ...; // Load your JSON
94+
final sduiWidget = SduiParser.parseJSON(json);
95+
final flutterWidget = sduiWidget.toFlutterWidget();
96+
```
97+
98+
You can also serialize SDUI widgets back to JSON:
99+
100+
```dart
101+
final json = SduiParser.toJson(sduiWidget);
102+
```
103+
104+
And convert Flutter widgets to SDUI (for supported types):
105+
106+
```dart
107+
import 'package:flutter_sdui/src/flutter_to_sdui.dart';
108+
final sduiWidget = flutterToSdui(myFlutterWidget);
109+
```
110+
111+
## Widget Coverage & Extensibility
112+
113+
- All core layout and display widgets are supported: `Column`, `Row`, `Text`, `Image`, `SizedBox`, `Container`, `Scaffold`, `Spacer`, `Icon`.
114+
- Adding new widgets is straightforward: implement the SDUI widget, add proto/JSON parsing, and update the toJson and Flutter conversion logic.
115+
- The codebase is up-to-date, with no remaining TODOs.
90116

91117
## Example
92118

@@ -298,13 +324,13 @@ pwsh ./tool/generate_protos.ps1
298324

299325
- [x] Basic widget support
300326
- [x] gRPC implementation
301-
- [ ] JSON implementation
327+
- [x] JSON implementation
302328
- [ ] Interactive widgets (buttons, forms)
303329
- [ ] More advanced widget support
304330

305331
## Contributing
306332

307-
We welcome contributions! Please see our [contributing guidelines](contributing.md) for details.
333+
See [ADDING_WIDGET.md](./ADDING_WIDGET.md) for instructions on how to add a new widget to the SDUI package.
308334

309335
## License
310336

SDUI_Flutter_Integration_Guide.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

example/grpc_server_example_dart.dart

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,6 @@ class SduiServiceImpl extends SduiServiceBase {
4242
SduiWidgetData _createHomeScreen() {
4343
final homeScreen = SduiWidgetData()
4444
..type = WidgetType.SCAFFOLD
45-
..appBar = (SduiWidgetData()
46-
..type = WidgetType.CONTAINER
47-
..boxDecoration = (BoxDecorationData()
48-
..color = (ColorData()
49-
..red = 25
50-
..green = 118
51-
..blue = 210
52-
..alpha = 255))
53-
..padding = (EdgeInsetsData()
54-
..top = 8
55-
..left = 16
56-
..right = 16
57-
..bottom = 8)
58-
..child = (SduiWidgetData()
59-
..type = WidgetType.TEXT
60-
..stringAttributes['text'] = 'Home Screen'
61-
..textStyle = (TextStyleData()
62-
..fontSize = 20
63-
..fontWeight = 'bold'
64-
..color = (ColorData()
65-
..red = 255
66-
..green = 255
67-
..blue = 255
68-
..alpha = 255))))
6945
..body = (SduiWidgetData()
7046
..type = WidgetType.COLUMN
7147
..children.addAll([
@@ -106,7 +82,7 @@ class SduiServiceImpl extends SduiServiceBase {
10682
SduiWidgetData()
10783
..type = WidgetType.ICON
10884
..icon = (IconDataMessage()
109-
..name = 'info'
85+
..name = 'home'
11086
..color = (ColorData()
11187
..red = 25
11288
..green = 118

example/sample_sdui.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"type": "scaffold",
3+
"appBar": {
4+
"type": "container",
5+
"padding": { "all": 16 },
6+
"child": {
7+
"type": "text",
8+
"text": "Sample SDUI App",
9+
"style": { "fontSize": 20, "fontWeight": "bold" }
10+
}
11+
},
12+
"body": {
13+
"type": "column",
14+
"mainAxisAlignment": "center",
15+
"crossAxisAlignment": "center",
16+
"children": [
17+
{
18+
"type": "text",
19+
"text": "Welcome to Server-Driven UI!",
20+
"style": { "fontSize": 22, "fontWeight": "bold" }
21+
},
22+
{
23+
"type": "sized_box",
24+
"height": 24
25+
},
26+
{
27+
"type": "image",
28+
"src": "https://storage.googleapis.com/cms-storage-bucket/c823e53b3a1a7b0d36a9.png",
29+
"width": 120,
30+
"height": 120,
31+
"fit": "contain"
32+
}
33+
]
34+
}
35+
}

0 commit comments

Comments
 (0)