mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-11-13 09:04:09 +01:00
* init commit * buy card UI * buy card detail page * card filter * dropdown button * user auth flow * create order * denomination option * fix searching * denom option fix UI * simulate payment * Update pr_test_build.yml * Update pr_test_build.yml * Implement order expiration handling [skip ci] * refactor code [skip ci] * remove ionia related code [skip ci] * change auth flow * add currency prefix * grid view UI * fix country filter issue * fix underline color * fix fetching card list [skip ci] * list view * update cake pay title * Optimize API usage by fetching CakePay vendors * handle no cards found case * adjust the flow of purchases * UI fixes * fix btc payment data * link extractor * fix fetch next page issue * UI fixes * fix text size * revert base page changes * Revert "revert base page changes" * UI fixes * fix UI * fix link style + localization * update cake pay title * update cake pay subtitle * Update cake_pay_order.dart * revert inject_app_details update
146 lines
5.1 KiB
Dart
146 lines
5.1 KiB
Dart
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
|
import 'package:cake_wallet/typography.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
class NumberTextField extends StatefulWidget {
|
|
final TextEditingController? controller;
|
|
final FocusNode? focusNode;
|
|
final int min;
|
|
final int max;
|
|
final int step;
|
|
final double arrowsWidth;
|
|
final double arrowsHeight;
|
|
final EdgeInsets contentPadding;
|
|
final double borderWidth;
|
|
final ValueChanged<int?>? onChanged;
|
|
|
|
const NumberTextField({
|
|
Key? key,
|
|
this.controller,
|
|
this.focusNode,
|
|
this.min = 0,
|
|
this.max = 999,
|
|
this.step = 1,
|
|
this.arrowsWidth = 24,
|
|
this.arrowsHeight = kMinInteractiveDimension,
|
|
this.contentPadding = const EdgeInsets.symmetric(horizontal: 8),
|
|
this.borderWidth = 2,
|
|
this.onChanged,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
State<StatefulWidget> createState() => _NumberTextFieldState();
|
|
}
|
|
|
|
class _NumberTextFieldState extends State<NumberTextField> {
|
|
late TextEditingController _controller;
|
|
late FocusNode _focusNode;
|
|
bool _canGoUp = false;
|
|
bool _canGoDown = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = widget.controller ?? TextEditingController();
|
|
_focusNode = widget.focusNode ?? FocusNode();
|
|
_updateArrows(int.tryParse(_controller.text));
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(covariant NumberTextField oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
_controller = widget.controller ?? _controller;
|
|
_focusNode = widget.focusNode ?? _focusNode;
|
|
_updateArrows(int.tryParse(_controller.text));
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) => TextField(
|
|
style: textMediumSemiBold(color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
|
enableInteractiveSelection: false,
|
|
textAlign: TextAlign.center,
|
|
textAlignVertical: TextAlignVertical.bottom,
|
|
controller: _controller,
|
|
focusNode: _focusNode,
|
|
textInputAction: TextInputAction.done,
|
|
keyboardType: TextInputType.number,
|
|
maxLength: widget.max.toString().length + (widget.min.isNegative ? 1 : 0),
|
|
decoration: InputDecoration(
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.all(0),
|
|
fillColor: Colors.transparent,
|
|
counterText: '',
|
|
isDense: true,
|
|
filled: true,
|
|
suffixIconConstraints: BoxConstraints(
|
|
maxHeight: widget.arrowsHeight,
|
|
maxWidth: widget.arrowsWidth + widget.contentPadding.right),
|
|
prefixIconConstraints: BoxConstraints(
|
|
maxHeight: widget.arrowsHeight,
|
|
maxWidth: widget.arrowsWidth + widget.contentPadding.left),
|
|
prefixIcon: Material(
|
|
type: MaterialType.transparency,
|
|
child: InkWell(
|
|
child: Container(
|
|
width: widget.arrowsWidth,
|
|
alignment: Alignment.bottomCenter,
|
|
child: Icon(Icons.arrow_left_outlined, size: widget.arrowsWidth)),
|
|
onTap: _canGoDown ? () => _update(false) : null)),
|
|
suffixIcon: Material(
|
|
type: MaterialType.transparency,
|
|
child: InkWell(
|
|
child: Container(
|
|
width: widget.arrowsWidth,
|
|
alignment: Alignment.bottomCenter,
|
|
child: Icon(Icons.arrow_right_outlined, size: widget.arrowsWidth)),
|
|
onTap: _canGoUp ? () => _update(true) : null))),
|
|
maxLines: 1,
|
|
onChanged: (value) {
|
|
final intValue = int.tryParse(value);
|
|
widget.onChanged?.call(intValue);
|
|
_updateArrows(intValue);
|
|
},
|
|
inputFormatters: [_NumberTextInputFormatter(widget.min, widget.max)]);
|
|
|
|
void _update(bool up) {
|
|
var intValue = int.tryParse(_controller.text);
|
|
intValue == null ? intValue = widget.min : intValue += up ? widget.step : -widget.step;
|
|
intValue = intValue.clamp(widget.min, widget.max); // Ensure intValue is within range
|
|
_controller.text = intValue.toString();
|
|
|
|
// Manually call the onChanged callback after updating the controller's text
|
|
widget.onChanged?.call(intValue);
|
|
|
|
_updateArrows(intValue);
|
|
_focusNode.requestFocus();
|
|
}
|
|
|
|
void _updateArrows(int? value) {
|
|
final canGoUp = value == null || value < widget.max;
|
|
final canGoDown = value == null || value > widget.min;
|
|
if (_canGoUp != canGoUp || _canGoDown != canGoDown)
|
|
setState(() {
|
|
_canGoUp = canGoUp;
|
|
_canGoDown = canGoDown;
|
|
});
|
|
}
|
|
}
|
|
|
|
class _NumberTextInputFormatter extends TextInputFormatter {
|
|
final int min;
|
|
final int max;
|
|
|
|
_NumberTextInputFormatter(this.min, this.max);
|
|
|
|
@override
|
|
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
|
if (const ['-', ''].contains(newValue.text)) return newValue;
|
|
final intValue = int.tryParse(newValue.text);
|
|
if (intValue == null) return oldValue;
|
|
if (intValue < min) return newValue.copyWith(text: min.toString());
|
|
if (intValue > max) return newValue.copyWith(text: max.toString());
|
|
return newValue.copyWith(text: intValue.toString());
|
|
}
|
|
}
|