mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-02-11 17:50:23 +00:00
feat: L10n for party room
* Initial plan * Fix l10n_gen multi-line string bug and add localization strings for party_room and splash modules Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com> * Fix const/import issues in l10n_replace output Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com> * Fix comment issues found in code review Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>
This commit is contained in:
@@ -232,7 +232,7 @@ class PartyRoomUIModel extends _$PartyRoomUIModel {
|
||||
/// 完成注册
|
||||
Future<void> completeRegister() async {
|
||||
if (state.registerGameUserId.isEmpty) {
|
||||
throw Exception('游戏ID不能为空');
|
||||
throw Exception(S.current.party_room_game_id_empty);
|
||||
}
|
||||
|
||||
state = state.copyWith(isLoading: true, errorMessage: null);
|
||||
@@ -338,4 +338,4 @@ class PartyRoomUIModel extends _$PartyRoomUIModel {
|
||||
void setMinimized(bool minimized) {
|
||||
state = state.copyWith(isMinimized: minimized);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ class PartyRoomGameLogTrackerProvider extends _$PartyRoomGameLogTrackerProvider
|
||||
}
|
||||
} catch (e) {
|
||||
// 游戏未启动或发生错误
|
||||
state = state.copyWith(location: '<游戏未启动>', gameStartTime: null, kills: 0, deaths: 0);
|
||||
state = state.copyWith(location: S.current.party_room_game_not_started, gameStartTime: null, kills: 0, deaths: 0);
|
||||
}
|
||||
await Future.delayed(const Duration(seconds: 10));
|
||||
}
|
||||
@@ -149,4 +149,4 @@ class PartyRoomGameLogTrackerProvider extends _$PartyRoomGameLogTrackerProvider
|
||||
var path = p.path;
|
||||
return path.replaceAll(r"Bin64\StarCitizen.exe", "Game.log");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
||||
import 'package:starcitizen_doctor/generated/proto/partroom/partroom.pb.dart' as partroom;
|
||||
import 'package:starcitizen_doctor/provider/party_room.dart';
|
||||
import 'package:starcitizen_doctor/generated/l10n.dart';
|
||||
|
||||
/// 创建/编辑房间对话框
|
||||
class CreateRoomDialog extends HookConsumerWidget {
|
||||
@@ -30,7 +31,7 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
|
||||
return ContentDialog(
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.5),
|
||||
title: Text(isEdit ? '编辑房间' : '创建房间'),
|
||||
title: Text(isEdit ? S.current.party_room_edit_room : '创建房间'),
|
||||
content: SizedBox(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
@@ -40,9 +41,9 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
Column(
|
||||
children: [
|
||||
InfoLabel(
|
||||
label: '房间类型',
|
||||
label: S.current.party_room_room_type,
|
||||
child: ComboBox<String>(
|
||||
placeholder: const Text('选择主标签'),
|
||||
placeholder: Text(S.current.party_room_select_main_tag),
|
||||
value: selectedMainTag.value,
|
||||
isExpanded: true,
|
||||
items: partyRoomState.room.tags.values.map((tag) {
|
||||
@@ -84,13 +85,13 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
|
||||
// 子标签 - 始终显示,避免布局跳动
|
||||
InfoLabel(
|
||||
label: '子标签 (可选)',
|
||||
label: S.current.party_room_sub_tag_optional,
|
||||
child: ComboBox<String>(
|
||||
placeholder: const Text('选择子标签'),
|
||||
placeholder: Text(S.current.party_room_select_sub_tag),
|
||||
value: selectedSubTag.value,
|
||||
isExpanded: true,
|
||||
items: [
|
||||
const ComboBoxItem(value: null, child: Text('无')),
|
||||
ComboBoxItem(value: null, child: Text(S.current.party_room_none)),
|
||||
if (selectedMainTagData != null)
|
||||
...selectedMainTagData.subTags.map((subTag) {
|
||||
return ComboBoxItem(
|
||||
@@ -132,10 +133,10 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
InfoLabel(
|
||||
label: '目标人数 (2-100)',
|
||||
label: S.current.party_room_target_members,
|
||||
child: TextBox(
|
||||
controller: targetMembersController,
|
||||
placeholder: '输入目标人数',
|
||||
placeholder: S.current.party_room_enter_target_members,
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
),
|
||||
@@ -148,21 +149,21 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
onChanged: (value) {
|
||||
hasPassword.value = value ?? false;
|
||||
},
|
||||
content: const Text('设置密码'),
|
||||
content: Text(S.current.party_room_set_password),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// 密码输入框 - 始终显示,避免布局跳动
|
||||
InfoLabel(
|
||||
label: '房间密码',
|
||||
label: S.current.party_room_room_password,
|
||||
child: TextBox(
|
||||
controller: passwordController,
|
||||
placeholder: isEdit
|
||||
? "为空则不更新密码,取消勾选则取消密码"
|
||||
? S.current.party_room_password_empty_hint
|
||||
: hasPassword.value
|
||||
? '输入密码'
|
||||
: '未启用密码',
|
||||
? S.current.party_room_enter_password
|
||||
: S.current.party_room_password_disabled,
|
||||
obscureText: hasPassword.value,
|
||||
maxLines: 1,
|
||||
maxLength: 12,
|
||||
@@ -172,10 +173,10 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
InfoLabel(
|
||||
label: '社交链接 (可选)',
|
||||
label: S.current.party_room_social_links_optional,
|
||||
child: TextBox(
|
||||
controller: socialLinksController,
|
||||
placeholder: '以 https:// 开头,目前仅支持 qq、discord、kook、oopz 链接',
|
||||
placeholder: S.current.party_room_social_links_placeholder,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
@@ -193,8 +194,8 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('请选择房间类型'),
|
||||
title: Text(S.current.app_common_tip),
|
||||
content: Text(S.current.party_room_select_room_type),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
);
|
||||
@@ -206,8 +207,8 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('目标人数必须在 2-100 之间'),
|
||||
title: Text(S.current.app_common_tip),
|
||||
content: Text(S.current.party_room_target_members_range),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
);
|
||||
@@ -219,8 +220,8 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('请输入密码'),
|
||||
title: Text(S.current.app_common_tip),
|
||||
content: Text(S.current.party_room_enter_password_required),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
);
|
||||
@@ -234,7 +235,7 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
// 检查是否为 https 开头的链接
|
||||
final invalidLinks = socialLinks.where((link) => !link.startsWith('https://')).toList();
|
||||
if (invalidLinks.isNotEmpty) {
|
||||
showToast(context, "链接格式错误!");
|
||||
showToast(context, S.current.party_room_link_format_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -270,7 +271,7 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: Text(isEdit ? '更新失败' : '创建失败'),
|
||||
title: Text(isEdit ? S.current.party_room_update_failed : '创建失败'),
|
||||
content: Text(e.toString()),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
@@ -280,9 +281,9 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
},
|
||||
child: isCreating.value
|
||||
? const SizedBox(width: 16, height: 16, child: ProgressRing(strokeWidth: 2))
|
||||
: Text(isEdit ? '保存' : '创建'),
|
||||
: Text(isEdit ? S.current.party_room_save : '创建'),
|
||||
),
|
||||
Button(onPressed: isCreating.value ? null : () => Navigator.pop(context), child: const Text('取消')),
|
||||
Button(onPressed: isCreating.value ? null : () => Navigator.pop(context), child: Text(S.current.home_action_cancel)),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -308,4 +309,4 @@ class CreateRoomDialog extends HookConsumerWidget {
|
||||
return Colors.grey;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,16 +36,16 @@ class _PartyRoomDetailPageState extends ConsumerState<PartyRoomDetailPage> {
|
||||
|
||||
final result = await showBaseDialog(
|
||||
context,
|
||||
title: '连接已断开',
|
||||
content: const Text('与房间服务器的连接已断开,是否重新连接?'),
|
||||
title: S.current.party_room_disconnected,
|
||||
content: Text(S.current.party_room_reconnect_prompt),
|
||||
actions: [
|
||||
Button(
|
||||
onPressed: () => Navigator.of(context).pop('leave'),
|
||||
child: const Padding(padding: EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8), child: Text('退出房间')),
|
||||
child: Padding(padding: const EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8), child: Text(S.current.party_room_exit_room)),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.of(context).pop('reconnect'),
|
||||
child: const Padding(padding: EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8), child: Text('重新连接')),
|
||||
child: Padding(padding: const EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8), child: Text(S.current.party_room_reconnect)),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -165,4 +165,4 @@ class _PartyRoomDetailPageState extends ConsumerState<PartyRoomDetailPage> {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
||||
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/widgets/create_room_dialog.dart';
|
||||
import 'package:starcitizen_doctor/generated/l10n.dart';
|
||||
|
||||
/// 房间信息头部组件
|
||||
class PartyRoomHeader extends ConsumerWidget {
|
||||
@@ -40,7 +41,7 @@ class PartyRoomHeader extends ConsumerWidget {
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
room?.ownerGameId ?? '房间',
|
||||
room?.ownerGameId ?? S.current.party_room_room,
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -70,7 +71,7 @@ class PartyRoomHeader extends ConsumerWidget {
|
||||
builder: (context) => CreateRoomDialog(roomInfo: room),
|
||||
);
|
||||
},
|
||||
child: const Text('编辑房间'),
|
||||
child: Text(S.current.party_room_edit_room),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -80,13 +81,13 @@ class PartyRoomHeader extends ConsumerWidget {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('确认解散'),
|
||||
content: const Text('确定要解散房间吗?所有成员将被移出。'),
|
||||
title: Text(S.current.party_room_confirm_dismiss),
|
||||
content: Text(S.current.party_room_dismiss_confirm_msg),
|
||||
actions: [
|
||||
Button(child: const Text('取消'), onPressed: () => Navigator.pop(context, false)),
|
||||
Button(child: Text(S.current.home_action_cancel), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(
|
||||
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(const Color(0xFFDA373C))),
|
||||
child: const Text('解散', style: TextStyle(color: Colors.white)),
|
||||
child: Text(S.current.party_room_dismiss, style: TextStyle(color: Colors.white)),
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
),
|
||||
],
|
||||
@@ -104,7 +105,7 @@ class PartyRoomHeader extends ConsumerWidget {
|
||||
return const Color(0xFFDA373C);
|
||||
}),
|
||||
),
|
||||
child: const Text('解散房间', style: TextStyle(color: Colors.white)),
|
||||
child: Text(S.current.party_room_dismiss_room, style: TextStyle(color: Colors.white)),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -115,7 +116,7 @@ class PartyRoomHeader extends ConsumerWidget {
|
||||
width: double.infinity,
|
||||
child: Button(
|
||||
onPressed: () async {
|
||||
final userOK = await showConfirmDialogs(context, "提示", Text("确认离开房间吗?"));
|
||||
final userOK = await showConfirmDialogs(context, S.current.app_common_tip, Text(S.current.party_room_leave_confirm));
|
||||
if (!userOK) return;
|
||||
await partyRoom.leaveRoom();
|
||||
},
|
||||
@@ -133,7 +134,7 @@ class PartyRoomHeader extends ConsumerWidget {
|
||||
return const Color(0xFFDBDEE1);
|
||||
}),
|
||||
),
|
||||
child: const Text('离开房间'),
|
||||
child: Text(S.current.party_room_leave_room),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -141,4 +142,4 @@ class PartyRoomHeader extends ConsumerWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:starcitizen_doctor/generated/proto/partroom/partroom.pb.dart';
|
||||
import 'package:starcitizen_doctor/provider/party_room.dart';
|
||||
import 'package:starcitizen_doctor/ui/party_room/utils/party_room_utils.dart';
|
||||
import 'package:starcitizen_doctor/widgets/src/cache_image.dart';
|
||||
import 'package:starcitizen_doctor/generated/l10n.dart';
|
||||
|
||||
/// 成员列表侧边栏
|
||||
class PartyRoomMemberList extends ConsumerWidget {
|
||||
@@ -18,7 +19,7 @@ class PartyRoomMemberList extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
if (members.isEmpty) {
|
||||
return Center(
|
||||
child: Text('暂无成员', style: TextStyle(color: Colors.white.withValues(alpha: 0.5), fontSize: 12)),
|
||||
child: Text(S.current.party_room_no_members, style: TextStyle(color: Colors.white.withValues(alpha: 0.5), fontSize: 12)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ class PartyRoomMemberItem extends ConsumerWidget {
|
||||
// 复制ID - 所有用户可用
|
||||
MenuFlyoutItem(
|
||||
leading: const Icon(FluentIcons.copy, size: 16),
|
||||
text: const Text('复制游戏ID'),
|
||||
text: Text(S.current.party_room_copy_game_id),
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(ClipboardData(text: member.gameUserId));
|
||||
},
|
||||
@@ -144,16 +145,16 @@ class PartyRoomMemberItem extends ConsumerWidget {
|
||||
const MenuFlyoutSeparator(),
|
||||
MenuFlyoutItem(
|
||||
leading: const Icon(FluentIcons.people, size: 16),
|
||||
text: const Text('转移房主'),
|
||||
text: Text(S.current.party_room_transfer_owner),
|
||||
onPressed: () async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('转移房主'),
|
||||
title: Text(S.current.party_room_transfer_owner),
|
||||
content: Text('确定要将房主转移给 ${member.handleName.isNotEmpty ? member.handleName : member.gameUserId} 吗?'),
|
||||
actions: [
|
||||
Button(child: const Text('取消'), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: const Text('转移'), onPressed: () => Navigator.pop(context, true)),
|
||||
Button(child: Text(S.current.home_action_cancel), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: Text(S.current.party_room_transfer), onPressed: () => Navigator.pop(context, true)),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -165,7 +166,7 @@ class PartyRoomMemberItem extends ConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('操作失败'),
|
||||
title: Text(S.current.party_room_operation_failed),
|
||||
content: Text('转移房主失败:$e'),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
@@ -177,18 +178,18 @@ class PartyRoomMemberItem extends ConsumerWidget {
|
||||
),
|
||||
MenuFlyoutItem(
|
||||
leading: const Icon(FluentIcons.remove_from_shopping_list, size: 16),
|
||||
text: const Text('踢出成员'),
|
||||
text: Text(S.current.party_room_kick_member),
|
||||
onPressed: () async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('踢出成员'),
|
||||
title: Text(S.current.party_room_kick_member),
|
||||
content: Text('确定要踢出 ${member.handleName.isNotEmpty ? member.handleName : member.gameUserId} 吗?'),
|
||||
actions: [
|
||||
Button(child: const Text('取消'), onPressed: () => Navigator.pop(context, false)),
|
||||
Button(child: Text(S.current.home_action_cancel), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(
|
||||
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(const Color(0xFFDA373C))),
|
||||
child: const Text('踢出'),
|
||||
child: Text(S.current.party_room_kick),
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
),
|
||||
],
|
||||
@@ -202,7 +203,7 @@ class PartyRoomMemberItem extends ConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('操作失败'),
|
||||
title: Text(S.current.party_room_operation_failed),
|
||||
content: Text('踢出成员失败:$e'),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
@@ -244,4 +245,4 @@ class PartyRoomMemberItem extends ConsumerWidget {
|
||||
);
|
||||
return avatarWidget;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import 'package:starcitizen_doctor/ui/party_room/utils/party_room_utils.dart';
|
||||
import 'package:starcitizen_doctor/widgets/src/cache_image.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:starcitizen_doctor/generated/l10n.dart';
|
||||
|
||||
/// 消息列表组件
|
||||
class PartyRoomMessageList extends ConsumerWidget {
|
||||
@@ -31,7 +32,7 @@ class PartyRoomMessageList extends ConsumerWidget {
|
||||
children: [
|
||||
Icon(FluentIcons.chat, size: 64, color: Colors.white.withValues(alpha: .6)),
|
||||
const SizedBox(height: 16),
|
||||
Text('暂无消息', style: TextStyle(color: Colors.white.withValues(alpha: 0.5), fontSize: 14)),
|
||||
Text(S.current.party_room_no_messages, style: TextStyle(color: Colors.white.withValues(alpha: 0.5), fontSize: 14)),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -79,10 +80,10 @@ class PartyRoomMessageList extends ConsumerWidget {
|
||||
child: const Icon(FluentIcons.info, size: 14, color: Colors.white),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Expanded(
|
||||
Expanded(
|
||||
child: Text(
|
||||
'该房间包含第三方社交链接,点击加入自由交流吧~',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFFDBDEE1), fontWeight: FontWeight.w500),
|
||||
S.current.party_room_social_links_hint,
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFFDBDEE1), fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -137,10 +138,10 @@ class PartyRoomMessageList extends ConsumerWidget {
|
||||
child: const Icon(FluentIcons.copy, size: 14, color: Colors.white),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Expanded(
|
||||
Expanded(
|
||||
child: Text(
|
||||
'复制房主的游戏ID,可在游戏首页添加好友,快速组队',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFFDBDEE1), fontWeight: FontWeight.w500),
|
||||
S.current.party_room_copy_owner_id_hint,
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFFDBDEE1), fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -170,9 +171,9 @@ class PartyRoomMessageList extends ConsumerWidget {
|
||||
return const Color(0xFF5865F2);
|
||||
}),
|
||||
),
|
||||
child: const Text(
|
||||
'复制',
|
||||
style: TextStyle(fontSize: 13, color: Colors.white, fontWeight: FontWeight.w500),
|
||||
child: Text(
|
||||
S.current.support_dev_copy_button,
|
||||
style: const TextStyle(fontSize: 13, color: Colors.white, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -193,7 +194,7 @@ class PartyRoomMessageList extends ConsumerWidget {
|
||||
if (link.contains('discord')) return 'Discord';
|
||||
if (link.contains('kook')) return 'KOOK';
|
||||
if (link.contains('qq')) return 'QQ';
|
||||
return '链接';
|
||||
return S.current.party_room_link;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,8 +271,8 @@ class _MessageItem extends ConsumerWidget {
|
||||
String userName,
|
||||
String? avatarUrl,
|
||||
) {
|
||||
final location = roomEvent.signalParams['location'] ?? '未知位置';
|
||||
final area = roomEvent.signalParams['area'] ?? '未知区域';
|
||||
final location = roomEvent.signalParams['location'] ?? S.current.party_room_unknown_location;
|
||||
final area = roomEvent.signalParams['area'] ?? S.current.party_room_unknown_area;
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
@@ -322,18 +323,18 @@ class _MessageItem extends ConsumerWidget {
|
||||
child: const Icon(FluentIcons.status_error_full, size: 14, color: Color(0xFFED4245)),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'玩家死亡',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFFED4245), fontWeight: FontWeight.w600),
|
||||
Text(
|
||||
S.current.party_room_player_death,
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFFED4245), fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 位置信息
|
||||
_buildInfoRow(icon: FluentIcons.location, label: '位置', value: location),
|
||||
_buildInfoRow(icon: FluentIcons.location, label: S.current.party_room_location, value: location),
|
||||
const SizedBox(height: 8),
|
||||
// 区域信息
|
||||
_buildInfoRow(icon: FluentIcons.map_pin, label: '区域', value: area),
|
||||
_buildInfoRow(icon: FluentIcons.map_pin, label: S.current.party_room_area, value: area),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -365,7 +366,7 @@ class _MessageItem extends ConsumerWidget {
|
||||
String _getEventUserName(partroom.RoomEvent event) {
|
||||
switch (event.type) {
|
||||
case partroom.RoomEventType.SIGNAL_BROADCAST:
|
||||
return event.signalSender.isNotEmpty ? event.signalSender : '未知用户';
|
||||
return event.signalSender.isNotEmpty ? event.signalSender : S.current.party_room_unknown_user;
|
||||
case partroom.RoomEventType.MEMBER_JOINED:
|
||||
case partroom.RoomEventType.MEMBER_LEFT:
|
||||
case partroom.RoomEventType.MEMBER_KICKED:
|
||||
@@ -373,11 +374,11 @@ class _MessageItem extends ConsumerWidget {
|
||||
? event.member.handleName
|
||||
: event.hasMember()
|
||||
? event.member.gameUserId
|
||||
: '未知用户';
|
||||
: S.current.party_room_unknown_user;
|
||||
case partroom.RoomEventType.OWNER_CHANGED:
|
||||
return event.hasMember() && event.member.handleName.isNotEmpty ? event.member.handleName : '新房主';
|
||||
return event.hasMember() && event.member.handleName.isNotEmpty ? event.member.handleName : S.current.party_room_new_owner;
|
||||
default:
|
||||
return '系统';
|
||||
return S.current.party_room_system;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,19 +409,19 @@ class _MessageItem extends ConsumerWidget {
|
||||
}
|
||||
return signalType?.name ?? event.signalId;
|
||||
case partroom.RoomEventType.MEMBER_JOINED:
|
||||
return '加入了房间';
|
||||
return S.current.party_room_joined_room;
|
||||
case partroom.RoomEventType.MEMBER_LEFT:
|
||||
return '离开了房间';
|
||||
return S.current.party_room_left_room;
|
||||
case partroom.RoomEventType.OWNER_CHANGED:
|
||||
return '成为了新房主';
|
||||
return S.current.party_room_became_owner;
|
||||
case partroom.RoomEventType.ROOM_UPDATED:
|
||||
return '房间信息已更新';
|
||||
return S.current.party_room_info_updated;
|
||||
case partroom.RoomEventType.MEMBER_STATUS_UPDATED:
|
||||
return null;
|
||||
case partroom.RoomEventType.ROOM_DISMISSED:
|
||||
return '房间已解散';
|
||||
return S.current.party_room_dismissed;
|
||||
case partroom.RoomEventType.MEMBER_KICKED:
|
||||
return '被踢出房间';
|
||||
return S.current.party_room_kicked;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -433,7 +434,7 @@ class _MessageItem extends ConsumerWidget {
|
||||
final diff = now.difference(date);
|
||||
|
||||
if (diff.inMinutes < 1) {
|
||||
return '刚刚';
|
||||
return S.current.party_room_just_now;
|
||||
} else if (diff.inMinutes < 60) {
|
||||
return '${diff.inMinutes} 分钟前';
|
||||
} else if (diff.inHours < 24) {
|
||||
@@ -465,4 +466,4 @@ class _MessageItem extends ConsumerWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:starcitizen_doctor/provider/party_room.dart';
|
||||
import 'package:starcitizen_doctor/generated/l10n.dart';
|
||||
|
||||
/// 信号发送器组件
|
||||
class PartyRoomSignalSender extends ConsumerWidget {
|
||||
@@ -25,7 +26,7 @@ class PartyRoomSignalSender extends ConsumerWidget {
|
||||
const Spacer(),
|
||||
DropDownButton(
|
||||
leading: const Icon(FluentIcons.send, size: 16),
|
||||
title: Text(signalTypes.isEmpty ? '加载中...' : '发送信号'),
|
||||
title: Text(signalTypes.isEmpty ? S.current.party_room_loading : '发送信号'),
|
||||
disabled: signalTypes.isEmpty || room == null,
|
||||
items: signalTypes.map((signal) {
|
||||
return MenuFlyoutItem(
|
||||
@@ -52,7 +53,7 @@ class PartyRoomSignalSender extends ConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('发送失败'),
|
||||
title: Text(S.current.party_room_send_failed),
|
||||
content: Text(e.toString()),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
@@ -60,4 +61,4 @@ class PartyRoomSignalSender extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:starcitizen_doctor/generated/l10n.dart';
|
||||
import 'package:starcitizen_doctor/ui/party_room/party_room_ui_model.dart';
|
||||
|
||||
/// 连接服务器页面
|
||||
@@ -40,14 +41,14 @@ class PartyRoomConnectPage extends HookConsumerWidget {
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// 标题
|
||||
const Text(
|
||||
'组队大厅',
|
||||
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0), letterSpacing: 2),
|
||||
Text(
|
||||
S.current.party_room_title,
|
||||
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0), letterSpacing: 2),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// 副标题
|
||||
Text('正在连接服务器...', style: TextStyle(fontSize: 14, color: Colors.white.withValues(alpha: 0.7))),
|
||||
Text(S.current.party_room_connecting, style: TextStyle(fontSize: 14, color: Colors.white.withValues(alpha: 0.7))),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// 加载动画
|
||||
@@ -66,13 +67,13 @@ class PartyRoomConnectPage extends HookConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Row(
|
||||
Row(
|
||||
children: [
|
||||
Icon(FluentIcons.error_badge, color: Color(0xFFFF6B6B), size: 16),
|
||||
SizedBox(width: 8),
|
||||
const Icon(FluentIcons.error_badge, color: Color(0xFFFF6B6B), size: 16),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'连接失败',
|
||||
style: TextStyle(color: Color(0xFFFF6B6B), fontWeight: FontWeight.bold),
|
||||
S.current.party_room_connect_failed,
|
||||
style: const TextStyle(color: Color(0xFFFF6B6B), fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -83,7 +84,7 @@ class PartyRoomConnectPage extends HookConsumerWidget {
|
||||
onPressed: () async {
|
||||
await uiModel.connectToServer();
|
||||
},
|
||||
child: const Text('重试'),
|
||||
child: Text(S.current.party_room_retry),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -95,4 +96,4 @@ class PartyRoomConnectPage extends HookConsumerWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'您正在以游客身份浏览,登录后可创建或加入房间。',
|
||||
S.current.party_room_guest_mode_hint,
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: 0.8)),
|
||||
),
|
||||
),
|
||||
@@ -78,7 +78,7 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
onPressed: () {
|
||||
ref.read(partyRoomUIModelProvider.notifier).exitGuestMode();
|
||||
},
|
||||
child: const Text('登录', style: TextStyle(fontSize: 12)),
|
||||
child: Text(S.current.party_room_login, style: TextStyle(fontSize: 12)),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -91,7 +91,7 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
Expanded(
|
||||
child: TextBox(
|
||||
controller: searchController,
|
||||
placeholder: '搜索房主名称...',
|
||||
placeholder: S.current.party_room_search_owner,
|
||||
prefix: const Padding(padding: EdgeInsets.only(left: 8), child: Icon(FluentIcons.search)),
|
||||
onSubmitted: (value) {
|
||||
uiModel.loadRoomList(searchName: value, page: 1);
|
||||
@@ -105,9 +105,9 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
const SizedBox(width: 12),
|
||||
FilledButton(
|
||||
onPressed: () => _showCreateRoomDialog(context, ref),
|
||||
child: const Row(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [Icon(FluentIcons.add, size: 16), SizedBox(width: 8), Text('创建房间')],
|
||||
children: [const Icon(FluentIcons.add, size: 16), const SizedBox(width: 8), Text(S.current.party_room_create_room)],
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -140,7 +140,7 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
padding: const EdgeInsets.all(16),
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Tooltip(
|
||||
message: '返回当前房间',
|
||||
message: S.current.party_room_return_to_room,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
ref.read(partyRoomUIModelProvider.notifier).setMinimized(false);
|
||||
@@ -177,10 +177,10 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
final tags = partyRoomState.room.tags;
|
||||
|
||||
return ComboBox<String>(
|
||||
placeholder: const Text('选择标签'),
|
||||
placeholder: Text(S.current.party_room_select_tag),
|
||||
value: uiState.selectedMainTagId,
|
||||
items: [
|
||||
const ComboBoxItem(value: null, child: Text('全部标签')),
|
||||
ComboBoxItem(value: null, child: Text(S.current.party_room_all_tags)),
|
||||
...tags.values.map((tag) => ComboBoxItem(value: tag.id, child: Text(tag.name))),
|
||||
],
|
||||
onChanged: (value) {
|
||||
@@ -213,7 +213,7 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
onPressed: () {
|
||||
ref.read(partyRoomUIModelProvider.notifier).refreshRoomList();
|
||||
},
|
||||
child: const Text('重试'),
|
||||
child: Text(S.current.party_room_retry),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -229,17 +229,17 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
uiState.searchOwnerName.isNotEmpty
|
||||
? '没有找到符合条件的房间'
|
||||
? S.current.party_room_no_matching_room
|
||||
: uiState.selectedMainTagId != null
|
||||
? '当前分类下没有房间'
|
||||
: '暂无可用房间',
|
||||
? S.current.party_room_no_room_in_category
|
||||
: S.current.party_room_no_available_room,
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: 0.7)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (uiState.searchOwnerName.isEmpty) ...[
|
||||
Text('成为第一个创建房间的人吧!', style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: 0.5))),
|
||||
Text(S.current.party_room_be_first_create, style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: 0.5))),
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(onPressed: () => _showCreateRoomDialog(context, ref), child: const Text('创建房间')),
|
||||
FilledButton(onPressed: () => _showCreateRoomDialog(context, ref), child: Text(S.current.party_room_create_room)),
|
||||
],
|
||||
],
|
||||
),
|
||||
@@ -264,7 +264,7 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
child: Center(
|
||||
child: uiState.isLoading
|
||||
? const ProgressRing()
|
||||
: Text('已加载全部房间', style: TextStyle(color: Colors.white.withValues(alpha: 0.5))),
|
||||
: Text(S.current.party_room_all_loaded, style: TextStyle(color: Colors.white.withValues(alpha: 0.5))),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -431,11 +431,11 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
final shouldLogin = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('需要登录'),
|
||||
content: const Text('创建房间需要先登录账号,是否现在去登录?'),
|
||||
title: Text(S.current.party_room_need_login),
|
||||
content: Text(S.current.party_room_create_need_login),
|
||||
actions: [
|
||||
Button(child: const Text('取消'), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: const Text('去登录'), onPressed: () => Navigator.pop(context, true)),
|
||||
Button(child: Text(S.current.home_action_cancel), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: Text(S.current.party_room_go_login), onPressed: () => Navigator.pop(context, true)),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -451,11 +451,11 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
final shouldLeave = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('创建新房间'),
|
||||
content: const Text('你已经在其他房间中,创建新房间将自动退出当前房间。是否继续?'),
|
||||
title: Text(S.current.party_room_create_new_room),
|
||||
content: Text(S.current.party_room_already_in_room_create),
|
||||
actions: [
|
||||
Button(child: const Text('取消'), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: const Text('继续'), onPressed: () => Navigator.pop(context, true)),
|
||||
Button(child: Text(S.current.home_action_cancel), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: Text(S.current.party_room_continue), onPressed: () => Navigator.pop(context, true)),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -478,11 +478,11 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
final shouldLogin = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('需要登录'),
|
||||
content: const Text('加入房间需要先登录账号,是否现在去登录?'),
|
||||
title: Text(S.current.party_room_need_login),
|
||||
content: Text(S.current.party_room_join_need_login),
|
||||
actions: [
|
||||
Button(child: const Text('取消'), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: const Text('去登录'), onPressed: () => Navigator.pop(context, true)),
|
||||
Button(child: Text(S.current.home_action_cancel), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: Text(S.current.party_room_go_login), onPressed: () => Navigator.pop(context, true)),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -506,11 +506,11 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('切换房间'),
|
||||
content: const Text('你已经在其他房间中,加入新房间将自动退出当前房间。是否继续?'),
|
||||
title: Text(S.current.party_room_switch_room),
|
||||
content: Text(S.current.party_room_already_in_room_join),
|
||||
actions: [
|
||||
Button(child: const Text('取消'), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: const Text('继续'), onPressed: () => Navigator.pop(context, true)),
|
||||
Button(child: Text(S.current.home_action_cancel), onPressed: () => Navigator.pop(context, false)),
|
||||
FilledButton(child: Text(S.current.party_room_continue), onPressed: () => Navigator.pop(context, true)),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -533,14 +533,14 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
builder: (context) {
|
||||
final passwordController = TextEditingController();
|
||||
return ContentDialog(
|
||||
title: const Text('输入房间密码'),
|
||||
title: Text(S.current.party_room_enter_room_password),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [TextBox(controller: passwordController, placeholder: '请输入密码', obscureText: true)],
|
||||
children: [TextBox(controller: passwordController, placeholder: S.current.party_room_enter_password_required, obscureText: true)],
|
||||
),
|
||||
actions: [
|
||||
Button(child: const Text('取消'), onPressed: () => Navigator.pop(context)),
|
||||
FilledButton(child: const Text('加入'), onPressed: () => Navigator.pop(context, passwordController.text)),
|
||||
Button(child: Text(S.current.home_action_cancel), onPressed: () => Navigator.pop(context)),
|
||||
FilledButton(child: Text(S.current.party_room_join), onPressed: () => Navigator.pop(context, passwordController.text)),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -561,7 +561,7 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('加入失败'),
|
||||
title: Text(S.current.party_room_join_failed),
|
||||
content: Text(e.toString()),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
@@ -569,4 +569,4 @@ class PartyRoomListPage extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:starcitizen_doctor/ui/party_room/party_room_ui_model.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:starcitizen_doctor/generated/l10n.dart';
|
||||
|
||||
/// 注册页面
|
||||
class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
@@ -34,10 +35,10 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
},
|
||||
icon: Padding(padding: const EdgeInsets.all(8.0), child: Icon(FluentIcons.back, size: 24)),
|
||||
),
|
||||
const Expanded(
|
||||
Expanded(
|
||||
child: Text(
|
||||
'注册账号',
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
S.current.party_room_register_title,
|
||||
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -46,7 +47,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
|
||||
if (uiState.errorMessage != null) ...[
|
||||
InfoBar(
|
||||
title: const Text('错误'),
|
||||
title: Text(S.current.party_room_error),
|
||||
content: Text(uiState.errorMessage!),
|
||||
severity: InfoBarSeverity.error,
|
||||
onClose: () => uiModel.clearError(),
|
||||
@@ -60,7 +61,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
_buildStepIndicator(
|
||||
context,
|
||||
number: 1,
|
||||
title: '输入游戏ID',
|
||||
title: S.current.party_room_step_enter_game_id,
|
||||
isActive: currentStep.value == 0,
|
||||
isCompleted: currentStep.value > 0,
|
||||
),
|
||||
@@ -68,7 +69,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
_buildStepIndicator(
|
||||
context,
|
||||
number: 2,
|
||||
title: '验证RSI账号',
|
||||
title: S.current.party_room_step_verify_rsi,
|
||||
isActive: currentStep.value == 1,
|
||||
isCompleted: currentStep.value > 1,
|
||||
),
|
||||
@@ -76,7 +77,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
_buildStepIndicator(
|
||||
context,
|
||||
number: 3,
|
||||
title: '完成注册',
|
||||
title: S.current.party_room_step_complete,
|
||||
isActive: currentStep.value == 2,
|
||||
isCompleted: false,
|
||||
),
|
||||
@@ -95,8 +96,8 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
|
||||
InfoBar(
|
||||
title: const Text('关于账号验证'),
|
||||
content: const Text('接下来,您需要在 RSI 账号简介中添加验证码以证明账号所有权,验证通过后,您可以移除该验证码。'),
|
||||
title: Text(S.current.party_room_about_verification),
|
||||
content: Text(S.current.party_room_verification_hint),
|
||||
severity: InfoBarSeverity.info,
|
||||
),
|
||||
],
|
||||
@@ -159,21 +160,20 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
ValueNotifier<int> currentStep,
|
||||
) {
|
||||
return [
|
||||
const Text(
|
||||
'步骤 1: 输入您的游戏ID',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
Text(
|
||||
S.current.party_room_step1_title,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'请输入您在星际公民中的游戏ID(Handle),'
|
||||
'这是您在游戏中使用的唯一标识符。',
|
||||
S.current.party_room_step1_desc,
|
||||
style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.6)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
TextBox(
|
||||
controller: gameIdController,
|
||||
placeholder: '例如: Citizen123',
|
||||
placeholder: S.current.party_room_game_id_example,
|
||||
enabled: !uiState.isLoading,
|
||||
onSubmitted: (value) async {
|
||||
if (value.trim().isEmpty) return;
|
||||
@@ -189,7 +189,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
onPressed: () {
|
||||
launchUrlString('https://robertsspaceindustries.com/en/account/dashboard');
|
||||
},
|
||||
child: const Text('查看我的游戏ID'),
|
||||
child: Text(S.current.party_room_view_game_id),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
FilledButton(
|
||||
@@ -201,8 +201,8 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('请输入游戏ID'),
|
||||
title: Text(S.current.app_common_tip),
|
||||
content: Text(S.current.party_room_enter_game_id),
|
||||
actions: [FilledButton(child: const Text('确定'), onPressed: () => Navigator.pop(context))],
|
||||
),
|
||||
);
|
||||
@@ -212,7 +212,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
},
|
||||
child: uiState.isLoading
|
||||
? const SizedBox(width: 16, height: 16, child: ProgressRing(strokeWidth: 2))
|
||||
: const Text('下一步'),
|
||||
: Text(S.current.party_room_next_step),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -241,12 +241,12 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
ValueNotifier<int> currentStep,
|
||||
) {
|
||||
return [
|
||||
const Text(
|
||||
'步骤 2: 验证 RSI 账号',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
Text(
|
||||
S.current.party_room_step2_title,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text('请按照以下步骤完成账号验证:', style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.6))),
|
||||
Text(S.current.party_room_step2_desc, style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.6))),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
Container(
|
||||
@@ -259,9 +259,9 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'1. 复制以下验证码:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
Text(
|
||||
S.current.party_room_copy_code,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
@@ -285,25 +285,25 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'2. 访问您的 RSI 账号资设置页',
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
Text(
|
||||
S.current.party_room_visit_rsi,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Button(
|
||||
onPressed: () {
|
||||
launchUrlString('https://robertsspaceindustries.com/en/account/profile');
|
||||
},
|
||||
child: const Text('打开资料页'),
|
||||
child: Text(S.current.party_room_open_profile),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'3. 编辑您的个人简介,将验证码添加到简介中',
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
Text(
|
||||
S.current.party_room_edit_bio,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'在简介的任意位置添加验证码即可,验证码30分钟内有效',
|
||||
S.current.party_room_code_validity,
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: 0.5)),
|
||||
),
|
||||
],
|
||||
@@ -318,7 +318,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
onPressed: () {
|
||||
currentStep.value = 0;
|
||||
},
|
||||
child: const Text('上一步'),
|
||||
child: Text(S.current.party_room_prev_step),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: uiState.isLoading
|
||||
@@ -328,7 +328,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
},
|
||||
child: uiState.isLoading
|
||||
? const SizedBox(width: 16, height: 16, child: ProgressRing(strokeWidth: 2))
|
||||
: const Text('我已添加,验证并注册'),
|
||||
: Text(S.current.party_room_verify_register),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -356,15 +356,15 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
children: [
|
||||
const Icon(FluentIcons.completed_solid, size: 64, color: Color(0xFF4CAF50)),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'注册成功!',
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
Text(
|
||||
S.current.party_room_register_success,
|
||||
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text('您已成功注册组队大厅,现在可以开始使用了', style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.6))),
|
||||
Text(S.current.party_room_register_success_msg, style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.6))),
|
||||
],
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,15 +100,15 @@ class SplashUI extends HookConsumerWidget {
|
||||
Text('诊断模式 - Step $currentStep', style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
|
||||
Row(
|
||||
children: [
|
||||
Button(onPressed: () => _loadDPrintLog(diagnosticLogs), child: const Text('读取完整日志')),
|
||||
Button(onPressed: () => _loadDPrintLog(diagnosticLogs), child: Text(S.current.splash_read_full_log)),
|
||||
const SizedBox(width: 8),
|
||||
Button(onPressed: () => _resetHiveDatabase(context), child: const Text('重置数据库')),
|
||||
Button(onPressed: () => _resetHiveDatabase(context), child: Text(S.current.splash_reset_database)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text('初始化任务执行情况:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
|
||||
Text(S.current.splash_init_task_status, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
|
||||
const SizedBox(height: 12),
|
||||
Expanded(
|
||||
child: ValueListenableBuilder<List<String>>(
|
||||
@@ -122,7 +122,7 @@ class SplashUI extends HookConsumerWidget {
|
||||
border: Border.all(color: Colors.grey),
|
||||
),
|
||||
child: logs.isEmpty
|
||||
? const Center(child: Text('等待日志...'))
|
||||
? Center(child: Text(S.current.splash_waiting_log))
|
||||
: ListView.builder(
|
||||
itemCount: logs.length,
|
||||
itemBuilder: (context, index) {
|
||||
@@ -130,7 +130,7 @@ class SplashUI extends HookConsumerWidget {
|
||||
Color textColor = Colors.white;
|
||||
if (log.contains('✓')) {
|
||||
textColor = Colors.green;
|
||||
} else if (log.contains('✗') || log.contains('超时') || log.contains('错误')) {
|
||||
} else if (log.contains('✗') || log.contains(S.current.splash_timeout) || log.contains(S.current.splash_error)) {
|
||||
textColor = Colors.red;
|
||||
} else if (log.contains('⚠')) {
|
||||
textColor = Colors.orange;
|
||||
@@ -169,95 +169,95 @@ class SplashUI extends HookConsumerWidget {
|
||||
addLog('[${DateTime.now().toIso8601String()}] 开始初始化...');
|
||||
|
||||
// Step 0: initApp with timeout
|
||||
addLog('执行 appModel.initApp()...');
|
||||
addLog(S.current.splash_exec_app_init);
|
||||
try {
|
||||
await appModel.initApp().timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () {
|
||||
addLog('✗ appModel.initApp() 超时 (10秒)');
|
||||
addLog(S.current.splash_app_init_timeout);
|
||||
throw TimeoutException('initApp timeout');
|
||||
},
|
||||
);
|
||||
addLog('✓ appModel.initApp() 完成');
|
||||
addLog(S.current.splash_app_init_done);
|
||||
} catch (e) {
|
||||
addLog('✗ appModel.initApp() 错误: $e');
|
||||
rethrow;
|
||||
}
|
||||
|
||||
// Open app_conf box with timeout
|
||||
addLog('打开 Hive app_conf box...');
|
||||
addLog(S.current.splash_open_hive_box);
|
||||
late Box appConf;
|
||||
try {
|
||||
appConf = await Hive.openBox("app_conf").timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () {
|
||||
addLog('✗ Hive.openBox("app_conf") 超时 (10秒)');
|
||||
addLog(S.current.splash_hive_timeout);
|
||||
throw TimeoutException('openBox timeout');
|
||||
},
|
||||
);
|
||||
addLog('✓ Hive.openBox("app_conf") 完成');
|
||||
addLog(S.current.splash_hive_done);
|
||||
} catch (e) {
|
||||
addLog('✗ Hive.openBox("app_conf") 错误: $e');
|
||||
rethrow;
|
||||
}
|
||||
|
||||
// Check alert info version
|
||||
addLog('检查 splash_alert_info_version...');
|
||||
addLog(S.current.splash_check_version);
|
||||
final v = appConf.get("splash_alert_info_version", defaultValue: 0);
|
||||
addLog('✓ splash_alert_info_version = $v');
|
||||
|
||||
// Analytics touch
|
||||
addLog('执行 AnalyticsApi.touch("launch")...');
|
||||
addLog(S.current.splash_exec_analytics);
|
||||
try {
|
||||
final touchFuture = AnalyticsApi.touch("launch");
|
||||
await touchFuture.timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () {
|
||||
addLog('⚠ AnalyticsApi.touch() 超时 (10秒) - 继续执行');
|
||||
addLog(S.current.splash_analytics_timeout);
|
||||
},
|
||||
);
|
||||
addLog('✓ AnalyticsApi.touch("launch") 完成');
|
||||
addLog(S.current.splash_analytics_done);
|
||||
} catch (e) {
|
||||
addLog('⚠ AnalyticsApi.touch("launch") 错误: $e - 继续执行');
|
||||
}
|
||||
|
||||
// Show alert if needed
|
||||
if (v < _alertInfoVersion) {
|
||||
addLog('需要显示用户协议对话框...');
|
||||
addLog(S.current.splash_show_agreement);
|
||||
if (!context.mounted) {
|
||||
addLog('✗ Context 已卸载,无法显示对话框');
|
||||
addLog(S.current.splash_context_unmounted_dialog);
|
||||
return;
|
||||
}
|
||||
await _showAlert(context, appConf);
|
||||
addLog('✓ 用户协议对话框已处理');
|
||||
addLog(S.current.splash_agreement_handled);
|
||||
}
|
||||
|
||||
// Check host
|
||||
addLog('执行 URLConf.checkHost()...');
|
||||
addLog(S.current.splash_exec_check_host);
|
||||
try {
|
||||
final checkHostFuture = URLConf.checkHost();
|
||||
await checkHostFuture.timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () {
|
||||
addLog('⚠ URLConf.checkHost() 超时 (10秒) - 继续执行');
|
||||
addLog(S.current.splash_check_host_timeout);
|
||||
return false;
|
||||
},
|
||||
);
|
||||
addLog('✓ URLConf.checkHost() 完成');
|
||||
addLog(S.current.splash_check_host_done);
|
||||
} catch (e) {
|
||||
addLog('⚠ URLConf.checkHost() 错误: $e - 继续执行');
|
||||
dPrint("checkHost Error:$e");
|
||||
}
|
||||
|
||||
addLog('--- Step 0 完成,进入 Step 1 ---');
|
||||
addLog(S.current.splash_step0_done);
|
||||
stepState.value = 1;
|
||||
if (!context.mounted) {
|
||||
addLog('✗ Context 已卸载');
|
||||
addLog(S.current.splash_context_unmounted);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 1: Check update
|
||||
addLog('执行 appModel.checkUpdate()...');
|
||||
addLog(S.current.splash_exec_check_update);
|
||||
dPrint("_initApp checkUpdate");
|
||||
try {
|
||||
await appModel
|
||||
@@ -265,37 +265,37 @@ class SplashUI extends HookConsumerWidget {
|
||||
.timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () {
|
||||
addLog('⚠ appModel.checkUpdate() 超时 (10秒) - 继续执行');
|
||||
addLog(S.current.splash_check_update_timeout);
|
||||
return false;
|
||||
},
|
||||
);
|
||||
addLog('✓ appModel.checkUpdate() 完成');
|
||||
addLog(S.current.splash_check_update_done);
|
||||
} catch (e) {
|
||||
addLog('⚠ appModel.checkUpdate() 错误: $e - 继续执行');
|
||||
}
|
||||
|
||||
addLog('--- Step 1 完成,进入 Step 2 ---');
|
||||
addLog(S.current.splash_step1_done);
|
||||
stepState.value = 2;
|
||||
|
||||
// Step 2: Initialize aria2c
|
||||
addLog('初始化 aria2cModelProvider...');
|
||||
addLog(S.current.splash_init_aria2c);
|
||||
dPrint("_initApp aria2cModelProvider");
|
||||
try {
|
||||
ref.read(aria2cModelProvider);
|
||||
addLog('✓ aria2cModelProvider 初始化完成');
|
||||
addLog(S.current.splash_aria2c_done);
|
||||
} catch (e) {
|
||||
addLog('⚠ aria2cModelProvider 初始化错误: $e');
|
||||
}
|
||||
|
||||
if (!context.mounted) {
|
||||
addLog('✗ Context 已卸载,无法导航');
|
||||
addLog(S.current.splash_context_unmounted_nav);
|
||||
return;
|
||||
}
|
||||
|
||||
addLog('✓ 所有初始化完成,准备跳转到主界面');
|
||||
addLog(S.current.splash_all_done);
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
if (!context.mounted) {
|
||||
addLog('✗ Context 已卸载,无法跳转');
|
||||
addLog(S.current.splash_context_unmounted_jump);
|
||||
return;
|
||||
}
|
||||
context.pushReplacement("/index");
|
||||
@@ -348,12 +348,12 @@ class SplashUI extends HookConsumerWidget {
|
||||
|
||||
void _resetHiveDatabase(BuildContext context) async {
|
||||
try {
|
||||
dPrint('[诊断] 用户请求重置数据库');
|
||||
dPrint(S.current.splash_user_reset_db);
|
||||
|
||||
// 关闭所有 Hive box
|
||||
try {
|
||||
await Hive.close();
|
||||
dPrint('[诊断] Hive boxes 已关闭');
|
||||
dPrint(S.current.splash_hive_boxes_closed);
|
||||
} catch (e) {
|
||||
dPrint('[诊断] 关闭 Hive boxes 失败: $e');
|
||||
}
|
||||
@@ -365,16 +365,16 @@ class SplashUI extends HookConsumerWidget {
|
||||
if (await dbDir.exists()) {
|
||||
dPrint('[诊断] 正在删除数据库目录: ${dbDir.path}');
|
||||
await dbDir.delete(recursive: true);
|
||||
dPrint('[诊断] 数据库目录已删除');
|
||||
dPrint(S.current.splash_db_deleted);
|
||||
} else {
|
||||
dPrint('[诊断] 数据库目录不存在: ${dbDir.path}');
|
||||
}
|
||||
|
||||
// 显示提示并退出
|
||||
dPrint('[诊断] 数据库重置完成,准备退出应用');
|
||||
dPrint(S.current.splash_db_reset_done);
|
||||
|
||||
if (context.mounted) {
|
||||
await showToast(context, "数据库已重置,应用将退出。请重新启动应用。");
|
||||
await showToast(context, S.current.splash_db_reset_msg);
|
||||
}
|
||||
|
||||
// 等待一小段时间确保日志写入
|
||||
@@ -382,7 +382,7 @@ class SplashUI extends HookConsumerWidget {
|
||||
|
||||
exit(0);
|
||||
} catch (e) {
|
||||
dPrint('[诊断] 重置数据库失败: $e');
|
||||
dPrint(S.current.splash_reset_db_failed(e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user