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 '../../profile/controllers/profile_controller.dart'; |
|||
import '../controllers/settings_controller.dart'; |
|||
|
|||
class SettingsBinding extends Bindings { |
|||
@override |
|||
void dependencies() { |
|||
Get.lazyPut<SettingsController>( |
|||
() => SettingsController(), |
|||
); |
|||
Get.lazyPut<SettingsController>(() => SettingsController()); |
|||
Get.lazyPut<ProfileController>(() => ProfileController()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue