Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: CI

on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]

jobs:
test:
name: Analyze, format, test
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: '3.27.0'
cache: true

- name: Print Flutter version
run: flutter --version

- name: Install dependencies
run: flutter pub get

- name: Verify formatting
run: dart format --output=none --set-exit-if-changed lib/ test/

- name: Static analysis
run: dart analyze --fatal-infos --fatal-warnings lib/ test/

- name: Run tests
run: flutter test

- name: Dry-run publish (catches packaging issues)
run: flutter pub publish --dry-run
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# chat_bubbles plugin

![Pub Version](https://img.shields.io/pub/v/chat_bubbles?color=blue)
[![CI](https://github.com/prahack/chat_bubbles/actions/workflows/ci.yml/badge.svg)](https://github.com/prahack/chat_bubbles/actions/workflows/ci.yml)
![GitHub](https://img.shields.io/github/license/prahack/chat_bubbles)
![GitHub forks](https://img.shields.io/github/forks/prahack/chat_bubbles)
![GitHub Repo stars](https://img.shields.io/github/stars/prahack/chat_bubbles)
Expand Down
3 changes: 1 addition & 2 deletions lib/algo/date_chip_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ class DateChipText {
final now = DateTime.now();
if (_formatter.format(now) == _formatter.format(date)) {
return 'Today';
} else if (_formatter
.format(DateTime(now.year, now.month, now.day - 1)) ==
} else if (_formatter.format(DateTime(now.year, now.month, now.day - 1)) ==
_formatter.format(date)) {
return 'Yesterday';
} else {
Expand Down
87 changes: 48 additions & 39 deletions lib/bubbles/bubble_link_preview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,82 +36,82 @@ const double defaultBubbleRadiusLinkPreview = 16;
class BubbleLinkPreview extends StatelessWidget {
/// the URL being previewed
final String url;

/// the title of the link preview
final String? title;

/// the description of the link preview
final String? description;

/// the preview image URL
final String? imageUrl;

/// optional message text accompanying the link
final String? text;

/// chat bubble [BorderRadius]
final double bubbleRadius;

/// message sender
final bool isSender;

/// chat bubble color
final Color color;

/// link preview card background color
final Color? previewBackgroundColor;

/// chat bubble tail
final bool tail;

/// message state - whether the message has been sent
final bool sent;

/// message state - whether the message has been delivered
final bool delivered;

/// message state - whether the message has been seen
final bool seen;

/// text style for the message text
final TextStyle textStyle;

/// text style for the link preview title
final TextStyle? titleTextStyle;

/// text style for the link preview description
final TextStyle? descriptionTextStyle;

/// text style for the URL
final TextStyle? urlTextStyle;

/// constraints for the chat bubble
final BoxConstraints? constraints;

/// widget displayed before the bubble for non-senders
final Widget? leading;

/// widget displayed after the bubble for senders
final Widget? trailing;

/// outer margin of the bubble
final EdgeInsets margin;

/// inner padding of the bubble
final EdgeInsets padding;

/// callback function when the bubble is tapped
final VoidCallback? onTap;

/// callback function when the bubble is long pressed
final VoidCallback? onLongPress;

/// callback function when the link preview is tapped
final VoidCallback? onLinkTap;

/// height of the preview image
final double? imageHeight;

/// whether to show the preview image
final bool showImage;

Expand Down Expand Up @@ -170,7 +170,7 @@ class BubbleLinkPreview extends StatelessWidget {
Widget build(BuildContext context) {
bool stateTick = false;
Icon? stateIcon;

if (sent) {
stateTick = true;
stateIcon = Icon(
Expand Down Expand Up @@ -279,12 +279,14 @@ class BubbleLinkPreview extends StatelessWidget {
color: previewBackgroundColor ??
Colors.grey.withValues(alpha: 0.1),
borderRadius: BorderRadius.only(
topLeft: (text == null || text!.isEmpty) && !isForwarded
? Radius.circular(bubbleRadius)
: Radius.zero,
topRight: (text == null || text!.isEmpty) && !isForwarded
? Radius.circular(bubbleRadius)
: Radius.zero,
topLeft:
(text == null || text!.isEmpty) && !isForwarded
? Radius.circular(bubbleRadius)
: Radius.zero,
topRight:
(text == null || text!.isEmpty) && !isForwarded
? Radius.circular(bubbleRadius)
: Radius.zero,
bottomLeft: Radius.circular(tail
? isSender
? bubbleRadius
Expand All @@ -301,13 +303,17 @@ class BubbleLinkPreview extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Preview image
if (showImage && imageUrl != null && imageUrl!.isNotEmpty)
if (showImage &&
imageUrl != null &&
imageUrl!.isNotEmpty)
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: (text == null || text!.isEmpty) && !isForwarded
topLeft: (text == null || text!.isEmpty) &&
!isForwarded
? Radius.circular(bubbleRadius)
: Radius.zero,
topRight: (text == null || text!.isEmpty) && !isForwarded
topRight: (text == null || text!.isEmpty) &&
!isForwarded
? Radius.circular(bubbleRadius)
: Radius.zero,
),
Expand Down Expand Up @@ -344,11 +350,13 @@ class BubbleLinkPreview extends StatelessWidget {
overflow: TextOverflow.ellipsis,
),
// Description
if (description != null && description!.isNotEmpty) ...[
if (description != null &&
description!.isNotEmpty) ...[
SizedBox(height: 4),
Text(
description!,
style: descriptionTextStyle ?? defaultDescriptionStyle,
style: descriptionTextStyle ??
defaultDescriptionStyle,
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
Expand Down Expand Up @@ -383,7 +391,8 @@ class BubbleLinkPreview extends StatelessWidget {
// Message status row
if (showStatusArea)
Padding(
padding: const EdgeInsets.only(right: 8, bottom: 6, top: 4),
padding:
const EdgeInsets.only(right: 8, bottom: 6, top: 4),
child: Align(
alignment: Alignment.centerRight,
child: BubbleStatusRow(
Expand Down
20 changes: 20 additions & 0 deletions lib/bubbles/bubble_normal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,44 +50,64 @@ const double defaultBubbleRadius = 16;
class BubbleNormal extends StatelessWidget {
/// chat bubble [BorderRadius]
final double bubbleRadius;

/// message sender
final bool isSender;

/// chat bubble color
final Color color;

/// message text
final String text;

/// chat bubble tail
final bool tail;

/// message state - whether the message has been sent
final bool sent;

/// message state - whether the message has been delivered
final bool delivered;

/// message state - whether the message has been seen
final bool seen;

/// text style for the message
final TextStyle textStyle;

/// constraints for the chat bubble
final BoxConstraints? constraints;

/// widget displayed before the bubble for non-senders
final Widget? leading;

/// widget displayed after the bubble for senders
final Widget? trailing;

/// outer margin of the bubble
final EdgeInsets margin;

/// inner padding of the bubble
final EdgeInsets padding;

/// callback function when the bubble is tapped
final VoidCallback? onTap;

/// callback function when the bubble is double tapped
final VoidCallback? onDoubleTap;

/// callback function when the bubble is long pressed
final VoidCallback? onLongPress;

/// optional timestamp string shown at the bottom-right (e.g. "12:34 PM")
final String? timestamp;

/// shows an "Edited" label next to the status area when true
final bool isEdited;

/// shows a "Forwarded" banner at the top of the bubble when true
final bool isForwarded;

/// optional identifier for tracking the message
final String? messageId;

Expand Down
Loading
Loading