Skip to content

Commit

Permalink
Merge branch 'release/16.0.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
joanpablo committed Aug 13, 2023
2 parents 59bf100 + c8ef868 commit b0f5c41
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 60 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# 16.0.4

## Fixes

- Add missing properties to `ReactiveSwitchListTile.adaptative()` widget.
- Add `showError()` to `ReactiveCheckbox` and `ReactiveCheckboxListTile` widgets. This does not
display any error messages but it is now compatible with the Flutter builtin behavior of Checkboxes
when Material 3 is enabled (`ThemeData(useMaterial3: true)`) in the active App Theme.

## Enhances

- Update `Readme.md` file with testing examples in the section
`ReactiveForm vs ReactiveFormBuilder which one?`

# 16.0.3

## Fixes
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ dependencies:
flutter:
sdk: flutter

reactive_forms: ^16.0.3
reactive_forms: ^16.0.4
```
Then run the command `flutter packages get` on the console.
Expand Down
2 changes: 1 addition & 1 deletion example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
17 changes: 8 additions & 9 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,14 @@ class ReactiveFormsApp extends StatelessWidget {
'uniqueEmail': (_) => 'This email is already in use',
},
child: MaterialApp(
theme: customTheme,
theme: ThemeData(
useMaterial3: true,
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
floatingLabelBehavior: FloatingLabelBehavior.auto,
alignLabelWithHint: true,
),
),
routes: <String, WidgetBuilder>{
Routes.complex: (_) => ComplexSample(),
Routes.simple: (_) => SimpleSample(),
Expand All @@ -55,11 +62,3 @@ class ReactiveFormsApp extends StatelessWidget {
);
}
}

final customTheme = ThemeData.light().copyWith(
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
floatingLabelBehavior: FloatingLabelBehavior.auto,
alignLabelWithHint: true,
),
);
1 change: 1 addition & 0 deletions example/lib/samples/complex_sample.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class ComplexSample extends StatelessWidget {
form: buildForm,
builder: (context, form, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ReactiveTextField<String>(
formControlName: 'email',
Expand Down
29 changes: 18 additions & 11 deletions example/lib/samples/login_sample.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ class LoginSample extends StatelessWidget {
validators: [Validators.required, Validators.email],
),
'password': ['', Validators.required, Validators.minLength(8)],
'rememberMe': false,
'acceptTerms': FormControl<bool>(
value: false,
validators: [Validators.requiredTrue],
),
});

@override
Expand All @@ -19,6 +22,7 @@ class LoginSample extends StatelessWidget {
form: buildForm,
builder: (context, form, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ReactiveTextField<String>(
formControlName: 'email',
Expand Down Expand Up @@ -55,11 +59,10 @@ class LoginSample extends StatelessWidget {
errorStyle: TextStyle(height: 0.7),
),
),
Row(
children: [
ReactiveCheckbox(formControlName: 'rememberMe'),
const Text('Remember me')
],
const SizedBox(height: 16.0),
ReactiveCheckboxListTile(
formControlName: 'acceptTerms',
title: const Text('Accept terms & conditions'),
),
const SizedBox(height: 16.0),
ElevatedButton(
Expand All @@ -72,12 +75,16 @@ class LoginSample extends StatelessWidget {
},
child: const Text('Sign Up'),
),
const SizedBox(height: 16.0),
ElevatedButton(
onPressed: () => form.resetState({
'email': ControlState<String>(value: null),
'password': ControlState<String>(value: null),
'rememberMe': ControlState<bool>(value: false),
}, removeFocus: true),
onPressed: () => form.resetState(
{
'email': ControlState<String>(value: null),
'password': ControlState<String>(value: null),
'acceptTerms': ControlState<bool>(value: false),
},
removeFocus: true,
),
child: const Text('Reset all'),
),
],
Expand Down
28 changes: 15 additions & 13 deletions lib/src/widgets/reactive_checkbox.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,19 @@ import 'package:reactive_forms/reactive_forms.dart';

/// This is a convenience widget that wraps a [Checkbox] widget in a
/// [ReactiveCheckbox].
///
/// Can optionally provide a [formControl] to bind this widget to a control.
///
/// Can optionally provide a [formControlName] to bind this ReactiveFormField
/// to a [FormControl].
///
/// Must provide one of the arguments [formControl] or a [formControlName],
/// but not both at the same time.
///
/// For documentation about the various parameters, see the [Checkbox] class
/// and [Checkbox], the constructor.
class ReactiveCheckbox extends ReactiveFocusableFormField<bool, bool> {
/// Create an instance of a [ReactiveCheckbox].
///
/// The [formControlName] arguments must not be null.
/// Can optionally provide a [formControl] to bind this widget to a control.
///
/// Can optionally provide a [formControlName] to bind this ReactiveFormField
/// to a [FormControl].
///
/// Must provide one of the arguments [formControl] or a [formControlName],
/// but not both at the same time.
///
/// For documentation about the various parameters, see the [Checkbox] class
/// and the [Checkbox] constructor.
ReactiveCheckbox({
Key? key,
String? formControlName,
Expand All @@ -42,11 +40,15 @@ class ReactiveCheckbox extends ReactiveFocusableFormField<bool, bool> {
OutlinedBorder? shape,
BorderSide? side,
ReactiveFormFieldCallback<bool>? onChanged,
ShowErrorsFunction<bool>? showErrors,
}) : super(
key: key,
formControl: formControl,
formControlName: formControlName,
focusNode: focusNode,
showErrors: showErrors ??
(control) =>
control.invalid && (control.dirty || control.touched),
builder: (field) {
return Checkbox(
value: tristate ? field.value : field.value ?? false,
Expand All @@ -65,7 +67,7 @@ class ReactiveCheckbox extends ReactiveFocusableFormField<bool, bool> {
focusNode: field.focusNode,
shape: shape,
side: side,
isError: !field.control.valid,
isError: field.errorText != null,
onChanged: field.control.enabled
? (value) {
field.didChange(value);
Expand Down
29 changes: 15 additions & 14 deletions lib/src/widgets/reactive_checkbox_list_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,19 @@ import 'package:reactive_forms/reactive_forms.dart';

/// This is a convenience widget that wraps a [CheckboxListTile] widget in a
/// [ReactiveCheckboxListTile].
///
/// Can optionally provide a [formControl] to bind this widget to a control.
///
/// Can optionally provide a [formControlName] to bind this ReactiveFormField
/// to a [FormControl].
///
/// Must provide one of the arguments [formControl] or a [formControlName],
/// but not both at the same time.
///
/// For documentation about the various parameters, see the [CheckboxListTile]
/// class and [CheckboxListTile], the constructor.
class ReactiveCheckboxListTile extends ReactiveFocusableFormField<bool, bool> {
/// Create an instance of a [ReactiveCheckbox].
///
/// The [formControlName] arguments must not be null.
/// Can optionally provide a [formControl] to bind this widget to a control.
///
/// See also [CheckboxListTile]
/// Can optionally provide a [formControlName] to bind this ReactiveFormField
/// to a [FormControl].
///
/// Must provide one of the arguments [formControl] or a [formControlName],
/// but not both at the same time.
///
/// For documentation about the various parameters, see the [CheckboxListTile]
/// class and the [CheckboxListTile] constructor.
ReactiveCheckboxListTile({
Key? key,
String? formControlName,
Expand Down Expand Up @@ -56,11 +52,15 @@ class ReactiveCheckboxListTile extends ReactiveFocusableFormField<bool, bool> {
double? splashRadius,
MaterialTapTargetSize? materialTapTargetSize,
ValueChanged<bool>? onFocusChange,
ShowErrorsFunction<bool>? showErrors,
}) : super(
key: key,
formControl: formControl,
formControlName: formControlName,
focusNode: focusNode,
showErrors: showErrors ??
(control) =>
control.invalid && (control.dirty || control.touched),
builder: (field) {
return CheckboxListTile(
value: tristate ? field.value : field.value ?? false,
Expand All @@ -73,7 +73,7 @@ class ReactiveCheckboxListTile extends ReactiveFocusableFormField<bool, bool> {
activeColor: activeColor,
checkColor: checkColor,
onFocusChange: onFocusChange,
isError: !field.control.valid,
isError: field.errorText != null,
title: title,
subtitle: subtitle,
isThreeLine: isThreeLine,
Expand All @@ -92,6 +92,7 @@ class ReactiveCheckboxListTile extends ReactiveFocusableFormField<bool, bool> {
enableFeedback: enableFeedback,
checkboxShape: checkboxShape,
side: side,
enabled: field.control.enabled,
onChanged: field.control.enabled
? (value) {
field.didChange(value);
Expand Down
9 changes: 7 additions & 2 deletions lib/src/widgets/reactive_dropdown_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import 'package:flutter/material.dart';
import 'package:reactive_forms/reactive_forms.dart';

/// A reactive widget that wraps a [DropdownButton].
/// A reactive widget that wraps a [DropdownButtonFormField].
class ReactiveDropdownField<T> extends ReactiveFocusableFormField<T, T> {
/// Creates a [DropdownButton] widget wrapped in an [InputDecorator].
///
Expand All @@ -20,7 +20,10 @@ class ReactiveDropdownField<T> extends ReactiveFocusableFormField<T, T> {
/// If [readOnly] is true, the button will be disabled, the down arrow will
/// be grayed out, and the disabledHint will be shown (if provided).
///
/// The [DropdownButton] [items] parameters must not be null.
/// The [items] parameter must not be null.
///
/// For more information about all various parameters,
/// see [DropdownButtonFormField] constructor.
ReactiveDropdownField({
Key? key,
String? formControlName,
Expand Down Expand Up @@ -50,6 +53,7 @@ class ReactiveDropdownField<T> extends ReactiveFocusableFormField<T, T> {
bool? enableFeedback,
AlignmentGeometry alignment = AlignmentDirectional.centerStart,
BorderRadius? borderRadius,
EdgeInsetsGeometry? padding,
ReactiveFormFieldCallback<T>? onTap,
ReactiveFormFieldCallback<T>? onChanged,
}) : assert(itemHeight == null || itemHeight > 0),
Expand Down Expand Up @@ -111,6 +115,7 @@ class ReactiveDropdownField<T> extends ReactiveFocusableFormField<T, T> {
enableFeedback: enableFeedback,
alignment: alignment,
borderRadius: borderRadius,
padding: padding,
onTap: onTap != null ? () => onTap(field.control) : null,
onChanged: isDisabled
? null
Expand Down
42 changes: 34 additions & 8 deletions lib/src/widgets/reactive_switch_list_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,31 @@ class ReactiveSwitchListTile extends ReactiveFocusableFormField<bool, bool> {
String? formControlName,
FormControl<bool>? formControl,
Color? activeColor,
ImageProvider? activeThumbImage,
Color? activeTrackColor,
Color? inactiveThumbColor,
Color? inactiveTrackColor,
ImageProvider? activeThumbImage,
ImageErrorListener? onActiveThumbImageError,
ImageProvider? inactiveThumbImage,
ImageErrorListener? onInactiveThumbImageError,
MaterialStateProperty<Color?>? thumbColor,
MaterialStateProperty<Color?>? trackColor,
MaterialStateProperty<Color?>? trackOutlineColor,
MaterialStateProperty<Icon?>? thumbIcon,
MaterialTapTargetSize? materialTapTargetSize,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
MouseCursor? mouseCursor,
MaterialStateProperty<Color?>? overlayColor,
double? splashRadius,
bool autofocus = false,
bool? applyCupertinoTheme,
EdgeInsetsGeometry? contentPadding,
ListTileControlAffinity controlAffinity = ListTileControlAffinity.platform,
bool? dense,
bool? enableFeedback,
FocusNode? focusNode,
ValueChanged<bool>? onFocusChange,
Color? hoverColor,
Color? inactiveThumbColor,
ImageProvider? inactiveThumbImage,
Color? inactiveTrackColor,
bool isThreeLine = false,
Widget? secondary,
bool selected = false,
Expand All @@ -167,18 +180,31 @@ class ReactiveSwitchListTile extends ReactiveFocusableFormField<bool, bool> {
return SwitchListTile.adaptive(
value: field.value ?? false,
activeColor: activeColor,
activeThumbImage: activeThumbImage,
activeTrackColor: activeTrackColor,
inactiveThumbColor: inactiveThumbColor,
inactiveTrackColor: inactiveTrackColor,
activeThumbImage: activeThumbImage,
onActiveThumbImageError: onActiveThumbImageError,
inactiveThumbImage: inactiveThumbImage,
onInactiveThumbImageError: onInactiveThumbImageError,
thumbColor: thumbColor,
trackColor: trackColor,
trackOutlineColor: trackOutlineColor,
thumbIcon: thumbIcon,
materialTapTargetSize: materialTapTargetSize,
dragStartBehavior: dragStartBehavior,
mouseCursor: mouseCursor,
overlayColor: overlayColor,
splashRadius: splashRadius,
autofocus: autofocus,
applyCupertinoTheme: applyCupertinoTheme,
contentPadding: contentPadding,
controlAffinity: controlAffinity,
dense: dense,
enableFeedback: enableFeedback,
focusNode: field.focusNode,
onFocusChange: onFocusChange,
hoverColor: hoverColor,
inactiveThumbColor: inactiveThumbColor,
inactiveThumbImage: inactiveThumbImage,
inactiveTrackColor: inactiveTrackColor,
isThreeLine: isThreeLine,
secondary: secondary,
selected: selected,
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: reactive_forms
description: This is a model-driven approach to handling form inputs and validations, heavily inspired in Angular Reactive Forms.
version: 16.0.3
version: 16.0.4
homepage: "https://github.com/joanpablo/reactive_forms"

environment:
Expand Down

0 comments on commit b0f5c41

Please sign in to comment.