Files
record-tool/lib/features/auth/pages/page_auth.dart
T
2026-07-29 18:06:53 +08:00

270 lines
8.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:recording_tool/app/router/app_navigator.dart';
import 'package:recording_tool/core/cache/app_storage.dart';
import 'package:recording_tool/core/cache/storage_keys.dart';
import 'package:recording_tool/core/utils/device_utils.dart';
import 'package:recording_tool/features/auth/view_model_auth/view_model_auth.dart';
import 'package:recording_tool/features/scan_qrcode/pages/page_scan_qrcode.dart';
import 'package:recording_tool/gen/assets.gen.dart';
import 'package:recording_tool/shared/widgets/app_dialog.dart';
import 'package:recording_tool/shared/widgets/app_toast.dart';
class AuthPageWidget extends ConsumerStatefulWidget {
const AuthPageWidget({super.key});
@override
ConsumerState<AuthPageWidget> createState() => _AuthPageWidgetState();
}
class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
late final TextEditingController _controller;
/// 记录点击次数
int _clickCount = 0;
@override
void initState() {
super.initState();
_controller = TextEditingController(text: '');
WidgetsBinding.instance.addPostFrameCallback((_) async {
final token = AppStorage.getString(StorageKeys.authToken);
if (token?.isNotEmpty ?? false) {
final success = await ref
.read(authProvider.notifier)
.parseTokenSetState();
if (!success) {
return;
}
AppNavigator.push(const ScanQrCodePage());
}
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _showDeviceCodeDialog() async {
final deviceCode = await DeviceUtils.deviceCode();
if (!mounted) return;
AppDialog.confirm(context, title: '设备码:$deviceCode');
}
@override
Widget build(BuildContext context) {
final authState = ref.watch(authProvider);
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.dark.copyWith(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.white,
),
child: Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
Positioned.fill(
child: Image.asset(
_AuthAssets.pageBg,
width: double.infinity,
fit: BoxFit.fill,
),
),
SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.w),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 190.h),
ClipRRect(
borderRadius: BorderRadius.circular(24.r),
child: GestureDetector(
onTap: () {
_clickCount++;
if (_clickCount >= 5) {
_showDeviceCodeDialog();
_clickCount = 0;
}
},
child: Image.asset(
_AuthAssets.appIcon,
width: 82.w,
height: 82.w,
fit: BoxFit.cover,
),
),
),
SizedBox(height: 18.h),
Image.asset(
_AuthAssets.appNameText,
width: 132.w,
height: 28.w,
fit: BoxFit.cover,
),
SizedBox(height: 78.h),
_PassCodeInput(controller: _controller),
SizedBox(height: 20.h),
_GradientConfirmButton(
isLoading: authState.isLoading,
onPressed: _handleSubmit,
),
// SizedBox(height: 20.h),
// AppButton(
// onPressed: () async {
// final deviceCode = await DeviceUtils.deviceCode();
// if (!mounted) return;
// AppDialog.confirm(context, title: '设备码:$deviceCode');
// },
// label: '获取设备码',
// ),
],
),
),
),
),
],
),
),
);
}
Future<void> _handleSubmit() async {
final success = await ref
.read(authProvider.notifier)
.auth(_controller.text);
if (!mounted) return;
if (success) {
_controller.clear();
AppNavigator.push(const ScanQrCodePage());
return;
}
final message = ref.read(authProvider).errorMessage;
if (message != null && message.isNotEmpty) {
AppToast.show(message);
}
}
}
class _PassCodeInput extends StatelessWidget {
const _PassCodeInput({required this.controller});
final TextEditingController controller;
@override
Widget build(BuildContext context) {
return Container(
height: 50.h,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.08),
blurRadius: 10.r,
offset: Offset(0, 2.h),
),
],
),
child: TextField(
controller: controller,
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
maxLength: 6,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(6),
],
style: TextStyle(
color: const Color(0xFF2F3338),
fontSize: 16.sp,
fontWeight: FontWeight.w500,
),
decoration: InputDecoration(
hintText: '请输入执裁口令',
hintStyle: TextStyle(
color: const Color(0xFFB6B9BF),
fontSize: 16.sp,
fontWeight: FontWeight.w400,
),
counterText: '',
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 16.w,
vertical: 14.h,
),
),
),
);
}
}
class _GradientConfirmButton extends StatelessWidget {
const _GradientConfirmButton({
required this.isLoading,
required this.onPressed,
});
final bool isLoading;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return Opacity(
opacity: isLoading ? 0.72 : 1,
child: GestureDetector(
onTap: isLoading ? null : onPressed,
child: Container(
height: 50.h,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.r),
gradient: const LinearGradient(
colors: [Color(0xFF268DFF), Color(0xFF5DD4F6)],
),
boxShadow: [
BoxShadow(
color: const Color(0xFF2196F3).withValues(alpha: 0.28),
blurRadius: 14.r,
offset: Offset(0, 6.h),
),
],
),
child: isLoading
? SizedBox.square(
dimension: 18.r,
child: CircularProgressIndicator(
strokeWidth: 2.r,
valueColor: const AlwaysStoppedAnimation<Color>(
Colors.white,
),
),
)
: Text(
'确定',
style: TextStyle(
color: Colors.white,
fontSize: 16.sp,
fontWeight: FontWeight.w500,
),
),
),
),
);
}
}
class _AuthAssets {
const _AuthAssets._();
static String pageBg = Assets.images.imagePageBg.path;
static String appIcon = Assets.images.imageAppIcon.path;
static String appNameText = Assets.images.imageAppNameText.path;
}