mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-12 00:40:28 +00:00
feat: Add message location details
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter_map/flutter_map.dart' as flutter_map;
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -628,7 +629,7 @@ class _MessageBubbleState extends State<MessageBubble> {
|
||||
recipientName = recipientContact?.advName;
|
||||
}
|
||||
|
||||
final senderLocationSnapshot = messagesProvider.getMessageContactLocation(
|
||||
final messageLocationSnapshot = messagesProvider.getMessageContactLocation(
|
||||
widget.message.id,
|
||||
);
|
||||
final receptionDetails = messagesProvider.getMessageReceptionDetails(
|
||||
@@ -742,9 +743,9 @@ class _MessageBubbleState extends State<MessageBubble> {
|
||||
'Retry result: ${retryResult ?? '-'}',
|
||||
'Sender key prefix: ${senderPrefixHex ?? '-'}',
|
||||
'Sender name: ${senderName ?? widget.message.senderName ?? '-'}',
|
||||
'Sender location at receipt: ${senderLocationSnapshot?.formattedCoordinates ?? '-'}',
|
||||
'Sender location source: ${senderLocationSnapshot?.technicalSourceLabel ?? '-'}',
|
||||
'Sender location timestamp: ${senderLocationSnapshot?.sourceTimestamp?.toIso8601String() ?? '-'}',
|
||||
'${widget.message.isSentMessage ? "Sent from location" : "Sender location at receipt"}: ${messageLocationSnapshot?.formattedCoordinates ?? '-'}',
|
||||
'${widget.message.isSentMessage ? "Sent from source" : "Sender location source"}: ${messageLocationSnapshot?.technicalSourceLabel ?? '-'}',
|
||||
'${widget.message.isSentMessage ? "Sent from timestamp" : "Sender location timestamp"}: ${messageLocationSnapshot?.sourceTimestamp?.toIso8601String() ?? '-'}',
|
||||
'Recipient key prefix: ${recipientPrefixHex ?? '-'}',
|
||||
'Recipient name: ${recipientName ?? '-'}',
|
||||
'Drawing flag: ${widget.message.isDrawing}',
|
||||
@@ -907,6 +908,54 @@ class _MessageBubbleState extends State<MessageBubble> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (messageLocationSnapshot != null) ...[
|
||||
const SizedBox(height: 12),
|
||||
_techSection(
|
||||
sheetContext,
|
||||
icon: Icons.location_on,
|
||||
title: AppLocalizations.of(context)!.location,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildLocationPreviewMap(
|
||||
sheetContext,
|
||||
messageLocationSnapshot.location,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_detailRow(
|
||||
sheetContext,
|
||||
label: AppLocalizations.of(
|
||||
context,
|
||||
)!.coordinates,
|
||||
value: messageLocationSnapshot
|
||||
.formattedCoordinates,
|
||||
onCopy: () => copyField(
|
||||
messageLocationSnapshot.formattedCoordinates,
|
||||
),
|
||||
),
|
||||
_detailRow(
|
||||
sheetContext,
|
||||
label: AppLocalizations.of(context)!.source,
|
||||
value: messageLocationSnapshot
|
||||
.technicalSourceLabel,
|
||||
),
|
||||
_detailRow(
|
||||
sheetContext,
|
||||
label: AppLocalizations.of(context)!.captured,
|
||||
value: _formatRfc3339(
|
||||
messageLocationSnapshot.sourceTimestamp ??
|
||||
messageLocationSnapshot.capturedAt,
|
||||
),
|
||||
onCopy: () => copyField(
|
||||
_formatRfc3339(
|
||||
messageLocationSnapshot.sourceTimestamp ??
|
||||
messageLocationSnapshot.capturedAt,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (widget.message.lastEchoRssiDbm != null ||
|
||||
snrDb != null ||
|
||||
rssiDbm != null) ...[
|
||||
@@ -1333,6 +1382,53 @@ class _MessageBubbleState extends State<MessageBubble> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLocationPreviewMap(BuildContext context, LatLng location) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: SizedBox(
|
||||
height: 180,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.outlineVariant,
|
||||
),
|
||||
),
|
||||
child: flutter_map.FlutterMap(
|
||||
options: flutter_map.MapOptions(
|
||||
initialCenter: location,
|
||||
initialZoom: 15,
|
||||
interactionOptions: const flutter_map.InteractionOptions(
|
||||
flags: flutter_map.InteractiveFlag.none,
|
||||
),
|
||||
),
|
||||
children: [
|
||||
flutter_map.TileLayer(
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
userAgentPackageName: 'com.meshcore.sar',
|
||||
),
|
||||
flutter_map.MarkerLayer(
|
||||
markers: [
|
||||
flutter_map.Marker(
|
||||
point: location,
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: Icon(
|
||||
widget.message.isSentMessage
|
||||
? Icons.near_me
|
||||
: Icons.location_on,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
size: 32,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _techSection(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
|
||||
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../../models/contact.dart';
|
||||
import '../../providers/app_provider.dart';
|
||||
import '../../providers/messages_provider.dart';
|
||||
import '../../utils/avatar_label_helper.dart';
|
||||
import '../common/contact_avatar.dart';
|
||||
@@ -259,6 +260,19 @@ class _RecipientSelectorSheetState extends State<RecipientSelectorSheet> {
|
||||
return _formatRelativeTime(context, lastActivityAt);
|
||||
}
|
||||
|
||||
IconData _channelLocationSharingIcon(ChannelLocationSharingMode mode) {
|
||||
return mode == ChannelLocationSharingMode.hardware
|
||||
? Icons.public_rounded
|
||||
: Icons.smartphone_rounded;
|
||||
}
|
||||
|
||||
Color _channelLocationSharingColor(
|
||||
BuildContext context,
|
||||
ChannelLocationSharingMode mode,
|
||||
) {
|
||||
return const Color(0xFF16A34A);
|
||||
}
|
||||
|
||||
Widget _buildTextSubtitle(
|
||||
BuildContext context,
|
||||
Contact contact,
|
||||
@@ -312,6 +326,9 @@ class _RecipientSelectorSheetState extends State<RecipientSelectorSheet> {
|
||||
MessagesProvider? messagesProvider,
|
||||
) {
|
||||
final previewData = _channelPreviewData(context, channel, messagesProvider);
|
||||
final sharingMode = context.watch<AppProvider>().channelLocationSharingModeForChannel(
|
||||
channel.publicKey.length > 1 ? channel.publicKey[1] : 0,
|
||||
);
|
||||
|
||||
return _buildRecipientCard(
|
||||
context: context,
|
||||
@@ -319,6 +336,7 @@ class _RecipientSelectorSheetState extends State<RecipientSelectorSheet> {
|
||||
contact: channel,
|
||||
title: channel.getLocalizedDisplayName(context),
|
||||
subtitle: _buildChannelSubtitle(context, channel, previewData),
|
||||
avatarMarkerMode: sharingMode,
|
||||
unreadCount: _unreadFor(channel),
|
||||
isSelected: _isSelected('channel', channel),
|
||||
compact: true,
|
||||
@@ -838,6 +856,7 @@ class _RecipientSelectorSheetState extends State<RecipientSelectorSheet> {
|
||||
required Contact contact,
|
||||
required String title,
|
||||
Widget? subtitle,
|
||||
ChannelLocationSharingMode? avatarMarkerMode,
|
||||
required int unreadCount,
|
||||
required bool isSelected,
|
||||
bool compact = false,
|
||||
@@ -846,6 +865,12 @@ class _RecipientSelectorSheetState extends State<RecipientSelectorSheet> {
|
||||
}) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final accentColor = _sectionColor(context, type);
|
||||
final markerColor = avatarMarkerMode == null
|
||||
? accentColor
|
||||
: _channelLocationSharingColor(context, avatarMarkerMode);
|
||||
final markerIcon = avatarMarkerMode == null
|
||||
? _typeIcon(contact)
|
||||
: _channelLocationSharingIcon(avatarMarkerMode);
|
||||
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
@@ -886,14 +911,14 @@ class _RecipientSelectorSheetState extends State<RecipientSelectorSheet> {
|
||||
color: colorScheme.surface,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: accentColor.withValues(alpha: 0.3),
|
||||
color: markerColor.withValues(alpha: 0.3),
|
||||
),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Icon(
|
||||
_typeIcon(contact),
|
||||
markerIcon,
|
||||
size: compact ? 9 : 10,
|
||||
color: accentColor,
|
||||
color: markerColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -945,7 +970,7 @@ class _RecipientSelectorSheetState extends State<RecipientSelectorSheet> {
|
||||
?.copyWith(
|
||||
color: accentColor,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user