fist commit ftc staff app clone

This commit is contained in:
2024-08-01 13:46:46 +05:30
commit bf9064a9c9
515 changed files with 42796 additions and 0 deletions

View File

@@ -0,0 +1,503 @@
import 'dart:developer';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:ftc_mobile_app/controllers/home/inbox_screen_controller.dart';
import 'package:ftc_mobile_app/models/chat/all_group_messages_model.dart';
import 'package:ftc_mobile_app/models/chat/single_chat.dart';
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
import 'package:ftc_mobile_app/utilities/frequent_functions.dart';
import 'package:ftc_mobile_app/utilities/image_picker_popup.dart';
import 'package:ftc_mobile_app/utilities/local_storage_manager/export_local_storage.dart';
import 'package:ftc_mobile_app/view/custom_widgets/home/custom_message_dialog.dart';
import 'package:ftc_mobile_app/view/screens/chat/arguments/chat_screen_args.dart';
import 'package:ftc_mobile_app/web_services/chat_services.dart';
import 'package:ftc_mobile_app/web_services/web_url.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:socket_io_client/socket_io_client.dart';
import '../../../../models/chat/ChatModel.dart';
class ChatScreenController extends GetxController {
final GlobalKey<ScaffoldState> screenKey = GlobalKey<ScaffoldState>();
final messageTEC = TextEditingController();
final messageFN = FocusNode();
final messages = RxList<ChatModel>();
final isSocketConnected = false.obs;
late final ChatScreenArgs args;
String myId = "";
ChatScreenController(ChatScreenArgs data) {
args = data;
}
late Socket _socketIO;
String listenId = "";
@override
void onInit() {
//Getting my ID
// String userJson = LocalStorageManager.getSessionToken(
// tokenKey: LocalStorageKeys.kUserModelKey,
// );
// UserModel userModel = UserModel.fromJson(json.decode(userJson));
myId = LocalStorageManager.userId;
if (_canChat) {
initializeSocket();
}
super.onInit();
}
@override
void onReady() {
if (isGroup) {
fetchGroupMessagesFromService(args.groupData!.groupId);
} else {
fetchSingleMessagesFromService();
}
if (_canChat.not) {
showCantMessageDialog();
}
super.onReady();
}
bool get isGroup => args.groupData != null;
/// This method checks the current date if it lies within schedule time or not.
/// If it does, it means chat is enabled else chat will be disabled.
/// If schedule times not available, it returns true;
bool get _canChat {
final startMills = args.groupData?.scheduleTime.startTime ?? 0;
final endMills = args.groupData?.scheduleTime.endTime ?? 0;
if (startMills > 0 && endMills > 0) {
// Schedule times are available
final scheduleTime = _getScheduleTime(startMills, endMills);
final currentTime = TimeOfDay.now();
// Current time within start, end schedule time
return (currentTime.isAfter(scheduleTime.start) &&
currentTime.isBefore(scheduleTime.end));
} else {
// Schedule times not available
return true;
}
}
//Make sure to pass correct millis values
({TimeOfDay start, TimeOfDay end}) _getScheduleTime(
int startMills, int endMills) {
final sd = DateTime.fromMillisecondsSinceEpoch(startMills);
final ed = DateTime.fromMillisecondsSinceEpoch(endMills);
final startTime = TimeOfDay(hour: sd.hour, minute: sd.minute);
final endTime = TimeOfDay(hour: ed.hour, minute: ed.minute);
return (start: startTime, end: endTime);
}
initializeSocket() {
debugPrint('Socket address: ${WebUrls.socketUrl}');
_socketIO = io(
WebUrls.socketUrl,
OptionBuilder()
.setTransports(['websocket']) // for Flutter or Dart VM
.enableForceNewConnection()
.enableAutoConnect()
.setExtraHeaders({'foo': 'bar'}) // optional
.build());
isSocketConnected.value = true;
_socketIO.onConnect((_) {
isSocketConnected.value = true;
debugPrint('Socket Connected');
});
_socketIO.onDisconnect((_) {
debugPrint('Socket Disconnected');
// isSocketConnected.value = false;
});
_socketIO.onConnectError((e) {
debugPrint('Socket Connection Error: ${e.toString()}');
// isSocketConnected.value = false;
});
_socketIO.onConnectTimeout((e) {
debugPrint('Socket timeout Error: ${e.toString()}');
// isSocketConnected.value = false;
});
//listenIdReceive
listenId = (isGroup) ? args.groupData!.groupId : (myId + args.otherUserId);
debugPrint('listen on: $listenId');
_socketIO.on(listenId, (data) {
debugPrint('listen on listenId: $data');
_handleIncomingMessages(data);
});
}
_handleIncomingMessages(Map<String, dynamic> chatJson) {
log("chat listen: $chatJson");
// _total += 1;
// _skip += 1;
final chatModel = ChatModel.fromJson(chatJson);
if (chatJson.containsKey('createdAt')) {
chatModel.date =
DateTime.tryParse(chatJson["createdAt"])?.millisecondsSinceEpoch ?? 0;
} else {
chatModel.date = DateTime.now().millisecondsSinceEpoch;
}
if (isGroup) {
if (chatJson.containsKey('userId') && chatJson["userId"] is Map) {
chatModel.from = UserData.fromJson(chatJson["userId"]);
}
_onFirstMessageSent();
} else {
chatModel.from = UserData(
id: args.otherUserId,
name: args.name,
profilePictureUrl: args.profilePicPath);
chatModel.to = UserData(id: chatJson['to']);
}
messages.insert(0, chatModel);
args.onLastMessageUpdate?.call(chatModel);
}
Future fetchSingleMessagesFromService() async {
// _skip = 0;
final response = await ChatService()
.allSingleUsersChatMessagesServerAdmin(
from: myId,
to: args.otherUserId,
)
.showLoader();
if (response is List<ChatModel>) {
if (response.isNotEmpty) {
//Note: Converting this response to List of ChatModel objects
// List<ChatModel> chats = [];
// await Future.forEach(response.reversed, (e) {
// chats.add(ChatModel(
// id: e.id,
// from: e.from,
// to: e.to,
// message: e.message,
// date:
// DateTime.tryParse(e.createdAt)?.millisecondsSinceEpoch ?? 0));
// });
messages.value = response.reversed.toList();
}
} else if (response is String) {
FrequentFunctions.showToast(message: response);
}
}
void fetchGroupMessagesFromService(String idOfGroup) async {
dynamic response = await ChatService().allGroupMessages(
sortOrder: -1,
offset: 0,
limit: 100000,
groupId: idOfGroup,
isDeleted: false).showLoader();
if (response is List<AllGroupMessages>) {
if (response.isNotEmpty) {
//Note: Converting this response to List of ChatModel objects
List<ChatModel> chats = [];
await Future.forEach(response, (e) {
chats.add(ChatModel(
id: e.id,
from: e.userId,
message: e.message,
messageType: e.messageType,
filePath: e.filePath,
date:
DateTime.tryParse(e.createdAt)?.millisecondsSinceEpoch ?? 0));
});
messages.value = chats;
}
} else if (response is String) {
FrequentFunctions.showToast(message: response);
}
}
void sendMessageButtonPressed() async {
if (messageTEC.text.trim().isEmpty) {
return;
}
_sendMessage(
message: messageTEC.text.trim(),
);
messageTEC.clear();
}
//if sending first message, then updating chat list screen by calling it's listing api
_onFirstMessageSent() {
if (messages.length == 1) {
try {
final iController = Get.find<InboxScreenController>();
iController.onFirstMessageSend.value = true;
print("Got controller");
} catch (e) {
debugPrint(e.toString());
}
}
}
_sendMessage({
String? message,
File? file,
}) {
if (isGroup) {
_sendGroupMessage(
message: message,
file: file,
);
} else {
_sendPrivateMessage(
message: message,
file: file,
);
}
}
///Note: no need to update ui for sent message here because
///it's gonna handled by socket event
_sendGroupMessage({
String? message,
File? file,
}) async {
await ChatService().addGroupMessageService(
message: message ?? "",
messageType: (file != null) ? MessageType.file : MessageType.message,
file: file,
userId: myId,
groupId: args.groupData!.groupId,
);
}
///Note: handling messages list update also here
_sendPrivateMessage({
String? message,
File? file,
}) async {
final id = DateTime.now().millisecondsSinceEpoch;
final model = ChatModel(
id: id.toString(),
from: UserData(id: LocalStorageManager.userId),
to: UserData(
id: args.otherUserId,
name: args.name,
profilePictureUrl: args.profilePicPath,
),
message: message,
messageType:
(file != null) ? MessageType.file.name : MessageType.message.name,
fileType: (file != null) ? ChatModel.fileTypeLocalPath : null,
date: id,
state: ChatModel.stateLoading,
);
messages.insert(0, model);
args.onLastMessageUpdate?.call(model);
dynamic response = await ChatService().addSingleMessage(
message: message ?? "",
messageType: (file != null) ? MessageType.file : MessageType.message,
file: file,
senderId: LocalStorageManager.userId,
receiverId: args.otherUserId,
);
final msg = messages.firstWhereOrNull((e) {
return e.id == id.toString();
});
if (msg != null) {
final index = messages.indexOf(msg);
if (response is SingleChatModelClass) {
//message sent successfully
msg.id = response.id;
msg.fileType = null;
msg.state = ChatModel.stateSuccess;
messages
..removeAt(index)
..insert(index, msg);
_onFirstMessageSent();
} else {
msg.state = ChatModel.stateError;
messages.removeAt(index);
}
}
}
pickAndSendFile() async {
Get.focusScope?.unfocus();
Get.bottomSheet(CupertinoActionSheet(
actions: [
ListTile(
onTap: () {
Get.back();
ImagePickerPopup.getImageFromSource(
fromCamera: true,
onFetchImage: (f) {
_sendMessage(file: f);
});
},
leading: const Icon(CupertinoIcons.camera),
title: const Text("Camera"),
trailing: Icon(
Icons.arrow_forward_ios_rounded,
size: 18.r,
),
),
ListTile(
onTap: () async {
Get.back();
FilePickerResult? result =
await FilePicker.platform.pickFiles(type: FileType.media);
if (result != null && result.files.single.path != null) {
if (result.files.single.path!.isImageFileName) {
_sendMessage(file: File(result.files.single.path!));
} else {
FrequentFunctions.showToast(message: "File doesn't supported ");
}
}
},
leading: const Icon(CupertinoIcons.photo_on_rectangle),
title: const Text("Gallery"),
trailing: Icon(
Icons.arrow_forward_ios_rounded,
size: 18.r,
),
),
ListTile(
onTap: () async {
Get.back();
final FilePickerResult? result = await FilePicker.platform
.pickFiles(
type: FileType.custom,
allowedExtensions: ["pdf", "doc", "docx", "xlsx", "xls"]);
if (result != null) {
_sendMessage(file: File(result.files.single.path!));
}
},
leading: const Icon(Icons.attach_file),
title: const Text("File"),
trailing: Icon(
Icons.arrow_forward_ios_rounded,
size: 18.r,
),
),
],
));
}
// _sendImage(File file) async {
// debugPrint("file: ${file.path}");
// //
// // ChatModel model = ChatModel(
// // sentBy: UserData(id: myId),
// // sentTo: otherUser,
// // date: DateTime.now().toUtc().millisecondsSinceEpoch,
// // files: [file.path],
// // fileType: fileTypeLocalPath,
// // state: ChatModel.stateLoading);
// //
// // final modelHash = model.hashCode.toString();
// // model.localId = modelHash;
// //
// // debugPrint("message modelHash: $modelHash");
// // _handleChat(model.toJson());
// //
// // // return;
// // var res = await repository.sendChatAttachmentApi(
// // req: ChatMessageRequest(
// // sentBy: myId,
// // sentTo: otherUser.id!,
// // files: [file],
// // fileType: "image"),
// // );
// //
// // final i = messages.indexWhere((e) => e.localId == modelHash);
// //
// // if (res.success == true) {
// // if (i != -1) {
// // messages[i].state = ChatModel.stateSuccess;
// // messages.refresh();
// // }
// // } else {
// // if (i != -1) {
// // messages[i].state = ChatModel.stateError;
// // messages.refresh();
// // }
// // }
// }
//Always call this method if _canChat is false
void showCantMessageDialog() {
final startMills = args.groupData!.scheduleTime.startTime;
final endMills = args.groupData!.scheduleTime.endTime;
final scheduleTime = _getScheduleTime(startMills, endMills);
final sd = DateTime(
2024, 1, 1, scheduleTime.start.hour, scheduleTime.start.minute, 0);
final ed =
DateTime(2024, 1, 1, scheduleTime.end.hour, scheduleTime.end.minute, 0);
showDialog(
context: screenKey.currentState!.context,
builder: (BuildContext context) {
return CustomMessageDialog(
dialogButtonText: "Close",
dialogMessageText:
"It is currently outside the working hours. You can only send message during the working hours",
dialogMessageTextBold:
"Working hours: ${DateFormat("hh:mm aa").format(sd)} - ${DateFormat("hh:mm aa").format(ed)}",
headingText: "You Can't message right now",
);
},
);
}
// new
void removeFocus() {
FocusScope.of(screenKey.currentContext!).unfocus();
}
@override
void dispose() {
try {
_socketIO.clearListeners();
_socketIO.disconnect();
_socketIO.destroy();
_socketIO.dispose();
} catch (e) {
print(e);
}
messageTEC.dispose();
messageFN.dispose();
// scrollController.dispose();
Get.delete<ChatScreenController>();
super.dispose();
}
}