moved roomserver chat into chat_screen

This commit is contained in:
Winston Lowe 2026-01-09 23:44:42 -08:00
parent f3aef42331
commit ab7cc84db5
3 changed files with 65 additions and 1252 deletions

View file

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
@ -162,13 +163,12 @@ class _ChatScreenState extends State<ChatScreen> {
body: Consumer<MeshCoreConnector>(
builder: (context, connector, child) {
final messages = connector.getMessages(widget.contact);
return Column(
children: [
Expanded(
child: messages.isEmpty
? _buildEmptyState()
: _buildMessageList(messages),
: _buildMessageList(messages, connector),
),
_buildInputBar(connector),
],
@ -199,18 +199,29 @@ class _ChatScreenState extends State<ChatScreen> {
);
}
Widget _buildMessageList(List<Message> messages) {
Widget _buildMessageList(List<Message> messages, MeshCoreConnector connector) {
return ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
itemCount: messages.length,
itemBuilder: (context, index) {
Contact contact = widget.contact;
final message = messages[index];
String fourByteHex = '';
if(widget.contact.type == advTypeRoom) {
contact = _resolveContactFrom4Bytes(
connector,
message.fourByteRoomContactKey.isEmpty ? Uint8List.fromList([0, 0, 0, 0]) : message.fourByteRoomContactKey,
);
fourByteHex = message.fourByteRoomContactKey.map((b) => b.toRadixString(16).padLeft(2, '0')).join().toUpperCase();
}
return _MessageBubble(
message: message,
senderName: widget.contact.name,
onTap: () => _openMessagePath(message),
onLongPress: () => _showMessageActions(message),
senderName: widget.contact.type == advTypeRoom ? "${contact.name} [$fourByteHex]" : contact.name,
isRoomServer: widget.contact.type == advTypeRoom,
onTap: () => _openMessagePath(message, contact),
onLongPress: () => _showMessageActions(message, contact),
);
},
);
@ -579,6 +590,13 @@ class _ChatScreenState extends State<ChatScreen> {
);
}
Contact _resolveContactFrom4Bytes(MeshCoreConnector connector, Uint8List key4Bytes) {
return connector.contacts.firstWhere(
(c) => listEquals(c.publicKey.sublist(0, 4), key4Bytes.sublist(0, 4)),
orElse: () => widget.contact,
);
}
String _currentPathLabel(Contact contact) {
// Check if user has set a path override
if (contact.pathOverride != null) {
@ -684,6 +702,15 @@ class _ChatScreenState extends State<ChatScreen> {
);
}
void _openChat(BuildContext context, Contact contact) {
// Check if this is a repeater
context.read<MeshCoreConnector>().markContactRead(contact.publicKeyHex);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ChatScreen(contact: contact)),
);
}
Future<void> _showCustomPathDialog(BuildContext context) async {
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
@ -734,10 +761,11 @@ class _ChatScreenState extends State<ChatScreen> {
}
void _openMessagePath(Message message) {
void _openMessagePath(Message message, Contact contact) {
final connector = context.read<MeshCoreConnector>();
final fourByteHex = message.fourByteRoomContactKey.map((b) => b.toRadixString(16).padLeft(2, '0')).join().toUpperCase();
final senderName =
message.isOutgoing ? (connector.selfName ?? 'Me') : widget.contact.name;
message.isOutgoing ? (connector.selfName ?? 'Me') : widget.contact.type == advTypeRoom ? "${contact.name} [$fourByteHex]" : widget.contact.name;
final pathMessage = ChannelMessage(
senderKey: null,
senderName: senderName,
@ -757,7 +785,7 @@ class _ChatScreenState extends State<ChatScreen> {
);
}
void _showMessageActions(Message message) {
void _showMessageActions(Message message, Contact contact) {
showModalBottomSheet(
context: context,
builder: (sheetContext) => SafeArea(
@ -798,6 +826,14 @@ class _ChatScreenState extends State<ChatScreen> {
_retryMessage(message);
},
),
if(widget.contact.type == advTypeRoom)
ListTile(
leading: const Icon(Icons.chat),
title: const Text('Open Chat'),
onTap: () {
_openChat(context, contact);
},
),
ListTile(
leading: const Icon(Icons.close),
title: const Text('Cancel'),
@ -862,12 +898,14 @@ class _ChatScreenState extends State<ChatScreen> {
class _MessageBubble extends StatelessWidget {
final Message message;
final String senderName;
final bool isRoomServer;
final VoidCallback? onTap;
final VoidCallback? onLongPress;
const _MessageBubble({
required this.message,
required this.senderName,
required this.isRoomServer,
this.onTap,
this.onLongPress,
});
@ -886,7 +924,10 @@ class _MessageBubble extends StatelessWidget {
? colorScheme.onErrorContainer
: (isOutgoing ? colorScheme.onPrimary : colorScheme.onSurface);
final metaColor = textColor.withValues(alpha: 0.7);
String messageText = message.text;
if (isRoomServer && !isOutgoing) {
messageText = message.text.substring(4.clamp(0, message.text.length));
}
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Column(
@ -936,12 +977,20 @@ class _MessageBubble extends StatelessWidget {
fallbackTextColor: textColor.withValues(alpha: 0.7),
)
else
Text(
message.text,
style: TextStyle(
color: textColor,
if(!isOutgoing)
Text(
messageText,
style: TextStyle(
color: textColor,
),
),
if(isOutgoing)
Text(
message.text,
style: TextStyle(
color: textColor,
),
),
),
if (isOutgoing && message.retryCount > 0) ...[
const SizedBox(height: 4),
Text(

View file

@ -22,7 +22,6 @@ import '../widgets/room_login_dialog.dart';
import '../widgets/unread_badge.dart';
import 'channels_screen.dart';
import 'chat_screen.dart';
import 'room_chat_screen.dart';
import 'map_screen.dart';
import 'repeater_hub_screen.dart';
import 'settings_screen.dart';
@ -451,7 +450,7 @@ class _ContactsScreenState extends State<ContactsScreen>
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RoomChatScreen(contact: room),
builder: (context) => ChatScreen(contact: room),
),
);
},

File diff suppressed because it is too large Load diff