From 1eec712c58068fcba3657c61cc492fdc7e9a1f8b Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Mon, 18 May 2026 21:13:35 +0300 Subject: [PATCH] Sync update: 2026-05-18 21:13:35 --- whatsapp_app/lib/widgets/message_bubble.dart | 70 ++++++++++++++------ 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/whatsapp_app/lib/widgets/message_bubble.dart b/whatsapp_app/lib/widgets/message_bubble.dart index 441e699..dec29bf 100644 --- a/whatsapp_app/lib/widgets/message_bubble.dart +++ b/whatsapp_app/lib/widgets/message_bubble.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:get/get.dart'; @@ -152,11 +153,13 @@ class MessageBubble extends StatelessWidget { Widget _buildAckIcon(int ack) { switch (ack) { case 1: // Pending/Queued - return const Icon(Icons.access_time, size: 13, color: AppTheme.textSecondary); + return const Icon(Icons.access_time, + size: 13, color: AppTheme.textSecondary); case 2: // Sent (single grey tick) return const Icon(Icons.done, size: 15, color: AppTheme.textSecondary); case 3: // Delivered (double grey tick) - return const Icon(Icons.done_all, size: 15, color: AppTheme.textSecondary); + return const Icon(Icons.done_all, + size: 15, color: AppTheme.textSecondary); case 4: // Read (double blue tick) return const Icon(Icons.done_all, size: 15, color: Colors.blue); case 5: // Played audio/video (double blue with wave icon) @@ -250,7 +253,8 @@ class _InteractiveMediaWidgetState extends State { await _player.pause(); } else { final bytes = base64Decode(base64Data); - final safeId = widget.message.id.replaceAll(RegExp(r'[^a-zA-Z0-9]'), ''); + final safeId = + widget.message.id.replaceAll(RegExp(r'[^a-zA-Z0-9]'), ''); final tempDir = Directory.systemTemp; final tempFile = File('${tempDir.path}/voice_$safeId.mp3'); @@ -293,7 +297,8 @@ class _InteractiveMediaWidgetState extends State { child: const SizedBox( width: 24, height: 24, - child: CircularProgressIndicator(strokeWidth: 2, color: AppTheme.primary), + child: CircularProgressIndicator( + strokeWidth: 2, color: AppTheme.primary), ), ); } @@ -318,12 +323,16 @@ class _InteractiveMediaWidgetState extends State { children: [ Text( _getLabel(), - style: const TextStyle(color: AppTheme.textPrimary, fontWeight: FontWeight.w500, fontSize: 13), + style: const TextStyle( + color: AppTheme.textPrimary, + fontWeight: FontWeight.w500, + fontSize: 13), ), const SizedBox(height: 2), const Text( 'Tap to download', - style: TextStyle(color: AppTheme.textSecondary, fontSize: 10), + style: + TextStyle(color: AppTheme.textSecondary, fontSize: 10), ), ], ), @@ -397,7 +406,9 @@ class _InteractiveMediaWidgetState extends State { children: [ IconButton( icon: Icon( - _isPlaying ? Icons.pause_circle_filled : Icons.play_circle_filled, + _isPlaying + ? Icons.pause_circle_filled + : Icons.play_circle_filled, color: AppTheme.primary, size: 36, ), @@ -413,8 +424,10 @@ class _InteractiveMediaWidgetState extends State { SliderTheme( data: SliderTheme.of(context).copyWith( trackHeight: 2.5, - thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 5), - overlayShape: const RoundSliderOverlayShape(overlayRadius: 10), + thumbShape: + const RoundSliderThumbShape(enabledThumbRadius: 5), + overlayShape: + const RoundSliderOverlayShape(overlayRadius: 10), activeTrackColor: AppTheme.primary, inactiveTrackColor: AppTheme.surfaceLight, thumbColor: AppTheme.primary, @@ -423,7 +436,8 @@ class _InteractiveMediaWidgetState extends State { child: Slider( value: _audioProgress.clamp(0.0, 1.0), onChanged: (v) async { - final targetMs = (v * _audioDurationSeconds * 1000).toInt(); + final targetMs = + (v * _audioDurationSeconds * 1000).toInt(); await _player.seek(Duration(milliseconds: targetMs)); }, ), @@ -457,11 +471,13 @@ class _InteractiveMediaWidgetState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - const Icon(Icons.check_circle_outline, color: AppTheme.primary, size: 32), + const Icon(Icons.check_circle_outline, + color: AppTheme.primary, size: 32), const SizedBox(width: 12), Text( _getLabel(), - style: const TextStyle(color: AppTheme.textPrimary, fontWeight: FontWeight.w500), + style: const TextStyle( + color: AppTheme.textPrimary, fontWeight: FontWeight.w500), ), ], ), @@ -470,21 +486,31 @@ class _InteractiveMediaWidgetState extends State { IconData _getIcon() { switch (widget.message.type) { - case "image": return Icons.photo_outlined; - case "video": return Icons.videocam_outlined; - case "audio": return Icons.audiotrack_outlined; - case "sticker": return Icons.emoji_emotions_outlined; - default: return Icons.insert_drive_file_outlined; + case "image": + return Icons.photo_outlined; + case "video": + return Icons.videocam_outlined; + case "audio": + return Icons.audiotrack_outlined; + case "sticker": + return Icons.emoji_emotions_outlined; + default: + return Icons.insert_drive_file_outlined; } } String _getLabel() { switch (widget.message.type) { - case "image": return "Image Attachment"; - case "video": return "Video Attachment"; - case "audio": return "Audio / Voice Note"; - case "sticker": return "Sticker Attachment"; - default: return "File Attachment"; + case "image": + return "Image Attachment"; + case "video": + return "Video Attachment"; + case "audio": + return "Audio / Voice Note"; + case "sticker": + return "Sticker Attachment"; + default: + return "File Attachment"; } } }