v_chat_bubbles 1.2.7 copy "v_chat_bubbles: ^1.2.7" to clipboard
v_chat_bubbles: ^1.2.7 copied to clipboard

A comprehensive Flutter chat bubble library supporting Telegram, WhatsApp, Messenger, and iMessage styles with full theming, callbacks, text formatting, and custom bubble support.

v_chat_bubbles #

A comprehensive Flutter package for building chat interfaces with multiple messaging platform styles (Telegram, WhatsApp, Messenger, iMessage). Provides highly customizable bubble widgets, theming, callbacks, text formatting, and an extensible architecture for custom message types.

pub package License: MIT


📸 Screenshots #

Preview
Preview
Telegram Style
Telegram
WhatsApp Style
WhatsApp
Reactions
Reactions
Polls & Location
Polls & Location
RTL Support
RTL Support
Web Support
Web & Desktop Support

Table of Contents #


Installation #

Add to your pubspec.yaml:

dependencies:
  v_chat_bubbles: ^latest_version

Then run:

flutter pub get

Quick Start #

import 'package:v_chat_bubbles/v_chat_bubbles.dart';

class ChatScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return VBubbleScope(
      style: VBubbleStyle.telegram,
      config: VBubbleConfig(),
      callbacks: VBubbleCallbacks(
        onTap: (messageId) => print('Tapped: $messageId'),
        onPatternTap: (match) => handlePatternTap(match),
      ),
      child: ListView(
        children: [
          VTextBubble(
            messageId: 'msg_1',
            isMeSender: true,
            time: '12:30',
            text: 'Hello! How are you?',
            status: VMessageStatus.read,
          ),
          VTextBubble(
            messageId: 'msg_2',
            isMeSender: false,
            time: '12:31',
            text: 'I am fine, thanks!',
            senderName: 'John',
            avatar: VPlatformFile.fromUrl(networkUrl: 'https://example.com/avatar.jpg'),
          ),
        ],
      ),
    );
  }
}

Architecture Overview #

VBubbleScope (InheritedWidget - provides config to all children)
    │
    ├── VBubbleStyle (telegram, whatsapp, messenger, imessage, custom)
    ├── VBubbleTheme (colors, typography, gradients)
    ├── VBubbleConfig (nested configuration objects)
    ├── VBubbleCallbacks (event handlers)
    └── Child Widgets
         │
         └── BaseBubble (abstract base class)
              │
              ├── VTextBubble
              ├── VImageBubble
              ├── VVideoBubble
              ├── VVoiceBubble
              ├── VFileBubble
              ├── VLocationBubble
              ├── VContactBubble
              ├── VPollBubble
              ├── VCallBubble
              ├── VGalleryBubble
              ├── VCustomBubble<T>
              └── ... more

VBubbleScope #

The root widget that provides configuration to all bubble descendants via InheritedWidget.

Constructor Parameters #

Parameter Type Default Description
style VBubbleStyle telegram Visual style preset
theme VBubbleTheme? null Custom theme (auto-generated if null)
config VBubbleConfig VBubbleConfig() Configuration object
callbacks VBubbleCallbacks VBubbleCallbacks() Event callbacks
isSelectionMode bool false Enable multi-selection
selectedIds Set<String> {} Currently selected message IDs
menuItemsBuilder VMenuItemsBuilder? null Dynamic context menu items
child Widget required Child widget tree

Available Styles #

enum VBubbleStyle {
  telegram,   // Gradient bubbles with distinctive tails
  whatsapp,   // Green outgoing, white incoming
  messenger,  // Blue gradient outgoing, gray incoming
  imessage,   // Blue outgoing, gray incoming, minimal tails
  custom,     // Fully custom styling
}

Example #

VBubbleScope(
  style: VBubbleStyle.whatsapp,
  theme: VBubbleTheme.whatsappLight(),
  config: VBubbleConfig.groupChat(),
  callbacks: _buildCallbacks(),
  isSelectionMode: _isSelectionMode,
  selectedIds: _selectedIds,
  menuItemsBuilder: (messageId, messageType, isMeSender) {
    return isMeSender
      ? [VDefaultMenuItems.edit, VDefaultMenuItems.delete]
      : [VDefaultMenuItems.reply, VDefaultMenuItems.forward];
  },
  child: ListView.builder(...),
)

VBubbleConfig #

Nested configuration object controlling all aspects of bubble behavior.

Constructor #

VBubbleConfig({
  VPatternConfig patterns,
  VGestureConfig gestures,
  VAvatarConfig avatar,
  VSizingConfig sizing,
  VSpacingConfig spacing,
  VMediaConfig media,
  VTextExpansionConfig textExpansion,
  VAnimationConfig animation,
  VAccessibilityConfig accessibility,
  VTranslationConfig translations,
})

Config Presets #

VBubbleConfig()              // Default configuration
VBubbleConfig.compact()      // Dense layout, smaller elements
VBubbleConfig.desktop()      // Wider bubbles, more spacing
VBubbleConfig.readOnly()     // No gestures (view-only mode)
VBubbleConfig.directChat()   // Hidden avatars (1:1 chat)
VBubbleConfig.groupChat()    // Always show avatars
VBubbleConfig.minimal()      // No tails, clean look
VBubbleConfig.accessible()   // Enhanced accessibility
VBubbleConfig.performance()  // No animations, minimal processing

VPatternConfig #

Controls text pattern detection and formatting.

Property Type Default Description
enableLinks bool true Detect URLs
enableEmails bool true Detect email addresses
enablePhones bool true Detect phone numbers
enableMentions bool false Detect @username
enableHashtags bool false Detect #hashtag
enableFormatting bool false Enable bold, italic, strike, `code`
enableCodeBlocks bool false Enable ```code blocks```
enableBlockquotes bool false Enable > blockquotes
enableBulletLists bool false Enable - bullet lists
enableNumberedLists bool false Enable 1. numbered lists
customPatterns List<VCustomPattern>? null Custom regex patterns

Presets:

VPatternConfig.standard      // Links, emails, phones
VPatternConfig.none          // No detection
VPatternConfig.linksOnly     // Only URLs
VPatternConfig.withFormatting // Standard + inline formatting
VPatternConfig.markdown      // Full markdown support (all patterns)
VPatternConfig.blocksOnly    // Only block-level patterns

Custom Pattern Example:

VPatternConfig(
  enableLinks: true,
  customPatterns: [
    VCustomPattern(
      id: 'ticket',
      pattern: RegExp(r'TKT-\d+'),
      style: TextStyle(color: Colors.purple, fontWeight: FontWeight.bold),
      isTappable: true,
    ),
    VCustomPattern(
      id: 'order',
      pattern: RegExp(r'ORD#\d+'),
      style: TextStyle(color: Colors.orange),
      isTappable: true,
    ),
  ],
)

VGestureConfig #

Controls gesture interactions.

Property Type Default Description
enableSwipeToReply bool true Swipe right to reply
enableLongPress bool true Long press for context menu
enableDoubleTapToReact bool false Double tap to add reaction
enableHapticFeedback bool true Vibration on interactions
swipeThreshold double 64 Swipe distance to trigger reply

Presets:

VGestureConfig.all   // All gestures enabled
VGestureConfig.none  // No gestures (read-only)

VAvatarConfig #

Controls avatar display.

Property Type Default Description
show bool true Show avatars
position VAvatarPosition bottom Avatar position (top/bottom)
size double 32 Avatar diameter

Presets:

VAvatarConfig.visible  // Show avatars
VAvatarConfig.hidden   // Hide avatars
VAvatarConfig.large    // Larger avatars (40px)

VSizingConfig #

Controls bubble dimensions.

Property Type Default Description
maxWidthFraction double 0.75 Max width as fraction of screen
maxWidth double? null Absolute max width
minWidth double 80 Minimum bubble width

Presets:

VSizingConfig.standard  // 75% max width
VSizingConfig.compact   // 65% max width
VSizingConfig.wide      // 85% max width

VSpacingConfig #

Controls spacing and padding.

Property Type Default Description
bubbleRadius double 16 Bubble corner radius
tailSize double 8 Bubble tail size
sameSenderSpacing double 2 Space between same-sender messages
differentSenderSpacing double 8 Space between different-sender messages
contentPaddingHorizontal double 12 Horizontal content padding
contentPaddingVertical double 8 Vertical content padding

VMediaConfig #

Controls media message display.

Property Type Default Description
cornerRadius double 12 Media corner radius
imageMaxHeight double 300 Max image height
videoMaxHeight double 250 Max video height
voiceWaveformHeight double 32 Voice waveform height
fileMessageWidth double 240 File bubble width
gallerySpacing double 2 Gallery grid spacing

VTextExpansionConfig #

Controls expandable text behavior.

Property Type Default Description
enabled bool true Enable text expansion
characterThreshold int 500 Characters before truncation

VAnimationConfig #

Controls animation durations.

Property Type Default Description
fadeIn Duration 200ms Fade in duration
fadeOut Duration 150ms Fade out duration
expand Duration 300ms Expand animation
collapse Duration 250ms Collapse animation
highlight Duration 1500ms Highlight animation
swipe Duration 600ms Swipe animation
defaultCurve Curve easeOutCubic Animation curve

Presets:

VAnimationConfig.standard  // Default timings
VAnimationConfig.fast      // Snappy animations
VAnimationConfig.slow      // Smooth animations
VAnimationConfig.none      // No animations (instant)

VAccessibilityConfig #

Controls accessibility features.

Property Type Default Description
enableSemanticLabels bool true Screen reader labels
minTapTargetSize double 48 Minimum tap target (44+ recommended)
enableHighContrast bool false High contrast mode
semanticLabelBuilder Function? null Custom semantic label builder

VTranslationConfig #

Controls localized strings.

VTranslationConfig(
  seeMore: 'See more',
  seeLess: 'See less',
  edited: 'edited',
  forwarded: 'Forwarded',
  repliedTo: 'Replied to',
  you: 'You',
  // ... more
)

// Preset for locale
VTranslationConfig.forLocale(Locale('ar'))  // Arabic translations
VTranslationConfig.forLocale(Locale('en'))  // English translations

VBubbleTheme #

Controls colors, typography, and visual styling.

Factory Constructors #

// Style + brightness combinations
VBubbleTheme.telegramLight()
VBubbleTheme.telegramDark()
VBubbleTheme.whatsappLight()
VBubbleTheme.whatsappDark()
VBubbleTheme.messengerLight()
VBubbleTheme.messengerDark()
VBubbleTheme.imessageLight()
VBubbleTheme.imessageDark()

// Get theme by enum
VBubbleTheme.fromStyle(VBubbleStyle.telegram, brightness: Brightness.light)

// Custom theme
VBubbleTheme.custom(
  outgoingBubbleColor: Colors.blue,
  incomingBubbleColor: Colors.grey[200]!,
  accentColor: Colors.blue,
  brightness: Brightness.light,
)

Key Properties #

Property Type Description
outgoingBubbleColor Color Sent message bubble color
incomingBubbleColor Color Received message bubble color
outgoingTextColor Color Sent message text color
incomingTextColor Color Received message text color
outgoingBubbleGradient Gradient? Gradient for sent bubbles
incomingBubbleGradient Gradient? Gradient for received bubbles
outgoingLinkColor Color Link color in sent messages
incomingLinkColor Color Link color in received messages
messageTextStyle TextStyle Message body text style
timeTextStyle TextStyle Timestamp text style
senderNameTextStyle TextStyle Sender name text style
captionTextStyle TextStyle Caption text style
linkTextStyle TextStyle Link text style
availableReactions List<String> Emoji reactions for menu
readIconColor Color Read receipt checkmark color

VBubbleCallbacks #

Event handlers for bubble interactions.

Context Menu Behavior #

By default, long-pressing a bubble opens the built-in iOS-style context menu (CupertinoContextMenu). You can customize this behavior:

Scenario Behavior
onLongPress not set Built-in context menu opens
onLongPress is set Your custom callback is called, built-in menu does NOT open
// Option 1: Use built-in context menu (default)
VBubbleCallbacks(
  // No onLongPress - built-in menu will open
  onMenuItemSelected: (messageId, item) {
    // Handle menu item selection
  },
)

// Option 2: Custom long press handler (replaces built-in menu)
VBubbleCallbacks(
  onLongPress: (messageId, position) {
    // Show your own menu at position
    showMenu(
      context: context,
      position: RelativeRect.fromLTRB(
        position.dx, position.dy, position.dx, position.dy,
      ),
      items: [
        PopupMenuItem(child: Text('Reply')),
        PopupMenuItem(child: Text('Copy')),
        PopupMenuItem(child: Text('Delete')),
      ],
    );
  },
)

All Callbacks #

VBubbleCallbacks(
  // === Core Callbacks ===
  onTap: (String messageId) { },
  onLongPress: (String messageId, Offset position) { }, // Replaces built-in menu when set
  onSwipeReply: (String messageId) { },
  onSelectionChanged: (String messageId, bool isSelected) { },
  onAvatarTap: (String senderId) { },
  onReplyPreviewTap: (String originalMessageId) { },

  // === Grouped Callbacks ===
  onReaction: (String messageId, String emoji, ReactionAction action) { },
  onReactionTap: (String messageId, String emoji, Offset position) { },
  onPatternTap: (VPatternMatch match) { },
  onMediaTap: (VMediaTapData data) { },
  onMenuItemSelected: (String messageId, VBubbleMenuItem item) { },

  // === Type-Specific Callbacks ===
  onPollVote: (String messageId, String optionId) { },
  onLocationTap: (VLocationTapData data) { },
  onContactTap: (VContactTapData data) { },
  onCallTap: (String messageId, bool isVideo) { },
  onExpandToggle: (String messageId, bool isExpanded) { },
  onDownload: (String messageId) { },
  onTransferStateChanged: (String messageId, VMediaTransferAction action) { },
)

Pattern Match Object #

class VPatternMatch {
  final String patternId;    // 'url', 'email', 'phone', 'mention', or custom ID
  final String matchedText;  // The matched text (transformed if applicable)
  final String rawText;      // Original matched text
  final String? messageId;   // Parent message ID
}

Example Handler #

onPatternTap: (match) {
  switch (match.patternId) {
    case 'url':
      launchUrl(Uri.parse(match.matchedText));
      break;
    case 'email':
      launchUrl(Uri.parse('mailto:${match.matchedText}'));
      break;
    case 'phone':
      launchUrl(Uri.parse('tel:${match.matchedText}'));
      break;
    case 'mention':
      navigateToUser(match.matchedText);
      break;
    case 'ticket':  // Custom pattern
      openTicket(match.matchedText);
      break;
  }
}

Available Bubble Widgets #

Common Properties (BaseBubble) #

All bubble widgets share these properties:

Property Type Required Description
messageId String Yes Unique message identifier
isMeSender bool Yes True if current user sent
time String Yes Display time (e.g., "12:30")
status VMessageStatus? No Delivery status
isSameSender bool No Same sender as previous message
avatar VPlatformFile? No Sender avatar image
senderName String? No Sender display name
senderColor Color? No Sender name color
replyTo VReplyData? No Reply preview data
forwardedFrom VForwardData? No Forward info
reactions List<VBubbleReaction> No Message reactions
isEdited bool No Show "edited" label
isPinned bool No Show pin indicator
isStarred bool No Show star indicator
isHighlighted bool No Highlight animation

VTextBubble #

VTextBubble(
  messageId: 'msg_1',
  isMeSender: true,
  time: '12:30',
  text: 'Hello *world*! Check https://flutter.dev',
  linkPreview: VLinkPreviewData(
    url: 'https://flutter.dev',
    title: 'Flutter',
    description: 'Build apps for any screen',
    image: VPlatformFile.fromUrl(networkUrl: '...'),
  ),
  status: VMessageStatus.read,
)

VImageBubble #

VImageBubble(
  messageId: 'msg_2',
  isMeSender: false,
  time: '12:31',
  imageFile: VPlatformFile.fromUrl(networkUrl: 'https://example.com/image.jpg'),
  caption: 'Beautiful sunset!',
  aspectRatio: 16/9,
)

VVideoBubble #

VVideoBubble(
  messageId: 'msg_3',
  isMeSender: true,
  time: '12:32',
  videoFile: VPlatformFile.fromUrl(
    networkUrl: 'https://example.com/video.mp4',
    fileSize: 15728640, // 15 MB
  ),
  thumbnailFile: VPlatformFile.fromUrl(networkUrl: '...'),
  duration: Duration(minutes: 2, seconds: 30),
  caption: 'Check this out!',
)

VVoiceBubble #

VVoiceBubble(
  messageId: 'msg_4',
  isMeSender: false,
  time: '12:33',
  controller: VVoiceMessageController(
    audioSrc: 'https://example.com/voice.mp3',
    maxDuration: Duration(minutes: 1, seconds: 30),
    waveform: [0.2, 0.5, 0.8, 0.3, 0.6, ...], // Optional waveform data
  ),
)

VFileBubble #

VFileBubble(
  messageId: 'msg_5',
  isMeSender: true,
  time: '12:34',
  file: VPlatformFile.fromUrl(
    networkUrl: 'https://example.com/document.pdf',
    fileSize: 2457600, // 2.4 MB
  ),
  transferState: VTransferState.completed,
)

VLocationBubble #

VLocationBubble(
  messageId: 'msg_6',
  isMeSender: false,
  time: '12:35',
  locationData: VLocationData(
    latitude: 40.7128,
    longitude: -74.0060,
    address: 'New York, NY',
    staticMapUrl: 'https://maps.example.com/static/...',
  ),
)

VContactBubble #

VContactBubble(
  messageId: 'msg_7',
  isMeSender: true,
  time: '12:36',
  contactData: VContactData(
    name: 'John Smith',
    phoneNumber: '+1-555-123-4567',
    avatar: VPlatformFile.fromUrl(networkUrl: '...'),
  ),
)

VPollBubble #

VPollBubble(
  messageId: 'msg_8',
  isMeSender: false,
  time: '12:37',
  pollData: VPollData(
    question: 'What is your favorite framework?',
    options: [
      VPollOption(id: '1', text: 'Flutter', voteCount: 150, percentage: 60),
      VPollOption(id: '2', text: 'React Native', voteCount: 75, percentage: 30),
      VPollOption(id: '3', text: 'Other', voteCount: 25, percentage: 10),
    ],
    totalVotes: 250,
    hasVoted: true,
    mode: VPollMode.single,
  ),
)

VCallBubble #

VCallBubble(
  messageId: 'msg_9',
  isMeSender: true,
  time: '12:38',
  callData: VCallData(
    type: VCallType.video,
    status: VCallStatus.completed,
    duration: Duration(minutes: 5, seconds: 30),
  ),
)

VGalleryBubble #

VGalleryBubble(
  messageId: 'msg_10',
  isMeSender: false,
  time: '12:39',
  items: [
    VGalleryItemData(messageId: 'img_1', file: VPlatformFile.fromUrl(...)),
    VGalleryItemData(messageId: 'img_2', file: VPlatformFile.fromUrl(...)),
    VGalleryItemData(messageId: 'img_3', file: VPlatformFile.fromUrl(...)),
  ],
)

VSystemBubble #

VSystemBubble(text: 'John joined the group')

VDateChip #

VDateChip(date: 'Today')

VDeletedBubble #

VDeletedBubble(
  isMeSender: true,
  time: '12:40',
)

Text Formatting & Patterns #

Supported Syntax #

Format Syntax Output
Bold *text* text
Italic _text_ text
Strikethrough ~text~ text
Inline Code `code` code
Code Block ```code``` Syntax highlighted block
Blockquote > text Indented quote
Bullet List - item Bulleted list
Numbered List 1. item Numbered list

Enable Formatting #

VBubbleConfig(
  patterns: VPatternConfig(
    enableFormatting: true,     // Bold, italic, etc.
    enableCodeBlocks: true,     // ```code```
    enableBlockquotes: true,    // > quotes
    enableBulletLists: true,    // - items
    enableNumberedLists: true,  // 1. items
  ),
)

// Or use preset
VBubbleConfig(patterns: VPatternConfig.markdown)

Custom Bubbles #

Create custom bubble widgets using VCustomBubble or by extending BaseBubble.

Using VCustomBubble (Quick & Easy) #

// 1. Define your data model
@immutable
class VPaymentData extends VCustomBubbleData {
  final double amount;
  final String currency;

  const VPaymentData({required this.amount, this.currency = 'USD'});

  @override
  String get contentType => 'payment';
}

// 2. Use VCustomBubble with a builder
VCustomBubble<VPaymentData>(
  messageId: 'msg_payment_1',
  isMeSender: true,
  time: '12:30',
  data: VPaymentData(amount: 99.99),
  builder: (context, data) {
    final theme = context.bubbleTheme;
    final textColor = theme.outgoingTextColor;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Icon(Icons.payment, color: Colors.green),
            SizedBox(width: 8),
            Text('Payment', style: TextStyle(color: textColor, fontWeight: FontWeight.bold)),
          ],
        ),
        SizedBox(height: 8),
        Text('\$${data.amount}', style: TextStyle(color: textColor, fontSize: 24)),
      ],
    );
  },
)

Extending BaseBubble (Full Control) #

class VPaymentBubble extends BaseBubble {
  final VPaymentData paymentData;

  @override
  String get messageType => 'payment';

  const VPaymentBubble({
    super.key,
    required super.messageId,
    required super.isMeSender,
    required super.time,
    required this.paymentData,
    super.status,
    super.isSameSender,
    super.avatar,
    super.senderName,
    super.senderColor,
  });

  @override
  Widget buildContent(BuildContext context) {
    final theme = context.bubbleTheme;
    final textColor = selectTextColor(theme);

    return buildBubbleContainer(
      context: context,
      showTail: !isSameSender,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Row(
            children: [
              Icon(Icons.payment, color: textColor),
              SizedBox(width: 8),
              Text('Payment', style: TextStyle(color: textColor, fontWeight: FontWeight.bold)),
            ],
          ),
          SizedBox(height: 8),
          Text(
            '\$${paymentData.amount.toStringAsFixed(2)}',
            style: TextStyle(color: textColor, fontSize: 24, fontWeight: FontWeight.w600),
          ),
          SizedBox(height: 8),
          buildMeta(context),
        ],
      ),
    );
  }
}

Available Helper Methods in BaseBubble #

Method Description
buildBubbleContainer() Wraps content with styled bubble shape
buildBubbleHeader() Forward header + sender name + reply preview
buildMeta() Timestamp + status + flags
buildTimestamp() Just timestamp widget
buildStatusIcon() Just status indicator
buildReactionsWidget() Reaction pills row
selectTextColor(theme) Get correct text color
selectSecondaryTextColor(theme) Get secondary text color
selectLinkColor(theme) Get link/accent color

Context Extensions #

Access scope data from any descendant widget:

// Full scope
final scope = context.bubbleScope;

// Individual properties
final theme = context.bubbleTheme;
final config = context.bubbleConfig;
final callbacks = context.bubbleCallbacks;
final style = context.bubbleStyle;

// Expansion state
final expandManager = context.expandStateManager;
final isExpanded = expandManager.isExpanded('msg_123');

// Custom builders
final hasBuilder = context.hasCustomBubbleBuilder('payment');
final builder = context.getCustomBubbleBuilder('payment');

Selection Mode #

Enable multi-selection for bulk operations:

class _ChatState extends State<ChatScreen> {
  bool _isSelectionMode = false;
  final Set<String> _selectedIds = {};

  @override
  Widget build(BuildContext context) {
    return VBubbleScope(
      isSelectionMode: _isSelectionMode,
      selectedIds: _selectedIds,
      callbacks: VBubbleCallbacks(
        onSelectionChanged: (messageId, isSelected) {
          setState(() {
            if (isSelected) {
              _selectedIds.add(messageId);
              _isSelectionMode = true;
            } else {
              _selectedIds.remove(messageId);
              if (_selectedIds.isEmpty) _isSelectionMode = false;
            }
          });
        },
      ),
      menuItemsBuilder: (messageId, messageType, isMeSender) {
        return [...VDefaultMenuItems.textDefaults]; // Includes select option
      },
      child: ...,
    );
  }
}

Default Menu Items #

VDefaultMenuItems.reply
VDefaultMenuItems.forward
VDefaultMenuItems.copy
VDefaultMenuItems.delete
VDefaultMenuItems.download
VDefaultMenuItems.pin
VDefaultMenuItems.star
VDefaultMenuItems.select    // Triggers selection mode
VDefaultMenuItems.edit
VDefaultMenuItems.report

// Preset lists
VDefaultMenuItems.textDefaults   // reply, forward, copy, edit, pin, delete, select
VDefaultMenuItems.mediaDefaults  // reply, forward, download, pin, delete

Performance Optimizations #

The package includes several built-in optimizations:

Caching System #

  • Span caching: Parsed text spans cached per message
  • Pattern caching: Built pattern lists cached per config
  • Block widget caching: Block-level widgets cached
  • Text direction caching: RTL/LTR detection cached

Efficient Rendering #

  • shouldRepaint optimization: Bubble painters only repaint when properties change
  • IntrinsicWidth wrapping: Bubbles shrink-wrap to content
  • Lazy parsing: Block patterns only parsed when enabled
  • Fast path detection: Quick checks before expensive regex operations

Best Practices #

// Use performance preset for very long lists
VBubbleConfig.performance()

// Disable unused patterns
VPatternConfig(
  enableLinks: true,
  enableEmails: false,  // Disable if not needed
  enablePhones: false,
  enableFormatting: false,
)

// Use appropriate image sizes
VPlatformFile.fromUrl(
  networkUrl: thumbnailUrl,  // Use thumbnails, not full images
)

License #

MIT License - see LICENSE file for details.


Author #

Hatem Ragap 📧 Email: hatemragapdev@gmail.com 🔗 GitHub: github.com/hatemragab


Support #

For issues, feature requests, or questions:

6
likes
150
points
273
downloads
screenshot

Publisher

verified publishervchatsdk.com

Weekly Downloads

A comprehensive Flutter chat bubble library supporting Telegram, WhatsApp, Messenger, and iMessage styles with full theming, callbacks, text formatting, and custom bubble support.

Repository (GitHub)
View/report issues

Topics

#chat #messaging #ui #widget #bubbles

Documentation

Documentation
API reference

Funding

Consider supporting this project:

github.com

License

MIT (license)

Dependencies

cached_network_image, emoji_picker_flutter, flutter, intl, v_chat_voice_player, v_platform, video_player

More

Packages that depend on v_chat_bubbles