Sync update: 2026-05-18 21:13:35

This commit is contained in:
Hamza-Ayed
2026-05-18 21:13:35 +03:00
parent 340a22fffa
commit 1eec712c58

View File

@@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -152,11 +153,13 @@ class MessageBubble extends StatelessWidget {
Widget _buildAckIcon(int ack) { Widget _buildAckIcon(int ack) {
switch (ack) { switch (ack) {
case 1: // Pending/Queued 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) case 2: // Sent (single grey tick)
return const Icon(Icons.done, size: 15, color: AppTheme.textSecondary); return const Icon(Icons.done, size: 15, color: AppTheme.textSecondary);
case 3: // Delivered (double grey tick) 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) case 4: // Read (double blue tick)
return const Icon(Icons.done_all, size: 15, color: Colors.blue); return const Icon(Icons.done_all, size: 15, color: Colors.blue);
case 5: // Played audio/video (double blue with wave icon) case 5: // Played audio/video (double blue with wave icon)
@@ -250,7 +253,8 @@ class _InteractiveMediaWidgetState extends State<InteractiveMediaWidget> {
await _player.pause(); await _player.pause();
} else { } else {
final bytes = base64Decode(base64Data); 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 tempDir = Directory.systemTemp;
final tempFile = File('${tempDir.path}/voice_$safeId.mp3'); final tempFile = File('${tempDir.path}/voice_$safeId.mp3');
@@ -293,7 +297,8 @@ class _InteractiveMediaWidgetState extends State<InteractiveMediaWidget> {
child: const SizedBox( child: const SizedBox(
width: 24, width: 24,
height: 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<InteractiveMediaWidget> {
children: [ children: [
Text( Text(
_getLabel(), _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 SizedBox(height: 2),
const Text( const Text(
'Tap to download', '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<InteractiveMediaWidget> {
children: [ children: [
IconButton( IconButton(
icon: Icon( icon: Icon(
_isPlaying ? Icons.pause_circle_filled : Icons.play_circle_filled, _isPlaying
? Icons.pause_circle_filled
: Icons.play_circle_filled,
color: AppTheme.primary, color: AppTheme.primary,
size: 36, size: 36,
), ),
@@ -413,8 +424,10 @@ class _InteractiveMediaWidgetState extends State<InteractiveMediaWidget> {
SliderTheme( SliderTheme(
data: SliderTheme.of(context).copyWith( data: SliderTheme.of(context).copyWith(
trackHeight: 2.5, trackHeight: 2.5,
thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 5), thumbShape:
overlayShape: const RoundSliderOverlayShape(overlayRadius: 10), const RoundSliderThumbShape(enabledThumbRadius: 5),
overlayShape:
const RoundSliderOverlayShape(overlayRadius: 10),
activeTrackColor: AppTheme.primary, activeTrackColor: AppTheme.primary,
inactiveTrackColor: AppTheme.surfaceLight, inactiveTrackColor: AppTheme.surfaceLight,
thumbColor: AppTheme.primary, thumbColor: AppTheme.primary,
@@ -423,7 +436,8 @@ class _InteractiveMediaWidgetState extends State<InteractiveMediaWidget> {
child: Slider( child: Slider(
value: _audioProgress.clamp(0.0, 1.0), value: _audioProgress.clamp(0.0, 1.0),
onChanged: (v) async { onChanged: (v) async {
final targetMs = (v * _audioDurationSeconds * 1000).toInt(); final targetMs =
(v * _audioDurationSeconds * 1000).toInt();
await _player.seek(Duration(milliseconds: targetMs)); await _player.seek(Duration(milliseconds: targetMs));
}, },
), ),
@@ -457,11 +471,13 @@ class _InteractiveMediaWidgetState extends State<InteractiveMediaWidget> {
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ 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), const SizedBox(width: 12),
Text( Text(
_getLabel(), _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<InteractiveMediaWidget> {
IconData _getIcon() { IconData _getIcon() {
switch (widget.message.type) { switch (widget.message.type) {
case "image": return Icons.photo_outlined; case "image":
case "video": return Icons.videocam_outlined; return Icons.photo_outlined;
case "audio": return Icons.audiotrack_outlined; case "video":
case "sticker": return Icons.emoji_emotions_outlined; return Icons.videocam_outlined;
default: return Icons.insert_drive_file_outlined; case "audio":
return Icons.audiotrack_outlined;
case "sticker":
return Icons.emoji_emotions_outlined;
default:
return Icons.insert_drive_file_outlined;
} }
} }
String _getLabel() { String _getLabel() {
switch (widget.message.type) { switch (widget.message.type) {
case "image": return "Image Attachment"; case "image":
case "video": return "Video Attachment"; return "Image Attachment";
case "audio": return "Audio / Voice Note"; case "video":
case "sticker": return "Sticker Attachment"; return "Video Attachment";
default: return "File Attachment"; case "audio":
return "Audio / Voice Note";
case "sticker":
return "Sticker Attachment";
default:
return "File Attachment";
} }
} }
} }