Skip to main content

dynamic_ui_engine 1.0.0 copy "dynamic_ui_engine: ^1.0.0" to clipboard
dynamic_ui_engine: ^1.0.0 copied to clipboard

A JSON-driven dynamic UI engine for Flutter that enables server-driven UI, navigation, and API workflows at runtime.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:dynamic_ui_engine/dynamic_ui_engine.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dynamic UI Engine Example',
      theme: ThemeData(useMaterial3: true),
      initialRoute: '/',
      routes: {
        '/': (context) => const DynamicUiScreen(),
        '/home': (context) => const Scaffold(
          body: Center(child: Text('Home screen')),
        ),
        '/profile': (context) {
          final args = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?;
          final userId = args?['userId'] ?? '?';
          return Scaffold(
            body: Center(child: Text('Profile – userId: $userId')),
          );
        },
      },
    );
  }
}

/// Sample JSON: column with text (with binding) and button (sequential api_call + navigate).
const sampleJson = '''
{
  "schemaVersion": "1.0",
  "ui": {
    "type": "column",
    "children": [
      {
        "type": "text",
        "data": {
          "value": "Welcome {{user.name}}",
          "style": { "fontSize": 18, "color": "#333333" }
        }
      },
      {
        "type": "button",
        "data": {
          "label": "Load user then go Home",
          "onClick": {
            "type": "action_group",
            "execution": "sequential",
            "actions": [
              {
                "type": "api_call",
                "url": "/user",
                "bindTo": "user"
              },
              {
                "type": "navigate",
                "route": "/home"
              }
            ]
          }
        }
      },
      {
        "type": "button",
        "data": {
          "label": "Go to Profile (userId: 42)",
          "onClick": {
            "type": "navigate",
            "route": "/profile",
            "arguments": { "userId": 42 }
          }
        }
      }
    ]
  }
}
''';

class DynamicUiScreen extends StatefulWidget {
  const DynamicUiScreen({super.key});

  @override
  State<DynamicUiScreen> createState() => _DynamicUiScreenState();
}

class _DynamicUiScreenState extends State<DynamicUiScreen> {
  Map<String, dynamic> bindingContext = {};

  void _updateBindingContext(Map<String, dynamic> updates) {
    setState(() {
      for (final e in updates.entries) {
        bindingContext[e.key] = e.value;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    final actionHandler = _ExampleActionHandler(
      context: context,
      onStateUpdate: _updateBindingContext,
    );

    final widget = DynamicWidgetBuilder.buildFromString(
      sampleJson,
      actionHandler: actionHandler,
      bindingContext: bindingContext.isEmpty ? null : bindingContext,
    );

    return Scaffold(
      appBar: AppBar(title: const Text('Dynamic UI Engine')),
      body: SafeArea(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: widget,
        ),
      ),
    );
  }
}

class _ExampleActionHandler implements ActionHandler {
  _ExampleActionHandler({
    required this.context,
    required this.onStateUpdate,
  });

  final BuildContext context;
  final void Function(Map<String, dynamic> updates) onStateUpdate;

  @override
  Future<void> handle(DynamicAction action) async {
    switch (action.type) {
      case ActionType.navigate:
        final route = action.route ?? '/';
        final args = action.arguments;
        if (context.mounted) {
          Navigator.of(context).pushNamed(route, arguments: args);
        }
        break;

      case ActionType.apiCall:
        // Mock API: simulate fetching user and bind to state
        await Future.delayed(const Duration(milliseconds: 300));
        final bindTo = action.bindTo;
        if (bindTo != null) {
          onStateUpdate({
            bindTo: {'name': 'Alice', 'id': 1},
          });
        }
        break;

      case ActionType.actionGroup:
        // Handled by ActionEngine; handler receives only single actions
        break;
    }
  }
}
0
likes
150
points
35
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

A JSON-driven dynamic UI engine for Flutter that enables server-driven UI, navigation, and API workflows at runtime.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on dynamic_ui_engine