Merge branch 'master' into fatima

fatima
Fatimah Alshammari 3 years ago
commit 1c750a4084

@ -10,7 +10,7 @@
"client_info": { "client_info": {
"mobilesdk_app_id": "1:679409052782:android:dba155ac0859d7fea78a7f", "mobilesdk_app_id": "1:679409052782:android:dba155ac0859d7fea78a7f",
"android_client_info": { "android_client_info": {
"package_name": "com.cloudSolutions.mohemmtest" "package_name": "hmg.cloudSolutions.mohem"
} }
}, },
"oauth_client": [ "oauth_client": [

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:#F15642;" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16
V416z"/>
<g>
<path style="fill:#FFFFFF;" d="M88.368,384c-4.096-2.304-6.656-6.912-4.096-12.288l36.72-71.744c3.456-6.784,12.656-7.04,15.856,0
l36.08,71.744c5.248,9.984-10.24,17.904-14.848,7.936l-5.632-11.248h-47.2l-5.52,11.248C97.712,384,92.992,384.912,88.368,384z
M143.392,351.52l-14.464-31.616l-15.744,31.616H143.392z"/>
<path style="fill:#FFFFFF;" d="M189.184,384c-4.096-2.304-6.656-6.912-4.096-12.288l36.704-71.744
c3.456-6.784,12.672-7.04,15.872,0l36.064,71.744c5.248,9.984-10.24,17.904-14.832,7.936l-5.648-11.248h-47.2l-5.504,11.248
C198.512,384,193.776,384.912,189.184,384z M244.192,351.52l-14.448-31.616l-15.728,31.616H244.192z"/>
<path style="fill:#FFFFFF;" d="M282.416,339.088c0-24.688,15.488-45.904,44.912-45.904c11.136,0,19.952,3.312,29.296,11.376
c3.456,3.184,3.84,8.832,0.384,12.4c-3.456,3.056-8.704,2.688-11.76-0.368c-5.248-5.504-10.624-7.024-17.92-7.024
c-19.696,0-29.168,13.936-29.168,29.536c0,15.872,9.344,30.464,29.168,30.464c7.296,0,14.08-2.96,19.952-8.192
c3.968-3.072,9.472-1.552,11.776,1.536c2.048,2.816,3.056,7.536-1.408,12.016c-8.96,8.336-19.696,9.984-30.336,9.984
C296.368,384.912,282.416,363.792,282.416,339.088z"/>
</g>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.616,14.4,32,32,32h320c17.6,0,32-14.384,32-32V128L352,0H128z
"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:#50BEE8;" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16
V416z"/>
<g>
<path style="fill:#FFFFFF;" d="M117.184,327.84v47.344c0,5.632-4.592,8.832-9.216,8.832c-4.096,0-7.664-3.2-7.664-8.832v-72.032
c0-6.64,5.632-8.832,7.664-8.832c3.712,0,5.888,2.192,8.064,4.608l28.16,38l29.152-39.408c4.24-5.248,14.592-3.2,14.592,5.632
v72.032c0,5.632-3.6,8.832-7.68,8.832c-4.592,0-8.192-3.2-8.192-8.832V327.84l-21.232,26.88c-4.592,5.632-10.352,5.632-14.576,0
L117.184,327.84z"/>
<path style="fill:#FFFFFF;" d="M210.288,303.152c0-4.224,3.328-8.832,8.704-8.832h29.552c16.64,0,31.616,11.136,31.616,32.496
c0,20.224-14.976,31.472-31.616,31.472h-21.36v16.896c0,5.632-3.584,8.832-8.192,8.832c-4.224,0-8.704-3.2-8.704-8.832V303.152z
M227.168,310.448v31.856h21.36c8.576,0,15.36-7.552,15.36-15.488c0-8.96-6.784-16.368-15.36-16.368L227.168,310.448
L227.168,310.448z"/>
<path style="fill:#FFFFFF;" d="M322.064,311.472h-21.872c-10.736,0-10.096-15.984,0-15.984h39.152c7.792,0,11.376,8.96,5.632,14.72
l-21.232,19.824c15.616-1.152,27.888,10.48,27.888,24.816c0,15.728-11.136,29.168-34.544,29.168
c-10.24,0-20.336-4.224-26.224-13.44c-6.144-9.072,7.024-17.776,13.936-8.832c3.328,4.352,8.704,6.528,14.448,6.528
c7.808,0,15.488-3.328,15.488-13.44c0-13.296-16.256-11.248-25.072-10.352c-10.752,2.048-13.936-9.6-7.664-14.448L322.064,311.472z
"/>
</g>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -514,5 +514,7 @@
"startingIn": "يبدأ في", "startingIn": "يبدأ في",
"youAreOutOfContest": "أنت خارج المسابقة.", "youAreOutOfContest": "أنت خارج المسابقة.",
"winners": "الفائزين!!!", "winners": "الفائزين!!!",
"fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية" "noUpcoming": "لا يوجد قادم",
"fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية",
"noWinner": "حزين! لم يفز أحد اليوم."
} }

@ -514,5 +514,7 @@
"startingIn": "Starting in", "startingIn": "Starting in",
"youAreOutOfContest": "You are out of the contest.", "youAreOutOfContest": "You are out of the contest.",
"winners": "WINNERS!!!", "winners": "WINNERS!!!",
"fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified." "noUpcoming": "There is no upcoming",
"fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified.",
"noWinner": "Sad! No one won today."
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -33,7 +33,6 @@ class ChatApiClient {
}, },
); );
if (!kReleaseMode) { if (!kReleaseMode) {
print("Status Code is ================" + response.statusCode.toString());
logger.i("res: " + response.body); logger.i("res: " + response.body);
} }
if (response.statusCode == 200) { if (response.statusCode == 200) {
@ -58,6 +57,7 @@ class ChatApiClient {
return List<ChatUser>.from(json.decode(response.body).map((x) => ChatUser.fromJson(x))); return List<ChatUser>.from(json.decode(response.body).map((x) => ChatUser.fromJson(x)));
} }
//Get User Recent Chats
Future<ChatUserModel> getRecentChats() async { Future<ChatUserModel> getRecentChats() async {
try { try {
Response response = await ApiClient().getJsonForResponse( Response response = await ApiClient().getJsonForResponse(
@ -75,6 +75,7 @@ class ChatApiClient {
} }
} }
// Get Favorite Users
Future<ChatUserModel> getFavUsers() async { Future<ChatUserModel> getFavUsers() async {
Response favRes = await ApiClient().getJsonForResponse( Response favRes = await ApiClient().getJsonForResponse(
"${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}", "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}",
@ -86,6 +87,7 @@ class ChatApiClient {
return ChatUserModel.fromJson(json.decode(favRes.body)); return ChatUserModel.fromJson(json.decode(favRes.body));
} }
//Get User Chat History
Future<Response> getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async { Future<Response> getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async {
try { try {
Response response = await ApiClient().getJsonForResponse( Response response = await ApiClient().getJsonForResponse(
@ -97,10 +99,12 @@ class ChatApiClient {
} }
return response; return response;
} catch (e) { } catch (e) {
getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal);
throw e; throw e;
} }
} }
//Favorite Users
Future<fav.FavoriteChatUser> favUser({required int userID, required int targetUserID}) async { Future<fav.FavoriteChatUser> favUser({required int userID, required int targetUserID}) async {
Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token);
if (!kReleaseMode) { if (!kReleaseMode) {
@ -110,6 +114,7 @@ class ChatApiClient {
return favoriteChatUser; return favoriteChatUser;
} }
//UnFavorite Users
Future<fav.FavoriteChatUser> unFavUser({required int userID, required int targetUserID}) async { Future<fav.FavoriteChatUser> unFavUser({required int userID, required int targetUserID}) async {
try { try {
Response response = await ApiClient().postJsonForResponse( Response response = await ApiClient().postJsonForResponse(
@ -120,7 +125,6 @@ class ChatApiClient {
if (!kReleaseMode) { if (!kReleaseMode) {
logger.i("res: " + response.body); logger.i("res: " + response.body);
} }
fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body);
return favoriteChatUser; return favoriteChatUser;
} catch (e) { } catch (e) {
@ -129,33 +133,37 @@ class ChatApiClient {
} }
} }
Future<StreamedResponse> uploadMedia(String userId, File file) async { // Upload Chat Media
Future<Object?> uploadMedia(String userId, File file) async {
if (kDebugMode) {
print("${ApiConsts.chatMediaImageUploadUrl}upload");
print(AppState().chatDetails!.response!.token);
}
dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload'));
request.fields.addAll({'userId': userId, 'fileSource': '1'}); request.fields.addAll({'userId': userId, 'fileSource': '1'});
request.files.add(await MultipartFile.fromPath('files', file.path)); request.files.add(await MultipartFile.fromPath('files', file.path));
request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'});
StreamedResponse response = await request.send(); StreamedResponse response = await request.send();
if (!kReleaseMode) {} String data = await response.stream.bytesToString();
return response; if (!kReleaseMode) {
logger.i("res: " + data);
}
return jsonDecode(data);
} }
// Download File For Chat // Download File For Chat
Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription}) async { Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription}) async {
print(fileName);
print(fileTypeDescription);
print("${ApiConsts.chatMediaImageUploadUrl}download");
print(AppState().chatDetails!.response!.token);
Response response = await ApiClient().postJsonForResponse( Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatMediaImageUploadUrl}download", "${ApiConsts.chatMediaImageUploadUrl}download",
{"fileType": fileTypeDescription, "fileName": fileName, "fileSource": 1}, {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": 1},
token: AppState().chatDetails!.response!.token, token: AppState().chatDetails!.response!.token,
); );
Uint8List data = Uint8List.fromList(response.bodyBytes); Uint8List data = Uint8List.fromList(response.bodyBytes);
return data; return data;
} }
//Get Chat Users & Favorite Images
Future<List<ChatUserImageModel>> getUsersImages({required List<String> encryptedEmails}) async { Future<List<ChatUserImageModel>> getUsersImages({required List<String> encryptedEmails}) async {
List<ChatUserImageModel> imagesData = []; List<ChatUserImageModel> imagesData = [];
Response response = await ApiClient().postJsonForResponse( Response response = await ApiClient().postJsonForResponse(

@ -1,14 +1,19 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:logger/logger.dart' as L; import 'package:logger/logger.dart' as L;
import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/api/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/consts.dart'; import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart'; import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_model.dart'; import 'package:mohem_flutter_app/models/marathon/marathon_model.dart';
import 'package:mohem_flutter_app/models/marathon/question_model.dart'; import 'package:mohem_flutter_app/models/marathon/question_model.dart';
import 'package:mohem_flutter_app/models/marathon/winner_model.dart'; import 'package:mohem_flutter_app/models/marathon/winner_model.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:provider/provider.dart';
import 'package:signalr_netcore/hub_connection.dart'; import 'package:signalr_netcore/hub_connection.dart';
class MarathonApiClient { class MarathonApiClient {
@ -18,52 +23,39 @@ class MarathonApiClient {
Future<String> getMarathonToken() async { Future<String> getMarathonToken() async {
String employeeUserName = AppState().getUserName ?? ""; String employeeUserName = AppState().getUserName ?? "";
String employeeSession = AppState().postParamsObject?.pSessionId.toString() ?? ""; String employeeSession = AppState().postParamsObject?.pSessionId.toString() ?? "";
Map<String, String> jsonObject = <String, String>{"userName": employeeUserName, "password": employeeSession}; Map<String, String> jsonObject = <String, String>{"userName": employeeUserName, "password": employeeSession};
Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonParticipantLoginUrl, jsonObject); return await ApiClient().postJsonForObject(
(json) {
var json = jsonDecode(response.body);
MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json); MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
if (marathonModel.statusCode == 200) {
if (marathonModel.data != null && marathonModel.isSuccessful == true) {
AppState().setMarathonToken = marathonModel.data["token"] ?? ""; AppState().setMarathonToken = marathonModel.data["token"] ?? "";
print("marathonToken: ${"AppState(): ${AppState().getMarathonToken}"}");
return marathonModel.data["token"] ?? ""; return marathonModel.data["token"] ?? "";
} else { },
//TODO : DO ERROR HANDLING HERE ApiConsts.marathonParticipantLoginUrl,
return ""; jsonObject,
} );
} else {
//TODO : DO ERROR HANDLING HERE
return "";
}
} }
Future<String> getProjectId() async { Future<String> getProjectId() async {
Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonProjectGetUrl, <String, dynamic>{}, token: AppState().getMarathonToken ?? await getMarathonToken()); return await ApiClient().postJsonForObject(
(json) {
var json = jsonDecode(response.body); MarathonGenericModel responseData = MarathonGenericModel.fromJson(json);
MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json); return responseData.data[0]["id"] ?? "";
},
if (marathonModel.statusCode == 200) { ApiConsts.marathonProjectGetUrl,
if (marathonModel.data != null && marathonModel.isSuccessful == true) { <String, dynamic>{},
logger.i("message: ${marathonModel.data[0]["id"]}"); token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
AppState().setMarathonProjectId = marathonModel.data[0]["id"] ?? ""; );
return marathonModel.data[0]["id"] ?? "";
} else {
return "";
}
} else {
return "";
}
} }
Future<MarathonDetailModel> getMarathonDetails() async { Future<MarathonDetailModel> getMarathonDetails() async {
String payrollString = AppState().postParamsObject?.payrollCodeStr.toString() ?? "CS"; String payrollString = AppState().postParamsObject?.payrollCodeStr.toString() ?? "CS";
Response response = await ApiClient().getJsonForResponse(ApiConsts.marathonUpcomingUrl + payrollString, token: AppState().getMarathonToken ?? await getMarathonToken()); Response response = await ApiClient().getJsonForResponse(
ApiConsts.marathonUpcomingUrl + payrollString,
token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
);
var json = jsonDecode(response.body); var json = jsonDecode(response.body);
logger.i("json in getMarathonDetails: $json"); logger.i("json in getMarathonDetails: $json");
@ -89,72 +81,73 @@ class MarathonApiClient {
"marathonId": AppState().getMarathonProjectId!, "marathonId": AppState().getMarathonProjectId!,
}; };
Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonJoinParticipantUrl, jsonObject, token: AppState().getMarathonToken ?? await getMarathonToken()); return await ApiClient().postJsonForObject(
(json) {
var json = jsonDecode(response.body);
MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json); MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
if (marathonModel.statusCode == 208) {
// means participant is already in the marathon i.e already joined
//TODO: NEED TO LOOK UPON THIS
return marathonModel.data["remainingTime"]; return marathonModel.data["remainingTime"];
},
ApiConsts.marathonJoinParticipantUrl,
jsonObject,
token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
);
} }
if (marathonModel.statusCode == 200) { Future<QuestionModel> getNextQuestion({required String? questionId, required String marathonId}) async {
if (marathonModel.data != null && marathonModel.isSuccessful == true) {
logger.i("joinMarathonAsParticipant: ${marathonModel.data}");
return marathonModel.data["remainingTime"];
} else {
return null;
}
} else {
return null;
}
}
Future<QuestionModel?> getNextQuestion({required String? questionId, required String marathonId}) async {
Map<String, String?> jsonObject = <String, String?>{ Map<String, String?> jsonObject = <String, String?>{
"previousQuestionId": questionId, "previousQuestionId": questionId,
"marathonId": marathonId, "marathonId": marathonId,
}; };
Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonNextQuestionUrl, jsonObject, token: AppState().getMarathonToken ?? await getMarathonToken()); return await ApiClient().postJsonForObject(
(json) {
var json = jsonDecode(response.body); MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
logger.i("json in NextQuestion: $json");
var data = json["data"];
if (data != null) { if (marathonModel.statusCode == 404 || marathonModel.statusCode == 208 || marathonModel.statusCode == 204 || marathonModel.statusCode == 500) {
QuestionModel newQuestion = QuestionModel.fromJson(data); Utils.confirmDialog(
return newQuestion; AppRoutes.navigatorKey.currentContext,
} else { marathonModel.message!,
return null; onTap: () {
AppRoutes.navigatorKey.currentContext!.read<MarathonProvider>().resetValues();
Navigator.of(
AppRoutes.navigatorKey.currentContext!,
).popUntil(ModalRoute.withName(AppRoutes.dashboard));
},
);
} }
QuestionModel newQuestion = QuestionModel.fromJson(marathonModel.data);
return newQuestion;
},
ApiConsts.marathonNextQuestionUrl,
jsonObject,
token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
);
} }
Future<bool> submitSelectedOption({required String marathonId, required String? questionId, required String? selectedAnswerId}) async { Future<bool> submitSelectedOption({required String marathonId, required String? questionId, required String? selectedAnswerId}) async {
Map<String, String?> jsonObject = <String, String?>{"marathonId": marathonId, "questionId": questionId, "selectedOptionId": selectedAnswerId}; Map<String, String?> jsonObject = <String, String?>{"marathonId": marathonId, "questionId": questionId, "selectedOptionId": selectedAnswerId};
Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonSubmitAnswerUrl, jsonObject, token: AppState().getMarathonToken ?? await getMarathonToken()); return await ApiClient().postJsonForObject(
(json) {
var json = jsonDecode(response.body);
logger.i("json in submitSelectedOption : $json");
MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json); MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
if (marathonModel.data != null) {
if (marathonModel.isSuccessful == null) { bool isOptionCorrect = marathonModel.data["isCorrect"];
return false; return isOptionCorrect;
} }
return false;
return marathonModel.isSuccessful!; },
ApiConsts.marathonSubmitAnswerUrl,
jsonObject,
token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
);
} }
Future<int?> getQualifiers({required String marathonId}) async { Future<int?> getQualifiers({required String marathonId}) async {
Map<String, String> params = <String, String>{"marathonId": marathonId}; Map<String, String> params = <String, String>{"marathonId": marathonId};
Response response = await ApiClient().getJsonForResponse(ApiConsts.marathonQualifiersUrl, queryParameters: params, token: AppState().getMarathonToken ?? await getMarathonToken()); Response response = await ApiClient().getJsonForResponse(
ApiConsts.marathonQualifiersUrl,
queryParameters: params,
token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
);
var json = jsonDecode(response.body); var json = jsonDecode(response.body);
logger.i("json in getQualifiers: $json"); logger.i("json in getQualifiers: $json");
@ -169,7 +162,11 @@ class MarathonApiClient {
Future<List<WinnerModel>?> getSelectedWinner({required String marathonId}) async { Future<List<WinnerModel>?> getSelectedWinner({required String marathonId}) async {
Map<String, String> params = <String, String>{"marathonId": marathonId}; Map<String, String> params = <String, String>{"marathonId": marathonId};
Response response = await ApiClient().getJsonForResponse(ApiConsts.marathonSelectedWinner, queryParameters: params, token: AppState().getMarathonToken ?? await getMarathonToken()); Response response = await ApiClient().getJsonForResponse(
ApiConsts.marathonSelectedWinner,
queryParameters: params,
token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
);
var json = jsonDecode(response.body); var json = jsonDecode(response.body);
logger.i("json in getSelectedWinner: $json"); logger.i("json in getSelectedWinner: $json");

File diff suppressed because one or more lines are too long

@ -44,6 +44,7 @@ class ApiConsts {
static int tabletMinLength = 500; static int tabletMinLength = 500;
} }
class SharedPrefsConsts { class SharedPrefsConsts {
static String isRememberMe = "remember_me"; static String isRememberMe = "remember_me";
static String username = "username"; static String username = "username";

@ -459,7 +459,7 @@ class DateUtil {
/// get data formatted like 10:30 according to lang /// get data formatted like 10:30 according to lang
static String formatDateToTimeLang(DateTime date, bool isArabic) { static String formatDateToTimeLang(DateTime date, bool isArabic) {
return DateFormat('HH:mm a', isArabic ? "ar_SA" : "en_US").format(date); return DateFormat('hh:mm a', isArabic ? "ar_SA" : "en_US").format(date);
} }
/// get data formatted like 26/4/2020 10:30 /// get data formatted like 26/4/2020 10:30

@ -7,4 +7,6 @@ class MyLottieConsts {
static const String marathonWaiting = "assets/lottie/marathon_waiting.json"; static const String marathonWaiting = "assets/lottie/marathon_waiting.json";
static const String wrongAnswerGif = "assets/images/wrong_answer.gif"; static const String wrongAnswerGif = "assets/images/wrong_answer.gif";
static const String congratsGif = "assets/images/congrats.gif"; static const String congratsGif = "assets/images/congrats.gif";
static const String loadingLottie = "assets/lottie/loading_lottie.json";
static const String noWinnerLottie = "assets/lottie/no_winner.json";
} }

@ -134,11 +134,22 @@ class Utils {
} }
} }
static void confirmDialog(cxt, String message) { static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message}) async {
return showDialog(
context: context,
builder: (BuildContext context) => ConfirmDialog(
message: message,
onTap: onOkTapped,
),
);
}
static void confirmDialog(cxt, String message, {VoidCallback? onTap}) {
showDialog( showDialog(
context: cxt, context: cxt,
builder: (cxt) => ConfirmDialog( builder: (BuildContext cxt) => ConfirmDialog(
message: message, message: message,
onTap: onTap,
), ),
); );
} }
@ -338,13 +349,13 @@ class Utils {
if (!Platform.isIOS) { if (!Platform.isIOS) {
await showCupertinoModalPopup( await showCupertinoModalPopup(
context: context, context: context,
builder: (cxt) => Container( builder: (BuildContext cxt) => Container(
height: 250, height: 250,
color: Colors.white, color: Colors.white,
child: CupertinoDatePicker( child: CupertinoDatePicker(
backgroundColor: Colors.white, backgroundColor: Colors.white,
mode: CupertinoDatePickerMode.date, mode: CupertinoDatePickerMode.date,
onDateTimeChanged: (value) { onDateTimeChanged: (DateTime value) {
if (value != null && value != selectedDate) { if (value != null && value != selectedDate) {
selectedDate = value; selectedDate = value;
} }
@ -364,7 +375,7 @@ class Utils {
static void readNFc({required Function(String) onRead}) { static void readNFc({required Function(String) onRead}) {
NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
var f; MifareUltralight f;
if (Platform.isAndroid) { if (Platform.isAndroid) {
f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22); f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
} else { } else {

@ -23,7 +23,6 @@ import 'package:mohem_flutter_app/ui/marathon/marathon_intro_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_screen.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_sponsor_video_screen.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_sponsor_video_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_waiting_screen.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_waiting_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/winner_screen.dart';
import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart'; import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart';
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart';
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart';
@ -299,7 +298,6 @@ class AppRoutes {
// Marathon // Marathon
marathonIntroScreen: (BuildContext context) => MarathonIntroScreen(), marathonIntroScreen: (BuildContext context) => MarathonIntroScreen(),
marathonScreen: (BuildContext context) => MarathonScreen(), marathonScreen: (BuildContext context) => MarathonScreen(),
marathonWinnerScreen: (BuildContext context) => WinnerScreen(),
marathonSponsorVideoScreen: (BuildContext context) => const SponsorVideoScreen(), marathonSponsorVideoScreen: (BuildContext context) => const SponsorVideoScreen(),
marathonWaitingScreen: (BuildContext context) => const MarathonWaitingScreen(), marathonWaitingScreen: (BuildContext context) => const MarathonWaitingScreen(),

@ -90,9 +90,9 @@ extension EmailValidator on String {
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.52, decoration: isUnderLine ? TextDecoration.underline : null), style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.52, decoration: isUnderLine ? TextDecoration.underline : null),
); );
Widget toText14({Color? color, bool isUnderLine = false, bool isBold = false, FontWeight? weight, int? maxlines, bool isCenter = false}) => Text( Widget toText14({Color? color, bool isUnderLine = false, bool isBold = false, FontWeight? weight, int? maxlines, TextAlign? textAlign, bool isCenter = false}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : TextAlign.left, textAlign: isCenter ? TextAlign.center : (textAlign ?? TextAlign.left),
maxLines: maxlines, maxLines: maxlines,
style: TextStyle( style: TextStyle(
color: color ?? MyColors.darkTextColor, color: color ?? MyColors.darkTextColor,
@ -131,8 +131,9 @@ extension EmailValidator on String {
style: TextStyle(fontSize: 19, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.14), style: TextStyle(fontSize: 19, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.14),
); );
Widget toText20({Color? color, bool isBold = false}) => Text( Widget toText20({Color? color, bool isBold = false, bool isCentered = false}) => Text(
this, this,
textAlign: isCentered ? TextAlign.center : null,
style: TextStyle(fontSize: 20, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4), style: TextStyle(fontSize: 20, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4),
); );

@ -444,11 +444,7 @@ class CodegenLoader extends AssetLoader{
"CorrectAddress": "تصحيح أو تعديل هذا العنوان", "CorrectAddress": "تصحيح أو تعديل هذا العنوان",
"SelectChangeWantToMake": " حدد نوع التغيير الذي تريد القيام به.", "SelectChangeWantToMake": " حدد نوع التغيير الذي تريد القيام به.",
"profile": { "profile": {
"reset_password": { "reset_password": {"label": "Reset Password", "username": "Username", "password": "password"},
"label": "Reset Password",
"username": "Username",
"password": "password"
},
"profileCompletionPer": "استكمال الملف الشخصي", "profileCompletionPer": "استكمال الملف الشخصي",
"completeProfile": "الملف الشخصي الكامل", "completeProfile": "الملف الشخصي الكامل",
"personalInformation": "معلومات شخصية", "personalInformation": "معلومات شخصية",
@ -470,10 +466,7 @@ class CodegenLoader extends AssetLoader{
"gender": { "gender": {
"male": "Hi man ;) ", "male": "Hi man ;) ",
"female": "Hello girl :)", "female": "Hello girl :)",
"with_arg": { "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"}
"male": "Hi man ;) {}",
"female": "Hello girl :) {}"
}
}, },
"reset_locale": "إعادة ضبط اللغة", "reset_locale": "إعادة ضبط اللغة",
"chat": "دردشة", "chat": "دردشة",
@ -530,7 +523,9 @@ class CodegenLoader extends AssetLoader{
"startingIn": "يبدأ في", "startingIn": "يبدأ في",
"youAreOutOfContest": "أنت خارج المسابقة.", "youAreOutOfContest": "أنت خارج المسابقة.",
"winners": "الفائزين!!!", "winners": "الفائزين!!!",
"fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية" "noUpcoming": "لا يوجد قادم",
"fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية",
"noWinner": "حزين! لم يفز أحد اليوم."
}; };
static const Map<String, dynamic> en_US = { static const Map<String, dynamic> en_US = {
"mohemm": "Mohemm", "mohemm": "Mohemm",
@ -962,11 +957,7 @@ static const Map<String,dynamic> en_US = {
"CorrectAddress": "Correct or amend this address", "CorrectAddress": "Correct or amend this address",
"SelectChangeWantToMake": "Select the type of change you want to make", "SelectChangeWantToMake": "Select the type of change you want to make",
"profile": { "profile": {
"reset_password": { "reset_password": {"label": "Reset Password", "username": "Username", "password": "password"},
"label": "Reset Password",
"username": "Username",
"password": "password"
},
"profileCompletionPer": "Profile Completion", "profileCompletionPer": "Profile Completion",
"completeProfile": "Complete Profile", "completeProfile": "Complete Profile",
"personalInformation": "Personal Information", "personalInformation": "Personal Information",
@ -988,10 +979,7 @@ static const Map<String,dynamic> en_US = {
"gender": { "gender": {
"male": "Hi man ;) ", "male": "Hi man ;) ",
"female": "Hello girl :)", "female": "Hello girl :)",
"with_arg": { "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"}
"male": "Hi man ;) {}",
"female": "Hello girl :) {}"
}
}, },
"reset_locale": "Reset Language", "reset_locale": "Reset Language",
"chat": "Chat", "chat": "Chat",
@ -1048,7 +1036,9 @@ static const Map<String,dynamic> en_US = {
"startingIn": "Starting in", "startingIn": "Starting in",
"youAreOutOfContest": "You are out of the contest.", "youAreOutOfContest": "You are out of the contest.",
"winners": "WINNERS!!!", "winners": "WINNERS!!!",
"fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified." "noUpcoming": "There is no upcoming",
"fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified.",
"noWinner": "Sad! No one won today."
}; };
static const Map<String, Map<String, dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; static const Map<String, Map<String, dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
} }

@ -500,6 +500,8 @@ abstract class LocaleKeys {
static const startingIn = 'startingIn'; static const startingIn = 'startingIn';
static const youAreOutOfContest = 'youAreOutOfContest'; static const youAreOutOfContest = 'youAreOutOfContest';
static const winners = 'winners'; static const winners = 'winners';
static const noUpcoming = 'noUpcoming';
static const fakeLocation = 'fakeLocation'; static const fakeLocation = 'fakeLocation';
static const noWinner = 'noWinner';
} }

@ -27,6 +27,7 @@ Logger logger = Logger(
// output: null, // U // output: null, // U
); );
class MyHttpOverrides extends HttpOverrides { class MyHttpOverrides extends HttpOverrides {
@override @override
HttpClient createHttpClient(SecurityContext? context) { HttpClient createHttpClient(SecurityContext? context) {

@ -1,7 +1,8 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:just_audio/just_audio.dart';
List<SingleUserChatModel> singleUserChatModelFromJson(String str) => List<SingleUserChatModel>.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); List<SingleUserChatModel> singleUserChatModelFromJson(String str) => List<SingleUserChatModel>.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x)));
@ -32,7 +33,9 @@ class SingleUserChatModel {
this.userChatReplyResponse, this.userChatReplyResponse,
this.isReplied, this.isReplied,
this.isImageLoaded, this.isImageLoaded,
this.image}); this.image,
this.voice,
this.voiceController});
int? userChatHistoryId; int? userChatHistoryId;
int? userChatHistoryLineId; int? userChatHistoryLineId;
@ -58,6 +61,8 @@ class SingleUserChatModel {
bool? isReplied; bool? isReplied;
bool? isImageLoaded; bool? isImageLoaded;
Uint8List? image; Uint8List? image;
File? voice;
AudioPlayer? voiceController;
factory SingleUserChatModel.fromJson(Map<String, dynamic> json) => SingleUserChatModel( factory SingleUserChatModel.fromJson(Map<String, dynamic> json) => SingleUserChatModel(
userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"], userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"],
@ -83,7 +88,9 @@ class SingleUserChatModel {
userChatReplyResponse: json["userChatReplyResponse"] == null ? null : UserChatReplyResponse.fromJson(json["userChatReplyResponse"]), userChatReplyResponse: json["userChatReplyResponse"] == null ? null : UserChatReplyResponse.fromJson(json["userChatReplyResponse"]),
isReplied: false, isReplied: false,
isImageLoaded: false, isImageLoaded: false,
image: null); image: null,
voice: null,
voiceController: json["fileTypeId"] == 13 ? AudioPlayer() : null);
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId,
@ -143,8 +150,8 @@ class FileTypeResponse {
} }
class UserChatReplyResponse { class UserChatReplyResponse {
UserChatReplyResponse({ UserChatReplyResponse(
this.userChatHistoryId, {this.userChatHistoryId,
this.chatEventId, this.chatEventId,
this.contant, this.contant,
this.contantNo, this.contantNo,
@ -155,7 +162,7 @@ class UserChatReplyResponse {
this.fileTypeResponse, this.fileTypeResponse,
this.isImageLoaded, this.isImageLoaded,
this.image, this.image,
}); this.voice});
int? userChatHistoryId; int? userChatHistoryId;
int? chatEventId; int? chatEventId;
@ -168,6 +175,7 @@ class UserChatReplyResponse {
FileTypeResponse? fileTypeResponse; FileTypeResponse? fileTypeResponse;
bool? isImageLoaded; bool? isImageLoaded;
Uint8List? image; Uint8List? image;
Uint8List? voice;
factory UserChatReplyResponse.fromJson(Map<String, dynamic> json) => UserChatReplyResponse( factory UserChatReplyResponse.fromJson(Map<String, dynamic> json) => UserChatReplyResponse(
userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"], userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"],
@ -180,7 +188,9 @@ class UserChatReplyResponse {
targetUserName: json["targetUserName"] == null ? null : json["targetUserName"], targetUserName: json["targetUserName"] == null ? null : json["targetUserName"],
fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]), fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]),
isImageLoaded: false, isImageLoaded: false,
image: null); image: null,
voice: null,
);
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId,

@ -16,9 +16,10 @@ class MarathonDetailModel {
List<Sponsors>? sponsors; List<Sponsors>? sponsors;
List<Questions>? questions; List<Questions>? questions;
int? totalQuestions; int? totalQuestions;
int? marathonBufferTime;
MarathonDetailModel( MarathonDetailModel({
{id, id,
titleEn, titleEn,
titleAr, titleAr,
descEn, descEn,
@ -34,7 +35,9 @@ class MarathonDetailModel {
projects, projects,
sponsors, sponsors,
questions, questions,
totalQuestions}); totalQuestions,
marathonBufferTime,
});
MarathonDetailModel.fromJson(Map<String, dynamic> json) { MarathonDetailModel.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
@ -50,9 +53,7 @@ class MarathonDetailModel {
marathoneStatusId = json['marathoneStatusId']; marathoneStatusId = json['marathoneStatusId'];
scheduleTime = json['scheduleTime']; scheduleTime = json['scheduleTime'];
selectedLanguage = json['selectedLanguage']; selectedLanguage = json['selectedLanguage'];
projects = json['projects'] != null projects = json['projects'] != null ? Projects.fromJson(json['projects']) : null;
? Projects.fromJson(json['projects'])
: null;
if (json['sponsors'] != null) { if (json['sponsors'] != null) {
sponsors = <Sponsors>[]; sponsors = <Sponsors>[];
json['sponsors'].forEach((v) { json['sponsors'].forEach((v) {
@ -66,6 +67,7 @@ class MarathonDetailModel {
}); });
} }
totalQuestions = json["totalQuestions"]; totalQuestions = json["totalQuestions"];
marathonBufferTime = json["marathonBufferTime"];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -93,6 +95,7 @@ class MarathonDetailModel {
data['questions'] = questions!.map((v) => v.toJson()).toList(); data['questions'] = questions!.map((v) => v.toJson()).toList();
} }
data['totalQuestions'] = totalQuestions; data['totalQuestions'] = totalQuestions;
data['marathonBufferTime'] = marathonBufferTime;
return data; return data;
} }
@ -132,14 +135,7 @@ class Sponsors {
String? logo; String? logo;
List<SponsorPrizes>? sponsorPrizes; List<SponsorPrizes>? sponsorPrizes;
Sponsors( Sponsors({id, nameEn, nameAr, image, video, logo, sponsorPrizes});
{id,
nameEn,
nameAr,
image,
video,
logo,
sponsorPrizes});
Sponsors.fromJson(Map<String, dynamic> json) { Sponsors.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
@ -165,8 +161,7 @@ class Sponsors {
data['video'] = video; data['video'] = video;
data['logo'] = logo; data['logo'] = logo;
if (sponsorPrizes != null) { if (sponsorPrizes != null) {
data['sponsorPrizes'] = data['sponsorPrizes'] = sponsorPrizes!.map((v) => v.toJson()).toList();
sponsorPrizes!.map((v) => v.toJson()).toList();
} }
return data; return data;
} }
@ -208,19 +203,7 @@ class Questions {
int? questOptionsLimit; int? questOptionsLimit;
List? questionOptions; List? questionOptions;
Questions( Questions({id, titleEn, titleAr, marathonId, questionTypeId, questionTime, nextQuestGap, gapType, gapValue, gapImage, questOptionsLimit, questionOptions});
{id,
titleEn,
titleAr,
marathonId,
questionTypeId,
questionTime,
nextQuestGap,
gapType,
gapValue,
gapImage,
questOptionsLimit,
questionOptions});
Questions.fromJson(Map<String, dynamic> json) { Questions.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];

@ -8,16 +8,16 @@ class UpdateUserTypesList {
UpdateUserTypesList.fromJson(Map<String, dynamic> json) { UpdateUserTypesList.fromJson(Map<String, dynamic> json) {
itemID = json['ItemID']; itemID = json['ItemID'];
pFYAENABLEDFALG = json['P_FYAENABLED_FALG']; pFYAENABLEDFALG = json['P_FYA_ENABLED_FALG'];
pFYIENABLEDFALG = json['P_FYIENABLED_FALG']; pFYIENABLEDFALG = json['P_FYI_ENABLED_FLAG'];
pITEMTYPE = json['P_ITEM_TYPE']; pITEMTYPE = json['P_ITEM_TYPE'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map<String, dynamic>(); Map<String, dynamic> data = new Map<String, dynamic>();
data['ItemID'] = this.itemID; data['ItemID'] = this.itemID;
data['P_FYAENABLED_FALG'] = this.pFYAENABLEDFALG; data['P_FYA_ENABLED_FALG'] = this.pFYAENABLEDFALG;
data['P_FYIENABLED_FALG'] = this.pFYIENABLEDFALG; data['P_FYI_ENABLED_FLAG'] = this.pFYIENABLEDFALG;
data['P_ITEM_TYPE'] = this.pITEMTYPE; data['P_ITEM_TYPE'] = this.pITEMTYPE;
return data; return data;
} }

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@ -9,9 +10,10 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:just_audio/just_audio.dart' as JustAudio; import 'package:just_audio/just_audio.dart' as JustAudio;
import 'package:just_audio/just_audio.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/api/my_team/my_team_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/app_permissions.dart';
import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/encryption.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';
@ -21,6 +23,7 @@ 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/get_user_login_token_model.dart' as userLoginToken; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as userLoginToken;
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;
import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/widgets/image_picker.dart'; import 'package:mohem_flutter_app/widgets/image_picker.dart';
import 'package:open_file/open_file.dart'; import 'package:open_file/open_file.dart';
@ -32,32 +35,42 @@ import 'package:uuid/uuid.dart';
class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
ScrollController scrollController = ScrollController(); ScrollController scrollController = ScrollController();
TextEditingController message = TextEditingController(); TextEditingController message = TextEditingController();
TextEditingController search = TextEditingController(); TextEditingController search = TextEditingController();
List<SingleUserChatModel> userChatHistory = []; List<SingleUserChatModel> userChatHistory = [], repliedMsg = [];
List<ChatUser>? pChatHistory, searchedChats; List<ChatUser>? pChatHistory, searchedChats;
String chatCID = ''; String chatCID = '';
bool isLoading = true; bool isLoading = true;
bool isChatScreenActive = false; bool isChatScreenActive = false;
int receiverID = 0; int receiverID = 0;
late File selectedFile; late File selectedFile;
bool isFileSelected = false;
String sFileType = ""; String sFileType = "";
bool isMsgReply = false;
List<SingleUserChatModel> repliedMsg = [];
List<ChatUser> favUsersList = []; List<ChatUser> favUsersList = [];
int paginationVal = 0; int paginationVal = 0;
bool currentUserTyping = false;
int? cTypingUserId = 0; int? cTypingUserId = 0;
bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false;
// Audio Recoding Work
Timer? _timer;
int _recodeDuration = 0;
bool isRecoding = false;
bool isPause = false;
bool isPlaying = false;
String? path;
String? musicFile;
late Directory appDirectory;
late RecorderController recorderController;
late PlayerController playerController;
List<GetEmployeeSubordinatesList> getEmployeeSubordinatesList = [];
List<ChatUser> teamMembersList = [];
//Chat Home Page Counter //Chat Home Page Counter
int chatUConvCounter = 0; int chatUConvCounter = 0;
Future<void> getUserAutoLoginToken() async { Future<void> getUserAutoLoginToken() async {
userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
print("======================================= Chat Login Token Check =====================================");
logger.d(userLoginResponse.toJson());
print("======================================= Chat Login Token Check =====================================");
if (userLoginResponse.response != null) { if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse; AppState().setchatUserDetails = userLoginResponse;
} else { } else {
@ -71,7 +84,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Future<void> buildHubConnection() async { Future<void> buildHubConnection() async {
chatHubConnection = await getHubConnection(); chatHubConnection = await getHubConnection();
await chatHubConnection.start(); await chatHubConnection.start();
print("Startedddddddd"); if (kDebugMode) {
logger.i("Hub Conn: Startedddddddd");
}
chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion);
} }
@ -88,12 +103,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void registerEvents() { void registerEvents() {
chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus);
// chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
// hubConnection.on("OnSeenChatUserAsync", onChatSeen); chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync);
chatHubConnection.on("OnUserTypingAsync", onUserTyping); chatHubConnection.on("OnUserTypingAsync", onUserTyping);
chatHubConnection.on("OnUserCountAsync", userCountAsync); chatHubConnection.on("OnUserCountAsync", userCountAsync);
// hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow);
chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
if (kDebugMode) {
logger.i("All listeners registered");
}
} }
void getUserRecentChats() async { void getUserRecentChats() async {
@ -110,9 +128,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
if (favUList.response != null && recentChat.response != null) { if (favUList.response != null && recentChat.response != null) {
favUsersList = favUList.response!; favUsersList = favUList.response!;
favUsersList.sort( favUsersList.sort(
(ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo( (ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase()),
b.userName!.toLowerCase(),
),
); );
for (dynamic user in recentChat.response!) { for (dynamic user in recentChat.response!) {
for (dynamic favUser in favUList.response!) { for (dynamic favUser in favUList.response!) {
@ -182,7 +198,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
void markRead(List<SingleUserChatModel> data, int receiverID) { void markRead(List<SingleUserChatModel> data, int receiverID) {
if (data != null) {
for (SingleUserChatModel element in data!) { for (SingleUserChatModel element in data!) {
if (AppState().chatDetails!.response!.id! == element.targetUserId) { if (AppState().chatDetails!.response!.id! == element.targetUserId) {
if (element.isSeen != null) { if (element.isSeen != null) {
@ -210,7 +225,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
notifyListeners(); notifyListeners();
} }
}
void updateUserChatHistoryStatusAsync(List data) { void updateUserChatHistoryStatusAsync(List data) {
try { try {
@ -233,16 +247,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Future<dynamic> uploadAttachments(String userId, File file) async { Future<dynamic> uploadAttachments(String userId, File file) async {
dynamic result; dynamic result;
try { try {
StreamedResponse response = await ChatApiClient().uploadMedia(userId, file); Object? response = await ChatApiClient().uploadMedia(userId, file);
if (response.statusCode == 200) { if (response != null) {
result = jsonDecode(await response.stream.bytesToString()); result = response;
} else { } else {
result = []; result = [];
} }
} catch (e) { } catch (e) {
throw e; throw e;
} }
return result; return result;
} }
@ -284,7 +297,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void updateChatHistoryWindow(List<Object?>? args) { void updateChatHistoryWindow(List<Object?>? args) {
dynamic items = args!.toList(); dynamic items = args!.toList();
print("---------------------------------Update Chat History Windows Async -------------------------------------"); if (kDebugMode) {
logger.i("---------------------------------Update Chat History Windows Async -------------------------------------");
}
logger.d(items); 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"]) {
@ -368,6 +383,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
ChatUser( ChatUser(
id: data.first.currentUserId, id: data.first.currentUserId,
userName: data.first.currentUserName, userName: data.first.currentUserName,
email: data.first.currentUserEmail,
unreadMessageCount: 0, unreadMessageCount: 0,
isImageLoading: false, isImageLoading: false,
image: chatImages!.first.profilePicture ?? "", image: chatImages!.first.profilePicture ?? "",
@ -407,6 +423,31 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
notifyListeners(); notifyListeners();
} }
void OnSubmitChatAsync(List<Object?>? parameters) {
print(isChatScreenActive);
print(receiverID);
print(isChatScreenActive);
logger.i(parameters);
List<SingleUserChatModel> data = [], temp = [];
for (dynamic msg in parameters!) {
data = getSingleUserChatModel(jsonEncode(msg));
temp = getSingleUserChatModel(jsonEncode(msg));
data.first.targetUserId = temp.first.currentUserId;
data.first.targetUserName = temp.first.currentUserName;
data.first.targetUserEmail = temp.first.currentUserEmail;
data.first.currentUserId = temp.first.targetUserId;
data.first.currentUserName = temp.first.targetUserName;
data.first.currentUserEmail = temp.first.targetUserEmail;
}
if (isChatScreenActive && data.first.currentUserId == receiverID) {
int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0);
logger.d(index);
userChatHistory[index] = data.first;
}
notifyListeners();
}
void sort() { void sort() {
searchedChats!.sort( searchedChats!.sort(
(ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!),
@ -457,6 +498,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return 2; return 2;
case ".rar": case ".rar":
return 2; return 2;
case ".aac":
return 13;
case ".mp3":
return 14;
default: default:
return 0; return 0;
} }
@ -490,6 +535,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return "application/octet-stream"; return "application/octet-stream";
case ".rar": case ".rar":
return "application/octet-stream"; return "application/octet-stream";
case ".aac":
return "audio/aac";
case ".mp3":
return "audio/mp3";
default: default:
return ""; return "";
} }
@ -504,11 +553,22 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
required bool isAttachment, required bool isAttachment,
required bool isReply, required bool isReply,
Uint8List? image, Uint8List? image,
required bool isImageLoaded}) async { required bool isImageLoaded,
String? userEmail,
int? userStatus,
File? voiceFile,
required bool isVoiceAttached}) async {
Uuid uuid = const Uuid(); Uuid uuid = const Uuid();
String contentNo = uuid.v4(); String contentNo = uuid.v4();
String msg = message.text; String msg;
if (isVoiceAttached) {
msg = voiceFile!.path.split("/").last;
} else {
msg = message.text;
logger.w(msg);
}
SingleUserChatModel data = SingleUserChatModel( SingleUserChatModel data = SingleUserChatModel(
userChatHistoryId: 0,
chatEventId: chatEventId, chatEventId: chatEventId,
chatSource: 1, chatSource: 1,
contant: msg, contant: msg,
@ -525,18 +585,24 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
fileTypeResponse: isAttachment fileTypeResponse: isAttachment
? FileTypeResponse( ? FileTypeResponse(
fileTypeId: fileTypeId, fileTypeId: fileTypeId,
fileTypeName: getFileExtension(selectedFile.path).toString(), fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(),
fileKind: "file", fileKind: "file",
fileName: selectedFile.path.split("/").last, fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last,
fileTypeDescription: getFileTypeDescription(getFileExtension(selectedFile.path).toString()), fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()),
) )
: null, : null,
image: image, image: image,
isImageLoaded: isImageLoaded, isImageLoaded: isImageLoaded,
); voice: isVoiceMsg ? voiceFile! : null,
voiceController: isVoiceMsg ? AudioPlayer() : null);
if (kDebugMode) {
logger.i("model data: " + jsonEncode(data));
}
userChatHistory.insert(0, data); userChatHistory.insert(0, data);
isFileSelected = false; isTextMsg = false;
isMsgReply = false; isReplyMsg = false;
isAttachmentMsg = false;
isVoiceMsg = false;
sFileType = ""; sFileType = "";
message.clear(); message.clear();
notifyListeners(); notifyListeners();
@ -547,35 +613,35 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
void sendChatMessage(BuildContext context, {required int targetUserId, required int userStatus, required String userEmail, required String targetUserName}) async { void sendChatMessage(BuildContext context, {required int targetUserId, required int userStatus, required String userEmail, required String targetUserName}) async {
if (!isFileSelected && !isMsgReply) { if (kDebugMode) {
print("Normal Text Msg"); print("====================== Values ============================");
if (message.text == null || message.text.isEmpty) { print("Is Text " + isTextMsg.toString());
print("isReply " + isReplyMsg.toString());
print("isAttachment " + isAttachmentMsg.toString());
print("isVoice " + isVoiceMsg.toString());
}
//Text
if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) {
logger.d("// Normal Text Message");
if (message.text.isEmpty) {
return; return;
} }
sendChatToServer( sendChatToServer(
chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: false, chatReplyId: null, isReply: false, isImageLoaded: false, image: null); chatEventId: 1,
} // normal Text msg fileTypeId: null,
if (isFileSelected && !isMsgReply) {
bool isImage = false;
print("Normal Attachment Msg");
Utils.showLoading(context);
dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile);
String? ext = getFileExtension(selectedFile.path);
Utils.hideLoading(context);
sendChatToServer(
chatEventId: 2,
fileTypeId: getFileType(ext.toString()),
targetUserId: targetUserId, targetUserId: targetUserId,
targetUserName: targetUserName, targetUserName: targetUserName,
isAttachment: true, isAttachment: false,
chatReplyId: null, chatReplyId: null,
isReply: false, isReply: false,
isImageLoaded: true, isImageLoaded: false,
image: selectedFile.readAsBytesSync()); image: null,
} // normal attachemnt msg isVoiceAttached: false,
if (!isFileSelected && isMsgReply) { userEmail: userEmail,
print("Normal Text To Text Reply"); userStatus: userStatus);
if (message.text == null || message.text.isEmpty) { } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) {
logger.d("// Text Message as Reply");
if (message.text.isEmpty) {
return; return;
} }
sendChatToServer( sendChatToServer(
@ -587,10 +653,34 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isAttachment: false, isAttachment: false,
isReply: true, isReply: true,
isImageLoaded: repliedMsg.first.isImageLoaded!, isImageLoaded: repliedMsg.first.isImageLoaded!,
image: repliedMsg.first.image); image: repliedMsg.first.image,
} // reply msg over image && normal isVoiceAttached: false,
if (isFileSelected && isMsgReply) { voiceFile: null,
print("Reply With File"); userEmail: userEmail,
userStatus: userStatus);
}
// Attachment
else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) {
logger.d("// Normal Image Message");
Utils.showLoading(context);
dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile);
String? ext = getFileExtension(selectedFile.path);
Utils.hideLoading(context);
sendChatToServer(
chatEventId: 2,
fileTypeId: getFileType(ext.toString()),
targetUserId: targetUserId,
targetUserName: targetUserName,
isAttachment: true,
chatReplyId: null,
isReply: false,
isImageLoaded: true,
image: selectedFile.readAsBytesSync(),
isVoiceAttached: false,
userEmail: userEmail,
userStatus: userStatus);
} else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) {
logger.d("// Image as Reply 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);
String? ext = getFileExtension(selectedFile.path); String? ext = getFileExtension(selectedFile.path);
@ -604,9 +694,81 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
chatReplyId: repliedMsg.first.userChatHistoryId, chatReplyId: repliedMsg.first.userChatHistoryId,
isReply: true, isReply: true,
isImageLoaded: true, isImageLoaded: true,
image: selectedFile.readAsBytesSync()); image: selectedFile.readAsBytesSync(),
isVoiceAttached: false,
userEmail: userEmail,
userStatus: userStatus);
} }
//Voice
else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) {
logger.d("// Normal Voice Message");
if (!isPause) {
path = await recorderController.stop(false);
}
if (kDebugMode) {
logger.i("path:" + path!);
}
File voiceFile = File(path!);
voiceFile.readAsBytesSync();
_timer?.cancel();
isPause = false;
isPlaying = false;
isRecoding = false;
Utils.showLoading(context);
dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile);
String? ext = getFileExtension(voiceFile.path);
Utils.hideLoading(context);
sendChatToServer(
chatEventId: 2,
fileTypeId: getFileType(ext.toString()),
targetUserId: targetUserId,
targetUserName: targetUserName,
chatReplyId: null,
isAttachment: true,
isReply: isReplyMsg,
isImageLoaded: false,
voiceFile: voiceFile,
isVoiceAttached: true,
userEmail: userEmail,
userStatus: userStatus);
notifyListeners();
} else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) {
logger.d("// Voice as Reply Msg");
if (!isPause) {
path = await recorderController.stop(false);
}
if (kDebugMode) {
logger.i("path:" + path!);
}
File voiceFile = File(path!);
voiceFile.readAsBytesSync();
_timer?.cancel();
isPause = false;
isPlaying = false;
isRecoding = false;
Utils.showLoading(context);
dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile);
String? ext = getFileExtension(voiceFile.path);
Utils.hideLoading(context);
sendChatToServer(
chatEventId: 2,
fileTypeId: getFileType(ext.toString()),
targetUserId: targetUserId,
targetUserName: targetUserName,
chatReplyId: null,
isAttachment: true,
isReply: isReplyMsg,
isImageLoaded: false,
voiceFile: voiceFile,
isVoiceAttached: true,
userEmail: userEmail,
userStatus: userStatus);
notifyListeners();
}
if (searchedChats != null) { if (searchedChats != null) {
dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId);
if (contain.isEmpty) { if (contain.isEmpty) {
@ -630,34 +792,36 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
); );
notifyListeners(); notifyListeners();
} }
} else {
List<String> emails = [];
emails.add(await EmailImageEncryption().encrypt(val: userEmail));
List<ChatUserImageModel> chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails);
searchedChats!.add(
ChatUser(
id: targetUserId,
userName: targetUserName,
unreadMessageCount: 0,
email: userEmail,
isImageLoading: false,
image: chatImages.first.profilePicture ?? "",
isImageLoaded: true,
isTyping: false,
isFav: false,
userStatus: userStatus,
userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()),
),
);
notifyListeners();
} }
// else {
// List<String> emails = [];
// emails.add(await EmailImageEncryption().encrypt(val: userEmail));
// List<ChatUserImageModel> chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails);
// searchedChats!.add(
// ChatUser(
// id: targetUserId,
// userName: targetUserName,
// unreadMessageCount: 0,
// email: userEmail,
// isImageLoading: false,
// image: chatImages.first.profilePicture ?? "",
// isImageLoaded: true,
// isTyping: false,
// isFav: false,
// userStatus: userStatus,
// userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()),
// ),
// );
// notifyListeners();
// }
} }
void selectImageToUpload(BuildContext context) { void selectImageToUpload(BuildContext context) {
ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { ImageOptions.showImageOptionsNew(context, true, (String image, File file) async {
if (checkFileSize(file.path)) { if (checkFileSize(file.path)) {
selectedFile = file; selectedFile = file;
isFileSelected = true; isAttachmentMsg = true;
isTextMsg = false;
sFileType = getFileExtension(file.path)!; sFileType = getFileExtension(file.path)!;
message.text = file.path.split("/").last; message.text = file.path.split("/").last;
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -669,7 +833,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
void removeAttachment() { void removeAttachment() {
isFileSelected = false; isAttachmentMsg = false;
sFileType = ""; sFileType = "";
message.text = ''; message.text = '';
notifyListeners(); notifyListeners();
@ -677,7 +841,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
String? getFileExtension(String fileName) { String? getFileExtension(String fileName) {
try { try {
print("Ext: " + "." + fileName.split('.').last); if (kDebugMode) {
logger.i("ext: " + "." + fileName.split('.').last);
}
return "." + fileName.split('.').last; return "." + fileName.split('.').last;
} catch (e) { } catch (e) {
return null; return null;
@ -724,6 +890,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return "assets/icons/chat/zip.svg"; return "assets/icons/chat/zip.svg";
case ".rar": case ".rar":
return "assets/icons/chat/zip.svg"; return "assets/icons/chat/zip.svg";
case ".aac":
return "assets/icons/chat/aac.svg";
case ".mp3":
return "assets/icons/chat/zip.mp3";
default: default:
return "assets/images/thumb.svg"; return "assets/images/thumb.svg";
} }
@ -732,14 +902,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void chatReply(SingleUserChatModel data) { void chatReply(SingleUserChatModel data) {
repliedMsg = []; repliedMsg = [];
data.isReplied = true; data.isReplied = true;
isMsgReply = true; isReplyMsg = true;
repliedMsg.add(data); repliedMsg.add(data);
notifyListeners(); notifyListeners();
} }
void closeMe() { void closeMe() {
repliedMsg = []; repliedMsg = [];
isMsgReply = false; isReplyMsg = false;
notifyListeners(); notifyListeners();
} }
@ -789,22 +959,26 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
receiverID = 0; receiverID = 0;
paginationVal = 0; paginationVal = 0;
message.text = ''; message.text = '';
isFileSelected = false; isAttachmentMsg = false;
repliedMsg = []; repliedMsg = [];
sFileType = ""; sFileType = "";
isMsgReply = false; isReplyMsg = false;
isTextMsg = false;
isVoiceMsg = false;
notifyListeners(); notifyListeners();
} }
void clearAll() { void clearAll() {
print("----------------- Disposed ---------------------------");
searchedChats = pChatHistory; searchedChats = pChatHistory;
search.clear(); search.clear();
isChatScreenActive = false; isChatScreenActive = false;
receiverID = 0; receiverID = 0;
paginationVal = 0; paginationVal = 0;
message.text = ''; message.text = '';
isFileSelected = false; isTextMsg = false;
isAttachmentMsg = false;
isVoiceMsg = false;
isReplyMsg = false;
repliedMsg = []; repliedMsg = [];
sFileType = ""; sFileType = "";
} }
@ -815,13 +989,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
receiverID = 0; receiverID = 0;
paginationVal = 0; paginationVal = 0;
message.text = ''; message.text = '';
isFileSelected = false; isTextMsg = false;
isAttachmentMsg = false;
isVoiceMsg = false;
isReplyMsg = false;
repliedMsg = []; repliedMsg = [];
sFileType = ""; sFileType = "";
deleteData(); deleteData();
favUsersList.clear(); favUsersList.clear();
searchedChats!.clear(); searchedChats?.clear();
pChatHistory!.clear(); pChatHistory?.clear();
chatHubConnection.stop(); chatHubConnection.stop();
AppState().chatDetails = null; AppState().chatDetails = null;
} }
@ -886,8 +1063,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} else { } else {
await deleteFile(userID); await deleteFile(userID);
Uint8List decodedBytes = base64Decode(encodedBytes); Uint8List decodedBytes = base64Decode(encodedBytes);
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1 Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
late File imageFile = File("${appDocumentsDirectory.path}/$userID.jpg"); String dirPath = '${appDocumentsDirectory.path}/chat_images';
if (!await Directory(dirPath).exists()) {
await Directory(dirPath).create();
await File('$dirPath/.nomedia').create();
}
late File imageFile = File("$dirPath/$userID.jpg");
imageFile.writeAsBytesSync(decodedBytes); imageFile.writeAsBytesSync(decodedBytes);
return imageFile; return imageFile;
} }
@ -895,7 +1077,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Future deleteFile(String userID) async { Future deleteFile(String userID) async {
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
late File imageFile = File('${appDocumentsDirectory.path}/$userID.jpg'); String dirPath = '${appDocumentsDirectory.path}/chat_images';
late File imageFile = File('$dirPath/$userID.jpg');
if (await imageFile.exists()) { if (await imageFile.exists()) {
await imageFile.delete(); await imageFile.delete();
} }
@ -952,33 +1135,30 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
void userTypingInvoke({required int currentUser, required int reciptUser}) async { void userTypingInvoke({required int currentUser, required int reciptUser}) async {
logger.d([reciptUser, currentUser]);
await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]);
} }
// Audio Recoding Work
Timer? _timer;
int _recodeDuration = 0;
bool isRecoding = false;
bool isPause = false;
bool isPlaying = false;
String? path;
String? musicFile;
late Directory appDirectory;
late RecorderController recorderController;
late PlayerController playerController;
//////// Audio Recoding Work //////////////////// //////// Audio Recoding Work ////////////////////
Future<void> initAudio() async { Future<void> initAudio({required int receiverId}) async {
// final dir = Directory((Platform.isAndroid
// ? await getExternalStorageDirectory() //FOR ANDROID
// : await getApplicationSupportDirectory() //FOR IOS
// )!
appDirectory = await getApplicationDocumentsDirectory(); appDirectory = await getApplicationDocumentsDirectory();
path = "${appDirectory.path}/${AppState().chatDetails!.response!.id}-${DateTime.now().microsecondsSinceEpoch}.aac"; String dirPath = '${appDirectory.path}/chat_audios';
if (!await Directory(dirPath).exists()) {
await Directory(dirPath).create();
await File('$dirPath/.nomedia').create();
}
path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac";
recorderController = RecorderController() recorderController = RecorderController()
..androidEncoder = AndroidEncoder.aac ..androidEncoder = AndroidEncoder.aac
..androidOutputFormat = AndroidOutputFormat.mpeg4 ..androidOutputFormat = AndroidOutputFormat.mpeg4
..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC
..sampleRate = 8000 ..sampleRate = 6000
..bitRate = 32000; ..updateFrequency = const Duration(milliseconds: 100)
..bitRate = 18000;
playerController = PlayerController(); playerController = PlayerController();
} }
@ -986,16 +1166,17 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isRecoding = false; isRecoding = false;
isPlaying = false; isPlaying = false;
isPause = false; isPause = false;
isVoiceMsg = false;
recorderController.dispose(); recorderController.dispose();
playerController.dispose(); playerController.dispose();
} }
void startRecoding() async { void startRecoding() async {
PermissionStatus status = await Permission.microphone.request(); PermissionStatus status = await Permission.microphone.request();
print(status);
if (status.isDenied == true) { if (status.isDenied == true) {
startRecoding(); startRecoding();
} else { } else {
isVoiceMsg = true;
recorderController.reset(); recorderController.reset();
await recorderController.record(path); await recorderController.record(path);
_recodeDuration = 0; _recodeDuration = 0;
@ -1005,13 +1186,21 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
} }
void _startTimer() { Future<void> _startTimer() async {
_timer?.cancel(); _timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (Timer t) { _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async {
_recodeDuration++; _recodeDuration++;
if (_recodeDuration <= 59) {
applyCounter();
} else {
pauseRecoding();
}
});
}
void applyCounter() {
buildTimer(); buildTimer();
notifyListeners(); notifyListeners();
});
} }
Future<void> pauseRecoding() async { Future<void> pauseRecoding() async {
@ -1019,44 +1208,38 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isPlaying = true; isPlaying = true;
recorderController.pause(); recorderController.pause();
path = await recorderController.stop(false); path = await recorderController.stop(false);
print(path);
File file = File(path!); File file = File(path!);
file.readAsBytesSync(); file.readAsBytesSync();
path = file.path;
await playerController.preparePlayer(file.path, 1.0); await playerController.preparePlayer(file.path, 1.0);
var tempDuration = _recodeDuration;
_recodeDuration = tempDuration;
_timer?.cancel(); _timer?.cancel();
notifyListeners(); notifyListeners();
} }
void resumeRecoding() {
isPause = false;
isPlaying = false;
isRecoding = true;
recorderController.record(path);
_startTimer();
}
Future<void> deleteRecoding() async { Future<void> deleteRecoding() async {
print(path);
_recodeDuration = 0; _recodeDuration = 0;
_timer?.cancel(); _timer?.cancel();
// path = await recorderController.stop(false); if (path == null) {
recorderController.reset(); path = await recorderController.stop(true);
print(path); } else {
await recorderController.stop(true);
}
if (path != null && path!.isNotEmpty) { if (path != null && path!.isNotEmpty) {
File delFile = File(path!); File delFile = File(path!);
double fileSizeInKB = delFile.lengthSync() / 1024; double fileSizeInKB = delFile.lengthSync() / 1024;
double fileSizeInMB = fileSizeInKB / 1024; double fileSizeInMB = fileSizeInKB / 1024;
if (kDebugMode) {
debugPrint("Deleted file size: ${delFile.lengthSync()}"); debugPrint("Deleted file size: ${delFile.lengthSync()}");
debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); debugPrint("Deleted file size in KB: " + fileSizeInKB.toString());
debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); debugPrint("Deleted file size in MB: " + fileSizeInMB.toString());
}
if (await delFile.exists()) { if (await delFile.exists()) {
delFile.delete(); delFile.delete();
} }
isPause = false; isPause = false;
isRecoding = false; isRecoding = false;
isPlaying = false; isPlaying = false;
isVoiceMsg = false;
notifyListeners(); notifyListeners();
} }
} }
@ -1075,13 +1258,81 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return numberStr; return numberStr;
} }
void playRecoding() async { Future<String> downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async {
isPlaying = true; String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios';
await playerController.startPlayer(finishMode: FinishMode.stop); if (!await Directory(dirPath).exists()) {
await Directory(dirPath).create();
await File('$dirPath/.nomedia').create();
}
File file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext);
await file.writeAsBytes(bytes);
return file.path;
} }
void playOrPause() async { void scrollToMsg(SingleUserChatModel data) {
playerController.playerState == PlayerState.playing ? await playerController.pausePlayer() : playRecoding(); if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) {
int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId);
if (index >= 1) {
double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent;
double target = contentSize * index / userChatHistory.length;
scrollController.position.animateTo(
target,
duration: const Duration(seconds: 1),
curve: Curves.easeInOut,
);
}
}
}
Future<void> getTeamMembers() async {
teamMembersList = [];
isLoading = true;
if (AppState().getemployeeSubordinatesList.isNotEmpty) {
print("=============== In App State =====================");
getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList;
for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) {
print(element.eMPLOYEEEMAILADDRESS);
teamMembersList.add(
ChatUser(
id: int.parse(element.eMPLOYEENUMBER!),
email: element.eMPLOYEEEMAILADDRESS,
userName: element.eMPLOYEENAME,
phone: element.eMPLOYEEMOBILENUMBER,
userStatus: 0,
unreadMessageCount: 0,
isFav: false,
isTyping: false,
isImageLoading: false,
image: element.eMPLOYEEIMAGE ?? "",
isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true,
userLocalDownlaodedImage:element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!),
),
);
}
} else {
getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", "");
AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList;
for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) {
print(element.eMPLOYEEEMAILADDRESS);
teamMembersList.add(
ChatUser(
id: int.parse(element.eMPLOYEENUMBER!),
email: element.eMPLOYEEEMAILADDRESS,
userName: element.eMPLOYEENAME,
phone: element.eMPLOYEEMOBILENUMBER,
userStatus: 0,
unreadMessageCount: 0,
isFav: false,
isTyping: false,
isImageLoading: false,
image: element.eMPLOYEEIMAGE ?? "",
isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true,
userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!),
),
);
}
}
isLoading = false;
notifyListeners(); notifyListeners();
} }
} }

@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/api/offers_and_discounts_api_client.dart'; import 'package:mohem_flutter_app/api/offers_and_discounts_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart'; 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/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
@ -35,8 +36,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
bool isWorkListLoading = true; bool isWorkListLoading = true;
int workListCounter = 0; int workListCounter = 0;
//Misssing Swipe //Misssing Swipe
bool isMissingSwipeLoading = true; bool isMissingSwipeLoading = true;
int missingSwipeCounter = 0; int missingSwipeCounter = 0;
@ -94,7 +93,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
accrualList = null; accrualList = null;
leaveBalanceAccrual = null; leaveBalanceAccrual = null;
ticketBalance = 0; ticketBalance = 0;
isServicesMenusLoading = true; isServicesMenusLoading = true;
homeMenus = null; homeMenus = null;
@ -107,7 +105,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation), DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation),
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi), DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi),
DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions), DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions),
DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen), // DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen),
DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword), DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword),
]; ];
@ -215,6 +213,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
List findMyTeam = menuList.where((element) => element.menuType == "M").toList(); List findMyTeam = menuList.where((element) => element.menuType == "M").toList();
if (findMyTeam.isNotEmpty) { if (findMyTeam.isNotEmpty) {
AppState().setempStatusIsManager = true;
drawerMenuItemList.insert(2, DrawerMenuItem("assets/images/drawer/my_team.svg", LocaleKeys.myTeamMembers.tr(), AppRoutes.myTeam)); drawerMenuItemList.insert(2, DrawerMenuItem("assets/images/drawer/my_team.svg", LocaleKeys.myTeamMembers.tr(), AppRoutes.myTeam));
} }
} catch (ex) { } catch (ex) {

@ -85,8 +85,8 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Map<String, double> dataMap = { Map<String, double> dataMap = {
"Present": getTimeCardSummaryList?.aTTENDEDDAYS?.toDouble() ?? 75, "Present": getTimeCardSummaryList?.aTTENDEDDAYS?.toDouble() ?? 0,
"Absent": getTimeCardSummaryList?.aBSENTDAYS?.toDouble() ?? 25, "Absent": getTimeCardSummaryList?.aBSENTDAYS?.toDouble() ?? 0,
}; };
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
@ -112,7 +112,8 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
], ],
).onPress(() async { ).onPress(() async {
showMonthPicker( showMonthPicker(
context: context, //locale: EasyLocalization.of(context)?.locale, context: context,
//locale: EasyLocalization.of(context)?.locale,
initialDate: formattedDate, initialDate: formattedDate,
firstDate: DateTime(searchYear - 2), firstDate: DateTime(searchYear - 2),
lastDate: DateTime.now(), lastDate: DateTime.now(),
@ -419,8 +420,8 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
} }
if (details.date!.month == formattedDate.month && details.date!.year == formattedDate.year) { if (details.date!.month == formattedDate.month && details.date!.year == formattedDate.year) {
int val = details.date!.day; int val = details.date!.day;
getDayHoursTypeDetailsList?[val - 1].aTTENDEDFLAG == 'Y' ? getDayHoursTypeDetailsList?[val - 1].aTTENDEDFLAG == 'Y'
showModalBottomSheet( ? showModalBottomSheet(
context: context, context: context,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
isScrollControlled: true, isScrollControlled: true,
@ -447,8 +448,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
child: ListView.builder( child: ListView.builder(
controller: controller, controller: controller,
itemCount: 1, itemCount: 1,
itemBuilder: (_, i) => itemBuilder: (_, i) => Container(
Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
borderRadius: BorderRadius.vertical( borderRadius: BorderRadius.vertical(
top: Radius.circular(25.0), top: Radius.circular(25.0),
@ -623,7 +623,8 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
}, },
); );
}, },
):null; )
: null;
} }
} }

@ -1,10 +1,10 @@
import 'dart:convert'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:just_audio/just_audio.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/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
@ -12,30 +12,37 @@ import 'package:mohem_flutter_app/classes/utils.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/main.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/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart'; import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/ui/chat/common.dart';
import 'package:open_file/open_file.dart'; import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';
// todo: @aamir use extension methods, and use correct widgets.
class ChatBubble extends StatelessWidget { class ChatBubble extends StatelessWidget {
ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key); ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key);
final String dateTime; final String dateTime;
final SingleUserChatModel cItem; final SingleUserChatModel cItem;
bool isCurrentUser = false; bool isCurrentUser = false;
bool isSeen = false; bool isSeen = false;
bool isReplied = false; bool isReplied = false;
int? fileTypeID; int? fileTypeID;
String? fileTypeName; String? fileTypeName;
late ChatProviderModel data;
late ChatProviderModel provider;
String? fileTypeDescription; String? fileTypeDescription;
bool isDelivered = false; bool isDelivered = false;
String userName = ''; String userName = '';
late Offset screenOffset; late Offset screenOffset;
void makeAssign() { void makeAssign() {
@ -49,12 +56,58 @@ class ChatBubble extends StatelessWidget {
userName = AppState().chatDetails!.response!.userName == cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString(); userName = AppState().chatDetails!.response!.userName == cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString();
} }
void playVoice(
BuildContext context, {
required SingleUserChatModel data,
}) async {
if (data.voice != null && data.voice!.existsSync()) {
await data.voiceController!.setFilePath(data!.voice!.path);
await data.voiceController!.setLoopMode(LoopMode.off);
Duration? duration = await data.voiceController!.load();
await data.voiceController!.seek(duration);
await data.voiceController!.play();
} else {
Utils.showLoading(context);
Uint8List encodedString = await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? ""));
try {
String path = await provider.downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data);
File file = File(path!);
await file.readAsBytes();
data.voice = file;
Duration? duration = await data.voiceController!.setFilePath(file.path);
await data.voiceController!.setLoopMode(LoopMode.off);
await data.voiceController!.seek(duration);
await data.voiceController!.setVolume(1.0);
await data.voiceController!.load();
Utils.hideLoading(context);
await data.voiceController!.play();
} catch (e) {
Utils.hideLoading(context);
Utils.showToast(e.toString());
}
}
}
void pausePlaying(BuildContext context, {required SingleUserChatModel data}) async {
await data.voiceController!.pause();
}
void rePlay(BuildContext context, {required SingleUserChatModel data}) async {
if (data.voice != null && data.voice!.existsSync()) {
await data.voiceController!.seek(Duration.zero);
await data.voiceController!.play();
}
}
Stream<PositionData> get _positionDataStream => Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(cItem.voiceController!.positionStream, cItem.voiceController!.bufferedPositionStream,
cItem.voiceController!.durationStream, (Duration position, Duration bufferedPosition, Duration? duration) => PositionData(position, bufferedPosition, duration ?? Duration.zero));
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Size windowSize = MediaQuery.of(context).size; Size windowSize = MediaQuery.of(context).size;
screenOffset = Offset(windowSize.width / 2, windowSize.height / 2); screenOffset = Offset(windowSize.width / 2, windowSize.height / 2);
makeAssign(); makeAssign();
data = Provider.of<ChatProviderModel>(context, listen: false); provider = Provider.of<ChatProviderModel>(context, listen: false);
return isCurrentUser ? currentUser(context) : receiptUser(context); return isCurrentUser ? currentUser(context) : receiptUser(context);
} }
@ -84,25 +137,24 @@ class ChatBubble extends StatelessWidget {
.paddingOnly(right: 5, top: 5, bottom: 8, left: 5), .paddingOnly(right: 5, top: 5, bottom: 8, left: 5),
], ],
).expanded, ).expanded,
if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 || if (cItem.userChatReplyResponse != null)
cItem.userChatReplyResponse!.fileTypeId == 3 || if (cItem.userChatReplyResponse!.fileTypeId == 12 || cItem.userChatReplyResponse!.fileTypeId == 3 || cItem.userChatReplyResponse!.fileTypeId == 4)
cItem.userChatReplyResponse!.fileTypeId == 4)
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: false,
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(bottom: 7), ).paddingOnly(bottom: 7).onPress(() {
provider.scrollToMsg(cItem);
}),
if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3) if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3)
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(5.0), borderRadius: BorderRadius.circular(5.0),
@ -117,18 +169,21 @@ class ChatBubble extends StatelessWidget {
); );
}), }),
), ),
).paddingOnly(bottom: 4) ).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
currentWaveBubble(context, cItem)
else else
Row( Row(
children: [ children: [
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
// || fileTypeID == 2 // || fileTypeID == 2
) )
SvgPicture.asset(data.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10), SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
(cItem.contant ?? "").toText12().expanded, (cItem.contant ?? "").toText12().expanded,
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
//|| fileTypeID == 2 //|| fileTypeID == 2
) const Icon(Icons.remove_red_eye, size: 16) )
const Icon(Icons.remove_red_eye, size: 16)
], ],
), ),
Align( Align(
@ -157,10 +212,7 @@ class ChatBubble extends StatelessWidget {
transform: GradientRotation(.83), transform: GradientRotation(.83),
begin: Alignment.topRight, begin: Alignment.topRight,
end: Alignment.bottomLeft, end: Alignment.bottomLeft,
colors: <Color>[ colors: <Color>[MyColors.gradiantEndColor, MyColors.gradiantStartColor],
MyColors.gradiantEndColor,
MyColors.gradiantStartColor,
],
), ),
), ),
child: Column( child: Column(
@ -186,9 +238,8 @@ class ChatBubble extends StatelessWidget {
.paddingOnly(right: 5, top: 5, bottom: 8, left: 5), .paddingOnly(right: 5, top: 5, bottom: 8, left: 5),
], ],
).expanded, ).expanded,
if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 || if (cItem.userChatReplyResponse != null)
cItem.userChatReplyResponse!.fileTypeId == 3 || if (cItem.userChatReplyResponse!.fileTypeId == 12 || cItem.userChatReplyResponse!.fileTypeId == 3 || cItem.userChatReplyResponse!.fileTypeId == 4)
cItem.userChatReplyResponse!.fileTypeId == 4)
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
child: SizedBox( child: SizedBox(
@ -203,7 +254,9 @@ class ChatBubble extends StatelessWidget {
], ],
), ),
), ),
).paddingOnly(bottom: 7), ).paddingOnly(bottom: 7).onPress(() {
provider.scrollToMsg(cItem);
}),
if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3) if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3)
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(5.0), borderRadius: BorderRadius.circular(5.0),
@ -218,14 +271,16 @@ class ChatBubble extends StatelessWidget {
); );
}), }),
), ),
).paddingOnly(bottom: 4) ).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
recipetWaveBubble(context, cItem)
else else
Row( Row(
children: [ children: [
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
// || fileTypeID == 2 // || fileTypeID == 2
) )
SvgPicture.asset(data.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10), SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
(cItem.contant ?? "").toText12(color: Colors.white).expanded, (cItem.contant ?? "").toText12(color: Colors.white).expanded,
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
//|| fileTypeID == 2 //|| fileTypeID == 2
@ -245,8 +300,6 @@ class ChatBubble extends StatelessWidget {
} }
Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) { Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) {
if (isReplyPreview) {}
if (cItem.isImageLoaded! && cItem.image != null) { if (cItem.isImageLoaded! && cItem.image != null) {
return Image.memory( return Image.memory(
cItem.image!, cItem.image!,
@ -283,64 +336,106 @@ class ChatBubble extends StatelessWidget {
); );
} }
} }
}
class WaveBubble extends StatelessWidget {
final PlayerController playerController;
final VoidCallback onTap;
final bool isPlaying;
const WaveBubble({
Key? key,
required this.playerController,
required this.onTap,
required this.isPlaying,
}) : super(key: key);
@override Widget currentWaveBubble(BuildContext context, SingleUserChatModel data) {
Widget build(BuildContext context) {
return Container( return Container(
margin: const EdgeInsets.all(10), margin: const EdgeInsets.all(0),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30), border: Border(
gradient: const LinearGradient( left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
transform: GradientRotation(.83),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: <Color>[
MyColors.gradiantEndColor,
MyColors.gradiantStartColor,
],
), ),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
IconButton( getPlayer(player: data.voiceController!, modelData: data),
onPressed: onTap, StreamBuilder<PositionData>(
icon: Icon(isPlaying ? Icons.stop : Icons.play_arrow), stream: _positionDataStream,
color: Colors.white, builder: (BuildContext context, AsyncSnapshot<PositionData> snapshot) {
splashColor: Colors.transparent, PositionData? positionData = snapshot.data;
highlightColor: Colors.transparent, return SeekBar(
duration: positionData?.duration ?? Duration.zero,
position: positionData?.position ?? Duration.zero,
bufferedPosition: positionData?.bufferedPosition ?? Duration.zero,
onChangeEnd: data.voiceController!.seek,
).expanded;
},
),
],
),
).circle(5);
}
Widget recipetWaveBubble(BuildContext context, SingleUserChatModel data) {
return Container(
margin: const EdgeInsets.all(0),
decoration: BoxDecoration(
border: Border(
left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
), ),
AudioFileWaveforms( color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
size: Size(MediaQuery.of(context).size.width / 2, 10),
playerController: playerController,
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
playerWaveStyle: const PlayerWaveStyle(
fixedWaveColor: Colors.white,
liveWaveColor:MyColors.lightGreenColor,
showTop: true,
showBottom: true,
waveCap: StrokeCap.round,
seekLineThickness: 3,
visualizerHeight: 6,
backgroundColor: Colors.transparent
), ),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
getPlayer(player: data.voiceController!, modelData: data),
StreamBuilder<PositionData>(
stream: _positionDataStream,
builder: (BuildContext context, AsyncSnapshot<PositionData> snapshot) {
PositionData? positionData = snapshot.data;
return SeekBar(
duration: positionData?.duration ?? Duration.zero,
position: positionData?.position ?? Duration.zero,
bufferedPosition: positionData?.bufferedPosition ?? Duration.zero,
onChangeEnd: data.voiceController!.seek,
).expanded;
},
), ),
], ],
), ),
).circle(5);
}
Widget getPlayer({required AudioPlayer player, required SingleUserChatModel modelData}) {
return StreamBuilder<PlayerState>(
stream: player!.playerStateStream,
builder: (BuildContext context, AsyncSnapshot<PlayerState> snapshot) {
PlayerState? playerState = snapshot.data;
ProcessingState? processingState = playerState?.processingState;
bool? playing = playerState?.playing;
if (processingState == ProcessingState.loading || processingState == ProcessingState.buffering) {
return Container(
margin: const EdgeInsets.all(8.0),
width: 30.0,
height: 30.0,
child: const CircularProgressIndicator(),
);
} else if (playing != true) {
return Icon(
Icons.play_arrow,
size: 30,
color: MyColors.lightGreenColor,
).onPress(() {
playVoice(context, data: modelData);
});
} else if (processingState != ProcessingState.completed) {
return Icon(
Icons.pause,
size: 30,
color: MyColors.lightGreenColor,
).onPress(() {
pausePlaying(context, data: modelData);
});
} else {
return Icon(
Icons.replay,
size: 30,
color: MyColors.lightGreenColor,
).onPress(() {
rePlay(context, data: modelData);
});
}
},
); );
} }
} }

@ -1,6 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -18,7 +16,7 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da
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/ui/chat/call/chat_outgoing_call_screen.dart'; import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart';
import 'package:mohem_flutter_app/ui/chat/chat_bubble.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/ui/chat/common.dart';
import 'package:mohem_flutter_app/widgets/chat_app_bar_widge.dart'; import 'package:mohem_flutter_app/widgets/chat_app_bar_widge.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';
@ -80,7 +78,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
loadMore: false, loadMore: false,
isNewChat: params!.isNewChat!, isNewChat: params!.isNewChat!,
); );
data.initAudio(); data.initAudio(receiverId: params!.chatUser!.id!);
} }
return Scaffold( return Scaffold(
@ -130,7 +128,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
reverse: true, reverse: true,
itemCount: m.userChatHistory.length, itemCount: m.userChatHistory.length,
padding: const EdgeInsets.all(21), padding: const EdgeInsets.all(21),
separatorBuilder: (cxt, index) => 8.height, separatorBuilder: (BuildContext cxt, int index) => 8.height,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
return SwipeTo( return SwipeTo(
iconColor: MyColors.lightGreenColor, iconColor: MyColors.lightGreenColor,
@ -144,15 +142,24 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
); );
}, },
).onPress(() async { ).onPress(() async {
if (m.userChatHistory[i].fileTypeResponse != null) { logger.w(m.userChatHistory[i].toJson());
if (m.userChatHistory[i].fileTypeResponse != null && m.userChatHistory[i].fileTypeId != null) {
if (m.userChatHistory[i].fileTypeId! == 1 ||
m.userChatHistory[i].fileTypeId! == 5 ||
m.userChatHistory[i].fileTypeId! == 7 ||
m.userChatHistory[i].fileTypeId! == 6 ||
m.userChatHistory[i].fileTypeId! == 8
// || m.userChatHistory[i].fileTypeId! == 2
) {
m.getChatMedia(context, m.getChatMedia(context,
fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!); fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!);
} }
}
}); });
}, },
), ),
).expanded, ).expanded,
if (m.isMsgReply) if (m.isReplyMsg)
SizedBox( SizedBox(
height: 82, height: 82,
child: Row( child: Row(
@ -174,7 +181,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
], ],
).expanded, ).expanded,
12.width, 12.width,
if (m.isMsgReply && m.repliedMsg.isNotEmpty) showReplyImage(m.repliedMsg, m), if (m.isReplyMsg && m.repliedMsg.isNotEmpty) showReplyImage(m.repliedMsg, m),
12.width, 12.width,
const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe), const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe),
], ],
@ -183,12 +190,9 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
], ],
), ),
), ),
if (m.isFileSelected && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg") if (m.isAttachmentMsg && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg")
SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21), SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21),
const Divider( const Divider(height: 1, color: MyColors.lightGreyEFColor),
height: 1,
color: MyColors.lightGreyEFColor,
),
if (m.isRecoding) if (m.isRecoding)
Column( Column(
children: <Widget>[ children: <Widget>[
@ -198,11 +202,10 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
if (m.isRecoding && m.isPlaying) if (m.isRecoding && m.isPlaying)
WaveBubble( WaveBubble(
playerController: m.playerController, playerController: m.playerController,
isPlaying: m.playerController.playerState == PlayerState.playing,
onTap: () { onTap: () {
m.playOrPause();
}, },
isPlaying: m.playerController.playerState == PlayerState.playing) ).expanded
.expanded
else else
AudioWaveforms( AudioWaveforms(
waveStyle: const WaveStyle( waveStyle: const WaveStyle(
@ -234,22 +237,6 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
).paddingAll(10).onPress(() { ).paddingAll(10).onPress(() {
m.deleteRecoding(); m.deleteRecoding();
}), }),
if (m.isPause)
const Icon(
Icons.mic,
size: 26,
color: MyColors.lightGreenColor,
).paddingOnly(right: 15).onPress(() {
m.resumeRecoding();
}),
if (!m.isPause)
const Icon(
Icons.pause_circle_outline,
size: 26,
color: MyColors.lightGreenColor,
).paddingOnly(right: 15).onPress(() {
m.pauseRecoding();
}),
SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26) SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26)
.onPress( .onPress(
() => m.sendChatMessage(context, () => m.sendChatMessage(context,
@ -269,8 +256,8 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
TextField( TextField(
controller: m.message, controller: m.message,
decoration: InputDecoration( decoration: InputDecoration(
hintText: m.isFileSelected ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(), hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(),
hintStyle: TextStyle(color: m.isFileSelected ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14),
border: InputBorder.none, border: InputBorder.none,
focusedBorder: InputBorder.none, focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none, enabledBorder: InputBorder.none,
@ -288,7 +275,13 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15) ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15)
: null, : null,
), ),
onChanged: (val) { onChanged: (String val) {
print(val.length);
if (val.isNotEmpty) {
m.isTextMsg = true;
} else {
m.isTextMsg = false;
}
m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.chatUser!.id!); m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.chatUser!.id!);
}, },
).expanded, ).expanded,
@ -306,7 +299,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
() => m.selectImageToUpload(context), () => m.selectImageToUpload(context),
), ),
).paddingOnly(right: 15), ).paddingOnly(right: 15),
Icon( const Icon(
Icons.mic, Icons.mic,
color: MyColors.lightGreenColor, color: MyColors.lightGreenColor,
).paddingOnly(right: 15).onPress(() { ).paddingOnly(right: 15).onPress(() {

@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.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/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';
@ -8,6 +9,7 @@ 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/ui/chat/chat_home_screen.dart'; import 'package:mohem_flutter_app/ui/chat/chat_home_screen.dart';
import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart'; import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart';
import 'package:mohem_flutter_app/ui/chat/my_team_screen.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -81,6 +83,7 @@ class _ChatHomeState extends State<ChatHome> {
children: <Widget>[ children: <Widget>[
myTab(LocaleKeys.mychats.tr(), 0), myTab(LocaleKeys.mychats.tr(), 0),
myTab(LocaleKeys.favorite.tr(), 1), myTab(LocaleKeys.favorite.tr(), 1),
AppState().getempStatusIsManager ? myTab("My Team", 2) : const SizedBox(),
], ],
), ),
), ),
@ -95,6 +98,7 @@ class _ChatHomeState extends State<ChatHome> {
children: <Widget>[ children: <Widget>[
ChatHomeScreen(), ChatHomeScreen(),
ChatFavoriteUsersScreen(), ChatFavoriteUsersScreen(),
AppState().getempStatusIsManager ? const MyTeamScreen() : const SizedBox(),
], ],
).expanded, ).expanded,
], ],

@ -0,0 +1,189 @@
import 'dart:math';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
class SeekBar extends StatefulWidget {
final Duration duration;
final Duration position;
final Duration bufferedPosition;
final ValueChanged<Duration>? onChanged;
final ValueChanged<Duration>? onChangeEnd;
const SeekBar({
Key? key,
required this.duration,
required this.position,
required this.bufferedPosition,
this.onChanged,
this.onChangeEnd,
}) : super(key: key);
@override
SeekBarState createState() => SeekBarState();
}
class SeekBarState extends State<SeekBar> {
double? _dragValue;
late SliderThemeData _sliderThemeData;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_sliderThemeData = SliderTheme.of(context).copyWith(
// trackHeight: 2.0,
thumbColor: MyColors.lightGreenColor,
activeTrackColor: MyColors.lightGreenColor,
inactiveTrackColor: MyColors.grey57Color.withOpacity(0.4),
);
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
SliderTheme(
data: _sliderThemeData.copyWith(
thumbShape: HiddenThumbComponentShape(),
),
child: ExcludeSemantics(
child: Slider(
min: 0.0,
max: widget.duration.inMilliseconds.toDouble(),
value: min(widget.bufferedPosition.inMilliseconds.toDouble(), widget.duration.inMilliseconds.toDouble()),
onChanged: (value) {
setState(() {
_dragValue = value;
});
if (widget.onChanged != null) {
widget.onChanged!(Duration(milliseconds: value.round()));
}
},
onChangeEnd: (value) {
if (widget.onChangeEnd != null) {
widget.onChangeEnd!(Duration(milliseconds: value.round()));
}
_dragValue = null;
},
),
),
),
SliderTheme(
data: _sliderThemeData.copyWith(
inactiveTrackColor: Colors.transparent,
),
child: Slider(
min: 0.0,
max: widget.duration.inMilliseconds.toDouble(),
value: min(_dragValue ?? widget.position.inMilliseconds.toDouble(), widget.duration.inMilliseconds.toDouble()),
onChanged: (value) {
setState(() {
_dragValue = value;
});
if (widget.onChanged != null) {
widget.onChanged!(Duration(milliseconds: value.round()));
}
},
onChangeEnd: (value) {
if (widget.onChangeEnd != null) {
widget.onChangeEnd!(Duration(milliseconds: value.round()));
}
_dragValue = null;
},
),
),
],
);
}
}
class PositionData {
final Duration position;
final Duration bufferedPosition;
final Duration duration;
PositionData(this.position, this.bufferedPosition, this.duration);
}
class HiddenThumbComponentShape extends SliderComponentShape {
@override
Size getPreferredSize(bool isEnabled, bool isDiscrete) => Size.zero;
@override
void paint(
PaintingContext context,
Offset center, {
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow,
}) {}
}
class WaveBubble extends StatelessWidget {
final PlayerController playerController;
final VoidCallback onTap;
final bool isPlaying;
const WaveBubble({
Key? key,
required this.playerController,
required this.onTap,
required this.isPlaying,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
gradient: const LinearGradient(
transform: GradientRotation(.83),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: <Color>[
MyColors.gradiantEndColor,
MyColors.gradiantStartColor,
],
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: onTap,
icon: Icon(isPlaying ? Icons.stop : Icons.play_arrow),
color: Colors.white,
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
AudioFileWaveforms(
size: Size(MediaQuery.of(context).size.width / 2, 10),
playerController: playerController,
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
enableSeekGesture: true,
density: 1,
playerWaveStyle: const PlayerWaveStyle(
fixedWaveColor: Colors.white,
liveWaveColor: MyColors.greenColor,
showTop: true,
showBottom: true,
waveCap: StrokeCap.round,
seekLineThickness: 2,
visualizerHeight: 4,
backgroundColor: Colors.transparent,
),
),
],
),
);
}
}

@ -0,0 +1,154 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.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/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
class MyTeamScreen extends StatefulWidget {
const MyTeamScreen({Key? key}) : super(key: key);
@override
State<MyTeamScreen> createState() => _MyTeamScreenState();
}
class _MyTeamScreenState extends State<MyTeamScreen> {
late ChatProviderModel provider;
@override
void initState() {
super.initState();
provider = Provider.of<ChatProviderModel>(context, listen: false);
loadMembers();
}
void loadMembers(){
provider.getTeamMembers();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: MyColors.white,
body: Consumer<ChatProviderModel>(
builder: (BuildContext context, ChatProviderModel m, Widget? child) {
if (m.isLoading) {
return ChatHomeShimmer(
isDetailedScreen: false,
);
} else {
return m.teamMembersList != null && m.teamMembersList.isNotEmpty
? ListView.separated(
itemCount: m.teamMembersList!.length,
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.only(bottom: 80.0),
itemBuilder: (BuildContext context, int index) {
return SizedBox(
height: 55,
child: Row(
children: [
Stack(
children: <Widget>[
if (m.teamMembersList![index].isImageLoading!)
const SizedBox(
height: 48,
width: 48,
).toShimmer().circle(30),
if (!m.teamMembersList![index].isImageLoading! && m.teamMembersList![index].userLocalDownlaodedImage == null)
SvgPicture.asset(
"assets/images/user.svg",
height: 48,
width: 48,
),
if (!m.teamMembersList![index].isImageLoading! && m.teamMembersList![index].userLocalDownlaodedImage != null)
Container(
width: 48.0,
height: 48.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
fit: BoxFit.cover,
image: FileImage(m.teamMembersList![index].userLocalDownlaodedImage!),
),
),
),
// Positioned(
// right: 5,
// bottom: 1,
// child: Container(
// width: 10,
// height: 10,
// decoration: BoxDecoration(
// color: m.teamMembersList![index].userStatus == 1 ? MyColors.green2DColor : Colors.red,
// ),
// ).circle(10),
// )
],
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(m.teamMembersList![index].userName! ?? "").toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 13),
],
).expanded,
// SizedBox(
// width: 60,
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisAlignment: MainAxisAlignment.end,
// mainAxisSize: MainAxisSize.max,
// children: <Widget>[
// Icon(
// m.teamMembersList![index].isFav! ? Icons.star : Icons.star_border,
// color: m.teamMembersList![index].isFav! ? MyColors.yellowColor : MyColors.grey35Color,
// ).onPress(() {
// if (m.teamMembersList![index].isFav!) {
// m.unFavoriteUser(
// userID: AppState().chatDetails!.response!.id!,
// targetUserID: m.teamMembersList![index].id!,
// );
// }
// }).center,
// ],
// ),
// ),
],
),
).onPress(() {
Navigator.pushNamed(
context,
AppRoutes.chatDetailed,
arguments: ChatDetailedScreenParams(m.teamMembersList![index], true),
).then(
(Object? value) {
m.clearSelections();
},
);
});
},
separatorBuilder: (BuildContext context, int index) => const Divider(color: MyColors.lightGreyE5Color).paddingOnly(left: 70),
).paddingAll(21)
: Column(
children: <Widget>[
Utils.getNoDataWidget(context).expanded,
],
);
}
},
),
);
}
}

@ -48,6 +48,9 @@ class _SuccessDialogState extends State<SuccessDialog> with TickerProviderStateM
width: size, width: size,
height: size, height: size,
child: Card( child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25.0),
),
child: Lottie.asset( child: Lottie.asset(
'assets/lottie/lt_success.json', 'assets/lottie/lt_success.json',
repeat: false, repeat: false,

@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart'; 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';
@ -32,6 +32,8 @@ import 'package:signalr_netcore/signalr_client.dart';
late HubConnection chatHubConnection; late HubConnection chatHubConnection;
class DashboardScreen extends StatefulWidget { class DashboardScreen extends StatefulWidget {
DashboardScreen({Key? key}) : super(key: key); DashboardScreen({Key? key}) : super(key: key);
@ -323,21 +325,8 @@ class _DashboardScreenState extends State<DashboardScreen> {
], ],
), ),
], ],
).paddingOnly(left: 21, right: 21, top: 7), ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21),
context.watch<MarathonProvider>().isLoading Column(
? const MarathonBannerShimmer().paddingAll(20)
: MarathonBanner(isMarathonUpcoming: context.watch<MarathonProvider>().isUpComingMarathon).paddingAll(20),
ServicesWidget(),
8.height,
Container(
width: double.infinity,
padding: const EdgeInsets.only(top: 31),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)),
border: Border.all(color: MyColors.lightGreyEDColor, width: 1),
),
child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -396,6 +385,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
width: 73, width: 73,
height: 73, height: 73,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all( borderRadius: const BorderRadius.all(
Radius.circular(100), Radius.circular(100),
), ),
@ -433,7 +423,24 @@ class _DashboardScreenState extends State<DashboardScreen> {
), ),
], ],
), ),
) Container(
width: double.infinity,
padding: const EdgeInsets.only(top: 31),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)),
border: Border.all(color: MyColors.lightGreyEDColor, width: 1),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ServicesWidget(),
context.watch<MarathonProvider>().isLoading
? const MarathonBannerShimmer().paddingAll(20)
: MarathonBanner(isMarathonUpcoming: context.watch<MarathonProvider>().isUpComingMarathon).paddingOnly(left: 21, right: 21, bottom: 21, top: 8),
],
),
),
], ],
), ),
), ),

@ -150,13 +150,9 @@ class _AppDrawerState extends State<AppDrawer> {
Widget menuItem(String icon, String title, String routeName, {Color? color, bool closeDrawer = true, VoidCallback? onPress}) { Widget menuItem(String icon, String title, String routeName, {Color? color, bool closeDrawer = true, VoidCallback? onPress}) {
return Row( return Row(
children: [ children: [
SvgPicture.asset( SvgPicture.asset(icon, height: 20, width: 20),
icon,
height: 20,
width: 20,
),
9.width, 9.width,
title.toText14(color: color).expanded title.toText14(color: color, textAlign: AppState().isArabic(context) ? TextAlign.right : null).expanded,
], ],
).paddingOnly(left: 21, top: 10, bottom: 10, right: 21).onPress(closeDrawer ).paddingOnly(left: 21, top: 10, bottom: 10, right: 21).onPress(closeDrawer
? () async { ? () async {

@ -1,60 +0,0 @@
import 'dart:ui';
import 'package:flutter/material.dart';
class DrawerItem extends StatefulWidget {
final String title;
final String subTitle;
final IconData icon;
final Color color;
final dynamic assetLink;
const DrawerItem(this.title, {required this.icon, required this.color, this.subTitle = '', this.assetLink});
@override
_DrawerItemState createState() => _DrawerItemState();
}
class _DrawerItemState extends State<DrawerItem> {
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: 0, bottom: 5, left: 0, right: 0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (widget.assetLink != null)
Container(
height: 20,
width: 20,
child: Image.asset(widget.assetLink),
),
if (widget.assetLink == null)
Icon(
widget.icon,
color: widget.color,
size: 25,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width * 0.45,
child: Text(widget.title,
style: TextStyle(
color: widget.color ?? Color(0xFF2E303A),
fontSize: 14,
fontFamily: 'Poppins',
fontWeight: FontWeight.w600,
letterSpacing: -0.84,
)),
),
],
),
),
],
));
}
}

@ -100,16 +100,16 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
passwordConstraintsUI(LocaleKeys.doNotUseRecentPassword.tr(), true), passwordConstraintsUI(LocaleKeys.doNotUseRecentPassword.tr(), true),
8.height, 8.height,
passwordConstraintsUI(LocaleKeys.atLeastOneLowercase.tr(), checkRegEx(r'[a-z]')), passwordConstraintsUI(LocaleKeys.atLeastOneLowercase.tr(), checkRegEx(r'[a-z]')),
8.height, // 8.height,
passwordConstraintsUI(LocaleKeys.atLeastOneUppercase.tr(), checkRegEx(r'[A-Z]')), // passwordConstraintsUI(LocaleKeys.atLeastOneUppercase.tr(), checkRegEx(r'[A-Z]')),
8.height, 8.height,
passwordConstraintsUI(LocaleKeys.atLeastOneNumeric.tr(), checkRegEx(r'[0-9]')), passwordConstraintsUI(LocaleKeys.atLeastOneNumeric.tr(), checkRegEx(r'[0-9]')),
8.height, 8.height,
passwordConstraintsUI(LocaleKeys.minimum8Characters.tr(), password.text.length >= 8), passwordConstraintsUI(LocaleKeys.minimum8Characters.tr(), password.text.length >= 8),
8.height, 8.height,
passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)), passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)),
8.height, // 8.height,
passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')), // passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')),
8.height, 8.height,
passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text), passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text),
], ],
@ -131,14 +131,14 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
return false; return false;
} }
bool hasUppercase = password.contains(RegExp(r'[A-Z]')); // bool hasUppercase = password.contains(RegExp(r'[A-Z]'));
bool hasDigits = password.contains(RegExp(r'[0-9]')); bool hasDigits = password.contains(RegExp(r'[0-9]'));
bool hasLowercase = password.contains(RegExp(r'[a-z]')); bool hasLowercase = password.contains(RegExp(r'[a-z]'));
bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]')); // bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'));
bool hasMinLength = password.length >= minLength; bool hasMinLength = password.length >= minLength;
bool isMatched = password == confirmPassword.text; bool isMatched = password == confirmPassword.text;
return hasDigits && hasUppercase && hasLowercase && hasSpecialCharacters && hasMinLength && isMatched && checkRepeatedChars(password); return hasDigits && hasLowercase && hasMinLength && isMatched && checkRepeatedChars(password);
} }
bool checkRepeatedChars(String password) { bool checkRepeatedChars(String password) {

@ -95,6 +95,8 @@ class _LoginScreenState extends State<LoginScreen> {
firebaseToken = await _firebaseMessaging.getToken(); firebaseToken = await _firebaseMessaging.getToken();
loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios");
if (loginInfo == null) { if (loginInfo == null) {
await checkPrefs();
_autoLogin = false;
Utils.hideLoading(context); Utils.hideLoading(context);
return; return;
} else { } else {
@ -163,6 +165,9 @@ class _LoginScreenState extends State<LoginScreen> {
// username.text = "206535"; // Hashim User // username.text = "206535"; // Hashim User
// password.text = "Namira786"; // password.text = "Namira786";
// 13777
// Ab12345cd
} }
if (isAppOpenBySystem!) checkFirebaseToken(); if (isAppOpenBySystem!) checkFirebaseToken();
} }

@ -94,8 +94,8 @@ class _NewPasswordScreenState extends State<NewPasswordScreen> {
passwordConstraintsUI(LocaleKeys.doNotUseRecentPassword.tr(), true), passwordConstraintsUI(LocaleKeys.doNotUseRecentPassword.tr(), true),
8.height, 8.height,
passwordConstraintsUI(LocaleKeys.atLeastOneLowercase.tr(), checkRegEx(r'[a-z]')), passwordConstraintsUI(LocaleKeys.atLeastOneLowercase.tr(), checkRegEx(r'[a-z]')),
8.height, // 8.height,
passwordConstraintsUI(LocaleKeys.atLeastOneUppercase.tr(), checkRegEx(r'[A-Z]')), // passwordConstraintsUI(LocaleKeys.atLeastOneUppercase.tr(), checkRegEx(r'[A-Z]')),
8.height, 8.height,
passwordConstraintsUI(LocaleKeys.atLeastOneNumeric.tr(), checkRegEx(r'[0-9]')), passwordConstraintsUI(LocaleKeys.atLeastOneNumeric.tr(), checkRegEx(r'[0-9]')),
8.height, 8.height,
@ -143,14 +143,14 @@ class _NewPasswordScreenState extends State<NewPasswordScreen> {
return false; return false;
} }
bool hasUppercase = password.contains(RegExp(r'[A-Z]')); // bool hasUppercase = password.contains(RegExp(r'[A-Z]'));
bool hasDigits = password.contains(RegExp(r'[0-9]')); bool hasDigits = password.contains(RegExp(r'[0-9]'));
bool hasLowercase = password.contains(RegExp(r'[a-z]')); bool hasLowercase = password.contains(RegExp(r'[a-z]'));
// bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]')); // bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'));
bool hasMinLength = password.length >= minLength; bool hasMinLength = password.length >= minLength;
bool isMatched = password == confirmPassword.text; bool isMatched = password == confirmPassword.text;
return hasDigits && hasUppercase && hasLowercase && hasMinLength && isMatched && checkRepeatedChars(password); return hasDigits && hasLowercase && hasMinLength && isMatched && checkRepeatedChars(password);
} }
bool checkRepeatedChars(String password) { bool checkRepeatedChars(String password) {

@ -2,7 +2,6 @@ import 'dart:async';
import 'package:appinio_swiper/appinio_swiper.dart'; import 'package:appinio_swiper/appinio_swiper.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/marathon/marathon_api_client.dart'; import 'package:mohem_flutter_app/api/marathon/marathon_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
@ -31,12 +30,12 @@ class MarathonProvider extends ChangeNotifier {
String? selectedOptionId; String? selectedOptionId;
int? totalQualifiers; int? totalQualifiers;
//TODO: THIS BUG NEEDS TO BE FIXED. NOT DONE YET
String? gapTimeImage; String? gapTimeImage;
String? gapTimeText; String? gapTimeText;
int? gapTimeType; int? gapTimeType;
bool iAmWinner = false; bool iAmWinner = false;
bool isGettingQualifiers = false;
bool isPrivilegedWithMarathon = false; bool isPrivilegedWithMarathon = false;
bool _isLoading = false; bool _isLoading = false;
@ -66,6 +65,24 @@ class MarathonProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
bool _isButtonEnabled = false;
bool get isButtonEnabled => _isButtonEnabled;
set isButtonEnabled(bool value) {
_isButtonEnabled = value;
notifyListeners();
}
bool _isUserWaiting = false;
bool get isUserWaiting => _isUserWaiting;
set isUserWaiting(bool value) {
_isUserWaiting = value;
notifyListeners();
}
bool _isMarathonCompleted = false; bool _isMarathonCompleted = false;
bool get isMarathonCompleted => _isMarathonCompleted; bool get isMarathonCompleted => _isMarathonCompleted;
@ -144,7 +161,13 @@ class MarathonProvider extends ChangeNotifier {
); );
} }
int totalSecondsToWaitForMarathon = 20; int totalSecondsToWaitForMarathon = 30;
set updateTotalSecondsToWaitForMarathon(int value) {
totalSecondsToWaitForMarathon = value;
notifyListeners();
}
Timer timerToWaitForMarathon = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); Timer timerToWaitForMarathon = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});
void startTimerToWaitForMarathon() { void startTimerToWaitForMarathon() {
@ -153,7 +176,13 @@ class MarathonProvider extends ChangeNotifier {
oneSec, oneSec,
(Timer timer) async { (Timer timer) async {
if (totalSecondsToWaitForMarathon == 0) { if (totalSecondsToWaitForMarathon == 0) {
callNextQuestionApi(); if (isUserWaiting) {
MarathonApiClient().joinMarathonAsParticipant().whenComplete(() async {
await callNextQuestionApi();
});
} else {
isButtonEnabled = false;
}
timer.cancel(); timer.cancel();
return; return;
} else { } else {
@ -173,7 +202,7 @@ class MarathonProvider extends ChangeNotifier {
timerForQuestion = Timer.periodic( timerForQuestion = Timer.periodic(
oneSec, oneSec,
(Timer timer) async { (Timer timer) async {
// This 2 is just to show the color of answer tile for 2 seconds and then update card status // This 2 is just to show the color of answer tile for 1 and then update card status
if (totalCurrentQuestionTime - currentGapTime == 1) { if (totalCurrentQuestionTime - currentGapTime == 1) {
getCorrectAnswerAndUpdateAnswerColor(); getCorrectAnswerAndUpdateAnswerColor();
} }
@ -184,11 +213,14 @@ class MarathonProvider extends ChangeNotifier {
updateCardStatusToAnswer(); updateCardStatusToAnswer();
scheduleMicrotask(() async { scheduleMicrotask(() async {
if (isUserOutOfGame) {
await callNextQuestionApi();
} else {
await callSubmitOptionApi().then((bool value) async { await callSubmitOptionApi().then((bool value) async {
if (value) { updateIsUserOutOfGame = !value;
await callNextQuestionApi(); await callNextQuestionApi();
}
}); });
}
}); });
} }
@ -198,7 +230,7 @@ class MarathonProvider extends ChangeNotifier {
gapTimeType = currentQuestion.gapType; gapTimeType = currentQuestion.gapType;
updateCardData(); updateCardData();
if (currentQuestionNumber - 1 == marathonDetailModel.totalQuestions!) { if (currentQuestionNumber - 1 == marathonDetailModel.totalQuestions!) {
callGetQualifiersApi(); isGettingQualifiers = true;
updateQuestionCardStatus(QuestionCardStatus.findingWinner); updateQuestionCardStatus(QuestionCardStatus.findingWinner);
timer.cancel(); timer.cancel();
cancelTimer(); cancelTimer();
@ -224,10 +256,13 @@ class MarathonProvider extends ChangeNotifier {
timerForWinnerSelection = Timer.periodic( timerForWinnerSelection = Timer.periodic(
oneSec, oneSec,
(Timer timer) async { (Timer timer) async {
if (totalSecondsToWaitForWinner == 0) { if (totalSecondsToWaitForWinner == 1) {
await callGetSelectedWinnersApi().whenComplete(() => updateQuestionCardStatus(QuestionCardStatus.winnerFound));
timer.cancel(); timer.cancel();
updateQuestionCardStatus(QuestionCardStatus.winnerFound);
return; return;
} else if (totalSecondsToWaitForWinner == 15) {
totalSecondsToWaitForWinner--;
await callGetQualifiersApi();
} else { } else {
totalSecondsToWaitForWinner--; totalSecondsToWaitForWinner--;
} }
@ -245,6 +280,7 @@ class MarathonProvider extends ChangeNotifier {
Future<void> callGetQualifiersApi() async { Future<void> callGetQualifiersApi() async {
totalQualifiers = await MarathonApiClient().getQualifiers(marathonId: marathonDetailModel.id!); totalQualifiers = await MarathonApiClient().getQualifiers(marathonId: marathonDetailModel.id!);
isGettingQualifiers = false;
notifyListeners(); notifyListeners();
} }
@ -268,7 +304,7 @@ class MarathonProvider extends ChangeNotifier {
if (currentQuestionNumber < marathonDetailModel.totalQuestions!) { if (currentQuestionNumber < marathonDetailModel.totalQuestions!) {
if (currentQuestionNumber == 0) { if (currentQuestionNumber == 0) {
Utils.showLoading(AppRoutes.navigatorKey.currentContext!); Utils.showLoading(AppRoutes.navigatorKey.currentContext!);
currentQuestion = (await MarathonApiClient().getNextQuestion(questionId: null, marathonId: marathonDetailModel.id!))!; currentQuestion = (await MarathonApiClient().getNextQuestion(questionId: null, marathonId: marathonDetailModel.id!));
gapTimeImage = currentQuestion.gapImage; gapTimeImage = currentQuestion.gapImage;
gapTimeText = currentQuestion.gapText; gapTimeText = currentQuestion.gapText;
gapTimeType = currentQuestion.gapType; gapTimeType = currentQuestion.gapType;
@ -277,10 +313,9 @@ class MarathonProvider extends ChangeNotifier {
} }
startTimerForQuestion(); startTimerForQuestion();
updateCardData(); updateCardData();
Navigator.pushReplacementNamed(AppRoutes.navigatorKey.currentContext!, AppRoutes.marathonScreen); Navigator.pushReplacementNamed(AppRoutes.navigatorKey.currentContext!, AppRoutes.marathonScreen);
} else { } else {
currentQuestion = (await MarathonApiClient().getNextQuestion(questionId: currentQuestion.id, marathonId: marathonDetailModel.id!))!; currentQuestion = (await MarathonApiClient().getNextQuestion(questionId: currentQuestion.id, marathonId: marathonDetailModel.id!));
} }
notifyListeners(); notifyListeners();
} }
@ -325,14 +360,15 @@ class MarathonProvider extends ChangeNotifier {
currentQuestion.questionOptions![i].optionStatus = QuestionsOptionStatus.unSelected; currentQuestion.questionOptions![i].optionStatus = QuestionsOptionStatus.unSelected;
} }
currentQuestion.questionOptions![index].optionStatus = status; currentQuestion.questionOptions![index].optionStatus = status;
selectedOptionId = currentQuestion.questionOptions![index].id;
selectedOptionIndex = index; selectedOptionIndex = index;
notifyListeners(); notifyListeners();
} }
void updateQuestionCardStatus(QuestionCardStatus status) { void updateQuestionCardStatus(QuestionCardStatus status) {
if (status == QuestionCardStatus.wrongAnswer || status == QuestionCardStatus.skippedAnswer) { // if (status == QuestionCardStatus.wrongAnswer || status == QuestionCardStatus.skippedAnswer) {
updateIsUserOutOfGame = true; // updateIsUserOutOfGame = true;
} // }
questionCardStatus = status; questionCardStatus = status;
notifyListeners(); notifyListeners();
} }
@ -369,18 +405,27 @@ class MarathonProvider extends ChangeNotifier {
void resetValues() async { void resetValues() async {
_currentQuestionNumber = 0; _currentQuestionNumber = 0;
cardContentList.clear(); cardContentList.clear();
itsMarathonTime = false;
timerForWinnerSelection.cancel(); timerForWinnerSelection.cancel();
timerForSponsorVideo.cancel(); timerForSponsorVideo.cancel();
timerToWaitForMarathon.cancel(); timerToWaitForMarathon.cancel();
timerForQuestion.cancel(); timerForQuestion.cancel();
_isMarathonCompleted = false; _isMarathonCompleted = false;
isUserOutOfGame = false; isUserOutOfGame = false;
isButtonEnabled = false;
isUserWaiting = false;
totalCurrentQuestionTime = 0; totalCurrentQuestionTime = 0;
sponsorsSecondsCounter = 0; sponsorsSecondsCounter = 0;
totalSponsorVideoSeconds = 0; totalSponsorVideoSeconds = 0;
totalSecondsToWaitForMarathon = 20; totalSecondsToWaitForWinner = 30;
totalSecondsToWaitForMarathon = 30;
currentGapTime = 0; currentGapTime = 0;
currentQuestion = QuestionModel(); currentQuestion = QuestionModel();
if (answerStatusesList.isNotEmpty) {
for (int i = 0; i < answerStatusesList.length; i++) {
answerStatusesList[i] = QuestionCardStatus.question;
}
}
notifyListeners(); notifyListeners();
} }
@ -390,7 +435,6 @@ class MarathonProvider extends ChangeNotifier {
} }
bool checkIfPrivilegedForMarathon() { bool checkIfPrivilegedForMarathon() {
return true;
for (PrivilegeListModel element in AppState().privilegeListModel!) { for (PrivilegeListModel element in AppState().privilegeListModel!) {
if (element.serviceName == "Marathon") { if (element.serviceName == "Marathon") {
if (element.previlege != null) { if (element.previlege != null) {
@ -406,16 +450,18 @@ class MarathonProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
isPrivilegedWithMarathon = checkIfPrivilegedForMarathon(); isPrivilegedWithMarathon = checkIfPrivilegedForMarathon();
if (isPrivilegedWithMarathon) { if (isPrivilegedWithMarathon) {
await MarathonApiClient().getMarathonToken().whenComplete(() async {
marathonDetailModel = await MarathonApiClient().getMarathonDetails(); marathonDetailModel = await MarathonApiClient().getMarathonDetails();
updateTotalSecondsToWaitForMarathon = marathonDetailModel.marathonBufferTime ?? 30;
if (marathonDetailModel.id == null) { if (marathonDetailModel.id == null) {
isUpComingMarathon = false; isUpComingMarathon = false;
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
return; return;
} }
if (DateTime.parse(marathonDetailModel.startTime!).isAfter(DateTime.now())) {
itsMarathonTime = false;
}
populateQuestionStatusesList(); populateQuestionStatusesList();
});
} }
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
@ -423,17 +469,9 @@ class MarathonProvider extends ChangeNotifier {
Future<void> onJoinMarathonPressed(BuildContext context) async { Future<void> onJoinMarathonPressed(BuildContext context) async {
try { try {
Utils.showLoading(context); isUserWaiting = true;
resetValues();
int? remainingTime = await MarathonApiClient().joinMarathonAsParticipant();
if (remainingTime != null) {
totalSecondsToWaitForMarathon = remainingTime;
notifyListeners();
startTimerToWaitForMarathon();
Navigator.pushReplacementNamed(context, AppRoutes.marathonWaitingScreen); Navigator.pushReplacementNamed(context, AppRoutes.marathonWaitingScreen);
}
} catch (e) { } catch (e) {
Utils.hideLoading(context);
Utils.confirmDialog(context, e.toString()); Utils.confirmDialog(context, e.toString());
} }
} }

@ -36,11 +36,11 @@ class MarathonScreen extends StatelessWidget {
} }
return gapText.toText18(color: MyColors.darkTextColor, isCentered: true); return gapText.toText18(color: MyColors.darkTextColor, isCentered: true);
} }
if (gapType == 2) { if (gapType == 0) {
if (gapImage == null) { if (gapImage == null) {
return Image.asset(MyLottieConsts.congratsGif, height: 200); return Image.asset(MyLottieConsts.congratsGif, height: 200);
} }
return Image.network(gapImage, height: 200); return Image.network(ApiConsts.marathonBaseUrlServices + gapImage, height: 200);
} }
return Image.asset(MyLottieConsts.congratsGif, height: 200); return Image.asset(MyLottieConsts.congratsGif, height: 200);
} }
@ -50,7 +50,16 @@ class MarathonScreen extends StatelessWidget {
width: double.infinity, width: double.infinity,
decoration: MyDecorations.shadowDecoration, decoration: MyDecorations.shadowDecoration,
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20), padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
child: Stack( child: provider.selectedWinners == null || (provider.selectedWinners!.isEmpty && !provider.iAmWinner)
? Column(
children: <Widget>[
Lottie.asset(MyLottieConsts.noWinnerLottie),
Center(
child: LocaleKeys.noWinner.tr().toText18(color: MyColors.grey3AColor, isCentered: true),
),
],
)
: Stack(
children: <Widget>[ children: <Widget>[
Column( Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -65,7 +74,11 @@ class MarathonScreen extends StatelessWidget {
), ),
Align( Align(
alignment: Alignment.center, alignment: Alignment.center,
child: LocaleKeys.winners.tr().toText32(color: MyColors.white, isBold: true, isCentered: true).paddingOnly(top: 07), child: ((provider.selectedWinners!.length == 1 && !provider.iAmWinner) || (provider.selectedWinners!.isEmpty && provider.iAmWinner)
? LocaleKeys.winner.tr()
: LocaleKeys.winners.tr())
.toText32(color: MyColors.white, isBold: true, isCentered: true)
.paddingOnly(top: 07),
) )
], ],
), ),
@ -118,12 +131,12 @@ class MarathonScreen extends StatelessWidget {
), ),
5.height, 5.height,
Image.network( Image.network(
ApiConsts.marathonBaseUrlServices + provider.marathonDetailModel.sponsors!.first.image!, ApiConsts.marathonBaseUrlServices + provider.marathonDetailModel.sponsors!.first.logo!,
height: 50, height: 50,
width: 150, width: 150,
fit: BoxFit.contain, fit: BoxFit.contain,
errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
return const Center(); return Image.asset("assets/images/logos/main_mohemm_logo.png", height: 50, width: 150);
}, },
) )
], ],
@ -166,6 +179,7 @@ class MarathonScreen extends StatelessWidget {
onHomeTapped: () { onHomeTapped: () {
if (provider.questionCardStatus == QuestionCardStatus.winnerFound) { if (provider.questionCardStatus == QuestionCardStatus.winnerFound) {
provider.resetValues(); provider.resetValues();
provider.getMarathonDetailsFromApi();
Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.dashboard)); Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.dashboard));
} else { } else {
showDialog( showDialog(
@ -174,6 +188,7 @@ class MarathonScreen extends StatelessWidget {
message: LocaleKeys.youWantToLeaveMarathon.tr(), message: LocaleKeys.youWantToLeaveMarathon.tr(),
onTap: () { onTap: () {
provider.resetValues(); provider.resetValues();
provider.getMarathonDetailsFromApi();
Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.dashboard)); Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.dashboard));
}, },
), ),
@ -183,6 +198,7 @@ class MarathonScreen extends StatelessWidget {
onBackTapped: () { onBackTapped: () {
if (provider.questionCardStatus == QuestionCardStatus.winnerFound) { if (provider.questionCardStatus == QuestionCardStatus.winnerFound) {
provider.resetValues(); provider.resetValues();
provider.getMarathonDetailsFromApi();
Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.dashboard)); Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.dashboard));
} else { } else {
showDialog( showDialog(
@ -201,8 +217,8 @@ class MarathonScreen extends StatelessWidget {
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
ListView( ListView(
children: [ children: <Widget>[
20.height, 10.height,
if (provider.questionCardStatus == QuestionCardStatus.findingWinner) ...<Widget>[ if (provider.questionCardStatus == QuestionCardStatus.findingWinner) ...<Widget>[
QualifiersContainer(provider: provider).paddingOnly(left: 21, right: 21), QualifiersContainer(provider: provider).paddingOnly(left: 21, right: 21),
] else if (provider.questionCardStatus == QuestionCardStatus.winnerFound) ] else if (provider.questionCardStatus == QuestionCardStatus.winnerFound)
@ -237,7 +253,7 @@ class MarathonScreen extends StatelessWidget {
subTitle: LocaleKeys.youMissedTheQuestion.tr().toText18(color: MyColors.darkTextColor, isCentered: true), subTitle: LocaleKeys.youMissedTheQuestion.tr().toText18(color: MyColors.darkTextColor, isCentered: true),
), ),
onFindingWinner: (BuildContext context) => CustomStatusWidget( onFindingWinner: (BuildContext context) => CustomStatusWidget(
asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168), asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168, reverse: false),
title: LocaleKeys.fingersCrossed.tr().toText22(color: MyColors.greenColor), title: LocaleKeys.fingersCrossed.tr().toText22(color: MyColors.greenColor),
subTitle: LocaleKeys.winnerSelectedRandomly.tr().toText18(color: MyColors.darkTextColor, isCentered: true), subTitle: LocaleKeys.winnerSelectedRandomly.tr().toText18(color: MyColors.darkTextColor, isCentered: true),
), ),
@ -248,6 +264,7 @@ class MarathonScreen extends StatelessWidget {
provider.questionCardStatus == QuestionCardStatus.winnerFound provider.questionCardStatus == QuestionCardStatus.winnerFound
? DefaultButton(LocaleKeys.ok.tr(), () { ? DefaultButton(LocaleKeys.ok.tr(), () {
provider.resetValues(); provider.resetValues();
provider.getMarathonDetailsFromApi();
Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.dashboard)); Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.dashboard));
}).insideContainer }).insideContainer
: const SizedBox() : const SizedBox()

@ -80,24 +80,24 @@ class MarathonWaitingScreen extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
LocaleKeys.startingIn.tr().toText16(), LocaleKeys.startingIn.tr().toText16(),
provider.totalSecondsToWaitForMarathon.toString().toText18(color: provider.totalSecondsToWaitForMarathon < 5 ? MyColors.redColor : MyColors.black), (provider.totalSecondsToWaitForMarathon < 10 ? "0${provider.totalSecondsToWaitForMarathon.toString()}" : provider.totalSecondsToWaitForMarathon.toString()).toText18(color: provider.totalSecondsToWaitForMarathon < 5 ? MyColors.redColor : MyColors.black),
],
),
),
Align(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
InkWell(
onTap: () {
provider.callNextQuestionApi();
provider.timerToWaitForMarathon.cancel();
},
child: "Join Now".toText16(),
).paddingOnly(bottom: 20),
], ],
), ),
), ),
// Align(
// child: Column(
// mainAxisAlignment: MainAxisAlignment.end,
// children: <Widget>[
// InkWell(
// onTap: () {
// provider.callNextQuestionApi();
// provider.timerToWaitForMarathon.cancel();
// },
// child: "Join Now".toText16(),
// ).paddingOnly(bottom: 20),
// ],
// ),
// ),
], ],
), ),
).expanded, ).expanded,

@ -0,0 +1,202 @@
import 'dart:async';
import 'dart:ui' as ui;
import 'package:auto_size_text/auto_size_text.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/current_remaining_time.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
class CountdownTimerForDetailScreen extends StatelessWidget {
final int timeToMarathon;
final MarathonProvider provider;
CountdownTimerForDetailScreen({
Key? key,
required this.provider,
required this.timeToMarathon,
}) : super(key: key);
final TextStyle styleTextHome = TextStyle(
color: MyColors.white.withOpacity(0.45),
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w800,
letterSpacing: -0.4,
);
final TextStyle styleDigitHome = TextStyle(
height: 22 / 27,
color: MyColors.white,
fontSize: isTablet ? 30 : 15,
fontStyle: FontStyle.italic,
letterSpacing: -1.44,
fontWeight: FontWeight.bold,
);
final TextStyle styleTextMarathon = const TextStyle(
fontSize: 10,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w600,
color: MyColors.grey57Color,
letterSpacing: -0.4,
);
final TextStyle styleDigitMarathon = const TextStyle(
height: 23 / 24,
color: MyColors.darkTextColor,
fontSize: 34,
letterSpacing: -1.44,
fontWeight: FontWeight.bold,
);
Widget buildSeparator() {
return AutoSizeText(
" : ",
maxFontSize: 24,
minFontSize: 20,
style: styleDigitMarathon,
);
}
Widget getTimeDigit(String text) {
return AutoSizeText(
text,
maxFontSize: 24,
minFontSize: 20,
style: styleDigitMarathon,
);
}
Widget getTimeText(String text) {
return AutoSizeText(
text,
minFontSize: 7,
maxFontSize: 8,
style: styleTextMarathon,
);
}
Widget buildEmptyWidget() {
return Directionality(
textDirection: ui.TextDirection.ltr,
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
children: <Widget>[
getTimeDigit("00"),
getTimeText(LocaleKeys.days.tr()),
],
),
buildSeparator(),
Column(
children: <Widget>[
getTimeDigit("00"),
getTimeText(LocaleKeys.hours.tr()),
],
),
buildSeparator(),
Column(
children: <Widget>[
getTimeDigit("00"),
getTimeText(LocaleKeys.minutes.tr()),
],
),
buildSeparator(),
Column(
children: <Widget>[
getTimeDigit("00"),
getTimeText(LocaleKeys.seconds.tr()),
],
),
],
),
);
}
Widget buildCountdownTimer(CurrentRemainingTime? time) {
if (time == null) {
if (!provider.itsMarathonTime) {
scheduleMicrotask(() {
provider.itsMarathonTime = true;
provider.isButtonEnabled = true;
provider.startTimerToWaitForMarathon();
});
}
return provider.itsMarathonTime
? Directionality(
textDirection: ui.TextDirection.ltr,
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
children: <Widget>[
getTimeDigit(provider.totalSecondsToWaitForMarathon.toString()),
getTimeText(LocaleKeys.seconds.tr()),
],
),
],
),
)
: buildEmptyWidget();
}
return Directionality(
textDirection: ui.TextDirection.ltr,
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
children: <Widget>[
time.days == null ? getTimeDigit("00") : getTimeDigit(time.days! < 10 ? "0${time.days.toString()}" : time.days.toString()),
getTimeText(LocaleKeys.days.tr()),
],
),
buildSeparator(),
Column(
children: <Widget>[
time.hours == null ? getTimeDigit("00") : getTimeDigit(time.hours! < 10 ? "0${time.hours.toString()}" : time.hours.toString()),
getTimeText(LocaleKeys.hours.tr()),
],
),
buildSeparator(),
Column(
children: <Widget>[
time.min == null ? getTimeDigit("00") : getTimeDigit(time.min! < 10 ? "0${time.min.toString()}" : time.min.toString()),
getTimeText(LocaleKeys.minutes.tr()),
],
),
buildSeparator(),
Column(
children: <Widget>[
time.sec == null ? getTimeDigit("00") : getTimeDigit(time.sec! < 10 ? "0${time.sec.toString()}" : time.sec.toString()),
getTimeText(LocaleKeys.seconds.tr()),
],
),
],
),
);
}
@override
Widget build(BuildContext context) {
return CountdownTimer(
endTime: timeToMarathon,
onEnd: null,
widgetBuilder: (BuildContext context, CurrentRemainingTime? time) {
return buildCountdownTimer(time);
},
);
}
}

@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
@ -11,16 +10,14 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
class BuildCountdownTimer extends StatelessWidget { class CountdownTimerForMainScreen extends StatelessWidget {
final int timeToMarathon; final int timeToMarathon;
final MarathonProvider provider; final MarathonProvider provider;
final int screenFlag;
BuildCountdownTimer({ CountdownTimerForMainScreen({
Key? key, Key? key,
required this.provider, required this.provider,
required this.timeToMarathon, required this.timeToMarathon,
required this.screenFlag,
}) : super(key: key); }) : super(key: key);
final TextStyle styleTextHome = TextStyle( final TextStyle styleTextHome = TextStyle(
@ -60,7 +57,7 @@ class BuildCountdownTimer extends StatelessWidget {
" : ", " : ",
maxFontSize: 24, maxFontSize: 24,
minFontSize: 20, minFontSize: 20,
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, style: styleDigitHome,
); );
} }
@ -69,7 +66,7 @@ class BuildCountdownTimer extends StatelessWidget {
text, text,
maxFontSize: 24, maxFontSize: 24,
minFontSize: 20, minFontSize: 20,
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, style: styleDigitHome,
); );
} }
@ -78,7 +75,7 @@ class BuildCountdownTimer extends StatelessWidget {
text, text,
minFontSize: 7, minFontSize: 7,
maxFontSize: 8, maxFontSize: 8,
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, style: styleTextHome,
); );
} }
@ -124,14 +121,9 @@ class BuildCountdownTimer extends StatelessWidget {
Widget buildCountdownTimer(CurrentRemainingTime? time) { Widget buildCountdownTimer(CurrentRemainingTime? time) {
if (time == null) { if (time == null) {
if (!provider.itsMarathonTime) {
scheduleMicrotask(() {
provider.itsMarathonTime = true;
});
}
return buildEmptyWidget(); return buildEmptyWidget();
} }
return Directionality( return Directionality(
textDirection: ui.TextDirection.ltr, textDirection: ui.TextDirection.ltr,
child: Row( child: Row(

@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:math' as math; import 'dart:math' as math;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -14,9 +15,13 @@ import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer_main_screen.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
// It is used to pass a dummy time to test Marathon
int dummyTime = DateTime.now().millisecondsSinceEpoch + 8690;
class MarathonBanner extends StatelessWidget { class MarathonBanner extends StatelessWidget {
final bool isMarathonUpcoming; final bool isMarathonUpcoming;
@ -180,11 +185,160 @@ class MarathonBanner extends StatelessWidget {
); );
} }
Widget getNoUpcomingMarathonWidget(BuildContext context) {
return Container(
decoration: MyDecorations.shadowDecoration,
height: isTablet ? MediaQuery.of(context).size.height * 0.17 : MediaQuery.of(context).size.height * 0.11,
clipBehavior: Clip.antiAlias,
child: Stack(
children: <Widget>[
Transform(
alignment: Alignment.center,
transform: Matrix4.rotationY(
AppState().isArabic(context) ? math.pi : 0,
),
child: SvgPicture.asset(
"assets/images/marathon_banner_bg.svg",
fit: BoxFit.fill,
width: double.infinity,
),
),
AppState().isArabic(context)
? Positioned(
right: -15,
top: -10,
child: Transform.rotate(
angle: 10,
child: Container(
width: isTablet ? 70 : 65,
height: isTablet ? 40 : 32,
color: MyColors.darkDigitColor,
),
),
)
: Positioned(
left: -20,
top: -10,
child: Transform.rotate(
angle: 15,
child: Container(
width: isTablet ? 70 : 65,
height: isTablet ? 40 : 32,
color: MyColors.darkDigitColor,
),
),
),
SizedBox(
width: double.infinity,
height: double.infinity,
child: Row(
children: <Widget>[
const Expanded(
flex: 3,
child: SizedBox(
width: double.infinity,
height: double.infinity,
),
),
Expanded(
flex: AppState().isArabic(context) ? 4 : 5,
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
AppState().isArabic(context) ? 0.height : 5.height,
Text(
LocaleKeys.noUpcoming.tr(),
style: TextStyle(
fontSize: isTablet ? 20 : 11,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w600,
color: MyColors.white.withOpacity(0.83),
letterSpacing: -0.4,
),
),
Text(
LocaleKeys.brainMarathon.tr(),
style: TextStyle(
fontStyle: FontStyle.italic,
fontSize: isTablet ? 30 : 19,
fontWeight: FontWeight.bold,
color: MyColors.white.withOpacity(0.83),
height: 32 / 22,
),
),
],
).paddingOnly(
left: AppState().isArabic(context) ? 12 : 3,
right: AppState().isArabic(context) ? 3 : 12,
)
],
),
),
),
],
),
),
AppState().isArabic(context)
? Align(
alignment: Alignment.topRight,
child: SizedBox(
height: isTablet ? 30 : 20,
width: isTablet ? 45 : 35,
child: Transform.rotate(
angle: math.pi / 4.5,
child: Text(
LocaleKeys.brainMarathon.tr(),
textAlign: TextAlign.center,
maxLines: 2,
style: TextStyle(
color: MyColors.white,
fontWeight: FontWeight.bold,
fontSize: isTablet ? 8 : 6,
height: 1.2,
),
),
),
),
).paddingOnly(top: 5)
: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: isTablet ? 30 : 20,
width: isTablet ? 45 : 35,
child: Transform.rotate(
angle: -math.pi / 4.5,
child: Text(
LocaleKeys.brainMarathon.tr(),
textAlign: TextAlign.center,
maxLines: 2,
style: TextStyle(
color: MyColors.kWhiteColor,
fontWeight: FontWeight.bold,
fontSize: isTablet ? 8 : 6,
height: 1.2,
),
),
),
),
).paddingOnly(top: 5),
],
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
MarathonProvider provider = context.read<MarathonProvider>(); MarathonProvider provider = context.read<MarathonProvider>();
return provider.isPrivilegedWithMarathon return !provider.isPrivilegedWithMarathon
? getUnPrivilegedMarathon(context) ? getUnPrivilegedMarathon(context)
: provider.marathonDetailModel.startTime != null : provider.marathonDetailModel.startTime != null
? Container( ? Container(
@ -276,10 +430,10 @@ class MarathonBanner extends StatelessWidget {
), ),
), ),
isTablet ? 10.height : 3.height, isTablet ? 10.height : 3.height,
BuildCountdownTimer( CountdownTimerForMainScreen(
timeToMarathon: DateTime.parse(provider.marathonDetailModel.startTime!).millisecondsSinceEpoch, timeToMarathon: DateTime.parse(provider.marathonDetailModel.startTime!).millisecondsSinceEpoch,
// timeToMarathon: dummyTime,
provider: provider, provider: provider,
screenFlag: 0,
), ),
], ],
).paddingOnly( ).paddingOnly(
@ -357,7 +511,7 @@ class MarathonBanner extends StatelessWidget {
).onPress(() async { ).onPress(() async {
int remainingTimeInMinutes = DateTime.parse(provider.marathonDetailModel.startTime!).difference(DateTime.now()).inMinutes; int remainingTimeInMinutes = DateTime.parse(provider.marathonDetailModel.startTime!).difference(DateTime.now()).inMinutes;
if (remainingTimeInMinutes > 2) { if (remainingTimeInMinutes > 2 && provider.marathonDetailModel.sponsors != null && provider.marathonDetailModel.sponsors!.isNotEmpty) {
Utils.showLoading(context); Utils.showLoading(context);
try { try {
await provider.initializeVideoPlayer().then((_) { await provider.initializeVideoPlayer().then((_) {
@ -367,7 +521,7 @@ class MarathonBanner extends StatelessWidget {
}); });
} catch (e) { } catch (e) {
if (kDebugMode) { if (kDebugMode) {
print("Error in VideoPlayer: ${e.toString()}"); log("Error in VideoPlayer: ${e.toString()}");
} }
Utils.hideLoading(context); Utils.hideLoading(context);
Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); Navigator.pushNamed(context, AppRoutes.marathonIntroScreen);
@ -376,8 +530,7 @@ class MarathonBanner extends StatelessWidget {
Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); Navigator.pushNamed(context, AppRoutes.marathonIntroScreen);
} }
}), }),
// );
) )
: const SizedBox(); : getNoUpcomingMarathonWidget(context);
} }
} }

@ -36,9 +36,9 @@ class MarathonDetailsCard extends StatelessWidget {
) )
], ],
), ),
if (provider.marathonDetailModel.sponsors != null) ...<Widget>[ if (provider.marathonDetailModel.sponsors != null && provider.marathonDetailModel.sponsors!.isNotEmpty) ...<Widget>[
5.height, 5.height,
provider.marathonDetailModel.sponsors?.first.sponsorPrizes != null provider.marathonDetailModel.sponsors!.first.sponsorPrizes != null
? Row( ? Row(
children: <Widget>[ children: <Widget>[
"${LocaleKeys.prize.tr()} ".toText16(color: MyColors.grey77Color, isBold: true), "${LocaleKeys.prize.tr()} ".toText16(color: MyColors.grey77Color, isBold: true),
@ -59,12 +59,12 @@ class MarathonDetailsCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Image.network( Image.network(
ApiConsts.marathonBaseUrlServices + provider.marathonDetailModel.sponsors!.first.image!, ApiConsts.marathonBaseUrlServices + provider.marathonDetailModel.sponsors!.first.logo!,
height: 50, height: 50,
width: 150, width: 150,
fit: BoxFit.contain, fit: BoxFit.contain,
errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
return const Center(); return Image.asset("assets/images/logos/main_mohemm_logo.png", height: 50, width: 150);
}, },
) )
], ],

@ -43,7 +43,7 @@ class MarathonFooter extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DefaultButton( return DefaultButton(
LocaleKeys.joinMarathon.tr(), LocaleKeys.joinMarathon.tr(),
!provider.itsMarathonTime ? () => provider.onJoinMarathonPressed(context) : null, provider.isButtonEnabled ? () => provider.onJoinMarathonPressed(context) : null,
).insideContainer; ).insideContainer;
} }
} }

@ -42,9 +42,13 @@ class MarathonProgressContainer extends StatelessWidget {
stepper(provider.currentQuestionNumber, provider.answerStatusesList, provider.marathonDetailModel.totalQuestions!, provider.isUserOutOfGame), stepper(provider.currentQuestionNumber, provider.answerStatusesList, provider.marathonDetailModel.totalQuestions!, provider.isUserOutOfGame),
8.height, 8.height,
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
"${provider.currentQuestionNumber == 1 ? 0 : (((provider.currentQuestionNumber - 1) / provider.marathonDetailModel.totalQuestions!) * 100).toInt()}% ${LocaleKeys.completed.tr()}" "${provider.currentQuestionNumber == 1 ? 0 : (((provider.currentQuestionNumber - 1) / provider.marathonDetailModel.totalQuestions!) * 100).toInt()}% ${LocaleKeys.completed.tr()}"
.toText14(), .toText14(),
provider.isUserOutOfGame
? LocaleKeys.youAreOutOfContest.tr().toText14(color: MyColors.redColor)
: const SizedBox(),
], ],
), ),
], ],

@ -1,7 +1,9 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/decorations_helper.dart'; import 'package:mohem_flutter_app/classes/decorations_helper.dart';
import 'package:mohem_flutter_app/classes/lottie_consts.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/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
@ -20,7 +22,6 @@ class _QualifiersContainerState extends State<QualifiersContainer> {
@override @override
void initState() { void initState() {
widget.provider.startTimerForWinnerSelection(); widget.provider.startTimerForWinnerSelection();
widget.provider.callGetSelectedWinnersApi();
super.initState(); super.initState();
} }
@ -42,7 +43,16 @@ class _QualifiersContainerState extends State<QualifiersContainer> {
], ],
), ),
10.height, 10.height,
Row( widget.provider.isGettingQualifiers
? Container(
alignment: Alignment.centerLeft,
child: Lottie.asset(
MyLottieConsts.loadingLottie,
width: 60,
fit: BoxFit.fill,
),
)
: Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[ children: <Widget>[
widget.provider.totalQualifiers != null ? widget.provider.totalQualifiers.toString().toText30(color: MyColors.greenColor, isBold: true) : const SizedBox(), widget.provider.totalQualifiers != null ? widget.provider.totalQualifiers.toString().toText30(color: MyColors.greenColor, isBold: true) : const SizedBox(),

@ -9,7 +9,8 @@ import 'package:mohem_flutter_app/classes/lottie_consts.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.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/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer_detail_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_banner.dart';
class MarathonTimerCard extends StatelessWidget { class MarathonTimerCard extends StatelessWidget {
@ -43,7 +44,11 @@ class MarathonTimerCard extends StatelessWidget {
], ],
), ),
Lottie.asset(MyLottieConsts.hourGlassLottie, height: 200), Lottie.asset(MyLottieConsts.hourGlassLottie, height: 200),
BuildCountdownTimer(timeToMarathon: timeToMarathon, provider: provider, screenFlag: 1), CountdownTimerForDetailScreen(
// timeToMarathon: dummyTime,
timeToMarathon: timeToMarathon,
provider: provider,
),
], ],
), ),
); );

@ -65,7 +65,6 @@ class CardContent extends StatelessWidget {
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Container( Container(
height: 78,
width: double.infinity, width: double.infinity,
decoration: const BoxDecoration( decoration: const BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
@ -84,9 +83,9 @@ class CardContent extends StatelessWidget {
), ),
child: Center( child: Center(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 13), padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 15),
child: Text( child: Text(
AppState().isArabic(context) ? provider.currentQuestion.titleAr ?? "" : provider.currentQuestion.titleEn ?? "", AppState().isArabic(context) ? "${provider.currentQuestion.titleAr}" ?? "" : provider.currentQuestion.titleEn ?? "",
style: const TextStyle( style: const TextStyle(
color: MyColors.white, color: MyColors.white,
fontSize: 16, fontSize: 16,
@ -110,7 +109,7 @@ class AnswerContent extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
MarathonProvider provider = context.watch<MarathonProvider>(); MarathonProvider provider = context.watch<MarathonProvider>();
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 31, horizontal: 13), padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 13),
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: MyColors.kWhiteColor, color: MyColors.kWhiteColor,
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
@ -126,7 +125,11 @@ class AnswerContent extends StatelessWidget {
return AnswerTileForText( return AnswerTileForText(
index: index, index: index,
onAnswerTapped: () { onAnswerTapped: () {
if (provider.totalCurrentQuestionTime - provider.currentGapTime <= 1) {
null;
} else {
provider.updateCurrentQuestionOptionStatus(QuestionsOptionStatus.selected, index); provider.updateCurrentQuestionOptionStatus(QuestionsOptionStatus.selected, index);
}
}, },
); );
}, },
@ -169,7 +172,7 @@ class AnswerTileForText extends StatelessWidget {
child: Center( child: Center(
child: (AppState().isArabic(context) ? provider.currentQuestion.questionOptions![index].titleAr! : provider.currentQuestion.questionOptions![index].titleEn!) child: (AppState().isArabic(context) ? provider.currentQuestion.questionOptions![index].titleAr! : provider.currentQuestion.questionOptions![index].titleEn!)
.toText16(color: provider.isUserOutOfGame ? MyColors.darkTextColor : getAnswerTextColor(provider.currentQuestion.questionOptions![index].optionStatus!)) .toText16(color: provider.isUserOutOfGame ? MyColors.darkTextColor : getAnswerTextColor(provider.currentQuestion.questionOptions![index].optionStatus!))
.paddingOnly(top: 17, bottom: 17), .paddingOnly(top: 13, bottom: 13),
), ),
), ),
); );

@ -1,93 +0,0 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:lottie/lottie.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/decorations_helper.dart';
import 'package:mohem_flutter_app/classes/lottie_consts.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/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
class WinnerScreen extends StatelessWidget {
const WinnerScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: MyColors.backgroundColor,
appBar: AppBarWidget(context, title: LocaleKeys.brainMarathon.tr()),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
60.height,
Container(
width: double.infinity,
decoration: MyDecorations.shadowDecoration,
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
child: Column(
children: <Widget>[
SizedBox(
height: 200,
child: Stack(
children: <Widget>[
Lottie.asset(
MyLottieConsts.celebrate1Lottie,
height: 200,
),
Lottie.asset(
MyLottieConsts.celebrate2Lottie,
height: 200,
),
],
),
),
26.height,
SizedBox(
height: 50,
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: SvgPicture.asset(
"assets/images/winner_ribbon.svg",
height: 50,
),
),
Align(
alignment: Alignment.center,
child: "WINNER".toText32(color: MyColors.white, isBold: true).paddingOnly(top: 07),
)
],
),
),
12.height,
"Muhammad Shrouff".toText22(color: MyColors.grey3AColor),
"837436".toText22(color: MyColors.grey57Color),
80.height,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
LocaleKeys.sponsoredBy.tr().toText14(color: MyColors.grey77Color),
" Extra".toText14(color: MyColors.darkTextColor, isBold: true),
],
),
5.height,
Image.asset(
"assets/images/logos/main_mohemm_logo.png",
height: 40,
fit: BoxFit.fill,
width: 150,
)
],
),
).paddingOnly(left: 21, right: 21),
10.height,
],
),
),
);
}
}

@ -57,7 +57,7 @@ class _DynamicInputScreenState extends State<DynamicInputScreen> {
} }
void validateTransaction() async { void validateTransaction() async {
try { // try {
Utils.showLoading(context); Utils.showLoading(context);
List<Map<String, dynamic>> values = getEitDffStructureList!.map((e) { List<Map<String, dynamic>> values = getEitDffStructureList!.map((e) {
String tempVar = e.eSERVICESDV?.pIDCOLUMNNAME ?? ""; String tempVar = e.eSERVICESDV?.pIDCOLUMNNAME ?? "";
@ -98,10 +98,10 @@ class _DynamicInputScreenState extends State<DynamicInputScreen> {
Utils.showLoading(context); Utils.showLoading(context);
await LeaveBalanceApiClient().cancelHrTransaction(submitEITTransactionList.pTRANSACTIONID!); await LeaveBalanceApiClient().cancelHrTransaction(submitEITTransactionList.pTRANSACTIONID!);
Utils.hideLoading(context); Utils.hideLoading(context);
} catch (ex) { // } catch (ex) {
Utils.hideLoading(context); // Utils.hideLoading(context);
Utils.handleException(ex, context, null); // Utils.handleException(ex, context, null);
} // }
} }
String dESCFLEXCONTEXTCODE = ""; String dESCFLEXCONTEXTCODE = "";

@ -81,7 +81,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
value: 0, name: 'COC', fullName: LocaleKeys.itemCreation.tr(), active: false, color: [Color(0xff787299), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'COC', disable: true) value: 0, name: 'COC', fullName: LocaleKeys.itemCreation.tr(), active: false, color: [Color(0xff787299), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'COC', disable: true)
]; ];
int workListItemIndex = 0; int? workListItemIndex;
List<WorkListResponseModel>? workList; List<WorkListResponseModel>? workList;
int pageNumber = 1; int pageNumber = 1;
@ -99,7 +99,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
super.initState(); super.initState();
providerData = Provider.of<DashboardProviderModel>(context, listen: false); providerData = Provider.of<DashboardProviderModel>(context, listen: false);
calculateCounter(); calculateCounter();
getWorkList(); if (workListItemIndex != null) getWorkList();
} }
void calculateCounter() { void calculateCounter() {
@ -115,11 +115,17 @@ class _WorkListScreenState extends State<WorkListScreen> {
} }
} }
}); });
workListItemTypes.removeWhere((element) => element.value == 0);
if (workListItemTypes.isNotEmpty) {
workListItemIndex = 0;
} else {
workListItemIndex = null;
}
} }
void verifyWorkListCounter() { void verifyWorkListCounter() {
workListItemTypes.forEach((workListElement) { workListItemTypes.forEach((workListElement) {
if (workListElement.key == "ITG" && workListItemTypes[workListItemIndex].key == "ITG") { if (workListElement.key == "ITG" && workListItemTypes[workListItemIndex!].key == "ITG") {
workListElement.value = providerData.itgFormsModel?.totalCount ?? 0; workListElement.value = providerData.itgFormsModel?.totalCount ?? 0;
if ((AppState().requestAllList?.length ?? 0) != workListElement.value) { if ((AppState().requestAllList?.length ?? 0) != workListElement.value) {
workListElement.value = AppState().requestAllList?.length ?? 0; workListElement.value = AppState().requestAllList?.length ?? 0;
@ -132,7 +138,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
workListElement.value = providerData.cocFinalCount; workListElement.value = providerData.cocFinalCount;
} else { } else {
providerData.getOpenNotificationsList?.forEach((element) { providerData.getOpenNotificationsList?.forEach((element) {
if ((element.itemType == workListItemTypes[workListItemIndex].key) && element.itemType == workListElement.key) { if ((element.itemType == workListItemTypes[workListItemIndex!].key) && element.itemType == workListElement.key) {
if ((AppState().workList?.length ?? 0) != (element.openNtfNumber ?? 0)) { if ((AppState().workList?.length ?? 0) != (element.openNtfNumber ?? 0)) {
workListElement.value = AppState().workList?.length ?? 0; workListElement.value = AppState().workList?.length ?? 0;
providerData.workListCounter = providerData.workListCounter - ((element.openNtfNumber ?? 0) - (AppState().workList?.length ?? 0)); providerData.workListCounter = providerData.workListCounter - ((element.openNtfNumber ?? 0) - (AppState().workList?.length ?? 0));
@ -162,7 +168,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
Future<void> getWorkList({bool showLoading = true}) async { Future<void> getWorkList({bool showLoading = true}) async {
try { try {
if (showLoading) Utils.showLoading(context); if (showLoading) Utils.showLoading(context);
if (workListItemTypes[workListItemIndex].key == "ITG") { if (workListItemTypes[workListItemIndex!].key == "ITG") {
itgFormsModel = await WorkListApiClient().getITGTaskCountRequestType(); itgFormsModel = await WorkListApiClient().getITGTaskCountRequestType();
List<RequestDetails> requestAllList = []; List<RequestDetails> requestAllList = [];
for (int i = 0; i < (itgFormsModel?.requestType!.length ?? 0); i++) { for (int i = 0; i < (itgFormsModel?.requestType!.length ?? 0); i++) {
@ -178,7 +184,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
} }
} else { } else {
itgRequestTypeIndex = null; itgRequestTypeIndex = null;
workList = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex].key, pNotificationType.toString()); workList = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex!].key, pNotificationType.toString());
AppState().setWorkList = workList; AppState().setWorkList = workList;
} }
if (showLoading) Utils.hideLoading(context); if (showLoading) Utils.hideLoading(context);
@ -216,7 +222,9 @@ class _WorkListScreenState extends State<WorkListScreen> {
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.workList.tr(), showWorkListSettingButton: true), appBar: AppBarWidget(context, title: LocaleKeys.workList.tr(), showWorkListSettingButton: true),
body: SizedBox( body: workListItemIndex == null
? Utils.getNoDataWidget(context)
: SizedBox(
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
child: Column( child: Column(
@ -262,7 +270,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
workListItemTypes[workListItemIndex].fullName.toSectionHeading().paddingOnly(left: 21, right: 21), workListItemTypes[workListItemIndex!].fullName.toSectionHeading().paddingOnly(left: 21, right: 21),
LocaleKeys.advancedSearch.tr().toText14(isUnderLine: true, color: MyColors.textMixColor).onPress(() { LocaleKeys.advancedSearch.tr().toText14(isUnderLine: true, color: MyColors.textMixColor).onPress(() {
openBottomSheet(context); openBottomSheet(context);
}).paddingOnly(left: 21, right: 21) }).paddingOnly(left: 21, right: 21)
@ -311,7 +319,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) { itemBuilder: (context, index) {
return itgRowItem(workListItemTypes[workListItemIndex], itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails![index], index); return itgRowItem(workListItemTypes[workListItemIndex!], itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails![index], index);
}, },
separatorBuilder: (context, index) => 12.height, separatorBuilder: (context, index) => 12.height,
itemCount: itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails?.length ?? 0, itemCount: itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails?.length ?? 0,
@ -326,7 +334,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) { itemBuilder: (context, index) {
return rowItem(workListItemTypes[workListItemIndex], workList![index], index); return rowItem(workListItemTypes[workListItemIndex!], workList![index], index);
}, },
separatorBuilder: (context, index) => 12.height, separatorBuilder: (context, index) => 12.height,
itemCount: workList?.length ?? 0, itemCount: workList?.length ?? 0,
@ -350,8 +358,11 @@ class _WorkListScreenState extends State<WorkListScreen> {
if (shouldReloadData.toString() == "delegate_reload") { if (shouldReloadData.toString() == "delegate_reload") {
providerData.itgFormsModel!.totalCount = providerData.itgFormsModel!.totalCount! - 1; providerData.itgFormsModel!.totalCount = providerData.itgFormsModel!.totalCount! - 1;
calculateCounter(); calculateCounter();
setState(() {});
if (workListItemIndex != null) {
getWorkList(); getWorkList();
} }
}
// workList!.remove(data); // workList!.remove(data);
// AppState().setWorkList = workList; // AppState().setWorkList = workList;
// if (data.iTEMTYPE == "ITG") { // if (data.iTEMTYPE == "ITG") {

@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart'; import 'package:mohem_flutter_app/api/worklist/worklist_api_client.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';
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';
@ -26,6 +25,7 @@ class _WorklistSettingsState extends State<WorklistSettings> {
List<GetUserItemTypesList> getUserItemTypesList = []; List<GetUserItemTypesList> getUserItemTypesList = [];
UpdateUserItemTypesList? updateUserItemTypesList; UpdateUserItemTypesList? updateUserItemTypesList;
@override
void initState() { void initState() {
super.initState(); super.initState();
userItemTypesList(); userItemTypesList();
@ -47,13 +47,17 @@ class _WorklistSettingsState extends State<WorklistSettings> {
try { try {
Utils.showLoading(context); Utils.showLoading(context);
List<Map<String, dynamic>> itemList = []; List<Map<String, dynamic>> itemList = [];
for (var element in getUserItemTypesList) { for (int index = 0; index < getUserItemTypesList.length; index++) {
itemList.add(UpdateUserTypesList(itemID: element.uSERITEMTYPEID, pITEMTYPE: element.iTEMTYPE, pFYAENABLEDFALG: element.fYAENABLEDFALG, pFYIENABLEDFALG: element.fYIENABLEDFLAG).toJson()); itemList.add(UpdateUserTypesList(
itemID: index,
pITEMTYPE: getUserItemTypesList[index].iTEMTYPE,
pFYAENABLEDFALG: getUserItemTypesList[index].fYAENABLEDFALG,
pFYIENABLEDFALG: getUserItemTypesList[index].fYIENABLEDFLAG)
.toJson());
} }
updateUserItemTypesList = await WorkListApiClient().updateUserItemTypes(itemList); updateUserItemTypesList = await WorkListApiClient().updateUserItemTypes(itemList);
Utils.hideLoading(context); Utils.hideLoading(context);
Navigator.pushNamed(context, AppRoutes.workList); Navigator.pop(context);
setState(() {});
} catch (ex) { } catch (ex) {
Utils.hideLoading(context); Utils.hideLoading(context);
Utils.handleException(ex, context, null); Utils.handleException(ex, context, null);
@ -86,22 +90,12 @@ class _WorklistSettingsState extends State<WorklistSettings> {
], ],
), ),
const Divider(color: MyColors.greyA5Color), const Divider(color: MyColors.greyA5Color),
SingleChildScrollView( ListView.separated(
scrollDirection: Axis.vertical,
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true, shrinkWrap: true,
physics: ScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemCount: getUserItemTypesList == null ? 0 : getUserItemTypesList.length, itemCount: getUserItemTypesList.length,
itemBuilder: (BuildContext context, int index) { separatorBuilder: (cxt, index) => 1.divider,
return Column(children: [ itemBuilder: (BuildContext context, int index) => customSwitch(getUserItemTypesList[index]),
customSwitch(getUserItemTypesList[index]),
Divider(
color: MyColors.greyC4Color,
thickness: 0.5,
),
]);
}),
), ),
], ],
).expanded, ).expanded,
@ -109,41 +103,45 @@ class _WorklistSettingsState extends State<WorklistSettings> {
updateUserItem(); updateUserItem();
}).insideContainer, }).insideContainer,
], ],
)); ),
);
} }
Widget customSwitch(GetUserItemTypesList list) { Widget customSwitch(GetUserItemTypesList list) {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 21), padding: const EdgeInsets.only(top: 8, bottom: 8),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( list.iTEMTYPE!.toText16(),
list.iTEMTYPE.toString(),
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: MyColors.blackColor),
),
const Spacer(), const Spacer(),
Row( Row(
children: [ children: [
CupertinoSwitch( Transform.scale(
scale: 0.8,
child: CupertinoSwitch(
trackColor: MyColors.grey57Color, trackColor: MyColors.grey57Color,
activeColor: MyColors.textMixColor, activeColor: MyColors.textMixColor,
value: list?.fYAENABLEDFALG == 'Y' ? true : false, value: list.fYAENABLEDFALG == 'Y',
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
list?.fYAENABLEDFALG = value == true ? 'Y' : 'N'; list.fYAENABLEDFALG = value ? 'Y' : 'N';
}); });
}), }),
CupertinoSwitch( ),
Transform.scale(
scale: 0.8,
child: CupertinoSwitch(
trackColor: MyColors.grey57Color, trackColor: MyColors.grey57Color,
activeColor: MyColors.textMixColor, activeColor: MyColors.textMixColor,
value: list?.fYIENABLEDFLAG == 'Y' ? true : false, value: list.fYIENABLEDFLAG == 'Y',
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
// list.isFYI = value; list.fYIENABLEDFLAG = value ? 'Y' : 'N';
list?.fYIENABLEDFLAG = value == true ? 'Y' : 'N';
}); });
}), },
),
),
], ],
) )
], ],

@ -73,7 +73,7 @@ class _BalancesDashboardWidgetState extends State<BalancesDashboardWidget> {
]; ];
} else { } else {
chartModelList = [ chartModelList = [
PieChartModel(LocaleKeys.adult.tr(), accrualList[1].accrualNetEntitlement ?? 0, MyColors.textMixColor, titleAppend: ""), PieChartModel(LocaleKeys.adult.tr(), accrualList[1].accrualNetEntitlement?.toDouble() ?? 0, MyColors.textMixColor, titleAppend: ""),
PieChartModel(LocaleKeys.child.tr(), accrualList[2].accrualNetEntitlement?.toDouble() ?? 0, MyColors.backgroundBlackColor, titleAppend: ""), PieChartModel(LocaleKeys.child.tr(), accrualList[2].accrualNetEntitlement?.toDouble() ?? 0, MyColors.backgroundBlackColor, titleAppend: ""),
PieChartModel(LocaleKeys.infants.tr(), accrualList[3].accrualNetEntitlement?.toDouble() ?? 0, MyColors.pinkColor, titleAppend: ""), PieChartModel(LocaleKeys.infants.tr(), accrualList[3].accrualNetEntitlement?.toDouble() ?? 0, MyColors.pinkColor, titleAppend: ""),
]; ];
@ -101,7 +101,7 @@ class _BalancesDashboardWidgetState extends State<BalancesDashboardWidget> {
ticketBalanceAccrualList = Provider.of<DashboardProviderModel>(context, listen: false).accrualList ?? []; ticketBalanceAccrualList = Provider.of<DashboardProviderModel>(context, listen: false).accrualList ?? [];
if (ticketBalanceAccrualList!.isNotEmpty) { if (ticketBalanceAccrualList!.isNotEmpty) {
chartModelList = [ chartModelList = [
PieChartModel(LocaleKeys.adult.tr(), ticketBalanceAccrualList![1].accrualNetEntitlement ?? 0, MyColors.textMixColor, titleAppend: ""), PieChartModel(LocaleKeys.adult.tr(), ticketBalanceAccrualList![1].accrualNetEntitlement?.toDouble() ?? 0, MyColors.textMixColor, titleAppend: ""),
PieChartModel(LocaleKeys.child.tr(), ticketBalanceAccrualList![2].accrualNetEntitlement?.toDouble() ?? 0, MyColors.backgroundBlackColor, titleAppend: ""), PieChartModel(LocaleKeys.child.tr(), ticketBalanceAccrualList![2].accrualNetEntitlement?.toDouble() ?? 0, MyColors.backgroundBlackColor, titleAppend: ""),
PieChartModel(LocaleKeys.infants.tr(), ticketBalanceAccrualList![3].accrualNetEntitlement?.toDouble() ?? 0, MyColors.pinkColor, titleAppend: ""), PieChartModel(LocaleKeys.infants.tr(), ticketBalanceAccrualList![3].accrualNetEntitlement?.toDouble() ?? 0, MyColors.pinkColor, titleAppend: ""),
]; ];
@ -185,7 +185,7 @@ class _BalancesDashboardWidgetState extends State<BalancesDashboardWidget> {
Widget getChart(List<PieChartModel> chartModelList) { Widget getChart(List<PieChartModel> chartModelList) {
List<Color> _colorList = chartModelList.map((e) => e.color).toList(); List<Color> _colorList = chartModelList.map((e) => e.color).toList();
return PieChart( return PieChart(
dataMap: {for (var e in chartModelList) e.title: e.parsedValue}, dataMap: {for (var e in chartModelList) e.title: e.value},
animationDuration: const Duration(milliseconds: 800), animationDuration: const Duration(milliseconds: 800),
chartRadius: MediaQuery.of(context).size.width / 3.2, chartRadius: MediaQuery.of(context).size.width / 3.2,
colorList: _colorList, colorList: _colorList,

@ -94,7 +94,7 @@ class _SearchEmployeeBottomSheetState extends State<SearchEmployeeBottomSheet> {
searchText, searchText,
int.parse(AppState().chatDetails!.response!.id.toString()), int.parse(AppState().chatDetails!.response!.id.toString()),
); );
chatUsersList!.removeWhere((element) => element.id == AppState().chatDetails!.response!.id); chatUsersList!.removeWhere((ChatUser element) => element.id == AppState().chatDetails!.response!.id);
Utils.hideLoading(context); Utils.hideLoading(context);
setState(() {}); setState(() {});
} catch (e) { } catch (e) {

@ -161,16 +161,16 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
); );
} else { } else {
bool status = await model.fetchAttendanceTracking(context); bool status = await model.fetchAttendanceTracking(context);
if (Platform.isIOS) await Future.delayed(const Duration(seconds: 3));
Utils.hideLoading(context); Utils.hideLoading(context);
showMDialog( showMDialog(
context, context,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
isDismissable: false, isDismissable: true,
child: SuccessDialog(widget.isFromDashboard), child: SuccessDialog(widget.isFromDashboard),
); );
} }
} catch (ex) { } catch (ex) {
print(ex);
Utils.hideLoading(context); Utils.hideLoading(context);
Utils.handleException(ex, context, (msg) { Utils.handleException(ex, context, (msg) {
Utils.confirmDialog(context, msg); Utils.confirmDialog(context, msg);
@ -239,7 +239,6 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
child: SuccessDialog(widget.isFromDashboard), child: SuccessDialog(widget.isFromDashboard),
); );
} catch (ex) { } catch (ex) {
print("performWifiAttendance: " + ex.toString());
await closeWifiRequest(); await closeWifiRequest();
Utils.hideLoading(context); Utils.hideLoading(context);
Utils.handleException(ex, context, (msg) { Utils.handleException(ex, context, (msg) {
@ -274,7 +273,7 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
showMDialog( showMDialog(
context, context,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
isDismissable: false, isDismissable: true,
child: SuccessDialog(widget.isFromDashboard), child: SuccessDialog(widget.isFromDashboard),
); );
} catch (ex) { } catch (ex) {

@ -132,7 +132,7 @@ class ServicesHeaderShimmer extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
"Other".tr().toText10().toShimmer(), LocaleKeys.otherCharges.tr().toText10().toShimmer(),
6.height, 6.height,
LocaleKeys.services.tr().toText12(isBold: true).toShimmer(), LocaleKeys.services.tr().toText12(isBold: true).toShimmer(),
], ],

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1 version: 3.1.5+300015
environment: environment:
sdk: ">=2.16.0 <3.0.0" sdk: ">=2.16.0 <3.0.0"
@ -94,9 +94,8 @@ dependencies:
camera: ^0.10.0+4 camera: ^0.10.0+4
#Chat Voice Message Recoding & Play #Chat Voice Message Recoding & Play
# record: ^4.4.3
audio_waveforms: ^0.1.5+1 audio_waveforms: ^0.1.5+1
# animated_text_kit: ^4.2.2 rxdart: ^0.27.7
#Encryption #Encryption
flutter_des: ^2.1.0 flutter_des: ^2.1.0
@ -106,6 +105,7 @@ dependencies:
safe_device: ^1.1.2 safe_device: ^1.1.2
flutter_layout_grid: ^2.0.1 flutter_layout_grid: ^2.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter

Loading…
Cancel
Save