955 lines
28 KiB
Dart
955 lines
28 KiB
Dart
import 'dart:async';
|
|
import 'dart:developer' as dev;
|
|
import 'dart:io';
|
|
import 'dart:math';
|
|
import 'package:audio_waveforms/audio_waveforms.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_sound/flutter_sound.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:taafee_mobile/core/utils/pagination_list.dart';
|
|
import 'package:taafee_mobile/core/utils/rx_futures.dart';
|
|
import 'package:taafee_mobile/core/utils/utils.dart';
|
|
import 'package:taafee_mobile/features/chat/data_layer/model/chat_user.dart';
|
|
import 'package:taafee_mobile/features/chat/data_layer/model/room.dart';
|
|
import 'package:taafee_mobile/features/chat/data_layer/service/chat_resource.dart'
|
|
as resource;
|
|
// import 'package:path_provider/path_provider.dart';
|
|
import 'package:rx_future/rx_future.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import '../../../core/errors/custom_exception.dart';
|
|
import '../../../core/local_storage/local_storage.dart';
|
|
import '../../../core/network/socket/socket.dart';
|
|
import '../data_layer/model/message.dart';
|
|
import '../data_layer/service/chat_files_source.dart';
|
|
import '../data_layer/service/chat_listener.dart';
|
|
|
|
enum SocketConnectionState { connected, connecting, notConnected, error }
|
|
|
|
class ChatController extends GetxController {
|
|
//sources
|
|
resource.ChatResource chatResource = resource.ChatResource();
|
|
|
|
ChatListener chatListener = ChatListener();
|
|
|
|
ChatFilesSource chatFilesSource = ChatFilesSource();
|
|
|
|
LocalStorage localStorage = LocalStorage();
|
|
//initialization
|
|
Future<void> init(
|
|
{dynamic Function(MessageModel)? handler,
|
|
required Function(dynamic) onSessionTerminated}) async {
|
|
if (isInitialized) return;
|
|
chatUser = ChatUser(
|
|
id: localStorage.getChatUserId() ?? 0,
|
|
name: localStorage.getUser()!.firstName);
|
|
await socketInit();
|
|
receiveMessagesInRoom();
|
|
receiveMessages(handler: handler);
|
|
listenForMessagesReading();
|
|
listenOnRoomState();
|
|
listenOnSessionTerminated(onSessionTerminated: onSessionTerminated);
|
|
}
|
|
|
|
//socket
|
|
|
|
SocketIO io = Get.find<SocketIO>();
|
|
|
|
bool isInitialized = false;
|
|
|
|
Future<void> socketInit() async {
|
|
if (isInitialized) return;
|
|
io.init();
|
|
io.setAuthentication(localStorage.getChatToken() ?? "");
|
|
io.setOnConnect(() {
|
|
connectionState.update((val) {
|
|
connectionState.value = SocketConnectionState.connected;
|
|
});
|
|
connectionState.refresh();
|
|
dev.log("Connected Successfully");
|
|
});
|
|
io.setOnDisconnect(() {
|
|
dev.log("Socket disconnected");
|
|
connectionState.update((val) {
|
|
val = SocketConnectionState.notConnected;
|
|
});
|
|
connectionState.refresh();
|
|
});
|
|
io.setOnConnecting(() {
|
|
connectionState.update((val) {
|
|
val = SocketConnectionState.connecting;
|
|
});
|
|
connectionState.refresh();
|
|
dev.log("Connecting to socket");
|
|
});
|
|
io.setOnConnectionError(() {
|
|
dev.log("Error Connecting to socket");
|
|
connectionState.update((val) {
|
|
val = SocketConnectionState.error;
|
|
});
|
|
connectionState.refresh();
|
|
throw GenericException(
|
|
type: ExceptionType.connectionError,
|
|
errorMessage: "You Have no Internet Connection",
|
|
);
|
|
});
|
|
|
|
isInitialized = true;
|
|
await io.connect();
|
|
}
|
|
|
|
// user
|
|
ChatUser chatUser = ChatUser.zero();
|
|
|
|
/// ------------------- connection -----------///
|
|
RxFuture<void> serverState = RxFuture(null);
|
|
|
|
Rx<SocketConnectionState> connectionState =
|
|
SocketConnectionState.notConnected.obs;
|
|
|
|
bool get shouldConnect =>
|
|
(connectionState.value == SocketConnectionState.error) |
|
|
(connectionState.value == SocketConnectionState.notConnected);
|
|
|
|
Future<void> connectToServer({Function? onSuccess}) async {
|
|
if (!shouldConnect) return;
|
|
serverState.observe((_) async {
|
|
return await io.boot();
|
|
}, onSuccess: ((p0) {
|
|
onSuccess?.call();
|
|
}));
|
|
}
|
|
|
|
/// ------------------- Rooms ----------------///
|
|
RxFuture<Pagination<Room>> rooms = RxFuture(Pagination());
|
|
|
|
int? get currentRoomId => currentRoom.value?.id;
|
|
|
|
ChatUser? get currentChatUser => currentRoom.value!.user;
|
|
|
|
Rx<Room?> currentRoom = null.obs;
|
|
|
|
//private
|
|
void setCurrentRoom(Room room) {
|
|
currentRoom = room.obs;
|
|
currentRoom.refresh();
|
|
}
|
|
|
|
Room? getRoomById(int? id) => id == null
|
|
? null
|
|
: rooms.result.data.firstWhereOrNull((element) => element.id == id);
|
|
|
|
// Future<void> getRooms({int? specificPage}) async {
|
|
// await connectToServer();
|
|
// await rooms.observe(
|
|
// (value) async {
|
|
// await value!.nextPage(
|
|
// (currentPage) async {
|
|
// return chatResource.getRooms(currentPage);
|
|
// },
|
|
// place: InsertPlace.end,
|
|
// );
|
|
|
|
// return value; // there is no way that this would be null, there is a default value in rooms declaration.
|
|
// },
|
|
// multipleCallsBehavior: MultipleCallsBehavior.abortNew,
|
|
// );
|
|
// }
|
|
|
|
Future<void> getRooms({String searchQuery = '', int? specificPage}) async {
|
|
await connectToServer();
|
|
if (specificPage != null) {
|
|
rooms.update((val) {
|
|
val!.value.clear();
|
|
});
|
|
rooms.refresh();
|
|
}
|
|
await rooms.observe(
|
|
(value) async {
|
|
await value!.nextPage(
|
|
(currentPage) async {
|
|
return chatResource.getRooms(
|
|
searchQuery: searchQuery,
|
|
currentPage: specificPage ?? currentPage);
|
|
},
|
|
place: InsertPlace.end,
|
|
);
|
|
|
|
return value; // there is no way that this would be null, there is a default value in rooms declaration.
|
|
},
|
|
multipleCallsBehavior: MultipleCallsBehavior.abortNew,
|
|
);
|
|
}
|
|
|
|
void updateRoom() {
|
|
int index = rooms.result.data
|
|
.indexWhere((element) => (element.id == currentRoomId));
|
|
// rooms = Pagination(
|
|
// data: rooms.result.data.insert(0, Room.copy(currentRoom.value!)));
|
|
rooms.update((val) {
|
|
if (index == -1) {
|
|
val!.value.data.insert(0, Room.copy(currentRoom.value!));
|
|
index = 0;
|
|
}
|
|
if (currentRoom.value!.messages.data.isNotEmpty) {
|
|
val!.value.data[index].lastMessage =
|
|
currentRoom.value!.messages.data[0];
|
|
val.value.data[index].lastMessageDate =
|
|
currentRoom.value!.messages.data[0].createdAt;
|
|
}
|
|
if (index != 0) {
|
|
Room room = val!.value.data[index];
|
|
val.value.data.removeAt(index);
|
|
val.value.data.insert(0, room);
|
|
}
|
|
});
|
|
rooms.refresh();
|
|
}
|
|
|
|
RxFuture<Room?> createRoomState = RxFuture(null);
|
|
void createRoom(
|
|
{required int chatUserId, void Function(Room?)? onSuccess}) async {
|
|
await createRoomState.observe((value) async {
|
|
return await chatResource.createRoom(id: chatUserId);
|
|
}, onSuccess: (room) async {
|
|
await getRooms();
|
|
Room? roomById = getRoomById(room!.id);
|
|
if (roomById != null) {
|
|
room = roomById;
|
|
}
|
|
currentRoom = room.obs;
|
|
|
|
// currentRoom.update((val) {
|
|
// val = room;
|
|
// });
|
|
// currentRoom.value = room;
|
|
currentRoom.refresh();
|
|
onSuccess?.call(room);
|
|
}, onError: (err) {
|
|
if (err.toString() == 'email_already_exists') {
|
|
// getRooms()
|
|
// get the room that contains two users (chatUserId)
|
|
// setCurrentRoom
|
|
//
|
|
}
|
|
});
|
|
}
|
|
|
|
RxFuture<void> blockRoomState = RxFuture(null);
|
|
void blockRoom(
|
|
{void Function()? onSuccess, void Function(Object)? onError}) async {
|
|
blockRoomState.observe((value) async {
|
|
return await chatResource.blockRoom(id: currentRoomId!);
|
|
}, onSuccess: (value) async {
|
|
if (rooms.result.data.isEmpty) {
|
|
await getRooms();
|
|
}
|
|
int index = rooms.result.data
|
|
.indexWhere((element) => element.id == currentRoomId);
|
|
rooms.update((val) {
|
|
val!.value.data[index].state = RoomState.blocked;
|
|
});
|
|
currentRoom.update((val) {
|
|
val!.state = RoomState.blocked;
|
|
});
|
|
currentRoom.refresh();
|
|
rooms.refresh();
|
|
onSuccess?.call();
|
|
}, onError: (err) {
|
|
onError?.call(err);
|
|
});
|
|
}
|
|
|
|
RxFuture<void> unblockRoomState = RxFuture(null);
|
|
void unblockRoom(
|
|
{void Function()? onSuccess, void Function(Object)? onError}) async {
|
|
blockRoomState.observe((value) async {
|
|
return await chatResource.unblockRoom(id: currentRoomId!);
|
|
}, onSuccess: (value) {
|
|
int index = rooms.result.data
|
|
.indexWhere((element) => element.id == currentRoomId);
|
|
rooms.update((val) {
|
|
val!.value.data[index].state = RoomState.active;
|
|
});
|
|
currentRoom.update((val) {
|
|
val!.state = RoomState.active;
|
|
});
|
|
currentRoom.refresh();
|
|
rooms.refresh();
|
|
onSuccess?.call();
|
|
}, onError: (err) {
|
|
onError?.call(err);
|
|
});
|
|
}
|
|
|
|
void listenOnRoomState() {
|
|
listenOnRoomBlocked();
|
|
listenOnRoomBlocking();
|
|
listenOnRoomUnblocked();
|
|
// chatListener.updatedRoom((roomId, roomStatus) {
|
|
// if (rooms.result.data.isNotEmpty) {
|
|
// int index = rooms.result.data
|
|
// .indexWhere((element) => element.id == currentRoomId);
|
|
// rooms.update((val) {
|
|
// val!.value.data[index].state = Room.getRoomStateByString(roomStatus)!;
|
|
// });
|
|
// rooms.refresh();
|
|
// if (currentRoomId == roomId) {
|
|
// currentRoom.update((val) {
|
|
// val!.state = Room.getRoomStateByString(roomStatus)!;
|
|
// });
|
|
// currentRoom.refresh();
|
|
// }
|
|
// }
|
|
// });
|
|
}
|
|
|
|
void listenOnRoomUnblocked() {
|
|
chatListener.unblockedRoom((roomId) {
|
|
if (rooms.result.data.isNotEmpty) {
|
|
int index = rooms.result.data
|
|
.indexWhere((element) => element.id == currentRoomId);
|
|
rooms.update((val) {
|
|
val!.value.data[index].state = RoomState.active;
|
|
});
|
|
rooms.refresh();
|
|
if (currentRoomId == roomId) {
|
|
currentRoom.update((val) {
|
|
val!.state = RoomState.active;
|
|
});
|
|
currentRoom.refresh();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void listenOnRoomBlocked() {
|
|
chatListener.blockedRoom((roomId) {
|
|
if (rooms.result.data.isNotEmpty) {
|
|
int index = rooms.result.data
|
|
.indexWhere((element) => element.id == currentRoomId);
|
|
rooms.update((val) {
|
|
val!.value.data[index].state = RoomState.blocking;
|
|
});
|
|
rooms.refresh();
|
|
if (currentRoomId == roomId) {
|
|
currentRoom.update((val) {
|
|
val!.state = RoomState.blocking;
|
|
});
|
|
currentRoom.refresh();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void listenOnRoomBlocking() {
|
|
chatListener.blockingRoom((roomId) {
|
|
if (rooms.result.data.isNotEmpty) {
|
|
int index = rooms.result.data
|
|
.indexWhere((element) => element.id == currentRoomId);
|
|
rooms.update((val) {
|
|
val!.value.data[index].state = RoomState.blocked;
|
|
});
|
|
rooms.refresh();
|
|
if (currentRoomId == roomId) {
|
|
currentRoom.update((val) {
|
|
val!.state = RoomState.blocked;
|
|
});
|
|
currentRoom.refresh();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void listenOnSessionTerminated(
|
|
{required Function(dynamic) onSessionTerminated}) {
|
|
chatListener.termminatedSession(onSessionTerminated);
|
|
}
|
|
|
|
//support
|
|
RxFuture<Room?> supportRoomState = RxFuture(null);
|
|
Future<void> checkSupportRoomStatus(
|
|
{void Function(Room?)? onSuccess, void Function(Object)? onError}) async {
|
|
supportRoomState.observe((value) async {
|
|
return await chatResource.checkSupportRoomStatus();
|
|
}, onSuccess: (room) async {
|
|
if (room == null) {
|
|
Room newSupportRoom = await chatResource.createSupportRoom();
|
|
setCurrentRoom(newSupportRoom);
|
|
//creat support room
|
|
//set current room
|
|
} else {
|
|
//set current room
|
|
setCurrentRoom(room);
|
|
}
|
|
onSuccess?.call(currentRoom.value);
|
|
}, onError: (err) {
|
|
onError?.call(err);
|
|
});
|
|
}
|
|
|
|
/// ------------- messages -------------- ///
|
|
|
|
// getMessages
|
|
RxFutures<void> messagesState = RxFutures();
|
|
|
|
Future<void> getCurrentRoomMessages({int? specificPage}) async {
|
|
if (currentRoom.value == null ||
|
|
(currentRoom.value!.messagesStateId != null &&
|
|
messagesState.loading(currentRoom.value!.messagesStateId!))) return;
|
|
|
|
String id = messagesState.init(RxFuture(null));
|
|
|
|
currentRoom.value!.messagesStateId = id;
|
|
|
|
await messagesState.observe(
|
|
id,
|
|
(value) async {
|
|
return await currentRoom.value!.messages.nextPage((currentPage) async {
|
|
return await chatResource.getCurrentRoomMessages(
|
|
roomId: currentRoomId!, page: specificPage ?? currentPage);
|
|
});
|
|
},
|
|
onSuccess: (value) {
|
|
currentRoom.refresh();
|
|
},
|
|
multipleCallsBehavior: MultipleCallsBehavior.abortNew,
|
|
);
|
|
}
|
|
|
|
//read Message
|
|
RxFutures<void> readMessageState = RxFutures();
|
|
void readMessage({required int messageId}) async {
|
|
dev.log('i am reading message with id : $messageId');
|
|
String sendingStateId = readMessageState.init(RxFuture(null));
|
|
readMessageState.observe(sendingStateId, (value) async {
|
|
await chatResource.readMessage(messageId: messageId);
|
|
}, onSuccess: (value) {
|
|
int index = currentRoom.value!.messages.data
|
|
.indexWhere((element) => element.id == messageId);
|
|
currentRoom.update((val) {
|
|
val!.messages.data[index].readBy!.ids
|
|
.insert(0, val.messages.data[index].user.id);
|
|
});
|
|
currentRoom.refresh();
|
|
});
|
|
}
|
|
|
|
void listenForMessagesReading() {
|
|
chatListener.messagesReaded((messageId, userId) {
|
|
if (currentRoom.value != null &&
|
|
currentRoom.value!.type == RoomType.private) {
|
|
currentRoom.update((val) {
|
|
int index = val!.messages.data
|
|
.indexWhere((element) => element.id == messageId);
|
|
|
|
val.messages.data[index].readBy!.ids.insert(0, userId);
|
|
});
|
|
currentRoom.refresh();
|
|
}
|
|
});
|
|
}
|
|
|
|
// sendMessages
|
|
RxFutures<MessageModel> sendingMessageState = RxFutures();
|
|
|
|
RxBool isMessageLoading(String? sendingMessageStateId) {
|
|
if (sendingMessageStateId != null) {
|
|
return messagesState.loading(sendingMessageStateId).obs;
|
|
} else {
|
|
return false.obs;
|
|
}
|
|
}
|
|
|
|
Future<void> sendMessage(MessageModel message,
|
|
{int? roomId, String? filePath, void Function(Object e)? onError}) async {
|
|
if (roomId == null && currentRoom.value == null) {
|
|
throw Exception(
|
|
"You must either provide room id, or select a room to send message",
|
|
);
|
|
}
|
|
message.user = chatUser;
|
|
message.userId = chatUser.id;
|
|
if (shouldConnect) {
|
|
try {
|
|
await io.boot();
|
|
await getCurrentRoomMessages(specificPage: 1);
|
|
} catch (err) {
|
|
onError?.call(err);
|
|
}
|
|
}
|
|
String sendingStateId = sendingMessageState.init(RxFuture(message));
|
|
|
|
message.sendingStateId = sendingStateId;
|
|
|
|
await sendingMessageState.observe(sendingStateId, (_) async {
|
|
message.sendingStateId = sendingStateId;
|
|
|
|
// currentRoom.value!.messages.data.insert(0, MessageModel.copy(message));
|
|
if (message.type != MessageType.voice) {
|
|
currentRoom.update((val) {
|
|
val!.messages.data.insert(0, MessageModel.copy(message));
|
|
});
|
|
}
|
|
if (message.type != MessageType.text) {
|
|
await uploadFile(filePath: filePath!);
|
|
if (uploadFileState.result != null) {
|
|
int id = uploadFileState.result!;
|
|
message.content = "$id";
|
|
} else {
|
|
onError?.call(e);
|
|
currentRoom.update((val) {
|
|
val!.messages.data.removeAt(0);
|
|
});
|
|
return message;
|
|
}
|
|
}
|
|
if (message.type == MessageType.voice) {
|
|
currentRoom.update((val) {
|
|
// message.temporaryFile = null;
|
|
|
|
val!.messages.data.insert(0, MessageModel.copy(message));
|
|
|
|
val.messages.data[0].content = '${uploadFileState.result}';
|
|
// val.messages.data[0].temporaryFile = null;
|
|
});
|
|
currentRoom.refresh();
|
|
}
|
|
return await chatResource.sendMessage(
|
|
messageModel: message, roomId: currentRoomId!);
|
|
}, onSuccess: (value) {
|
|
currentRoom.update((val) {
|
|
val!.messages.data[0].id = value.id;
|
|
val.messages.data[0].sendingStateId = null;
|
|
val.messages.data[0].content = value.content;
|
|
val.messages.data[0].readBy = value.readBy;
|
|
if (message.type != MessageType.voice) {
|
|
val.messages.data[0].temporaryFile = null;
|
|
}
|
|
});
|
|
rooms.refresh();
|
|
}, onError: (err) {
|
|
currentRoom.update((val) {
|
|
val!.messages.data.removeAt(0);
|
|
});
|
|
|
|
onError?.call(err);
|
|
});
|
|
}
|
|
|
|
// cancel sending
|
|
void cancelSendingMessage(MessageModel message) {
|
|
if (message.sendingStateId == null ||
|
|
!sendingMessageState.loading(message.sendingStateId!)) return;
|
|
|
|
sendingMessageState.cancel(message.sendingStateId!);
|
|
}
|
|
|
|
// receive Messages
|
|
|
|
void receiveMessagesInRoom() async {
|
|
connectToServer();
|
|
|
|
chatListener.receiveMessage((message) {
|
|
currentRoom.update((val) {
|
|
val?.messages.data.insert(0, message);
|
|
});
|
|
});
|
|
}
|
|
|
|
void receiveMessages({dynamic Function(MessageModel)? handler}) async {
|
|
connectToServer();
|
|
chatListener.receiveMessage((message) async {
|
|
if (rooms.result.data.isEmpty) {
|
|
await getRooms();
|
|
}
|
|
if (rooms.result.data
|
|
.lastIndexWhere((element) => element.id == message.roomId) ==
|
|
-1) {
|
|
await getRooms();
|
|
}
|
|
|
|
int index = rooms.result.data
|
|
.lastIndexWhere((element) => element.id == message.roomId);
|
|
|
|
if (index == -1) {
|
|
rooms.update((val) {
|
|
val!.value.data.insert(
|
|
0,
|
|
Room(
|
|
id: message.roomId,
|
|
user: message.user,
|
|
lastMessageDate: message.createdAt));
|
|
});
|
|
index = 0;
|
|
}
|
|
rooms.update((val) {
|
|
val!.value.data[index].lastMessage = message;
|
|
});
|
|
rooms.refresh();
|
|
//assign when user tap .
|
|
// currentRoom.value = rooms.result.data
|
|
// .firstWhere((element) => (element.id == message.roomId));
|
|
handler?.call(message);
|
|
});
|
|
}
|
|
|
|
// upload Files
|
|
RxFuture<int?> uploadFileState = RxFuture(null);
|
|
Future<void> uploadFile({required String filePath}) async {
|
|
await uploadFileState.observe((value) async {
|
|
return await chatFilesSource.uploadFile(
|
|
roomId: currentRoomId!, filePath: filePath);
|
|
});
|
|
}
|
|
|
|
// Chat Details scroll controller
|
|
Rx<ScrollController> scrollController = ScrollController().obs;
|
|
|
|
void scrollControllerJump() {
|
|
scrollController.update((val) {
|
|
val!.jumpTo(0);
|
|
});
|
|
scrollController.refresh();
|
|
}
|
|
|
|
// keyBoard opening detection
|
|
RxBool keyBoardOpened = false.obs;
|
|
void setkeyBoardOpened(bool newValue) {
|
|
keyBoardOpened.value = newValue;
|
|
keyBoardOpened.refresh();
|
|
}
|
|
|
|
//reply senario handling
|
|
RxBool isReplying = false.obs;
|
|
|
|
void toggleIsReplying() => isReplying.value = !isReplying.value;
|
|
|
|
Rx<MessageModel> replyModel = MessageModel.zero().obs;
|
|
|
|
void updateReplyModel({
|
|
required MessageModel messageModel,
|
|
}) {
|
|
replyModel.value = messageModel;
|
|
|
|
replyModel.refresh();
|
|
}
|
|
|
|
//voice message
|
|
FlutterSoundRecorder voiceRecorder = FlutterSoundRecorder();
|
|
|
|
File recordFile = File('record.wav');
|
|
|
|
bool isRecordReady = false;
|
|
|
|
RxBool isRecording = false.obs;
|
|
|
|
RxString recordingTime = '00:00'.obs;
|
|
|
|
File? audioFile;
|
|
|
|
toggleIsRecording() {
|
|
if (isRecording.value == false) {
|
|
recordingTime.value = '00:00';
|
|
recordingTime.refresh();
|
|
}
|
|
isRecording.value = !isRecording.value;
|
|
isRecording.refresh();
|
|
}
|
|
|
|
Future<File?> getVoiceFile({required String id}) async {
|
|
return await chatFilesSource.getVoiceFile(id);
|
|
}
|
|
|
|
void timer() {
|
|
var startTime = DateTime.now();
|
|
Timer.periodic(const Duration(seconds: 1), (t) {
|
|
var diff = DateTime.now().difference(startTime);
|
|
recordingTime.value =
|
|
'${diff.inHours == 0 ? '' : '${diff.inHours.toString().padLeft(2, "0")}:'}${(diff.inMinutes % 60).floor().toString().padLeft(2, "0")}:${(diff.inSeconds % 60).floor().toString().padLeft(2, '0')}';
|
|
recordingTime.refresh();
|
|
if (!voiceRecorder.isRecording) {
|
|
t.cancel();
|
|
}
|
|
});
|
|
}
|
|
|
|
Future initRecorder() async {
|
|
final status = await Permission.microphone.request();
|
|
if (status != PermissionStatus.granted) {
|
|
throw 'dfaf';
|
|
}
|
|
await Permission.storage.request();
|
|
await Permission.manageExternalStorage.request();
|
|
|
|
await voiceRecorder.openRecorder();
|
|
|
|
isRecordReady = true;
|
|
|
|
voiceRecorder.setSubscriptionDuration(const Duration(microseconds: 500));
|
|
}
|
|
|
|
Future record() async {
|
|
if (!isRecordReady) return;
|
|
|
|
await voiceRecorder.startRecorder(
|
|
toFile: '${Utils.randomString(5)}${Random().nextInt(100000)}');
|
|
|
|
timer();
|
|
}
|
|
|
|
Future cancelRecording() async {
|
|
recordingTime.value = '00:00';
|
|
recordingTime.refresh();
|
|
await voiceRecorder.stopRecorder();
|
|
}
|
|
|
|
Future stopRecording({void Function(Object)? onError}) async {
|
|
recordingTime.value = '00:00';
|
|
recordingTime.refresh();
|
|
if (!isRecordReady) return;
|
|
|
|
String? path = await voiceRecorder.stopRecorder();
|
|
audioFile = File(path!);
|
|
await sendMessage(
|
|
MessageModel(
|
|
user: chatUser,
|
|
userId: chatUser.id,
|
|
roomId: currentRoomId!,
|
|
content: '',
|
|
createdAt: DateTime.now(),
|
|
temporaryFile: File(audioFile!.path),
|
|
type: MessageType.voice,
|
|
),
|
|
filePath: audioFile!.path,
|
|
roomId: currentRoomId, onError: (err) {
|
|
onError?.call(err);
|
|
});
|
|
}
|
|
|
|
RxMap<String, File> voiceFiles = <String, File>{}.obs;
|
|
|
|
Map<String, Rx<PlayerController>> voicePlayers = {};
|
|
|
|
RxMap<String, bool> isPlayingMap = <String, bool>{}.obs;
|
|
|
|
RxMap<String, bool> isLoadingMap = <String, bool>{}.obs;
|
|
|
|
void addVoiceFile(String id, File file) {
|
|
voiceFiles[id] = file;
|
|
voiceFiles.refresh();
|
|
}
|
|
|
|
Rx<PlayerController> getVoicePlayer(String id) {
|
|
if (voicePlayers[id] != null) {
|
|
return voicePlayers[id]!;
|
|
}
|
|
voicePlayers[id] = PlayerController().obs;
|
|
return voicePlayers[id]!;
|
|
}
|
|
|
|
void updateIsLoading(String id, bool newValue) {
|
|
isLoadingMap[id] = newValue;
|
|
isLoadingMap.refresh();
|
|
}
|
|
|
|
void updateIsPlaying(String id, bool newValue) {
|
|
isPlayingMap[id] = newValue;
|
|
isPlayingMap.refresh();
|
|
}
|
|
|
|
void clear() {
|
|
isInitialized = false;
|
|
connectionState = SocketConnectionState.notConnected.obs;
|
|
voiceFiles.clear();
|
|
voicePlayers.clear();
|
|
isPlayingMap.clear();
|
|
isLoadingMap.clear();
|
|
voiceRecorder = FlutterSoundRecorder();
|
|
recordFile = File('record.wav');
|
|
isRecordReady = false;
|
|
isRecording = false.obs;
|
|
recordingTime = '00:00'.obs;
|
|
isReplying = false.obs;
|
|
replyModel = MessageModel.zero().obs;
|
|
keyBoardOpened = false.obs;
|
|
scrollController = ScrollController().obs;
|
|
messagesState.clear();
|
|
rooms = RxFuture(Pagination());
|
|
currentRoom = null.obs;
|
|
io.clearListeners();
|
|
}
|
|
|
|
// RxBool isPlaying(String id) {
|
|
// if (isPlayingMap[id] != null) {
|
|
// return isPlayingMap[id]!;
|
|
// }
|
|
// isPlayingMap[id] = false.obs;
|
|
// return isPlayingMap[id]!;
|
|
// }
|
|
|
|
// RxBool isLoading(String id) {
|
|
// if (isLoadingMap[id] != null) {
|
|
// return isLoadingMap[id]!;
|
|
// }
|
|
// isLoadingMap[id] = false.obs;
|
|
// return isLoadingMap[id]!;
|
|
// }
|
|
}
|
|
|
|
//dummy
|
|
// RxList<MessageModel> messages = [
|
|
// MessageModel(
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// createdAt: DateTime.now().toString(),
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// ),
|
|
// MessageModel(
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// roomId: 0,
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// direction: MessageDirection.received,
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// direction: MessageDirection.received,
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// direction: MessageDirection.received,
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// direction: MessageDirection.received,
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// direction: MessageDirection.received,
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// direction: MessageDirection.received,
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// createdAt: DateTime.now().toString(),
|
|
// direction: MessageDirection.received,
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: networkImageTest,
|
|
// type: MessageType.image,
|
|
// createdAt: DateTime.now().toString(),
|
|
// direction: MessageDirection.received,
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: networkImageTest,
|
|
// type: MessageType.image,
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// repliedMessage: MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: networkImageTest,
|
|
// type: MessageType.image,
|
|
// createdAt: DateTime.now().toString(),
|
|
// direction: MessageDirection.received,
|
|
// ),
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// repliedMessage: MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// repliedMessage: MessageModel(
|
|
// user: ChatUser(id: 0, name: 'name'),
|
|
// roomId: 0,
|
|
// userId: 0,
|
|
// content: 'message,hi',
|
|
// createdAt: DateTime.now().toString(),
|
|
// direction: MessageDirection.received,
|
|
// ),
|
|
// createdAt: DateTime.now().toString(),
|
|
// ),
|
|
// ].obs;
|