Merge branch 'master' into development_sikander
# Conflicts: # lib/classes/consts.dart # lib/generated/locale_keys.g.dart # lib/ui/landing/dashboard_screen.dartfaiz_marathon_signalR_critical
commit
d200624ac2
@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="29.557" height="29.557" viewBox="0 0 29.557 29.557">
|
||||
<g id="chat_3_" data-name="chat (3)" transform="translate(0 -0.008)">
|
||||
<g id="Group_8672" data-name="Group 8672" transform="translate(0 0.007)">
|
||||
<g id="Group_8671" data-name="Group 8671" transform="translate(0 0)">
|
||||
<path id="Path_13684" data-name="Path 13684" d="M29.348,17.685l-2.039-2.379A8.6,8.6,0,0,0,29.556,9.59c0-5.369-5.209-9.583-11.315-9.583-6.207,0-11.257,4.3-11.257,9.583,0,.133,0,.266.011.4-4.131,1.641-7,5.18-7,9.271a9.341,9.341,0,0,0,2.483,6.276L.214,28.127a.866.866,0,0,0,.652,1.436H13.046c.1,0,.4-.055.462-.061A12.95,12.95,0,0,0,21,26.322a9.481,9.481,0,0,0,3.3-7.207H28.69A.867.867,0,0,0,29.348,17.685ZM13.219,27.79c-.076.006-.337.029-.39.042H2.774l1.538-1.758a.866.866,0,0,0-.056-1.2,7.739,7.739,0,0,1-2.525-5.616c0-4.694,4.687-8.515,10.449-8.515,5.73,0,10.391,3.82,10.391,8.515C22.571,23.649,18.482,27.36,13.219,27.79ZM24.1,17.383h0C23.057,12.566,18.06,9.013,12.18,9.013a14.281,14.281,0,0,0-3.461.422c.1-4.258,4.333-7.7,9.523-7.7,5.284,0,9.583,3.522,9.583,7.851a7.016,7.016,0,0,1-2.284,5.058.866.866,0,0,0-.059,1.189l1.326,1.547Z" transform="translate(0 -0.007)" fill="#989898"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group_8674" data-name="Group 8674" transform="translate(5.253 17.383)">
|
||||
<g id="Group_8673" data-name="Group 8673">
|
||||
<path id="Path_13685" data-name="Path 13685" d="M92.729,301a1.732,1.732,0,1,0,1.732,1.732A1.734,1.734,0,0,0,92.729,301Z" transform="translate(-90.997 -300.999)" fill="#989898"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group_8676" data-name="Group 8676" transform="translate(10.448 17.383)">
|
||||
<g id="Group_8675" data-name="Group 8675">
|
||||
<path id="Path_13686" data-name="Path 13686" d="M182.726,301a1.732,1.732,0,1,0,1.732,1.732A1.734,1.734,0,0,0,182.726,301Z" transform="translate(-180.994 -300.999)" fill="#989898"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group_8678" data-name="Group 8678" transform="translate(15.644 17.383)">
|
||||
<g id="Group_8677" data-name="Group 8677">
|
||||
<path id="Path_13687" data-name="Path 13687" d="M272.723,301a1.732,1.732,0,1,0,1.732,1.732A1.734,1.734,0,0,0,272.723,301Z" transform="translate(-270.991 -300.999)" fill="#989898"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="29.559" height="29.557" viewBox="0 0 29.559 29.557">
|
||||
<g id="chat_2_" data-name="chat (2)" transform="translate(0 -0.006)">
|
||||
<g id="Group_8680" data-name="Group 8680" transform="translate(0 8.954)">
|
||||
<g id="Group_8679" data-name="Group 8679" transform="translate(0)">
|
||||
<path id="Path_13688" data-name="Path 13688" d="M12.181,155C5.5,155,0,159.595,0,165.245a9.543,9.543,0,0,0,2.483,6.333L.214,174.171a.866.866,0,0,0,.652,1.436H13.046c4.936,0,11.315-4.25,11.315-10.362C24.361,159.595,18.865,155,12.181,155ZM6.927,166.832A1.732,1.732,0,1,1,8.659,165.1,1.734,1.734,0,0,1,6.927,166.832Zm5.253,0a1.732,1.732,0,1,1,1.732-1.732A1.734,1.734,0,0,1,12.181,166.832Zm5.253,0a1.732,1.732,0,1,1,1.732-1.732A1.734,1.734,0,0,1,17.434,166.832Z" transform="translate(0 -154.998)" fill="#2e303a"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group_8682" data-name="Group 8682" transform="translate(7.077 0.006)">
|
||||
<g id="Group_8681" data-name="Group 8681" transform="translate(0 0)">
|
||||
<path id="Path_13689" data-name="Path 13689" d="M144.854,17.626l-2.039-2.379a8.6,8.6,0,0,0,2.248-5.716c0-5.252-5.05-9.525-11.257-9.525-5.613,0-10.381,3.5-11.223,8.05a16.022,16.022,0,0,1,5.1-.835c7.583,0,13.813,5.3,13.9,11.834H144.2A.867.867,0,0,0,144.854,17.626Z" transform="translate(-122.583 -0.006)" fill="#2e303a"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="26.298" height="26.298" viewBox="0 0 26.298 26.298">
|
||||
<path id="send" d="M26.3,0,0,14.793l8.4,3.113L21.367,5.753l-9.86,13.3.008,0-.01,0V26.3l4.713-5.5,5.97,2.211Z" fill="#2bb8a6"/>
|
||||
</svg>
|
After Width: | Height: | Size: 236 B |
@ -0,0 +1,213 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:mohem_flutter_app/api/api_client.dart';
|
||||
import 'package:mohem_flutter_app/classes/consts.dart';
|
||||
import 'package:mohem_flutter_app/classes/utils.dart';
|
||||
import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart';
|
||||
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_Model.dart';
|
||||
import 'package:signalr_netcore/hub_connection.dart';
|
||||
import 'package:signalr_netcore/signalr_client.dart';
|
||||
import 'package:logger/logger.dart' as L;
|
||||
|
||||
class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
|
||||
List<SingleUserChatModel> userChatHistory = [];
|
||||
List<ChatUser>? pChatHistory, searchedChats;
|
||||
late HubConnection hubConnection;
|
||||
L.Logger logger = L.Logger();
|
||||
TextEditingController message = TextEditingController();
|
||||
ScrollController scrollController = ScrollController();
|
||||
static String token =
|
||||
"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiI0MjA2MiIsImVtYWlsIjoiYWFtaXIubXVoYW1tYWRAY2xvdWRzb2x1dGlvbnMuY29tLnNhIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy91c2VyZGF0YSI6ImFhbWlyLm11aGFtbWFkIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbW9iaWxlcGhvbmUiOiI5NjY1MzA4OTYwMTgiLCJuYmYiOjE2NjU5MjA2NDEsImV4cCI6MTY2NjAwNzA0MSwiaWF0IjoxNjY1OTIwNjQxfQ.70tXWdpXtQ20PNBO3WF9ScWNWSyECpFfrW7_iuOmNfWmA63PCZzlTO0E6I3q3K9Kg2CWvOT9-dSDLjlRuXuC2w";
|
||||
|
||||
bool isLoading = true;
|
||||
|
||||
void getChatMemberFromSearch(String sName, int cUserId) async {
|
||||
isLoading = true;
|
||||
notifyListeners();
|
||||
Response response = await ApiClient().getJsonForResponse(
|
||||
"${ApiConsts.chatSearchMember}$sName/$cUserId",
|
||||
token: token,
|
||||
);
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void getUserRecentChats() async {
|
||||
Response response = await ApiClient().getJsonForResponse(
|
||||
"${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatRecentUrl}",
|
||||
token: token,
|
||||
);
|
||||
ChatUserModel recentChat = userToList(response.body);
|
||||
pChatHistory = recentChat.response;
|
||||
searchedChats = pChatHistory;
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void getSingleUserChatHistory({required String senderUID, required int receiverUID, required String pagination}) async {
|
||||
isLoading = true;
|
||||
Response response = await ApiClient().getJsonForResponse(
|
||||
"${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatSingleUserHistoryUrl}/$senderUID/$receiverUID/$pagination",
|
||||
token: token,
|
||||
);
|
||||
userChatHistory = getSingleUserChatintoModel(response.body);
|
||||
isLoading = false;
|
||||
logger.d(jsonEncode(userChatHistory));
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
List<SingleUserChatModel> getSingleUserChatintoModel(String str) => List<SingleUserChatModel>.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x)));
|
||||
|
||||
ChatUserModel userToList(String str) => ChatUserModel.fromJson(json.decode(str));
|
||||
|
||||
void buildHubConnection() async {
|
||||
HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
|
||||
hubConnection = await HubConnectionBuilder()
|
||||
.withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=42062&source=Web&access_token=$token", options: httpOp)
|
||||
.withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000])
|
||||
.configureLogging(Logger("Logs Enabled"))
|
||||
.build();
|
||||
hubConnection.onclose(
|
||||
({Exception? error}) {
|
||||
logger.d(error);
|
||||
},
|
||||
);
|
||||
hubConnection.onreconnecting(
|
||||
({Exception? error}) {
|
||||
logger.d(error);
|
||||
logger.d("Reconnecting");
|
||||
},
|
||||
);
|
||||
hubConnection.onreconnected(
|
||||
({String? connectionId}) {
|
||||
logger.d("Reconnected");
|
||||
},
|
||||
);
|
||||
if (hubConnection.state != HubConnectionState.Connected) {
|
||||
await hubConnection.start();
|
||||
hubConnection.on("OnUpdateUserStatusAsync", changeStatus);
|
||||
hubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
|
||||
// hubConnection.on("OnUserTypingAsync", onUserTyping);
|
||||
//hubConnection.on("OnUserTypingAsync", changeTypingStatus);
|
||||
} else {
|
||||
hubConnection.on("OnUpdateUserStatusAsync", changeStatus);
|
||||
hubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
|
||||
// hubConnection.on("OnUserTypingAsync", onUserTyping);
|
||||
//hubConnection.on("OnUserTypingAsync", changeTypingStatus);
|
||||
}
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void changeStatus(List<Object?>? args) {
|
||||
List items = args!.toList();
|
||||
for (var user in searchedChats!) {
|
||||
if (user.id == items.first["id"]) {
|
||||
user.userStatus = items.first["userStatus"];
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void filter(String value) async {
|
||||
List<ChatUser>? tmp = [];
|
||||
if (value.isEmpty || value == "") {
|
||||
tmp = pChatHistory;
|
||||
} else {
|
||||
for (var element in pChatHistory!) {
|
||||
if (element.userName!.toLowerCase().contains(value.toLowerCase())) {
|
||||
tmp.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
searchedChats = tmp;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> onMsgReceived(List<Object?>? parameters) async {
|
||||
List<SingleUserChatModel> data = [];
|
||||
for (dynamic msg in parameters!) {
|
||||
data = getSingleUserChatintoModel(jsonEncode(msg));
|
||||
logger.d(msg);
|
||||
}
|
||||
userChatHistory.add(data.first);
|
||||
notifyListeners();
|
||||
scrollDown();
|
||||
}
|
||||
|
||||
void onUserTyping(List<Object?>? parameters) {
|
||||
print("==================== Typing Active ==================");
|
||||
logger.d(parameters);
|
||||
for (ChatUser user in searchedChats!) {
|
||||
if (user.id == parameters![1] && parameters[0] == true) {
|
||||
user.isTyping = parameters[0] as bool?;
|
||||
} else {
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 500),
|
||||
() {
|
||||
user.isTyping = false;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void sendChatMessage(String chatMessage, int targetUserId, String targetUserName) async {
|
||||
if (chatMessage == null || chatMessage.isEmpty) {
|
||||
return;
|
||||
}
|
||||
String chatData =
|
||||
'{"contant":"$chatMessage","contantNo":"8a129295-36d7-7185-5d34-cc4eec7bcba4","chatEventId":1,"fileTypeId":null,"currentUserId":42062,"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"conversationId":"715f8b13-96ee-cd36-cb07-5a982a219982"}';
|
||||
await hubConnection.invoke("AddChatUserAsync", args: <Object>[json.decode(chatData)]);
|
||||
userChatHistory.add(
|
||||
SingleUserChatModel(
|
||||
chatEventId: 1,
|
||||
chatSource: 1,
|
||||
contant: chatMessage,
|
||||
contantNo: "8a129295-36d7-7185-5d34-cc4eec7bcba4",
|
||||
conversationId: "715f8b13-96ee-cd36-cb07-5a982a219982",
|
||||
createdDate: DateTime.now(),
|
||||
currentUserId: 42062,
|
||||
currentUserName: "aamir.muhammad",
|
||||
targetUserId: targetUserId,
|
||||
targetUserName: targetUserName,
|
||||
),
|
||||
);
|
||||
message.clear();
|
||||
notifyListeners();
|
||||
scrollDown();
|
||||
}
|
||||
|
||||
void scrollDown() {
|
||||
scrollController.animateTo(
|
||||
scrollController.position.maxScrollExtent + 100,
|
||||
curve: Curves.easeOut,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
);
|
||||
|
||||
// scrollController.animateTo(double.parse(userChatHistory.length.toString()), duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// void _scrollListener() {
|
||||
// if (scrollController.position.extentAfter.toInt() <= 0 && canCallApi) {
|
||||
// if (userChatHistory.length < _ayatTangheemTypeMapped.totalItemsCount) {
|
||||
// currentPageNo++;
|
||||
// if (widget.tangheemQuery == null) {
|
||||
// getTangheemData();
|
||||
// } else {
|
||||
// getTangheemDataByKeyword();
|
||||
// }
|
||||
// }
|
||||
// canCallApi = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
class ChatUserModel {
|
||||
ChatUserModel({
|
||||
this.response,
|
||||
this.errorResponses,
|
||||
});
|
||||
|
||||
List<ChatUser>? response;
|
||||
dynamic errorResponses;
|
||||
|
||||
factory ChatUserModel.fromJson(Map<String, dynamic> json) => ChatUserModel(
|
||||
response: json["response"] == null ? null : List<ChatUser>.from(json["response"].map((x) => ChatUser.fromJson(x))),
|
||||
errorResponses: json["errorResponses"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"response": response == null ? null : List<dynamic>.from(response!.map((x) => x.toJson())),
|
||||
"errorResponses": errorResponses,
|
||||
};
|
||||
}
|
||||
|
||||
class ChatUser {
|
||||
ChatUser({
|
||||
this.id,
|
||||
this.userName,
|
||||
this.email,
|
||||
this.phone,
|
||||
this.title,
|
||||
this.userStatus,
|
||||
this.image,
|
||||
this.unreadMessageCount,
|
||||
this.userAction,
|
||||
this.isPin,
|
||||
this.isFav,
|
||||
this.isAdmin,
|
||||
this.isTyping,
|
||||
});
|
||||
|
||||
int? id;
|
||||
String? userName;
|
||||
String? email;
|
||||
dynamic? phone;
|
||||
dynamic? title;
|
||||
int? userStatus;
|
||||
dynamic? image;
|
||||
int? unreadMessageCount;
|
||||
dynamic? userAction;
|
||||
bool? isPin;
|
||||
bool? isFav;
|
||||
bool? isAdmin;
|
||||
bool? isTyping;
|
||||
|
||||
factory ChatUser.fromJson(Map<String, dynamic> json) => ChatUser(
|
||||
id: json["id"] == null ? null : json["id"],
|
||||
userName: json["userName"] == null ? null : json["userName"],
|
||||
email: json["email"] == null ? null : json["email"],
|
||||
phone: json["phone"],
|
||||
title: json["title"],
|
||||
userStatus: json["userStatus"] == null ? null : json["userStatus"],
|
||||
image: json["image"],
|
||||
unreadMessageCount: json["unreadMessageCount"] == null ? null : json["unreadMessageCount"],
|
||||
userAction: json["userAction"],
|
||||
isPin: json["isPin"] == null ? null : json["isPin"],
|
||||
isFav: json["isFav"] == null ? null : json["isFav"],
|
||||
isAdmin: json["isAdmin"] == null ? null : json["isAdmin"],
|
||||
isTyping: false,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"id": id == null ? null : id,
|
||||
"userName": userName == null ? null : userName,
|
||||
"email": email == null ? null : email,
|
||||
"phone": phone,
|
||||
"title": title,
|
||||
"userStatus": userStatus == null ? null : userStatus,
|
||||
"image": image,
|
||||
"unreadMessageCount": unreadMessageCount == null ? null : unreadMessageCount,
|
||||
"userAction": userAction,
|
||||
"isPin": isPin == null ? null : isPin,
|
||||
"isFav": isFav == null ? null : isFav,
|
||||
"isAdmin": isAdmin == null ? null : isAdmin,
|
||||
};
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
class SingleUserChatModel {
|
||||
SingleUserChatModel({
|
||||
this.userChatHistoryId,
|
||||
this.userChatHistoryLineId,
|
||||
this.contant,
|
||||
this.contantNo,
|
||||
this.currentUserId,
|
||||
this.currentUserName,
|
||||
this.targetUserId,
|
||||
this.targetUserName,
|
||||
this.encryptedTargetUserId,
|
||||
this.encryptedTargetUserName,
|
||||
this.chatEventId,
|
||||
this.fileTypeId,
|
||||
this.isSeen,
|
||||
this.isDelivered,
|
||||
this.createdDate,
|
||||
this.chatSource,
|
||||
this.conversationId,
|
||||
this.fileTypeResponse,
|
||||
this.userChatReplyResponse,
|
||||
});
|
||||
|
||||
int? userChatHistoryId;
|
||||
int? userChatHistoryLineId;
|
||||
String? contant;
|
||||
String? contantNo;
|
||||
int? currentUserId;
|
||||
String? currentUserName;
|
||||
int? targetUserId;
|
||||
String? targetUserName;
|
||||
dynamic encryptedTargetUserId;
|
||||
dynamic encryptedTargetUserName;
|
||||
int? chatEventId;
|
||||
dynamic fileTypeId;
|
||||
bool? isSeen;
|
||||
bool? isDelivered;
|
||||
DateTime? createdDate;
|
||||
int? chatSource;
|
||||
String? conversationId;
|
||||
FileTypeResponse? fileTypeResponse;
|
||||
dynamic userChatReplyResponse;
|
||||
|
||||
factory SingleUserChatModel.fromJson(Map<String, dynamic> json) => SingleUserChatModel(
|
||||
userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"],
|
||||
userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"],
|
||||
contant: json["contant"] == null ? null : json["contant"],
|
||||
contantNo: json["contantNo"] == null ? null : json["contantNo"],
|
||||
currentUserId: json["currentUserId"] == null ? null : json["currentUserId"],
|
||||
currentUserName: json["currentUserName"] == null ? null : json["currentUserName"],
|
||||
targetUserId: json["targetUserId"] == null ? null : json["targetUserId"],
|
||||
targetUserName: json["targetUserName"] == null ? null : json["targetUserName"],
|
||||
encryptedTargetUserId: json["encryptedTargetUserId"],
|
||||
encryptedTargetUserName: json["encryptedTargetUserName"],
|
||||
chatEventId: json["chatEventId"] == null ? null : json["chatEventId"],
|
||||
fileTypeId: json["fileTypeId"],
|
||||
isSeen: json["isSeen"] == null ? null : json["isSeen"],
|
||||
isDelivered: json["isDelivered"] == null ? null : json["isDelivered"],
|
||||
createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]),
|
||||
chatSource: json["chatSource"] == null ? null : json["chatSource"],
|
||||
conversationId: json["conversationId"] == null ? null : json["conversationId"],
|
||||
fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]),
|
||||
userChatReplyResponse: json["userChatReplyResponse"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId,
|
||||
"userChatHistoryLineId": userChatHistoryLineId == null ? null : userChatHistoryLineId,
|
||||
"contant": contant == null ? null : contant,
|
||||
"contantNo": contantNo == null ? null : contantNo,
|
||||
"currentUserId": currentUserId == null ? null : currentUserId,
|
||||
"currentUserName": currentUserName == null ? null : currentUserName,
|
||||
"targetUserId": targetUserId == null ? null : targetUserId,
|
||||
"targetUserName": targetUserName == null ? null : targetUserName,
|
||||
"encryptedTargetUserId": encryptedTargetUserId,
|
||||
"encryptedTargetUserName": encryptedTargetUserName,
|
||||
"chatEventId": chatEventId == null ? null : chatEventId,
|
||||
"fileTypeId": fileTypeId,
|
||||
"isSeen": isSeen == null ? null : isSeen,
|
||||
"isDelivered": isDelivered == null ? null : isDelivered,
|
||||
"createdDate": createdDate == null ? null : createdDate!.toIso8601String(),
|
||||
"chatSource": chatSource == null ? null : chatSource,
|
||||
"conversationId": conversationId == null ? null : conversationId,
|
||||
"fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(),
|
||||
"userChatReplyResponse": userChatReplyResponse,
|
||||
};
|
||||
}
|
||||
|
||||
class FileTypeResponse {
|
||||
FileTypeResponse({
|
||||
this.fileTypeId,
|
||||
this.fileTypeName,
|
||||
this.fileTypeDescription,
|
||||
this.fileKind,
|
||||
this.fileName,
|
||||
});
|
||||
|
||||
int? fileTypeId;
|
||||
dynamic fileTypeName;
|
||||
dynamic fileTypeDescription;
|
||||
dynamic fileKind;
|
||||
dynamic fileName;
|
||||
|
||||
factory FileTypeResponse.fromJson(Map<String, dynamic> json) => FileTypeResponse(
|
||||
fileTypeId: json["fileTypeId"] == null ? null : json["fileTypeId"],
|
||||
fileTypeName: json["fileTypeName"],
|
||||
fileTypeDescription: json["fileTypeDescription"],
|
||||
fileKind: json["fileKind"],
|
||||
fileName: json["fileName"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"fileTypeId": fileTypeId == null ? null : fileTypeId,
|
||||
"fileTypeName": fileTypeName,
|
||||
"fileTypeDescription": fileTypeDescription,
|
||||
"fileKind": fileKind,
|
||||
"fileName": fileName,
|
||||
};
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||
|
||||
class ChatBubble extends StatelessWidget {
|
||||
const ChatBubble(
|
||||
{Key? key,
|
||||
required this.text,
|
||||
required this.isCurrentUser,
|
||||
required this.isSeen,
|
||||
required this.isDelivered,
|
||||
required this.dateTime})
|
||||
: super(key: key);
|
||||
final String text;
|
||||
final bool isCurrentUser;
|
||||
final bool isSeen;
|
||||
final bool isDelivered;
|
||||
final String dateTime;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
// asymmetric padding
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
isCurrentUser ? 64.0 : 16.0,
|
||||
4,
|
||||
isCurrentUser ? 16.0 : 64.0,
|
||||
4,
|
||||
),
|
||||
child: Align(
|
||||
// align the child within the container
|
||||
alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft,
|
||||
child: DecoratedBox(
|
||||
// chat bubble decoration
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
gradient: isCurrentUser
|
||||
? null
|
||||
: LinearGradient(
|
||||
transform: GradientRotation(.46),
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
colors: [
|
||||
MyColors.gradiantEndColor,
|
||||
MyColors.gradiantStartColor,
|
||||
]),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
text.toText12(
|
||||
color:
|
||||
isCurrentUser ? MyColors.grey57Color : MyColors.white),
|
||||
8.height,
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
dateTime.toText12(
|
||||
color: isCurrentUser
|
||||
? MyColors.grey41Color.withOpacity(.5)
|
||||
: Colors.white.withOpacity(0.7)),
|
||||
if (isCurrentUser) 5.width,
|
||||
if (isCurrentUser)
|
||||
Icon(
|
||||
isDelivered
|
||||
? Icons.done_all
|
||||
: Icons.done_all,
|
||||
color: isSeen
|
||||
? MyColors.textMixColor
|
||||
: MyColors.grey9DColor,
|
||||
size: 14,
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart';
|
||||
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||
import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart';
|
||||
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
|
||||
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ChatDetailScreen extends StatelessWidget {
|
||||
dynamic userDetails;
|
||||
late ChatProviderModel data;
|
||||
|
||||
ChatDetailScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
userDetails = ModalRoute.of(context)!.settings.arguments;
|
||||
data = Provider.of<ChatProviderModel>(context, listen: false);
|
||||
data.getSingleUserChatHistory(senderUID: "42062", receiverUID: userDetails["targetUser"].id, pagination: "0");
|
||||
Timer(const Duration(seconds: 1), () => data.scrollDown());
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF8F8F8),
|
||||
appBar: AppBarWidget(context, title: userDetails["targetUser"].userName, showHomeButton: false, image: userDetails["targetUser"].image),
|
||||
body: Consumer<ChatProviderModel>(
|
||||
builder: (BuildContext context, ChatProviderModel m, Widget? child) {
|
||||
return (m.isLoading
|
||||
? ChatHomeShimmer()
|
||||
: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
controller: m.scrollController,
|
||||
shrinkWrap: true,
|
||||
itemCount: m.userChatHistory.length,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
itemBuilder: (BuildContext context, int i) {
|
||||
return ChatBubble(
|
||||
text: m.userChatHistory[i].contant.toString(),
|
||||
isSeen: m.userChatHistory[i].isSeen == true ? true : false,
|
||||
isCurrentUser: m.userChatHistory[i].currentUserId == 42062 ? true : false,
|
||||
isDelivered: m.userChatHistory[i].currentUserId == 42062 && m.userChatHistory[i].isDelivered == true ? true : false,
|
||||
dateTime: m.userChatHistory[i].createdDate.toString(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: TextField(
|
||||
controller: m.message,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Type here to reply',
|
||||
hintStyle: const TextStyle(color: MyColors.grey98Color),
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
errorBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||
suffixIcon: IconButton(
|
||||
icon: SvgPicture.asset(
|
||||
"assets/icons/chat/chat_send_icon.svg",
|
||||
height: 26,
|
||||
width: 35,
|
||||
),
|
||||
onPressed: () {
|
||||
m.sendChatMessage(m.message.text, userDetails["targetUser"].id, userDetails["targetUser"].userName);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart';
|
||||
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||
import 'package:mohem_flutter_app/config/routes.dart';
|
||||
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
|
||||
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
|
||||
import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart';
|
||||
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ChatHomeScreen extends StatefulWidget {
|
||||
const ChatHomeScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ChatHomeScreen> createState() => _ChatHomeScreenState();
|
||||
}
|
||||
|
||||
class _ChatHomeScreenState extends State<ChatHomeScreen> {
|
||||
TextEditingController search = new TextEditingController();
|
||||
late ChatProviderModel data;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
data = Provider.of<ChatProviderModel>(context, listen: false);
|
||||
data.buildHubConnection();
|
||||
data.getUserRecentChats();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBarWidget(context, title: "My Chats", showHomeButton: false),
|
||||
body: Consumer<ChatProviderModel>(builder: (BuildContext context, ChatProviderModel m, Widget? child) {
|
||||
return m.isLoading
|
||||
? ChatHomeShimmer()
|
||||
: ListView(
|
||||
shrinkWrap: true,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 20),
|
||||
child: TextField(
|
||||
onChanged: (String val) {
|
||||
m.filter(val);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
borderSide: const BorderSide(
|
||||
color: Color(0xFFE5E5E5),
|
||||
),
|
||||
),
|
||||
errorBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
|
||||
hintText: "Search from chat",
|
||||
hintStyle: const TextStyle(color: MyColors.lightTextColor, fontStyle: FontStyle.italic),
|
||||
filled: true,
|
||||
fillColor: const Color(0xFFF7F7F7),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (m.searchedChats != null)
|
||||
ListView.separated(
|
||||
itemCount: m.searchedChats!.length,
|
||||
padding: const EdgeInsets.only(top: 0),
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return ListTile(
|
||||
leading: Stack(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
"assets/images/user.svg",
|
||||
height: 48,
|
||||
width: 48,
|
||||
),
|
||||
Positioned(
|
||||
right: 5,
|
||||
bottom: 1,
|
||||
child: Container(
|
||||
width: 10,
|
||||
height: 10,
|
||||
decoration: BoxDecoration(
|
||||
color: m.searchedChats![index].userStatus == 1 ? MyColors.green2DColor : Colors.red,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(10),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
title: (m.searchedChats![index].userName ?? "").toText14(color: MyColors.darkTextColor),
|
||||
subtitle: (m.searchedChats![index].isTyping == true ? "Something is Typing" : "Last message text").toText11(color: MyColors.normalTextColor),
|
||||
trailing: ("Today").toText10(color: MyColors.lightTextColor),
|
||||
minVerticalPadding: 0,
|
||||
onTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
AppRoutes.chatDetailed,
|
||||
arguments: {"currentUser": "42062", "targetUser": m.searchedChats![index]},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const Padding(
|
||||
padding: EdgeInsets.only(right: 10, left: 70),
|
||||
child: Divider(
|
||||
color: Color(0xFFE5E5E5),
|
||||
),
|
||||
),
|
||||
),
|
||||
// if (searchedUsersList == null) Utils.getNoChatWidget(context),
|
||||
],
|
||||
);
|
||||
}),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: LinearGradient(
|
||||
transform: GradientRotation(.46),
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
colors: [
|
||||
MyColors.gradiantEndColor,
|
||||
MyColors.gradiantStartColor,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.add,
|
||||
size: 30,
|
||||
color: MyColors.white,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
// var userData = await ChatApiClient()
|
||||
// .getChatMemberFromSearch("aamir.muhammad", 36239);
|
||||
showMyBottomSheet(
|
||||
context,
|
||||
child: SearchEmployeeBottomSheet(
|
||||
title: LocaleKeys.searchForEmployee.tr(),
|
||||
apiMode: LocaleKeys.delegate.tr(),
|
||||
onSelectEmployee: (_selectedEmployee) {
|
||||
// Navigator.pop(context);
|
||||
// selectedReplacementEmployee = _selectedEmployee;
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue