Merge branch 'development_aamir' into 'master'

Chat Fixes & User Chat Counter & Read Event & Chat Images API With Encryption.

See merge request Cloud_Solution/mohemm-flutter-app!81
sultan-dev
haroon amjad 2 years ago
commit 64ba4cdad9

@ -9,6 +9,7 @@ import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/exceptions/api_exception.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart';
import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart';
import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user;
import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav;
@ -152,16 +153,12 @@ class ChatApiClient {
return data; return data;
} }
Future getUsersImages({required List encryptedEmails}) async { Future<List<ChatUserImageModel>> getUsersImages({required List<String> encryptedEmails}) async {
Response response = await ApiClient().postJsonForResponse( Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatUserImages}images", "${ApiConsts.chatUserImages}images",
{ {"encryptedEmails": encryptedEmails, "fromClient": false},
"encryptedEmails": ["/g8Rc+s6eEOdci41PwJuV5dX+gXe51G9OTHzb9ahcVlHCmVvNhxReirudF79+hdxVSkCnQ6wC5DBFV8xnJlC74X6157PxF7mNYrAYuHRgp4="],
"fromClient": true
},
token: AppState().chatDetails!.response!.token, token: AppState().chatDetails!.response!.token,
); );
logger.d(response.body); return chatUserImageModelFromJson(response.body);
// Uint8List data = Uint8List.fromList(response.body);
} }
} }

@ -2,8 +2,8 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart';
class ApiConsts { class ApiConsts {
//static String baseUrl = "http://10.200.204.20:2801/"; // Local server //static String baseUrl = "http://10.200.204.20:2801/"; // Local server
static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server //static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server
// static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrl = "https://hmgwebservices.com"; // Live server
static String baseUrlServices = baseUrl + "/Services/"; // server static String baseUrlServices = baseUrl + "/Services/"; // server
// static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server
static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/";
@ -12,8 +12,6 @@ class ApiConsts {
static String user = baseUrlServices + "api/User/"; static String user = baseUrlServices + "api/User/";
static String cocRest = baseUrlServices + "COCWS.svc/REST/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/";
// todo @aamir move api end point last repo to concerned method.
//Chat //Chat
static String chatServerBaseUrl = "https://apiderichat.hmg.com/"; static String chatServerBaseUrl = "https://apiderichat.hmg.com/";
static String chatServerBaseApiUrl = chatServerBaseUrl + "api/"; static String chatServerBaseApiUrl = chatServerBaseUrl + "api/";

@ -0,0 +1,26 @@
import 'dart:convert';
import 'package:flutter/services.dart';
class EmailImageEncryption {
static final EmailImageEncryption _instance = EmailImageEncryption._internal();
static const MethodChannel _channel = MethodChannel('flutter_des');
static const key = "PeShVmYp";
static const iv = "j70IbWYn";
EmailImageEncryption._internal();
factory EmailImageEncryption() => _instance;
Future<String> encrypt({required String val}) async {
Uint8List? crypt = await _channel.invokeMethod('encrypt', [val, key, iv]);
String enc = base64Encode(crypt!.toList());
return enc;
}
Future<String> decrypt({required String encodedVal}) async {
Uint8List deco = base64Decode(encodedVal);
String? decCrypt = await _channel.invokeMethod('decrypt', [deco, key, iv]);
return decCrypt!;
}
}

@ -0,0 +1,33 @@
// To parse this JSON data, do
//
// final chatUserImageModel = chatUserImageModelFromJson(jsonString);
import 'dart:convert';
List<ChatUserImageModel> chatUserImageModelFromJson(String str) => List<ChatUserImageModel>.from(json.decode(str).map((x) => ChatUserImageModel.fromJson(x)));
String chatUserImageModelToJson(List<ChatUserImageModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class ChatUserImageModel {
ChatUserImageModel({
this.email,
this.profilePicture,
this.mobileNumber,
});
String? email;
String? profilePicture;
String? mobileNumber;
factory ChatUserImageModel.fromJson(Map<String, dynamic> json) => ChatUserImageModel(
email: json["email"] == null ? null : json["email"],
profilePicture: json["profilePicture"] == null ? null : json["profilePicture"],
mobileNumber: json["mobileNumber"] == null ? null : json["mobileNumber"],
);
Map<String, dynamic> toJson() => {
"email": email == null ? null : email,
"profilePicture": profilePicture == null ? null : profilePicture,
"mobileNumber": mobileNumber == null ? null : mobileNumber,
};
}

@ -19,21 +19,23 @@ class ChatUserModel {
} }
class ChatUser { class ChatUser {
ChatUser( ChatUser({
{this.id, this.id,
this.userName, this.userName,
this.email, this.email,
this.phone, this.phone,
this.title, this.title,
this.userStatus, this.userStatus,
this.image, this.image,
this.unreadMessageCount, this.unreadMessageCount,
this.userAction, this.userAction,
this.isPin, this.isPin,
this.isFav, this.isFav,
this.isAdmin, this.isAdmin,
this.isTyping, this.isTyping,
this.isLoadingCounter}); this.isImageLoaded,
this.isImageLoading,
});
int? id; int? id;
String? userName; String? userName;
@ -48,7 +50,8 @@ class ChatUser {
bool? isFav; bool? isFav;
bool? isAdmin; bool? isAdmin;
bool? isTyping; bool? isTyping;
bool? isLoadingCounter; bool? isImageLoaded;
bool? isImageLoading;
factory ChatUser.fromJson(Map<String, dynamic> json) => ChatUser( factory ChatUser.fromJson(Map<String, dynamic> json) => ChatUser(
id: json["id"] == null ? null : json["id"], id: json["id"] == null ? null : json["id"],
@ -64,7 +67,8 @@ class ChatUser {
isFav: json["isFav"] == null ? null : json["isFav"], isFav: json["isFav"] == null ? null : json["isFav"],
isAdmin: json["isAdmin"] == null ? null : json["isAdmin"], isAdmin: json["isAdmin"] == null ? null : json["isAdmin"],
isTyping: false, isTyping: false,
isLoadingCounter: true, isImageLoaded: false,
isImageLoading: true,
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

@ -7,8 +7,10 @@ import 'package:flutter/foundation.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.dart'; import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/encryption.dart';
import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart';
import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.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:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav;
@ -36,10 +38,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void registerEvents() { void registerEvents() {
hubConnection.on("OnUpdateUserStatusAsync", changeStatus); hubConnection.on("OnUpdateUserStatusAsync", changeStatus);
hubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); hubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
// hubConnection.on("OnSeenChatUserAsync", onChatSeen); // hubConnection.on("OnSeenChatUserAsync", onChatSeen);
//hubConnection.on("OnUserTypingAsync", onUserTyping); //hubConnection.on("OnUserTypingAsync", onUserTyping);
hubConnection.on("OnUserCountAsync", userCountAsync); hubConnection.on("OnUserCountAsync", userCountAsync);
hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); // hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow);
hubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); hubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
hubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); hubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
} }
@ -75,6 +77,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
), ),
); );
notifyListeners(); notifyListeners();
getUserImages();
} }
Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async {
@ -119,21 +122,27 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
for (SingleUserChatModel element in data!) { for (SingleUserChatModel element in data!) {
if (element.isSeen != null) { if (element.isSeen != null) {
if (!element.isSeen!) { if (!element.isSeen!) {
print("Found Un Read"); element.isSeen = true;
logger.d(jsonEncode(element));
dynamic data = [ dynamic data = [
{"userChatHistoryId": element.userChatHistoryId, "TargetUserId": element.targetUserId, "isDelivered": true, "isSeen": true} {
"userChatHistoryId": element.userChatHistoryId,
"TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId,
"isDelivered": true,
"isSeen": true,
}
]; ];
updateUserChatHistoryStatusAsync(data); updateUserChatHistoryStatusAsync(data);
notifyListeners();
} }
} }
} }
for (ChatUser element in searchedChats!) { for (ChatUser element in searchedChats!) {
if (element.id == receiverID) { if (element.id == receiverID) {
element.unreadMessageCount = 0; element.unreadMessageCount = 0;
notifyListeners(); // notifyListeners();
} }
} }
notifyListeners();
} }
} }
@ -186,8 +195,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void onChatSeen(List<Object?>? args) { void onChatSeen(List<Object?>? args) {
dynamic items = args!.toList(); dynamic items = args!.toList();
logger.d("---------------------------------Chat Seen -------------------------------------");
logger.d(items);
// for (var user in searchedChats!) { // for (var user in searchedChats!) {
// if (user.id == items.first["id"]) { // if (user.id == items.first["id"]) {
// user.userStatus = items.first["userStatus"]; // user.userStatus = items.first["userStatus"];
@ -223,7 +230,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void chatNotDelivered(List<Object?>? args) { void chatNotDelivered(List<Object?>? args) {
dynamic items = args!.toList(); dynamic items = args!.toList();
logger.d(items);
for (dynamic item in items[0]) { for (dynamic item in items[0]) {
searchedChats!.forEach( searchedChats!.forEach(
(ChatUser element) { (ChatUser element) {
@ -231,7 +237,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
int? val = element.unreadMessageCount ?? 0; int? val = element.unreadMessageCount ?? 0;
element.unreadMessageCount = val! + 1; element.unreadMessageCount = val! + 1;
} }
element.isLoadingCounter = false;
}, },
); );
} }
@ -289,7 +294,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
userChatHistory.insert(0, data.first); userChatHistory.insert(0, data.first);
var list = [ if (searchedChats != null && !isChatScreenActive) {
for (ChatUser user in searchedChats!) {
if (user.id == data.first.currentUserId) {
var tempCount = user.unreadMessageCount ?? 0;
user.unreadMessageCount = tempCount + 1;
}
}
}
List list = [
{"userChatHistoryId": data.first.userChatHistoryId, "TargetUserId": temp.first.targetUserId, "isDelivered": true, "isSeen": isChatScreenActive ? true : false} {"userChatHistoryId": data.first.userChatHistoryId, "TargetUserId": temp.first.targetUserId, "isDelivered": true, "isSeen": isChatScreenActive ? true : false}
]; ];
updateUserChatHistoryOnMsg(list); updateUserChatHistoryOnMsg(list);
@ -449,7 +463,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
print("Normal Attachment Msg"); print("Normal Attachment Msg");
Utils.showLoading(context); Utils.showLoading(context);
dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile);
logger.d(value);
String? ext = getFileExtension(selectedFile.path); String? ext = getFileExtension(selectedFile.path);
Utils.hideLoading(context); Utils.hideLoading(context);
sendChatToServer( sendChatToServer(
@ -624,7 +637,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
void clearSelections() { void clearSelections() {
print("Hereee i am ");
searchedChats = pChatHistory; searchedChats = pChatHistory;
search.clear(); search.clear();
isChatScreenActive = false; isChatScreenActive = false;
@ -648,46 +660,30 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
sFileType = ""; sFileType = "";
} }
// void scrollListener() { void getUserImages() async {
// _firstAutoscrollExecuted = true; List<String> emails = [];
// if (scrollController.hasClients && scrollController.position.pixels == scrollController.position.maxScrollExtent) { for (ChatUser element in searchedChats!) {
// _shouldAutoscroll = true; emails.add(await EmailImageEncryption().encrypt(val: element.email!));
// } else { }
// _shouldAutoscroll = false; List<ChatUserImageModel> chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails);
// } for (ChatUser user in searchedChats!) {
// } for (ChatUserImageModel uImage in chatImages) {
// if (user.email == uImage.email) {
// void scrollToBottom() { user.image = uImage.profilePicture ?? "";
// scrollController.animateTo( user.isImageLoading = false;
// scrollController.position.maxScrollExtent + 100, user.isImageLoaded = true;
// duration: const Duration(milliseconds: 500), }
// curve: Curves.easeIn, }
// ); }
// } for (ChatUser favUser in favUsersList) {
for (ChatUserImageModel uImage in chatImages) {
void msgScroll() { if (favUser.email == uImage.email) {
// scrollController.animateTo( favUser.image = uImage.profilePicture ?? "";
// // index: 150, favUser.isImageLoading = false;
// duration: Duration(seconds: 2), favUser.isImageLoaded = true;
// curve: Curves.easeInOutCubic); }
// scrollController.animateTo( }
// scrollController.position.minScrollExtent - 100, }
// duration: const Duration(milliseconds: 500), notifyListeners();
// curve: Curves.easeIn, }
// );
}
// Future<void> getDownLoadFile(String fileName) async {
// var data = await ChatApiClient().downloadURL(fileName: "data");
// Image.memory(data);
// }
// void getUserChatHistoryNotDeliveredAsync({required int userId}) async {
// try {
// await hubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]);
// } finally {
// hubConnection.off("GetUserChatHistoryNotDeliveredAsync", method: chatNotDelivered);
// }
// }
} }

@ -307,13 +307,21 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Future<HubConnection> getHubConnection() async { Future<HubConnection> getHubConnection() async {
HubConnection hub; HubConnection hub;
// try {
HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
hub = HubConnectionBuilder() hub = HubConnectionBuilder()
.withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Web&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Web&access_token=${AppState().chatDetails!.response!.token}", options: httpOp)
.withAutomaticReconnect(retryDelays: <int>[2000, 5000, 10000, 20000]).build(); .withAutomaticReconnect(retryDelays: <int>[2000, 5000, 10000, 20000]).build();
isChatHubLoding = false; isChatHubLoding = false;
return hub; return hub;
// } catch (e) {
// getUserAutoLoginToken().whenComplete(() {
// getHubConnection();
// });
// throw e;
// }
} }
void notify() { void notify() {
notifyListeners(); notifyListeners();
} }

@ -28,6 +28,7 @@ class ChatBubble extends StatelessWidget {
String? fileTypeDescription; String? fileTypeDescription;
bool isDelivered = false; bool isDelivered = false;
String userName = ''; String userName = '';
late Offset screenOffset;
void makeAssign() { void makeAssign() {
isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id ? true : false; isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id ? true : false;
@ -41,6 +42,8 @@ class ChatBubble extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Size windowSize = MediaQuery.of(context).size;
screenOffset = Offset(windowSize.width / 2, windowSize.height / 2);
makeAssign(); makeAssign();
return isCurrentUser ? currentUser(context) : receiptUser(context); return isCurrentUser ? currentUser(context) : receiptUser(context);
} }
@ -108,7 +111,11 @@ class ChatBubble extends StatelessWidget {
).paddingOnly(right: 5, bottom: 7), ).paddingOnly(right: 5, bottom: 7),
if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3) if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3)
showImage(isReplyPreview: false, fileName: cItem.contant!, fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription).paddingOnly(right: 5).onPress(() { showImage(isReplyPreview: false, fileName: cItem.contant!, fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription).paddingOnly(right: 5).onPress(() {
showDialog(context: context, builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!)); showDialog(
context: context,
anchorPoint: screenOffset,
builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!),
);
}), }),
cItem.contant!.toText12(), cItem.contant!.toText12(),
Align( Align(
@ -172,23 +179,28 @@ class ChatBubble extends StatelessWidget {
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
child: SizedBox( child: SizedBox(
height: 32, height: 32,
width: 32, width: 32,
child: showImage( child: showImage(
isReplyPreview: true, isReplyPreview: true,
fileName: cItem.userChatReplyResponse!.contant!, fileName: cItem.userChatReplyResponse!.contant!,
fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg")), fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg"),
),
).paddingOnly(left: 10, right: 10, bottom: 16, top: 16) ).paddingOnly(left: 10, right: 10, bottom: 16, top: 16)
], ],
), ),
), ),
).paddingOnly(right: 5, bottom: 7), ).paddingOnly(right: 5, bottom: 7),
if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3) if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3)
showImage(isReplyPreview: false, fileName: cItem.contant!, fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription ?? "image/jpg").paddingOnly(right: 5).onPress(() { showImage(isReplyPreview: false, fileName: cItem.contant ?? "", fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription ?? "image/jpg").paddingOnly(right: 5).onPress(() {
showDialog(context: context, builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!)); showDialog(
context: context,
anchorPoint: screenOffset,
builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant ?? "", img: cItem.image!),
);
}) })
else else
(cItem.contant! ?? "").toText12(color: Colors.white), (cItem.contant ?? "").toText12(color: Colors.white),
Align( Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: dateTime.toText10(color: Colors.white.withOpacity(.71)), child: dateTime.toText10(color: Colors.white.withOpacity(.71)),

@ -75,7 +75,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
context, context,
title: userDetails["targetUser"].userName.toString().replaceAll(".", " ").capitalizeFirstofEach, title: userDetails["targetUser"].userName.toString().replaceAll(".", " ").capitalizeFirstofEach,
showHomeButton: false, showHomeButton: false,
image: userDetails["targetUser"].image, image: userDetails["targetUser"].image.isEmpty ? null : userDetails["targetUser"].image,
actions: [ actions: [
SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() { SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() {
// makeCall(callType: "AUDIO", con: hubConnection); // makeCall(callType: "AUDIO", con: hubConnection);
@ -90,7 +90,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
body: Consumer<ChatProviderModel>( body: Consumer<ChatProviderModel>(
builder: (BuildContext context, ChatProviderModel m, Widget? child) { builder: (BuildContext context, ChatProviderModel m, Widget? child) {
return (m.isLoading return (m.isLoading
? ChatHomeShimmer() ? ChatHomeShimmer(isDetailedScreen: true,)
: Column( : Column(
children: <Widget>[ children: <Widget>[
SmartRefresher( SmartRefresher(

@ -12,29 +12,40 @@ class ChatImagePreviewScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return Dialog(
onTap: () { backgroundColor: Colors.transparent,
Navigator.of(context).pop(); insetPadding: const EdgeInsets.all(10),
}, child: Stack(
child: Dialog( alignment: Alignment.center,
backgroundColor: Colors.transparent, fit: StackFit.loose,
insetPadding: const EdgeInsets.all(10), children: [
child: Stack( Image.memory(
alignment: Alignment.center, img,
children: [ fit: BoxFit.fill,
Image.memory( height:500,
img, width: 500,
fit: BoxFit.cover, ).paddingAll(15),
height: 400, Positioned(
width: double.infinity, right: 0,
).paddingAll(10), top: 0,
const Positioned( child: Container(
right: 0, width: 30,
top: 0, height: 30,
child: Icon(Icons.cancel, color: MyColors.redA3Color, size: 35), alignment: Alignment.center,
) padding: EdgeInsets.zero,
], margin: EdgeInsets.zero,
), constraints: const BoxConstraints(),
color: MyColors.white,
child: const Icon(
Icons.cancel,
color: MyColors.redA3Color,
size: 30,
),
).onPress(() {
Navigator.of(context).pop();
}).circle(35),
)
],
), ),
); );
} }

@ -27,6 +27,10 @@ class _ChatHomeState extends State<ChatHome> {
void initState() { void initState() {
super.initState(); super.initState();
data = Provider.of<ChatProviderModel>(context, listen: false); data = Provider.of<ChatProviderModel>(context, listen: false);
data.registerEvents();
if (data.searchedChats == null || data.searchedChats!.isEmpty) {
data.getUserRecentChats();
}
} }
@override @override

@ -1,10 +1,14 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_des/flutter_des.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/encryption.dart';
import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
@ -12,10 +16,13 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.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/bottom_sheets/search_employee_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/circular_avatar.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class ChatHomeScreen extends StatefulWidget { class ChatHomeScreen extends StatefulWidget {
const ChatHomeScreen({Key? key}) : super(key: key);
@override @override
State<ChatHomeScreen> createState() => _ChatHomeScreenState(); State<ChatHomeScreen> createState() => _ChatHomeScreenState();
} }
@ -26,11 +33,8 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
@override @override
void initState() { void initState() {
// TODO: implement initState
super.initState(); super.initState();
data = Provider.of<ChatProviderModel>(context, listen: false); data = Provider.of<ChatProviderModel>(context, listen: false);
data.registerEvents();
data.getUserRecentChats();
} }
@override @override
@ -46,7 +50,7 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
body: Consumer<ChatProviderModel>( body: Consumer<ChatProviderModel>(
builder: (BuildContext context, ChatProviderModel m, Widget? child) { builder: (BuildContext context, ChatProviderModel m, Widget? child) {
return m.isLoading return m.isLoading
? ChatHomeShimmer() ? ChatHomeShimmer(isDetailedScreen: false,)
: Column( : Column(
children: <Widget>[ children: <Widget>[
TextField( TextField(
@ -63,7 +67,7 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
hintText: LocaleKeys.searchfromchat.tr(), hintText: LocaleKeys.searchfromchat.tr(),
hintStyle: const TextStyle(color: MyColors.lightTextColor, fontStyle: FontStyle.italic, fontWeight: FontWeight.w500, fontSize: 12), hintStyle: const TextStyle(color: MyColors.lightTextColor, fontStyle: FontStyle.italic, fontWeight: FontWeight.w500, fontSize: 12),
filled: true, filled: true,
fillColor: const Color(0xFFF7F7F7), fillColor: MyColors.greyF7Color,
suffixIconConstraints: const BoxConstraints(), suffixIconConstraints: const BoxConstraints(),
suffixIcon: m.search.text.isNotEmpty suffixIcon: m.search.text.isNotEmpty
? IconButton( ? IconButton(
@ -82,19 +86,33 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
itemCount: m.searchedChats!.length, itemCount: m.searchedChats!.length,
shrinkWrap: true, shrinkWrap: true,
physics: const ClampingScrollPhysics(), physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.only(bottom: 80.0),
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
// todo @aamir, remove list tile, make a custom ui instead
return SizedBox( return SizedBox(
height: 55, height: 55,
child: Row( child: Row(
children: [ children: [
Stack( Stack(
children: <Widget>[ children: <Widget>[
SvgPicture.asset( if (m.searchedChats![index].isImageLoading!)
"assets/images/user.svg", const SizedBox(
height: 48, height: 48,
width: 48, width: 48,
), ).toShimmer().circle(30),
if (m.searchedChats![index].isImageLoaded! && m.searchedChats![index].image != null && m.searchedChats![index].image.isNotEmpty)
CircularAvatar(
radius: 20,
height: 48,
width: 48,
url: m.searchedChats![index].image,
isImageBase64: true,
),
if (!m.searchedChats![index].isImageLoading! && m.searchedChats![index].isImageLoaded! && m.searchedChats![index].image.isEmpty)
SvgPicture.asset(
"assets/images/user.svg",
height: 48,
width: 48,
),
Positioned( Positioned(
right: 5, right: 5,
bottom: 1, bottom: 1,
@ -103,11 +121,8 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
height: 10, height: 10,
decoration: BoxDecoration( decoration: BoxDecoration(
color: m.searchedChats![index].userStatus == 1 ? MyColors.green2DColor : Colors.red, color: m.searchedChats![index].userStatus == 1 ? MyColors.green2DColor : Colors.red,
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
), ),
), ).circle(10),
) )
], ],
), ),
@ -176,14 +191,13 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
AppRoutes.chatDetailed, AppRoutes.chatDetailed,
arguments: {"targetUser": m.searchedChats![index], "isNewChat": false}, arguments: {"targetUser": m.searchedChats![index], "isNewChat": false},
).then((Object? value) { ).then((Object? value) {
// m.GetUserChatHistoryNotDeliveredAsync(userId: int.parse(AppState().chatDetails!.response!.id.toString()));
m.clearSelections(); m.clearSelections();
m.notifyListeners(); m.notifyListeners();
}); });
}); });
}, },
separatorBuilder: (BuildContext context, int index) => const Divider(color: MyColors.lightGreyE5Color).paddingOnly(left: 59), separatorBuilder: (BuildContext context, int index) => const Divider(color: MyColors.lightGreyE5Color).paddingOnly(left: 59),
).paddingOnly(bottom: 70).expanded, ).expanded,
], ],
).paddingOnly(left: 21, right: 21); ).paddingOnly(left: 21, right: 21);
}, },
@ -211,9 +225,6 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
), ),
), ),
onPressed: () async { onPressed: () async {
// String plainText = 'Muhamad.Alam@cloudsolutions.com.sa';
// String key = "PeShVmYp";
// passEncrypt(plainText, "PeShVmYp");
showMyBottomSheet( showMyBottomSheet(
context, context,
callBackFunc: () {}, callBackFunc: () {},
@ -231,137 +242,10 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
OutlineInputBorder fieldBorder({required double radius, required int color}) { OutlineInputBorder fieldBorder({required double radius, required int color}) {
return OutlineInputBorder( return OutlineInputBorder(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(radius),
radius,
),
borderSide: BorderSide( borderSide: BorderSide(
color: Color( color: Color(color),
color,
),
), ),
); );
} }
//
// void passEncrypt(String text, String pass) async {
// var salt = randomUint8List(8);
// var keyndIV = deriveKeyAndIV(pass, salt);
// var key = encrypt.Key(keyndIV.item1);
// var iv = encrypt.IV(keyndIV.item2);
// var encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
// var encrypted = encrypter.encrypt(text, iv: iv);
// Uint8List encryptedBytesWithSalt = Uint8List.fromList(createUint8ListFromString("Salted__") + salt + encrypted.bytes);
// var resulttt = base64.encode(encryptedBytesWithSalt);
// print("Enc : " + resulttt);
//
// decryptAESCryptoJS(resulttt, pass);
// }
//
// Uint8List randomUint8List(int length) {
// assert(length > 0);
// var random = Random();
// var ret = Uint8List(length);
// for (var i = 0; i < length; i++) {
// ret[i] = random.nextInt(256);
// }
// return ret;
// }
//
// void decryptAESCryptoJS(String encrypted, String passphrase) {
// try {
// Uint8List encryptedBytesWithSalt = base64.decode(encrypted);
// Uint8List encryptedBytes = encryptedBytesWithSalt.sublist(16, encryptedBytesWithSalt.length);
// var salt = encryptedBytesWithSalt.sublist(8, 16);
// var keyndIV = deriveKeyAndIV(passphrase, salt);
// var key = encrypt.Key(keyndIV.item1);
// var iv = encrypt.IV(keyndIV.item2);
// var encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
// var decrypted = encrypter.decrypt64(base64.encode(encryptedBytes), iv: iv);
// print("Dec : " + decrypted);
// // return decrypted;
// } catch (error) {
// throw error;
// }
// }
void enc(String input) {
var ekey = "PeShVmYp";
var eIV = "j70IbWYn";
List<int> eByt = utf8.encode(ekey);
List<int> eIvByt = utf8.encode(eIV);
List<int> iByt = utf8.encode(input);
}
// ///Accepts encrypted data and decrypt it. Returns plain text
// String decryptWithAES(String key, Encrypted encryptedData) {
// var cipherKey = encrypt.Key.fromUtf8(key);
// var encryptService = Encrypter(AES(cipherKey, mode: AESMode.cbc,padding: null));
// var initVector = IV.fromUtf8(key.substring(0, 16));
// return encryptService.decrypt(encryptedData, iv: initVector);
// }
//
// ///Encrypts the given plainText using the key. Returns encrypted data
// Encrypted encryptWithAES(String key, String plainText) {
// var cipherKey = encrypt.Key.fromUtf8(key);
// var encryptService = Encrypter(AES(cipherKey, mode: AESMode.cbc,padding: null));
// var initVector = IV.fromUtf8("j70IbWYn");
// Encrypted encryptedData = encryptService.encrypt(plainText, iv: initVector);
// print(encryptedData.base64);
// return encryptedData;
// }
//
// Tuple2<Uint8List, Uint8List> deriveKeyAndIV(String passphrase, Uint8List salt) {
// var password = createUint8ListFromString(passphrase);
// Uint8List concatenatedHashes = Uint8List(0);
// Uint8List currentHash = Uint8List(0);
// bool enoughBytesForKey = false;
// Uint8List preHash = Uint8List(0);
//
// while (!enoughBytesForKey) {
// int preHashLength = currentHash.length + password.length + salt.length;
// if (currentHash.length > 0)
// preHash = Uint8List.fromList(currentHash + password + salt);
// else
// preHash = Uint8List.fromList(password + salt);
//
// currentHash = preHash;
// concatenatedHashes = Uint8List.fromList(concatenatedHashes + currentHash);
// if (concatenatedHashes.length >= 48) enoughBytesForKey = true;
// }
//
// var keyBtyes = concatenatedHashes.sublist(0, 32);
// var ivBtyes = concatenatedHashes.sublist(32, 48);
// return new Tuple2(keyBtyes, ivBtyes);
// }
//
// Uint8List createUint8ListFromString(String s) {
// var ret = new Uint8List(s.length);
// for (var i = 0; i < s.length; i++) {
// ret[i] = s.codeUnitAt(i);
// }
// return ret;
// }
//
// Uint8List genRandomWithNonZero(int seedLength) {
// var random = Random.secure();
// const int randomMax = 245;
// Uint8List uint8list = Uint8List(seedLength);
// for (int i = 0; i < seedLength; i++) {
// uint8list[i] = random.nextInt(randomMax) + 1;
// }
// return uint8list;
// }
//
//
//
// void test(String text, String kk) {
// Uint8List key = Uint8List.fromList(utf8.encode(kk));
// PaddedBlockCipher cipher = exp.PaddedBlockCipherImpl(exp.PKCS7Padding(), exp.ECBBlockCipher(exp.AESEngine()));
// cipher.init(true, PaddedBlockCipherParameters<CipherParameters, CipherParameters>(KeyParameter(key), null));
// var byte = Uint8List.fromList(utf8.encode(text));
// var data = cipher.process(byte);
// print(data);
// }
} }

@ -9,6 +9,7 @@ import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/widgets/circular_avatar.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -22,7 +23,7 @@ class ChatFavoriteUsersScreen extends StatelessWidget {
body: Consumer<ChatProviderModel>( body: Consumer<ChatProviderModel>(
builder: (BuildContext context, ChatProviderModel m, Widget? child) { builder: (BuildContext context, ChatProviderModel m, Widget? child) {
if (m.isLoading) { if (m.isLoading) {
return ChatHomeShimmer(); return ChatHomeShimmer(isDetailedScreen: false,);
} else { } else {
return m.favUsersList != null && m.favUsersList.isNotEmpty return m.favUsersList != null && m.favUsersList.isNotEmpty
? ListView.separated( ? ListView.separated(
@ -36,11 +37,25 @@ class ChatFavoriteUsersScreen extends StatelessWidget {
children: [ children: [
Stack( Stack(
children: <Widget>[ children: <Widget>[
SvgPicture.asset( if (m.favUsersList![index].isImageLoading!)
"assets/images/user.svg", const SizedBox(
height: 48, height: 48,
width: 48, width: 48,
), ).toShimmer().circle(30),
if (m.favUsersList![index].isImageLoaded! && m.favUsersList![index].image != null && m.favUsersList![index].image.isNotEmpty)
CircularAvatar(
radius: 20,
height: 48,
width: 48,
url: m.favUsersList![index].image,
isImageBase64: true,
),
if (!m.favUsersList![index].isImageLoading! && m.favUsersList![index].isImageLoaded! && m.favUsersList![index].image.isEmpty)
SvgPicture.asset(
"assets/images/user.svg",
height: 48,
width: 48,
),
Positioned( Positioned(
right: 5, right: 5,
bottom: 1, bottom: 1,
@ -49,11 +64,8 @@ class ChatFavoriteUsersScreen extends StatelessWidget {
height: 10, height: 10,
decoration: BoxDecoration( decoration: BoxDecoration(
color: m.favUsersList![index].userStatus == 1 ? MyColors.green2DColor : Colors.red, color: m.favUsersList![index].userStatus == 1 ? MyColors.green2DColor : Colors.red,
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
), ),
), ).circle(10),
) )
], ],
), ),

@ -6,6 +6,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/classes/utils.dart';
@ -63,6 +64,12 @@ class _DashboardScreenState extends State<DashboardScreen> {
void buildHubConnection() async { void buildHubConnection() async {
hubConnection = await data.getHubConnection(); hubConnection = await data.getHubConnection();
await hubConnection.start(); await hubConnection.start();
hubConnection.onreconnecting(({Exception? error}) {
print("============== Reconnecting Hub ======================");
data.getUserAutoLoginToken().whenComplete(() {
buildHubConnection();
});
});
} }
@override @override
@ -106,9 +113,11 @@ class _DashboardScreenState extends State<DashboardScreen> {
// onPressed: () { // onPressed: () {
// data.getITGNotification().then((val) { // data.getITGNotification().then((val) {
// if (val!.result!.data != null) { // if (val!.result!.data != null) {
// print("-------------------- Survey ----------------------------");
// if (val.result!.data!.notificationType == "Survey") { // if (val.result!.data!.notificationType == "Survey") {
// Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data); // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data);
// } else { // } else {
// print("------------------------------------------- Ads --------------------");
// DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then( // DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then(
// (value) { // (value) {
// if (value!.mohemmItgResponseItem!.statusCode == 200) { // if (value!.mohemmItgResponseItem!.statusCode == 200) {

@ -69,7 +69,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
await controller.setLooping(false); await controller.setLooping(false);
return controller; return controller;
} catch (e) { } catch (e) {
return new VideoPlayerController.asset("dataSource"); return VideoPlayerController.asset("dataSource");
} }
} }
@ -94,29 +94,28 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
if (advertisementData != null) { if (advertisementData != null) {
checkFileType(); checkFileType();
} }
double height = MediaQuery.of(context).size.height * .25; // double height = MediaQuery.of(context).size.height * .25;
return Scaffold( return Scaffold(
body: Column( body: Stack(
children: [ children: [
if (isVideo) if (isVideo)
SizedBox( FutureBuilder(
height: MediaQuery.of(context).size.height * .3, future: _futureController,
child: FutureBuilder( builder: (BuildContext context, AsyncSnapshot<Object?> snapshot) {
future: _futureController, if (snapshot.connectionState == ConnectionState.done && snapshot.data != null) {
builder: (BuildContext context, AsyncSnapshot<Object?> snapshot) { _controller = snapshot.data as VideoPlayerController;
if (snapshot.connectionState == ConnectionState.done && snapshot.data != null) { return Positioned.fill(
_controller = snapshot.data as VideoPlayerController; child: AspectRatio(
return AspectRatio(
aspectRatio: _controller.value.aspectRatio, aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller), child: VideoPlayer(_controller),
); ),
} else { );
return const Center( } else {
child: CircularProgressIndicator(), return const Center(
); child: CircularProgressIndicator(),
} );
}, }
), },
), ),
if (isImage) Image.file(imageFile), if (isImage) Image.file(imageFile),
if (skip) if (skip)

@ -5,6 +5,7 @@ import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/widgets/circular_avatar.dart';
AppBar AppBarWidget(BuildContext context, AppBar AppBarWidget(BuildContext context,
{required String title, bool showHomeButton = true, bool showNotificationButton = false, bool showMemberButton = false, String? image, List<Widget>? actions}) { {required String title, bool showHomeButton = true, bool showNotificationButton = false, bool showMemberButton = false, String? image, List<Widget>? actions}) {
@ -25,10 +26,11 @@ AppBar AppBarWidget(BuildContext context,
), ),
4.width, 4.width,
if (image != null) if (image != null)
SvgPicture.asset( CircularAvatar(
image, url: image,
height: 40, height: 40,
width: 40, width: 40,
isImageBase64: true,
), ),
if (image != null) 14.width, if (image != null) 14.width,
title.toText24(color: MyColors.darkTextColor, isBold: true).expanded, title.toText24(color: MyColors.darkTextColor, isBold: true).expanded,

@ -188,7 +188,6 @@ class ServicesMenuShimmer extends StatelessWidget {
} }
} }
class MarathonBannerShimmer extends StatelessWidget { class MarathonBannerShimmer extends StatelessWidget {
const MarathonBannerShimmer({Key? key}) : super(key: key); const MarathonBannerShimmer({Key? key}) : super(key: key);
@ -236,6 +235,11 @@ class MarathonBannerShimmer extends StatelessWidget {
} }
class ChatHomeShimmer extends StatelessWidget { class ChatHomeShimmer extends StatelessWidget {
bool isDetailedScreen;
ChatHomeShimmer({Key? key, required this.isDetailedScreen}) : super(key: key);
@override
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
@ -254,42 +258,42 @@ class ChatHomeShimmer extends StatelessWidget {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Container( if (!isDetailedScreen)
width: 48.0, Container(
height: 48.0, width: 48.0,
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40))), height: 48.0,
), decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40))),
const Padding( ),
padding: EdgeInsets.symmetric(horizontal: 8.0), if (!isDetailedScreen)
), const Padding(
Expanded( padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: double.infinity,
height: 8.0,
color: Colors.white,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 2.0),
),
Container(
width: double.infinity,
height: 8.0,
color: Colors.white,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 2.0),
),
Container(
width: 40.0,
height: 8.0,
color: Colors.white,
),
],
), ),
) Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: double.infinity,
height: 8.0,
color: Colors.white,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 2.0),
),
Container(
width: double.infinity,
height: 8.0,
color: Colors.white,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 2.0),
),
Container(
width: 40.0,
height: 8.0,
color: Colors.white,
),
],
).expanded
], ],
), ),
), ),

@ -93,11 +93,8 @@ dependencies:
flutter_webrtc: ^0.9.16 flutter_webrtc: ^0.9.16
camera: ^0.10.0+4 camera: ^0.10.0+4
#Encryption #Encryption
cryptography: ^2.0.5 flutter_des: ^2.1.0
cryptography_flutter: ^2.0.2
video_player: ^2.4.7 video_player: ^2.4.7
just_audio: ^0.9.30 just_audio: ^0.9.30

Loading…
Cancel
Save