feat: ✨ Add customizable timestamp styling for chat bubbles and improve timestamp rendering logic#440
feat: ✨ Add customizable timestamp styling for chat bubbles and improve timestamp rendering logic#440vasu-nageshri wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new “in-bubble timestamp” mode to ChatView, including customizable timestamp text styling per bubble direction, and updates timestamp layout/rendering across text, image, and voice message bubbles. This addresses the request to show message time within/near the bubble rather than only via swipe-to-reveal.
Changes:
- Introduce
FeatureActiveConfig.showTimestamp(mutually exclusive withenableSwipeToSeeTime) and plumb it into message rendering. - Add
ChatBubble.messageTimeTextStyleand apply it when rendering in-bubble timestamps for text/image/voice. - Update
DateTime.getTimeFromDateTimeformatting tohh:mm aand add adaptive inline vs bottom-right timestamp layout for text messages.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/src/widgets/voice_message_view.dart | Adds in-bubble timestamp rendering for voice messages and plumbs featureActiveConfig. |
| lib/src/widgets/text_message_view.dart | Implements adaptive timestamp layout (inline when it fits, otherwise bottom-right) and per-bubble timestamp styling. |
| lib/src/widgets/message_view.dart | Passes featureActiveConfig through to image/text/voice message views. |
| lib/src/widgets/image_message_view.dart | Overlays timestamp inside image bubble when showTimestamp is enabled. |
| lib/src/widgets/chat_list_widget.dart | Disables swipe-to-see-time gesture when showTimestamp is enabled. |
| lib/src/widgets/chat_bubble_widget.dart | Prevents swipe-to-see-time stack from activating when showTimestamp is enabled; adds safer slideAnimation handling. |
| lib/src/models/config_models/feature_active_config.dart | Adds showTimestamp flag and an assert preventing it from being enabled alongside enableSwipeToSeeTime. |
| lib/src/models/chat_bubble.dart | Adds messageTimeTextStyle to support per-bubble timestamp typography. |
| lib/src/extensions/extensions.dart | Changes time formatting to 12-hour format with AM/PM. |
| doc/documentation.md | Documents new timestamp styling and the mutual exclusivity of showTimestamp and enableSwipeToSeeTime. |
| CHANGELOG.md | Adds an Unreleased entry for issue #115. |
Comments suppressed due to low confidence (2)
lib/src/widgets/text_message_view.dart:231
- This getter’s indentation suggests the file hasn’t been run through
dart format. Since CI enforces formatting (dart format --set-exit-if-changed .), please reformat to avoid failing the build.
TextStyle? get _messageTimeTextStyle => isMessageBySender
? outgoingChatBubbleConfig?.messageTimeTextStyle
: inComingChatBubbleConfig?.messageTimeTextStyle;
lib/src/widgets/voice_message_view.dart:55
- PR description mentions adding voice message duration display and a
VoiceDurationFormat(hhmmss/mmss/adaptive), but there’s no corresponding implementation in this PR (noVoiceDurationFormatsymbol exists in the repo). Please either add the missing duration feature or update the PR description to match the actual changes.
class VoiceMessageView extends StatefulWidget {
const VoiceMessageView({
Key? key,
required this.screenWidth,
required this.message,
required this.isMessageBySender,
this.inComingChatBubbleConfig,
this.outgoingChatBubbleConfig,
this.onMaxDuration,
this.messageReactionConfig,
this.config,
this.featureActiveConfig,
}) : super(key: key);
/// Provides configuration related to voice message.
final VoiceMessageConfiguration? config;
/// Allow user to set width of chat bubble.
final double screenWidth;
/// Provides message instance of chat.
final Message message;
final ValueSetter<int>? onMaxDuration;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| final TextStyle? textStyle; | ||
|
|
||
| /// Used for giving text style of in-bubble message timestamp. | ||
| /// Only has effect when [FeatureActiveConfig.showTimestamp] is `true`. |
| /// throw an [AssertionError] in debug mode. | ||
| /// | ||
| /// When `true`, timestamps are displayed inside bubbles for all message types | ||
| /// (text, image, voice). Use [ChatBubble.messageTimeTextStyle] to customise |
| final canShowInSingleLine = showTimestamp && | ||
| extractedUrls.isEmpty && | ||
| !textMessage.contains('\n') && | ||
| _canRenderTimeInSingleLine( | ||
| context: context, | ||
| messageText: textMessage, | ||
| messageStyle: _textStyle ?? | ||
| textTheme.bodyMedium?.copyWith( | ||
| color: Colors.white, | ||
| fontSize: 16, | ||
| ) ?? | ||
| const TextStyle(fontSize: 16), | ||
| timeText: timeText, | ||
| timeStyle: timestampStyle, | ||
| maxContentWidth: constraints.maxWidth, | ||
| ); |
| final messagePainter = TextPainter( | ||
| text: TextSpan(text: messageText, style: messageStyle), | ||
| textDirection: TextDirection.ltr, | ||
| maxLines: 1, | ||
| textScaler: textScaler, | ||
| )..layout(maxWidth: maxContentWidth); | ||
|
|
||
| final timePainter = TextPainter( | ||
| text: TextSpan(text: timeText, style: timeStyle), | ||
| textDirection: TextDirection.ltr, |
| padding: const EdgeInsets.symmetric( | ||
| horizontal: 6, | ||
| vertical: 2, | ||
| ), | ||
| decoration: BoxDecoration( | ||
| color: Colors.black45, | ||
| borderRadius: BorderRadius.circular(10), | ||
| ), | ||
| child: Text( | ||
| message.createdAt.getTimeFromDateTime, | ||
| style: const TextStyle( | ||
| color: Colors.white, | ||
| fontSize: 10, | ||
| fontWeight: FontWeight.w500, | ||
| ).merge( | ||
| isMessageBySender | ||
| ? outgoingChatBubbleConfig?.messageTimeTextStyle | ||
| : inComingChatBubbleConfig?.messageTimeTextStyle, | ||
| ), | ||
| ), | ||
| ), | ||
| ), |
ef1f4ff to
5299eb4
Compare
There was a problem hiding this comment.
What if we give true both to enableSwipeToReply enableSwipeToSeeTime?
There was a problem hiding this comment.
swipe-to-reply will work when swiping directly on the message bubble. Swiping outside the bubble will continue to show the message time UI, so there won’t be any conflict between the two gestures.
| Widget build(BuildContext context) { | ||
| final borderRadius = imageMessageConfig?.borderRadius ?? | ||
| const BorderRadius.all(Radius.circular(14)); | ||
| const BorderRadius.all(Radius.circular(10)); |
There was a problem hiding this comment.
the Bubble UI looking good without timestamp also?
…ve timestamp rendering logic - Adaptive layout: inline for short messages, bottom-right for long messages - Image/voice message timestamps overlaid inside the bubble - Add in for per-bubble timestamp styling - Update time format to 12-hour AM/PM (e.g. 04:32 PM) - Add voice message duration display: (VoiceDurationFormat.hhmmss/mmss/adaptive) - Reduce chat bubble border radius for modern look
5299eb4 to
5217429
Compare
Description
Visual Representations:
showTimestamp: trueswipeToSeeTime: trueboth: trueChecklist
fix:,feat:,docs:etc).docsand added dartdoc comments with///.examplesordocs.Breaking Change?
Related Issues
Closes #115