flutter_duit 4.1.0
flutter_duit: ^4.1.0 copied to clipboard
Server driver UI framework for Flutter. Allows you to update your cool UI without updating the app!
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:example/src/custom/index.dart';
import 'package:flutter/material.dart';
import 'package:flutter_duit/flutter_duit.dart';
class CustomDecoder extends Converter<Uint8List, Map<String, dynamic>> {
@override
Map<String, dynamic> convert(Uint8List input) {
return jsonDecode(utf8.decode(input));
}
}
final class _Handler implements ExternalEventHandler {
const _Handler();
@override
FutureOr<void> handleCustomEvent(
BuildContext context, String key, Object? extra) {
switch (key) {
case "event1":
{
debugPrint("Event 1");
break;
}
case "event2":
{
debugPrint("Event 2");
break;
}
}
}
@override
FutureOr<void> handleNavigation(
BuildContext context,
String path,
Object? extra,
) {
// TODO: implement handleNavigation
throw UnimplementedError();
}
@override
FutureOr<void> handleOpenUrl(String url) {
// TODO: implement handleOpenUrl
throw UnimplementedError();
}
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// final dio = Dio();
// DuitRegistry.configure(
// logger: DefaultLogger.instance,
// themeLoader: HttpThemeLoader(
// dio,
// "http://localhost:8999/theme",
// ),
// );
// await DuitRegistry.initTheme();
DuitRegistry.register(
exampleCustomWidget,
buildFactory: exampleBuildFactory,
);
// final res = await dio.get<List>("http://localhost:8999/components");
// final comps = res.data!.cast<Map<String, dynamic>>();
// await DuitRegistry.registerComponents(comps);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Duit Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late final DuitDriver driver1;
late final FocusNode f1, f2, f3, f4;
@override
void initState() {
f1 = FocusNode();
f2 = FocusNode();
f3 = FocusNode();
f4 = FocusNode();
driver1 = DuitDriver.static(
{
"type": "Row",
"id": "row",
"attributes": {
"mainAxisAlignment": MainAxisAlignment.spaceBetween,
},
"children": [
{
"type": "Expanded",
"id": "ex",
"child": {
"type": "Column",
"id": "1",
"children": [
{
"type": "Text",
"id": "txt1",
"attributes": {"data": "Input 1"}
},
{
"type": "TextField",
"id": "tf1",
"attributes": {
"focusNode": {
"debugLabel": "tf1_label",
},
"inputDecoration": const InputDecoration(
focusColor: Colors.red,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green,
),
),
filled: true,
),
}
},
{
"type": "Text",
"id": "txt2",
"attributes": {"data": "Input 2"}
},
{
"type": "TextField",
"id": "tf2",
"attributes": const {
"focusNode": {
"debugLabel": "tf2_label",
},
"inputDecoration": InputDecoration(
focusColor: Colors.red,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green,
),
),
filled: true,
),
}
},
],
}
},
{
"type": "Expanded",
"id": "ex",
"child": {
"type": "Column",
"id": "1",
"children": [
{
"type": "Text",
"id": "txt1",
"attributes": {"data": "Input 3"}
},
{
"type": "TextField",
"id": "tf3",
"attributes": {
"focusNode": {
"debugLabel": "tf3_label",
},
"inputDecoration": const InputDecoration(
focusColor: Colors.red,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green,
),
),
filled: true,
),
}
},
{
"type": "Text",
"id": "txt2",
"attributes": {"data": "Input 4"}
},
{
"type": "TextField",
"id": "tf4",
"attributes": const {
"focusNode": {
"debugLabel": "tf4_label",
},
"inputDecoration": InputDecoration(
focusColor: Colors.red,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green,
),
),
filled: true,
),
}
},
],
}
}
]
},
transportOptions: EmptyTransportOptions(),
externalEventHandler: const _Handler(),
);
super.initState();
}
@override
void dispose() {
driver1.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
FocusScope(
child: DuitViewHost(
driver: driver1,
),
),
// FocusScope(
// child: Row(
// children: [
// Expanded(
// child: Column(
// children: [
// TextField(
// focusNode: f1,
// ),
// TextField(
// focusNode: f2,
// ),
// ],
// ),
// ),
// Expanded(
// child: Column(
// children: [
// TextField(
// focusNode: f3,
// ),
// TextField(
// focusNode: f4,
// ),
// ],
// ),
// )
// ],
// ),
// ),
TextButton(
onPressed: () {
driver1.requestFocus("tf1");
},
child: const Text("Focus 1"),
),
TextButton(
onPressed: () {
driver1.requestFocus("tf2");
},
child: const Text("Focus 2"),
),
TextButton(
onPressed: () {
debugPrint(
'PRIMARY BEFORE = ${FocusManager.instance.primaryFocus?.debugLabel}');
driver1.nextFocus("tf1");
debugPrint(
'PRIMARY AFTER = ${FocusManager.instance.primaryFocus?.debugLabel}');
},
child: const Text("Next"),
),
TextButton(
onPressed: () {
// f1.previousFocus();
driver1.previousFocus("tf1");
},
child: const Text("Prev"),
),
TextButton(
onPressed: () {
driver1.unfocus("tf1");
},
child: const Text("Unfocus"),
),
TextButton(
onPressed: () {
driver1.addExternalEventStream(Stream.value({
"type": "command",
"controllerId": "tf1",
"commandData": <String, dynamic>{
"type": "focusNode",
"action": "requestFocus",
},
}));
},
child: const Text("Command req focus node 1"),
),
TextButton(
onPressed: () {
driver1.addExternalEventStream(Stream.value({
"type": "command",
"controllerId": "tf1",
"commandData": <String, dynamic>{
"type": "focusNode",
"action": "unfocus",
},
}));
},
child: const Text("Command unfocus"),
),
TextButton(
onPressed: () {
driver1.addExternalEventStream(Stream.value({
"type": "command",
"controllerId": "tf1",
"commandData": <String, dynamic>{
"type": "focusNode",
"action": "nextFocus",
},
}));
},
child: const Text("Command nextFocus"),
),
TextButton(
onPressed: () {
driver1.addExternalEventStream(Stream.value({
"type": "command",
"controllerId": "tf1",
"commandData": <String, dynamic>{
"type": "focusNode",
"action": "previousFocus",
},
}));
},
child: const Text("Command prefFocus"),
),
TextButton(
onPressed: () {
driver1.addExternalEventStream(Stream.value({
"type": "command",
"controllerId": "tf4",
"commandData": <String, dynamic>{
"type": "focusNode",
"action": "focusInDirection",
"direaction": "left",
},
}));
},
child: const Text("Command focus left for node 4"),
),
TextButton(
onPressed: () {
driver1.addExternalEventStream(Stream.value({
"type": "command",
"controllerId": "tf3",
"commandData": <String, dynamic>{
"type": "focusNode",
"action": "requestFocus",
},
}));
},
child: const Text("Command requestFocus node 3"),
),
],
),
),
);
}
}