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'
|
||||
|
||||
## 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(
|
||||
children: [
|
||||
Container(height: 10),
|
||||
const Text('FlutterFormInputSwitch'),
|
||||
FlutterFormInputSwitch(
|
||||
const Text('FlutterFormInputBool'),
|
||||
FlutterFormInputBool(
|
||||
initialValue: true,
|
||||
onChanged: (v) {
|
||||
debugPrint('Switch changed to $v');
|
||||
|
|
|
@ -68,7 +68,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "2.7.0"
|
||||
version: "3.0.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
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 {
|
||||
const FlutterFormInputSwitch({
|
||||
class FlutterFormInputBool extends StatelessWidget {
|
||||
const FlutterFormInputBool({
|
||||
super.key,
|
||||
this.label,
|
||||
this.onSaved,
|
||||
|
@ -17,20 +17,35 @@ class FlutterFormInputSwitch extends StatelessWidget {
|
|||
this.onChanged,
|
||||
this.focusNode,
|
||||
this.initialValue = false,
|
||||
this.widgetType = BoolWidgetType.switchWidget,
|
||||
this.leftWidget,
|
||||
this.rightWidget,
|
||||
});
|
||||
|
||||
final Widget? label;
|
||||
final Function(bool?)? onSaved;
|
||||
final String? Function(bool?)? validator;
|
||||
final Function(bool?)? onChanged;
|
||||
final bool? initialValue;
|
||||
final FocusNode? focusNode;
|
||||
final BoolWidgetType widgetType;
|
||||
final Widget? leftWidget;
|
||||
final Widget? rightWidget;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SwitchFormField(
|
||||
Widget build(BuildContext context) => BoolFormField(
|
||||
onSaved: (value) => onSaved?.call(value),
|
||||
onChanged: (value) => onChanged?.call(value),
|
||||
validator: (value) => validator?.call(value),
|
||||
initialValue: initialValue ?? false,
|
||||
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
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// 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
|
||||
/// 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
|
||||
/// correlating index is sought.
|
||||
///
|
||||
/// 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
|
||||
/// ending stream. By calling [getRealIndex] with position and base we get
|
||||
/// an offset. This offset modulo our length, 6, will return a number between
|
||||
/// 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
|
||||
/// ending stream. By calling [getRealIndex] with position and base we get
|
||||
/// 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.
|
||||
int getRealIndex(int position, int base, int? length) {
|
||||
var offset = position - base;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
export 'bool/bool.dart';
|
||||
export 'carousel/carousel.dart';
|
||||
export 'date_picker/date_picker.dart';
|
||||
export 'number_picker/number_picker.dart';
|
||||
export 'scroll_picker/scroll_picker.dart';
|
||||
export 'slider/slider.dart';
|
||||
export 'switch/switch.dart';
|
||||
export 'text/password.dart';
|
||||
export 'text/plain_text.dart';
|
||||
|
|
|
@ -45,11 +45,11 @@ class DecimalNumberPicker extends StatelessWidget {
|
|||
final TextMapper? decimalTextMapper;
|
||||
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
|
||||
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
|
||||
final Decoration? decimalDecoration;
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ class InfiniteListViewState extends State<InfiniteListView> {
|
|||
physics: scrollPhysics,
|
||||
viewportBuilder: (BuildContext context, ViewportOffset offset) => Builder(
|
||||
builder: (BuildContext context) {
|
||||
/// Build negative [ScrollPosition] for the negative scrolling
|
||||
/// Build negative [ScrollPosition] for the negative scrolling
|
||||
/// [Viewport].
|
||||
var state = Scrollable.of(context);
|
||||
var negativeOffset = _InfiniteScrollPosition(
|
||||
|
@ -170,13 +170,13 @@ class InfiniteListViewState extends State<InfiniteListView> {
|
|||
negativeScroll: true,
|
||||
);
|
||||
|
||||
/// Keep the negative scrolling [Viewport] positioned to the
|
||||
/// Keep the negative scrolling [Viewport] positioned to the
|
||||
/// [ScrollPosition].
|
||||
offset.addListener(() {
|
||||
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.
|
||||
return Stack(
|
||||
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.
|
||||
class InfiniteScrollController extends ScrollController {
|
||||
/// 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/services.dart';
|
||||
|
||||
/// Generates a [TextFormField] for passwords. It requires a
|
||||
/// [FlutterFormInputController] as the [controller] parameter and an
|
||||
/// Generates a [TextFormField] for passwords. It requires a
|
||||
/// [FlutterFormInputController] as the [controller] parameter and an
|
||||
/// optional [Widget] as [label]
|
||||
class FlutterFormInputPassword extends StatefulWidget {
|
||||
const FlutterFormInputPassword({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: flutter_input_library
|
||||
description: A new Flutter package project.
|
||||
version: 2.7.1
|
||||
version: 3.0.0
|
||||
repository: https://github.com/Iconica-Development/flutter_input_library
|
||||
|
||||
environment:
|
||||
|
|
Loading…
Reference in a new issue