diff --git a/packages/wyatt_form_bloc/example/.metadata b/packages/wyatt_form_bloc/example/.metadata index 3c3e4b52..75a8145c 100644 --- a/packages/wyatt_form_bloc/example/.metadata +++ b/packages/wyatt_form_bloc/example/.metadata @@ -1,10 +1,30 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled and should not be manually edited. +# This file should be version controlled. version: - revision: 5464c5bac742001448fe4fc0597be939379f88ea + revision: 85684f9300908116a78138ea4c6036c35c9a1236 channel: stable project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 85684f9300908116a78138ea4c6036c35c9a1236 + base_revision: 85684f9300908116a78138ea4c6036c35c9a1236 + - platform: web + create_revision: 85684f9300908116a78138ea4c6036c35c9a1236 + base_revision: 85684f9300908116a78138ea4c6036c35c9a1236 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/wyatt_form_bloc/example/lib/app/app.dart b/packages/wyatt_form_bloc/example/lib/app/app.dart index 60d99e66..cc8691b4 100644 --- a/packages/wyatt_form_bloc/example/lib/app/app.dart +++ b/packages/wyatt_form_bloc/example/lib/app/app.dart @@ -16,31 +16,37 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:form_bloc_example/app/metadata.dart'; import 'package:form_bloc_example/constants.dart'; import 'package:form_bloc_example/cubit/custom_form_cubit.dart'; import 'package:form_bloc_example/sign_up/sign_up_page.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +const blue = Metadata(category: Category.perso); +const red = Metadata(category: Category.business); + class App extends StatelessWidget { const App({Key? key}) : super(key: key); - static List getNormalEntries() { + static List getNormalEntries() { return const [ - FormEntry(formFieldName, Name.pure()), - FormEntry(formFieldEmail, Email.pure()), - FormEntry(formFieldPhone, Phone.pure()), - FormEntry( + FormInput(formFieldName, Name.pure(), metadata: FormInputMetadata(extra: blue)), + FormInput(formFieldEmail, Email.pure(), metadata: FormInputMetadata(extra: blue)), + FormInput(formFieldPhone, Phone.pure(), metadata: FormInputMetadata(extra: red)), + FormInput( formFieldList, ListOption.pure(defaultValue: ['checkbox3'])), - FormEntry(formFieldRadio, TextString.pure()), - FormEntry(formFieldPro, Boolean.pure(), name: 'business'), - FormEntry(formFieldHidden, Boolean.pure(), export: false), + FormInput(formFieldRadio, TextString.pure()), + FormInput(formFieldPro, Boolean.pure(), + metadata: FormInputMetadata(name: 'business')), + FormInput(formFieldHidden, Boolean.pure(), + metadata: FormInputMetadata(export: false, extra: blue)), ]; } - static List getBusinessEntries() { + static List getBusinessEntries() { const entries = [ - FormEntry(formFieldSiren, Siren.pure()), - FormEntry(formFieldIban, Iban.pure()), + FormInput(formFieldSiren, Siren.pure()), + FormInput(formFieldIban, Iban.pure()), ]; return getNormalEntries() + entries; } @@ -55,7 +61,7 @@ class App extends StatelessWidget { @override Widget build(BuildContext context) { - FormDataCubit _formCubit = CustomFormCubit(entries: getNormalFormData()); + FormDataCubit _formCubit = CustomFormCubit(inputs: getNormalFormData()); return BlocProvider( create: (context) => _formCubit, diff --git a/packages/wyatt_form_bloc/example/lib/cubit/custom_form_state.dart b/packages/wyatt_form_bloc/example/lib/app/metadata.dart similarity index 72% rename from packages/wyatt_form_bloc/example/lib/cubit/custom_form_state.dart rename to packages/wyatt_form_bloc/example/lib/app/metadata.dart index f6993044..b4e68725 100644 --- a/packages/wyatt_form_bloc/example/lib/cubit/custom_form_state.dart +++ b/packages/wyatt_form_bloc/example/lib/app/metadata.dart @@ -1,3 +1,4 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // @@ -14,9 +15,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -part of 'custom_form_cubit.dart'; +enum Category { + perso, + business +} -@immutable -abstract class CustomFormState {} +class Metadata { + final Category category; -class CustomFormInitial extends CustomFormState {} + const Metadata({ + required this.category, + }); + + @override + String toString() { + return category.toString(); + } +} diff --git a/packages/wyatt_form_bloc/example/lib/cubit/custom_form_cubit.dart b/packages/wyatt_form_bloc/example/lib/cubit/custom_form_cubit.dart index 6cdae37d..3f211c60 100644 --- a/packages/wyatt_form_bloc/example/lib/cubit/custom_form_cubit.dart +++ b/packages/wyatt_form_bloc/example/lib/cubit/custom_form_cubit.dart @@ -16,18 +16,15 @@ import 'dart:developer'; -import 'package:meta/meta.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; -part 'custom_form_state.dart'; - class CustomFormCubit extends FormDataCubit { - CustomFormCubit({required FormData entries}) : super(entries: entries); + CustomFormCubit({required FormData inputs}) : super(inputs: inputs); @override Future submitForm() { log(state.data.toMap().toString()); - + return Future.value(); } } diff --git a/packages/wyatt_form_bloc/example/lib/sign_up/widgets/sign_up_form.dart b/packages/wyatt_form_bloc/example/lib/sign_up/widgets/sign_up_form.dart index 82d28ed2..6d611a5d 100644 --- a/packages/wyatt_form_bloc/example/lib/sign_up/widgets/sign_up_form.dart +++ b/packages/wyatt_form_bloc/example/lib/sign_up/widgets/sign_up_form.dart @@ -19,35 +19,83 @@ import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:form_bloc_example/app/app.dart'; +import 'package:form_bloc_example/app/metadata.dart'; import 'package:form_bloc_example/constants.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +class CategoryIndicator extends StatelessWidget { + const CategoryIndicator( + {Key? key, required this.field, required this.builder}) + : super(key: key); + + final String field; + final Function(BuildContext context, FormDataState state) builder; + + Color computeColor(Metadata meta) { + switch (meta.category) { + case Category.perso: + return Colors.blue; + case Category.business: + return Colors.red; + } + } + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: ((context, state) { + final meta = state.data.metadataOf(field).extra as Metadata; + final color = computeColor(meta); + + return Row( + children: [ + Container( + height: 8, + width: 8, + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(8), + ), + ), + const SizedBox(width: 20,), + SizedBox( + width: MediaQuery.of(context).size.width - 45, + child: builder(context, state), + ) + ], + ); + }), + ); + } +} + class _NameInput extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - return TextField( - onChanged: (name) => context - .read() - .dataChanged(formFieldName, Name.dirty(name)), - keyboardType: TextInputType.name, - decoration: InputDecoration( - labelText: 'name', - helperText: '', - errorText: - state.data.input(formFieldName).invalid ? 'invalid name' : null, - ), - ); - }, - ); + return CategoryIndicator( + field: formFieldName, + builder: (context, state) { + return TextField( + onChanged: (name) => context + .read() + .dataChanged(formFieldName, Name.dirty(name)), + keyboardType: TextInputType.name, + decoration: InputDecoration( + labelText: 'name', + helperText: '', + errorText: + state.data.isNotValid(formFieldName) ? 'invalid name' : null, + ), + ); + }); } } class _EmailInput extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( + return CategoryIndicator( + field: formFieldEmail, builder: (context, state) { return TextField( onChanged: (email) => context @@ -57,9 +105,8 @@ class _EmailInput extends StatelessWidget { decoration: InputDecoration( labelText: 'email', helperText: '', - errorText: state.data.input(formFieldEmail).invalid - ? 'invalid email' - : null, + errorText: + state.data.isNotValid(formFieldEmail) ? 'invalid email' : null, ), ); }, @@ -70,7 +117,8 @@ class _EmailInput extends StatelessWidget { class _PhoneInput extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( + return CategoryIndicator( + field: formFieldPhone, builder: (context, state) { return TextField( onChanged: (phone) => context @@ -80,9 +128,8 @@ class _PhoneInput extends StatelessWidget { decoration: InputDecoration( labelText: 'phone', helperText: '', - errorText: state.data.input(formFieldPhone).invalid - ? 'invalid phone' - : null, + errorText: + state.data.isNotValid(formFieldPhone) ? 'invalid phone' : null, ), ); }, @@ -93,7 +140,8 @@ class _PhoneInput extends StatelessWidget { class _SirenInput extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( + return CategoryIndicator( + field: formFieldName, builder: (context, state) { return TextField( onChanged: (siren) => context @@ -103,9 +151,8 @@ class _SirenInput extends StatelessWidget { decoration: InputDecoration( labelText: 'siren', helperText: '', - errorText: state.data.input(formFieldSiren).invalid - ? 'invalid SIREN' - : null, + errorText: + state.data.isNotValid(formFieldSiren) ? 'invalid SIREN' : null, ), ); }, @@ -127,7 +174,7 @@ class _IbanInput extends StatelessWidget { labelText: 'iban', helperText: '', errorText: - state.data.input(formFieldIban).invalid ? 'invalid IBAN' : null, + state.data.isNotValid(formFieldIban) ? 'invalid IBAN' : null, ), ); }, @@ -141,7 +188,7 @@ class _CheckListInput extends StatelessWidget { return BlocBuilder( builder: (context, state) { final _input = - state.data.input>(formFieldList) as ListOption; + state.data.validatorOf>(formFieldList); final _options = _input.value; return Column( @@ -192,8 +239,7 @@ class _RadioListInput extends StatelessWidget { Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - final _input = - state.data.input(formFieldRadio) as TextString; + final _input = state.data.validatorOf(formFieldRadio); return Column( mainAxisSize: MainAxisSize.min, @@ -249,7 +295,7 @@ class _CheckHiddenInput extends StatelessWidget { trailing: BlocBuilder( builder: (context, state) { return Checkbox( - value: state.data.input(formFieldHidden).value, + value: state.data.validatorOf(formFieldHidden).value, onChanged: (v) { final value = v!; // state is false, so value can't be null @@ -272,7 +318,7 @@ class _CheckIsProInput extends StatelessWidget { trailing: BlocBuilder( builder: (context, state) { return Checkbox( - value: state.data.input(formFieldPro).value, + value: state.data.validatorOf(formFieldPro).value, onChanged: (isPro) { final value = isPro!; // state is false, so value can't be null @@ -370,7 +416,7 @@ class SignUpForm extends StatelessWidget { const SizedBox(height: 8), BlocBuilder( builder: (context, state) { - if (state.data.input(formFieldPro).value) { + if (state.data.validatorOf(formFieldPro).value) { return Column(children: [ _SirenInput(), const SizedBox(height: 8), diff --git a/packages/wyatt_form_bloc/example/pubspec.yaml b/packages/wyatt_form_bloc/example/pubspec.yaml index b3afe238..7ba2bbf1 100644 --- a/packages/wyatt_form_bloc/example/pubspec.yaml +++ b/packages/wyatt_form_bloc/example/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.16.2 <3.0.0" + sdk: ">=2.17.2 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions diff --git a/packages/wyatt_form_bloc/example/web/favicon.png b/packages/wyatt_form_bloc/example/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/packages/wyatt_form_bloc/example/web/favicon.png differ diff --git a/packages/wyatt_form_bloc/example/web/icons/Icon-192.png b/packages/wyatt_form_bloc/example/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/packages/wyatt_form_bloc/example/web/icons/Icon-192.png differ diff --git a/packages/wyatt_form_bloc/example/web/icons/Icon-512.png b/packages/wyatt_form_bloc/example/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/packages/wyatt_form_bloc/example/web/icons/Icon-512.png differ diff --git a/packages/wyatt_form_bloc/example/web/icons/Icon-maskable-192.png b/packages/wyatt_form_bloc/example/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/packages/wyatt_form_bloc/example/web/icons/Icon-maskable-192.png differ diff --git a/packages/wyatt_form_bloc/example/web/icons/Icon-maskable-512.png b/packages/wyatt_form_bloc/example/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/packages/wyatt_form_bloc/example/web/icons/Icon-maskable-512.png differ diff --git a/packages/wyatt_form_bloc/example/web/index.html b/packages/wyatt_form_bloc/example/web/index.html new file mode 100644 index 00000000..41b3bc33 --- /dev/null +++ b/packages/wyatt_form_bloc/example/web/index.html @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + + + + + diff --git a/packages/wyatt_form_bloc/example/web/manifest.json b/packages/wyatt_form_bloc/example/web/manifest.json new file mode 100644 index 00000000..096edf8f --- /dev/null +++ b/packages/wyatt_form_bloc/example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +}