Browse Source
- 新增 profile_meeting 路由和视图 - 在会议模块中集成个人信息控制器 - 统一头像显示逻辑 - 移除 SettingsController 中的冗余用户信息管理weicu
9 changed files with 639 additions and 165 deletions
@ -0,0 +1,477 @@ |
|||||
|
import 'dart:io'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import '../controllers/profile_controller.dart'; |
||||
|
|
||||
|
class ProfileMeetingView extends GetView<ProfileController> { |
||||
|
ProfileMeetingView({super.key}); |
||||
|
|
||||
|
// 昵称编辑控制器 - 与 profile_view.dart 保持一致 |
||||
|
final TextEditingController nameController = TextEditingController(); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
|
return Scaffold( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
|
appBar: _buildAppBar(isDarkMode), |
||||
|
body: _buildBody(isDarkMode), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
PreferredSizeWidget _buildAppBar(bool isDarkMode) { |
||||
|
// 初始化 nameController 的文本内容 |
||||
|
nameController.text = controller.userInfo.value.name; |
||||
|
return AppBar( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
|
elevation: 0, |
||||
|
leading: IconButton( |
||||
|
icon: Icon( |
||||
|
Icons.arrow_back_ios, |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
size: 20.w, |
||||
|
), |
||||
|
onPressed: () => Get.back(), |
||||
|
), |
||||
|
title: Text( |
||||
|
'账号和资料', |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
fontSize: 18.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
), |
||||
|
), |
||||
|
centerTitle: true, |
||||
|
actions: [ |
||||
|
Obx(() => Visibility( |
||||
|
visible: controller.hasEdits.value, |
||||
|
child: controller.isUpdating.value |
||||
|
? Padding( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
child: SizedBox( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
child: CircularProgressIndicator( |
||||
|
strokeWidth: 2, |
||||
|
valueColor: AlwaysStoppedAnimation<Color>( |
||||
|
isDarkMode ? Colors.blue[300]! : Colors.blue, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
) |
||||
|
: TextButton( |
||||
|
onPressed: () async { |
||||
|
// 保存用户名和头像 |
||||
|
await controller |
||||
|
.updateUserNameAndAvatar(nameController.text); |
||||
|
// 如果保存成功(没有编辑状态),延迟返回上一级页面让用户看到成功提示 |
||||
|
if (!controller.hasEdits.value) { |
||||
|
// 延迟跳转,让用户看到成功提示 |
||||
|
Future.delayed(const Duration(milliseconds: 500), () { |
||||
|
if (Get.isRegistered<ProfileController>()) { |
||||
|
Get.back(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
child: Text( |
||||
|
'save'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: isDarkMode ? Colors.blue[300] : Colors.blue, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
)) |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildBody(bool isDarkMode) { |
||||
|
return SafeArea( |
||||
|
child: ListView( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w), |
||||
|
children: [ |
||||
|
SizedBox(height: 4.h), |
||||
|
_buildAvatarSection(isDarkMode), |
||||
|
SizedBox(height: 16.h), |
||||
|
_buildNicknameItem(isDarkMode), |
||||
|
Divider( |
||||
|
height: 1.h, |
||||
|
color: isDarkMode ? Colors.grey[800] : Colors.grey[200]), |
||||
|
_buildLoginMethodItem(isDarkMode), |
||||
|
Divider( |
||||
|
height: 1.h, |
||||
|
color: isDarkMode ? Colors.grey[800] : Colors.grey[200]), |
||||
|
_buildManageLoginItem(isDarkMode), |
||||
|
Divider( |
||||
|
height: 1.h, |
||||
|
color: isDarkMode ? Colors.grey[800] : Colors.grey[200]), |
||||
|
SizedBox(height: 32.h), |
||||
|
_buildLogoutButton(isDarkMode), |
||||
|
SizedBox(height: 16.h), |
||||
|
_buildDeleteAccountButton(isDarkMode), |
||||
|
SizedBox(height: 8.h), |
||||
|
_buildWarningText(), |
||||
|
SizedBox(height: 32.h), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildAvatarSection(bool isDarkMode) { |
||||
|
return Center( |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
Obx(() => GestureDetector( |
||||
|
onTap: () => controller.updateUserAvatar(), |
||||
|
child: Stack( |
||||
|
children: [ |
||||
|
CircleAvatar( |
||||
|
radius: 40.r, |
||||
|
backgroundImage: controller.localAvatar.value.isNotEmpty |
||||
|
? FileImage(File(controller.localAvatar.value)) |
||||
|
: (controller.userInfo.value.avatar.isNotEmpty |
||||
|
? NetworkImage(controller.userInfo.value.avatar) |
||||
|
: null) as ImageProvider<Object>?, |
||||
|
backgroundColor: |
||||
|
isDarkMode ? Colors.grey[800] : Colors.grey[200], |
||||
|
child: (controller.localAvatar.value.isEmpty && |
||||
|
controller.userInfo.value.avatar.isEmpty) |
||||
|
? Icon( |
||||
|
Icons.person, |
||||
|
size: 30.r, |
||||
|
color: isDarkMode |
||||
|
? Colors.grey[400] |
||||
|
: Colors.grey[600], |
||||
|
) |
||||
|
: null, |
||||
|
), |
||||
|
Positioned( |
||||
|
bottom: 0, |
||||
|
right: 0, |
||||
|
child: Container( |
||||
|
width: 22.w, |
||||
|
height: 22.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: |
||||
|
isDarkMode ? Colors.grey[600] : Colors.grey[350], |
||||
|
shape: BoxShape.circle, |
||||
|
border: Border.all( |
||||
|
color: isDarkMode ? Colors.black : Colors.white, |
||||
|
width: 0.w, |
||||
|
), |
||||
|
), |
||||
|
child: Icon( |
||||
|
Icons.camera_alt, |
||||
|
size: 14.w, |
||||
|
color: Colors.black, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
)), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 昵称设置项(双模式内联编辑)- 与 profile_view.dart 完全相同的逻辑 |
||||
|
Widget _buildNicknameItem(bool isDarkMode) { |
||||
|
return Obx(() { |
||||
|
// 根据编辑状态显示不同的UI |
||||
|
if (controller.isEditingNickname.value) { |
||||
|
return _buildNicknameEditingMode(isDarkMode, nameController); |
||||
|
} else { |
||||
|
return _buildNicknameDisplayMode(isDarkMode, nameController); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 构建昵称显示模式 - 适配 profile_meeting_view 的 ListTile 样式 |
||||
|
Widget _buildNicknameDisplayMode( |
||||
|
bool isDarkMode, TextEditingController nameController) { |
||||
|
return ListTile( |
||||
|
onTap: () { |
||||
|
// 开始内联编辑 |
||||
|
nameController.text = controller.userInfo.value.name; |
||||
|
controller.startEditingNickname(); |
||||
|
}, |
||||
|
// 禁用水波纹效果 |
||||
|
splashColor: Colors.transparent, |
||||
|
title: Text( |
||||
|
'nickname'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
trailing: Row( |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
children: [ |
||||
|
Obx(() => Text( |
||||
|
controller.userInfo.value.name.isNotEmpty |
||||
|
? controller.userInfo.value.name |
||||
|
: '未设置昵称', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: isDarkMode ? Colors.white : Colors.grey[600], |
||||
|
), |
||||
|
)), |
||||
|
SizedBox(width: 8.w), |
||||
|
Icon( |
||||
|
Icons.arrow_forward_ios, |
||||
|
size: 16.w, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 构建昵称编辑模式 - 适配 profile_meeting_view 的 ListTile 样式 |
||||
|
Widget _buildNicknameEditingMode( |
||||
|
bool isDarkMode, TextEditingController nameController) { |
||||
|
return ListTile( |
||||
|
title: Text( |
||||
|
'nickname'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
trailing: Row( |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
children: [ |
||||
|
// 编辑输入框 - 替换原来的昵称文本显示区域 |
||||
|
Container( |
||||
|
constraints: BoxConstraints( |
||||
|
minWidth: 80.w, // 确保有足够的编辑空间 |
||||
|
maxWidth: 120.w, // 限制最大宽度保持布局稳定 |
||||
|
), |
||||
|
child: TextField( |
||||
|
controller: nameController, |
||||
|
autofocus: true, |
||||
|
textAlign: TextAlign.right, // 右对齐,与原昵称显示保持一致 |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: isDarkMode ? Colors.white : Colors.grey[600], |
||||
|
), |
||||
|
decoration: InputDecoration( |
||||
|
hintText: '输入昵称', |
||||
|
hintStyle: TextStyle( |
||||
|
color: isDarkMode ? Colors.grey[500] : Colors.grey[400], |
||||
|
fontSize: 16.sp, |
||||
|
), |
||||
|
border: InputBorder.none, // 移除边框,保持简洁 |
||||
|
enabledBorder: InputBorder.none, |
||||
|
focusedBorder: InputBorder.none, |
||||
|
contentPadding: EdgeInsets.zero, // 移除内边距 |
||||
|
isDense: true, |
||||
|
), |
||||
|
onSubmitted: (value) { |
||||
|
// 按回车确认编辑 |
||||
|
controller.finishEditingNickname(value); |
||||
|
}, |
||||
|
onTapOutside: (event) { |
||||
|
// 点击外部区域确认编辑 |
||||
|
controller.finishEditingNickname(nameController.text); |
||||
|
}, |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 8.w), |
||||
|
// 保持原有的箭头图标位置,但在编辑模式下可以考虑隐藏或改变 |
||||
|
Icon( |
||||
|
Icons.arrow_forward_ios, |
||||
|
size: 16.w, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildLoginMethodItem(bool isDarkMode) { |
||||
|
return ListTile( |
||||
|
title: Text( |
||||
|
'登录方式', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
trailing: Icon( |
||||
|
Icons.arrow_forward_ios, |
||||
|
size: 16.w, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildManageLoginItem(bool isDarkMode) { |
||||
|
return ListTile( |
||||
|
title: Text( |
||||
|
'管理我的登录', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
trailing: Icon( |
||||
|
Icons.arrow_forward_ios, |
||||
|
size: 16.w, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildLogoutButton(bool isDarkMode) { |
||||
|
return SizedBox( |
||||
|
width: double.infinity, |
||||
|
height: 48.h, |
||||
|
child: OutlinedButton( |
||||
|
onPressed: () => _showLogoutDialog(isDarkMode), |
||||
|
style: OutlinedButton.styleFrom( |
||||
|
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.grey[50], |
||||
|
side: BorderSide( |
||||
|
color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!), |
||||
|
shape: RoundedRectangleBorder( |
||||
|
borderRadius: BorderRadius.circular(8.r), |
||||
|
), |
||||
|
), |
||||
|
child: Text( |
||||
|
'退出登录', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildDeleteAccountButton(bool isDarkMode) { |
||||
|
return SizedBox( |
||||
|
width: double.infinity, |
||||
|
height: 48.h, |
||||
|
child: ElevatedButton( |
||||
|
onPressed: () => _showDeleteAccountDialog(isDarkMode), |
||||
|
style: ElevatedButton.styleFrom( |
||||
|
backgroundColor: Colors.red, |
||||
|
shape: RoundedRectangleBorder( |
||||
|
borderRadius: BorderRadius.circular(8.r), |
||||
|
), |
||||
|
), |
||||
|
child: Text( |
||||
|
'删除账号', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildWarningText() { |
||||
|
return Text( |
||||
|
'警告:您的账号信息和所有文件将被永久删除。', |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: Colors.red, |
||||
|
), |
||||
|
textAlign: TextAlign.center, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
//退出登录提示窗 |
||||
|
void _showLogoutDialog(bool isDarkMode) { |
||||
|
Get.dialog( |
||||
|
AlertDialog( |
||||
|
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
title: Text( |
||||
|
'退出登录', |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
), |
||||
|
), |
||||
|
content: Text( |
||||
|
'确定要退出当前账号吗?\n请确认所有转写任务已完成。', |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
actions: [ |
||||
|
TextButton( |
||||
|
onPressed: () => Get.back(), |
||||
|
child: Text( |
||||
|
'cancel'.tr, |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
TextButton( |
||||
|
onPressed: () { |
||||
|
Get.back(); |
||||
|
controller.signOut(); |
||||
|
}, |
||||
|
child: Text( |
||||
|
'confirm'.tr, |
||||
|
style: const TextStyle( |
||||
|
color: Colors.red, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
void _showDeleteAccountDialog(bool isDarkMode) { |
||||
|
Get.dialog( |
||||
|
AlertDialog( |
||||
|
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
title: Text( |
||||
|
'删除账号', |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
), |
||||
|
), |
||||
|
content: Text( |
||||
|
'警告:您的账号信息和所有文件将被永久删除。', |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
actions: [ |
||||
|
TextButton( |
||||
|
onPressed: () => Get.back(), |
||||
|
child: Text( |
||||
|
'取消', |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
TextButton( |
||||
|
onPressed: () { |
||||
|
Get.back(); |
||||
|
controller.deleteAccount(); |
||||
|
}, |
||||
|
child: Text( |
||||
|
'comfirm'.tr, |
||||
|
style: const TextStyle( |
||||
|
color: Colors.red, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -1,11 +1,11 @@ |
|||||
import 'package:get/get.dart'; |
import 'package:get/get.dart'; |
||||
|
import '../../profile/controllers/profile_controller.dart'; |
||||
import '../controllers/settings_controller.dart'; |
import '../controllers/settings_controller.dart'; |
||||
|
|
||||
class SettingsBinding extends Bindings { |
class SettingsBinding extends Bindings { |
||||
@override |
@override |
||||
void dependencies() { |
void dependencies() { |
||||
Get.lazyPut<SettingsController>( |
Get.lazyPut<SettingsController>(() => SettingsController()); |
||||
() => SettingsController(), |
Get.lazyPut<ProfileController>(() => ProfileController()); |
||||
); |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue