From 6f7ec0b0e6e708840b468f623abd5112a39c8974 Mon Sep 17 00:00:00 2001 From: Stein Milder Date: Mon, 26 Sep 2022 10:35:53 +0200 Subject: [PATCH] feat: registration options, translations --- example/lib/main.dart | 11 +- lib/flutter_registration.dart | 2 + lib/src/auth_screen.dart | 234 +++++++++--------- lib/src/config/registration_options.dart | 51 ++++ lib/src/config/registration_translations.dart | 15 ++ lib/src/registration_screen.dart | 65 ++--- 6 files changed, 216 insertions(+), 162 deletions(-) create mode 100644 lib/src/config/registration_options.dart create mode 100644 lib/src/config/registration_translations.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index dc76638..bf58a0f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -16,10 +16,13 @@ class FlutterRegistrationDemo extends StatelessWidget { @override Widget build(BuildContext context) { return RegistrationScreen( - afterRegistration: () { - debugPrint('Registered!'); - }, - repository: ExampleRegistrationRepository(), + registrationOptions: RegistrationOptions( + registrationRepository: ExampleRegistrationRepository(), + registrationSteps: RegistrationOptions.defaultSteps, + afterRegistration: () { + debugPrint('Registered!'); + }, + ), ); } } diff --git a/lib/flutter_registration.dart b/lib/flutter_registration.dart index 7fac6a1..d7cb925 100644 --- a/lib/flutter_registration.dart +++ b/lib/flutter_registration.dart @@ -1,5 +1,7 @@ library flutter_registration; +export 'src/config/registration_options.dart'; +export 'src/config/registration_translations.dart'; export 'src/model/auth_exception.dart'; export 'src/model/auth_field.dart'; export 'src/model/auth_step.dart'; diff --git a/lib/src/auth_screen.dart b/lib/src/auth_screen.dart index a889e11..657b7fc 100644 --- a/lib/src/auth_screen.dart +++ b/lib/src/auth_screen.dart @@ -8,6 +8,8 @@ class AuthScreen extends StatefulWidget { required this.title, required this.steps, required this.submitBtnTitle, + required this.nextBtnTitle, + required this.previousBtnTitle, required this.onFinish, super.key, }) : assert(steps.length > 0, 'At least one step is required'); @@ -16,6 +18,8 @@ class AuthScreen extends StatefulWidget { final Function(HashMap) onFinish; final List steps; final String submitBtnTitle; + final String nextBtnTitle; + final String previousBtnTitle; @override State createState() => _AuthScreenState(); @@ -28,128 +32,136 @@ class _AuthScreenState extends State { final _animationCurve = Curves.ease; @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Theme.of(context).backgroundColor, - appBar: AppBar( - title: Text(widget.title), - ), - body: Form( - key: _formKey, - child: PageView( - physics: const NeverScrollableScrollPhysics(), - controller: _pageController, - children: [ - for (AuthStep step in widget.steps) - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Spacer(), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 30.0, + Widget build(BuildContext context) => Scaffold( + backgroundColor: Theme.of(context).backgroundColor, + appBar: AppBar( + title: Text(widget.title), + ), + body: Form( + key: _formKey, + child: PageView( + physics: const NeverScrollableScrollPhysics(), + controller: _pageController, + children: [ + for (AuthStep step in widget.steps) + Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Center( + child: ListView( + physics: const ClampingScrollPhysics(), + shrinkWrap: true, + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 30.0, + ), + children: [ + for (AuthField field in step.fields) + Align( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only( + top: 24.0, + bottom: 12.0, + ), + child: Text( + field.title, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + field.build(), + ], + ), + ) + ], + ), + ), ), - child: Column( - children: [ - for (AuthField field in step.fields) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only( - top: 24.0, - bottom: 12.0, - ), - child: Text( - field.title, - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), + Padding( + padding: const EdgeInsets.only( + top: 15.0, + bottom: 30.0, + left: 30.0, + right: 30.0, + ), + child: Row( + mainAxisAlignment: widget.steps.first != step + ? MainAxisAlignment.spaceBetween + : MainAxisAlignment.end, + children: [ + if (widget.steps.first != step) + ElevatedButton( + onPressed: () => _pageController.previousPage( + duration: _animationDuration, + curve: _animationCurve, + ), + child: Row( + children: [ + const Icon( + Icons.arrow_back, + size: 18, + ), + Padding( + padding: const EdgeInsets.only(left: 4.0), + child: Text(widget.previousBtnTitle), + ), + ], ), - field.build(), - ], - ) - ], - ), - ), - const Spacer(), - Padding( - padding: const EdgeInsets.all(30.0), - child: Row( - mainAxisAlignment: widget.steps.first != step - ? MainAxisAlignment.spaceBetween - : MainAxisAlignment.end, - children: [ - if (widget.steps.first != step) - ElevatedButton( - onPressed: () => _pageController.previousPage( - duration: _animationDuration, - curve: _animationCurve, ), + ElevatedButton( + onPressed: () { + if (!_formKey.currentState!.validate()) { + return; + } + + if (widget.steps.last == step) { + var values = HashMap(); + + for (var step in widget.steps) { + for (var field in step.fields) { + values[field.name] = field.value; + } + } + + widget.onFinish(values); + + return; + } + + _pageController.nextPage( + duration: _animationDuration, + curve: _animationCurve, + ); + }, child: Row( children: [ - const Icon( - Icons.arrow_back, - size: 18, + Text( + widget.steps.last == step + ? widget.submitBtnTitle + : widget.nextBtnTitle, ), const Padding( padding: EdgeInsets.only(left: 4.0), - child: Text('Vorige stap'), + child: Icon( + Icons.arrow_forward, + size: 18, + ), ), ], ), ), - ElevatedButton( - onPressed: () { - if (!_formKey.currentState!.validate()) { - return; - } - - if (widget.steps.last == step) { - var values = HashMap(); - - for (var step in widget.steps) { - for (var field in step.fields) { - values[field.name] = field.value; - } - } - - widget.onFinish(values); - return; - } - - _pageController.nextPage( - duration: _animationDuration, - curve: _animationCurve, - ); - }, - child: Row( - children: [ - Text( - widget.steps.last == step - ? widget.submitBtnTitle - : 'Volgende stap', - ), - const Padding( - padding: EdgeInsets.only(left: 4.0), - child: Icon( - Icons.arrow_forward, - size: 18, - ), - ), - ], - ), - ), - ], - ), - ) - ], - ), - ], + ], + ), + ) + ], + ), + ], + ), ), - ), - ); - } + ); } diff --git a/lib/src/config/registration_options.dart b/lib/src/config/registration_options.dart new file mode 100644 index 0000000..ba97084 --- /dev/null +++ b/lib/src/config/registration_options.dart @@ -0,0 +1,51 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_registration/flutter_registration.dart'; + +class RegistrationOptions { + RegistrationOptions({ + required this.registrationRepository, + required this.registrationSteps, + required this.afterRegistration, + this.registrationTranslations = const RegistrationTranslations(), + }); + + final RegistrationTranslations registrationTranslations; + final List registrationSteps; + final VoidCallback afterRegistration; + final RegistrationRepository registrationRepository; + + static List get defaultSteps => [ + AuthStep( + fields: [ + AuthTextField( + name: 'email', + title: 'Wat is je e-mailadres?', + validators: [ + (email) => (email == null || email.isEmpty) + ? 'Geef uw e-mailadres op' + : null, + (email) => + RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") + .hasMatch(email!) + ? null + : 'Geef een geldig e-mailadres op', + ], + ) + ], + ), + AuthStep( + fields: [ + AuthTextField( + name: 'password', + title: 'Kies een wachtwoord', + obscureText: true, + validators: [ + (value) => (value == null || value.isEmpty) + ? 'Geef een wachtwoord op' + : null, + ], + ), + ], + ), + ]; +} diff --git a/lib/src/config/registration_translations.dart b/lib/src/config/registration_translations.dart new file mode 100644 index 0000000..ab0ac9a --- /dev/null +++ b/lib/src/config/registration_translations.dart @@ -0,0 +1,15 @@ +class RegistrationTranslations { + const RegistrationTranslations({ + this.title = 'Registreren', + this.registerBtn = 'Registreren', + this.previousStepBtn = 'Vorige stap', + this.nextStepBtn = 'Volgende stap', + this.closeBtn = 'Sluiten', + }); + + final String title; + final String registerBtn; + final String previousStepBtn; + final String nextStepBtn; + final String closeBtn; +} diff --git a/lib/src/registration_screen.dart b/lib/src/registration_screen.dart index 37e5de2..643bd0e 100644 --- a/lib/src/registration_screen.dart +++ b/lib/src/registration_screen.dart @@ -4,35 +4,38 @@ import 'package:flutter_registration/src/auth_screen.dart'; class RegistrationScreen extends StatelessWidget { const RegistrationScreen({ - required this.afterRegistration, - required this.repository, - this.additionalSteps = const [], + required this.registrationOptions, super.key, }); - final VoidCallback afterRegistration; - final RegistrationRepository repository; - final List additionalSteps; + final RegistrationOptions registrationOptions; @override Widget build(BuildContext context) { + var translations = registrationOptions.registrationTranslations; + void showError(String error) => showDialog( context: context, builder: (BuildContext context) => AlertDialog( content: Text(error), actions: [ TextButton( - onPressed: () => Navigator.pop(context, 'Sluit'), - child: const Text('Sluit'), + onPressed: () => Navigator.pop( + context, + translations.closeBtn, + ), + child: Text( + translations.closeBtn, + ), ), ], ), ); - void register(values) => repository + void register(values) => registrationOptions.registrationRepository .register(values) .then( - (value) => afterRegistration(), + (_) => registrationOptions.afterRegistration(), ) .catchError( (error) { @@ -43,44 +46,12 @@ class RegistrationScreen extends StatelessWidget { ); return AuthScreen( - title: 'Registreren', - submitBtnTitle: 'Registreren', - steps: [ - AuthStep( - fields: [ - AuthTextField( - name: 'email', - title: 'Wat is je e-mailadres?', - validators: [ - (email) => (email == null || email.isEmpty) - ? 'Geef uw e-mailadres op' - : null, - (email) => - RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") - .hasMatch(email!) - ? null - : 'Geef een geldig e-mailadres op', - ], - ) - ], - ), - AuthStep( - fields: [ - AuthTextField( - name: 'password', - title: 'Kies een wachtwoord', - obscureText: true, - validators: [ - (value) => (value == null || value.isEmpty) - ? 'Geef een wachtwoord op' - : null, - ], - ), - ], - ), - ...additionalSteps - ], + steps: registrationOptions.registrationSteps, onFinish: register, + title: translations.title, + submitBtnTitle: translations.registerBtn, + nextBtnTitle: translations.nextStepBtn, + previousBtnTitle: translations.previousStepBtn, ); } }