Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions lib/screens/chat_detail_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
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();
}
}
Expand Down Expand Up @@ -283,7 +282,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
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() {
Expand Down
6 changes: 5 additions & 1 deletion lib/services/api/tf_api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,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<String, dynamic>? _parseJsonMap(String? result) {
if (result == null) {
Expand Down
8 changes: 3 additions & 5 deletions lib/services/chat_data_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,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(
Expand All @@ -683,7 +682,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(
Expand All @@ -700,7 +698,7 @@ class ChatDataService extends ChangeNotifier {
}

void _addToCacheSilent(String roomId, ChatMessage msg) {
final cached = _messageCache[roomId] ?? [];
final cached = List<ChatMessage>.from(_messageCache[roomId] ?? []);
final exists = _containsMessage(cached, msg);
if (!exists) {
cached.add(msg);
Expand Down Expand Up @@ -734,7 +732,7 @@ class ChatDataService extends ChangeNotifier {
}

void _addToCache(String roomId, ChatMessage msg) {
final cached = _messageCache[roomId] ?? [];
final cached = List<ChatMessage>.from(_messageCache[roomId] ?? []);
final exists = _containsMessage(cached, msg);
if (!exists) {
cached.add(msg);
Expand Down Expand Up @@ -894,7 +892,7 @@ class ChatDataService extends ChangeNotifier {
}

void addSentMessage(String roomId, ChatMessage msg) {
final cached = _messageCache[roomId] ?? [];
final cached = List<ChatMessage>.from(_messageCache[roomId] ?? []);
if (!_containsMessage(cached, msg)) {
cached.add(msg);
cached.sort((a, b) => a.timestamp.compareTo(b.timestamp));
Expand Down
12 changes: 2 additions & 10 deletions lib/services/chat_ws_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -416,11 +416,7 @@ class ChatWsService extends ChangeNotifier {
try {
final payload = <String, dynamic>{
'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));
Expand All @@ -441,11 +437,7 @@ class ChatWsService extends ChangeNotifier {
try {
final payload = <String, dynamic>{
'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));
Expand Down
95 changes: 45 additions & 50 deletions lib/widgets/chat_input_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -257,57 +257,52 @@ class _ChatInputBarState extends State<ChatInputBar>
style: TextStyle(color: colorScheme.onSurfaceVariant, fontSize: 13),
),
const SizedBox(height: 12),
PopupMenuButton<String>(
onSelected: (value) async {
await _handleAttachment(value);
ElevatedButton.icon(
onPressed: () async {
final selected = await showMenu<String>(
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),
),
],
),
Expand Down