[Flutter Input Handling] #flutter #dart #input #handling
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'unit.dart';
const _padding = EdgeInsets.all(16.0);
class ConverterRoute extends StatefulWidget {
final String name;
final Color color;
final List<Unit> units;
const ConverterRoute({
@required this.name,
@required this.color,
@required this.units,
}) : assert(name != null),
assert(color != null),
assert(units != null);
@override
_ConverterRouteState createState() => _ConverterRouteState();
}
class _ConverterRouteState extends State<ConverterRoute> {
Unit _fromValue;
Unit _toValue;
double _inputValue;
String _convertedValue = '';
List<DropdownMenuItem> _unitMenuItems;
bool _showValidationError = false;
@override
void initState() {
super.initState();
_createDropdownMenuItems();
_setDefaults();
}
void _createDropdownMenuItems() {
var newItems = <DropdownMenuItem>[];
for (var unit in widget.units) {
newItems.add(DropdownMenuItem(
value: unit.name,
child: Container(
child: Text(
unit.name,
softWrap: true,
),
),
));
}
setState(() {
_unitMenuItems = newItems;
});
}
void _setDefaults() {
setState(() {
_fromValue = widget.units[0];
_toValue = widget.units[1];
});
}
String _format(double conversion) {
var outputNum = conversion.toStringAsPrecision(7);
if (outputNum.contains('.') && outputNum.endsWith('0')) {
var i = outputNum.length - 1;
while (outputNum[i] == '0') {
i -= 1;
}
outputNum = outputNum.substring(0, i + 1);
}
if (outputNum.endsWith('.')) {
return outputNum.substring(0, outputNum.length - 1);
}
return outputNum;
}
void _updateConversion() {
setState(() {
_convertedValue =
_format(_inputValue * (_toValue.conversion / _fromValue.conversion));
});
}
void _updateInputValue(String input) {
setState(() {
if (input == null || input.isEmpty) {
_convertedValue = '';
} else {
try {
final inputDouble = double.parse(input);
_showValidationError = false;
_inputValue = inputDouble;
_updateConversion();
} on Exception catch (e) {
print('Error: $e');
_showValidationError = true;
}
}
});
}
Unit _getUnit(String unitName) {
return widget.units.firstWhere(
(Unit unit) {
return unit.name == unitName;
},
orElse: null,
);
}
void _updateFromConversion(dynamic unitName) {
setState(() {
_fromValue = _getUnit(unitName);
});
if (_inputValue != null) {
_updateConversion();
}
}
void _updateToConversion(dynamic unitName) {
setState(() {
_toValue = _getUnit(unitName);
});
if (_inputValue != null) {
_updateConversion();
}
}
Widget _createDropdown(String currentValue, ValueChanged<dynamic> onChanged) {
return Container(
margin: EdgeInsets.only(top: 16.0),
decoration: BoxDecoration(
color: Colors.grey[50],
border: Border.all(
color: Colors.grey[400],
width: 1.0,
),
),
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Theme(
data: Theme.of(context).copyWith(
canvasColor: Colors.grey[50],
),
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton(
value: currentValue,
items: _unitMenuItems,
onChanged: onChanged,
style: Theme.of(context).textTheme.title,
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
final input = Padding(
padding: _padding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
style: Theme.of(context).textTheme.display1,
decoration: InputDecoration(
labelStyle: Theme.of(context).textTheme.display1,
errorText: _showValidationError ? 'Invalid number entered' : null,
labelText: 'Input',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(0.0),
),
),
keyboardType: TextInputType.number,
onChanged: _updateInputValue,
),
_createDropdown(_fromValue.name, _updateFromConversion),
],
),
);
final arrows = RotatedBox(
quarterTurns: 1,
child: Icon(
Icons.compare_arrows,
size: 40.0,
),
);
final output = Padding(
padding: _padding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
InputDecorator(
child: Text(
_convertedValue,
style: Theme.of(context).textTheme.display1,
),
decoration: InputDecoration(
labelText: 'Output',
labelStyle: Theme.of(context).textTheme.display1,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(0.0),
),
),
),
_createDropdown(_toValue.name, _updateToConversion),
],
),
);
final converter = Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
input,
arrows,
output,
],
);
return Padding(
padding: _padding,
child: converter,
);
}
}
class $1 extends StatefulWidget {
const $1();
@override
_$2 createState() => _$2();
}
class $2 extends State<$1> {
const $2();
@override
void initState() {
super.initState();
}
void _updateInputValue(String input) {
setState(() {
});
}
Widget build(BuildContext context) {
return Container(
onChanged: _updateInputValue,
);
}
}