mirror of
https://github.com/Iconica-Development/flutter_input_library.git
synced 2025-05-18 17:03:45 +02:00
Merge pull request #29 from Iconica-Development/feature/multiple_bool_input
feat: Add checkbox as option to the flutter input switch which is now…
This commit is contained in:
commit
7d1880b8e3
12 changed files with 166 additions and 87 deletions
|
@ -62,5 +62,7 @@
|
||||||
* Addition of 'decoration' parameter to 'FlutterFormInputPassword'
|
* Addition of 'decoration' parameter to 'FlutterFormInputPassword'
|
||||||
|
|
||||||
## 2.7.1
|
## 2.7.1
|
||||||
|
* Added Iconica CI and Iconica Linter
|
||||||
|
|
||||||
* Added Iconica CI and Iconica Linter
|
## 3.0.0
|
||||||
|
* Updated the FlutterFormInputSwitch to FlutterFormInputBool. This now includes a parameter to either show a checkbox or switch
|
||||||
|
|
|
@ -54,8 +54,8 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(height: 10),
|
Container(height: 10),
|
||||||
const Text('FlutterFormInputSwitch'),
|
const Text('FlutterFormInputBool'),
|
||||||
FlutterFormInputSwitch(
|
FlutterFormInputBool(
|
||||||
initialValue: true,
|
initialValue: true,
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
debugPrint('Switch changed to $v');
|
debugPrint('Switch changed to $v');
|
||||||
|
|
|
@ -68,7 +68,7 @@ packages:
|
||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "2.7.0"
|
version: "3.0.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:flutter_input_library/src/inputs/switch/switch_field.dart';
|
import 'package:flutter_input_library/src/inputs/bool/bool_field.dart';
|
||||||
|
|
||||||
class FlutterFormInputSwitch extends StatelessWidget {
|
class FlutterFormInputBool extends StatelessWidget {
|
||||||
const FlutterFormInputSwitch({
|
const FlutterFormInputBool({
|
||||||
super.key,
|
super.key,
|
||||||
this.label,
|
this.label,
|
||||||
this.onSaved,
|
this.onSaved,
|
||||||
|
@ -17,20 +17,35 @@ class FlutterFormInputSwitch extends StatelessWidget {
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
this.focusNode,
|
this.focusNode,
|
||||||
this.initialValue = false,
|
this.initialValue = false,
|
||||||
|
this.widgetType = BoolWidgetType.switchWidget,
|
||||||
|
this.leftWidget,
|
||||||
|
this.rightWidget,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Widget? label;
|
final Widget? label;
|
||||||
final Function(bool?)? onSaved;
|
final Function(bool?)? onSaved;
|
||||||
final String? Function(bool?)? validator;
|
final String? Function(bool?)? validator;
|
||||||
final Function(bool?)? onChanged;
|
final Function(bool?)? onChanged;
|
||||||
final bool? initialValue;
|
final bool? initialValue;
|
||||||
final FocusNode? focusNode;
|
final FocusNode? focusNode;
|
||||||
|
final BoolWidgetType widgetType;
|
||||||
|
final Widget? leftWidget;
|
||||||
|
final Widget? rightWidget;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => SwitchFormField(
|
Widget build(BuildContext context) => BoolFormField(
|
||||||
onSaved: (value) => onSaved?.call(value),
|
onSaved: (value) => onSaved?.call(value),
|
||||||
onChanged: (value) => onChanged?.call(value),
|
onChanged: (value) => onChanged?.call(value),
|
||||||
validator: (value) => validator?.call(value),
|
validator: (value) => validator?.call(value),
|
||||||
initialValue: initialValue ?? false,
|
initialValue: initialValue ?? false,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
|
widgetType: widgetType,
|
||||||
|
leftWidget: leftWidget,
|
||||||
|
rightWidget: rightWidget,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum BoolWidgetType {
|
||||||
|
switchWidget,
|
||||||
|
checkbox,
|
||||||
|
}
|
124
lib/src/inputs/bool/bool_field.dart
Normal file
124
lib/src/inputs/bool/bool_field.dart
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Iconica
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// ignore_for_file: avoid_positional_boolean_parameters
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_input_library/flutter_input_library.dart';
|
||||||
|
|
||||||
|
class BoolFormField extends FormField<bool> {
|
||||||
|
BoolFormField({
|
||||||
|
required FormFieldSetter<bool> super.onSaved,
|
||||||
|
required FormFieldValidator<bool> super.validator,
|
||||||
|
super.key,
|
||||||
|
FocusNode? focusNode,
|
||||||
|
bool super.initialValue = false,
|
||||||
|
void Function(bool? value)? onChanged,
|
||||||
|
BoolWidgetType widgetType = BoolWidgetType.switchWidget,
|
||||||
|
Widget? leftWidget,
|
||||||
|
Widget? rightWidget,
|
||||||
|
}) : super(
|
||||||
|
builder: (FormFieldState<bool> state) => BoolWidget(
|
||||||
|
initialValue: initialValue,
|
||||||
|
state: state,
|
||||||
|
focusNode: focusNode,
|
||||||
|
onChanged: onChanged,
|
||||||
|
widgetType: widgetType,
|
||||||
|
errorText: state.errorText,
|
||||||
|
leftWidget: leftWidget,
|
||||||
|
rightWidget: rightWidget,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BoolWidget extends StatefulWidget {
|
||||||
|
const BoolWidget({
|
||||||
|
required this.state,
|
||||||
|
this.initialValue = false,
|
||||||
|
this.onChanged,
|
||||||
|
this.focusNode,
|
||||||
|
this.widgetType = BoolWidgetType.switchWidget,
|
||||||
|
this.errorText,
|
||||||
|
this.leftWidget,
|
||||||
|
this.rightWidget,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final bool initialValue;
|
||||||
|
final FormFieldState<bool> state;
|
||||||
|
final FocusNode? focusNode;
|
||||||
|
final void Function(bool? value)? onChanged;
|
||||||
|
final BoolWidgetType widgetType;
|
||||||
|
final String? errorText;
|
||||||
|
final Widget? leftWidget;
|
||||||
|
final Widget? rightWidget;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BoolWidget> createState() => _BoolWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BoolWidgetState extends State<BoolWidget> {
|
||||||
|
late Widget child;
|
||||||
|
late bool value = widget.initialValue;
|
||||||
|
|
||||||
|
void onChanged(bool value) {
|
||||||
|
widget.onChanged?.call(value);
|
||||||
|
|
||||||
|
widget.state.didChange(value);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
this.value = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var theme = Theme.of(context);
|
||||||
|
|
||||||
|
late Widget child;
|
||||||
|
|
||||||
|
switch (widget.widgetType) {
|
||||||
|
case BoolWidgetType.switchWidget:
|
||||||
|
child = Switch(
|
||||||
|
value: value,
|
||||||
|
focusNode: widget.focusNode,
|
||||||
|
onChanged: onChanged,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BoolWidgetType.checkbox:
|
||||||
|
child = Checkbox(
|
||||||
|
value: value,
|
||||||
|
focusNode: widget.focusNode,
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
if (value != null) {
|
||||||
|
onChanged(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
widget.leftWidget ?? const SizedBox.shrink(),
|
||||||
|
child,
|
||||||
|
widget.rightWidget ?? const SizedBox.shrink(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (widget.errorText != null) ...[
|
||||||
|
Text(
|
||||||
|
widget.errorText!,
|
||||||
|
style: theme.inputDecorationTheme.errorStyle,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,17 +2,17 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
/// Converts an index of a set size to the corresponding index of a collection
|
/// Converts an index of a set size to the corresponding index of a collection
|
||||||
/// of another size as if they were circular.
|
/// of another size as if they were circular.
|
||||||
///
|
///
|
||||||
/// Takes a [position] from collection Foo, a [base] from where Foo's index
|
/// Takes a [position] from collection Foo, a [base] from where Foo's index
|
||||||
/// originated and the [length] of a second collection Baa, for which the
|
/// originated and the [length] of a second collection Baa, for which the
|
||||||
/// correlating index is sought.
|
/// correlating index is sought.
|
||||||
///
|
///
|
||||||
/// For example; We have a Carousel of 10000(simulating infinity) but only 6
|
/// For example; We have a Carousel of 10000(simulating infinity) but only 6
|
||||||
/// images. We need to repeat the images to give the illusion of a never
|
/// images. We need to repeat the images to give the illusion of a never
|
||||||
/// ending stream. By calling [getRealIndex] with position and base we get
|
/// ending stream. By calling [getRealIndex] with position and base we get
|
||||||
/// an offset. This offset modulo our length, 6, will return a number between
|
/// an offset. This offset modulo our length, 6, will return a number between
|
||||||
/// 0 and 5, which represent the image to be placed in the given position.
|
/// 0 and 5, which represent the image to be placed in the given position.
|
||||||
int getRealIndex(int position, int base, int? length) {
|
int getRealIndex(int position, int base, int? length) {
|
||||||
var offset = position - base;
|
var offset = position - base;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
export 'bool/bool.dart';
|
||||||
export 'carousel/carousel.dart';
|
export 'carousel/carousel.dart';
|
||||||
export 'date_picker/date_picker.dart';
|
export 'date_picker/date_picker.dart';
|
||||||
export 'number_picker/number_picker.dart';
|
export 'number_picker/number_picker.dart';
|
||||||
export 'scroll_picker/scroll_picker.dart';
|
export 'scroll_picker/scroll_picker.dart';
|
||||||
export 'slider/slider.dart';
|
export 'slider/slider.dart';
|
||||||
export 'switch/switch.dart';
|
|
||||||
export 'text/password.dart';
|
export 'text/password.dart';
|
||||||
export 'text/plain_text.dart';
|
export 'text/plain_text.dart';
|
||||||
|
|
|
@ -45,11 +45,11 @@ class DecimalNumberPicker extends StatelessWidget {
|
||||||
final TextMapper? decimalTextMapper;
|
final TextMapper? decimalTextMapper;
|
||||||
final bool integerZeroPad;
|
final bool integerZeroPad;
|
||||||
|
|
||||||
/// Decoration to apply to central box where the selected integer value
|
/// Decoration to apply to central box where the selected integer value
|
||||||
/// is placed
|
/// is placed
|
||||||
final Decoration? integerDecoration;
|
final Decoration? integerDecoration;
|
||||||
|
|
||||||
/// Decoration to apply to central box where the selected decimal value
|
/// Decoration to apply to central box where the selected decimal value
|
||||||
/// is placed
|
/// is placed
|
||||||
final Decoration? decimalDecoration;
|
final Decoration? decimalDecoration;
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ class InfiniteListViewState extends State<InfiniteListView> {
|
||||||
physics: scrollPhysics,
|
physics: scrollPhysics,
|
||||||
viewportBuilder: (BuildContext context, ViewportOffset offset) => Builder(
|
viewportBuilder: (BuildContext context, ViewportOffset offset) => Builder(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
/// Build negative [ScrollPosition] for the negative scrolling
|
/// Build negative [ScrollPosition] for the negative scrolling
|
||||||
/// [Viewport].
|
/// [Viewport].
|
||||||
var state = Scrollable.of(context);
|
var state = Scrollable.of(context);
|
||||||
var negativeOffset = _InfiniteScrollPosition(
|
var negativeOffset = _InfiniteScrollPosition(
|
||||||
|
@ -170,13 +170,13 @@ class InfiniteListViewState extends State<InfiniteListView> {
|
||||||
negativeScroll: true,
|
negativeScroll: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Keep the negative scrolling [Viewport] positioned to the
|
/// Keep the negative scrolling [Viewport] positioned to the
|
||||||
/// [ScrollPosition].
|
/// [ScrollPosition].
|
||||||
offset.addListener(() {
|
offset.addListener(() {
|
||||||
negativeOffset._forceNegativePixels(offset.pixels);
|
negativeOffset._forceNegativePixels(offset.pixels);
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Stack the two [Viewport]s on top of each other so they move in
|
/// Stack the two [Viewport]s on top of each other so they move in
|
||||||
/// sync.
|
/// sync.
|
||||||
return Stack(
|
return Stack(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
@ -315,7 +315,7 @@ class InfiniteListViewState extends State<InfiniteListView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as a [ScrollController] except it provides [ScrollPosition] objects
|
/// Same as a [ScrollController] except it provides [ScrollPosition] objects
|
||||||
/// with infinite bounds.
|
/// with infinite bounds.
|
||||||
class InfiniteScrollController extends ScrollController {
|
class InfiniteScrollController extends ScrollController {
|
||||||
/// Creates a new [InfiniteScrollController]
|
/// Creates a new [InfiniteScrollController]
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2022 Iconica
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SwitchFormField extends FormField<bool> {
|
|
||||||
SwitchFormField({
|
|
||||||
required FormFieldSetter<bool> super.onSaved,
|
|
||||||
required FormFieldValidator<bool> super.validator,
|
|
||||||
super.key,
|
|
||||||
FocusNode? focusNode,
|
|
||||||
bool super.initialValue = false,
|
|
||||||
// ignore: avoid_positional_boolean_parameters
|
|
||||||
void Function(bool? value)? onChanged,
|
|
||||||
}) : super(
|
|
||||||
builder: (FormFieldState<bool> state) => SwitchWidget(
|
|
||||||
initialValue: initialValue,
|
|
||||||
state: state,
|
|
||||||
focusNode: focusNode,
|
|
||||||
onChanged: onChanged,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class SwitchWidget extends StatefulWidget {
|
|
||||||
const SwitchWidget({
|
|
||||||
required this.state,
|
|
||||||
this.initialValue = false,
|
|
||||||
this.onChanged,
|
|
||||||
this.focusNode,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final bool initialValue;
|
|
||||||
final FormFieldState<bool> state;
|
|
||||||
final FocusNode? focusNode;
|
|
||||||
// ignore: avoid_positional_boolean_parameters
|
|
||||||
final void Function(bool? value)? onChanged;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SwitchWidget> createState() => _SwitchWidgetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SwitchWidgetState extends State<SwitchWidget> {
|
|
||||||
late bool value = widget.initialValue;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => Switch(
|
|
||||||
value: value,
|
|
||||||
focusNode: widget.focusNode,
|
|
||||||
onChanged: (bool value) {
|
|
||||||
widget.onChanged?.call(value);
|
|
||||||
|
|
||||||
widget.state.didChange(value);
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
this.value = value;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -5,8 +5,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
/// Generates a [TextFormField] for passwords. It requires a
|
/// Generates a [TextFormField] for passwords. It requires a
|
||||||
/// [FlutterFormInputController] as the [controller] parameter and an
|
/// [FlutterFormInputController] as the [controller] parameter and an
|
||||||
/// optional [Widget] as [label]
|
/// optional [Widget] as [label]
|
||||||
class FlutterFormInputPassword extends StatefulWidget {
|
class FlutterFormInputPassword extends StatefulWidget {
|
||||||
const FlutterFormInputPassword({
|
const FlutterFormInputPassword({
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: flutter_input_library
|
name: flutter_input_library
|
||||||
description: A new Flutter package project.
|
description: A new Flutter package project.
|
||||||
version: 2.7.1
|
version: 3.0.0
|
||||||
repository: https://github.com/Iconica-Development/flutter_input_library
|
repository: https://github.com/Iconica-Development/flutter_input_library
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|
Loading…
Reference in a new issue