|
|
|
|
@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter/rendering.dart';
|
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
import 'package:hmg_patient_app/uitl/utils.dart';
|
|
|
|
|
|
|
|
|
|
typedef OnDone = void Function(String text);
|
|
|
|
|
|
|
|
|
|
@ -80,7 +81,7 @@ class OTPWidget extends StatefulWidget {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixin {
|
|
|
|
|
late AnimationController _highlightAnimationController;
|
|
|
|
|
late AnimationController _highlightAnimationController;
|
|
|
|
|
late FocusNode focusNode;
|
|
|
|
|
String text = "";
|
|
|
|
|
int currentIndex = 0;
|
|
|
|
|
@ -195,6 +196,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Stack(
|
|
|
|
|
fit: StackFit.loose,
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
_otpTextInput(),
|
|
|
|
|
_touchPinBoxRow(),
|
|
|
|
|
@ -223,10 +225,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
|
|
|
|
|
|
|
|
|
|
Widget _otpTextInput() {
|
|
|
|
|
var transparentBorder = OutlineInputBorder(
|
|
|
|
|
borderSide: BorderSide(
|
|
|
|
|
color: Colors.transparent,
|
|
|
|
|
width: 0.0,
|
|
|
|
|
),
|
|
|
|
|
borderSide: BorderSide(color: Colors.transparent, width: 0),
|
|
|
|
|
);
|
|
|
|
|
return Container(
|
|
|
|
|
width: _width,
|
|
|
|
|
@ -238,27 +237,20 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
|
|
|
|
|
controller: widget.controller,
|
|
|
|
|
keyboardType: widget.keyboardType,
|
|
|
|
|
inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null,
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
height: 0.1,
|
|
|
|
|
color: Colors.transparent,
|
|
|
|
|
),
|
|
|
|
|
style: TextStyle(height: 0.1, color: Colors.transparent),
|
|
|
|
|
decoration: InputDecoration(
|
|
|
|
|
contentPadding: EdgeInsets.all(0),
|
|
|
|
|
focusedErrorBorder: transparentBorder,
|
|
|
|
|
errorBorder: transparentBorder,
|
|
|
|
|
disabledBorder: transparentBorder,
|
|
|
|
|
enabledBorder: transparentBorder,
|
|
|
|
|
focusedBorder: transparentBorder,
|
|
|
|
|
counterText: null,
|
|
|
|
|
counterStyle: null,
|
|
|
|
|
helperStyle: TextStyle(
|
|
|
|
|
height: 0.0,
|
|
|
|
|
color: Colors.transparent,
|
|
|
|
|
),
|
|
|
|
|
labelStyle: TextStyle(height: 0.1),
|
|
|
|
|
fillColor: Colors.transparent,
|
|
|
|
|
border: InputBorder.none,
|
|
|
|
|
),
|
|
|
|
|
contentPadding: EdgeInsets.all(0),
|
|
|
|
|
focusedErrorBorder: transparentBorder,
|
|
|
|
|
errorBorder: transparentBorder,
|
|
|
|
|
disabledBorder: transparentBorder,
|
|
|
|
|
enabledBorder: transparentBorder,
|
|
|
|
|
focusedBorder: transparentBorder,
|
|
|
|
|
counterText: null,
|
|
|
|
|
counterStyle: null,
|
|
|
|
|
helperStyle: TextStyle(height: 0.0, color: Colors.transparent),
|
|
|
|
|
labelStyle: TextStyle(height: 0.1),
|
|
|
|
|
fillColor: Colors.transparent,
|
|
|
|
|
border: InputBorder.none),
|
|
|
|
|
cursorColor: Colors.transparent,
|
|
|
|
|
showCursor: false,
|
|
|
|
|
maxLength: widget.maxLength,
|
|
|
|
|
@ -295,83 +287,195 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
|
|
|
|
|
List<Widget> pinCodes = List.generate(widget.maxLength, (int i) {
|
|
|
|
|
return _buildPinCode(i, context);
|
|
|
|
|
});
|
|
|
|
|
return Row(
|
|
|
|
|
children: pinCodes,
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
return SingleChildScrollView(
|
|
|
|
|
// Add this
|
|
|
|
|
scrollDirection: Axis.horizontal, // For horizontal scrolling
|
|
|
|
|
child: Row(
|
|
|
|
|
children: pinCodes,
|
|
|
|
|
mainAxisSize: MainAxisSize.min, // Important when inside a scroll view
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.start, // Or another suitable alignment
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Widget _pinBoxRow(BuildContext context) {
|
|
|
|
|
// _calculateStrList();
|
|
|
|
|
// List<Widget> pinCodes = List.generate(widget.maxLength, (int i) {
|
|
|
|
|
// return _buildPinCode(i, context);
|
|
|
|
|
// });
|
|
|
|
|
// return Row(
|
|
|
|
|
// children: pinCodes,
|
|
|
|
|
// mainAxisSize: MainAxisSize.min,
|
|
|
|
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
Widget _buildPinCode(int i, BuildContext context) {
|
|
|
|
|
Color borderColor;
|
|
|
|
|
Color pinBoxColor = widget.pinBoxColor;
|
|
|
|
|
final bool isFilled = i < text.length;
|
|
|
|
|
final bool isCurrent = i == currentIndex;
|
|
|
|
|
final bool isFocused = hasFocus && isCurrent;
|
|
|
|
|
|
|
|
|
|
// Colors based on state
|
|
|
|
|
Color bgColor = Colors.white;
|
|
|
|
|
Color borderColor = widget.defaultBorderColor;
|
|
|
|
|
Color textColor = Colors.black;
|
|
|
|
|
|
|
|
|
|
if (widget.hasError) {
|
|
|
|
|
borderColor = widget.errorBorderColor;
|
|
|
|
|
} else if (i < text.length) {
|
|
|
|
|
borderColor = widget.textBorderColor;
|
|
|
|
|
} else {
|
|
|
|
|
borderColor = widget.defaultBorderColor;
|
|
|
|
|
pinBoxColor = widget.pinBoxColor;
|
|
|
|
|
bgColor = Colors.red.shade50;
|
|
|
|
|
} else if (isFocused) {
|
|
|
|
|
borderColor = Colors.transparent;
|
|
|
|
|
bgColor = Colors.white;
|
|
|
|
|
textColor = Colors.white;
|
|
|
|
|
} else if (isFilled) {
|
|
|
|
|
borderColor = Colors.green;
|
|
|
|
|
bgColor = Colors.green;
|
|
|
|
|
textColor = Colors.white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EdgeInsets insets;
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
insets = EdgeInsets.only(
|
|
|
|
|
left: 0,
|
|
|
|
|
top: widget.pinBoxOuterPadding.top,
|
|
|
|
|
right: widget.pinBoxOuterPadding.right,
|
|
|
|
|
bottom: widget.pinBoxOuterPadding.bottom,
|
|
|
|
|
);
|
|
|
|
|
} else if (i == strList.length - 1) {
|
|
|
|
|
insets = EdgeInsets.only(
|
|
|
|
|
left: widget.pinBoxOuterPadding.left,
|
|
|
|
|
top: widget.pinBoxOuterPadding.top,
|
|
|
|
|
right: 0,
|
|
|
|
|
bottom: widget.pinBoxOuterPadding.bottom,
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
insets = widget.pinBoxOuterPadding;
|
|
|
|
|
}
|
|
|
|
|
return Container(
|
|
|
|
|
key: ValueKey<String>("container$i"),
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0),
|
|
|
|
|
margin: insets,
|
|
|
|
|
child: _animatedTextBox(strList[i], i),
|
|
|
|
|
margin: widget.pinBoxOuterPadding,
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: bgColor,
|
|
|
|
|
border: Border.all(
|
|
|
|
|
color: borderColor,
|
|
|
|
|
width: widget.pinBoxBorderWidth,
|
|
|
|
|
),
|
|
|
|
|
color: pinBoxColor,
|
|
|
|
|
borderRadius: BorderRadius.circular(widget.pinBoxRadius),
|
|
|
|
|
borderRadius: BorderRadius.circular(16), // Rounded edges
|
|
|
|
|
),
|
|
|
|
|
width: widget.pinBoxWidth,
|
|
|
|
|
height: widget.pinBoxHeight,
|
|
|
|
|
child: _animatedTextBox(
|
|
|
|
|
strList[i],
|
|
|
|
|
i,
|
|
|
|
|
textColor,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _animatedTextBox(String text, int i) {
|
|
|
|
|
// Widget _buildPinCode(int i, BuildContext context) {
|
|
|
|
|
// Color borderColor;
|
|
|
|
|
// Color pinBoxColor = widget.pinBoxColor;
|
|
|
|
|
//
|
|
|
|
|
// if (widget.hasError) {
|
|
|
|
|
// borderColor = widget.errorBorderColor;
|
|
|
|
|
// } else if (i < text.length) {
|
|
|
|
|
// borderColor = widget.textBorderColor;
|
|
|
|
|
// } else {
|
|
|
|
|
// borderColor = widget.defaultBorderColor;
|
|
|
|
|
// pinBoxColor = widget.pinBoxColor;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// EdgeInsets insets;
|
|
|
|
|
// if (i == 0) {
|
|
|
|
|
// insets = EdgeInsets.only(
|
|
|
|
|
// left: 0,
|
|
|
|
|
// top: widget.pinBoxOuterPadding.top,
|
|
|
|
|
// right: widget.pinBoxOuterPadding.right,
|
|
|
|
|
// bottom: widget.pinBoxOuterPadding.bottom,
|
|
|
|
|
// );
|
|
|
|
|
// } else if (i == strList.length - 1) {
|
|
|
|
|
// insets = EdgeInsets.only(
|
|
|
|
|
// left: widget.pinBoxOuterPadding.left,
|
|
|
|
|
// top: widget.pinBoxOuterPadding.top,
|
|
|
|
|
// right: 0,
|
|
|
|
|
// bottom: widget.pinBoxOuterPadding.bottom,
|
|
|
|
|
// );
|
|
|
|
|
// } else {
|
|
|
|
|
// insets = widget.pinBoxOuterPadding;
|
|
|
|
|
// }
|
|
|
|
|
// return Container(
|
|
|
|
|
// key: ValueKey<String>("container$i"),
|
|
|
|
|
// alignment: Alignment.center,
|
|
|
|
|
// // padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0),
|
|
|
|
|
// margin: insets,
|
|
|
|
|
// child: _animatedTextBox(strList[i], i),
|
|
|
|
|
// decoration: BoxDecoration(
|
|
|
|
|
// border: Border.all(
|
|
|
|
|
// color: borderColor,
|
|
|
|
|
// width: widget.pinBoxBorderWidth,
|
|
|
|
|
// ),
|
|
|
|
|
// color: pinBoxColor,
|
|
|
|
|
// borderRadius: BorderRadius.circular(widget.pinBoxRadius),
|
|
|
|
|
// ),
|
|
|
|
|
// width: widget.pinBoxWidth,
|
|
|
|
|
// height: widget.pinBoxHeight,
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Widget _animatedTextBox(String text, int i) {
|
|
|
|
|
// if (widget.pinTextAnimatedSwitcherTransition != null) {
|
|
|
|
|
// return AnimatedSwitcher(
|
|
|
|
|
// duration: widget.pinTextAnimatedSwitcherDuration,
|
|
|
|
|
// transitionBuilder: widget.pinTextAnimatedSwitcherTransition ??
|
|
|
|
|
// (Widget child, Animation<double> animation) {
|
|
|
|
|
// return child;
|
|
|
|
|
// },
|
|
|
|
|
// child: Text(
|
|
|
|
|
// text,
|
|
|
|
|
// key: ValueKey<String>("$text$i"),
|
|
|
|
|
// style: widget.pinTextStyle,
|
|
|
|
|
// ),
|
|
|
|
|
// );
|
|
|
|
|
// } else {
|
|
|
|
|
// return Text(
|
|
|
|
|
// text,
|
|
|
|
|
// key: ValueKey<String>("${strList[i]}$i"),
|
|
|
|
|
// style: widget.pinTextStyle,
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
Widget _animatedTextBox(String text, int i, Color textColor) {
|
|
|
|
|
final bool isFilled = text.isNotEmpty;
|
|
|
|
|
|
|
|
|
|
final double fontSize = isFilled ? 64 : 64; // Increased when filled
|
|
|
|
|
final FontWeight fontWeight = isFilled ? FontWeight.w600 : FontWeight.normal;
|
|
|
|
|
|
|
|
|
|
if (widget.pinTextAnimatedSwitcherTransition != null) {
|
|
|
|
|
return AnimatedSwitcher(
|
|
|
|
|
duration: widget.pinTextAnimatedSwitcherDuration,
|
|
|
|
|
transitionBuilder: widget.pinTextAnimatedSwitcherTransition ??
|
|
|
|
|
(Widget child, Animation<double> animation) {
|
|
|
|
|
return child;
|
|
|
|
|
},
|
|
|
|
|
transitionBuilder: widget.pinTextAnimatedSwitcherTransition!,
|
|
|
|
|
child: Text(
|
|
|
|
|
text,
|
|
|
|
|
key: ValueKey<String>("$text$i"),
|
|
|
|
|
style: widget.pinTextStyle,
|
|
|
|
|
style: widget.pinTextStyle?.copyWith(color: textColor, fontSize: fontSize, fontWeight: fontWeight, fontFamily: context.fontFamily) ??
|
|
|
|
|
TextStyle(color: textColor, fontSize: fontSize, fontWeight: fontWeight, fontFamily: context.fontFamily),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return Text(
|
|
|
|
|
text,
|
|
|
|
|
key: ValueKey<String>("${strList[i]}$i"),
|
|
|
|
|
style: widget.pinTextStyle,
|
|
|
|
|
style: widget.pinTextStyle?.copyWith(color: textColor, fontSize: fontSize, fontWeight: fontWeight, fontFamily: context.fontFamily) ??
|
|
|
|
|
TextStyle(color: textColor, fontSize: fontSize, fontWeight: fontWeight, fontFamily: context.fontFamily),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Widget _animatedTextBox(String text, int i, Color textColor) {
|
|
|
|
|
// if (widget.pinTextAnimatedSwitcherTransition != null) {
|
|
|
|
|
// return AnimatedSwitcher(
|
|
|
|
|
// duration: widget.pinTextAnimatedSwitcherDuration,
|
|
|
|
|
// transitionBuilder: widget.pinTextAnimatedSwitcherTransition!,
|
|
|
|
|
// child: Text(
|
|
|
|
|
// text,
|
|
|
|
|
// key: ValueKey<String>("$text$i"),
|
|
|
|
|
// style: widget.pinTextStyle?.copyWith(color: textColor) ??
|
|
|
|
|
// TextStyle(color: textColor, fontSize: 24, fontWeight: FontWeight.bold),
|
|
|
|
|
// ),
|
|
|
|
|
// );
|
|
|
|
|
// } else {
|
|
|
|
|
// return Text(
|
|
|
|
|
// text,
|
|
|
|
|
// key: ValueKey<String>("${strList[i]}$i"),
|
|
|
|
|
// style: widget.pinTextStyle?.copyWith(color: textColor) ??
|
|
|
|
|
// TextStyle(color: textColor, fontSize: 24, fontWeight: FontWeight.bold),
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|