-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* created stepper * implementing min and max values * widgetbook * pr comments
- Loading branch information
1 parent
8507830
commit ca51b1f
Showing
7 changed files
with
263 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:zeta_example/widgets.dart'; | ||
import 'package:zeta_flutter/zeta_flutter.dart'; | ||
|
||
class StepperInputExample extends StatefulWidget { | ||
static const name = 'StepperInput'; | ||
|
||
const StepperInputExample({super.key}); | ||
|
||
@override | ||
State<StepperInputExample> createState() => _StepperInputExampleState(); | ||
} | ||
|
||
class _StepperInputExampleState extends State<StepperInputExample> { | ||
@override | ||
Widget build(BuildContext context) { | ||
return ExampleScaffold( | ||
name: StepperInputExample.name, | ||
child: Center( | ||
child: Column( | ||
mainAxisSize: MainAxisSize.min, | ||
children: [ | ||
ZetaStepperInput( | ||
min: 0, | ||
max: 10, | ||
initialValue: 5, | ||
onChange: (_) {}, | ||
), | ||
ZetaStepperInput(rounded: false), | ||
ZetaStepperInput( | ||
size: ZetaStepperInputSize.large, | ||
onChange: (_) {}, | ||
), | ||
].divide(const SizedBox(height: 16)).toList(), | ||
), | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
example/widgetbook/pages/components/stepper_input_widgetbook.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:widgetbook/widgetbook.dart'; | ||
import 'package:zeta_flutter/zeta_flutter.dart'; | ||
|
||
import '../../test/test_components.dart'; | ||
import '../../utils/utils.dart'; | ||
|
||
Widget stepperInputUseCase(BuildContext context) { | ||
return WidgetbookTestWidget( | ||
widget: ZetaStepperInput( | ||
initialValue: context.knobs.int.input(label: 'Initial value'), | ||
min: context.knobs.int.input(label: 'Minimum value'), | ||
max: context.knobs.int.input(label: 'Maximum value'), | ||
size: context.knobs.list( | ||
label: 'Size', | ||
options: ZetaStepperInputSize.values, | ||
labelBuilder: enumLabelBuilder, | ||
), | ||
rounded: context.knobs.boolean(label: 'Rounded', initialValue: true), | ||
onChange: context.knobs.boolean(label: 'Disabled', initialValue: false) ? null : (_) {}, | ||
), | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
import 'package:flutter/foundation.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter/services.dart'; | ||
|
||
import '../../../zeta_flutter.dart'; | ||
|
||
/// Sizes for [ZetaStepperInput] | ||
enum ZetaStepperInputSize { | ||
/// Medium | ||
medium, | ||
|
||
/// Large | ||
large, | ||
} | ||
|
||
/// A stepper input, also called numeric stepper, is a common UI element that allows uers to input a number or value simply by clicking the plus and minus buttons. | ||
class ZetaStepperInput extends StatefulWidget { | ||
/// Creates a new [ZetaStepperInput] | ||
const ZetaStepperInput({ | ||
this.rounded = true, | ||
this.size = ZetaStepperInputSize.medium, | ||
this.initialValue, | ||
this.min, | ||
this.max, | ||
this.onChange, | ||
super.key, | ||
}) : assert( | ||
(min == null || (initialValue ?? 0) >= min) && (max == null || (initialValue ?? 0) <= max), | ||
'Initial value must be inside given min and max values', | ||
); | ||
|
||
/// {@macro zeta-component-rounded} | ||
final bool rounded; | ||
|
||
/// The size of the stepper input. | ||
final ZetaStepperInputSize size; | ||
|
||
/// The initial value of the stepper input. | ||
/// | ||
/// Must be in the bounds of [min] and [max] (if given). | ||
final int? initialValue; | ||
|
||
/// The minimum value of the stepper input. | ||
final int? min; | ||
|
||
/// The maximum value of the stepper input. | ||
final int? max; | ||
|
||
/// Called with the value of the stepper whenever it is changed. | ||
final ValueChanged<int>? onChange; | ||
|
||
@override | ||
State<ZetaStepperInput> createState() => _ZetaStepperInputState(); | ||
@override | ||
void debugFillProperties(DiagnosticPropertiesBuilder properties) { | ||
super.debugFillProperties(properties); | ||
properties | ||
..add(DiagnosticsProperty<bool>('rounded', rounded)) | ||
..add(EnumProperty<ZetaStepperInputSize>('size', size)) | ||
..add(IntProperty('initialValue', initialValue)) | ||
..add(IntProperty('min', min)) | ||
..add(IntProperty('max', max)) | ||
..add(ObjectFlagProperty<ValueChanged<int>?>.has('onChange', onChange)); | ||
} | ||
} | ||
|
||
class _ZetaStepperInputState extends State<ZetaStepperInput> { | ||
final TextEditingController _controller = TextEditingController(); | ||
int _value = 0; | ||
late final bool _disabled; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_disabled = widget.onChange == null; | ||
if (widget.initialValue != null) { | ||
_value = widget.initialValue!; | ||
} | ||
_controller.text = _value.toString(); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
super.dispose(); | ||
_controller.dispose(); | ||
} | ||
|
||
InputBorder get _border { | ||
final colors = Zeta.of(context).colors; | ||
|
||
return OutlineInputBorder( | ||
borderSide: BorderSide( | ||
color: !_disabled ? colors.borderSubtle : colors.borderDisabled, | ||
), | ||
borderRadius: widget.rounded ? ZetaRadius.minimal : ZetaRadius.none, | ||
); | ||
} | ||
|
||
double get _height { | ||
if (widget.size != ZetaStepperInputSize.large) { | ||
return ZetaSpacing.x10; | ||
} else { | ||
return ZetaSpacing.x12; | ||
} | ||
} | ||
|
||
void _onTextChange(String value) { | ||
int? val = int.tryParse(value); | ||
if (val != null) { | ||
if (widget.max != null && val > widget.max!) { | ||
val = widget.max; | ||
} | ||
if (widget.min != null && val! < widget.min!) { | ||
val = widget.min; | ||
} | ||
_onChange(val!); | ||
} | ||
} | ||
|
||
void _onChange(int value) { | ||
if (!(widget.max != null && value > widget.max! || widget.min != null && value < widget.min!)) { | ||
setState(() { | ||
_value = value; | ||
}); | ||
_controller.text = value.toString(); | ||
widget.onChange?.call(value); | ||
} | ||
} | ||
|
||
ZetaIconButton _getButton({bool increase = false}) { | ||
return ZetaIconButton( | ||
icon: increase | ||
? widget.rounded | ||
? ZetaIcons.add_round | ||
: ZetaIcons.add_sharp | ||
: widget.rounded | ||
? ZetaIcons.remove_round | ||
: ZetaIcons.remove_sharp, | ||
type: ZetaButtonType.outlineSubtle, | ||
size: widget.size == ZetaStepperInputSize.medium ? ZetaWidgetSize.medium : ZetaWidgetSize.large, | ||
borderType: widget.rounded ? ZetaWidgetBorder.rounded : ZetaWidgetBorder.sharp, | ||
onPressed: !_disabled | ||
? () => _onChange( | ||
_value + (increase ? 1 : -1), | ||
) | ||
: null, | ||
); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final colors = Zeta.of(context).colors; | ||
|
||
return Row( | ||
mainAxisSize: MainAxisSize.min, | ||
children: [ | ||
_getButton(), | ||
SizedBox( | ||
width: ZetaSpacing.xl, | ||
child: TextFormField( | ||
keyboardType: TextInputType.number, | ||
enabled: !_disabled, | ||
controller: _controller, | ||
onChanged: _onTextChange, | ||
textAlign: TextAlign.center, | ||
inputFormatters: [FilteringTextInputFormatter.digitsOnly], | ||
style: Theme.of(context).textTheme.bodyMedium?.copyWith( | ||
color: _disabled ? colors.textDisabled : null, | ||
), | ||
onTapOutside: (_) { | ||
if (_controller.text.isEmpty) { | ||
_controller.text = _value.toString(); | ||
} | ||
}, | ||
decoration: InputDecoration( | ||
filled: true, | ||
fillColor: _disabled ? colors.surfaceDisabled : null, | ||
contentPadding: EdgeInsets.zero, | ||
constraints: BoxConstraints(maxHeight: _height), | ||
border: _border, | ||
focusedBorder: _border, | ||
enabledBorder: _border, | ||
disabledBorder: _border, | ||
), | ||
), | ||
), | ||
_getButton(increase: true), | ||
].divide(const SizedBox(width: ZetaSpacing.x2)).toList(), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters