sdui 0.1.188 sdui: ^0.1.188 copied to clipboard
SDUI make it easy to implement Server Driven UI pattern on flutter.
SDUI #
SDUI make it easy to implement Server Driven UI pattern on flutter.
- The server decides what to render by describing in a JSON the widgets to render.
- The Flutter screen parse the JSON and build the widgets
Kind like HTML... but not really.
Example #
The Server #
Here is an example of JSON returned by the URL POST http://myapp.herokuapp.com/screens/profile
:
{
"type": "Screen",
"appBar": {
"type": "AppBar",
"attributes": {
"title": "Profile"
}
},
"child": {
"type": "Form",
"attributes": {
"padding": 10
},
"children": [
{
"type": "Input",
"attributes": {
"name": "first_name",
"value": "Ray",
"caption": "First Name",
"maxLength": 30
}
},
{
"type": "Input",
"attributes": {
"name": "last_name",
"value": "Sponsible",
"caption": "Last Name",
"maxLength": 30
}
},
{
"type": "Input",
"attributes": {
"name": "email",
"value": "ray.sponsible@gmail.com",
"caption": "Email *",
"required": true
}
},
{
"type": "Input",
"attributes": {
"type": "date",
"name": "birth_date",
"caption": "Date of Birth"
}
},
{
"type": "Input",
"attributes": {
"type": "Submit",
"name": "submit",
"caption": "Create Profile"
},
"action": {
"type": "Command",
"url": "https://myapp.herokuapp.com/commands/save-profile",
"prompt": {
"type": "Dialog",
"attributes": {
"type": "confirm",
"title": "Confirmation",
"message": "Are you sure you want to change your profile?"
}
}
}
}
]
}
}
The UI in Flutter #
import 'package:flutter/material.dart';
import 'package:sdui/sdui.dart';
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(title: 'Demo', initialRoute: '/', routes: _routes());
}
Map<String, WidgetBuilder> _routes() =>
{
'/': (context) =>
const DynamicRoute(
provider: HttpRouteContentProvider(
'http://www.myapp.com/screens/profile'))
};
}
Screenshots #
Screen | Date Picker | Alert Dialog |
---|---|---|
Widgets #
In Flutter, UI is composed of a hierarchy of Widgets. A widget is a visual element on a screen.
SDUI described widgets with the following json structure:
{
"type": "...",
"attributes": {
"padding": 12,
"color": "#ff0000",
...
},
"children": [
...
]
}
type
: indicates the type of widgetattributes
: key/value pair of the attributes of the widget. Ex:caption
,color
,padding
,spacing
etc.children
: The list of children widgets
Widget Library #
- Navigation widgets
- Layout widgets
- Images/Icons
- Input widgets
- Other
Global Variables #
sduiErrorState
: Function for building the error state.sduiLoadingState
: Function for building the loading state.sduiProgressIndicator
: Function for building the progress indicator.sduiRouteObserver
: Route observer that reload each page on navigation.sduiAnalytics
: Analytics class. See SDUIAnalyticssduiCameras
: List of available cameras. Empty by default, must be initialized the application
Actions #
With actions, you can:
- Execute a command on a server (Ex: Saver User Profile, Delete User Account etc.)
- Navigate to another screen.
- Prompt a message to user.
SDUI described actions with the following json structure:
{
"type": "...",
"attributes": {
...
},
...
"action": {
"type": "...",
"url": "...",
"prompt": {
"type": "...",
"title": "Confirmation",
"message": "Are you sure you want to change your profile?"
}
}
}
type
: Defines the type of action:Route
: To redirect to another routePage
: To redirect to another page, in the context of [PageView]Command
: Remote action to execute. The screen is associated with a URL that will execute the command, and redirect the user to the next screenShare
: Share a message to user via email/messenger/whatsapp etc.Navigate
: Navigate user to a web page
url
: is the URL associated with the actionroute:/..
: redirect users to previous routeroute:/~
: redirect users to 1st route- URL starting with
route:/<ROUTE_NAME>
redirect user the a named route. (Ex:route:/checkout
) - URL starting with
http://
orhttps
redirect user to a server driven page page:/<PAGE_NUMBER>
: redirect users to a given page.<PAGE_NUMBER>
is the page index (starting with0
).
replacement
: Fortype=Route
, this indicate if we replace the current view or navigate.parameters
: Parameters to add to the URL where to redirect tomessage
: Message to shareprompt
: Shows a Dialog before execute the actiontype
: The type of prompt (Exemple:Confirm
,Error
,Warning
,Information
)title
: Title of the alert box to openmessage
: Message to display to the user
Build your own Widget #
You can integrate your own widget into sdui
.
Step 1: Create your instance of SDUIWidget
#
This is an example of widget that render a text with a margin and padding. The widget has the following attributes
text
: The text to displaypadding
: The padding valuemargin
: The margin value
class MyWidget extends SDUIWidget {
String text = '';
double padding = 10.0;
double margin = 10.0;
/// This method will be called by [SDUIParser] to read the widget attributes from the JSON data
@override
SDUIWidget fromJson(Map<String, dynamic>? json) {
text = json?['caption'] ?? '';
margin = json?['margin'] ?? 10.0;
padding = json?['padding'] ?? 10.0;
return this;
}
/// This method will be called when rendering the page to create the Flutter widget
@override
Widget toWidget(BuildContext context) =>
Container(
padding: EdgeInsets.all(padding),
margin: EdgeInsets.all(margin),
child: Text(
text,
style:
const TextStyle(fontWeight: FontWeight.bold, color: Colors.red),
),
);
}
Step 2: Register the widget #
The Widget is registered into SDUI and associated with the type MyWidget
void main() async {
// Register 3rd party widget
SDUIWidgetRegistry.getInstance().register('MyWidget', () => MyWidget());
runApp(constMyApp());
}
class MyApp extends StatelessWidget {
// ...
}
Step 3: Add the widget into the JSONs #
Here is an example of JSON with our 3rd party widget
{
"type": "Screen",
"appBar": {
"type": "AppBar",
"attributes": {
"title": "Home"
}
},
"child": {
"type": "Center",
"children": [
{
"type": "MyWidget",
"attributes": {
"caption": "3rd Party Widget",
"padding": 5.0,
"margin": 5.0
}
}
]
}
}