mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-01-13 19:50:28 +00:00
feat: Add user profile refresh
This commit is contained in:
parent
724f7d8242
commit
1d59acff2d
@ -277,6 +277,24 @@ class PartyRoom extends _$PartyRoom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 刷新用户资料
|
||||||
|
Future<void> refreshUserProfile() async {
|
||||||
|
try {
|
||||||
|
final client = state.client.authClient;
|
||||||
|
if (client == null) throw Exception('Not connected to server');
|
||||||
|
|
||||||
|
final response = await client.refreshUserProfile(auth.RefreshUserProfileRequest(), options: getAuthCallOptions());
|
||||||
|
|
||||||
|
if (response.success && response.hasUserInfo()) {
|
||||||
|
state = state.copyWith(auth: state.auth.copyWith(userInfo: response.userInfo));
|
||||||
|
dPrint('[PartyRoom] User profile refreshed: ${response.userInfo.gameUserId}');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
dPrint('[PartyRoom] RefreshUserProfile error: $e');
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 房间相关方法 ==========
|
// ========== 房间相关方法 ==========
|
||||||
|
|
||||||
/// 加载标签和信号类型
|
/// 加载标签和信号类型
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:starcitizen_doctor/provider/party_room.dart';
|
|||||||
import 'package:starcitizen_doctor/ui/party_room/party_room_ui_model.dart';
|
import 'package:starcitizen_doctor/ui/party_room/party_room_ui_model.dart';
|
||||||
import 'package:starcitizen_doctor/ui/party_room/utils/party_room_utils.dart';
|
import 'package:starcitizen_doctor/ui/party_room/utils/party_room_utils.dart';
|
||||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||||
|
import 'package:grpc/grpc.dart';
|
||||||
|
|
||||||
class UserAvatarWidget extends HookConsumerWidget {
|
class UserAvatarWidget extends HookConsumerWidget {
|
||||||
final VoidCallback onTapNavigateToPartyRoom;
|
final VoidCallback onTapNavigateToPartyRoom;
|
||||||
@ -52,14 +53,14 @@ class UserAvatarWidget extends HookConsumerWidget {
|
|||||||
child: uiState.isLoggingIn
|
child: uiState.isLoggingIn
|
||||||
? const Padding(padding: EdgeInsets.all(4), child: ProgressRing(strokeWidth: 2))
|
? const Padding(padding: EdgeInsets.all(4), child: ProgressRing(strokeWidth: 2))
|
||||||
: (fullAvatarUrl != null
|
: (fullAvatarUrl != null
|
||||||
? CacheNetImage(url: fullAvatarUrl, fit: BoxFit.cover)
|
? CacheNetImage(url: fullAvatarUrl, fit: BoxFit.cover)
|
||||||
: Center(
|
: Center(
|
||||||
child: Icon(
|
child: Icon(
|
||||||
isLoggedIn ? FluentIcons.contact : FluentIcons.unknown,
|
isLoggedIn ? FluentIcons.contact : FluentIcons.unknown,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@ -85,91 +86,136 @@ class UserAvatarWidget extends HookConsumerWidget {
|
|||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
barrierColor: Colors.transparent,
|
barrierColor: Colors.transparent,
|
||||||
builder: (BuildContext dialogContext) {
|
builder: (BuildContext dialogContext) {
|
||||||
return Stack(
|
return Consumer(
|
||||||
children: [
|
builder: (context, ref, child) {
|
||||||
// 透明遮罩,点击关闭
|
final partyRoomState = ref.watch(partyRoomProvider);
|
||||||
GestureDetector(
|
final userInfo = partyRoomState.auth.userInfo;
|
||||||
onTap: () => Navigator.of(dialogContext).pop(),
|
final displayUserName = userInfo?.gameUserId ?? userName;
|
||||||
child: Container(color: Colors.transparent),
|
final displayAvatarUrl = PartyRoomUtils.getAvatarUrl(userInfo?.avatarUrl);
|
||||||
),
|
final displayEnlistedDate = userInfo?.enlistedDate ?? enlistedDate;
|
||||||
// 账户卡片
|
|
||||||
Positioned(
|
return Stack(
|
||||||
left: offset.dx - 100,
|
children: [
|
||||||
top: offset.dy + (box?.size.height ?? 0) + 8,
|
// 透明遮罩,点击关闭
|
||||||
child: Container(
|
GestureDetector(
|
||||||
width: 360,
|
onTap: () => Navigator.of(dialogContext).pop(),
|
||||||
decoration: BoxDecoration(
|
child: Container(color: Colors.transparent),
|
||||||
color: FluentTheme
|
|
||||||
.of(context)
|
|
||||||
.micaBackgroundColor,
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
border: Border.all(color: Colors.white.withValues(alpha: .1), width: 1),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(color: Colors.black.withValues(alpha: .3), blurRadius: 20, offset: const Offset(0, 8)),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
child: Padding(
|
// 账户卡片
|
||||||
padding: const EdgeInsets.all(16),
|
Positioned(
|
||||||
child: Column(
|
left: offset.dx - 100,
|
||||||
mainAxisSize: MainAxisSize.min,
|
top: offset.dy + (box?.size.height ?? 0) + 8,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Container(
|
||||||
children: [
|
width: 360,
|
||||||
// 用户信息
|
decoration: BoxDecoration(
|
||||||
Row(
|
color: FluentTheme.of(context).micaBackgroundColor,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: Colors.white.withValues(alpha: .1), width: 1),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: .3),
|
||||||
|
blurRadius: 20,
|
||||||
|
offset: const Offset(0, 8),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
// 用户信息
|
||||||
width: 48,
|
Row(
|
||||||
height: 48,
|
children: [
|
||||||
decoration: BoxDecoration(color: Colors.blue, borderRadius: BorderRadius.circular(24)),
|
Container(
|
||||||
child: ClipRRect(
|
width: 48,
|
||||||
borderRadius: BorderRadius.circular(24),
|
height: 48,
|
||||||
child: avatarUrl != null
|
decoration: BoxDecoration(color: Colors.blue, borderRadius: BorderRadius.circular(24)),
|
||||||
? CacheNetImage(url: avatarUrl, fit: BoxFit.cover)
|
child: ClipRRect(
|
||||||
: const Center(child: Icon(FluentIcons.contact, size: 24, color: Colors.white)),
|
borderRadius: BorderRadius.circular(24),
|
||||||
),
|
child: displayAvatarUrl != null
|
||||||
|
? CacheNetImage(url: displayAvatarUrl, fit: BoxFit.cover)
|
||||||
|
: const Center(child: Icon(FluentIcons.contact, size: 24, color: Colors.white)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
displayUserName,
|
||||||
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
'注册时间:${PartyRoomUtils.formatDateTime(displayEnlistedDate)}',
|
||||||
|
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .6)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
const Divider(),
|
||||||
child: Column(
|
const SizedBox(height: 8),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
// 按钮组
|
||||||
children: [
|
Row(
|
||||||
Text(
|
children: [
|
||||||
userName,
|
// 刷新按钮
|
||||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
Expanded(
|
||||||
maxLines: 1,
|
child: Tooltip(
|
||||||
overflow: TextOverflow.ellipsis,
|
message: '每小时仅可刷新一次',
|
||||||
|
child: FilledButton(
|
||||||
|
onPressed: () async {
|
||||||
|
try {
|
||||||
|
await ref.read(partyRoomProvider.notifier).refreshUserProfile();
|
||||||
|
if (context.mounted) {
|
||||||
|
showToast(context, '刷新成功');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
if (e is GrpcError && e.code == StatusCode.resourceExhausted) {
|
||||||
|
showToast(context, '资料刷新过于频繁,请一小时后再试');
|
||||||
|
} else {
|
||||||
|
showToast(context, '刷新失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text('刷新资料'),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
),
|
||||||
Text(
|
const SizedBox(width: 8),
|
||||||
'注册时间:${PartyRoomUtils.formatDateTime(enlistedDate)}',
|
// 注销按钮
|
||||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .6)),
|
Expanded(
|
||||||
|
child: FilledButton(
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
await _handleUnregister(context, ref);
|
||||||
|
},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.red)),
|
||||||
|
child: Text(
|
||||||
|
S.current.user_action_unregister,
|
||||||
|
style: const TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
),
|
||||||
const Divider(),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
// 注销按钮
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: FilledButton(
|
|
||||||
onPressed: () async {
|
|
||||||
Navigator.of(dialogContext).pop();
|
|
||||||
await _handleUnregister(context, ref);
|
|
||||||
},
|
|
||||||
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.red)),
|
|
||||||
child: Text(S.current.user_action_unregister, style: const TextStyle(color: Colors.white)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
);
|
||||||
],
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user