From affa510a5c51993283f6271a2ed67ec2b7893e21 Mon Sep 17 00:00:00 2001 From: Thomas Klein Langenhorst Date: Tue, 25 Oct 2022 08:36:32 +0200 Subject: [PATCH] WIP adresscontroller validator --- example/lib/main.dart | 96 +++++++++-------- lib/flutter_address_form.dart | 1 + lib/src/address_form.dart | 153 ++++++++++++++++------------ pubspec.yaml | 1 - test/flutter_address_form_test.dart | 81 ++++++++------- 5 files changed, 187 insertions(+), 145 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index c6bd1e6..9d712df 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -31,54 +31,66 @@ class MyApp extends StatelessWidget { } class AddressFormExample extends StatelessWidget { - AddressFormExample({Key? key}) : super(key: key); + AddressFormExample({super.key}); - final RegExp zipcodeRegExp = RegExp(r'^[1-9][0-9]{3}\s?[a-zA-Z]{2}$'); + // final RegExp zipcodeRegExp = RegExp(r'^[1-9][0-9]{3}\s?[a-zA-Z]{2}$'); + + final _addressController = AddressController( + zipCodeValidator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + if (!RegExp(r'^[1-9][0-9]{3}\s?[a-zA-Z]{2}$').hasMatch(text)) { + return 'Invalid zipcode'; + } + return null; + }, + housenumberValidator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + if (text.length >= 3 || int.tryParse(text) == null) { + return 'Invalid number'; + } + return null; + }, + suffixValidator: (text) { + if (text.isNotEmpty && RegExp(r'/^[a-z]*$/').hasMatch(text)) { + return 'Invalid prefix'; + } + return null; + }, + streetValidator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + return null; + }, + onAutoComplete: (address) { + return address; + }, + cityValidator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + return null; + }, + ); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), - body: AddressForm( - zipCodeValidator: (text) { - if (text.isEmpty) { - return 'Can\'t be empty'; - } - if (!zipcodeRegExp.hasMatch(text)) { - return 'Invalid zipcode'; - } - return null; - }, - housenumberValidator: (text) { - if (text.isEmpty) { - return 'Can\'t be empty'; - } - if (text.length >= 3 || int.tryParse(text) == null) { - return 'Invalid number'; - } - return null; - }, - suffixValidator: (text) { - if (text.isNotEmpty && RegExp(r'/^[a-z]*$/').hasMatch(text)) { - return 'Invalid prefix'; - } - return null; - }, - streetValidator: (text) { - if (text.isEmpty) { - return 'Can\'t be empty'; - } - return null; - }, - cityValidator: (text) { - if (text.isEmpty) { - return 'Can\'t be empty'; - } - return null; - }, - controller: AddressController(onAutoComplete: (address) { - return address; - }), + body: Column( + children: [ + AddressForm( + onSubmit: (value) => value, controller: _addressController), + TextButton( + onPressed: () { + _addressController.validate; + }, + child: Text('Test')) + ], ), ); } diff --git a/lib/flutter_address_form.dart b/lib/flutter_address_form.dart index 253c382..8ae6d3d 100644 --- a/lib/flutter_address_form.dart +++ b/lib/flutter_address_form.dart @@ -1,3 +1,4 @@ library flutter_address_form; export 'src/address_form.dart'; +export 'src/models/address_model.dart'; diff --git a/lib/src/address_form.dart b/lib/src/address_form.dart index c07b805..3493112 100644 --- a/lib/src/address_form.dart +++ b/lib/src/address_form.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:ffi'; import 'package:flutter/material.dart'; @@ -6,74 +7,74 @@ import 'package:flutter_address_form/src/models/address_model.dart'; /// A widget that creates a form with different address fields widgets. /// Returns a `AddressModel` Object from a `AddressController`. -class AddressForm extends StatelessWidget { +class AddressForm extends StatefulWidget { AddressForm({ - Key? key, - this.zipCodeLabel = const Text('Zipcode'), - this.housenumberLabel = const Text('Housenumber'), - this.suffixLabel = const Text('Suffix'), - this.streetLabel = const Text('Street'), - this.cityLabel = const Text('City'), - required this.zipCodeValidator, - required this.housenumberValidator, - required this.suffixValidator, - required this.streetValidator, - required this.cityValidator, + super.key, AddressController? controller, + this.zipCodeDecoration = const InputDecoration(label: Text('Zipcode')), + this.housenumberDecoration = + const InputDecoration(label: Text('Housenumber')), + this.suffixDecoration = const InputDecoration(label: Text('Suffix')), + this.streetDecoration = const InputDecoration(label: Text('Street')), + this.cityDecoration = const InputDecoration(label: Text('City')), + required this.onSubmit, }) { - _addressController = - controller ?? AddressController(onAutoComplete: (model) => model); + _addressController = controller ?? + AddressController( + onAutoComplete: (model) => model, + zipCodeValidator: (text) => null, + cityValidator: (text) => null, + housenumberValidator: (text) => null, + streetValidator: (text) => null, + suffixValidator: (text) => null, + ); } - final Widget zipCodeLabel; - final Widget housenumberLabel; - final Widget suffixLabel; - final Widget streetLabel; - final Widget cityLabel; + final InputDecoration zipCodeDecoration; + final InputDecoration housenumberDecoration; + final InputDecoration suffixDecoration; + final InputDecoration streetDecoration; + final InputDecoration cityDecoration; - final String? Function(String) zipCodeValidator; - final String? Function(String) housenumberValidator; - final String? Function(String) suffixValidator; - final String? Function(String) streetValidator; - final String? Function(String) cityValidator; + final ValueChanged onSubmit; /// Controls the `AddressModel` late final AddressController _addressController; + @override + State createState() => _AddressFormState(); +} + +class _AddressFormState extends State { @override Widget build(BuildContext context) { return Column( children: [ AddressFormTextField( - controller: _addressController._zipcodeController, - validator: zipCodeValidator, - label: zipCodeLabel, + controller: widget._addressController._zipcodeController, + fieldDecoration: widget.zipCodeDecoration, ), Flexible( child: Row( children: [ AddressFormTextField( - controller: _addressController._housenumberController, - validator: housenumberValidator, - label: housenumberLabel, + controller: widget._addressController._housenumberController, + fieldDecoration: widget.housenumberDecoration, ), AddressFormTextField( - controller: _addressController._suffixController, - validator: suffixValidator, - label: suffixLabel, + controller: widget._addressController._suffixController, + fieldDecoration: widget.suffixDecoration, ), ], ), ), AddressFormTextField( - controller: _addressController._streetController, - validator: streetValidator, - label: streetLabel, + controller: widget._addressController._streetController, + fieldDecoration: widget.streetDecoration, ), AddressFormTextField( - controller: _addressController._cityController, - validator: cityValidator, - label: cityLabel, + controller: widget._addressController._cityController, + fieldDecoration: widget.cityDecoration, ), ], ); @@ -81,36 +82,35 @@ class AddressForm extends StatelessWidget { } class AddressFormTextField extends StatelessWidget { - final Widget label; - final TextEditingController controller; - final String? Function(String) validator; - const AddressFormTextField({ - Key? key, - required this.label, + AddressFormTextField({ + super.key, + required this.fieldDecoration, required this.controller, - required this.validator, - }) : super(key: key); + }) { + _addressFieldDecoration = fieldDecoration; + } - String? get _errorText => validator(controller.value.text); + final TextEditingController controller; + final InputDecoration fieldDecoration; + + late final InputDecoration _addressFieldDecoration; @override Widget build(BuildContext context) { return ValueListenableBuilder( - valueListenable: controller, - builder: (context, value, _) { - return Flexible( - child: Container( - margin: const EdgeInsets.all(10), - child: TextField( - controller: controller, - decoration: InputDecoration( - label: label, - border: const OutlineInputBorder(), - errorText: _errorText), - ), + valueListenable: controller, + builder: (context, value, _) { + return Flexible( + child: Container( + margin: const EdgeInsets.all(10), + child: TextField( + controller: controller, + decoration: _addressFieldDecoration, ), - ); - }); + ), + ); + }, + ); } } @@ -121,7 +121,14 @@ class AddressController extends ChangeNotifier { /// When the form changes, the function passes the current `AddressModel` as an argument and gives the possibility to manipulate and return a `AddressModel`. final FutureOr Function(AddressModel)? onAutoComplete; - AddressController({this.initialValue, this.onAutoComplete}) { + AddressController( + {this.initialValue, + this.onAutoComplete, + required this.zipCodeValidator, + required this.housenumberValidator, + required this.suffixValidator, + required this.streetValidator, + required this.cityValidator}) { _model = initialValue ?? const AddressModel( zipcode: null, @@ -140,6 +147,12 @@ class AddressController extends ChangeNotifier { late AddressModel _model; + final String? Function(String) zipCodeValidator; + final String? Function(String) housenumberValidator; + final String? Function(String) suffixValidator; + final String? Function(String) streetValidator; + final String? Function(String) cityValidator; + late final _zipcodeController = TextEditingController(text: initialValue?.zipcode); late final _streetController = @@ -152,6 +165,20 @@ class AddressController extends ChangeNotifier { AddressModel get model => _model; + bool get validate => _validate(); + + bool _validate() { + if (zipCodeValidator.call(_zipcodeController.text) == null && + streetValidator.call(_streetController.text) == null && + housenumberValidator.call(_housenumberController.text) == null && + suffixValidator.call(_suffixController.text) == null && + cityValidator.call(_cityController.text) == null) { + return true; + } else { + return false; + } + } + void _update() async { AddressModel updatedModel = _model.copyWith( zipcode: _zipcodeController.text, diff --git a/pubspec.yaml b/pubspec.yaml index ec8d961..989a71b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,6 @@ name: flutter_address_form description: A new Flutter package project. version: 0.0.1 -homepage: environment: sdk: '>=2.18.2 <3.0.0' diff --git a/test/flutter_address_form_test.dart b/test/flutter_address_form_test.dart index 56106d7..71896d2 100644 --- a/test/flutter_address_form_test.dart +++ b/test/flutter_address_form_test.dart @@ -11,45 +11,48 @@ void main() { home: Scaffold( appBar: AppBar(), body: AddressForm( - zipCodeValidator: (text) { - if (text.isEmpty) { - return 'Can\'t be empty'; - } - if (!zipcodeRegExp.hasMatch(text)) { - return 'Invalid zipcode'; - } - return null; - }, - housenumberValidator: (text) { - if (text.isEmpty) { - return 'Can\'t be empty'; - } - if (text.length >= 3 || int.tryParse(text) == null) { - return 'Invalid number'; - } - return null; - }, - suffixValidator: (text) { - if (text.isNotEmpty && RegExp(r'/^[a-z]*$/').hasMatch(text)) { - return 'Invalid prefix'; - } - return null; - }, - streetValidator: (text) { - if (text.isEmpty) { - return 'Can\'t be empty'; - } - return null; - }, - cityValidator: (text) { - if (text.isEmpty) { - return 'Can\'t be empty'; - } - return null; - }, - controller: AddressController(onAutoComplete: (address) { - return address; - }), + onSubmit: (value) => value, + controller: AddressController( + zipCodeValidator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + if (!zipcodeRegExp.hasMatch(text)) { + return 'Invalid zipcode'; + } + return null; + }, + housenumberValidator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + if (text.length >= 3 || int.tryParse(text) == null) { + return 'Invalid number'; + } + return null; + }, + suffixValidator: (text) { + if (text.isNotEmpty && RegExp(r'/^[a-z]*$/').hasMatch(text)) { + return 'Invalid prefix'; + } + return null; + }, + streetValidator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + return null; + }, + onAutoComplete: (address) { + return address; + }, + cityValidator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + return null; + }, + ), ), ), ),