diff --git a/lib/src/address_controller.dart b/lib/src/address_controller.dart new file mode 100644 index 0000000..34d5b32 --- /dev/null +++ b/lib/src/address_controller.dart @@ -0,0 +1,13 @@ +import 'package:flutter/foundation.dart'; + +class AddressController extends ChangeNotifier { + final String zipcode; + final int houseNumber; + final String prefix; + final String street; + final String city; + + AddressController(this.zipcode, this.houseNumber, this.prefix, this.street, this.city); + + +} diff --git a/lib/src/address_form.dart b/lib/src/address_form.dart index 6ca5fee..47b6d3e 100644 --- a/lib/src/address_form.dart +++ b/lib/src/address_form.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter_address_form/src/models/address.dart'; class AddressForm extends StatefulWidget { - AddressForm({Key? key}) : super(key: key); + const AddressForm({Key? key}) : super(key: key); @override State createState() => _AddressFormState(); @@ -10,58 +10,146 @@ class AddressForm extends StatefulWidget { class _AddressFormState extends State { final TextEditingController _zipcodeController = TextEditingController(); + final TextEditingController _houseNumberController = TextEditingController(); + final TextEditingController _prefixController = TextEditingController(); + final TextEditingController _streetController = TextEditingController(); + final TextEditingController _cityController = TextEditingController(); + final RegExp _zipcodeRegExp = RegExp(r'^[1-9][0-9]{3}\s?[a-zA-Z]{2}$'); @override Widget build(BuildContext context) { - return Form( - child: Column( - children: [ - _createField( - label: 'Postcode', - controller: _zipcodeController, + return Column( + children: [ + AddressFormTextField( + controller: _zipcodeController, + validator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + if (!_zipcodeRegExp.hasMatch(text)) { + return 'Invalid zipcode'; + } + return null; + }, + label: 'Postcode', + ), + Flexible( + child: Row( + children: [ + AddressFormTextField( + controller: _houseNumberController, + validator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + if (text.length >= 3 || int.tryParse(text) == null) { + return 'Invalid number'; + } + return null; + }, + label: 'Huisnummer', + ), + AddressFormTextField( + controller: _prefixController, + validator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + if (RegExp(r'/^[a-z]*$/').hasMatch(text) && + text.length != 1) { + return 'Invalid prefix'; + } + return null; + }, + label: 'Toevoeging', + ), + ], ), - Flexible( - child: Row( - children: [ - _createField( - label: 'Huisnummer', - controller: TextEditingController(), - ), - _createField( - label: 'Toevoeging', - controller: TextEditingController(), - ), - ], - ), - ), - _createField( - label: 'Straatnaam', - controller: TextEditingController(), - ), - _createField( - label: 'Woonplaats', - controller: TextEditingController(), - ) - ], - ), + ), + AddressFormTextField( + controller: _streetController, + validator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + return null; + }, + label: 'Straatnaam', + ), + AddressFormTextField( + controller: _cityController, + validator: (text) { + if (text.isEmpty) { + return 'Can\'t be empty'; + } + return null; + }, + label: 'Woonplaats', + ), + TextButton( + onPressed: () {}, + child: Text('Test'), + ) + ], ); } - Widget _createField( - {required String label, required TextEditingController controller}) { - return Flexible( - child: Container( - margin: const EdgeInsets.all(10), - child: TextFormField( - validator: (value) { - print(_zipcodeRegExp.hasMatch(value!)); - }, - decoration: InputDecoration( - label: Text(label), - border: const OutlineInputBorder(), - ), - ), - ), - ); + @override + void dispose() { + _zipcodeController.dispose(); + _houseNumberController.dispose(); + _prefixController.dispose(); + _streetController.dispose(); + _cityController.dispose(); + super.dispose(); + } +} + +class AddressFormTextField extends StatefulWidget { + final String label; + final TextEditingController controller; + final String? Function(String) validator; + AddressFormTextField({ + Key? key, + required this.label, + required this.controller, + required this.validator, + }) : super(key: key); + + @override + State createState() => _AddressFormTextFieldState(); +} + +class _AddressFormTextFieldState extends State { + final Address addressModel = Address(); + + String? get _errorText { + final text = widget.controller.value.text; + return widget.validator(text); + } + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: widget.controller, + builder: (context, value, _) { + return Flexible( + child: Container( + margin: const EdgeInsets.all(10), + child: TextField( + controller: widget.controller, + decoration: InputDecoration( + label: Text(widget.label), + border: const OutlineInputBorder(), + errorText: _errorText), + ), + ), + ); + }); } } diff --git a/lib/src/models/address.dart b/lib/src/models/address.dart new file mode 100644 index 0000000..2a6ac9f --- /dev/null +++ b/lib/src/models/address.dart @@ -0,0 +1,30 @@ +class Address { + Address({ + this.zipcode, + this.street, + this.housenumber, + this.suffix, + this.city, + }); + + final String? zipcode; + final String? street; + final int? housenumber; + final String? suffix; + final String? city; + + Address copyWith({ + String? zipcode, + String? street, + int? housenumber, + String? suffix, + String? city, + }) => + Address( + zipcode: zipcode ?? this.zipcode, + street: street ?? this.street, + housenumber: housenumber ?? this.housenumber, + suffix: suffix ?? this.suffix, + city: city ?? this.city, + ); +}