Files
flutterApp/lib/features/my/presentation/web_view/user_info_pages.dart

327 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:go_router/go_router.dart';
import 'package:maibu_satabot_v2/core/router/route_paths.dart';
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubit.dart';
import 'package:maibu_satabot_v2/features/my/presentation/bloc/my_cubit.dart';
import 'package:maibu_satabot_v2/features/my/presentation/bloc/my_state.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:get_it/get_it.dart';
import '../../../auth/presentation/bloc/auth_cubit.dart';
class UserInfoCard extends StatefulWidget {
final String userName;
final String userId;
const UserInfoCard({super.key, required this.userName, required this.userId});
@override
State<UserInfoCard> createState() => _UserInfoCardState();
}
class _UserInfoCardState extends State<UserInfoCard> {
late TextEditingController _nicknameController;
final GetIt _getIt = GetIt.I;
MyCubit? _myCubit;
@override
void initState() {
super.initState();
try {
_myCubit = BlocProvider.of<MyCubit>(context);
} catch (e) {
debugPrint('从 BlocProvider 获取 MyCubit 失败:$e,尝试从 GetIt 获取');
try {
_myCubit = _getIt<MyCubit>();
} catch (e) {
debugPrint('从 GetIt 获取 MyCubit 也失败:$e');
}
}
_nicknameController = TextEditingController(text: widget.userName);
}
@override
void dispose() {
_nicknameController.dispose();
super.dispose();
}
// ✅ 登录失效提示弹窗 + 2秒后跳登录
void _showSessionExpiredDialog() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => WillPopScope(
onWillPop: () async => false,
child: AlertDialog(
title: const Text('提示'),
content: const Text('登录状态失效,请重新登录!'),
actions: [
Center(
child: TextButton(onPressed: () {}, child: const Text('确定')),
),
],
),
),
);
// 2秒后关闭弹窗并跳登录
Future.delayed(const Duration(seconds: 2), () {
if (mounted) {
Navigator.pop(context); // 关闭弹窗
context.go(RoutePaths.login);
}
});
}
void _openEditNicknameBottomSheet() {
final myCubit = _myCubit;
if (myCubit == null) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Cubit 初始化失败,无法修改昵称'), backgroundColor: Colors.red));
return;
}
showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))),
isScrollControlled: true,
backgroundColor: Colors.transparent,
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.8),
builder: (context) => BlocProvider.value(
value: myCubit,
child: BlocBuilder<MyCubit, MyState>(
builder: (context, myState) {
// ==================== ✅ 核心修复 ====================
if (myState.errorMessage == '登录状态失效,请重新登录') {
WidgetsBinding.instance.addPostFrameCallback((_) {
_showSessionExpiredDialog(); // 弹窗提示,不直接跳转
});
}
return Padding(
padding: EdgeInsets.only(left: 16, right: 16, top: 20, bottom: MediaQuery.of(context).viewInsets.bottom + 80),
child: Container(
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('修改昵称', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
IconButton(padding: EdgeInsets.zero, icon: const Icon(Icons.close, size: 20), onPressed: () => Navigator.pop(context)),
],
),
const SizedBox(height: 16),
const Text('新昵称', style: TextStyle(fontSize: 12, color: Colors.grey)),
const SizedBox(height: 8),
TextField(
controller: _nicknameController,
style: const TextStyle(fontSize: 16),
decoration: const InputDecoration(border: OutlineInputBorder(), contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 10)),
autofocus: true,
enabled: !myState.isLoading,
),
const SizedBox(height: 20),
if (myState.isLoading)
const Center(
child: Column(
children: [
CircularProgressIndicator(color: Colors.blue),
SizedBox(height: 8),
Text("修改中...", style: TextStyle(color: Colors.grey)),
],
),
)
else
Column(
children: [
if (myState.errorMessage?.isNotEmpty ?? false)
Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Text(myState.errorMessage ?? "修改失败", style: const TextStyle(color: Colors.red, fontSize: 14)),
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () => _submitNewNickname(context),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: const Text('确定修改', style: TextStyle(fontSize: 16, color: Colors.white)),
),
),
],
),
],
),
),
),
);
},
),
),
);
}
Future<void> _submitNewNickname(BuildContext context) async {
final newNickname = _nicknameController.text.trim();
if (newNickname.isEmpty) {
Navigator.pop(context);
return;
}
final myCubit = _myCubit;
if (myCubit == null) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Cubit 初始化失败'), backgroundColor: Colors.red));
}
Navigator.pop(context);
return;
}
await myCubit.updateName(newNickname);
if (context.mounted && (myCubit.state.errorMessage?.isEmpty ?? true)) {
setState(() {
_nicknameController.text = newNickname;
});
Navigator.pop(context);
}
}
Future<void> _handleScanAndBind(BuildContext context) async {
bool isScanned = false;
final String? deviceCode = await Navigator.push<String>(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
title: const Text('扫码绑定设备'),
backgroundColor: Colors.black54,
leading: IconButton(icon: const Icon(Icons.close), onPressed: () => Navigator.pop(context)),
),
body: MobileScanner(
onDetect: (BarcodeCapture capture) {
if (isScanned) return;
final List<Barcode> barcodes = capture.barcodes;
if (barcodes.isNotEmpty) {
final String? code = barcodes.first.rawValue;
if (code != null && code.isNotEmpty) {
isScanned = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (context.mounted && Navigator.canPop(context)) {
Navigator.pop(context, code);
}
});
}
}
},
),
),
),
);
if (deviceCode == null || deviceCode.isEmpty) {
return;
}
final bool? confirmBind = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: const Text('确认绑定设备'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [const Text('设备信息:'), const SizedBox(height: 8), Text('设备编码:$deviceCode'), const Text('设备状态:未绑定'), const Text('设备类型:智能设备')],
),
actions: [
TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('取消')),
ElevatedButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('确定绑定'),
style: ElevatedButton.styleFrom(backgroundColor: Colors.blue),
),
],
),
);
if (confirmBind != true) {
return;
}
BuildContext? loadingContext;
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
loadingContext = context;
return const Center(child: CircularProgressIndicator());
},
);
try {
final devicesCubit = GetIt.I<DevicesCubit>();
await devicesCubit.bindDevice(deviceCode, '');
if (loadingContext != null && Navigator.canPop(loadingContext!)) {
Navigator.pop(loadingContext!);
}
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green));
}
} catch (e) {
if (loadingContext != null && Navigator.canPop(loadingContext!)) {
Navigator.pop(loadingContext!);
}
if (context.mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('绑定失败:${e.toString()}'), backgroundColor: Colors.red, duration: const Duration(seconds: 4)));
}
debugPrint('设备绑定失败详情:$e');
}
}
@override
Widget build(BuildContext context) {
return Row(
children: [
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: const DecorationImage(image: NetworkImage('https://pic4.zhimg.com/v2-c34c61a90095abb8713de9d1dca7ec7b_r.jpg'), fit: BoxFit.cover),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_nicknameController.text, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Text('用户 id:${widget.userId}', style: const TextStyle(fontSize: 12, color: Colors.grey)),
],
),
),
IconButton(icon: const Icon(Icons.edit), onPressed: _openEditNicknameBottomSheet),
const Spacer(),
IconButton(icon: const Icon(Icons.add), onPressed: () => _handleScanAndBind(context)),
],
);
}
}