You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

214 line
8.0 KiB

  1. // ignore_for_file: public_member_api_docs, sort_constructors_first
  2. import 'package:flutter/material.dart';
  3. import 'package:go_router/go_router.dart';
  4. import 'package:provider/provider.dart';
  5. import 'package:qadirneyriz/config/config.dart';
  6. import 'package:qadirneyriz/main.dart';
  7. import 'package:qadirneyriz/screens/auth/state/state.dart';
  8. import 'package:qadirneyriz/utils/enums/status.dart';
  9. import 'package:qadirneyriz/utils/timer/apt_simple_timer_with_controller.dart';
  10. import 'package:qadirneyriz/utils/tools/tools.dart';
  11. import 'package:qadirneyriz/widgets/otp_textfield.dart';
  12. import 'package:flutter_gen/gen_l10n/app_localizations.dart';
  13. class OtpScreen extends StatefulWidget {
  14. final String phoneNumber;
  15. const OtpScreen({
  16. super.key,
  17. required this.phoneNumber,
  18. });
  19. @override
  20. State<OtpScreen> createState() => _OtpScreenState();
  21. }
  22. class _OtpScreenState extends State<OtpScreen> {
  23. bool timerEnd = false;
  24. @override
  25. Widget build(BuildContext context) {
  26. return Scaffold(
  27. body: Consumer<AuthState>(
  28. builder: (context, value, child) {
  29. return CustomScrollView(
  30. slivers: <Widget>[
  31. SliverToBoxAdapter(
  32. child: Container(
  33. height: 30,
  34. color: config.ui.mainGreen,
  35. ),
  36. ),
  37. // Header Image with cut-out shape at the bottom
  38. SliverToBoxAdapter(
  39. child: ClipPath(
  40. child: Image.asset(
  41. 'assets/images/template.png',
  42. width: double.infinity,
  43. fit: BoxFit.cover,
  44. ),
  45. ),
  46. ),
  47. SliverPadding(
  48. padding: const EdgeInsets.symmetric(horizontal: 20),
  49. sliver: SliverToBoxAdapter(
  50. child: Container(
  51. padding: const EdgeInsets.all(16),
  52. decoration: BoxDecoration(
  53. color: Colors.white,
  54. borderRadius: BorderRadius.circular(16),
  55. boxShadow: [
  56. BoxShadow(
  57. color:
  58. Colors.black.withOpacity(0.1), // light shadow
  59. blurRadius: 10,
  60. spreadRadius: 5,
  61. ),
  62. ],
  63. ),
  64. child: Column(
  65. children: [
  66. Text(
  67. AppLocalizations.of(context)!.enterotp,
  68. style: TextStyle(
  69. color: config.ui.mainGray,
  70. fontSize: 18,
  71. fontWeight: FontWeight.bold),
  72. ),
  73. const SizedBox(
  74. height: 5,
  75. ),
  76. Text(
  77. AppLocalizations.of(context)!.an4digitotp,
  78. style: TextStyle(
  79. color: config.ui.mainGray.withOpacity(.5),
  80. fontSize: 14,
  81. ),
  82. ),
  83. const SizedBox(
  84. height: 5,
  85. ),
  86. Row(
  87. mainAxisAlignment: MainAxisAlignment.center,
  88. children: [
  89. Text(
  90. widget.phoneNumber,
  91. style: TextStyle(
  92. color: config.ui.mainGray.withOpacity(.5),
  93. fontSize: 16,
  94. fontWeight: FontWeight.bold),
  95. ),
  96. Icon(
  97. Icons.phone_callback_outlined,
  98. color: config.ui.mainGreen,
  99. )
  100. ],
  101. ),
  102. const SizedBox(
  103. height: 10,
  104. ),
  105. OTPTextField(
  106. length: 4,
  107. onSubmitted: (onSubmitted) {
  108. otpCheckCode(onSubmitted, value);
  109. }),
  110. const SizedBox(
  111. height: 20,
  112. ),
  113. Row(
  114. mainAxisAlignment: MainAxisAlignment.center,
  115. children: [
  116. resendOtpbutton(value),
  117. if (!timerEnd)
  118. Directionality(
  119. textDirection: TextDirection.ltr,
  120. child: AptSimpleTimerWithController(
  121. seconds: 60,
  122. fontSize: 16,
  123. timerColor: const Color(0xff8FA5B6)
  124. .withOpacity(0.6),
  125. onTimerEnd: () {
  126. setState(() {
  127. timerEnd = true;
  128. });
  129. },
  130. ),
  131. ),
  132. ],
  133. ),
  134. ],
  135. )),
  136. ),
  137. ),
  138. ],
  139. );
  140. },
  141. ),
  142. );
  143. }
  144. Widget resendOtpbutton(AuthState value) {
  145. return timerEnd
  146. ? GestureDetector(
  147. onTap: value.statusSendotp != Status.loading
  148. ? () async {
  149. final status = await value.sendOtp(
  150. mobile: widget.phoneNumber,
  151. );
  152. if (status == Status.ready) {
  153. setState(() {
  154. timerEnd = false;
  155. });
  156. } else {
  157. Tools.showCustomSnackBar(
  158. text: value.errorsSendOtp == null
  159. ? value.messageSendOtp ?? 'An error has occurred'
  160. : Tools.combineErrorMessages(
  161. value.errorsSendOtp ?? {}),
  162. isError: true,
  163. context,
  164. );
  165. }
  166. }
  167. : null,
  168. child: Text(
  169. value.statusSendotp == Status.loading
  170. ? AppLocalizations.of(context)!.loading
  171. : AppLocalizations.of(context)!.resend,
  172. style: TextStyle(
  173. color: config.ui.secendGreen,
  174. fontSize: 16,
  175. ),
  176. ),
  177. )
  178. : Container();
  179. }
  180. void otpCheckCode(onSubmitted, AuthState value) async {
  181. String? token = await messaging.getToken();
  182. if (onSubmitted.length == 4) {
  183. final status = await value.login(
  184. mobile: widget.phoneNumber, otp: onSubmitted, fcm_token: token ?? '');
  185. if (status == Status.ready) {
  186. context.goNamed('navigate', pathParameters: {'tab': '0'});
  187. } else if (status == Status.error) {
  188. Tools.showCustomSnackBar(
  189. text: value.errorsLogin == null
  190. ? value.messageLogin ?? AppLocalizations.of(context)!.haserror
  191. : Tools.combineErrorMessages(value.errorsLogin ?? {}),
  192. isError: true,
  193. context,
  194. );
  195. setState(() {});
  196. } else if (status == Status.empty) {
  197. Tools.showCustomSnackBar(
  198. text: value.errorsLogin == null
  199. ? value.messageLogin ?? AppLocalizations.of(context)!.haserror
  200. : Tools.combineErrorMessages(value.errorsLogin ?? {}),
  201. isError: true,
  202. context,
  203. );
  204. onSubmitted = '';
  205. }
  206. }
  207. }
  208. }