2026-04-15

This commit is contained in:
mageshwaran committed 2026-04-15 12:32:30 +05:30
1 parent d01e5ba860
commit 96de59e9be
46 files changed
+1299 -1191

No files matched your search

+3 -3
View File
@@ -39,7 +39,7 @@ class ChatProfileScreen extends ConsumerWidget {
title: const Text(
"Profile",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w400,
fontSize: 20,
height: 1.4,
@@ -113,7 +113,7 @@ class ChatProfileScreen extends ConsumerWidget {
const Text(
"Shared By Taxglide",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 20,
height: 1.4,
@@ -213,7 +213,7 @@ class ChatProfileScreen extends ConsumerWidget {
const Text(
"Shared By Client",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 20,
height: 1.4,
+53 -54
View File
@@ -7,6 +7,7 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:taxglide/consts/download_helper.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/controller/api_repository.dart';
import 'package:taxglide/model/chat_model.dart';
import 'package:taxglide/view/Mahi_chat/live_chat_screen.dart';
// ⭐⭐⭐ CHAT INPUT BOX WITH FILE TAG SUPPORT ⭐⭐⭐
@@ -246,49 +247,61 @@ class _ChatInputBoxState extends ConsumerState<ChatInputBox> {
setState(() => _isSending = true);
// Show loading dialog
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => WillPopScope(
onWillPop: () async => false,
child: const Center(
child: Card(
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text("Sending message..."),
],
),
),
),
),
),
// ⭐ OPTIMISTIC UI: Create a temporary message and add it immediately
final tempId = DateTime.now().millisecondsSinceEpoch;
final tempMsg = MessageModel(
id: tempId,
chatBy: "user", // User
message: text,
type: selectedFiles.isNotEmpty ? "file" : "text",
isDelivered: 0,
isRead: 0,
createdAt: DateTime.now().toIso8601String(),
userId: 0,
tagId: tagId > 0 ? tagId : null,
parentTag: taggedMessage != null ? ParentTagModel(
id: taggedMessage.id,
message: taggedMessage.message,
type: taggedMessage.type,
fileName: taggedMessage.fileName,
) : null,
uploadedDocuments: selectedFiles.map((file) => DocumentModel(
filePath: file.path,
fileName: file.path.split('/').last,
fileType: "image",
)).toList(),
documents: [],
);
// Add to UI immediately
final notifier = ref.read(chatMessagesProvider(widget.chatId).notifier);
notifier.addNewMessage(tempMsg);
// Clear input immediately for snappy feel
final savedSelectedFiles = List<File>.from(selectedFiles);
messageCtrl.clear();
selectedFiles.clear();
ref.read(taggedMessageProvider.notifier).state = null;
// Notify parent to scroll to bottom instantly
if (widget.onMessageSent != null) {
widget.onMessageSent!();
}
try {
List<File> filesToUpload = [];
// ⭐⭐⭐ Save files to Send folder
if (selectedFiles.isNotEmpty) {
print("📤 Saving ${selectedFiles.length} files to Send folder...");
for (File file in selectedFiles) {
if (savedSelectedFiles.isNotEmpty) {
for (File file in savedSelectedFiles) {
try {
// Try to save to Send folder, fallback to original if fails
final savedPath = await DownloadHelper.saveToSendFolder(file);
filesToUpload.add(File(savedPath));
} catch (e) {
print("⚠️ Could not save file, using original: $e");
filesToUpload.add(file);
}
}
print("✅ Files prepared for upload: ${filesToUpload.length}");
}
// Send message with files
@@ -299,37 +312,22 @@ class _ChatInputBoxState extends ConsumerState<ChatInputBox> {
files: filesToUpload,
);
// Refresh chat messages
await ref.read(chatMessagesProvider(widget.chatId).notifier).refresh();
// Refresh chat messages (this will replace the temp message with the real one)
await notifier.refresh();
ref.invalidate(chatDocumentProvider);
print("✅ Message sent successfully with tagId: $tagId");
// Close loading dialog
if (mounted) Navigator.pop(context);
// Clear input
if (mounted) {
setState(() {
messageCtrl.clear();
selectedFiles.clear();
_isSending = false;
});
}
// Clear the tagged message
ref.read(taggedMessageProvider.notifier).state = null;
// Notify parent to scroll to bottom
if (widget.onMessageSent != null) {
widget.onMessageSent!();
setState(() => _isSending = false);
}
} catch (e) {
print("❌ Error sending message: $e");
if (mounted) {
setState(() => _isSending = false);
}
// Close loading dialog
if (mounted) Navigator.pop(context);
setState(() => _isSending = false);
// If it failed, delete the temporary message
notifier.deleteMessage(tempId);
// Show error message
if (mounted) {
@@ -361,6 +359,7 @@ class _ChatInputBoxState extends ConsumerState<ChatInputBox> {
}
}
@override
Widget build(BuildContext context) {
final taggedMessage = ref.watch(taggedMessageProvider);
+1 -1
View File
@@ -270,7 +270,7 @@ class _DownloadsScreenState extends State<DownloadsScreen>
title: const Text(
"Downloads",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
),
),
+2 -5
View File
@@ -9,7 +9,7 @@ class SwipeableMessageBubble extends StatefulWidget {
final MessageModel message;
final DateTime msgDate;
final String Function(DateTime) formatTime;
final Widget Function(int, int) buildTick;
final Widget Function(MessageModel) buildTick;
final VoidCallback onSwipe;
final Function(int?)? onParentTagTap;
final Function(List<String> imageUrls, int initialIndex)?
@@ -669,10 +669,7 @@ class SwipeableMessageBubbleState extends State<SwipeableMessageBubble>
),
),
const SizedBox(width: 4),
widget.buildTick(
widget.message.isDelivered,
widget.message.isRead,
),
widget.buildTick(widget.message),
],
),
],
+16 -4
View File
@@ -160,8 +160,11 @@ class _LiveChatScreenState extends ConsumerState<LiveChatScreen>
try {
final event = message['event'] as String?;
if (event == 'message.sent' || event == 'message.received') {
debugPrint("🔔 New message detected!");
if (event == 'message.sent' ||
event == 'message.received' ||
event == 'message.read' ||
event == 'message.delivered') {
debugPrint("🔔 Message status/new message event: $event");
if (WidgetsBinding.instance.lifecycleState ==
AppLifecycleState.resumed) {
@@ -409,7 +412,16 @@ class _LiveChatScreenState extends ConsumerState<LiveChatScreen>
return "$hour:$minute $period";
}
Widget buildTick(int isDelivered, int isRead) {
Widget buildTick(MessageModel message) {
// ⭐ Status 0/1/pending
final isRead = message.isRead;
final isDelivered = message.isDelivered;
// Check if it's an optimistic pending message (huge ID)
if (message.id > 1000000000000) {
return const Icon(Icons.schedule, size: 14, color: Colors.grey);
}
if (isRead == 1) {
return const Icon(Icons.done_all, size: 16, color: Colors.blue);
} else if (isDelivered == 1) {
@@ -445,7 +457,7 @@ class _LiveChatScreenState extends ConsumerState<LiveChatScreen>
? 'File ID : ${widget.fileid.toString()}'
: "Live Chat",
style: const TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
),
),