diff --git a/analysis_options.yaml b/analysis_options.yaml index 0d29021..64fc40d 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,28 +1 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options +# This file configures the analyzer, which statically analyzes Dart code to # check for errors, warnings, and lints. # # The issues identified by the analyzer are surfaced in the UI of Dart-enabled # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be # invoked from the command line by running `flutter analyze`. # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` # included above or to enable additional rules. A list of all available lints # and their documentation is published at https://dart.dev/lints. # # Instead of disabling a lint rule for the entire project in the # section below, it can also be suppressed for a single line of code # or a specific dart file by using the `// ignore: name_of_lint` and # `// ignore_for_file: name_of_lint` syntax on the line or in the file # producing the lint. rules: # avoid_print: false # Uncomment to disable the `avoid_print` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties index f018a61..bfd5523 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1 @@ -org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError -android.useAndroidX=true -android.enableJetifier=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 6dcc88d..d6dd6df 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.10.2-all.zip +distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.10.2-all.zip \ No newline at end of file diff --git a/forui.yaml b/forui.yaml deleted file mode 100644 index 12cc8d1..0000000 --- a/forui.yaml +++ /dev/null @@ -1,9 +0,0 @@ -cli: - # The default file or directory to output generated snippets. - snippet-output: lib - - # The default file or directory to output generated widget styles. - style-output: lib/theme - - # The default file or directory to output generated themes. - theme-output: lib/theme/theme.dart diff --git a/lib/main.dart b/lib/main.dart index 3de3482..a7feff8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,8 +3,10 @@ import 'package:food_hub_app/profile.dart'; import 'package:food_hub_app/record.dart'; import 'package:food_hub_app/views/login.dart'; import 'package:food_hub_app/views/recordForm.dart'; +import 'package:form_builder_validators/form_builder_validators.dart'; void main() { + FormBuilderLocalizations.delegate.load(const Locale('zh', 'CN')); runApp(const MyApp()); } @@ -17,6 +19,7 @@ class MyApp extends StatelessWidget { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(fontFamily: 'CustomFont', primaryColor: Colors.green), + locale: const Locale('zh', 'CN'), home: LoginPage(), routes: { '/home': (context) => MainPage(), diff --git a/lib/profile.dart b/lib/profile.dart index 6e925e3..c801faf 100644 --- a/lib/profile.dart +++ b/lib/profile.dart @@ -1,15 +1,126 @@ import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:form_builder_validators/form_builder_validators.dart'; +import 'package:intl/intl.dart'; -class ProfilePage extends StatefulWidget{ +class ProfilePage extends StatefulWidget { const ProfilePage({super.key}); @override State createState() => _ProfilePage(); } -class _ProfilePage extends State{ +// class _ProfilePage extends State{ +// @override +// Widget build(BuildContext context) { +// return const Center(child: Text("个人主页")); +// } +// } + +class _ProfilePage extends State { + final _formKey = GlobalKey(); + bool autoValidate = true; + bool readOnly = false; + bool showSegmentedControl = true; + final _genderOptions = ['Male', 'Female', 'Other']; + @override Widget build(BuildContext context) { - return const Center(child: Text("个人主页")); + return Padding( + padding: const EdgeInsets.all(16.0), + child: SingleChildScrollView( + child: Column( + children: [ + FormBuilder( + key: _formKey, + // enabled: false, + autovalidateMode: AutovalidateMode.onUserInteraction, + initialValue: {'date': DateTime.now(), 'accept_terms': false}, + skipDisabled: true, + child: Column( + children: [ + const SizedBox(height: 15), + FormBuilderTextField( + name: 'name', + decoration: InputDecoration( + labelText: '姓名', + hintText: '请输入姓名', + filled: true, + fillColor: Colors.white, + floatingLabelBehavior: FloatingLabelBehavior.always, + // 始终显示标签 + border: OutlineInputBorder(), + ), + // onChanged: (val) => print(val), + validator: FormBuilderValidators.compose([ + FormBuilderValidators.required(), + FormBuilderValidators.minLength(3), + FormBuilderValidators.maxLength(70), + ]), + keyboardType: TextInputType.name, + ), + const SizedBox(height: 15), + FormBuilderDateTimePicker( + name: 'date', + decoration: InputDecoration( + labelText: '时间', + hintText: '请选择时间', + filled: true, + fillColor: Colors.white, + border: OutlineInputBorder(), + ), + inputType: InputType.both, + initialDate: DateTime.now(), + firstDate: DateTime(1900), + lastDate: DateTime(2100), + format: DateFormat('yyyy-MM-dd HH:mm:ss'), + // enabled: _formKey.currentState?.fields['date']?.enabled ?? true, + ), + ], + ), + ), + const SizedBox(height: 20), + Row( + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + if (_formKey.currentState?.saveAndValidate() ?? false) { + print(_formKey.currentState?.value); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Processing Data')), + ); + } else { + print(_formKey.currentState?.value); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Validation failed')), + ); + } + }, + child: const Text( + 'Submit', + style: TextStyle(color: Colors.green), + ), + ), + ), + const SizedBox(width: 20), + Expanded( + child: OutlinedButton( + onPressed: () { + _formKey.currentState?.reset(); + }, + // color: Colors.red, + child: const Text( + 'Reset', + style: TextStyle(color: Colors.red), + ), + ), + ), + ], + ), + ], + ), + ), + ); } -} \ No newline at end of file +} diff --git a/lib/views/login.dart b/lib/views/login.dart index 652838c..49a566c 100644 --- a/lib/views/login.dart +++ b/lib/views/login.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:form_builder_validators/form_builder_validators.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); @@ -21,7 +23,7 @@ class _LoginPage extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, + backgroundColor: Colors.grey[100], body: Form( key: _formKey, autovalidateMode: AutovalidateMode.onUserInteraction, @@ -84,40 +86,36 @@ class _LoginPage extends State { } Widget buildUsernameTextField() { - return TextFormField( + return FormBuilderTextField( + name: 'username', decoration: InputDecoration( labelText: '账号', prefixIcon: Icon(Icons.person), hintText: "请输入账号", border: OutlineInputBorder(), + floatingLabelBehavior: FloatingLabelBehavior.always, filled: true, - fillColor: Colors.grey[100], + fillColor: Colors.white, ), - validator: (v) { - if (v!.isEmpty) { - return '请输入账号'; - } - }, + validator: FormBuilderValidators.required(), onSaved: (v) => _username = v!, ); } Widget buildPasswordTextField(BuildContext context) { - return TextFormField( + return FormBuilderTextField( + name: 'password', obscureText: _isObscure, // 是否显示文字 onSaved: (v) => _password = v!, - validator: (v) { - if (v!.isEmpty) { - return '请输入密码'; - } - }, + validator: FormBuilderValidators.required(), decoration: InputDecoration( labelText: "密码", prefixIcon: Icon(Icons.lock), hintText: "请输入密码", border: OutlineInputBorder(), filled: true, - fillColor: Colors.grey[100], + fillColor: Colors.white, + floatingLabelBehavior: FloatingLabelBehavior.always, suffixIcon: IconButton( icon: Icon(Icons.remove_red_eye, color: _eyeColor), onPressed: () { diff --git a/pubspec.lock b/pubspec.lock index ffe9fa5..92a4e98 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -86,6 +86,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" + flutter_form_builder: + dependency: "direct main" + description: + name: flutter_form_builder + sha256: aa3901466c70b69ae6c7f3d03fcbccaec5fde179d3fded0b10203144b546ad28 + url: "https://pub.flutter-io.cn" + source: hosted + version: "10.0.1" flutter_lints: dependency: "direct dev" description: @@ -104,8 +112,16 @@ packages: description: flutter source: sdk version: "0.0.0" + form_builder_validators: + dependency: "direct main" + description: + name: form_builder_validators + sha256: cd617fa346250293ff3e2709961d0faf7b80e6e4f0ff7b500126b28d7422dd67 + url: "https://pub.flutter-io.cn" + source: hosted + version: "11.1.2" intl: - dependency: transitive + dependency: "direct main" description: name: intl sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf @@ -271,4 +287,4 @@ packages: version: "14.3.1" sdks: dart: ">=3.7.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index dfd6fc1..a491646 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,9 @@ dependencies: custom_sliding_segmented_control: ^1.8.5 flutter_datetime_picker_plus: ^2.2.0 flutter_date_pickers: ^0.4.3 + flutter_form_builder: ^10.0.0 + form_builder_validators: ^11.1.2 + intl: ^0.19.0 dev_dependencies: flutter_test: