From ddf3cdbcd98a57b8540c4ef63b8a9f09d44990ef Mon Sep 17 00:00:00 2001 From: zsz-qwq Date: Fri, 17 Jul 2026 04:34:35 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8D=E6=96=87=E4=BB=B6Bug?= =?UTF-8?q?=E5=B9=B6=E4=BF=9D=E6=8C=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: traeagent --- lib/screens/chat_detail_screen.dart | 5 +- lib/services/api/tf_api_client.dart | 6 +- lib/services/chat_data_service.dart | 8 +-- lib/services/chat_ws_service.dart | 4 +- lib/widgets/chat_input_bar.dart | 87 +++++++++++++++-------------- 5 files changed, 57 insertions(+), 53 deletions(-) diff --git a/lib/screens/chat_detail_screen.dart b/lib/screens/chat_detail_screen.dart index 4137f2e..d477c11 100644 --- a/lib/screens/chat_detail_screen.dart +++ b/lib/screens/chat_detail_screen.dart @@ -176,8 +176,7 @@ class _ChatDetailScreenState extends State { void _onScroll() { if (!_scrollController.hasClients) return; if (_isLoadingOlder || !_hasMoreMessages) return; - // Trigger when user scrolls near the top - if (_scrollController.position.pixels < 50) { + if (_scrollController.position.pixels < 200) { _loadOlder(); } } @@ -256,7 +255,7 @@ class _ChatDetailScreenState extends State { bool get _isNearBottom { if (!_scrollController.hasClients) return true; final pos = _scrollController.position; - return pos.pixels >= pos.maxScrollExtent - 100; + return pos.maxScrollExtent == 0 || pos.pixels >= pos.maxScrollExtent - 200; } void _onChatDataChanged() { diff --git a/lib/services/api/tf_api_client.dart b/lib/services/api/tf_api_client.dart index 8ee4abf..21022c3 100644 --- a/lib/services/api/tf_api_client.dart +++ b/lib/services/api/tf_api_client.dart @@ -577,7 +577,11 @@ class TfApiClient { } } - bool _parseBool(String? result) => result?.endsWith('True') ?? false; + bool _parseBool(String? result) { + if (result == null) return false; + final trimmed = result.trim().toLowerCase(); + return trimmed == 'true' || trimmed.endsWith('true'); + } Map? _parseJsonMap(String? result) { if (result == null) { diff --git a/lib/services/chat_data_service.dart b/lib/services/chat_data_service.dart index 7f14c0a..3a6594c 100644 --- a/lib/services/chat_data_service.dart +++ b/lib/services/chat_data_service.dart @@ -428,7 +428,6 @@ class ChatDataService extends ChangeNotifier { if (uid == null) return; final senderUid = info.senderUid; if (senderUid == null) return; - if (senderUid == uid && info.groupId == null && info.roomId == null) return; final roomId = _roomIdForNotification(info, uid); final msg = ChatMessage.fromNotification( @@ -445,7 +444,6 @@ class ChatDataService extends ChangeNotifier { if (uid == null) return; final senderUid = info.senderUid; if (senderUid == null) return; - if (senderUid == uid && info.groupId == null && info.roomId == null) return; final roomId = _roomIdForNotification(info, uid); final msg = ChatMessage.fromNotification( @@ -458,7 +456,7 @@ class ChatDataService extends ChangeNotifier { } void _addToCacheSilent(String roomId, ChatMessage msg) { - final cached = _messageCache[roomId] ?? []; + final cached = List.from(_messageCache[roomId] ?? []); final exists = _containsMessage(cached, msg); if (!exists) { cached.add(msg); @@ -490,7 +488,7 @@ class ChatDataService extends ChangeNotifier { } void _addToCache(String roomId, ChatMessage msg) { - final cached = _messageCache[roomId] ?? []; + final cached = List.from(_messageCache[roomId] ?? []); final exists = _containsMessage(cached, msg); if (!exists) { cached.add(msg); @@ -589,7 +587,7 @@ class ChatDataService extends ChangeNotifier { } void addSentMessage(String roomId, ChatMessage msg) { - final cached = _messageCache[roomId] ?? []; + final cached = List.from(_messageCache[roomId] ?? []); if (!_containsMessage(cached, msg)) { cached.add(msg); cached.sort((a, b) => a.timestamp.compareTo(b.timestamp)); diff --git a/lib/services/chat_ws_service.dart b/lib/services/chat_ws_service.dart index 942fc78..b3b866d 100644 --- a/lib/services/chat_ws_service.dart +++ b/lib/services/chat_ws_service.dart @@ -342,7 +342,7 @@ class ChatWsService extends ChangeNotifier { try { final payload = { 'type': 'message.file', - 'content': {'send_to': 'U$sendToUid', 'quote': quote, 'file_hashes': fileHash}, + 'content': {'send_to': 'U$sendToUid', 'quote': quote, 'file_hashes': [fileHash]}, }; if (clientMid != null) payload['client_mid'] = clientMid; _sendEncrypted(jsonEncode(payload)); @@ -358,7 +358,7 @@ class ChatWsService extends ChangeNotifier { try { final payload = { 'type': 'message.file', - 'content': {'send_to': 'G$gid', 'quote': quote, 'file_hashes': fileHash}, + 'content': {'send_to': 'G$gid', 'quote': quote, 'file_hashes': [fileHash]}, }; if (clientMid != null) payload['client_mid'] = clientMid; _sendEncrypted(jsonEncode(payload)); diff --git a/lib/widgets/chat_input_bar.dart b/lib/widgets/chat_input_bar.dart index b70b785..23a76a9 100644 --- a/lib/widgets/chat_input_bar.dart +++ b/lib/widgets/chat_input_bar.dart @@ -242,49 +242,52 @@ class _ChatInputBarState extends State with SingleTickerProviderSt style: TextStyle(color: colorScheme.onSurfaceVariant, fontSize: 13), ), const SizedBox(height: 12), - PopupMenuButton( - onSelected: (value) async { - await _handleAttachment(value); + ElevatedButton.icon( + onPressed: () async { + final selected = await showMenu( + context: context, + position: const RelativeRect.fromLTRB(0, 0, 0, 0), + items: [ + PopupMenuItem( + value: 'image', + child: Row(children: [ + const Icon(Icons.image), + const SizedBox(width: 12), + Text(l10n.mediaPickImage), + ]), + ), + PopupMenuItem( + value: 'video', + child: Row(children: [ + const Icon(Icons.videocam), + const SizedBox(width: 12), + Text(l10n.mediaPickVideo), + ]), + ), + PopupMenuItem( + value: 'audio', + child: Row(children: [ + const Icon(Icons.audiotrack), + const SizedBox(width: 12), + Text(l10n.mediaPickAudio), + ]), + ), + PopupMenuItem( + value: 'file', + child: Row(children: [ + const Icon(Icons.file_upload), + const SizedBox(width: 12), + Text(l10n.chatInputUploadFile), + ]), + ), + ], + ); + if (selected != null) { + await _handleAttachment(selected); + } }, - itemBuilder: (context) => [ - PopupMenuItem( - value: 'image', - child: Row(children: [ - const Icon(Icons.image), - const SizedBox(width: 12), - Text(l10n.mediaPickImage), - ]), - ), - PopupMenuItem( - value: 'video', - child: Row(children: [ - const Icon(Icons.videocam), - const SizedBox(width: 12), - Text(l10n.mediaPickVideo), - ]), - ), - PopupMenuItem( - value: 'audio', - child: Row(children: [ - const Icon(Icons.audiotrack), - const SizedBox(width: 12), - Text(l10n.mediaPickAudio), - ]), - ), - PopupMenuItem( - value: 'file', - child: Row(children: [ - const Icon(Icons.file_upload), - const SizedBox(width: 12), - Text(l10n.chatInputUploadFile), - ]), - ), - ], - child: ElevatedButton.icon( - onPressed: null, - icon: const Icon(Icons.add, size: 18), - label: Text(l10n.chatFunctionPickFile), - ), + icon: const Icon(Icons.add, size: 18), + label: Text(l10n.chatFunctionPickFile), ), ], ),