Files
feature-next-arch/lib/features/my/presentation/web_view/user_info_pages.dart
2026-03-04 21:21:43 +08:00

251 lines
9.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_webrtc/flutter_webrtc.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();
// 优先从 BlocProvider 获取,获取失败则从 GetIt 兜底
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();
}
// 打开修改昵称的底部抽屉
void _openEditNicknameBottomSheet() {
// 修复1:先校验 _myCubit 是否为 null,避免空断言
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) {
final cubit = context.read<MyCubit>();
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: InputDecoration(
border: const OutlineInputBorder(),
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
),
autofocus: true,
enabled: !myState.isLoading,
),
const SizedBox(height: 20),
// 核心:根据 MyState 显示加载/按钮/错误提示
if (myState.isLoading)
const Center(
child: Column(
children: [
CircularProgressIndicator(color: Colors.blue),
SizedBox(height: 8),
Text("修改中...", style: TextStyle(color: Colors.grey)),
],
),
)
else
Column(
children: [
// 修复2:使用 ?. 和 ?? 避免空断言,安全判断错误信息
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;
}
// 移除重复的加载弹窗(由 BlocBuilder 显示加载状态)
await myCubit.updateName(newNickname);
// 成功后由 BlocBuilder 监听状态并处理弹窗关闭和提示
if (context.mounted && myCubit.state.errorMessage!.isEmpty ?? true) {
setState(() {
_nicknameController.text = newNickname;
});
Navigator.pop(context);
// 触发 AuthCubit 重新获取用户信息
}
}
// 扫码绑定设备逻辑(保留)
Future<void> _handleScanAndBind(BuildContext context) async {
final String? qrCode = await Navigator.push<String>(
context,
MaterialPageRoute(
builder: (context) => MobileScanner(
onDetect: (capture) {
final List<Barcode> barcodes = capture.barcodes;
if (barcodes.isNotEmpty) {
final String? code = barcodes.first.rawValue;
if (code != null && code.isNotEmpty) {
Navigator.pop(context, code);
}
}
},
),
),
);
if (qrCode == null || qrCode.isEmpty) return;
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const Center(child: CircularProgressIndicator(color: Color(0xFF1677FF), strokeWidth: 4)),
);
try {
final devicesCubit = _getIt<DevicesCubit>();
// await devicesCubit.bindDevice(qrCode);
if (context.mounted) Navigator.pop(context);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green));
}
} catch (e) {
if (context.mounted) Navigator.pop(context);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('绑定失败:$e'), backgroundColor: Colors.red));
}
}
}
@override
Widget build(BuildContext context) {
return Row(
children: [
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: 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)),
],
);
}
}