229 lines
6.3 KiB
Dart
229 lines
6.3 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:plan/api/endpoints/user_api.dart';
|
||
import 'package:plan/api/network/safe.dart';
|
||
import 'package:provider/provider.dart';
|
||
|
||
import '../../../providers/app_store.dart';
|
||
import '../../../router/config/route_paths.dart';
|
||
|
||
class LoginCodePage extends StatefulWidget {
|
||
final String email;
|
||
final String password;
|
||
|
||
const LoginCodePage({super.key, required this.email, required this.password});
|
||
|
||
@override
|
||
State<LoginCodePage> createState() => _LoginCodePageState();
|
||
}
|
||
|
||
class _LoginCodePageState extends State<LoginCodePage> {
|
||
final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode());
|
||
final List<TextEditingController> _controllers = List.generate(
|
||
4,
|
||
(_) => TextEditingController(),
|
||
);
|
||
|
||
//倒计时
|
||
int _count = 60;
|
||
Timer? _timer;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_handSendCode();
|
||
_handClear();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_timer?.cancel();
|
||
_handClear();
|
||
super.dispose();
|
||
}
|
||
|
||
///小输入框改变时
|
||
void _onChanged(String value, int index) async {
|
||
//一键复制
|
||
if (value.length == 4) {
|
||
_handlePaste(value);
|
||
}
|
||
//提交
|
||
if (value.isNotEmpty && index == 3) {
|
||
_handSubmit();
|
||
return;
|
||
}
|
||
// 自动跳到下一格
|
||
if (value.length == 1 && index < 3) {
|
||
_focusNodes[index + 1].requestFocus();
|
||
}
|
||
}
|
||
|
||
void _handlePaste(String pastedText) {
|
||
// 只取前4位数字
|
||
final digits = pastedText.replaceAll(RegExp(r'[^0-9]'), '');
|
||
for (int i = 0; i < 4; i++) {
|
||
_controllers[i].text = i < digits.length ? digits[i] : '';
|
||
}
|
||
if (digits.length >= 4) {
|
||
_focusNodes[3].requestFocus();
|
||
_handSubmit();
|
||
} else if (digits.isNotEmpty) {
|
||
_focusNodes[digits.length].requestFocus();
|
||
}
|
||
}
|
||
|
||
///删除键
|
||
void _onDelete(KeyEvent event, int index) {
|
||
if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.backspace) {
|
||
final currentController = _controllers[index];
|
||
if (currentController.text.isEmpty && index > 0) {
|
||
_focusNodes[index - 1].requestFocus();
|
||
_controllers[index - 1].clear();
|
||
}
|
||
}
|
||
}
|
||
|
||
///发送验证码
|
||
void _handSendCode() {
|
||
if (_count != 60) {
|
||
return;
|
||
}
|
||
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
|
||
setState(() {
|
||
_count--;
|
||
});
|
||
if (_count == 0) {
|
||
setState(() {
|
||
_count = 60;
|
||
});
|
||
timer.cancel();
|
||
}
|
||
});
|
||
sendEmailCodeApi(widget.email);
|
||
EasyLoading.showToast("Send success");
|
||
}
|
||
|
||
///提交
|
||
void _handSubmit() async {
|
||
String code = _controllers.map((controller) => controller.text).join();
|
||
if (code.length == 4) {
|
||
EasyLoading.show();
|
||
var res = await safeRequest(
|
||
registerApi(
|
||
widget.email,
|
||
widget.password,
|
||
code,
|
||
),
|
||
onError: (error) {
|
||
_handClear();
|
||
EasyLoading.showToast("Login Error");
|
||
},
|
||
);
|
||
var appStore = context.read<AppStore>();
|
||
await appStore.setInfo(res);
|
||
context.go(RoutePaths.layout);
|
||
}
|
||
}
|
||
|
||
///清空
|
||
void _handClear() {
|
||
for (var controller in _controllers) {
|
||
controller.clear();
|
||
}
|
||
_focusNodes.first.requestFocus();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: Colors.white,
|
||
appBar: AppBar(),
|
||
body: ListView(
|
||
physics: NeverScrollableScrollPhysics(),
|
||
padding: EdgeInsets.all(20),
|
||
children: [
|
||
Container(
|
||
margin: EdgeInsets.only(bottom: 20),
|
||
child: Text(
|
||
"Check your inbox",
|
||
style: Theme.of(context).textTheme.titleLarge,
|
||
),
|
||
),
|
||
Container(
|
||
margin: EdgeInsets.only(bottom: 60),
|
||
child: Text(
|
||
"Verification code has been sent to ${widget.email}",
|
||
style: Theme.of(context).textTheme.labelLarge,
|
||
),
|
||
),
|
||
Row(
|
||
spacing: 20,
|
||
children: List.generate(4, (index) {
|
||
return Expanded(
|
||
child: AspectRatio(
|
||
aspectRatio: 1,
|
||
child: Container(
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||
borderRadius: BorderRadius.circular(10),
|
||
),
|
||
child: KeyboardListener(
|
||
focusNode: FocusNode(),
|
||
onKeyEvent: (event) {
|
||
_onDelete(event, index);
|
||
},
|
||
child: TextField(
|
||
controller: _controllers[index],
|
||
focusNode: _focusNodes[index],
|
||
textAlign: TextAlign.center,
|
||
keyboardType: TextInputType.number,
|
||
maxLength: 4,
|
||
style: TextStyle(fontSize: 32),
|
||
decoration: InputDecoration(
|
||
counterText: "",
|
||
border: InputBorder.none,
|
||
isCollapsed: true,
|
||
),
|
||
onChanged: (value) {
|
||
_onChanged(value, index);
|
||
},
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}),
|
||
),
|
||
Container(
|
||
margin: EdgeInsets.only(top: 30),
|
||
child: Row(
|
||
children: [
|
||
GestureDetector(
|
||
onTap: _handSendCode,
|
||
child: Visibility(
|
||
visible: _count != 60,
|
||
replacement: Text(
|
||
"Resend Code",
|
||
style: Theme.of(context).textTheme.bodySmall,
|
||
),
|
||
child: Text(
|
||
"Resend Code(${_count}s)",
|
||
style: Theme.of(context).textTheme.labelMedium,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|