💄 Optimize message indicator

This commit is contained in:
2025-10-10 21:38:53 +08:00
parent 598c51bc1a
commit a201f20793
3 changed files with 271 additions and 281 deletions

View File

@@ -9,6 +9,7 @@ class MessageIndicators extends StatelessWidget {
final MessageStatus? status; final MessageStatus? status;
final bool isCurrentUser; final bool isCurrentUser;
final Color textColor; final Color textColor;
final EdgeInsets padding;
const MessageIndicators({ const MessageIndicators({
super.key, super.key,
@@ -16,26 +17,43 @@ class MessageIndicators extends StatelessWidget {
this.status, this.status,
required this.isCurrentUser, required this.isCurrentUser,
required this.textColor, required this.textColor,
this.padding = const EdgeInsets.only(left: 6),
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Row( final children = <Widget>[];
spacing: 4,
mainAxisSize: MainAxisSize.min, if (editedAt != null) {
children: [ children.add(
if (editedAt != null)
Text( Text(
'edited'.tr().toLowerCase(), 'edited'.tr().toLowerCase(),
style: TextStyle(fontSize: 11, color: textColor.withOpacity(0.7)), style: TextStyle(fontSize: 11, color: textColor.withOpacity(0.7)),
), ),
if (isCurrentUser && status != null) );
}
if (isCurrentUser && status != null && status != MessageStatus.sent) {
children.add(
_buildStatusIcon( _buildStatusIcon(
context, context,
status!, status!,
textColor.withOpacity(0.7), textColor.withOpacity(0.7),
).padding(bottom: 3), ).padding(bottom: 4),
], );
}
if (children.isEmpty) {
return const SizedBox.shrink();
}
return Padding(
padding: padding,
child: Row(
spacing: 4,
mainAxisSize: MainAxisSize.min,
children: children,
),
); );
} }
@@ -46,9 +64,18 @@ class MessageIndicators extends StatelessWidget {
) { ) {
switch (status) { switch (status) {
case MessageStatus.pending: case MessageStatus.pending:
return Icon(Icons.access_time, size: 12, color: textColor); return SizedBox(
width: 10,
height: 10,
child: CircularProgressIndicator(
padding: EdgeInsets.zero,
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(textColor),
),
);
case MessageStatus.sent: case MessageStatus.sent:
return Icon(Icons.check, size: 12, color: textColor); // Sent status is hidden
return const SizedBox.shrink();
case MessageStatus.failed: case MessageStatus.failed:
return Consumer( return Consumer(
builder: builder:

View File

@@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:intl/intl.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -714,44 +715,11 @@ class MessageItemDisplayBubble extends HookConsumerWidget {
renderingPadding: EdgeInsets.zero, renderingPadding: EdgeInsets.zero,
maxWidth: 480, maxWidth: 480,
), ),
if (progress != null && progress!.isNotEmpty) FileUploadProgressWidget(
Column( progress: progress,
crossAxisAlignment: CrossAxisAlignment.stretch, textColor: textColor,
spacing: 8, hasContent:
children: [ remoteMessage.content?.isNotEmpty ?? false,
if ((remoteMessage.content?.isNotEmpty ?? false))
const Gap(0),
for (var entry in progress!.entries)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'fileUploadingProgress'.tr(
args: [
(entry.key + 1).toString(),
entry.value.toStringAsFixed(1),
],
),
style: TextStyle(
fontSize: 12,
color: textColor.withOpacity(0.8),
),
),
const Gap(4),
LinearProgressIndicator(
value: entry.value / 100,
backgroundColor:
Theme.of(
context,
).colorScheme.surfaceVariant,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.primary,
),
),
],
),
const Gap(0),
],
), ),
], ],
), ),
@@ -833,6 +801,11 @@ class MessageItemDisplayIRC extends HookConsumerWidget {
), ),
const Gap(8), const Gap(8),
Expanded( Expanded(
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -872,41 +845,19 @@ class MessageItemDisplayIRC extends HookConsumerWidget {
renderingPadding: EdgeInsets.zero, renderingPadding: EdgeInsets.zero,
maxWidth: 480, maxWidth: 480,
), ),
if (progress != null && progress!.isNotEmpty) FileUploadProgressWidget(
Column( progress: progress,
crossAxisAlignment: CrossAxisAlignment.stretch, textColor: textColor,
spacing: 8, hasContent: remoteMessage.content?.isNotEmpty ?? false,
children: [
if ((remoteMessage.content?.isNotEmpty ?? false))
const SizedBox.shrink(),
for (var entry in progress!.entries)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'fileUploadingProgress'.tr(
args: [
(entry.key + 1).toString(),
entry.value.toStringAsFixed(1),
],
),
style: TextStyle(
fontSize: 12,
color: textColor.withOpacity(0.8),
),
),
const Gap(4),
LinearProgressIndicator(
value: entry.value / 100,
backgroundColor:
Theme.of(context).colorScheme.surfaceVariant,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.primary,
),
), ),
], ],
), ),
], ),
MessageIndicators(
editedAt: remoteMessage.editedAt,
status: message.status,
isCurrentUser: isCurrentUser,
textColor: textColor,
), ),
], ],
), ),
@@ -971,7 +922,12 @@ class MessageItemDisplayDiscord extends HookConsumerWidget {
), ),
], ],
), ),
Column( Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (remoteMessage.repliedMessageId != null) if (remoteMessage.repliedMessageId != null)
@@ -1004,49 +960,28 @@ class MessageItemDisplayDiscord extends HookConsumerWidget {
if (remoteMessage.meta['embeds'] != null && if (remoteMessage.meta['embeds'] != null &&
kMessageEnableEmbedTypes.contains(message.type)) kMessageEnableEmbedTypes.contains(message.type))
EmbedListWidget( EmbedListWidget(
embeds: remoteMessage.meta['embeds'] as List<dynamic>, embeds:
remoteMessage.meta['embeds']
as List<dynamic>,
isInteractive: true, isInteractive: true,
isFullPost: false, isFullPost: false,
renderingPadding: EdgeInsets.zero, renderingPadding: EdgeInsets.zero,
maxWidth: 480, maxWidth: 480,
), ),
if (progress != null && progress!.isNotEmpty) FileUploadProgressWidget(
Column( progress: progress,
crossAxisAlignment: CrossAxisAlignment.stretch, textColor: textColor,
spacing: 8, hasContent:
children: [ remoteMessage.content?.isNotEmpty ?? false,
if ((remoteMessage.content?.isNotEmpty ?? false))
const SizedBox.shrink(),
for (var entry in progress!.entries)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'fileUploadingProgress'.tr(
args: [
(entry.key + 1).toString(),
entry.value.toStringAsFixed(1),
],
),
style: TextStyle(
fontSize: 12,
color: textColor.withOpacity(0.8),
),
),
const Gap(4),
LinearProgressIndicator(
value: entry.value / 100,
backgroundColor:
Theme.of(
context,
).colorScheme.surfaceVariant,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.primary,
),
), ),
], ],
), ),
], ),
MessageIndicators(
editedAt: remoteMessage.editedAt,
status: message.status,
isCurrentUser: isCurrentUser,
textColor: textColor,
), ),
], ],
).padding(left: kAvatarRadius * 2 + 8), ).padding(left: kAvatarRadius * 2 + 8),
@@ -1054,17 +989,14 @@ class MessageItemDisplayDiscord extends HookConsumerWidget {
) )
: Padding( : Padding(
padding: EdgeInsets.only(left: kAvatarRadius * 2 + 8), padding: EdgeInsets.only(left: kAvatarRadius * 2 + 8),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (showAvatar)
MessageSenderInfo(
sender: sender,
createdAt: message.createdAt,
textColor: textColor,
showAvatar: false,
isCompact: true,
),
if (remoteMessage.repliedMessageId != null) if (remoteMessage.repliedMessageId != null)
MessageQuoteWidget( MessageQuoteWidget(
message: message, message: message,
@@ -1095,50 +1027,27 @@ class MessageItemDisplayDiscord extends HookConsumerWidget {
if (remoteMessage.meta['embeds'] != null && if (remoteMessage.meta['embeds'] != null &&
kMessageEnableEmbedTypes.contains(message.type)) kMessageEnableEmbedTypes.contains(message.type))
EmbedListWidget( EmbedListWidget(
embeds: remoteMessage.meta['embeds'] as List<dynamic>, embeds:
remoteMessage.meta['embeds'] as List<dynamic>,
isInteractive: true, isInteractive: true,
isFullPost: false, isFullPost: false,
renderingPadding: EdgeInsets.zero, renderingPadding: EdgeInsets.zero,
maxWidth: 480, maxWidth: 480,
), ),
if (progress != null && progress!.isNotEmpty) FileUploadProgressWidget(
Column( progress: progress,
crossAxisAlignment: CrossAxisAlignment.stretch, textColor: textColor,
spacing: 8, hasContent:
children: [ remoteMessage.content?.isNotEmpty ?? false,
if ((remoteMessage.content?.isNotEmpty ?? false))
const Gap(0),
for (var entry in progress!.entries)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'fileUploadingProgress'.tr(
args: [
(entry.key + 1).toString(),
entry.value.toStringAsFixed(1),
],
),
style: TextStyle(
fontSize: 12,
color: textColor.withOpacity(0.8),
),
),
const Gap(4),
LinearProgressIndicator(
value: entry.value / 100,
backgroundColor:
Theme.of(
context,
).colorScheme.surfaceVariant,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.primary,
),
), ),
], ],
), ),
const Gap(0), ),
], MessageIndicators(
editedAt: remoteMessage.editedAt,
status: message.status,
isCurrentUser: isCurrentUser,
textColor: textColor,
), ),
], ],
), ),
@@ -1249,3 +1158,57 @@ class MessageQuoteWidget extends HookConsumerWidget {
); );
} }
} }
class FileUploadProgressWidget extends StatelessWidget {
final Map<int, double>? progress;
final Color textColor;
final bool hasContent;
const FileUploadProgressWidget({
super.key,
required this.progress,
required this.textColor,
required this.hasContent,
});
@override
Widget build(BuildContext context) {
if (progress == null || progress!.isEmpty) return const SizedBox.shrink();
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 8,
children: [
if (hasContent) const Gap(0),
for (var entry in progress!.entries)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'fileUploadingProgress'.tr(
args: [
(entry.key + 1).toString(),
entry.value.toStringAsFixed(1),
],
),
style: TextStyle(
fontSize: 12,
color: textColor.withOpacity(0.8),
),
),
const Gap(4),
LinearProgressIndicator(
value: entry.value,
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.primary,
),
trackGap: 0,
),
],
),
const Gap(0),
],
);
}
}

View File

@@ -52,7 +52,7 @@ class UploadMenu extends StatelessWidget {
leadingIcon: Icon(item.icon), leadingIcon: Icon(item.icon),
style: ButtonStyle( style: ButtonStyle(
padding: WidgetStatePropertyAll( padding: WidgetStatePropertyAll(
EdgeInsets.symmetric(horizontal: 16, vertical: 20), EdgeInsets.only(left: 12, right: 16, top: 20, bottom: 20),
), ),
), ),
child: Text(item.textKey.tr()), child: Text(item.textKey.tr()),