pilot_ui 0.0.11
pilot_ui: ^0.0.11 copied to clipboard
A dynamic, theme-aware JSON UI rendering engine for Flutter with extensible parsers, action handlers, and ready-to-use smart dispatch & RTS action components.
Pilot UI 🚀 #
A powerful, dynamic, theme-aware JSON UI compilation and rendering engine for Flutter. Build interactive, responsive widget trees directly from JSON schemas or server-driven definitions, complete with state management, expression evaluation, extensible registries, and specialized UI components.
✨ Features #
- 🧱 Server-Driven UI (SDUI): Render complete Flutter widget trees directly from JSON payloads.
- ⚡ Extensible Registry: Register your own custom widget parsers and action handlers seamlessly via
PilotRegistry. - 🔄 Reactive State Management: Built-in state context (
PilotStateContext) and expression evaluator (${state.myValue}) for interactive UI flows. - 🎨 Theme-Aware & Responsive: Dynamic theme resolution (colors, typography, elevation) and responsive props adapting to device screen sizes and breakpoints.
- 📝 Lightweight Markdown Engine: Built-in
PilotMarkdownTextsupporting bold (**), italic (*), inline code (`), bullet lists (-), headers (#), and hyperlinks ([text](url)) without third-party dependencies. - 📦 Rich Widget Parser Suite:
- Layout:
Container,Column,Row,Flex,Stack,ListView,Expanded,Wrap,SafeArea - Display:
Text,Markdown/MarkdownText,Icon,CachedImage,Card,Avatar,Badge,ProgressIndicator,GlassContainer - Inputs & Buttons:
TextField,Checkbox,ElevatedButton,TextButton - Structure & Nav:
AppBar,BottomNavigationBar,FloatingActionButton,PageView,TabView
- Layout:
- 🎯 Action Routing: Declarative action handling for
showDialog,showBottomSheet,setState, and custom event emission (emitEvent). - 🚚 Specialized Dispatch & Fleet Components:
RtsActionCard: Ready-to-use, interactive Return-to-Station request cards featuring animated countdown expiry progress bars, integrated driver contact bar, audio note player, dark mode support, markdown text formatting, expandable/collapsible animation, severity badges, interactive AI Insights callouts, header edit callbacks, and dynamic action buttons.DriverContactBar: Direct dial pad calling interface with driver avatars, phone number formatting, and dark theme support.PilotAudioPlayer: Sleek, seekable audio player for driver voice notes with play/pause controls, slider scrubbing, tabular time formatting, and stream handling.DynamicActionButtons: Configurable action trigger buttons with icon matching, async loading states, dark theme palettes, and customizable colors.
📦 Installation #
Add pilot_ui to your pubspec.yaml dependencies:
dependencies:
flutter:
sdk: flutter
pilot_ui: ^0.0.11
Or run:
flutter pub add pilot_ui
🚀 Quick Start #
1. Basic JSON Widget Rendering #
Use PilotBuilder to compile a JSON UI specification into live Flutter widgets:
import 'package:flutter/material.dart';
import 'package:pilot_ui/pilot_ui.dart';
class DynamicScreen extends StatelessWidget {
const DynamicScreen({super.key});
final Map<String, dynamic> jsonUi = const {
"type": "container",
"children": [
{
"type": "column",
"children": [
{
"type": "text",
"properties": {
"text": "Hello, Pilot UI!",
"style": {
"fontSize": 22.0,
"fontWeight": "bold",
"color": "#7C4DFF"
}
}
},
{
"type": "markdown",
"properties": {
"text": "Render **bold**, *italic*, `code`, and [links](https://flutter.dev) easily!"
}
},
{
"type": "elevated_button",
"properties": {
"label": "Click Me"
},
"actions": {
"onTap": {
"action": "showDialog",
"params": {
"title": "Welcome",
"message": "Rendered dynamically from JSON!"
}
}
}
}
]
}
]
};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Dynamic UI')),
body: PilotBuilder(
json: jsonUi,
initialState: const {
'user': 'Driver #42',
},
onEvent: (eventName, payload) {
debugPrint('Event emitted: $eventName -> $payload');
},
),
);
}
}
📝 Markdown Text: PilotMarkdownText #
Render markdown formatting in Flutter directly or via JSON without needing bulky markdown libraries. Hyperlinks ([label](url)) and raw URLs are automatically clickable and open in the default browser/external application:
import 'package:pilot_ui/pilot_ui.dart';
PilotMarkdownText(
"Driver **Aaron Pouncy** requested *RTS*. Read the [guidelines](https://example.com).",
style: const TextStyle(fontSize: 14, color: Colors.black87),
// Optional custom link tap callback; if omitted, URLs launch automatically
onLinkTap: (url) {
debugPrint('Navigating to: $url');
},
)
JSON definition:
{
"type": "markdown",
"properties": {
"text": "### Notice\n- **Driver ID**: #42\n- **Status**: *En Route*\n- Visit [Support Portal](https://support.fleetglide.io)",
"style": {
"fontSize": 14.0,
"color": "#1E293B"
}
}
}
📞 Driver Contact Bar: DriverContactBar #
Quickly connect dispatchers to drivers with phone number normalization and one-tap dialer launch:
import 'package:pilot_ui/pilot_ui.dart';
DriverContactBar(
driverName: "Abas Ali",
driverPhone: "+1 (555) 234-5678",
isDarkMode: false,
onCall: () {
debugPrint('Initiating call to driver');
},
)
🎵 Voice Note & Audio Player: PilotAudioPlayer #
Play voice notes and driver audio clips with seek scrubbing and streaming status:
import 'package:pilot_ui/pilot_ui.dart';
PilotAudioPlayer(
audioUrl: "https://example.com/audio/driver_note.mp3",
title: "Driver Voice Note",
autoPlay: false,
)
🚚 Specialized Components: RtsActionCard #
pilot_ui includes high-fidelity operational components for logistics and dispatch feeds with countdown expiry timers, driver contact bars, audio note players, markdown formatting, AI Insights callouts, and dark theme support:
import 'package:flutter/material.dart';
import 'package:pilot_ui/pilot_ui.dart';
Widget buildEventCard(Map<String, dynamic> eventJson, BuildContext context) {
return RtsActionCard(
data: eventJson,
initiallyExpanded: false, // Collapsed by default; tap to expand
isDarkMode: Theme.of(context).brightness == Brightness.dark, // Optional manual dark mode override
showEdit: true,
onEdit: () => debugPrint('Edit card tapped'),
onCallDriver: () => debugPrint('Driver call triggered'),
onLinkTap: (url) => debugPrint('Tapped link in card: $url'),
onButtonTap: (action) {
debugPrint('Triggered: ${action?.actionType} with payload: ${action?.actionPayload}');
},
);
}
You can also render RtsActionCard dynamically inside your JSON definitions:
// Register specialized components before building
PilotComponents.registerAll();
{
"type": "rts_action_card",
"title": "**Driver RTS Request** - 50 Undeliverables",
"severity": "warning",
"status": "pending",
"description": "Driver **Aaron** requested early return to station. Reason: `Heavy Traffic`.",
"ai_diagnosis": "High volume of remaining packages. Recommend review.",
"audio_url": "https://example.com/audio/voice_note.mp3",
"expires_at": "2026-09-22T14:45:00Z",
"expires_in_seconds": 900,
"ui_schema": {
"data": {
"driver_name": "Aaron Pouncy",
"driver_phone": "+1 (555) 019-2834"
}
},
"actions": [
{
"action_type": "APPROVE_RTS",
"action_label": "⚡ Approve Return to Station",
"action_payload": {"status": "approved"}
},
{
"action_type": "REJECT_RTS",
"action_label": "❌ Reject Return",
"action_payload": {"status": "rejected"}
}
]
}
🛠️ Extending Pilot UI #
Registering Custom Widget Parsers #
Implement BaseWidgetParser and register it with PilotRegistry:
import 'package:flutter/material.dart';
import 'package:pilot_ui/pilot_ui.dart';
class CustomHeaderParser extends BaseWidgetParser {
@override
Widget parse(JsonWidgetData data, BuildContext context) {
final title = data.props['title'] ?? '';
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.deepPurple.shade50,
borderRadius: BorderRadius.circular(8),
),
child: Text(
title,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
);
}
}
// In your app initialization:
PilotRegistry.registerWidget('custom_header', CustomHeaderParser());
Registering Custom Action Handlers #
Implement BaseActionHandler and register it with PilotRegistry:
import 'package:flutter/material.dart';
import 'package:pilot_ui/pilot_ui.dart';
class AnalyticsActionHandler extends BaseActionHandler {
@override
void handle(ActionModel action, BuildContext context) {
final eventName = action.params['event_name'];
debugPrint('Analytics tracked: $eventName');
}
}
// In your app initialization:
PilotRegistry.registerAction('trackAnalytics', AnalyticsActionHandler());
📂 Example App #
An interactive dashboard example is available in the example/ directory.
To run the example:
cd example
flutter run
📄 License #
This project is licensed under the MIT License.