junny_form 0.0.4+2
junny_form: ^0.0.4+2 copied to clipboard
A flexible Flutter form management library that supports centralized field management, async validation, and custom field types.
example/lib/main.dart
import 'dart:math';
import 'package:example/address/address_utils.dart';
import 'package:example/pages/dict_enum_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:junny_form/junny_form.dart';
import 'pages/home_page.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
JunnyFormGlobalConfig.instance.init(
getDictByEnum: (enumValue, _) => [
{
'dataCode': '01',
'dataName': '1%',
},
{
'dataCode': '02',
'dataName': '3%',
},
{
'dataCode': '03',
'dataName': '5%',
},
],
attachmentsFormatter: (attachments) {
return attachments?.isNotEmpty ?? false
? '${attachments?.splitIterable<int>().nonNulls.length ?? 0} 个附件'
: null;
},
getAttachmentsData: (attachment, cancelToken) async {
final attachmentIds = attachment.splitIterable<int>();
if (attachmentIds.isEmpty) {
return [];
} else {
// 做一个模拟数据
return List.generate(
attachmentIds.length,
(index) => {
'id': attachmentIds.elementAt(index),
'name': '附件${attachmentIds.elementAt(index)}',
},
);
}
},
selectAttachments: (BuildContext context, AttachmentTapParams params) async {
// 模拟选择, 结合maxCount 返回结果
// 如果maxCount 为 3,则返回 3 个附件
final int maxCount = params.maxCount;
final bool enabled = params.enabled;
final List<Map<String, dynamic>> attachments = params.attachments;
if (!enabled) {
if (attachments.isNotEmpty) {
// toast提示
JunnyToastUtils.instance.show('附件不可编辑, 但可以预览');
}
return attachments;
}
final List<Map<String, dynamic>> result = [
{'id': 1, 'name': '附件1'},
{'id': 2, 'name': '附件2'},
{'id': 3, 'name': '附件3'},
{'id': 4, 'name': '附件4'},
{'id': 5, 'name': '附件5'},
{'id': 6, 'name': '附件6'},
{'id': 7, 'name': '附件7'},
{'id': 8, 'name': '附件8'},
{'id': 9, 'name': '附件9'},
{'id': 10, 'name': '附件10'},
{'id': 11, 'name': '附件11'},
{'id': 12, 'name': '附件12'},
{'id': 13, 'name': '附件13'},
{'id': 14, 'name': '附件14'},
{'id': 15, 'name': '附件15'},
];
// 修复:确保随机选择的起始位置加上 maxCount 不会超出数组长度
final int startIndex = Random().nextInt(result.length - maxCount + 1);
// 选择不超过 maxCount 个附件
return result.sublist(
startIndex,
startIndex + Random().nextInt(maxCount),
);
},
isTaxRateEnum: (enumValue) => enumValue == ExampleEnum.taxRate,
);
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late AddressUtils _addressUtils;
@override
void initState() {
super.initState();
init();
}
Future<void> init() async {
_addressUtils = await AddressUtils.create();
// 组件库初始化全局配置
JunnyGlobalWidgetConfig.instance.initialize(
addressChildrenDataQuery: ([int? parentId]) => _addressUtils
.getChildrenAddresses(parentId ?? 0)
.map((e) => e.toJson())
.toList(),
addressDataInitializer: () async {
// 如果没有初始化地址数据
if (_addressUtils.count() <= 0) {
return _addressUtils.initAddressData();
}
},
addressDataQuery: (int id) => _addressUtils.getAddress(id)?.toJson(),
addressDataConverter: (String data) => _addressUtils.getAddressData(data),
// emptyIconBuilder: (BuildContext context) =>
// JunnyKitAssets.images.common.noData.image(width: 50, height: 50),
// emptyTextBuilder: (BuildContext context) =>
// 'noData'.withTips.translate(context),
// yearPickerPresenter: ({
// required BuildContext context,
// required Widget Function(ValueSetter<int?>? onYearChanged) picker,
// }) async {
// int? selectedYear;
// void onYearChanged(int? year) {
// selectedYear = year;
// }
// final int? result =
// await JunnyDialogUtils.instance.showCommonDialog<int>(
// contentWidget: picker(onYearChanged),
// title: MaterialLocalizations.of(context).selectYearSemanticsLabel,
// onConfirm: () =>
// JunnyDialogUtils.instance.dismiss<int>(result: selectedYear),
// );
// return result;
// },
);
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blueAccent),
useMaterial3: true,
),
locale: const Locale.fromSubtags(languageCode: 'zh'),
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: const [
Locale('zh', 'CN'),
],
navigatorObservers: <NavigatorObserver>[
FlutterSmartDialog.observer,
],
home: const HomePage(),
builder: FlutterSmartDialog.init(),
);
}
}