mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-04-20 22:13:48 +00:00
chat fixes
This commit is contained in:
parent
7465e81996
commit
173fdf7168
5 changed files with 187 additions and 90 deletions
|
|
@ -4,6 +4,7 @@ import 'dart:math' as math;
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:flutter_linkify/flutter_linkify.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
|
@ -23,6 +24,7 @@ import '../widgets/emoji_picker.dart';
|
|||
import '../widgets/gif_message.dart';
|
||||
import '../widgets/jump_to_bottom_button.dart';
|
||||
import '../widgets/gif_picker.dart';
|
||||
import '../widgets/message_status_icon.dart';
|
||||
import 'channel_message_path_screen.dart';
|
||||
import 'map_screen.dart';
|
||||
|
||||
|
|
@ -337,7 +339,23 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||
const SizedBox(height: 8),
|
||||
],
|
||||
if (poi != null)
|
||||
_buildPoiMessage(context, poi, isOutgoing)
|
||||
_buildPoiMessage(
|
||||
context,
|
||||
poi,
|
||||
isOutgoing,
|
||||
trailing: (!enableTracing && isOutgoing)
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: MessageStatusIcon(
|
||||
isAcked: message.status ==
|
||||
ChannelMessageStatus.sent &&
|
||||
displayPath.isNotEmpty,
|
||||
isFailed: message.status ==
|
||||
ChannelMessageStatus.failed,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
)
|
||||
else if (gifId != null)
|
||||
Stack(
|
||||
children: [
|
||||
|
|
@ -358,33 +376,31 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||
),
|
||||
if (!enableTracing && isOutgoing)
|
||||
Positioned(
|
||||
top: 4,
|
||||
right: 4,
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(2),
|
||||
padding: const EdgeInsets.all(3),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.3),
|
||||
shape: BoxShape.circle,
|
||||
color: isOutgoing
|
||||
? Theme.of(
|
||||
context,
|
||||
).colorScheme.primaryContainer
|
||||
: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(10),
|
||||
topRight: Radius.circular(8),
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
(message.status ==
|
||||
ChannelMessageStatus.sent &&
|
||||
displayPath.isNotEmpty)
|
||||
? Icons.check_circle
|
||||
: message.status ==
|
||||
ChannelMessageStatus.failed
|
||||
? Icons.cancel
|
||||
: Icons.cloud,
|
||||
size: 14,
|
||||
color:
|
||||
(message.status ==
|
||||
ChannelMessageStatus.sent &&
|
||||
displayPath.isNotEmpty)
|
||||
? Colors.green
|
||||
: message.status ==
|
||||
ChannelMessageStatus.failed
|
||||
? Colors.red
|
||||
: Colors.white70,
|
||||
child: MessageStatusIcon(
|
||||
isAcked:
|
||||
message.status ==
|
||||
ChannelMessageStatus.sent &&
|
||||
displayPath.isNotEmpty,
|
||||
isFailed:
|
||||
message.status ==
|
||||
ChannelMessageStatus.failed,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -419,25 +435,14 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||
const SizedBox(width: 4),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: Icon(
|
||||
(message.status ==
|
||||
ChannelMessageStatus.sent &&
|
||||
displayPath.isNotEmpty)
|
||||
? Icons.check_circle
|
||||
: message.status ==
|
||||
ChannelMessageStatus.failed
|
||||
? Icons.cancel
|
||||
: Icons.cloud,
|
||||
size: 14,
|
||||
color:
|
||||
(message.status ==
|
||||
ChannelMessageStatus.sent &&
|
||||
displayPath.isNotEmpty)
|
||||
? Colors.green
|
||||
: message.status ==
|
||||
ChannelMessageStatus.failed
|
||||
? Colors.red
|
||||
: Colors.grey,
|
||||
child: MessageStatusIcon(
|
||||
isAcked:
|
||||
message.status ==
|
||||
ChannelMessageStatus.sent &&
|
||||
displayPath.isNotEmpty,
|
||||
isFailed:
|
||||
message.status ==
|
||||
ChannelMessageStatus.failed,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -727,7 +732,12 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||
return _PoiInfo(lat: lat, lon: lon, label: label);
|
||||
}
|
||||
|
||||
Widget _buildPoiMessage(BuildContext context, _PoiInfo poi, bool isOutgoing) {
|
||||
Widget _buildPoiMessage(
|
||||
BuildContext context,
|
||||
_PoiInfo poi,
|
||||
bool isOutgoing, {
|
||||
Widget? trailing,
|
||||
}) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final textColor = isOutgoing
|
||||
? colorScheme.onPrimaryContainer
|
||||
|
|
@ -773,6 +783,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
if (trailing != null) ...[
|
||||
const SizedBox(width: 4),
|
||||
trailing,
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:flutter_linkify/flutter_linkify.dart';
|
||||
import 'package:meshcore_open/screens/path_trace_map.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
|
@ -13,6 +14,7 @@ import 'package:latlong2/latlong.dart';
|
|||
import '../connector/meshcore_connector.dart';
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../helpers/reaction_helper.dart';
|
||||
import '../widgets/message_status_icon.dart';
|
||||
import '../helpers/chat_scroll_controller.dart';
|
||||
import '../helpers/link_handler.dart';
|
||||
import '../helpers/utf8_length_limiter.dart';
|
||||
|
|
@ -1252,7 +1254,24 @@ class _MessageBubble extends StatelessWidget {
|
|||
if (gifId == null) const SizedBox(height: 4),
|
||||
],
|
||||
if (poi != null)
|
||||
_buildPoiMessage(context, poi, textColor, metaColor)
|
||||
_buildPoiMessage(
|
||||
context,
|
||||
poi,
|
||||
textColor,
|
||||
metaColor,
|
||||
trailing: (!enableTracing && isOutgoing)
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: MessageStatusIcon(
|
||||
isAcked: message.status ==
|
||||
MessageStatus.delivered &&
|
||||
message.pathBytes.isNotEmpty,
|
||||
isFailed: message.status ==
|
||||
MessageStatus.failed,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
)
|
||||
else if (gifId != null)
|
||||
Stack(
|
||||
children: [
|
||||
|
|
@ -1269,35 +1288,25 @@ class _MessageBubble extends StatelessWidget {
|
|||
),
|
||||
if (!enableTracing && isOutgoing)
|
||||
Positioned(
|
||||
top: 4,
|
||||
right: 4,
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(2),
|
||||
padding: const EdgeInsets.all(3),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(
|
||||
alpha: 0.3,
|
||||
color: bubbleColor,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(10),
|
||||
topRight: Radius.circular(12),
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
(message.status ==
|
||||
MessageStatus.delivered &&
|
||||
message.pathBytes.isNotEmpty)
|
||||
? Icons.check_circle
|
||||
: message.status ==
|
||||
MessageStatus.failed
|
||||
? Icons.cancel
|
||||
: Icons.cloud,
|
||||
size: 14,
|
||||
color:
|
||||
(message.status ==
|
||||
MessageStatus.delivered &&
|
||||
message.pathBytes.isNotEmpty)
|
||||
? Colors.green
|
||||
: message.status ==
|
||||
MessageStatus.failed
|
||||
? Colors.red
|
||||
: Colors.white70,
|
||||
child: MessageStatusIcon(
|
||||
isAcked:
|
||||
message.status ==
|
||||
MessageStatus.delivered &&
|
||||
message.pathBytes.isNotEmpty,
|
||||
isFailed:
|
||||
message.status ==
|
||||
MessageStatus.failed,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -1331,23 +1340,13 @@ class _MessageBubble extends StatelessWidget {
|
|||
const SizedBox(width: 4),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: Icon(
|
||||
(message.status ==
|
||||
MessageStatus.delivered &&
|
||||
message.pathBytes.isNotEmpty)
|
||||
? Icons.check_circle
|
||||
: message.status == MessageStatus.failed
|
||||
? Icons.cancel
|
||||
: Icons.cloud,
|
||||
size: 14,
|
||||
color:
|
||||
(message.status ==
|
||||
MessageStatus.delivered &&
|
||||
message.pathBytes.isNotEmpty)
|
||||
? Colors.green
|
||||
: message.status == MessageStatus.failed
|
||||
? Colors.red
|
||||
: Colors.grey,
|
||||
child: MessageStatusIcon(
|
||||
isAcked:
|
||||
message.status ==
|
||||
MessageStatus.delivered &&
|
||||
message.pathBytes.isNotEmpty,
|
||||
isFailed:
|
||||
message.status == MessageStatus.failed,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -1464,8 +1463,9 @@ class _MessageBubble extends StatelessWidget {
|
|||
BuildContext context,
|
||||
_PoiInfo poi,
|
||||
Color textColor,
|
||||
Color metaColor,
|
||||
) {
|
||||
Color metaColor, {
|
||||
Widget? trailing,
|
||||
}) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
|
|
@ -1502,6 +1502,10 @@ class _MessageBubble extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
if (trailing != null) ...[
|
||||
const SizedBox(width: 4),
|
||||
trailing,
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
36
lib/widgets/message_status_icon.dart
Normal file
36
lib/widgets/message_status_icon.dart
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class MessageStatusIcon extends StatelessWidget {
|
||||
final bool isAcked;
|
||||
final bool isFailed;
|
||||
final double size;
|
||||
|
||||
const MessageStatusIcon({
|
||||
super.key,
|
||||
required this.isAcked,
|
||||
this.isFailed = false,
|
||||
this.size = 14,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (isFailed) {
|
||||
return Icon(Icons.cancel, size: size, color: Colors.red);
|
||||
}
|
||||
|
||||
final Color color;
|
||||
if (isAcked) {
|
||||
color = Colors.green;
|
||||
} else {
|
||||
color = Colors.grey;
|
||||
}
|
||||
|
||||
return SvgPicture.asset(
|
||||
'assets/icons/done_all.svg',
|
||||
width: size,
|
||||
height: size,
|
||||
colorFilter: ColorFilter.mode(color, BlendMode.srcIn),
|
||||
);
|
||||
}
|
||||
}
|
||||
40
pubspec.lock
40
pubspec.lock
|
|
@ -347,6 +347,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.2.2"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
|
@ -597,6 +605,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
path_parsing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_parsing
|
||||
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -1010,6 +1026,30 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.2"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics
|
||||
sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.19"
|
||||
vector_graphics_codec:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_codec
|
||||
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.13"
|
||||
vector_graphics_compiler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ dependencies:
|
|||
gpx: ^2.3.0
|
||||
path_provider: ^2.1.5
|
||||
share_plus: ^12.0.1
|
||||
web: ^1.1.1
|
||||
flutter_svg: ^2.0.10+1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
@ -87,6 +89,7 @@ flutter:
|
|||
|
||||
assets:
|
||||
- assets/images/
|
||||
- assets/icons/
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue