This commit is contained in:
2026-05-24 16:25:51 +08:00
parent 4ad57dc1cf
commit feed9b898a
4 changed files with 42 additions and 16 deletions

View File

@@ -92,6 +92,7 @@ class _HomePageState extends State<HomePage> {
Future<void> _performLogout() async {
setState(() => _loggingOut = true);
await Future.delayed(const Duration(seconds: 5));
try {
if (TitleServerConfigHolder().isConfigured && _data != null && _data!.isLogin) {
final service = TitleApiService(TitleServerConfigHolder().config!);
@@ -114,17 +115,21 @@ class _HomePageState extends State<HomePage> {
appBar: AppBar(
title: Text(_tabTitles[_currentTab]),
actions: [
IconButton(
icon: _loggingOut
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.logout),
tooltip: AppStrings.logoutTooltip,
onPressed: _loggingOut ? null : _performLogout,
),
if (_loggingOut)
const Padding(
padding: EdgeInsets.only(right: 12),
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
)
else
IconButton(
icon: const Icon(Icons.logout),
tooltip: AppStrings.logoutTooltip,
onPressed: _performLogout,
),
],
),
body: IndexedStack(

View File

@@ -206,6 +206,9 @@ class _TicketPageState extends State<TicketPage> {
// ignore: avoid_print
print('[TICKET] user already logged in, force-logout stale session...');
try {
print('[TICKET] force-logout: waiting 5s...');
await Future.delayed(const Duration(seconds: 5));
print('[TICKET] force-logout: sending...');
await service.userLogout(userId: userId, loginDateTime: DateTime.now().millisecondsSinceEpoch ~/ 1000);
// ignore: avoid_print
print('[TICKET] force-logout done');
@@ -226,6 +229,11 @@ class _TicketPageState extends State<TicketPage> {
// ignore: avoid_print
print('[TICKET] loginId=$loginId lastLoginDate=$lastLoginDate loginDateTime=$loginTimestamp newToken=${loginResult.token}');
// Wait 60s after LoginPacket for stability
// ignore: avoid_print
print('[TICKET] waiting 60s after LoginPacket...');
await Future.delayed(const Duration(seconds: 60));
// Step 3: Get user data (for playerRating)
// ignore: avoid_print
print('[TICKET] ── Step 3: getUserData ──');
@@ -324,6 +332,9 @@ class _TicketPageState extends State<TicketPage> {
print('[TICKET] ── Step 7: userLogout (loginId=$loginId, loginTimestamp=$loginTimestamp) ──');
try {
_updateStep(TicketStep.logout);
print('[TICKET] ── Step 7: userLogout ── waiting 5s...');
await Future.delayed(const Duration(seconds: 5));
print('[TICKET] ── Step 7: userLogout ── sending...');
await service.userLogout(userId: userId, loginDateTime: loginTimestamp);
// ignore: avoid_print
print('[TICKET] userLogout OK');

View File

@@ -90,10 +90,16 @@ class TitleApiService {
}
Map<String, dynamic> _processResponseBody(Uint8List bodyBytes) {
final decrypted = _aesDecrypt(bodyBytes);
final decompressed = _decompress(decrypted);
final jsonStr = utf8.decode(decompressed);
return jsonDecode(jsonStr) as Map<String, dynamic>;
try {
final decrypted = _aesDecrypt(bodyBytes);
final decompressed = _decompress(decrypted);
final jsonStr = utf8.decode(decompressed);
return jsonDecode(jsonStr) as Map<String, dynamic>;
} on FormatException catch (e) {
throw TitleApiException('Response body is not valid JSON: $e');
} on Exception catch (e) {
throw TitleApiException('Failed to process response body: $e');
}
}
String _buildHash(String apiName) {
@@ -155,6 +161,10 @@ class TitleApiService {
throw TitleApiException('$apiName returned ${response.statusCode}');
}
if (response.bodyBytes.isEmpty) {
throw TitleApiException('$apiName returned empty body');
}
final json = _processResponseBody(response.bodyBytes);
final raw = const JsonEncoder.withIndent(' ').convert(json);
// ignore: avoid_print