wutsi / sdui

SDUI make it easy to implement Server Driven UI pattern on flutter.
MIT License
94 stars 18 forks source link
dart flutter server-driven-ui

pub package

SDUI

SDUI make it easy to implement Server Driven UI pattern on flutter.

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": [
      ...
    ]
}

Widget Library

Global Variables

Actions

With actions, you can:

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?"
      }
    }

}

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

    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
                }
            }
        ]
    }
}