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
+64 -15
View File
@@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@@ -162,13 +163,12 @@ class _ChatScreenState extends State<ChatScreen> {
body: Consumer<MeshCoreConnector>( body: Consumer<MeshCoreConnector>(
builder: (context, connector, child) { builder: (context, connector, child) {
final messages = connector.getMessages(widget.contact); final messages = connector.getMessages(widget.contact);
return Column( return Column(
children: [ children: [
Expanded( Expanded(
child: messages.isEmpty child: messages.isEmpty
? _buildEmptyState() ? _buildEmptyState()
: _buildMessageList(messages), : _buildMessageList(messages, connector),
), ),
_buildInputBar(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( return ListView.builder(
controller: _scrollController, controller: _scrollController,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
itemCount: messages.length, itemCount: messages.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
Contact contact = widget.contact;
final message = messages[index]; 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( return _MessageBubble(
message: message, message: message,
senderName: widget.contact.name, senderName: widget.contact.type == advTypeRoom ? "${contact.name} [$fourByteHex]" : contact.name,
onTap: () => _openMessagePath(message), isRoomServer: widget.contact.type == advTypeRoom,
onLongPress: () => _showMessageActions(message), 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) { String _currentPathLabel(Contact contact) {
// Check if user has set a path override // Check if user has set a path override
if (contact.pathOverride != null) { 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 { Future<void> _showCustomPathDialog(BuildContext context) async {
final connector = Provider.of<MeshCoreConnector>(context, listen: false); 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 connector = context.read<MeshCoreConnector>();
final fourByteHex = message.fourByteRoomContactKey.map((b) => b.toRadixString(16).padLeft(2, '0')).join().toUpperCase();
final senderName = 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( final pathMessage = ChannelMessage(
senderKey: null, senderKey: null,
senderName: senderName, senderName: senderName,
@@ -757,7 +785,7 @@ class _ChatScreenState extends State<ChatScreen> {
); );
} }
void _showMessageActions(Message message) { void _showMessageActions(Message message, Contact contact) {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
builder: (sheetContext) => SafeArea( builder: (sheetContext) => SafeArea(
@@ -798,6 +826,14 @@ class _ChatScreenState extends State<ChatScreen> {
_retryMessage(message); _retryMessage(message);
}, },
), ),
if(widget.contact.type == advTypeRoom)
ListTile(
leading: const Icon(Icons.chat),
title: const Text('Open Chat'),
onTap: () {
_openChat(context, contact);
},
),
ListTile( ListTile(
leading: const Icon(Icons.close), leading: const Icon(Icons.close),
title: const Text('Cancel'), title: const Text('Cancel'),
@@ -862,12 +898,14 @@ class _ChatScreenState extends State<ChatScreen> {
class _MessageBubble extends StatelessWidget { class _MessageBubble extends StatelessWidget {
final Message message; final Message message;
final String senderName; final String senderName;
final bool isRoomServer;
final VoidCallback? onTap; final VoidCallback? onTap;
final VoidCallback? onLongPress; final VoidCallback? onLongPress;
const _MessageBubble({ const _MessageBubble({
required this.message, required this.message,
required this.senderName, required this.senderName,
required this.isRoomServer,
this.onTap, this.onTap,
this.onLongPress, this.onLongPress,
}); });
@@ -886,7 +924,10 @@ class _MessageBubble extends StatelessWidget {
? colorScheme.onErrorContainer ? colorScheme.onErrorContainer
: (isOutgoing ? colorScheme.onPrimary : colorScheme.onSurface); : (isOutgoing ? colorScheme.onPrimary : colorScheme.onSurface);
final metaColor = textColor.withValues(alpha: 0.7); 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( return Padding(
padding: const EdgeInsets.symmetric(vertical: 4), padding: const EdgeInsets.symmetric(vertical: 4),
child: Column( child: Column(
@@ -936,12 +977,20 @@ class _MessageBubble extends StatelessWidget {
fallbackTextColor: textColor.withValues(alpha: 0.7), fallbackTextColor: textColor.withValues(alpha: 0.7),
) )
else else
Text( if(!isOutgoing)
message.text, Text(
style: TextStyle( messageText,
color: textColor, style: TextStyle(
color: textColor,
),
),
if(isOutgoing)
Text(
message.text,
style: TextStyle(
color: textColor,
),
), ),
),
if (isOutgoing && message.retryCount > 0) ...[ if (isOutgoing && message.retryCount > 0) ...[
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
+1 -2
View File
@@ -22,7 +22,6 @@ import '../widgets/room_login_dialog.dart';
import '../widgets/unread_badge.dart'; import '../widgets/unread_badge.dart';
import 'channels_screen.dart'; import 'channels_screen.dart';
import 'chat_screen.dart'; import 'chat_screen.dart';
import 'room_chat_screen.dart';
import 'map_screen.dart'; import 'map_screen.dart';
import 'repeater_hub_screen.dart'; import 'repeater_hub_screen.dart';
import 'settings_screen.dart'; import 'settings_screen.dart';
@@ -451,7 +450,7 @@ class _ContactsScreenState extends State<ContactsScreen>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => RoomChatScreen(contact: room), builder: (context) => ChatScreen(contact: room),
), ),
); );
}, },
File diff suppressed because it is too large Load Diff