Merge branch 'master' into fatima

# Conflicts:
#	lib/classes/consts.dart
#	lib/ui/leave_balance/add_leave_balance_screen.dart
fatima
Fatimah Alshammari 3 years ago
commit 85be372ad8

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

@ -500,5 +500,9 @@
"codeExpire": "انتهت صلاحية رمز التحقق", "codeExpire": "انتهت صلاحية رمز التحقق",
"typeheretoreply": "اكتب هنا للرد", "typeheretoreply": "اكتب هنا للرد",
"favorite": "مفضلتي", "favorite": "مفضلتي",
"searchfromchat": "البحث من الدردشة" "searchfromchat": "البحث من الدردشة",
"yourAnswerCorrect": "إجابتك صحيحة",
"youMissedTheQuestion": "فاتك !! أنت خارج اللعبة. لكن يمكنك المتابعة.",
"wrongAnswer": "إجابة خاطئة! أنت خارج اللعبة. لكن يمكنك المتابعة."
} }

@ -500,6 +500,9 @@
"allQuestionsCorrect": "You have answered all questions correct", "allQuestionsCorrect": "You have answered all questions correct",
"typeheretoreply": "Type here to reply", "typeheretoreply": "Type here to reply",
"favorite" : "My Favorites", "favorite" : "My Favorites",
"searchfromchat": "Search from chat" "searchfromchat": "Search from chat",
"yourAnswerCorrect": "Your answer is correct",
"youMissedTheQuestion": "You Missed !! You are out of the game. But you can follow up.",
"wrongAnswer": "Wrong Answer! You are out of the game. But you can follow up."
} }

5
ios/.gitignore vendored

@ -31,3 +31,8 @@ Runner/GeneratedPluginRegistrant.*
!default.mode2v3 !default.mode2v3
!default.pbxuser !default.pbxuser
!default.perspectivev3 !default.perspectivev3
ios/Podfile
ios/Runner/Runner.entitlements

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.cloudsolutions.mohemm</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudDocuments</string>
</array>
<key>com.apple.developer.networking.HotspotConfiguration</key>
<true/>
<key>com.apple.developer.networking.networkextension</key>
<array/>
<key>com.apple.developer.networking.wifi-info</key>
<true/>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
</array>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>iCloud.com.cloudsolutions.mohemm</string>
</array>
</dict>
</plist>

@ -18,8 +18,7 @@ class APIError {
APIError(this.errorCode, this.errorMessage); APIError(this.errorCode, this.errorMessage);
Map<String, dynamic> toJson() => Map<String, dynamic> toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage};
{'errorCode': errorCode, 'errorMessage': errorMessage};
@override @override
String toString() { String toString() {
@ -54,8 +53,7 @@ APIException _throwAPIException(Response response) {
return APIException(APIException.INTERNAL_SERVER_ERROR); return APIException(APIException.INTERNAL_SERVER_ERROR);
case 444: case 444:
var downloadUrl = response.headers["location"]; var downloadUrl = response.headers["location"];
return APIException(APIException.UPGRADE_REQUIRED, return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl);
arguments: downloadUrl);
default: default:
return APIException(APIException.OTHER); return APIException(APIException.OTHER);
} }
@ -68,13 +66,8 @@ class ApiClient {
factory ApiClient() => _instance; factory ApiClient() => _instance;
Future<U> postJsonForObject<T, U>( Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject,
FactoryConstructor<U> factoryConstructor, String url, T jsonObject, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
{String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0,
bool isFormData = false}) async {
var _headers = {'Accept': 'application/json'}; var _headers = {'Accept': 'application/json'};
if (headers != null && headers.isNotEmpty) { if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers); _headers.addAll(headers);
@ -84,12 +77,7 @@ class ApiClient {
var bodyJson = json.encode(jsonObject); var bodyJson = json.encode(jsonObject);
print("body:$bodyJson"); print("body:$bodyJson");
} }
var response = await postJsonForResponse(url, jsonObject, var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData);
token: token,
queryParameters: queryParameters,
headers: _headers,
retryTimes: retryTimes,
isFormData: isFormData);
// try { // try {
if (!kReleaseMode) { if (!kReleaseMode) {
logger.i("res: " + response.body); logger.i("res: " + response.body);
@ -102,8 +90,7 @@ class ApiClient {
return factoryConstructor(jsonData); return factoryConstructor(jsonData);
} else { } else {
APIError? apiError; APIError? apiError;
apiError = apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage']);
APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage']);
throw APIException(APIException.BAD_REQUEST, error: apiError); throw APIException(APIException.BAD_REQUEST, error: apiError);
} }
// } catch (ex) { // } catch (ex) {
@ -116,11 +103,7 @@ class ApiClient {
} }
Future<Response> postJsonForResponse<T>(String url, T jsonObject, Future<Response> postJsonForResponse<T>(String url, T jsonObject,
{String? token, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0,
bool isFormData = false}) async {
String? requestBody; String? requestBody;
late Map<String, String> stringObj; late Map<String, String> stringObj;
if (jsonObject != null) { if (jsonObject != null) {
@ -134,22 +117,13 @@ class ApiClient {
if (isFormData) { if (isFormData) {
headers = {'Content-Type': 'application/x-www-form-urlencoded'}; headers = {'Content-Type': 'application/x-www-form-urlencoded'};
stringObj = ((jsonObject ?? {}) as Map<String, dynamic>) stringObj = ((jsonObject ?? {}) as Map<String, dynamic>).map((key, value) => MapEntry(key, value?.toString() ?? ""));
.map((key, value) => MapEntry(key, value?.toString() ?? ""));
} }
return await _postForResponse(url, isFormData ? stringObj : requestBody, return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes);
token: token,
queryParameters: queryParameters,
headers: headers,
retryTimes: retryTimes);
} }
Future<Response> _postForResponse(String url, requestBody, Future<Response> _postForResponse(String url, requestBody, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0}) async {
{String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0}) async {
try { try {
var _headers = <String, String>{}; var _headers = <String, String>{};
if (token != null) { if (token != null) {
@ -164,9 +138,7 @@ class ApiClient {
var queryString = new Uri(queryParameters: queryParameters).query; var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString; url = url + '?' + queryString;
} }
var response = var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120));
await _post(Uri.parse(url), body: requestBody, headers: _headers)
.timeout(Duration(seconds: 120));
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
return response; return response;
@ -177,11 +149,7 @@ class ApiClient {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
token: token,
queryParameters: queryParameters,
headers: headers,
retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
} }
@ -189,11 +157,7 @@ class ApiClient {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
token: token,
queryParameters: queryParameters,
headers: headers,
retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
} }
@ -203,39 +167,23 @@ class ApiClient {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
token: token,
queryParameters: queryParameters,
headers: headers,
retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
} }
} }
} }
Future<Response> getJsonForResponse<T>(String url, Future<Response> getJsonForResponse<T>(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0}) async {
{String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0}) async {
if (headers == null) { if (headers == null) {
headers = {'Content-Type': 'application/json'}; headers = {'Content-Type': 'application/json'};
} else { } else {
headers['Content-Type'] = 'application/json'; headers['Content-Type'] = 'application/json';
} }
return await _getForResponse(url, return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes);
token: token,
queryParameters: queryParameters,
headers: headers,
retryTimes: retryTimes);
} }
Future<Response> _getForResponse(String url, Future<Response> _getForResponse(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0}) async {
{String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0}) async {
try { try {
var _headers = <String, String>{}; var _headers = <String, String>{};
if (token != null) { if (token != null) {
@ -250,8 +198,7 @@ class ApiClient {
var queryString = new Uri(queryParameters: queryParameters).query; var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString; url = url + '?' + queryString;
} }
var response = await _get(Uri.parse(url), headers: _headers) var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60));
.timeout(Duration(seconds: 60));
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
return response; return response;
@ -262,11 +209,7 @@ class ApiClient {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
token: token,
queryParameters: queryParameters,
headers: headers,
retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
} }
@ -274,11 +217,7 @@ class ApiClient {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
token: token,
queryParameters: queryParameters,
headers: headers,
retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
} }
@ -288,19 +227,14 @@ class ApiClient {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
token: token,
queryParameters: queryParameters,
headers: headers,
retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
} }
} }
} }
Future<Response> _get(url, {Map<String, String>? headers}) => Future<Response> _get(url, {Map<String, String>? headers}) => _withClient((client) => client.get(url, headers: headers));
_withClient((client) => client.get(url, headers: headers));
bool _certificateCheck(X509Certificate cert, String host, int port) => true; bool _certificateCheck(X509Certificate cert, String host, int port) => true;
@ -314,8 +248,5 @@ class ApiClient {
} }
} }
Future<Response> _post(url, Future<Response> _post(url, {Map<String, String>? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding));
{Map<String, String>? headers, body, Encoding? encoding}) =>
_withClient((client) =>
client.post(url, headers: headers, body: body, encoding: encoding));
} }

@ -0,0 +1,167 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:http/http.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/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/exceptions/api_exception.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user;
import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav;
class ChatApiClient {
static final ChatApiClient _instance = ChatApiClient._internal();
ChatApiClient._internal();
factory ChatApiClient() => _instance;
Future<user.UserAutoLoginModel> getUserLoginToken() async {
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatLoginTokenUrl}externaluserlogin",
{
"employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
"password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG",
},
);
user.UserAutoLoginModel userLoginResponse = user.userAutoLoginModelFromJson(response.body);
return userLoginResponse;
}
Future<List<ChatUser>?> getChatMemberFromSearch(String sName, int cUserId) async {
Response response = await ApiClient().getJsonForResponse(
"${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync/$sName/$cUserId",
token: AppState().chatDetails!.response!.token,
);
return searchUserJsonModel(response.body);
}
List<ChatUser> searchUserJsonModel(String str) => List<ChatUser>.from(json.decode(str).map((x) => ChatUser.fromJson(x)));
Future<ChatUserModel> getRecentChats() async {
try {
Response response = await ApiClient().getJsonForResponse(
"${ApiConsts.chatRecentUrl}getchathistorybyuserid",
token: AppState().chatDetails!.response!.token,
);
return ChatUserModel.fromJson(
json.decode(response.body),
);
} catch (e) {
e as APIException;
if (e.message == "api_common_unauthorized") {
user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse;
getRecentChats();
} else {
Utils.showToast(
userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr",
);
}
}
throw e;
}
}
Future<ChatUserModel> getFavUsers() async {
Response favRes = await ApiClient().getJsonForResponse(
"${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}",
token: AppState().chatDetails!.response!.token,
);
return ChatUserModel.fromJson(
json.decode(favRes.body),
);
}
Future<Response> getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async {
try {
Response response = await ApiClient().getJsonForResponse(
"${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal",
token: AppState().chatDetails!.response!.token,
);
return response;
} catch (e) {
e as APIException;
if (e.message == "api_common_unauthorized") {
user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse;
getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal);
} else {
Utils.showToast(userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr");
}
}
throw e;
}
}
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);
fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body);
return favoriteChatUser;
}
Future<fav.FavoriteChatUser> unFavUser({required int userID, required int targetUserID}) async {
try {
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatFavUser}deleteFavUser",
{"targetUserId": targetUserID, "userId": userID},
token: AppState().chatDetails!.response!.token,
);
fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body);
return favoriteChatUser;
} catch (e) {
e as APIException;
if (e.message == "api_common_unauthorized") {
logger.d("Token Generated On APIIIIII");
user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse;
unFavUser(userID: userID, targetUserID: targetUserID);
} else {
Utils.showToast(userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr");
}
}
throw e;
}
}
Future<StreamedResponse> uploadMedia(String userId, File file) async {
dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload'));
request.fields.addAll({'userId': userId, 'fileSource': '1'});
request.files.add(await MultipartFile.fromPath('files', file.path));
request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'});
StreamedResponse response = await request.send();
return response;
}
// Download File For Chat
Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription}) async {
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatMediaImageUploadUrl}download",
{"fileType": fileTypeDescription, "fileName": fileName, "fileSource": 1},
token: AppState().chatDetails!.response!.token,
);
Uint8List data = Uint8List.fromList(response.bodyBytes);
return data;
}
Future getUsersImages({required List encryptedEmails}) async {
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatUserImages}images",
{
"encryptedEmails": ["/g8Rc+s6eEOdci41PwJuV5dX+gXe51G9OTHzb9ahcVlHCmVvNhxReirudF79+hdxVSkCnQ6wC5DBFV8xnJlC74X6157PxF7mNYrAYuHRgp4="],
"fromClient": true
},
token: AppState().chatDetails!.response!.token,
);
logger.d(response.body);
// Uint8List data = Uint8List.fromList(response.body);
}
}

@ -185,8 +185,22 @@ class DashboardApiClient {
Future<ChatUnreadCovnCountModel> getChatCount() async { Future<ChatUnreadCovnCountModel> getChatCount() async {
Response response = await ApiClient().getJsonForResponse( Response response = await ApiClient().getJsonForResponse(
"${ApiConsts.chatServerBaseApiUrl}user/unreadconversationcount/${AppState().getUserName}", "${ApiConsts.chatLoginTokenUrl}unreadconversationcount/${AppState().getUserName}",
); );
return chatUnreadCovnCountModelFromJson(response.body); return chatUnreadCovnCountModelFromJson(response.body);
} }
// Future setAdvertisementViewed(String masterID, int advertisementId) async {
// String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed";
//
// Map<String, dynamic> postParams = {
// "ItgNotificationMasterId": masterID,
// "ItgAdvertisement": {"advertisementId": advertisementId, "acknowledgment": true} //Mobile Id
// };
// postParams.addAll(AppState().postParamsJson);
// return await ApiClient().postJsonForObject((json) {
// // ItgMainRes responseData = ItgMainRes.fromJson(json);
// return json;
// }, url, postParams);
// }
} }

@ -0,0 +1,178 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:logger/logger.dart' as L;
import 'package:logging/logging.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/classes/consts.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/question_model.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:provider/provider.dart';
import 'package:signalr_netcore/http_connection_options.dart';
import 'package:signalr_netcore/hub_connection.dart';
import 'package:signalr_netcore/hub_connection_builder.dart';
class MarathonApiClient {
Future<String> getMarathonToken() async {
String employeeUserName = AppState().getUserName ?? "";
String employeeSession = AppState().postParamsObject?.pSessionId.toString() ?? "";
Map<String, String> jsonObject = <String, String>{"userName": employeeUserName, "password": employeeSession};
Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonParticipantLoginUrl, jsonObject);
var json = jsonDecode(response.body);
MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
if (marathonModel.statusCode == 200) {
if (marathonModel.data != null && marathonModel.isSuccessful == true) {
AppState().setMarathonToken = marathonModel.data["token"] ?? "";
print("bearer: ${AppState().getMarathonToken}");
return marathonModel.data["token"] ?? "";
} else {
//TODO : DO ERROR HANDLING HERE
return "";
}
} else {
//TODO : DO ERROR HANDLING HERE
return "";
}
}
Future<String> getProjectId() async {
Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonProjectGetUrl, <String, dynamic>{}, token: AppState().getMarathonToken ?? await getMarathonToken());
var json = jsonDecode(response.body);
MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
if (marathonModel.statusCode == 200) {
if (marathonModel.data != null && marathonModel.isSuccessful == true) {
logger.i("message: ${marathonModel.data[0]["id"]}");
AppState().setMarathonProjectId = marathonModel.data[0]["id"] ?? "";
return marathonModel.data[0]["id"] ?? "";
} else {
//TODO : DO ERROR HANDLING HERE
return "";
}
} else {
//TODO : DO ERROR HANDLING HERE
return "";
}
}
Future<MarathonDetailModel> getMarathonDetails() async {
String payrollString = AppState().postParamsObject?.payrollCodeStr.toString() ?? "CS";
Response response = await ApiClient().getJsonForResponse(ApiConsts.marathonUpcomingUrl + payrollString, token: AppState().getMarathonToken ?? await getMarathonToken());
var json = jsonDecode(response.body);
MarathonGenericModel marathonGenericModel = MarathonGenericModel.fromJson(json);
MarathonDetailModel marathonDetailModel = MarathonDetailModel.fromJson(marathonGenericModel.data);
AppState().setMarathonProjectId = marathonDetailModel.id!;
return marathonDetailModel;
}
late HubConnection hubConnection;
L.Logger logger = L.Logger();
Future<void> buildHubConnection(BuildContext context) async {
HttpConnectionOptions httpOptions = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
hubConnection = HubConnectionBuilder()
.withUrl(
ApiConsts.marathonHubConnectionUrl + "?employeeNumber=${AppState().memberInformationList!.eMPLOYEENUMBER ?? ""}&employeeName=${AppState().memberInformationList!.eMPLOYEENAME ?? ""}",
options: httpOptions,
)
.withAutomaticReconnect(
retryDelays: <int>[2000, 5000, 10000, 20000],
)
.configureLogging(
Logger("Logging"),
)
.build();
hubConnection.onclose(
({Exception? error}) {
logger.i("onclose");
},
);
hubConnection.onreconnecting(
({Exception? error}) {
logger.i("onreconnecting");
},
);
hubConnection.onreconnected(
({String? connectionId}) {
logger.i("onreconnected");
},
);
if (hubConnection.state != HubConnectionState.Connected) {
await hubConnection.start();
logger.i("Started HubConnection");
await hubConnection.invoke(
"AddParticipant",
args: <Object>[
<String, dynamic>{
"employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "",
"employeeName": AppState().memberInformationList!.eMPLOYEENAME ?? "",
"marathonId": AppState().getMarathonProjectId,
}
],
).catchError((e) {
logger.i("Error in AddParticipant: $e");
});
context.read<MarathonProvider>().addItemToList(ApiConsts.dummyQuestion);
await hubConnection.invoke(
"SendQuestionToParticipant",
args: <Object>[
<String, dynamic>{
"marathonId": "${AppState().getMarathonProjectId}",
}
],
).catchError((e) {
logger.i("Error in SendQuestionToParticipant: $e");
});
try {
hubConnection.on("OnSendQuestionToParticipant", (List<Object?>? arguments) {
onSendQuestionToParticipant(arguments, context);
});
} catch (e, s) {
logger.i("Error in OnSendQuestionToParticipant");
}
try {
hubConnection.on("OnParticipantJoin", (List<Object?>? arguments) {
onParticipantJoin(arguments, context);
});
} catch (e, s) {
logger.i("Error in OnParticipantJoin");
}
}
}
Future<void> onSendQuestionToParticipant(List<Object?>? arguments, BuildContext context) async {
logger.i("onSendQuestionToParticipant arguments: $arguments");
if (arguments != null) {
Map<dynamic, dynamic> data = arguments.first! as Map<dynamic, dynamic>;
var json = data["data"];
QuestionModel newQuestion = QuestionModel.fromJson(json);
context.read<MarathonProvider>().onNewQuestionReceived(newQuestion);
}
}
Future<void> onParticipantJoin(List<Object?>? arguments, BuildContext context) async {
logger.i("OnParticipantJoin arguments: $arguments");
context.watch<MarathonProvider>().totalMarathoners++;
}
}

@ -51,6 +51,18 @@ class AppState {
String? get getMohemmWifiPassword => _mohemmWifiPassword; String? get getMohemmWifiPassword => _mohemmWifiPassword;
String? _marathonToken ;
set setMarathonToken(String token) => _marathonToken = token;
String? get getMarathonToken => _marathonToken;
String? _projectID ;
set setMarathonProjectId(String token) => _projectID = token;
String? get getMarathonProjectId => _projectID;
final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.0, mobileType: Platform.isAndroid ? "android" : "ios"); final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.0, mobileType: Platform.isAndroid ? "android" : "ios");
void setPostParamsInitConfig() { void setPostParamsInitConfig() {

@ -17,6 +17,7 @@ class MyColors {
static const Color greyF7Color = Color(0xffF7F7F7); static const Color greyF7Color = Color(0xffF7F7F7);
static const Color grey80Color = Color(0xff808080); static const Color grey80Color = Color(0xff808080);
static const Color grey70Color = Color(0xff707070); static const Color grey70Color = Color(0xff707070);
static const Color grey7BColor = Color(0xff7B7B7B);
static const Color greyACColor = Color(0xffACACAC); static const Color greyACColor = Color(0xffACACAC);
static const Color grey98Color = Color(0xff989898); static const Color grey98Color = Color(0xff989898);
static const Color lightGreyEFColor = Color(0xffEFEFEF); static const Color lightGreyEFColor = Color(0xffEFEFEF);
@ -61,4 +62,5 @@ class MyColors {
static const Color grey9DColor = Color(0xff9D9D9D); static const Color grey9DColor = Color(0xff9D9D9D);
static const Color darkDigitColor = Color(0xff2D2F39); static const Color darkDigitColor = Color(0xff2D2F39);
static const Color grey71Color = Color(0xff717171); static const Color grey71Color = Color(0xff717171);
static const Color darkGrey3BColor = Color(0xff3B3B3B);
} }

@ -1,7 +1,9 @@
import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart';
class ApiConsts { class ApiConsts {
//static String baseUrl = "http://10.200.204.20:2801/"; // Local server //static String baseUrl = "http://10.200.204.20:2801/"; // Local server
static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server
//static String baseUrl = "https://hmgwebservices.com"; // Live server // static String baseUrl = "https://hmgwebservices.com"; // Live server
static String baseUrlServices = baseUrl + "/Services/"; // server static String baseUrlServices = baseUrl + "/Services/"; // server
// static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server
static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/";
@ -10,15 +12,32 @@ class ApiConsts {
static String user = baseUrlServices + "api/User/"; static String user = baseUrlServices + "api/User/";
static String cocRest = baseUrlServices + "COCWS.svc/REST/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/";
// todo @aamir move api end point last repo to concerned method.
//Chat //Chat
static String chatServerBaseUrl = "https://apiderichat.hmg.com"; static String chatServerBaseUrl = "https://apiderichat.hmg.com/";
static String chatServerBaseApiUrl = "https://apiderichat.hmg.com/api/"; static String chatServerBaseApiUrl = chatServerBaseUrl + "api/";
static String chatHubConnectionUrl = chatServerBaseUrl + "/ConnectionChatHub"; static String chatLoginTokenUrl = chatServerBaseApiUrl + "user/";
static String chatSearchMember = "user/getUserWithStatusAndFavAsync/"; static String chatHubConnectionUrl = chatServerBaseUrl + "ConnectionChatHub";
static String chatRecentUrl = "UserChatHistory/getchathistorybyuserid"; //For a Mem
static String chatSingleUserHistoryUrl = "UserChatHistory/GetUserChatHistory"; // static String chatSearchMember = chatLoginTokenUrl + "user/";
static String chatMediaImageUploadUrl = "shared/upload"; static String chatRecentUrl = chatServerBaseApiUrl + "UserChatHistory/"; //For a Mem
static String chatFavoriteUsers = "FavUser/getFavUserById/"; static String chatSingleUserHistoryUrl = chatServerBaseApiUrl + "UserChatHistory/";
static String chatMediaImageUploadUrl = chatServerBaseApiUrl + "shared/";
static String chatFavUser = chatServerBaseApiUrl + "FavUser/";
static String chatUserImages = chatServerBaseUrl + "empservice/api/employee/";
//Brain Marathon Constants
static String marathonBaseUrl = "https://18.188.181.12/service/";
static String marathonParticipantLoginUrl = marathonBaseUrl + "api/auth/participantlogin";
static String marathonProjectGetUrl = marathonBaseUrl + "api/Project/Project_Get";
static String marathonUpcomingUrl = marathonBaseUrl + "api/marathon/upcoming/";
static String marathonHubConnectionUrl = marathonBaseUrl + "MarathonBroadCast";
//DummyCards for the UI
static CardContent dummyQuestion = const CardContent();
} }
class SharedPrefsConsts { class SharedPrefsConsts {

@ -3,6 +3,26 @@ import 'package:intl/intl.dart';
class DateUtil { class DateUtil {
/// convert String To Date function /// convert String To Date function
/// [date] String we want to convert /// [date] String we want to convert
///
///
static DateTime convertStringToDateMarathon(String date) {
// /Date(1585774800000+0300)/
if (date != null) {
const start = "/Date(";
const end = "+0300)";
int startIndex = date.indexOf(start);
int endIndex = date.indexOf(end, startIndex + start.length);
return DateTime.fromMillisecondsSinceEpoch(
int.parse(
date.substring(startIndex + start.length, endIndex),
),
);
} else
return DateTime.now();
}
static DateTime convertStringToDate(String date) { static DateTime convertStringToDate(String date) {
// /Date(1585774800000+0300)/ // /Date(1585774800000+0300)/
if (date != null) { if (date != null) {
@ -20,7 +40,7 @@ class DateUtil {
} }
static DateTime convertSimpleStringDateToDate(String date) { static DateTime convertSimpleStringDateToDate(String date) {
return DateFormat("MM/dd/yyyy hh:mm:ss").parse(date); return DateFormat("MM/dd/yyyy hh:mm:ss a").parse(date);
} }
static DateTime convertSimpleStringDateToDateddMMyyyy(String date) { static DateTime convertSimpleStringDateToDateddMMyyyy(String date) {
@ -55,8 +75,9 @@ class DateUtil {
} }
return DateTime.now(); return DateTime.now();
} else } else {
return DateTime.now(); return DateTime.now();
}
} }
static String convertDateToString(DateTime date) { static String convertDateToString(DateTime date) {
@ -94,7 +115,7 @@ class DateUtil {
} }
static String convertDateMSToJsonDate(utc) { static String convertDateMSToJsonDate(utc) {
var dt = new DateTime.fromMicrosecondsSinceEpoch(utc); var dt = DateTime.fromMicrosecondsSinceEpoch(utc);
return "/Date(" + (dt.millisecondsSinceEpoch * 1000).toString() + '+0300' + ")/"; return "/Date(" + (dt.millisecondsSinceEpoch * 1000).toString() + '+0300' + ")/";
} }
@ -416,7 +437,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', 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

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/models/marathon/question_model.dart';
class MyDecorations { class MyDecorations {
static Decoration shadowDecoration = BoxDecoration( static Decoration shadowDecoration = BoxDecoration(
@ -22,4 +23,18 @@ class MyDecorations {
); );
return answerContainerDecoration; return answerContainerDecoration;
} }
static Decoration getAnswersContainerColor(QuestionsOptionStatus questionsOptionStatus) {
switch (questionsOptionStatus) {
case QuestionsOptionStatus.correct:
return getContainersDecoration(MyColors.greenColor);
case QuestionsOptionStatus.wrong:
return getContainersDecoration(MyColors.redColor);
case QuestionsOptionStatus.selected:
return getContainersDecoration(MyColors.yellowColorII);
case QuestionsOptionStatus.unSelected:
return getContainersDecoration(MyColors.greyF7Color);
}
}
} }

@ -4,4 +4,6 @@ class MyLottieConsts {
static const String celebrate2Lottie = "assets/lottie/celebrate2.json"; static const String celebrate2Lottie = "assets/lottie/celebrate2.json";
static const String winnerLottie = "assets/lottie/winner3.json"; static const String winnerLottie = "assets/lottie/winner3.json";
static const String allQuestions = "assets/lottie/all_questions.json"; static const String allQuestions = "assets/lottie/all_questions.json";
static const String wrongAnswerGif = "assets/images/wrong_answer.gif";
} }

@ -7,6 +7,7 @@ import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart';
import 'package:mohem_flutter_app/ui/chat/chat_home.dart'; import 'package:mohem_flutter_app/ui/chat/chat_home.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/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/ui/landing/itg/its_add_screen_video_image.dart';
import 'package:mohem_flutter_app/ui/landing/itg/survey_screen.dart'; import 'package:mohem_flutter_app/ui/landing/itg/survey_screen.dart';
import 'package:mohem_flutter_app/ui/landing/today_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/landing/today_attendance_screen.dart';
import 'package:mohem_flutter_app/ui/landing/today_attendance_screen2.dart'; import 'package:mohem_flutter_app/ui/landing/today_attendance_screen2.dart';
@ -87,6 +88,7 @@ class AppRoutes {
static const String addEitScreen = "/addeitScreen"; static const String addEitScreen = "/addeitScreen";
static const String initialRoute = login; static const String initialRoute = login;
static const String survey = "/survey"; static const String survey = "/survey";
static const String advertisement = "/advertisement";
//Work List //Work List
static const String workList = "/workList"; static const String workList = "/workList";
@ -116,8 +118,7 @@ class AppRoutes {
static const String addVacationRule = "/addVacationRule"; static const String addVacationRule = "/addVacationRule";
//Bottom Sheet //Bottom Sheet
static const String attendanceDetailsBottomSheet = static const String attendanceDetailsBottomSheet = "/attendanceDetailsBottomSheet";
"/attendanceDetailsBottomSheet";
//Profile //Profile
static const String profile = "/profile"; static const String profile = "/profile";
@ -135,8 +136,7 @@ class AppRoutes {
// Pending Transactions // Pending Transactions
static const String pendingTransactions = "/pendingTransactions"; static const String pendingTransactions = "/pendingTransactions";
static const String pendingTransactionsDetails = static const String pendingTransactionsDetails = "/pendingTransactionsDetails";
"/pendingTransactionsDetails";
// Announcements // Announcements
static const String announcements = "/announcements"; static const String announcements = "/announcements";
@ -192,6 +192,7 @@ class AppRoutes {
verifyLastLogin: (BuildContext context) => VerifyLastLoginScreen(), verifyLastLogin: (BuildContext context) => VerifyLastLoginScreen(),
dashboard: (BuildContext context) => DashboardScreen(), dashboard: (BuildContext context) => DashboardScreen(),
survey: (BuildContext context) => SurveyScreen(), survey: (BuildContext context) => SurveyScreen(),
advertisement: (BuildContext context) => ITGAdsScreen(),
subMenuScreen: (BuildContext context) => SubMenuScreen(), subMenuScreen: (BuildContext context) => SubMenuScreen(),
newPassword: (BuildContext context) => NewPasswordScreen(), newPassword: (BuildContext context) => NewPasswordScreen(),
@ -223,8 +224,7 @@ class AppRoutes {
addVacationRule: (BuildContext context) => AddVacationRuleScreen(), addVacationRule: (BuildContext context) => AddVacationRuleScreen(),
//Bottom Sheet //Bottom Sheet
attendanceDetailsBottomSheet: (BuildContext context) => attendanceDetailsBottomSheet: (BuildContext context) => AttendenceDetailsBottomSheet(),
AttendenceDetailsBottomSheet(),
//Profile //Profile
//profile: (BuildContext context) => Profile(), //profile: (BuildContext context) => Profile(),
@ -235,13 +235,10 @@ class AppRoutes {
familyMembers: (BuildContext context) => FamilyMembers(), familyMembers: (BuildContext context) => FamilyMembers(),
dynamicScreen: (BuildContext context) => DynamicListViewScreen(), dynamicScreen: (BuildContext context) => DynamicListViewScreen(),
addDynamicInput: (BuildContext context) => DynamicInputScreen(), addDynamicInput: (BuildContext context) => DynamicInputScreen(),
addDynamicInputProfile: (BuildContext context) => addDynamicInputProfile: (BuildContext context) => DynamicInputScreenProfile(),
DynamicInputScreenProfile(), addDynamicAddressScreen: (BuildContext context) => DynamicInputScreenAddress(),
addDynamicAddressScreen: (BuildContext context) =>
DynamicInputScreenAddress(),
deleteFamilyMember: (BuildContext context) => deleteFamilyMember: (BuildContext context) => DeleteFamilyMember(ModalRoute.of(context)!.settings.arguments as int),
DeleteFamilyMember(ModalRoute.of(context)!.settings.arguments as int),
requestSubmitScreen: (BuildContext context) => RequestSubmitScreen(), requestSubmitScreen: (BuildContext context) => RequestSubmitScreen(),
addUpdateFamilyMember: (BuildContext context) => AddUpdateFamilyMember(), addUpdateFamilyMember: (BuildContext context) => AddUpdateFamilyMember(),
@ -251,8 +248,7 @@ class AppRoutes {
mowadhafhiHRRequest: (BuildContext context) => MowadhafhiHRRequest(), mowadhafhiHRRequest: (BuildContext context) => MowadhafhiHRRequest(),
pendingTransactions: (BuildContext context) => PendingTransactions(), pendingTransactions: (BuildContext context) => PendingTransactions(),
pendingTransactionsDetails: (BuildContext context) => pendingTransactionsDetails: (BuildContext context) => PendingTransactionsDetails(),
PendingTransactionsDetails(),
announcements: (BuildContext context) => Announcements(), announcements: (BuildContext context) => Announcements(),
announcementsDetails: (BuildContext context) => AnnouncementDetails(), announcementsDetails: (BuildContext context) => AnnouncementDetails(),
@ -268,8 +264,7 @@ class AppRoutes {
// Offers & Discounts // Offers & Discounts
offersAndDiscounts: (BuildContext context) => OffersAndDiscountsHome(), offersAndDiscounts: (BuildContext context) => OffersAndDiscountsHome(),
offersAndDiscountsDetails: (BuildContext context) => offersAndDiscountsDetails: (BuildContext context) => OffersAndDiscountsDetails(),
OffersAndDiscountsDetails(),
//pay slip //pay slip
monthlyPaySlip: (BuildContext context) => MonthlyPaySlipScreen(), monthlyPaySlip: (BuildContext context) => MonthlyPaySlipScreen(),
@ -296,8 +291,7 @@ class AppRoutes {
// Marathon // Marathon
marathonIntroScreen: (BuildContext context) => MarathonIntroScreen(), marathonIntroScreen: (BuildContext context) => MarathonIntroScreen(),
marathonScreen: (BuildContext context) => MarathonScreen(), marathonScreen: (BuildContext context) => MarathonScreen(),
marathonWinnerSelection: (BuildContext context) => marathonWinnerSelection: (BuildContext context) => MarathonWinnerSelection(),
MarathonWinnerSelection(),
marathonWinnerScreen: (BuildContext context) => WinnerScreen(), marathonWinnerScreen: (BuildContext context) => WinnerScreen(),
}; };
} }

@ -136,7 +136,7 @@ extension EmailValidator on String {
Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text( Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
this, this,
maxLines: maxlines, maxLines: maxlines,
style: TextStyle(color: color ?? MyColors.grey3AColor, fontSize: 21, letterSpacing: -0.31, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600)), style: TextStyle(color: color ?? MyColors.grey3AColor, fontSize: 21, letterSpacing: -0.84, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600)),
); );
Widget toText22({Color? color, bool isBold = false}) => Text( Widget toText22({Color? color, bool isBold = false}) => Text(
@ -149,6 +149,11 @@ extension EmailValidator on String {
style: TextStyle(height: 23 / 24, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), style: TextStyle(height: 23 / 24, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
); );
Widget toText30({Color? color, bool isBold = false}) => Text(
this,
style: TextStyle(height: 20 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.2, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
);
Widget toText32({Color? color, bool isBold = false}) => Text( Widget toText32({Color? color, bool isBold = false}) => Text(
this, this,
style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.92, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.92, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),

@ -487,5 +487,8 @@ abstract class LocaleKeys {
static const typeheretoreply = 'typeheretoreply'; static const typeheretoreply = 'typeheretoreply';
static const favorite = 'favorite'; static const favorite = 'favorite';
static const searchfromchat = 'searchfromchat'; static const searchfromchat = 'searchfromchat';
static const yourAnswerCorrect = 'yourAnswerCorrect';
static const youMissedTheQuestion = 'youMissedTheQuestion';
static const wrongAnswer = 'wrongAnswer';
} }

@ -3,7 +3,7 @@ import 'dart:io';
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:logger/logger.dart'; import 'package:logger/logger.dart';
import 'package:mohem_flutter_app/api/chat/chat_provider_model.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/app_state/app_state.dart';
import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/generated/codegen_loader.g.dart'; import 'package:mohem_flutter_app/generated/codegen_loader.g.dart';

@ -7,7 +7,7 @@ import 'dart:convert';
class CallDataModel { class CallDataModel {
CallDataModel({ CallDataModel({
this.callerId, this.callerId,
this.callReciverId, this.callReceiverID,
this.notificationForeground, this.notificationForeground,
this.message, this.message,
this.title, this.title,
@ -27,7 +27,7 @@ class CallDataModel {
}); });
String? callerId; String? callerId;
String? callReciverId; String? callReceiverID;
String? notificationForeground; String? notificationForeground;
String? message; String? message;
String? title; String? title;
@ -51,7 +51,7 @@ class CallDataModel {
factory CallDataModel.fromJson(Map<String, dynamic> json) => CallDataModel( factory CallDataModel.fromJson(Map<String, dynamic> json) => CallDataModel(
callerId: json["callerID"] == null ? null : json["callerID"], callerId: json["callerID"] == null ? null : json["callerID"],
callReciverId: json["callReciverID"] == null ? null : json["callReciverID"], callReceiverID: json["callReceiverID"] == null ? null : json["callReceiverID"],
notificationForeground: json["notification_foreground"] == null ? null : json["notification_foreground"], notificationForeground: json["notification_foreground"] == null ? null : json["notification_foreground"],
message: json["message"] == null ? null : json["message"], message: json["message"] == null ? null : json["message"],
title: json["title"] == null ? null : json["title"], title: json["title"] == null ? null : json["title"],
@ -78,7 +78,7 @@ class CallDataModel {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"callerID": callerId == null ? null : callerId, "callerID": callerId == null ? null : callerId,
"callReciverID": callReciverId == null ? null : callReciverId, "callReceiverID": callReceiverID == null ? null : callReceiverID,
"notification_foreground": notificationForeground == null ? null : notificationForeground, "notification_foreground": notificationForeground == null ? null : notificationForeground,
"message": message == null ? null : message, "message": message == null ? null : message,
"title": title == null ? null : title, "title": title == null ? null : title,

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

@ -1,32 +1,35 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.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)));
String singleUserChatModelToJson(List<SingleUserChatModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson()))); String singleUserChatModelToJson(List<SingleUserChatModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class SingleUserChatModel { class SingleUserChatModel {
SingleUserChatModel({ SingleUserChatModel(
this.userChatHistoryId, {this.userChatHistoryId,
this.userChatHistoryLineId, this.userChatHistoryLineId,
this.contant, this.contant,
this.contantNo, this.contantNo,
this.currentUserId, this.currentUserId,
this.currentUserName, this.currentUserName,
this.targetUserId, this.targetUserId,
this.targetUserName, this.targetUserName,
this.encryptedTargetUserId, this.encryptedTargetUserId,
this.encryptedTargetUserName, this.encryptedTargetUserName,
this.chatEventId, this.chatEventId,
this.fileTypeId, this.fileTypeId,
this.isSeen, this.isSeen,
this.isDelivered, this.isDelivered,
this.createdDate, this.createdDate,
this.chatSource, this.chatSource,
this.conversationId, this.conversationId,
this.fileTypeResponse, this.fileTypeResponse,
this.userChatReplyResponse, this.userChatReplyResponse,
this.isReplied, this.isReplied,
}); this.isImageLoaded,
this.image});
int? userChatHistoryId; int? userChatHistoryId;
int? userChatHistoryLineId; int? userChatHistoryLineId;
@ -48,29 +51,32 @@ class SingleUserChatModel {
FileTypeResponse? fileTypeResponse; FileTypeResponse? fileTypeResponse;
UserChatReplyResponse? userChatReplyResponse; UserChatReplyResponse? userChatReplyResponse;
bool? isReplied; bool? isReplied;
bool? isImageLoaded;
Uint8List? image;
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"],
userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"], userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"],
contant: json["contant"] == null ? null : json["contant"], contant: json["contant"] == null ? null : json["contant"],
contantNo: json["contantNo"] == null ? null : json["contantNo"], contantNo: json["contantNo"] == null ? null : json["contantNo"],
currentUserId: json["currentUserId"] == null ? null : json["currentUserId"], currentUserId: json["currentUserId"] == null ? null : json["currentUserId"],
currentUserName: json["currentUserName"] == null ? null : json["currentUserName"], currentUserName: json["currentUserName"] == null ? null : json["currentUserName"],
targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], targetUserId: json["targetUserId"] == null ? null : json["targetUserId"],
targetUserName: json["targetUserName"] == null ? null : json["targetUserName"], targetUserName: json["targetUserName"] == null ? null : json["targetUserName"],
encryptedTargetUserId: json["encryptedTargetUserId"] == null ? null : json["encryptedTargetUserId"], encryptedTargetUserId: json["encryptedTargetUserId"] == null ? null : json["encryptedTargetUserId"],
encryptedTargetUserName: json["encryptedTargetUserName"] == null ? null : json["encryptedTargetUserName"], encryptedTargetUserName: json["encryptedTargetUserName"] == null ? null : json["encryptedTargetUserName"],
chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], chatEventId: json["chatEventId"] == null ? null : json["chatEventId"],
fileTypeId: json["fileTypeId"], fileTypeId: json["fileTypeId"],
isSeen: json["isSeen"] == null ? null : json["isSeen"], isSeen: json["isSeen"] == null ? null : json["isSeen"],
isDelivered: json["isDelivered"] == null ? null : json["isDelivered"], isDelivered: json["isDelivered"] == null ? null : json["isDelivered"],
createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]), createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]),
chatSource: json["chatSource"] == null ? null : json["chatSource"], chatSource: json["chatSource"] == null ? null : json["chatSource"],
conversationId: json["conversationId"] == null ? null : json["conversationId"], conversationId: json["conversationId"] == null ? null : json["conversationId"],
fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]), fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]),
userChatReplyResponse: json["userChatReplyResponse"] == null ? null : UserChatReplyResponse.fromJson(json["userChatReplyResponse"]), userChatReplyResponse: json["userChatReplyResponse"] == null ? null : UserChatReplyResponse.fromJson(json["userChatReplyResponse"]),
isReplied: false, isReplied: false,
); isImageLoaded: false,
image: null);
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId,
@ -138,6 +144,8 @@ class UserChatReplyResponse {
this.targetUserId, this.targetUserId,
this.targetUserName, this.targetUserName,
this.fileTypeResponse, this.fileTypeResponse,
this.isImageLoaded,
this.image,
}); });
int? userChatHistoryId; int? userChatHistoryId;
@ -149,18 +157,21 @@ class UserChatReplyResponse {
int? targetUserId; int? targetUserId;
String? targetUserName; String? targetUserName;
FileTypeResponse? fileTypeResponse; FileTypeResponse? fileTypeResponse;
bool? isImageLoaded;
Uint8List? image;
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"],
chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], chatEventId: json["chatEventId"] == null ? null : json["chatEventId"],
contant: json["contant"] == null ? null : json["contant"], contant: json["contant"] == null ? null : json["contant"],
contantNo: json["contantNo"] == null ? null : json["contantNo"], contantNo: json["contantNo"] == null ? null : json["contantNo"],
fileTypeId: json["fileTypeId"], fileTypeId: json["fileTypeId"],
createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]), createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]),
targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], targetUserId: json["targetUserId"] == null ? null : json["targetUserId"],
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,
image: null);
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId,

@ -0,0 +1,31 @@
class MarathonGenericModel {
MarathonGenericModel({
this.data,
this.isSuccessful,
this.message,
this.statusCode,
this.errors,
});
dynamic data;
bool? isSuccessful;
String? message;
int? statusCode;
dynamic errors;
factory MarathonGenericModel.fromJson(Map<String, dynamic> json) => MarathonGenericModel(
data: json["data"],
isSuccessful: json["isSuccessful"],
message: json["message"],
statusCode: json["statusCode"],
errors: json["errors"],
);
Map<String, dynamic> toJson() => {
"data": data,
"isSuccessful": isSuccessful,
"message": message,
"statusCode": statusCode,
"errors": errors,
};
}

@ -0,0 +1,256 @@
class MarathonDetailModel {
String? id;
String? titleEn;
String? titleAr;
String? descEn;
String? descAr;
int? winDeciderTime;
int? winnersCount;
int? questGapTime;
String? startTime;
String? endTime;
int? marathoneStatusId;
String? scheduleTime;
int? selectedLanguage;
Projects? projects;
List<Sponsors>? sponsors;
List<Questions>? questions;
int? totalQuestions;
MarathonDetailModel(
{id,
titleEn,
titleAr,
descEn,
descAr,
winDeciderTime,
winnersCount,
questGapTime,
startTime,
endTime,
marathoneStatusId,
scheduleTime,
selectedLanguage,
projects,
sponsors,
questions,
totalQuestions});
MarathonDetailModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
titleEn = json['titleEn'];
titleAr = json['titleAr'];
descEn = json['descEn'];
descAr = json['descAr'];
winDeciderTime = json['winDeciderTime'];
winnersCount = json['winnersCount'];
questGapTime = json['questGapTime'];
startTime = json['startTime'];
endTime = json['endTime'];
marathoneStatusId = json['marathoneStatusId'];
scheduleTime = json['scheduleTime'];
selectedLanguage = json['selectedLanguage'];
projects = json['projects'] != null
? Projects.fromJson(json['projects'])
: null;
if (json['sponsors'] != null) {
sponsors = <Sponsors>[];
json['sponsors'].forEach((v) {
sponsors!.add( Sponsors.fromJson(v));
});
}
if (json['questions'] != null) {
questions = <Questions>[];
json['questions'].forEach((v) {
questions!.add( Questions.fromJson(v));
});
}
totalQuestions = json["totalQuestions"];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['titleEn'] = titleEn;
data['titleAr'] = titleAr;
data['descEn'] = descEn;
data['descAr'] = descAr;
data['winDeciderTime'] = winDeciderTime;
data['winnersCount'] = winnersCount;
data['questGapTime'] = questGapTime;
data['startTime'] = startTime;
data['endTime'] = endTime;
data['marathoneStatusId'] = marathoneStatusId;
data['scheduleTime'] = scheduleTime;
data['selectedLanguage'] = selectedLanguage;
if (projects != null) {
data['projects'] = projects!.toJson();
}
if (sponsors != null) {
data['sponsors'] = sponsors!.map((v) => v.toJson()).toList();
}
if (questions != null) {
data['questions'] = questions!.map((v) => v.toJson()).toList();
}
data['totalQuestions'] = totalQuestions;
return data;
}
}
class Projects {
String? id;
String? nameEn;
String? nameAr;
String? projectCode;
Projects({id, nameEn, nameAr, projectCode});
Projects.fromJson(Map<String, dynamic> json) {
id = json['id'];
nameEn = json['nameEn'];
nameAr = json['nameAr'];
projectCode = json['projectCode'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['nameEn'] = nameEn;
data['nameAr'] = nameAr;
data['projectCode'] = projectCode;
return data;
}
}
class Sponsors {
String? id;
String? nameEn;
Null? nameAr;
String? image;
Null? video;
Null? logo;
List<SponsorPrizes>? sponsorPrizes;
Sponsors(
{id,
nameEn,
nameAr,
image,
video,
logo,
sponsorPrizes});
Sponsors.fromJson(Map<String, dynamic> json) {
id = json['id'];
nameEn = json['nameEn'];
nameAr = json['nameAr'];
image = json['image'];
video = json['video'];
logo = json['logo'];
if (json['sponsorPrizes'] != null) {
sponsorPrizes = <SponsorPrizes>[];
json['sponsorPrizes'].forEach((v) {
sponsorPrizes!.add( SponsorPrizes.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['nameEn'] = nameEn;
data['nameAr'] = nameAr;
data['image'] = image;
data['video'] = video;
data['logo'] = logo;
if (sponsorPrizes != null) {
data['sponsorPrizes'] =
sponsorPrizes!.map((v) => v.toJson()).toList();
}
return data;
}
}
class SponsorPrizes {
String? id;
String? marathonPrizeEn;
String? marathonPrizeAr;
SponsorPrizes({id, marathonPrizeEn, marathonPrizeAr});
SponsorPrizes.fromJson(Map<String, dynamic> json) {
id = json['id'];
marathonPrizeEn = json['marathonPrizeEn'];
marathonPrizeAr = json['marathonPrizeAr'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = id;
data['marathonPrizeEn'] = marathonPrizeEn;
data['marathonPrizeAr'] = marathonPrizeAr;
return data;
}
}
class Questions {
String? id;
String? titleEn;
String? titleAr;
String? marathonId;
int? questionTypeId;
int? questionTime;
int? nextQuestGap;
int? gapType;
String? gapValue;
String? gapImage;
int? questOptionsLimit;
List? questionOptions;
Questions(
{id,
titleEn,
titleAr,
marathonId,
questionTypeId,
questionTime,
nextQuestGap,
gapType,
gapValue,
gapImage,
questOptionsLimit,
questionOptions});
Questions.fromJson(Map<String, dynamic> json) {
id = json['id'];
titleEn = json['titleEn'];
titleAr = json['titleAr'];
marathonId = json['marathonId'];
questionTypeId = json['questionTypeId'];
questionTime = json['questionTime'];
nextQuestGap = json['nextQuestGap'];
gapType = json['gapType'];
gapValue = json['gapValue'];
gapImage = json['gapImage'];
questOptionsLimit = json['questOptionsLimit'];
questionOptions = json['questionOptions'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['titleEn'] = titleEn;
data['titleAr'] = titleAr;
data['marathonId'] = marathonId;
data['questionTypeId'] = questionTypeId;
data['questionTime'] = questionTime;
data['nextQuestGap'] = nextQuestGap;
data['gapType'] = gapType;
data['gapValue'] = gapValue;
data['gapImage'] = gapImage;
data['questOptionsLimit'] = questOptionsLimit;
data['questionOptions'] = questionOptions;
return data;
}
}

@ -0,0 +1,117 @@
enum QuestionsOptionStatus { correct, wrong, selected, unSelected }
enum QuestionCardStatus { question, wrongAnswer, correctAnswer, skippedAnswer, completed, findingWinner, winnerFound }
class QuestionModel {
String? id;
String? titleEn;
String? titleAr;
String? marathonId;
int? questionTypeId;
int? questionTime;
int? nextQuestGap;
int? gapType;
String? gapText;
String? gapImage;
int? questOptionsLimit;
List<QuestionOptions>? questionOptions;
QuestionModel({
String? id,
String? titleEn,
String? titleAr,
String? marathonId,
int? questionTypeId,
int? questionTime,
int? nextQuestGap,
int? gapType,
String? gapText,
String? gapImage,
int? questOptionsLimit,
List<QuestionOptions>? questionOptions,
});
QuestionModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
titleEn = json['titleEn'];
titleAr = json['titleAr'];
marathonId = json['marathonId'];
questionTypeId = json['questionTypeId'];
questionTime = json['questionTime'];
nextQuestGap = json['nextQuestGap'];
gapType = json['gapType'];
gapText = json['gapText'];
gapImage = json['gapImage'];
questOptionsLimit = json['questOptionsLimit'];
if (json['questionOptions'] != null) {
questionOptions = <QuestionOptions>[];
json['questionOptions'].forEach((v) {
questionOptions!.add(QuestionOptions.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['titleEn'] = titleEn;
data['titleAr'] = titleAr;
data['marathonId'] = marathonId;
data['questionTypeId'] = questionTypeId;
data['questionTime'] = questionTime;
data['nextQuestGap'] = nextQuestGap;
data['gapType'] = gapType;
data['gapText'] = gapText;
data['gapImage'] = gapImage;
data['questOptionsLimit'] = questOptionsLimit;
if (questionOptions != null) {
data['questionOptions'] = questionOptions!.map((v) => v.toJson()).toList();
}
return data;
}
}
class QuestionOptions {
String? id;
String? titleEn;
String? titleAr;
String? questionId;
int? sequence;
String? image;
bool? isCorrectOption;
QuestionsOptionStatus? optionStatus;
QuestionOptions({
String? id,
String? titleEn,
String? titleAr,
String? questionId,
int? sequence,
String? image,
bool? isCorrectOption,
QuestionsOptionStatus? optionStatus,
});
QuestionOptions.fromJson(Map<String, dynamic> json) {
id = json['id'];
titleEn = json['titleEn'];
titleAr = json['titleAr'];
questionId = json['questionId'];
sequence = json['sequence'];
image = json['image'];
isCorrectOption = json['isCorrectOption'];
optionStatus = QuestionsOptionStatus.unSelected;
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['titleEn'] = titleEn;
data['titleAr'] = titleAr;
data['questionId'] = questionId;
data['sequence'] = sequence;
data['image'] = image;
data['isCorrectOption'] = isCorrectOption;
return data;
}
}

@ -1,23 +1,19 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:logger/logger.dart' as L; import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
import 'package:logging/logging.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/utils.dart'; import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as login;
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/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:signalr_netcore/signalr_client.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
@ -26,9 +22,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
TextEditingController search = TextEditingController(); TextEditingController search = TextEditingController();
List<SingleUserChatModel> userChatHistory = []; List<SingleUserChatModel> userChatHistory = [];
List<ChatUser>? pChatHistory, searchedChats; List<ChatUser>? pChatHistory, searchedChats;
late HubConnection hubConnection;
L.Logger logger = L.Logger();
bool hubConInitialized = false;
String chatCID = ''; String chatCID = '';
bool isLoading = true; bool isLoading = true;
bool isChatScreenActive = false; bool isChatScreenActive = false;
@ -40,56 +33,20 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
List<ChatUser> favUsersList = []; List<ChatUser> favUsersList = [];
int paginationVal = 0; int paginationVal = 0;
Future<void> getUserAutoLoginToken(BuildContext cxt) async { void registerEvents() {
Response response = await ApiClient().postJsonForResponse( hubConnection.on("OnUpdateUserStatusAsync", changeStatus);
"${ApiConsts.chatServerBaseApiUrl}user/externaluserlogin", hubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
{ // hubConnection.on("OnSeenChatUserAsync", onChatSeen);
"employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), //hubConnection.on("OnUserTypingAsync", onUserTyping);
"password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", hubConnection.on("OnUserCountAsync", userCountAsync);
}, hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow);
); hubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
login.UserAutoLoginModel userLoginResponse = login.userAutoLoginModelFromJson( hubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
response.body,
);
if (userLoginResponse.response != null) {
hubConInitialized = true;
AppState().setchatUserDetails = userLoginResponse;
await buildHubConnection();
} else {
Utils.showToast(
userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr",
);
return;
}
} }
Future<List<ChatUser>?> getChatMemberFromSearch(String sName, int cUserId) async {
Response response = await ApiClient().getJsonForResponse(
"${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatSearchMember}$sName/$cUserId",
token: AppState().chatDetails!.response!.token,
);
return searchUserJsonModel(response.body);
}
List<ChatUser> searchUserJsonModel(String str) => List<ChatUser>.from(
json.decode(str).map(
(x) => ChatUser.fromJson(x),
),
);
void getUserRecentChats() async { void getUserRecentChats() async {
Response response = await ApiClient().getJsonForResponse( ChatUserModel recentChat = await ChatApiClient().getRecentChats();
"${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatRecentUrl}", ChatUserModel favUList = await ChatApiClient().getFavUsers();
token: AppState().chatDetails!.response!.token,
);
ChatUserModel recentChat = userToList(response.body);
Response favRes = await ApiClient().getJsonForResponse(
"${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatFavoriteUsers}${AppState().chatDetails!.response!.id}",
token: AppState().chatDetails!.response!.token,
);
ChatUserModel favUList = userToList(favRes.body);
if (favUList.response != null && recentChat.response != null) { if (favUList.response != null && recentChat.response != null) {
favUsersList = favUList.response!; favUsersList = favUList.response!;
@ -108,21 +65,20 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
pChatHistory = recentChat.response ?? []; pChatHistory = recentChat.response ?? [];
pChatHistory!.sort( pChatHistory!.sort(
(ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo( (ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase()),
b.userName!.toLowerCase(),
),
); );
searchedChats = pChatHistory; searchedChats = pChatHistory;
isLoading = false; isLoading = false;
await invokeUserChatHistoryNotDeliveredAsync(
userId: int.parse(
AppState().chatDetails!.response!.id.toString(),
),
);
notifyListeners(); notifyListeners();
} }
Future getUserChatHistoryNotDeliveredAsync({required int userId}) async { Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async {
await hubConnection.invoke( await hubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]);
"GetUserChatHistoryNotDeliveredAsync",
args: [userId],
);
return ""; return "";
} }
@ -131,10 +87,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
if (isNewChat) userChatHistory = []; if (isNewChat) userChatHistory = [];
if (!loadMore) paginationVal = 0; if (!loadMore) paginationVal = 0;
isChatScreenActive = true; isChatScreenActive = true;
Response response = await ApiClient().getJsonForResponse( Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal);
"${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatSingleUserHistoryUrl}/$senderUID/$receiverUID/$paginationVal",
token: AppState().chatDetails!.response!.token,
);
if (response.statusCode == 204) { if (response.statusCode == 204) {
if (isNewChat) { if (isNewChat) {
userChatHistory = []; userChatHistory = [];
@ -144,27 +97,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
} else { } else {
if (loadMore) { if (loadMore) {
List<SingleUserChatModel> temp = getSingleUserChatModel( List<SingleUserChatModel> temp = getSingleUserChatModel(response.body).reversed.toList();
response.body, userChatHistory.addAll(temp);
).reversed.toList();
userChatHistory.addAll(
temp,
);
} else { } else {
userChatHistory = getSingleUserChatModel( userChatHistory = getSingleUserChatModel(response.body).reversed.toList();
response.body,
).reversed.toList();
} }
} }
await getUserChatHistoryNotDeliveredAsync(
userId: senderUID,
);
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
markRead( markRead(userChatHistory, receiverUID);
userChatHistory,
receiverUID,
);
generateConvId(); generateConvId();
} }
@ -173,134 +114,74 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
chatCID = uuid.v4(); chatCID = uuid.v4();
} }
void markRead(List<SingleUserChatModel> data, reciverID) { void markRead(List<SingleUserChatModel> data, int receiverID) {
for (SingleUserChatModel element in data!) { if (data != null) {
if (!element.isSeen!) { for (SingleUserChatModel element in data!) {
dynamic data = [ if (element.isSeen != null) {
{ if (!element.isSeen!) {
"userChatHistoryId": element.userChatHistoryId, print("Found Un Read");
"TargetUserId": element.targetUserId, logger.d(jsonEncode(element));
"isDelivered": true, dynamic data = [
"isSeen": true, {"userChatHistoryId": element.userChatHistoryId, "TargetUserId": element.targetUserId, "isDelivered": true, "isSeen": true}
];
updateUserChatHistoryStatusAsync(data);
} }
]; }
updateUserChatHistoryStatusAsync(data);
} }
} for (ChatUser element in searchedChats!) {
for (ChatUser element in searchedChats!) { if (element.id == receiverID) {
if (element.id == reciverID) { element.unreadMessageCount = 0;
element.unreadMessageCount = 0; notifyListeners();
notifyListeners(); }
} }
} }
} }
void updateUserChatHistoryStatusAsync(List data) { void updateUserChatHistoryStatusAsync(List data) {
hubConnection.invoke( try {
"UpdateUserChatHistoryStatusAsync", hubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]);
args: [data], } catch (e) {
); throw e;
}
} }
List<SingleUserChatModel> getSingleUserChatModel(String str) => List<SingleUserChatModel>.from( void updateUserChatHistoryOnMsg(List data) {
json.decode(str).map( try {
(x) => SingleUserChatModel.fromJson(x), hubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]);
), } catch (e) {
); throw e;
}
}
ChatUserModel userToList(String str) => ChatUserModel.fromJson( List<SingleUserChatModel> getSingleUserChatModel(String str) => List<SingleUserChatModel>.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x)));
json.decode(str),
);
Future<dynamic> uploadAttachments(String userId, File file) async { Future<dynamic> uploadAttachments(String userId, File file) async {
dynamic result; dynamic result;
dynamic request = MultipartRequest(
'POST',
Uri.parse(
'${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatMediaImageUploadUrl}',
),
);
request.fields.addAll({'userId': userId, 'fileSource': '1'});
request.files.add(await MultipartFile.fromPath('files', file.path));
request.headers.addAll(
{
'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}',
},
);
try { try {
StreamedResponse response = await request.send(); StreamedResponse response = await ChatApiClient().uploadMedia(userId, file);
if (response.statusCode == 200) { if (response.statusCode == 200) {
result = jsonDecode( result = jsonDecode(await response.stream.bytesToString());
await response.stream.bytesToString(),
);
} else { } else {
result = []; result = [];
} }
} catch (e) { } catch (e) {
if (kDebugMode) { throw e;
print(e);
}
} }
;
return result;
}
Future<void> buildHubConnection() async { return result;
HttpConnectionOptions httpOp = HttpConnectionOptions(
skipNegotiation: false,
logMessageContent: true,
);
hubConnection = HubConnectionBuilder()
.withUrl(
ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Web&access_token=${AppState().chatDetails!.response!.token}",
options: httpOp,
)
.withAutomaticReconnect(
retryDelays: <int>[2000, 5000, 10000, 20000],
)
.configureLogging(
Logger("Loggin"),
)
.build();
hubConnection.onclose(
({Exception? error}) {},
);
hubConnection.onreconnecting(
({Exception? error}) {},
);
hubConnection.onreconnected(
({String? connectionId}) {},
);
if (hubConnection.state != HubConnectionState.Connected) {
await hubConnection.start();
getUserChatHistoryNotDeliveredAsync(
userId: int.parse(
AppState().chatDetails!.response!.id.toString(),
),
);
hubConnection.on("OnUpdateUserStatusAsync", changeStatus);
hubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
// hubConnection.on("OnSeenChatUserAsync", onChatSeen);
//hubConnection.on("OnUserTypingAsync", onUserTyping);
hubConnection.on("OnUserCountAsync", userCountAsync);
hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow);
hubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
hubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
}
} }
void updateUserChatStatus(List<Object?>? args) { void updateUserChatStatus(List<Object?>? args) {
dynamic items = args!.toList(); dynamic items = args!.toList();
for (dynamic cItem in items[0]) { for (var cItem in items[0]) {
for (SingleUserChatModel chat in userChatHistory) { for (SingleUserChatModel chat in userChatHistory) {
if (chat.userChatHistoryId.toString() == cItem["userChatHistoryId"].toString()) { if (cItem["contantNo"].toString() == chat.contantNo.toString()) {
chat.isSeen = cItem["isSeen"]; chat.isSeen = cItem["isSeen"];
chat.isDelivered = cItem["isDelivered"]; chat.isDelivered = cItem["isDelivered"];
notifyListeners();
} }
} }
} }
notifyListeners();
} }
void onChatSeen(List<Object?>? args) { void onChatSeen(List<Object?>? args) {
@ -342,32 +223,23 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void chatNotDelivered(List<Object?>? args) { void chatNotDelivered(List<Object?>? args) {
dynamic items = args!.toList(); dynamic items = args!.toList();
logger.d(items);
for (dynamic item in items[0]) { for (dynamic item in items[0]) {
searchedChats!.forEach((element) { searchedChats!.forEach(
if (element.id == item["currentUserId"]) { (ChatUser element) {
var val = element.unreadMessageCount == null ? 0 : element.unreadMessageCount; if (element.id == item["currentUserId"]) {
element.unreadMessageCount = val! + 1; int? val = element.unreadMessageCount ?? 0;
} element.unreadMessageCount = val! + 1;
}); }
// dynamic data = [ element.isLoadingCounter = false;
// { },
// "userChatHistoryId": item["userChatHistoryId"], );
// "TargetUserId": item["targetUserId"],
// "isDelivered": true,
// "isSeen": true,
// }
// ];
// updateUserChatHistoryStatusAsync(data);
} }
notifyListeners(); notifyListeners();
} }
void changeStatus(List<Object?>? args) { void changeStatus(List<Object?>? args) {
if (kDebugMode) {
// print("================= Status Online // Offline ====================");
}
dynamic items = args!.toList(); dynamic items = args!.toList();
// logger.d(items);
for (ChatUser user in searchedChats!) { for (ChatUser user in searchedChats!) {
if (user.id == items.first["id"]) { if (user.id == items.first["id"]) {
user.userStatus = items.first["userStatus"]; user.userStatus = items.first["userStatus"];
@ -401,32 +273,30 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
data.first.targetUserName = temp.first.currentUserName; data.first.targetUserName = temp.first.currentUserName;
data.first.currentUserId = temp.first.targetUserId; data.first.currentUserId = temp.first.targetUserId;
data.first.currentUserName = temp.first.targetUserName; data.first.currentUserName = temp.first.targetUserName;
if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) {
data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg");
}
if (data.first.userChatReplyResponse != null) {
if (data.first.fileTypeResponse != null) {
if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) {
data.first.userChatReplyResponse!.image =
await ChatApiClient().downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg");
data.first.userChatReplyResponse!.isImageLoaded = true;
}
}
}
} }
userChatHistory.insert(0, data.first); userChatHistory.insert(0, data.first);
// searchedChats!.forEach((element) {
// if (element.id == data.first.currentUserId) {
// var val = element.unreadMessageCount == null ? 0 : element.unreadMessageCount;
// element.unreadMessageCount = val! + 1;
// }
// });
var list = [ var list = [
{ {"userChatHistoryId": data.first.userChatHistoryId, "TargetUserId": temp.first.targetUserId, "isDelivered": true, "isSeen": isChatScreenActive ? true : false}
"userChatHistoryId": data.first.userChatHistoryId,
"TargetUserId": data.first.targetUserId,
"isDelivered": true,
"isSeen": isChatScreenActive ? true : false,
}
]; ];
updateUserChatHistoryStatusAsync(list); updateUserChatHistoryOnMsg(list);
notifyListeners(); notifyListeners();
// if (isChatScreenActive) scrollToBottom();
} }
void onUserTyping(List<Object?>? parameters) { void onUserTyping(List<Object?>? parameters) {
// print("==================== Typing Active ==================");
// logger.d(parameters);
for (ChatUser user in searchedChats!) { for (ChatUser user in searchedChats!) {
if (user.id == parameters![1] && parameters[0] == true) { if (user.id == parameters![1] && parameters[0] == true) {
user.isTyping = parameters[0] as bool?; user.isTyping = parameters[0] as bool?;
@ -509,34 +379,44 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
Future<void> sendChatToServer( Future<void> sendChatToServer(
{required int chatEventId, required fileTypeId, required int targetUserId, required String targetUserName, required chatReplyId, required bool isAttachment, required bool isReply}) async { {required int chatEventId,
required fileTypeId,
required int targetUserId,
required String targetUserName,
required chatReplyId,
required bool isAttachment,
required bool isReply,
Uint8List? image,
required bool isImageLoaded}) async {
Uuid uuid = const Uuid(); Uuid uuid = const Uuid();
var contentNo = uuid.v4();
var msg = message.text; var msg = message.text;
SingleUserChatModel data = SingleUserChatModel( SingleUserChatModel data = SingleUserChatModel(
chatEventId: chatEventId, chatEventId: chatEventId,
chatSource: 1, chatSource: 1,
contant: msg, contant: msg,
contantNo: uuid.v4(), contantNo: contentNo,
conversationId: chatCID, conversationId: chatCID,
createdDate: DateTime.now(), createdDate: DateTime.now(),
currentUserId: AppState().chatDetails!.response!.id, currentUserId: AppState().chatDetails!.response!.id,
currentUserName: AppState().chatDetails!.response!.userName, currentUserName: AppState().chatDetails!.response!.userName,
targetUserId: targetUserId, targetUserId: targetUserId,
targetUserName: targetUserName, targetUserName: targetUserName,
isReplied: false, isReplied: false,
fileTypeId: fileTypeId, fileTypeId: fileTypeId,
userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null,
fileTypeResponse: isAttachment fileTypeResponse: isAttachment
? FileTypeResponse( ? FileTypeResponse(
fileTypeId: fileTypeId, fileTypeId: fileTypeId,
fileTypeName: getFileType(getFileExtension(selectedFile.path).toString()), fileTypeName: getFileType(getFileExtension(selectedFile.path).toString()),
fileKind: getFileExtension(selectedFile.path), fileKind: getFileExtension(selectedFile.path),
fileName: selectedFile.path.split("/").last, fileName: selectedFile.path.split("/").last,
fileTypeDescription: getFileTypeDescription(getFileExtension(selectedFile.path).toString()), fileTypeDescription: getFileTypeDescription(getFileExtension(selectedFile.path).toString()),
) )
: null, : null,
); image: image,
isImageLoaded: isImageLoaded);
userChatHistory.insert(0, data); userChatHistory.insert(0, data);
isFileSelected = false; isFileSelected = false;
isMsgReply = false; isMsgReply = false;
@ -545,7 +425,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
notifyListeners(); notifyListeners();
String chatData = String chatData =
'{"contant":"$msg","contantNo":"${uuid.v4()}","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}';
await hubConnection.invoke("AddChatUserAsync", args: <Object>[json.decode(chatData)]); await hubConnection.invoke("AddChatUserAsync", args: <Object>[json.decode(chatData)]);
} }
@ -553,51 +433,68 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId);
if (contain.isEmpty) { if (contain.isEmpty) {
searchedChats!.add( searchedChats!.add(
ChatUser( ChatUser(id: targetUserId, userName: targetUserName, unreadMessageCount: 0),
id: targetUserId,
userName: targetUserName,
),
); );
notifyListeners(); notifyListeners();
} }
if (!isFileSelected && !isMsgReply) { if (!isFileSelected && !isMsgReply) {
logger.d("Normal Text Message"); print("Normal Text Msg");
if (message.text == null || message.text.isEmpty) { if (message.text == null || message.text.isEmpty) {
return; return;
} }
sendChatToServer(chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: false, chatReplyId: null, isReply: false); sendChatToServer(
} chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: false, chatReplyId: null, isReply: false, isImageLoaded: false, image: null);
} // normal Text msg
if (isFileSelected && !isMsgReply) { if (isFileSelected && !isMsgReply) {
print("Normal Attachment Msg");
Utils.showLoading(context); Utils.showLoading(context);
//logger.d("Normal Attachment Message");
dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile);
logger.d(value);
String? ext = getFileExtension(selectedFile.path); String? ext = getFileExtension(selectedFile.path);
Utils.hideLoading(context); Utils.hideLoading(context);
sendChatToServer(chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: true, chatReplyId: null, isReply: false); sendChatToServer(
} chatEventId: 2,
fileTypeId: getFileType(ext.toString()),
targetUserId: targetUserId,
targetUserName: targetUserName,
isAttachment: true,
chatReplyId: null,
isReply: false,
isImageLoaded: true,
image: selectedFile.readAsBytesSync());
} // normal attachemnt msg
if (!isFileSelected && isMsgReply) { if (!isFileSelected && isMsgReply) {
// logger.d("Normal Text Message With Reply"); print("Normal Text To Text Reply");
if (message.text == null || message.text.isEmpty) { if (message.text == null || message.text.isEmpty) {
return; return;
} }
sendChatToServer( sendChatToServer(
chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, chatReplyId: repliedMsg.first.userChatHistoryId, isAttachment: false, isReply: true); chatEventId: 1,
} fileTypeId: null,
targetUserId: targetUserId,
targetUserName: targetUserName,
chatReplyId: repliedMsg.first.userChatHistoryId,
isAttachment: false,
isReply: true,
isImageLoaded: repliedMsg.first.isImageLoaded!,
image: repliedMsg.first.image);
} // reply msg over image && normal
if (isFileSelected && isMsgReply) { if (isFileSelected && isMsgReply) {
// logger.d("Attachment Message With Reply"); print("Reply With File");
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);
Utils.hideLoading(context); Utils.hideLoading(context);
sendChatToServer( sendChatToServer(
chatEventId: 2, chatEventId: 2,
fileTypeId: getFileType(ext.toString()), fileTypeId: getFileType(ext.toString()),
targetUserId: targetUserId, targetUserId: targetUserId,
targetUserName: targetUserName, targetUserName: targetUserName,
isAttachment: true, isAttachment: true,
chatReplyId: repliedMsg.first.userChatHistoryId, chatReplyId: repliedMsg.first.userChatHistoryId,
isReply: true, isReply: true,
); isImageLoaded: true,
image: selectedFile.readAsBytesSync());
} }
} }
@ -697,9 +594,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
Future<void> favoriteUser({required int userID, required int targetUserID}) async { Future<void> favoriteUser({required int userID, required int targetUserID}) async {
Response response = fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID);
await ApiClient().postJsonForResponse("${ApiConsts.chatServerBaseApiUrl}FavUser/addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token);
fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body);
if (favoriteChatUser.response != null) { if (favoriteChatUser.response != null) {
for (ChatUser user in searchedChats!) { for (ChatUser user in searchedChats!) {
if (user.id == favoriteChatUser.response!.targetUserId!) { if (user.id == favoriteChatUser.response!.targetUserId!) {
@ -712,21 +607,24 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
Future<void> unFavoriteUser({required int userID, required int targetUserID}) async { Future<void> unFavoriteUser({required int userID, required int targetUserID}) async {
Response response = await ApiClient() fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID);
.postJsonForResponse("${ApiConsts.chatServerBaseApiUrl}FavUser/deleteFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token);
fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body);
if (favoriteChatUser.response != null) { if (favoriteChatUser.response != null) {
for (var user in searchedChats!) { for (ChatUser user in searchedChats!) {
if (user.id == favoriteChatUser.response!.targetUserId!) { if (user.id == favoriteChatUser.response!.targetUserId!) {
user.isFav = favoriteChatUser.response!.isFav; user.isFav = favoriteChatUser.response!.isFav;
} }
} }
favUsersList.removeWhere((ChatUser element) => element.id == targetUserID); favUsersList.removeWhere(
(ChatUser element) => element.id == targetUserID,
);
} }
notifyListeners(); notifyListeners();
} }
void clearSelections() { void clearSelections() {
print("Hereee i am ");
searchedChats = pChatHistory; searchedChats = pChatHistory;
search.clear(); search.clear();
isChatScreenActive = false; isChatScreenActive = false;
@ -735,6 +633,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isFileSelected = false; isFileSelected = false;
repliedMsg = []; repliedMsg = [];
sFileType = ""; sFileType = "";
isMsgReply = false;
notifyListeners(); notifyListeners();
} }
@ -767,10 +666,28 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
// } // }
void msgScroll() { void msgScroll() {
scrollController.animateTo( // scrollController.animateTo(
scrollController.position.minScrollExtent - 100, // // index: 150,
duration: const Duration(milliseconds: 500), // duration: Duration(seconds: 2),
curve: Curves.easeIn, // curve: Curves.easeInOutCubic);
); // scrollController.animateTo(
} // scrollController.position.minScrollExtent - 100,
// duration: const Duration(milliseconds: 500),
// curve: Curves.easeIn,
// );
}
// Future<void> getDownLoadFile(String fileName) async {
// var data = await ChatApiClient().downloadURL(fileName: "data");
// Image.memory(data);
// }
// void getUserChatHistoryNotDeliveredAsync({required int userId}) async {
// try {
// await hubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]);
// } finally {
// hubConnection.off("GetUserChatHistoryNotDeliveredAsync", method: chatNotDelivered);
// }
// }
} }

@ -1,13 +1,17 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.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/consts.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';
import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/chat_count_conversation_model.dart'; import 'package:mohem_flutter_app/models/chat/chat_count_conversation_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/models/dashboard/drawer_menu_item_model.dart'; import 'package:mohem_flutter_app/models/dashboard/drawer_menu_item_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart';
@ -21,6 +25,7 @@ import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:signalr_netcore/signalr_client.dart';
/// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool /// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool
// ignore: prefer_mixin // ignore: prefer_mixin
@ -37,6 +42,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
//Chat //Chat
bool isChatCounterLoding = true; bool isChatCounterLoding = true;
bool isChatHubLoding = true;
int chatUConvCounter = 0; int chatUConvCounter = 0;
//Misssing Swipe //Misssing Swipe
@ -97,6 +103,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
leaveBalanceAccrual = null; leaveBalanceAccrual = null;
isChatCounterLoding = true; isChatCounterLoding = true;
isChatHubLoding = true;
chatUConvCounter = 0; chatUConvCounter = 0;
ticketBalance = 0; ticketBalance = 0;
@ -287,6 +294,26 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
} }
Future<void> getUserAutoLoginToken() async {
UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse;
} else {
Utils.showToast(
userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr",
);
}
}
Future<HubConnection> getHubConnection() async {
HubConnection hub;
HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
hub = HubConnectionBuilder()
.withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Web&access_token=${AppState().chatDetails!.response!.token}", options: httpOp)
.withAutomaticReconnect(retryDelays: <int>[2000, 5000, 10000, 20000]).build();
isChatHubLoding = false;
return hub;
}
void notify() { void notify() {
notifyListeners(); notifyListeners();
} }

@ -316,7 +316,7 @@ class _AddVacationRuleScreenState extends State<AddVacationRuleScreen> {
12.height, 12.height,
PopupMenuButton( PopupMenuButton(
child: DynamicTextFieldWidget( child: DynamicTextFieldWidget(
"Notification", LocaleKeys.notification.tr(),
selectedItemTypeNotification == null ? LocaleKeys.selectNotification.tr() : selectedItemTypeNotification!.nOTIFICATIONDISPLAYNAME!, selectedItemTypeNotification == null ? LocaleKeys.selectNotification.tr() : selectedItemTypeNotification!.nOTIFICATIONDISPLAYNAME!,
isEnable: false, isEnable: false,
isPopup: true, isPopup: true,

@ -91,6 +91,8 @@ class _IncomingCallState extends State<IncomingCall> with SingleTickerProviderSt
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: const <Widget>[ children: const <Widget>[
// todo @aamir, need to use extension mehtods
Text( Text(
"Aamir Saleem Ahmad", "Aamir Saleem Ahmad",
style: TextStyle( style: TextStyle(

@ -1,150 +1,237 @@
import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/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/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';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:sizer/sizer.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/ui/chat/chat_full_image_preview.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
// todo: @aamir use extension methods, and use correct widgets.
class ChatBubble extends StatelessWidget { class ChatBubble extends StatelessWidget {
const ChatBubble( ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key);
{Key? key,
required this.text,
required this.replyText,
required this.isCurrentUser,
required this.isSeen,
required this.isDelivered,
required this.dateTime,
required this.isReplied,
required this.userName})
: super(key: key);
final String text;
final String replyText;
final bool isCurrentUser;
final bool isSeen;
final bool isDelivered;
final String dateTime; final String dateTime;
final bool isReplied; final SingleUserChatModel cItem;
final String userName;
bool isCurrentUser = false;
bool isSeen = false;
bool isReplied = false;
int? fileTypeID;
String? fileTypeDescription;
bool isDelivered = false;
String userName = '';
void makeAssign() {
isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id ? true : false;
isSeen = cItem.isSeen == true ? true : false;
isReplied = cItem.userChatReplyResponse != null ? true : false;
fileTypeID = cItem.fileTypeId;
fileTypeDescription = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeDescription : "";
isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id && cItem.isDelivered == true ? true : false;
userName = AppState().chatDetails!.response!.userName == cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( makeAssign();
// padding: EdgeInsets.zero, return isCurrentUser ? currentUser(context) : receiptUser(context);
padding: EdgeInsets.only( }
left: isCurrentUser ? 110 : 20,
right: isCurrentUser ? 20 : 110,
bottom: 9,
),
child: Align( Widget currentUser(context) {
alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft, return Column(
child: DecoratedBox( crossAxisAlignment: CrossAxisAlignment.start,
decoration: BoxDecoration( children: [
color: MyColors.white, if (isReplied)
gradient: isCurrentUser ClipRRect(
? null borderRadius: BorderRadius.circular(5.0),
: const LinearGradient( child: Container(
transform: GradientRotation( width: double.infinity,
.46, decoration: BoxDecoration(
), border: Border(
begin: Alignment.topRight, left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
end: Alignment.bottomLeft, ),
colors: <Color>[ color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
MyColors.gradiantEndColor, ),
MyColors.gradiantStartColor, child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
(cItem.userChatReplyResponse != null ? cItem.userChatReplyResponse!.contant.toString() : "")
.toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4)
.paddingOnly(right: 5, top: 5, bottom: 8, left: 5),
], ],
), ).expanded,
borderRadius: BorderRadius.circular( if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 ||
10, cItem.userChatReplyResponse!.fileTypeId == 3 ||
), cItem.userChatReplyResponse!.fileTypeId == 4)
), // Container(
child: Padding( // padding: EdgeInsets.all(0), // Border width
padding: EdgeInsets.only( // decoration: BoxDecoration(color: Colors.red, borderRadius: const BorderRadius.all(Radius.circular(8))),
top: isReplied ? 8 : 5, // child: ClipRRect(
right: 8, // borderRadius: const BorderRadius.all(
left: 8, // Radius.circular(8),
bottom: 5, // ),
), // child: SizedBox.fromSize(
child: Column( // size: Size.fromRadius(8), // Image radius
crossAxisAlignment: CrossAxisAlignment.start, // child: showImage(
mainAxisAlignment: MainAxisAlignment.start, // isReplyPreview: true,
children: [ // fileName: cItem.userChatReplyResponse!.contant!,
if (isReplied) // fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg"),
ClipRRect( // ),
borderRadius: BorderRadius.circular( // ),
5.0, // ),
), ClipRRect(
child: Container( borderRadius: BorderRadius.circular(8.0),
decoration: BoxDecoration( child: SizedBox(
border: Border( height: 32,
left: BorderSide( width: 32,
width: 6, child: showImage(
color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white, isReplyPreview: true,
), fileName: cItem.userChatReplyResponse!.contant!,
), fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg")
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30), .paddingOnly(left: 10, right: 10, bottom: 16, top: 16),
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(userName)
.toText12(
color: MyColors.gradiantStartColor,
isBold: false,
)
.paddingOnly(
right: 5,
top: 5,
bottom: 0,
left: 5,
),
replyText
.toText10(
color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5),
isBold: false,
maxlines: 4,
)
.paddingOnly(
right: 5,
top: 5,
bottom: 8,
left: 5,
),
],
),
),
],
), ),
), ),
), ],
if (isReplied) 8.height, ),
text.toText12( ),
color: isCurrentUser ? MyColors.grey57Color : MyColors.white, ).paddingOnly(right: 5, bottom: 7),
if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3)
showImage(isReplyPreview: false, fileName: cItem.contant!, fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription).paddingOnly(right: 5).onPress(() {
showDialog(context: context, builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!));
}),
cItem.contant!.toText12(),
Align(
alignment: Alignment.centerRight,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
dateTime.toText10(
color: MyColors.grey41Color.withOpacity(.5),
),
7.width,
Icon(isDelivered ? Icons.done_all : Icons.done_all, color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, size: 14),
],
),
),
],
).paddingOnly(top: 11, left: 13, right: 7, bottom: 5).objectContainerView(disablePadding: true).paddingOnly(left: MediaQuery.of(context).size.width * 0.3);
}
Widget receiptUser(BuildContext context) {
return Container(
padding: const EdgeInsets.only(top: 11, left: 13, right: 7, bottom: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
gradient: const LinearGradient(
transform: GradientRotation(.83),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: <Color>[
MyColors.gradiantEndColor,
MyColors.gradiantStartColor,
],
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isReplied)
ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white)),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
), ),
Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.end, children: [
mainAxisAlignment: MainAxisAlignment.end, Column(
children: <Widget>[ crossAxisAlignment: CrossAxisAlignment.start,
dateTime.toText12( children: <Widget>[
color: isCurrentUser ? MyColors.grey41Color.withOpacity(.5) : MyColors.white.withOpacity(0.7), (userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
), (cItem.userChatReplyResponse != null ? cItem.userChatReplyResponse!.contant.toString() : "")
if (isCurrentUser) 5.width, .toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4)
// if (isCurrentUser) .paddingOnly(right: 5, top: 5, bottom: 8, left: 5),
// Icon( ],
// isDelivered ? Icons.done_all : Icons.done_all, ).expanded,
// color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 ||
// size: 14, cItem.userChatReplyResponse!.fileTypeId == 3 ||
// ), cItem.userChatReplyResponse!.fileTypeId == 4)
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: SizedBox(
height: 32,
width: 32,
child: showImage(
isReplyPreview: true,
fileName: cItem.userChatReplyResponse!.contant!,
fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg")),
).paddingOnly(left: 10, right: 10, bottom: 16, top: 16)
], ],
), ),
], ),
), ).paddingOnly(right: 5, bottom: 7),
if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3)
showImage(isReplyPreview: false, fileName: cItem.contant!, fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription ?? "image/jpg").paddingOnly(right: 5).onPress(() {
showDialog(context: context, builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!));
})
else
(cItem.contant! ?? "").toText12(color: Colors.white),
Align(
alignment: Alignment.centerRight,
child: dateTime.toText10(color: Colors.white.withOpacity(.71)),
), ),
), ],
), ),
); ).paddingOnly(right: MediaQuery.of(context).size.width * 0.3);
}
Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) {
if (cItem.isImageLoaded! && cItem.image != null) {
return Image.memory(
cItem.image!,
height: isReplyPreview ? 32 : 140,
width: isReplyPreview ? 32 : 227,
fit: BoxFit.cover,
);
} else {
return FutureBuilder<Uint8List>(
future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState != ConnectionState.waiting) {
if (snapshot.data == null) {
return SizedBox();
} else {
cItem.image = snapshot.data;
cItem.isImageLoaded = true;
return Image.memory(
snapshot.data,
height: isReplyPreview ? 32 : 140,
width: isReplyPreview ? 32 : 227,
fit: BoxFit.cover,
);
}
} else {
return SizedBox(
height: isReplyPreview ? 32 : 140,
width: isReplyPreview ? 32 : 227,
child: const Center(child: CircularProgressIndicator()),
);
}
},
);
}
} }
} }

@ -4,7 +4,6 @@ import 'dart:convert';
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_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart';
@ -13,13 +12,17 @@ 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/models/chat/call.dart'; import 'package:mohem_flutter_app/models/chat/call.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/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/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: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';
import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart'; import 'package:signalr_netcore/signalr_client.dart';
import 'package:sizer/sizer.dart';
import 'package:swipe_to/swipe_to.dart'; import 'package:swipe_to/swipe_to.dart';
class ChatDetailScreen extends StatefulWidget { class ChatDetailScreen extends StatefulWidget {
@ -38,18 +41,17 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
void getMoreChat() async { void getMoreChat() async {
if (userDetails != null) { if (userDetails != null) {
data.paginationVal = data.paginationVal + 10; data.paginationVal = data.paginationVal + 10;
if (userDetails != null) if (userDetails != null) {
data.getSingleUserChatHistory( data.getSingleUserChatHistory(
senderUID: AppState().chatDetails!.response!.id!.toInt(), senderUID: AppState().chatDetails!.response!.id!.toInt(),
receiverUID: userDetails["targetUser"].id, receiverUID: userDetails["targetUser"].id,
loadMore: true, loadMore: true,
isNewChat: false, isNewChat: false,
); );
}
} }
await Future.delayed( await Future.delayed(
const Duration( const Duration(milliseconds: 1000),
milliseconds: 1000,
),
); );
_rc.loadComplete(); _rc.loadComplete();
} }
@ -68,284 +70,146 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
} }
return Scaffold( return Scaffold(
backgroundColor: const Color(0xFFF8F8F8), backgroundColor: MyColors.backgroundColor,
appBar: AppBarWidget(context, appBar: AppBarWidget(
title: userDetails["targetUser"].userName.toString().replaceAll(".", " ").capitalizeFirstofEach, context,
showHomeButton: false, title: userDetails["targetUser"].userName.toString().replaceAll(".", " ").capitalizeFirstofEach,
image: userDetails["targetUser"].image, showHomeButton: false,
actions: [ image: userDetails["targetUser"].image,
IconButton( actions: [
onPressed: () { SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() {
// makeCall( // makeCall(callType: "AUDIO", con: hubConnection);
// callType: "AUDIO", }),
// con: data.hubConnection, 24.width,
// ); SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() {
}, // makeCall(callType: "VIDEO", con: hubConnection);
icon: SvgPicture.asset( }),
"assets/icons/chat/call.svg", 21.width,
width: 22, ],
height: 22, ),
),
),
IconButton(
onPressed: () {
// makeCall(
// callType: "VIDEO",
// con: data.hubConnection,
// );
},
icon: SvgPicture.asset(
"assets/icons/chat/video_call.svg",
width: 20,
height: 20,
),
),
10.width,
]),
body: Consumer<ChatProviderModel>( body: Consumer<ChatProviderModel>(
builder: (BuildContext context, ChatProviderModel m, Widget? child) { builder: (BuildContext context, ChatProviderModel m, Widget? child) {
return (m.isLoading return (m.isLoading
? ChatHomeShimmer() ? ChatHomeShimmer()
: Column( : Column(
children: <Widget>[ children: <Widget>[
Expanded( SmartRefresher(
flex: 2, enablePullDown: false,
child: SmartRefresher( enablePullUp: true,
enablePullDown: false, onLoading: () {
enablePullUp: true, getMoreChat();
onLoading: () { },
getMoreChat(); header: const MaterialClassicHeader(
}, color: MyColors.gradiantEndColor,
header: const MaterialClassicHeader( ),
color: MyColors.gradiantEndColor, controller: _rc,
), reverse: true,
controller: _rc, child: ListView.separated(
controller: m.scrollController,
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
reverse: true, reverse: true,
child: ListView.builder( itemCount: m.userChatHistory.length,
controller: m.scrollController, padding: const EdgeInsets.all(21),
shrinkWrap: true, separatorBuilder: (cxt, index) => 8.height,
physics: const BouncingScrollPhysics(), itemBuilder: (BuildContext context, int i) {
reverse: true, return SwipeTo(
itemCount: m.userChatHistory.length, iconColor: MyColors.lightGreenColor,
padding: const EdgeInsets.only(top: 20), child: ChatBubble(
itemBuilder: (BuildContext context, int i) { dateTime: m.dateFormte(m.userChatHistory[i].createdDate!),
return SwipeTo( cItem: m.userChatHistory[i],
iconColor: MyColors.lightGreenColor, ),
child: ChatBubble( onRightSwipe: () {
text: m.userChatHistory[i].contant.toString(), m.chatReply(
replyText: m.userChatHistory[i].userChatReplyResponse != null ? m.userChatHistory[i].userChatReplyResponse!.contant.toString() : "", m.userChatHistory[i],
isSeen: m.userChatHistory[i].isSeen == true ? true : false, );
isCurrentUser: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id ? true : false, },
isDelivered: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id && m.userChatHistory[i].isDelivered == true ? true : false, ).onPress(() {
dateTime: m.dateFormte(m.userChatHistory[i].createdDate!), logger.d(jsonEncode(m.userChatHistory[i]));
isReplied: m.userChatHistory[i].userChatReplyResponse != null ? true : false, });
userName: AppState().chatDetails!.response!.userName == m.userChatHistory[i].currentUserName.toString() ? "You" : m.userChatHistory[i].currentUserName.toString(), },
),
onRightSwipe: () {
m.chatReply(
m.userChatHistory[i],
);
},
);
},
),
), ),
), ).expanded,
if (m.isMsgReply) if (m.isMsgReply)
Row( SizedBox(
children: <Widget>[ height: 82,
Container( child: Row(
height: 80, children: <Widget>[
color: MyColors.textMixColor, Container(height: 82, color: MyColors.textMixColor, width: 6),
width: 6, Container(
), color: MyColors.darkTextColor.withOpacity(0.10),
Expanded( padding: const EdgeInsets.only(top: 11, left: 14, bottom: 14, right: 21),
child: Container( child: Row(
height: 80, children: [
color: MyColors.black.withOpacity(0.10), Column(
child: ListTile( crossAxisAlignment: CrossAxisAlignment.start,
title: (AppState().chatDetails!.response!.userName == m.repliedMsg.first.currentUserName.toString() children: [
? "You" (AppState().chatDetails!.response!.userName == m.repliedMsg.first.currentUserName.toString()
: m.repliedMsg.first.currentUserName.toString().replaceAll(".", " ")) ? "You"
.toText14(color: MyColors.lightGreenColor), : m.repliedMsg.first.currentUserName.toString().replaceAll(".", " "))
subtitle: (m.repliedMsg.isNotEmpty ? m.repliedMsg.first.contant! : "").toText12( .toText14(color: MyColors.lightGreenColor),
color: MyColors.white, (m.repliedMsg.isNotEmpty ? m.repliedMsg.first.contant! : "").toText12(color: MyColors.grey71Color, maxLine: 2)
maxLine: 2, ],
), ).expanded,
trailing: GestureDetector( 12.width,
onTap: m.closeMe, if (m.isMsgReply && m.repliedMsg.isNotEmpty) showReplyImage(m.repliedMsg),
child: Container( 12.width,
decoration: BoxDecoration( const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe),
color: MyColors.white.withOpacity(0.5), ],
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
child: const Icon(
Icons.close,
size: 23,
color: MyColors.white,
),
),
),
), ),
), ).expanded,
), ],
], ),
), ),
if (m.isFileSelected && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg") if (m.isFileSelected && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg")
Card( SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21),
margin: EdgeInsets.zero, TextField(
elevation: 0, controller: m.message,
child: Padding( decoration: InputDecoration(
padding: const EdgeInsets.only( hintText: m.isFileSelected ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(),
left: 20, hintStyle: TextStyle(color: m.isFileSelected ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14),
right: 20, border: InputBorder.none,
top: 20, focusedBorder: InputBorder.none,
bottom: 0, enabledBorder: InputBorder.none,
), errorBorder: InputBorder.none,
child: Card( disabledBorder: InputBorder.none,
margin: EdgeInsets.zero, filled: true,
shape: RoundedRectangleBorder( fillColor: MyColors.white,
borderRadius: BorderRadius.circular(0), contentPadding: const EdgeInsets.only(
), left: 21,
elevation: 0, top: 20,
child: Container( bottom: 20,
height: 200,
decoration: BoxDecoration(
image: DecorationImage(
image: FileImage(
m.selectedFile,
),
fit: BoxFit.cover,
),
borderRadius: const BorderRadius.all(
Radius.circular(0),
),
),
child: const SizedBox(
width: double.infinity,
height: 200,
),
),
),
), ),
), prefixIconConstraints: const BoxConstraints(),
Card( prefixIcon: m.sFileType.isNotEmpty
margin: EdgeInsets.zero, ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15)
child: TextField( : null,
controller: m.message, suffixIcon: SizedBox(
decoration: InputDecoration( width: 100,
hintText: m.isFileSelected ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(), child: Row(
hintStyle: TextStyle( mainAxisAlignment: MainAxisAlignment.end,
color: m.isFileSelected ? MyColors.darkTextColor : MyColors.grey98Color, crossAxisAlignment: CrossAxisAlignment.center, // added line
fontSize: 14, children: <Widget>[
), if (m.sFileType.isNotEmpty)
border: InputBorder.none, Row(
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
contentPadding: EdgeInsets.only(
left: m.sFileType.isNotEmpty ? 10 : 20,
right: m.sFileType.isNotEmpty ? 0 : 5,
top: 20,
bottom: 20,
),
prefixIcon: m.sFileType.isNotEmpty
? Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[ children: <Widget>[
SvgPicture.asset( const Icon(Icons.cancel, size: 15, color: MyColors.redA3Color).paddingOnly(right: 5),
m.getType(m.sFileType), ("Clear").toText11(color: MyColors.redA3Color, isUnderLine: true).paddingOnly(left: 0),
height: 30,
width: 25,
alignment: Alignment.center,
fit: BoxFit.cover,
).paddingOnly(left: 20),
], ],
) ).onPress(() => m.removeAttachment()).paddingOnly(right: 25),
: null, if (m.sFileType.isEmpty)
suffixIcon: SizedBox( RotationTransition(
width: 96, turns: const AlwaysStoppedAnimation(45 / 360),
child: Row( child: const Icon(Icons.attach_file_rounded, size: 26, color: MyColors.grey3AColor).onPress(
mainAxisAlignment: MainAxisAlignment.end, () => m.selectImageToUpload(context),
crossAxisAlignment: CrossAxisAlignment.center, // added line
children: <Widget>[
if (m.sFileType.isNotEmpty)
IconButton(
padding: EdgeInsets.zero,
alignment: Alignment.centerRight,
icon: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
decoration: const BoxDecoration(
color: MyColors.redA3Color,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: const Icon(
Icons.close,
size: 15,
color: MyColors.white,
),
),
("Clear")
.toText11(
color: MyColors.redA3Color,
)
.paddingOnly(
left: 4,
),
],
),
onPressed: () async {
m.removeAttachment();
},
),
if (m.sFileType.isEmpty)
RotationTransition(
turns: const AlwaysStoppedAnimation(45 / 360),
child: IconButton(
padding: EdgeInsets.zero,
alignment: Alignment.topRight,
icon: const Icon(
Icons.attach_file_rounded,
size: 26,
color: MyColors.grey3AColor,
),
onPressed: () async {
m.selectImageToUpload(context);
},
),
),
IconButton(
alignment: Alignment.centerRight,
padding: EdgeInsets.zero,
icon: SvgPicture.asset(
"assets/icons/chat/chat_send_icon.svg",
height: 26,
width: 26,
), ),
onPressed: () { ).paddingOnly(right: 25),
m.sendChatMessage( SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26).onPress(
userDetails["targetUser"].id, () => m.sendChatMessage(userDetails["targetUser"].id, userDetails["targetUser"].userName, context),
userDetails["targetUser"].userName, ),
context, ],
);
},
)
],
),
).paddingOnly(
right: 20,
), ),
), ).paddingOnly(right: 21),
), ),
), ),
], ],
@ -355,40 +219,56 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
); );
} }
Widget showReplyImage(List<SingleUserChatModel> data) {
if (data.first.isImageLoaded! && data.first.image != null) {
return Container(
width: 43,
height: 43,
decoration: BoxDecoration(
border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), image: DecorationImage(image: MemoryImage(data.first.image!), fit: BoxFit.cover)),
);
} else {
return const SizedBox();
}
}
void makeCall({required String callType, required HubConnection con}) async { void makeCall({required String callType, required HubConnection con}) async {
print("================== Make call Triggered ============================"); print("================== Make call Triggered ============================");
logger.d(jsonEncode(AppState().chatDetails!.response));
Map<String, dynamic> json = { Map<String, dynamic> json = {
"callerID": AppState().chatDetails!.response!.id!.toString(), "callerID": AppState().chatDetails!.response!.id!.toString(),
"callReciverID": userDetails["targetUser"].id.toString(), "callReceiverID": userDetails["targetUser"].id.toString(),
"notification_foreground": "true", "notification_foreground": "true",
"message": "Aamir is calling ", "message": "Aamir is calling",
"title": "Video Call", "title": "Video Call",
"type": callType == "VIDEO" ? "Video" : "Audio", "type": callType == "VIDEO" ? "Video" : "Audio",
"identity": "Aamir.Muhammad", "identity": AppState().chatDetails!.response!.userName,
"name": "Aamir Saleem Ahmad", "name": AppState().chatDetails!.response!.title,
"is_call": "true", "is_call": "true",
"is_webrtc": "true", "is_webrtc": "true",
"contant": "Start video Call Aamir.Muhammad", "contant": "Start video Call ${AppState().chatDetails!.response!.userName}",
"contantNo": "775d1f11-62d9-6fcc-91f6-21f8c14559fb", "contantNo": "775d1f11-62d9-6fcc-91f6-21f8c14559fb",
"chatEventId": "3", "chatEventId": "3",
"fileTypeId": null, "fileTypeId": null,
"currentUserId": "266642", "currentUserId": AppState().chatDetails!.response!.id!.toString(),
"chatSource": "1", "chatSource": "1",
"userChatHistoryLineRequestList": [ "userChatHistoryLineRequestList": [
{"isSeen": false, "isDelivered": false, "targetUserId": 341682, "targetUserStatus": 4} {
"isSeen": false,
"isDelivered": false,
"targetUserId": userDetails["targetUser"].id,
"targetUserStatus": 4,
}
], ],
// "server": "https://192.168.8.163:8086", // "server": "https://192.168.8.163:8086",
"server": "https://livecareturn.hmg.com:8086", "server": "https://livecareturn.hmg.com:8086",
}; };
CallDataModel callData = CallDataModel.fromJson(json);
CallDataModel incomingCallData = CallDataModel.fromJson(json);
await Navigator.push( await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (BuildContext context) => OutGoingCall( builder: (BuildContext context) => OutGoingCall(
isVideoCall: callType == "VIDEO" ? true : false, isVideoCall: callType == "VIDEO" ? true : false,
OutGoingCallData: incomingCallData, OutGoingCallData: callData,
), ),
), ),
); );

@ -0,0 +1,41 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
class ChatImagePreviewScreen extends StatelessWidget {
const ChatImagePreviewScreen({Key? key, required this.imgTitle, required this.img}) : super(key: key);
final String imgTitle;
final Uint8List img;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Dialog(
backgroundColor: Colors.transparent,
insetPadding: const EdgeInsets.all(10),
child: Stack(
alignment: Alignment.center,
children: [
Image.memory(
img,
fit: BoxFit.cover,
height: 400,
width: double.infinity,
).paddingAll(10),
const Positioned(
right: 0,
top: 0,
child: Icon(Icons.cancel, color: MyColors.redA3Color, size: 35),
)
],
),
),
);
}
}

@ -1,19 +1,13 @@
import 'dart:convert';
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/api/chat/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/colors.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';
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/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/screens/items_for_sale/fragments/items_for_sale.dart';
import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.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';
@ -31,32 +25,21 @@ class _ChatHomeState extends State<ChatHome> {
@override @override
void initState() { void initState() {
// TODO: implement initState
super.initState(); super.initState();
data = Provider.of<ChatProviderModel>(context, listen: false); data = Provider.of<ChatProviderModel>(context, listen: false);
data.getUserAutoLoginToken(context).whenComplete(() {
data.getUserRecentChats();
});
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
data.clearAll(); data.clearAll();
if (data.hubConInitialized) {
data.hubConnection.stop();
}
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: MyColors.white, backgroundColor: MyColors.white,
appBar: AppBarWidget( appBar: AppBarWidget(context, title: LocaleKeys.chat.tr(), showHomeButton: true),
context,
title: LocaleKeys.chat.tr(),
showHomeButton: true,
),
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
Container( Container(

@ -1,14 +1,15 @@
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; 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/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
@ -21,6 +22,16 @@ class ChatHomeScreen extends StatefulWidget {
class _ChatHomeScreenState extends State<ChatHomeScreen> { class _ChatHomeScreenState extends State<ChatHomeScreen> {
TextEditingController search = TextEditingController(); TextEditingController search = TextEditingController();
late ChatProviderModel data;
@override
void initState() {
// TODO: implement initState
super.initState();
data = Provider.of<ChatProviderModel>(context, listen: false);
data.registerEvents();
data.getUserRecentChats();
}
@override @override
void dispose() { void dispose() {
@ -36,110 +47,87 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
builder: (BuildContext context, ChatProviderModel m, Widget? child) { builder: (BuildContext context, ChatProviderModel m, Widget? child) {
return m.isLoading return m.isLoading
? ChatHomeShimmer() ? ChatHomeShimmer()
: ListView( : Column(
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
children: <Widget>[ children: <Widget>[
Padding( TextField(
padding: const EdgeInsets.symmetric( controller: m.search,
vertical: 20, style: const TextStyle(color: MyColors.darkTextColor, fontWeight: FontWeight.w500, fontSize: 12),
horizontal: 20, onChanged: (String val) {
), m.filter(val);
child: TextField( },
controller: m.search, decoration: InputDecoration(
onChanged: (String val) { border: fieldBorder(radius: 5, color: 0xFFE5E5E5),
m.filter(val); focusedBorder: fieldBorder(radius: 5, color: 0xFFE5E5E5),
}, enabledBorder: fieldBorder(radius: 5, color: 0xFFE5E5E5),
decoration: InputDecoration( contentPadding: const EdgeInsets.all(11),
border: fieldBorder( hintText: LocaleKeys.searchfromchat.tr(),
radius: 5, hintStyle: const TextStyle(color: MyColors.lightTextColor, fontStyle: FontStyle.italic, fontWeight: FontWeight.w500, fontSize: 12),
color: 0xFFE5E5E5, filled: true,
), fillColor: const Color(0xFFF7F7F7),
focusedBorder: fieldBorder( suffixIconConstraints: const BoxConstraints(),
radius: 5, suffixIcon: m.search.text.isNotEmpty
color: 0xFFE5E5E5, ? IconButton(
), constraints: const BoxConstraints(),
enabledBorder: fieldBorder( onPressed: () {
radius: 5, m.clearSelections();
color: 0xFFE5E5E5, },
), icon: const Icon(Icons.clear, size: 22),
contentPadding: const EdgeInsets.symmetric( color: MyColors.redA3Color,
horizontal: 15, )
vertical: 10, : null,
),
hintText: LocaleKeys.searchfromchat.tr(),
hintStyle: const TextStyle(
color: MyColors.lightTextColor,
fontStyle: FontStyle.italic,
),
filled: true,
fillColor: const Color(
0xFFF7F7F7,
),
suffixIcon: m.search.text.isNotEmpty
? IconButton(
onPressed: () {
m.clearSelections();
},
icon: const Icon(
Icons.clear,
size: 22,
),
color: MyColors.redA3Color,
)
: null,
),
), ),
), ).paddingOnly(top: 20, bottom: 14),
if (m.searchedChats != null) if (m.searchedChats != null)
ListView.separated( ListView.separated(
itemCount: m.searchedChats!.length, itemCount: m.searchedChats!.length,
padding: const EdgeInsets.only(
bottom: 80,
),
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const ClampingScrollPhysics(),
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
// todo @aamir, remove list tile, make a custom ui instead
return SizedBox( return SizedBox(
height: 55, height: 55,
child: ListTile( child: Row(
leading: Stack( children: [
children: <Widget>[ Stack(
SvgPicture.asset( children: <Widget>[
"assets/images/user.svg", SvgPicture.asset(
height: 48, "assets/images/user.svg",
width: 48, height: 48,
), width: 48,
Positioned( ),
right: 5, Positioned(
bottom: 1, right: 5,
child: Container( bottom: 1,
width: 10, child: Container(
height: 10, width: 10,
decoration: BoxDecoration( height: 10,
color: m.searchedChats![index].userStatus == 1 ? MyColors.green2DColor : Colors.red, decoration: BoxDecoration(
borderRadius: const BorderRadius.all( color: m.searchedChats![index].userStatus == 1 ? MyColors.green2DColor : Colors.red,
Radius.circular(10), borderRadius: const BorderRadius.all(
Radius.circular(10),
),
), ),
), ),
), )
) ],
], ),
), Column(
title: (m.searchedChats![index].userName!.replaceFirst(".", " ").capitalizeFirstofEach ?? "").toText14(color: MyColors.darkTextColor), mainAxisAlignment: MainAxisAlignment.start,
// subtitle: (m.searchedChats![index].isTyping == true ? "Typing ..." : "").toText11(color: MyColors.normalTextColor), crossAxisAlignment: CrossAxisAlignment.start,
trailing: SizedBox( children: [
width: 60, (m.searchedChats![index].userName!.replaceFirst(".", " ").capitalizeFirstofEach ?? "").toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 13),
child: Row( ],
crossAxisAlignment: CrossAxisAlignment.center, ).expanded,
mainAxisAlignment: MainAxisAlignment.end, SizedBox(
mainAxisSize: MainAxisSize.max, width: 60,
children: <Widget>[ child: Row(
if (m.searchedChats![index].unreadMessageCount! > 0) crossAxisAlignment: CrossAxisAlignment.center,
Flexible( mainAxisAlignment: MainAxisAlignment.end,
child: Container( mainAxisSize: MainAxisSize.max,
padding: EdgeInsets.zero, children: <Widget>[
alignment: Alignment.centerRight, if (m.searchedChats![index].unreadMessageCount! > 0)
Container(
alignment: Alignment.center,
width: 18, width: 18,
height: 18, height: 18,
decoration: const BoxDecoration( decoration: const BoxDecoration(
@ -153,17 +141,12 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
color: MyColors.white, color: MyColors.white,
) )
.center, .center,
), ).paddingOnly(right: 10).center,
), Icon(
Flexible( m.searchedChats![index].isFav != null && m.searchedChats![index].isFav == false ? Icons.star_sharp : Icons.star_sharp,
child: IconButton(
alignment: Alignment.centerRight,
padding: EdgeInsets.zero,
icon: Icon(
m.searchedChats![index].isFav != null && m.searchedChats![index].isFav == false ? Icons.star_sharp : Icons.star_sharp,
),
color: m.searchedChats![index].isFav != null && m.searchedChats![index].isFav == true ? MyColors.yellowColor : MyColors.grey35Color, color: m.searchedChats![index].isFav != null && m.searchedChats![index].isFav == true ? MyColors.yellowColor : MyColors.grey35Color,
onPressed: () { ).onPress(
() {
if (m.searchedChats![index].isFav == null || m.searchedChats![index].isFav == false) { if (m.searchedChats![index].isFav == null || m.searchedChats![index].isFav == false) {
m.favoriteUser( m.favoriteUser(
userID: AppState().chatDetails!.response!.id!, userID: AppState().chatDetails!.response!.id!,
@ -181,40 +164,28 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
); );
} }
}, },
), ).center
) ],
], ),
), ),
), ],
minVerticalPadding: 0,
onTap: () {
Navigator.pushNamed(
context,
AppRoutes.chatDetailed,
arguments: {"targetUser": m.searchedChats![index], "isNewChat": false},
).then((Object? value) {
// m.GetUserChatHistoryNotDeliveredAsync(userId: int.parse(AppState().chatDetails!.response!.id.toString()));
m.clearSelections();
m.notifyListeners();
});
},
), ),
); ).onPress(() {
Navigator.pushNamed(
context,
AppRoutes.chatDetailed,
arguments: {"targetUser": m.searchedChats![index], "isNewChat": false},
).then((Object? value) {
// m.GetUserChatHistoryNotDeliveredAsync(userId: int.parse(AppState().chatDetails!.response!.id.toString()));
m.clearSelections();
m.notifyListeners();
});
});
}, },
separatorBuilder: (BuildContext context, int index) => const Padding( separatorBuilder: (BuildContext context, int index) => const Divider(color: MyColors.lightGreyE5Color).paddingOnly(left: 59),
padding: EdgeInsets.only( ).paddingOnly(bottom: 70).expanded,
right: 10,
left: 70,
),
child: Divider(
color: Color(
0xFFE5E5E5,
),
),
),
),
], ],
); ).paddingOnly(left: 21, right: 21);
}, },
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
@ -240,6 +211,9 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
), ),
), ),
onPressed: () async { onPressed: () async {
// String plainText = 'Muhamad.Alam@cloudsolutions.com.sa';
// String key = "PeShVmYp";
// passEncrypt(plainText, "PeShVmYp");
showMyBottomSheet( showMyBottomSheet(
context, context,
callBackFunc: () {}, callBackFunc: () {},
@ -267,4 +241,127 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
), ),
); );
} }
//
// void passEncrypt(String text, String pass) async {
// var salt = randomUint8List(8);
// var keyndIV = deriveKeyAndIV(pass, salt);
// var key = encrypt.Key(keyndIV.item1);
// var iv = encrypt.IV(keyndIV.item2);
// var encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
// var encrypted = encrypter.encrypt(text, iv: iv);
// Uint8List encryptedBytesWithSalt = Uint8List.fromList(createUint8ListFromString("Salted__") + salt + encrypted.bytes);
// var resulttt = base64.encode(encryptedBytesWithSalt);
// print("Enc : " + resulttt);
//
// decryptAESCryptoJS(resulttt, pass);
// }
//
// Uint8List randomUint8List(int length) {
// assert(length > 0);
// var random = Random();
// var ret = Uint8List(length);
// for (var i = 0; i < length; i++) {
// ret[i] = random.nextInt(256);
// }
// return ret;
// }
//
// void decryptAESCryptoJS(String encrypted, String passphrase) {
// try {
// Uint8List encryptedBytesWithSalt = base64.decode(encrypted);
// Uint8List encryptedBytes = encryptedBytesWithSalt.sublist(16, encryptedBytesWithSalt.length);
// var salt = encryptedBytesWithSalt.sublist(8, 16);
// var keyndIV = deriveKeyAndIV(passphrase, salt);
// var key = encrypt.Key(keyndIV.item1);
// var iv = encrypt.IV(keyndIV.item2);
// var encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
// var decrypted = encrypter.decrypt64(base64.encode(encryptedBytes), iv: iv);
// print("Dec : " + decrypted);
// // return decrypted;
// } catch (error) {
// throw error;
// }
// }
void enc(String input) {
var ekey = "PeShVmYp";
var eIV = "j70IbWYn";
List<int> eByt = utf8.encode(ekey);
List<int> eIvByt = utf8.encode(eIV);
List<int> iByt = utf8.encode(input);
}
// ///Accepts encrypted data and decrypt it. Returns plain text
// String decryptWithAES(String key, Encrypted encryptedData) {
// var cipherKey = encrypt.Key.fromUtf8(key);
// var encryptService = Encrypter(AES(cipherKey, mode: AESMode.cbc,padding: null));
// var initVector = IV.fromUtf8(key.substring(0, 16));
// return encryptService.decrypt(encryptedData, iv: initVector);
// }
//
// ///Encrypts the given plainText using the key. Returns encrypted data
// Encrypted encryptWithAES(String key, String plainText) {
// var cipherKey = encrypt.Key.fromUtf8(key);
// var encryptService = Encrypter(AES(cipherKey, mode: AESMode.cbc,padding: null));
// var initVector = IV.fromUtf8("j70IbWYn");
// Encrypted encryptedData = encryptService.encrypt(plainText, iv: initVector);
// print(encryptedData.base64);
// return encryptedData;
// }
//
// Tuple2<Uint8List, Uint8List> deriveKeyAndIV(String passphrase, Uint8List salt) {
// var password = createUint8ListFromString(passphrase);
// Uint8List concatenatedHashes = Uint8List(0);
// Uint8List currentHash = Uint8List(0);
// bool enoughBytesForKey = false;
// Uint8List preHash = Uint8List(0);
//
// while (!enoughBytesForKey) {
// int preHashLength = currentHash.length + password.length + salt.length;
// if (currentHash.length > 0)
// preHash = Uint8List.fromList(currentHash + password + salt);
// else
// preHash = Uint8List.fromList(password + salt);
//
// currentHash = preHash;
// concatenatedHashes = Uint8List.fromList(concatenatedHashes + currentHash);
// if (concatenatedHashes.length >= 48) enoughBytesForKey = true;
// }
//
// var keyBtyes = concatenatedHashes.sublist(0, 32);
// var ivBtyes = concatenatedHashes.sublist(32, 48);
// return new Tuple2(keyBtyes, ivBtyes);
// }
//
// Uint8List createUint8ListFromString(String s) {
// var ret = new Uint8List(s.length);
// for (var i = 0; i < s.length; i++) {
// ret[i] = s.codeUnitAt(i);
// }
// return ret;
// }
//
// Uint8List genRandomWithNonZero(int seedLength) {
// var random = Random.secure();
// const int randomMax = 245;
// Uint8List uint8list = Uint8List(seedLength);
// for (int i = 0; i < seedLength; i++) {
// uint8list[i] = random.nextInt(randomMax) + 1;
// }
// return uint8list;
// }
//
//
//
// void test(String text, String kk) {
// Uint8List key = Uint8List.fromList(utf8.encode(kk));
// PaddedBlockCipher cipher = exp.PaddedBlockCipherImpl(exp.PKCS7Padding(), exp.ECBBlockCipher(exp.AESEngine()));
// cipher.init(true, PaddedBlockCipherParameters<CipherParameters, CipherParameters>(KeyParameter(key), null));
// var byte = Uint8List.fromList(utf8.encode(text));
// var data = cipher.process(byte);
// print(data);
// }
} }

@ -1,7 +1,8 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart'; import 'package:mohem_flutter_app/main.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/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/classes/utils.dart';
@ -26,81 +27,80 @@ class ChatFavoriteUsersScreen extends StatelessWidget {
return m.favUsersList != null && m.favUsersList.isNotEmpty return m.favUsersList != null && m.favUsersList.isNotEmpty
? ListView.separated( ? ListView.separated(
itemCount: m.favUsersList!.length, itemCount: m.favUsersList!.length,
padding: const EdgeInsets.only(top: 20),
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return SizedBox( return SizedBox(
height: 55, height: 55,
child: ListTile( child: Row(
leading: Stack( children: [
children: <Widget>[ Stack(
SvgPicture.asset( children: <Widget>[
"assets/images/user.svg", SvgPicture.asset(
height: 48, "assets/images/user.svg",
width: 48, height: 48,
), width: 48,
Positioned( ),
right: 5, Positioned(
bottom: 1, right: 5,
child: Container( bottom: 1,
width: 10, child: Container(
height: 10, width: 10,
decoration: BoxDecoration( height: 10,
color: m.favUsersList![index].userStatus == 1 ? MyColors.green2DColor : Colors.red, decoration: BoxDecoration(
borderRadius: const BorderRadius.all( color: m.favUsersList![index].userStatus == 1 ? MyColors.green2DColor : Colors.red,
Radius.circular(10), borderRadius: const BorderRadius.all(
Radius.circular(10),
),
), ),
), ),
), )
) ],
],
),
title: (m.favUsersList![index].userName!.replaceFirst(".", " ").capitalizeFirstofEach ?? "").toText14(
color: MyColors.darkTextColor,
),
trailing: IconButton(
alignment: Alignment.centerRight,
padding: EdgeInsets.zero,
icon: Icon(
m.favUsersList![index].isFav! ? Icons.star : Icons.star_border,
), ),
color: m.favUsersList![index].isFav! ? MyColors.yellowColor : MyColors.grey35Color, Column(
onPressed: () { mainAxisAlignment: MainAxisAlignment.start,
if (m.favUsersList![index].isFav!) crossAxisAlignment: CrossAxisAlignment.start,
m.unFavoriteUser( children: [
userID: AppState().chatDetails!.response!.id!, (m.favUsersList![index].userName!.replaceFirst(".", " ").capitalizeFirstofEach ?? "").toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 13),
targetUserID: m.favUsersList![index].id!, ],
); ).expanded,
}, SizedBox(
), width: 60,
minVerticalPadding: 0, child: Row(
onTap: () { crossAxisAlignment: CrossAxisAlignment.center,
Navigator.pushNamed( mainAxisAlignment: MainAxisAlignment.end,
context, mainAxisSize: MainAxisSize.max,
AppRoutes.chatDetailed, children: <Widget>[
arguments: {"targetUser": m.favUsersList![index], "isNewChat": false}, Icon(
).then( m.favUsersList![index].isFav! ? Icons.star : Icons.star_border,
(Object? value) { color: m.favUsersList![index].isFav! ? MyColors.yellowColor : MyColors.grey35Color,
m.clearSelections(); ).onPress(() {
}, if (m.favUsersList![index].isFav!) {
); m.unFavoriteUser(
}, userID: AppState().chatDetails!.response!.id!,
targetUserID: m.favUsersList![index].id!,
);
}
}).center,
],
),
),
],
), ),
); ).onPress(() {
Navigator.pushNamed(
context,
AppRoutes.chatDetailed,
arguments: {"targetUser": m.favUsersList![index], "isNewChat": false},
).then(
(Object? value) {
m.clearSelections();
},
);
});
}, },
separatorBuilder: (BuildContext context, int index) => const Padding( separatorBuilder: (BuildContext context, int index) => const Divider(color: MyColors.lightGreyE5Color).paddingOnly(left: 70),
padding: EdgeInsets.only( ).paddingAll(21)
right: 10,
left: 70,
),
child: Divider(
color: Color(
0xFFE5E5E5,
),
),
),
)
: Column( : Column(
children: <Widget>[ children: <Widget>[
Utils.getNoDataWidget(context).expanded, Utils.getNoDataWidget(context).expanded,

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
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';
@ -13,12 +14,12 @@ 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/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/models/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/landing/widget/app_drawer.dart'; import 'package:mohem_flutter_app/ui/landing/widget/app_drawer.dart';
import 'package:mohem_flutter_app/ui/landing/widget/menus_widget.dart'; import 'package:mohem_flutter_app/ui/landing/widget/menus_widget.dart';
import 'package:mohem_flutter_app/ui/landing/widget/services_widget.dart'; import 'package:mohem_flutter_app/ui/landing/widget/services_widget.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_banner.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_banner.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/mark_attendance_widget.dart'; import 'package:mohem_flutter_app/widgets/mark_attendance_widget.dart';
@ -26,6 +27,9 @@ import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'
import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart';
late HubConnection hubConnection;
class DashboardScreen extends StatefulWidget { class DashboardScreen extends StatefulWidget {
DashboardScreen({Key? key}) : super(key: key); DashboardScreen({Key? key}) : super(key: key);
@ -38,6 +42,7 @@ class DashboardScreen extends StatefulWidget {
class _DashboardScreenState extends State<DashboardScreen> { class _DashboardScreenState extends State<DashboardScreen> {
late DashboardProviderModel data; late DashboardProviderModel data;
late MarathonProvider marathonProvider;
final GlobalKey<ScaffoldState> _scaffoldState = GlobalKey(); final GlobalKey<ScaffoldState> _scaffoldState = GlobalKey();
final RefreshController _refreshController = RefreshController(initialRefresh: false); final RefreshController _refreshController = RefreshController(initialRefresh: false);
@ -49,13 +54,27 @@ class _DashboardScreenState extends State<DashboardScreen> {
super.initState(); super.initState();
scheduleMicrotask(() { scheduleMicrotask(() {
data = Provider.of<DashboardProviderModel>(context, listen: false); data = Provider.of<DashboardProviderModel>(context, listen: false);
marathonProvider = Provider.of<MarathonProvider>(context, listen: false);
_bHubCon();
_onRefresh(); _onRefresh();
}); });
} }
void buildHubConnection() async {
hubConnection = await data.getHubConnection();
await hubConnection.start();
}
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
hubConnection.stop();
}
void _bHubCon() {
data.getUserAutoLoginToken().whenComplete(() {
buildHubConnection();
});
} }
void _onRefresh() async { void _onRefresh() async {
@ -72,6 +91,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
data.fetchLeaveTicketBalance(context, DateTime.now()); data.fetchLeaveTicketBalance(context, DateTime.now());
data.fetchMenuEntries(); data.fetchMenuEntries();
data.getCategoryOffersListAPI(context); data.getCategoryOffersListAPI(context);
marathonProvider.getMarathonDetailsFromApi();
data.fetchChatCounts(); data.fetchChatCounts();
_refreshController.refreshCompleted(); _refreshController.refreshCompleted();
} }
@ -84,29 +104,29 @@ class _DashboardScreenState extends State<DashboardScreen> {
// actions: [ // actions: [
// IconButton( // IconButton(
// onPressed: () { // onPressed: () {
// data.getITGNotification().then((value) { // data.getITGNotification().then((val) {
// print("--------------------detail_1-----------------"); // if (val!.result!.data != null) {
// if (value!.result!.data != null) { // if (val.result!.data!.notificationType == "Survey") {
// print(value.result!.data!.notificationMasterId); // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data);
// print(value.result!.data!.notificationType);
// if (value.result!.data!.notificationType == "Survey") {
// Navigator.pushNamed(context, AppRoutes.survey, arguments: value.result!.data);
// } else { // } else {
// DashboardApiClient().getAdvertisementDetail(value.result!.data!.notificationMasterId ?? "").then( // DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then(
// (value) { // (value) {
// if (value!.mohemmItgResponseItem!.statusCode == 200) { // if (value!.mohemmItgResponseItem!.statusCode == 200) {
// if (value.mohemmItgResponseItem!.result!.data != null) { // if (value.mohemmItgResponseItem!.result!.data != null) {
// String? image64 = value.mohemmItgResponseItem!.result!.data!.advertisement!.viewAttachFileColl!.first.base64String; // Navigator.pushNamed(context, AppRoutes.advertisement, arguments: {
// print(image64); // "masterId": val.result!.data!.notificationMasterId,
// var sp = image64!.split("base64,"); // "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement,
// Navigator.push( // });
// context, //
// MaterialPageRoute( // // Navigator.push(
// builder: (context) => MovieTheaterBody( // // context,
// encodedBytes: sp[1], // // MaterialPageRoute(
// ), // // builder: (BuildContext context) => ITGAdsScreen(
// ), // // addMasterId: val.result!.data!.notificationMasterId!,
// ); // // advertisement: value.mohemmItgResponseItem!.result!.data!.advertisement!,
// // ),
// // ),
// // );
// } // }
// } // }
// }, // },
@ -217,11 +237,14 @@ class _DashboardScreenState extends State<DashboardScreen> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
9.height, 9.height,
CountdownTimer( Directionality(
endTime: model.endTime, textDirection: ui.TextDirection.ltr,
onEnd: null, child: CountdownTimer(
endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), endTime: model.endTime,
textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), onEnd: null,
endWidget: "00:00:00".toText14(color: Colors.white, isBold: true),
textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold),
),
), ),
LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white),
9.height, 9.height,
@ -298,7 +321,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
), ),
], ],
).paddingOnly(left: 21, right: 21, top: 7), ).paddingOnly(left: 21, right: 21, top: 7),
const MarathonBanner().paddingAll(20), context.watch<MarathonProvider>().isLoading ? MarathonBannerShimmer().paddingAll(20) : MarathonBanner().paddingAll(20),
ServicesWidget(), ServicesWidget(),
// 8.height, // 8.height,
Container( Container(
@ -344,7 +367,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
], ],
).paddingOnly(left: 21, right: 21), ).paddingOnly(left: 21, right: 21),
Consumer<DashboardProviderModel>( Consumer<DashboardProviderModel>(
builder: (context, model, child) { builder: (BuildContext context, DashboardProviderModel model, Widget? child) {
return SizedBox( return SizedBox(
height: 103 + 33, height: 103 + 33,
child: ListView.separated( child: ListView.separated(

@ -0,0 +1,135 @@
import 'dart:convert';
import 'dart:io' as Io;
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads;
import 'package:path_provider/path_provider.dart';
import 'package:video_player/video_player.dart';
class ITGAdsScreen extends StatefulWidget {
const ITGAdsScreen({Key? key}) : super(key: key);
@override
_ITGAdsScreenState createState() => _ITGAdsScreenState();
}
class _ITGAdsScreenState extends State<ITGAdsScreen> {
late Future<VideoPlayerController> _futureController;
late VideoPlayerController _controller;
bool skip = false;
bool isVideo = false;
bool isImage = false;
String ext = '';
late File imageFile;
ads.Advertisement? advertisementData;
dynamic data;
String? masterID;
void checkFileType() async {
String? rFile = advertisementData!.viewAttachFileColl!.first.base64String;
String? rFileExt = advertisementData!.viewAttachFileColl!.first.fileName;
ext = "." + rFileExt!.split(".").last.toLowerCase();
if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif") {
await processImage(rFile!);
isImage = true;
} else {
isVideo = true;
_futureController = createVideoPlayer(rFile!);
}
setState(() {});
initTimer();
}
Future processImage(String encodedBytes) async {
try {
Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last);
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1
imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext");
imageFile.writeAsBytesSync(decodedBytes);
} catch (e) {
logger.d(e);
}
}
Future<VideoPlayerController> createVideoPlayer(String encodedBytes) async {
try {
Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last);
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1
File file = Io.File("${appDocumentsDirectory.path}/myAdsVideo.mp4");
file.writeAsBytesSync(decodedBytes);
VideoPlayerController controller = VideoPlayerController.file(file);
await controller.initialize();
await controller.play();
await controller.setVolume(1.0);
await controller.setLooping(false);
return controller;
} catch (e) {
return new VideoPlayerController.asset("dataSource");
}
}
void initTimer() {
Future.delayed(const Duration(seconds: 5), () {
skip = true;
setState(() {});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
data = ModalRoute.of(context)!.settings.arguments;
if (advertisementData == null) advertisementData = data["advertisement"] as ads.Advertisement;
if (masterID == null) masterID = data["masterId"];
if (advertisementData != null) {
checkFileType();
}
double height = MediaQuery.of(context).size.height * .25;
return Scaffold(
body: Column(
children: [
if (isVideo)
SizedBox(
height: MediaQuery.of(context).size.height * .3,
child: FutureBuilder(
future: _futureController,
builder: (BuildContext context, AsyncSnapshot<Object?> snapshot) {
if (snapshot.connectionState == ConnectionState.done && snapshot.data != null) {
_controller = snapshot.data as VideoPlayerController;
return AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
),
if (isImage) Image.file(imageFile),
if (skip)
ElevatedButton(
onPressed: () async {
// DashboardApiClient().setAdvertisementViewed(widget.addMasterId, widget.advertisement!.advertisementId!).then((value) {
// logger.d(value);
// });
},
child: const Text("Go To Dashboard"),
)
],
),
);
}
}

@ -1,96 +0,0 @@
import 'dart:convert';
import 'dart:io' as Io;
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class MovieTheaterBody extends StatefulWidget {
final String encodedBytes;
const MovieTheaterBody({required this.encodedBytes});
@override
_MovieTheaterBodyState createState() => _MovieTheaterBodyState();
}
class _MovieTheaterBodyState extends State<MovieTheaterBody> {
late Future<VideoPlayerController> _futureController;
late VideoPlayerController _controller;
Future<VideoPlayerController> createVideoPlayer() async {
try {
var decodedBytes = base64Decode(widget.encodedBytes);
var file = Io.File("decodedBezkoder.mp4");
file.writeAsBytesSync(decodedBytes);
VideoPlayerController controller = VideoPlayerController.file(file);
await controller.initialize();
await controller.setLooping(true);
return controller;
} catch (e) {
print("object0000000");
print(e);
return new VideoPlayerController.asset("dataSource");
}
}
@override
void initState() {
_futureController = createVideoPlayer();
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Expanded(
child: FutureBuilder(
future: _futureController,
builder: (context, snapshot) {
//UST: 05/2021 - MovieTheaterBody - id:11 - 2pts - Criação
if (snapshot.connectionState == ConnectionState.done && snapshot.data != null) {
_controller = snapshot.data as VideoPlayerController;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
),
const SizedBox(
height: 50,
),
FloatingActionButton(
onPressed: () {
setState(() {
if (_controller.value.isPlaying) {
_controller.pause();
} else {
// If the video is paused, play it.
_controller.play();
}
});
},
backgroundColor: Colors.green[700],
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
)
],
);
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
),
);
}
}

@ -99,10 +99,13 @@ class _TodayAttendanceScreenState extends State<TodayAttendanceScreen2> {
child: CountdownTimer( child: CountdownTimer(
endTime: model.endTime, endTime: model.endTime,
widgetBuilder: (context, v) { widgetBuilder: (context, v) {
return AutoSizeText( return Directionality(
getValue(v?.hours) + " : " + getValue(v?.min) + " : " + getValue(v?.sec), textDirection: TextDirection.ltr,
maxLines: 1, child: AutoSizeText(
style: const TextStyle(color: Colors.white, fontSize: 42, letterSpacing: -1.92, fontWeight: FontWeight.bold, height: 1), getValue(v?.hours) + " : " + getValue(v?.min) + " : " + getValue(v?.sec),
maxLines: 1,
style: const TextStyle(color: Colors.white, fontSize: 42, letterSpacing: -1.92, fontWeight: FontWeight.bold, height: 1),
),
); );
}, },
onEnd: null, onEnd: null,
@ -116,7 +119,7 @@ class _TodayAttendanceScreenState extends State<TodayAttendanceScreen2> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
LocaleKeys.shiftTime.tr().tr().toTextAuto(color: MyColors.greyACColor, fontSize: 18, maxLine: 1).paddingOnly(left: 21,right: 21), LocaleKeys.shiftTime.tr().tr().toTextAuto(color: MyColors.greyACColor, fontSize: 18, maxLine: 1).paddingOnly(left: 21, right: 21),
(model.attendanceTracking!.pShtName ?? "00:00:00").toString().toTextAuto(color: Colors.white, isBold: true, fontSize: 26, maxLine: 1), (model.attendanceTracking!.pShtName ?? "00:00:00").toString().toTextAuto(color: Colors.white, isBold: true, fontSize: 26, maxLine: 1),
], ],
), ),

@ -139,8 +139,10 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
Utils.hideLoading(context); Utils.hideLoading(context);
await Navigator.pushNamed(context, AppRoutes.requestSubmitScreen, arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submit.pTRANSACTIONID!, "", "add_leave_balance")); var res = await Navigator.pushNamed(context, AppRoutes.requestSubmitScreen, arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submit.pTRANSACTIONID!, "", "add_leave_balance"));
Utils.showLoading(context); if (res != null && res == true) {
Utils.showLoading(context);
}
await LeaveBalanceApiClient().cancelHrTransaction(submit.pTRANSACTIONID!); await LeaveBalanceApiClient().cancelHrTransaction(submit.pTRANSACTIONID!);
Utils.hideLoading(context); Utils.hideLoading(context);
} catch (ex) { } catch (ex) {

@ -128,6 +128,7 @@ class _LoginScreenState extends State<LoginScreen> {
Navigator.pushNamed(context, AppRoutes.verifyLogin, Navigator.pushNamed(context, AppRoutes.verifyLogin,
arguments: "$firebaseToken"); arguments: "$firebaseToken");
} }
Utils.saveStringFromPrefs(SharedPrefsConsts.password, password.text);
} catch (ex) { } catch (ex) {
Utils.hideLoading(context); Utils.hideLoading(context);
Utils.handleException(ex, context, (msg) { Utils.handleException(ex, context, (msg) {
@ -142,8 +143,8 @@ class _LoginScreenState extends State<LoginScreen> {
isAppOpenBySystem = (ModalRoute.of(context)!.settings.arguments ?? true) as bool; isAppOpenBySystem = (ModalRoute.of(context)!.settings.arguments ?? true) as bool;
if (!kReleaseMode) { if (!kReleaseMode) {
// username.text = "15444"; // Maha User // username.text = "15444"; // Maha User
// username.text = "15153"; // Tamer User username.text = "15153"; // Tamer User
// password.text = "Abcd@12345"; password.text = "Abcd@1234";
// username.text = "206535"; // Hashim User // username.text = "206535"; // Hashim User
// password.text = "Namira786"; // password.text = "Namira786";

@ -1,9 +1,12 @@
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:lottie/lottie.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/date_uitl.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/classes/lottie_consts.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/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';
@ -15,8 +18,6 @@ import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
final int dummyEndTime = DateTime.now().millisecondsSinceEpoch + 1000 * 30;
class MarathonIntroScreen extends StatelessWidget { class MarathonIntroScreen extends StatelessWidget {
const MarathonIntroScreen({Key? key}) : super(key: key); const MarathonIntroScreen({Key? key}) : super(key: key);
@ -25,26 +26,18 @@ class MarathonIntroScreen extends StatelessWidget {
MarathonProvider provider = context.watch<MarathonProvider>(); MarathonProvider provider = context.watch<MarathonProvider>();
return Scaffold( return Scaffold(
appBar: AppBarWidget(context, title: LocaleKeys.brainMarathon.tr()), appBar: AppBarWidget(context, title: LocaleKeys.brainMarathon.tr()),
body: Stack( body: Column(
children: <Widget>[ children: <Widget>[
SingleChildScrollView( ListView(
child: Column( padding: const EdgeInsets.all(21),
children: <Widget>[ children: <Widget>[
MarathonDetailsCard(provider: provider).paddingAll(15), MarathonDetailsCard(provider: provider),
MarathonTimerCard( 10.height,
provider: provider, MarathonTimerCard(provider: provider, timeToMarathon: DateTime.parse(provider.marathonDetailModel.startTime!).millisecondsSinceEpoch,),
timeToMarathon: dummyEndTime, ],
).paddingOnly(left: 15, right: 15, bottom: 15), ).expanded,
const SizedBox( 1.divider,
height: 100, MarathonFooter(provider: provider),
),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: MarathonFooter(provider: provider),
),
], ],
), ),
); );
@ -61,7 +54,7 @@ class MarathonDetailsCard extends StatelessWidget {
return Container( return Container(
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: 18, horizontal: 14),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -70,37 +63,44 @@ class MarathonDetailsCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
LocaleKeys.contestTopicAbout.tr().toText16(color: MyColors.grey77Color), LocaleKeys.contestTopicAbout.tr().toText16(color: MyColors.grey77Color),
"Saudi Arabia".toText20(color: MyColors.textMixColor, isBold: true), "${AppState().isArabic(context) ? provider.marathonDetailModel.titleAr : provider.marathonDetailModel.titleEn}".toText20(color: MyColors.textMixColor, isBold: true),
Row( Row(
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
child: "Nam suscipit turpis in pharetra euismsdef. Duis rutrum at nulla id aliquam".toText14(color: MyColors.grey77Color), child: "${AppState().isArabic(context) ? provider.marathonDetailModel.descAr : provider.marathonDetailModel.descEn}".toText14(color: MyColors.grey77Color),
) )
], ],
), ),
if (provider.itsMarathonTime) ...<Widget>[ if (provider.itsMarathonTime && provider.marathonDetailModel.sponsors != null) ...<Widget>[
5.height, 5.height,
provider.marathonDetailModel.sponsors?.first.sponsorPrizes != null
? Row(
children: <Widget>[
"${LocaleKeys.prize.tr()} ".toText16(color: MyColors.grey77Color, isBold: true),
"${AppState().isArabic(context) ? provider.marathonDetailModel.sponsors?.first.sponsorPrizes?.first.marathonPrizeAr : provider.marathonDetailModel.sponsors?.first.sponsorPrizes?.first.marathonPrizeAr}"
.toText16(color: MyColors.greenColor, isBold: true),
],
)
: const SizedBox(),
Row( Row(
children: <Widget>[ children: <Widget>[
LocaleKeys.prize.tr().toText16(color: MyColors.grey77Color, isBold: true), "${LocaleKeys.sponsoredBy.tr()} ".toText16(color: MyColors.grey77Color),
" LED 55\" Android TV".toText16(color: MyColors.greenColor, isBold: true), "${AppState().isArabic(context) ? provider.marathonDetailModel.sponsors?.first.nameAr : provider.marathonDetailModel.sponsors?.first.nameEn}"
], .toText16(color: MyColors.darkTextColor, isBold: true),
),
Row(
children: <Widget>[
LocaleKeys.sponsoredBy.tr().toText16(color: MyColors.grey77Color),
" Extra".toText16(color: MyColors.darkTextColor, isBold: true),
], ],
), ),
10.height, 10.height,
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Image.asset( Image.network(
"assets/images/logos/main_mohemm_logo.png", provider.marathonDetailModel.sponsors!.first.image!,
height: 40, height: 40,
fit: BoxFit.fill,
width: 150, width: 150,
fit: BoxFit.fill,
errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
return const Center();
},
) )
], ],
), ),
@ -128,30 +128,23 @@ class MarathonTimerCard extends StatelessWidget {
return Container( return Container(
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: 18, horizontal: 14),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Row( Row(
children: <Widget>[ children: <Widget>[
LocaleKeys.gameDate.tr().toText16(color: MyColors.grey77Color), "${LocaleKeys.gameDate.tr()} ".toText16(color: MyColors.grey77Color),
" 10 Oct, 2022".toText16(color: MyColors.darkTextColor, isBold: true), DateUtil.getMonthDayYearDateFormatted(DateTime.parse(provider.marathonDetailModel.startTime!)).toText16(color: MyColors.darkTextColor, isBold: true),
], ],
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
LocaleKeys.gameTime.tr().toText16(color: MyColors.grey77Color), "${LocaleKeys.gameTime.tr()} ".toText16(color: MyColors.grey77Color),
" 3:00pm".toText16(color: MyColors.darkTextColor, isBold: true), DateUtil.formatDateToTimeLang(DateTime.parse(provider.marathonDetailModel.startTime!), AppState().isArabic(context)).toText16(color: MyColors.darkTextColor, isBold: true),
], ],
), ),
Lottie.asset( Lottie.asset(MyLottieConsts.hourGlassLottie, height: 200),
MyLottieConsts.hourGlassLottie, BuildCountdownTimer(timeToMarathon: timeToMarathon, provider: provider, screenFlag: 1),
height: 200,
),
BuildCountdownTimer(
timeToMarathon: timeToMarathon,
provider: provider,
screenFlag: 1,
),
], ],
), ),
); );
@ -172,38 +165,19 @@ class MarathonFooter extends StatelessWidget {
children: <InlineSpan>[ children: <InlineSpan>[
TextSpan( TextSpan(
text: LocaleKeys.note.tr(), text: LocaleKeys.note.tr(),
style: const TextStyle( style: const TextStyle(color: MyColors.darkTextColor, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.bold),
color: MyColors.darkTextColor,
fontSize: 17,
letterSpacing: -0.64,
fontWeight: FontWeight.bold,
),
), ),
TextSpan( TextSpan(
text: " " + LocaleKeys.demoMarathonNoteP1.tr(), text: " " + LocaleKeys.demoMarathonNoteP1.tr(),
style: const TextStyle( style: const TextStyle(color: MyColors.grey77Color, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.w500),
color: MyColors.grey77Color,
fontSize: 17,
letterSpacing: -0.64,
fontWeight: FontWeight.w500,
),
), ),
TextSpan( TextSpan(
text: " " + LocaleKeys.demoMarathonNoteP2.tr(), text: " " + LocaleKeys.demoMarathonNoteP2.tr(),
style: const TextStyle( style: const TextStyle(color: MyColors.darkTextColor, fontSize: 17, fontWeight: FontWeight.bold),
color: MyColors.darkTextColor,
fontSize: 17,
fontWeight: FontWeight.bold,
),
), ),
TextSpan( TextSpan(
text: " " + LocaleKeys.demoMarathonNoteP3.tr(), text: " " + LocaleKeys.demoMarathonNoteP3.tr(),
style: const TextStyle( style: const TextStyle(color: MyColors.grey77Color, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.w500),
color: MyColors.grey77Color,
fontSize: 17,
letterSpacing: -0.64,
fontWeight: FontWeight.w500,
),
) )
], ],
), ),
@ -212,10 +186,21 @@ class MarathonFooter extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return provider.itsMarathonTime return !provider.itsMarathonTime
? DefaultButton( ? DefaultButton(
LocaleKeys.joinMarathon.tr(), LocaleKeys.joinMarathon.tr(),
() => Navigator.pushNamed(context, AppRoutes.marathonScreen), () async {
Utils.showLoading(context);
try {
provider.resetValues();
await provider.connectSignalrAndJoinMarathon(context);
} catch (e, s) {
Utils.confirmDialog(context, e.toString());
print(s);
}
Utils.hideLoading(context);
Navigator.pushNamed(context, AppRoutes.marathonScreen);
},
).insideContainer ).insideContainer
: Container( : Container(
color: Colors.white, color: Colors.white,
@ -225,7 +210,9 @@ class MarathonFooter extends StatelessWidget {
buildNoteForDemo(), buildNoteForDemo(),
DefaultButton( DefaultButton(
LocaleKeys.joinDemoMarathon.tr(), LocaleKeys.joinDemoMarathon.tr(),
() {}, () {
provider.connectSignalrAndJoinMarathon(context);
},
color: MyColors.yellowColorII, color: MyColors.yellowColorII,
).insideContainer, ).insideContainer,
], ],

@ -3,12 +3,64 @@ 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/material.dart'; import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/api/marathon/marathon_api_client.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/ui/marathon/widgets/question_card.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart';
class MarathonProvider extends ChangeNotifier { class MarathonProvider extends ChangeNotifier {
final AppinioSwiperController swiperController = AppinioSwiperController(); final AppinioSwiperController swiperController = AppinioSwiperController();
MarathonDetailModel marathonDetailModel = MarathonDetailModel();
List<CardContent> cardContentList = <CardContent>[];
QuestionModel currentQuestion = QuestionModel();
QuestionCardStatus questionCardStatus = QuestionCardStatus.question;
int? selectedOptionIndex;
int currentQuestionTime = 0;
void onNewQuestionReceived(QuestionModel newQuestion) {
if (currentQuestionNumber > 0) {
swipeCardLeft();
}
selectedOptionIndex = null;
currentQuestionNumber++;
currentQuestion = newQuestion;
cardContentList.add(const CardContent());
currentQuestionTime = newQuestion.questionTime!;
questionCardStatus = QuestionCardStatus.question;
notifyListeners();
}
void addItemToList(CardContent value) {
cardContentList.add(value);
notifyListeners();
}
void updateCurrentQuestionOptionStatus(QuestionsOptionStatus status, int index) {
for (int i = 0; i < currentQuestion.questionOptions!.length; i++) {
currentQuestion.questionOptions![i].optionStatus = QuestionsOptionStatus.unSelected;
}
currentQuestion.questionOptions![index].optionStatus = status;
selectedOptionIndex = index;
notifyListeners();
}
void updateQuestionCardStatus(QuestionCardStatus status) {
questionCardStatus = status;
notifyListeners();
}
bool _isLoading = false;
bool get isLoading => _isLoading;
set isLoading(bool value) {
_isLoading = value;
notifyListeners();
}
bool _itsMarathonTime = false; bool _itsMarathonTime = false;
bool get itsMarathonTime => _itsMarathonTime; bool get itsMarathonTime => _itsMarathonTime;
@ -27,14 +79,7 @@ class MarathonProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void swipeCardLeft() { int _currentQuestionNumber = 0;
currentQuestionNumber = currentQuestionNumber + 1;
swiperController.swipeLeft();
notifyListeners();
}
int _currentQuestionNumber = 1;
final int totalQuestions = 10;
int get currentQuestionNumber => _currentQuestionNumber; int get currentQuestionNumber => _currentQuestionNumber;
@ -43,44 +88,73 @@ class MarathonProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void resetAll() { int _totalMarathoners = 23;
isSelectedOptions[0] = false;
isSelectedOptions[1] = false; int get totalMarathoners => _totalMarathoners;
isSelectedOptions[2] = false;
isSelectedOptions[3] = false; set totalMarathoners(int value) {
_totalMarathoners = value;
notifyListeners();
}
void swipeCardLeft() {
swiperController.swipeLeft();
notifyListeners();
}
void getCorrectAnswerAndUpdateAnswerColor() {
if (selectedOptionIndex != null) {
if (currentQuestion.questionOptions![selectedOptionIndex!].isCorrectOption!) {
updateCurrentQuestionOptionStatus(QuestionsOptionStatus.correct, selectedOptionIndex!);
} else {
updateCurrentQuestionOptionStatus(QuestionsOptionStatus.wrong, selectedOptionIndex!);
}
}
}
void updateCardStatusToAnswer() {
if (currentQuestionNumber == 0) {
return;
}
if (selectedOptionIndex != null) {
if (currentQuestion.questionOptions![selectedOptionIndex!].isCorrectOption!) {
updateQuestionCardStatus(QuestionCardStatus.correctAnswer);
} else {
updateQuestionCardStatus(QuestionCardStatus.wrongAnswer);
}
} else {
updateQuestionCardStatus(QuestionCardStatus.skippedAnswer);
}
} }
Timer timerU = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); Timer timerU = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});
int start = 8;
void startTimer(BuildContext context) { void startTimer(BuildContext context) {
start = 8;
const Duration oneSec = Duration(seconds: 1); const Duration oneSec = Duration(seconds: 1);
timerU = Timer.periodic( timerU = Timer.periodic(
oneSec, oneSec,
(Timer timer) async { (Timer timer) async {
if (start == 0) { if (currentQuestionTime == 2) {
if (currentQuestionNumber == 9) { getCorrectAnswerAndUpdateAnswerColor();
timer.cancel(); }
cancelTimer(); if (currentQuestionTime == 0) {
isMarathonCompleted = true; updateCardStatusToAnswer();
await Future<dynamic>.delayed(const Duration(seconds: 3)).whenComplete( // if (currentQuestionNumber == 9) {
() => Navigator.pushReplacementNamed( // timer.cancel();
context, // cancelTimer();
AppRoutes.marathonWinnerSelection, // isMarathonCompleted = true;
), // await Future<dynamic>.delayed(const Duration(seconds: 2)).whenComplete(
); // () => Navigator.pushReplacementNamed(context, AppRoutes.marathonWinnerSelection),
// );
resetValues(); //
// resetValues();
return; //
} // return;
resetAll(); // }
timer.cancel(); // timer.cancel();
cancelTimer();
swipeCardLeft();
} else { } else {
start--; currentQuestionTime--;
} }
notifyListeners(); notifyListeners();
}, },
@ -88,9 +162,12 @@ class MarathonProvider extends ChangeNotifier {
} }
void resetValues() { void resetValues() {
_currentQuestionNumber = 0;
cardContentList.clear();
timerU.cancel(); timerU.cancel();
_isMarathonCompleted = false; _isMarathonCompleted = false;
_currentQuestionNumber = 1; currentQuestionTime = 0;
currentQuestion = QuestionModel();
notifyListeners(); notifyListeners();
} }
@ -98,4 +175,18 @@ class MarathonProvider extends ChangeNotifier {
timerU.cancel(); timerU.cancel();
notifyListeners(); notifyListeners();
} }
Future<void> getMarathonDetailsFromApi() async {
isLoading = true;
notifyListeners();
await MarathonApiClient().getMarathonToken().whenComplete(() async {
marathonDetailModel = await MarathonApiClient().getMarathonDetails();
isLoading = false;
notifyListeners();
});
}
Future<void> connectSignalrAndJoinMarathon(BuildContext context) async {
await MarathonApiClient().buildHubConnection(context);
}
} }

@ -6,7 +6,6 @@ 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/classes/lottie_consts.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';
@ -14,10 +13,9 @@ 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/custom_status_widget.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/custom_status_widget.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/question_card_builder.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';
import 'package:sizer/sizer.dart';
import 'package:steps_indicator/steps_indicator.dart';
class MarathonScreen extends StatelessWidget { class MarathonScreen extends StatelessWidget {
const MarathonScreen({Key? key}) : super(key: key); const MarathonScreen({Key? key}) : super(key: key);
@ -25,48 +23,52 @@ class MarathonScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
MarathonProvider provider = context.watch<MarathonProvider>(); MarathonProvider provider = context.watch<MarathonProvider>();
return Scaffold( return WillPopScope(
appBar: AppBarWidget(context, title: LocaleKeys.brainMarathon.tr()), child: Scaffold(
body: SingleChildScrollView( appBar: AppBarWidget(context, title: LocaleKeys.brainMarathon.tr()),
child: Column( body: SingleChildScrollView(
children: <Widget>[ child: Column(
20.height, children: <Widget>[
MarathonProgressContainer(provider: provider).paddingOnly(left: 21, right: 21), 20.height,
if (provider.isMarathonCompleted) MarathonProgressContainer(provider: provider).paddingOnly(left: 21, right: 21),
InkWell( QuestionCardBuilder(
onTap: () { onQuestion: (BuildContext context) => QuestionCard(provider: provider),
Navigator.pushReplacementNamed( onCompleted: (BuildContext context) => CustomStatusWidget(
context, asset: Lottie.asset(MyLottieConsts.allQuestions, height: 200),
AppRoutes.marathonWinnerSelection, title: LocaleKeys.congrats.tr().toText22(color: MyColors.greenColor),
); subTitle: LocaleKeys.allQuestionsCorrect.toText18(color: MyColors.darkTextColor),
}, ),
child: CustomStatusWidget( onCorrectAnswer: (BuildContext context) => CustomStatusWidget(
asset: Lottie.asset( asset: Lottie.asset(MyLottieConsts.allQuestions, height: 200),
MyLottieConsts.allQuestions, title: LocaleKeys.congrats.tr().toText22(color: MyColors.greenColor),
height: 200, subTitle: LocaleKeys.yourAnswerCorrect.toText18(color: MyColors.darkTextColor),
), ),
title: Text( onWinner: (BuildContext context) => QuestionCard(provider: provider),
LocaleKeys.congrats.tr(), onWrongAnswer: (BuildContext context) => CustomStatusWidget(
style: const TextStyle( asset: Image.asset(MyLottieConsts.wrongAnswerGif, height: 200),
height: 23 / 24, title: const Text(""),
color: MyColors.greenColor, subTitle: LocaleKeys.wrongAnswer.tr().toText18(color: MyColors.darkTextColor),
fontSize: 27, ),
letterSpacing: -1, onSkippedAnswer: (BuildContext context) => CustomStatusWidget(
fontWeight: FontWeight.w600, asset: Image.asset(MyLottieConsts.wrongAnswerGif, height: 200),
), title: const Text(""),
), subTitle: LocaleKeys.youMissedTheQuestion.tr().toText18(color: MyColors.darkTextColor),
subTitle: Text( ),
LocaleKeys.allQuestionsCorrect.tr(), questionCardStatus: provider.questionCardStatus,
textAlign: TextAlign.center, onFindingWinner: (BuildContext context) => CustomStatusWidget(
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: MyColors.darkTextColor, letterSpacing: -1.08), asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168),
), title: LocaleKeys.fingersCrossed.tr().toText22(color: MyColors.greenColor),
).paddingOnly(top: 12, left: 21, right: 21), subTitle: LocaleKeys.winnerSelectedRandomly.tr().toText18(color: MyColors.darkTextColor),
) ),
else ).paddingOnly(top: 12, left: 21, right: 21),
QuestionCard(provider: provider).paddingOnly(top: 12, left: 21, right: 21), ],
], ),
), ),
), ),
onWillPop: () {
provider.resetValues();
return Future<bool>.value(true);
},
); );
} }
} }
@ -91,7 +93,6 @@ class _MarathonProgressContainerState extends State<MarathonProgressContainer> {
@override @override
void dispose() { void dispose() {
widget.provider.cancelTimer();
super.dispose(); super.dispose();
} }
@ -100,7 +101,7 @@ class _MarathonProgressContainerState extends State<MarathonProgressContainer> {
return Container( return Container(
width: double.infinity, width: double.infinity,
decoration: MyDecorations.shadowDecoration, decoration: MyDecorations.shadowDecoration,
padding: const EdgeInsets.all(21), padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 13),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
@ -108,47 +109,90 @@ class _MarathonProgressContainerState extends State<MarathonProgressContainer> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(color: MyColors.greenColor, borderRadius: BorderRadius.circular(5)),
color: MyColors.greenColor,
borderRadius: BorderRadius.circular(5),
),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 8), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 8),
child: "${widget.provider.currentQuestionNumber.toString()} / ${widget.provider.totalQuestions.toString()} ${LocaleKeys.question.tr()}".toText12(color: MyColors.white), child: "${widget.provider.currentQuestionNumber.toString()} / ${widget.provider.marathonDetailModel.totalQuestions.toString()} ${LocaleKeys.question.tr()}"
.toText12(color: MyColors.white),
), ),
"23 ${LocaleKeys.marathoners.tr()}".toText14(), "${widget.provider.totalMarathoners} ${LocaleKeys.marathoners.tr()}".toText14(),
"00:${widget.provider.start < 10 ? "0${widget.provider.start}" : widget.provider.start}".toText18(), "00:${widget.provider.currentQuestionTime < 10 ? "0${widget.provider.currentQuestionTime}" : widget.provider.currentQuestionTime}"
.toText18(color: widget.provider.currentQuestionTime < 5 ? MyColors.redColor : MyColors.black),
], ],
), ),
15.height,
StepsIndicator(
lineLength: SizerUtil.deviceType == DeviceType.tablet ? MediaQuery.of(context).size.width * 0.077 : MediaQuery.of(context).size.width * 0.054,
nbSteps: 10,
selectedStep: widget.provider.currentQuestionNumber,
doneLineColor: MyColors.greenColor,
doneStepColor: MyColors.greenColor,
doneLineThickness: 6,
undoneLineThickness: 6,
selectedStepSize: 10,
unselectedStepSize: 10,
doneStepSize: 10,
selectedStepBorderSize: 0,
unselectedStepBorderSize: 0,
selectedStepColorIn: MyColors.greenColor,
selectedStepColorOut: MyColors.greenColor,
unselectedStepColorIn: MyColors.lightGreyDeColor,
unselectedStepColorOut: MyColors.lightGreyDeColor,
undoneLineColor: MyColors.lightGreyDeColor,
enableLineAnimation: false,
enableStepAnimation: false,
),
12.height, 12.height,
stepper(widget.provider.currentQuestionNumber),
8.height,
Row( Row(
children: <Widget>[ children: <Widget>[
"${widget.provider.currentQuestionNumber * 10}% ${LocaleKeys.completed.tr()}".toText14(isBold: true), "${((widget.provider.currentQuestionNumber / widget.provider.marathonDetailModel.totalQuestions!) * 100).toInt()}% ${LocaleKeys.completed.tr()}".toText14(),
], ],
), ),
], ],
), ),
); );
} }
Widget stepper(int value) {
return SizedBox(
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (int i = 0; i < 10; i++)
if (value <= i) roundContainer(MyColors.lightGreyDeColor, i != 0) else roundContainer(MyColors.greenColor, i != 0)
],
),
);
}
Widget roundContainer(Color color, bool isNeedLeftBorder) {
if (isNeedLeftBorder) {
return Row(
children: [
Divider(thickness: 6, color: color).expanded,
Container(
width: 10,
height: 10,
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
),
],
).expanded;
}
return Container(
width: 10,
height: 10,
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
);
}
} }
// InkWell(
// onTap: () {
// Navigator.pushReplacementNamed(
// context,
// AppRoutes.marathonWinnerSelection,
// );
// },
// child: CustomStatusWidget(
// asset: Lottie.asset(
// MyLottieConsts.allQuestions,
// height: 200,
// ),
// title: Text(
// LocaleKeys.congrats.tr(),
// style: const TextStyle(
// height: 23 / 24,
// color: MyColors.greenColor,
// fontSize: 27,
// letterSpacing: -1,
// fontWeight: FontWeight.w600,
// ),
// ),
// subTitle: Text(
// LocaleKeys.allQuestionsCorrect.tr(),
// textAlign: TextAlign.center,
// style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: MyColors.darkTextColor, letterSpacing: -1.08),
// ),
// ).paddingOnly(top: 12, left: 21, right: 21),
// )

@ -29,7 +29,7 @@ class MarathonWinnerSelection extends StatelessWidget {
children: [ children: [
20.height, 20.height,
QualifiersContainer(provider: provider).paddingOnly(left: 21, right: 21), QualifiersContainer(provider: provider).paddingOnly(left: 21, right: 21),
20.height, 12.height,
InkWell( InkWell(
onTap: () { onTap: () {
Navigator.pushNamed(context, AppRoutes.marathonWinnerScreen); Navigator.pushNamed(context, AppRoutes.marathonWinnerScreen);
@ -52,8 +52,8 @@ class MarathonWinnerSelection extends StatelessWidget {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
"Muhammad Shrouff".toText18(isBold: true, color: MyColors.white), "Muhammad Shrouff".toText17(isBold: true, color: MyColors.white),
"837436".toText18(isBold: true, color: MyColors.white), "837436".toText17(isBold: true, color: MyColors.white),
], ],
), ),
), ),
@ -67,10 +67,10 @@ class MarathonWinnerSelection extends StatelessWidget {
title: Text( title: Text(
LocaleKeys.fingersCrossed.tr(), LocaleKeys.fingersCrossed.tr(),
style: const TextStyle( style: const TextStyle(
height: 23 / 24, height: 27 / 27,
color: MyColors.greenColor, color: MyColors.greenColor,
fontSize: 27, fontSize: 27,
letterSpacing: -1, letterSpacing: -1.08,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@ -78,9 +78,9 @@ class MarathonWinnerSelection extends StatelessWidget {
LocaleKeys.winnerSelectedRandomly.tr(), LocaleKeys.winnerSelectedRandomly.tr(),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: const TextStyle( style: const TextStyle(
color: MyColors.grey77Color, color: MyColors.darkTextColor,
fontSize: 16, fontSize: 18,
letterSpacing: -0.64, letterSpacing: -0.72,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
)).paddingOnly(left: 21, right: 21, top: 20, bottom: 20), )).paddingOnly(left: 21, right: 21, top: 20, bottom: 20),
@ -108,14 +108,14 @@ class _QualifiersContainerState extends State<QualifiersContainer> {
@override @override
void initState() { void initState() {
scheduleMicrotask(() { scheduleMicrotask(() {
widget.provider.startTimer(context); // widget.provider.startTimer(context);
}); });
super.initState(); super.initState();
} }
@override @override
void dispose() { void dispose() {
widget.provider.cancelTimer(); // widget.provider.cancelTimer();
super.dispose(); super.dispose();
} }
@ -124,22 +124,22 @@ class _QualifiersContainerState extends State<QualifiersContainer> {
return Container( return Container(
width: double.infinity, width: double.infinity,
decoration: MyDecorations.shadowDecoration, decoration: MyDecorations.shadowDecoration,
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20), padding: const EdgeInsets.only(top: 14,left: 18,right: 14,bottom: 18),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
LocaleKeys.winnerSelection.tr().toText18(isBold: true, color: MyColors.grey3AColor), LocaleKeys.winnerSelection.tr().toText21(color: MyColors.grey3AColor),
"00:${widget.provider.start < 10 ? "0${widget.provider.start}" : widget.provider.start}".toText18(isBold: true, color: MyColors.redColor), // "00:${widget.provider.start < 10 ? "0${widget.provider.start}" : widget.provider.start}".toText18(color: MyColors.redColor),
], ],
), ),
10.height, 10.height,
Row( Row(
children: [ children: [
"18 ".toText32(color: MyColors.greenColor), "18".toText30(color: MyColors.greenColor, isBold: true),2.width,
LocaleKeys.qualifiers.tr().toText20(color: MyColors.greenColor), LocaleKeys.qualifiers.tr().toText16(color: MyColors.greenColor),
], ],
), ),
], ],

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:ui' as ui;
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -29,7 +30,7 @@ class BuildCountdownTimer extends StatelessWidget {
); );
final TextStyle styleDigitHome = const TextStyle( final TextStyle styleDigitHome = const TextStyle(
height: 23 / 27, height: 22 / 27,
color: MyColors.white, color: MyColors.white,
fontStyle: FontStyle.italic, fontStyle: FontStyle.italic,
letterSpacing: -1.44, letterSpacing: -1.44,
@ -53,79 +54,83 @@ class BuildCountdownTimer extends StatelessWidget {
); );
Widget buildEmptyWidget() { Widget buildEmptyWidget() {
return Row( return Directionality(
mainAxisSize: MainAxisSize.min, textDirection: ui.TextDirection.ltr,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, child: Row(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min,
children: <Widget>[ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
Column( crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
AutoSizeText( Column(
"00", children: <Widget>[
maxFontSize: 24, // todo @faiz: Make a separate method and pass string , so we can minimize code replication
minFontSize: 20, AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, "00",
), maxFontSize: 24,
AutoSizeText( minFontSize: 20,
LocaleKeys.days.tr(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
minFontSize: 7, ),
maxFontSize: 8, AutoSizeText(
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, LocaleKeys.days.tr(),
), minFontSize: 7,
], maxFontSize: 8,
), style: screenFlag == 0 ? styleTextHome : styleTextMarathon,
buildSeparator(), ),
Column( ],
children: <Widget>[ ),
AutoSizeText( buildSeparator(),
"00", Column(
maxFontSize: 24, children: <Widget>[
minFontSize: 20, AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, "00",
), maxFontSize: 24,
AutoSizeText( minFontSize: 20,
LocaleKeys.hours.tr(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
minFontSize: 7, ),
maxFontSize: 8, AutoSizeText(
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, LocaleKeys.hours.tr(),
), minFontSize: 7,
], maxFontSize: 8,
), style: screenFlag == 0 ? styleTextHome : styleTextMarathon,
buildSeparator(), ),
Column( ],
children: <Widget>[ ),
AutoSizeText( buildSeparator(),
"00", Column(
maxFontSize: 24, children: <Widget>[
minFontSize: 20, AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, "00",
), maxFontSize: 24,
AutoSizeText( minFontSize: 20,
LocaleKeys.minutes.tr(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
minFontSize: 7, ),
maxFontSize: 8, AutoSizeText(
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, LocaleKeys.minutes.tr(),
), minFontSize: 7,
], maxFontSize: 8,
), style: screenFlag == 0 ? styleTextHome : styleTextMarathon,
buildSeparator(), ),
Column( ],
children: <Widget>[ ),
AutoSizeText( buildSeparator(),
"00", Column(
maxFontSize: 24, children: <Widget>[
minFontSize: 20, AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, "00",
), maxFontSize: 24,
AutoSizeText( minFontSize: 20,
LocaleKeys.seconds.tr(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
minFontSize: 7, ),
maxFontSize: 8, AutoSizeText(
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, LocaleKeys.seconds.tr(),
), minFontSize: 7,
], maxFontSize: 8,
), style: screenFlag == 0 ? styleTextHome : styleTextMarathon,
], ),
],
),
],
),
); );
} }
@ -148,107 +153,111 @@ class BuildCountdownTimer extends StatelessWidget {
return buildEmptyWidget(); return buildEmptyWidget();
} }
return Row( return Directionality(
mainAxisSize: MainAxisSize.min, textDirection: ui.TextDirection.ltr,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, child: Row(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min,
children: <Widget>[ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
Column( crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
time.days == null Column(
? AutoSizeText( children: <Widget>[
"00", // todo @faiz: Make a separate method and pass value and string , so we can minimize code replication
maxFontSize: 24, time.days == null
minFontSize: 20, ? AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, "00",
) maxFontSize: 24,
: AutoSizeText( minFontSize: 20,
time.days! < 10 ? "0${time.days.toString()}" : time.days.toString(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
maxFontSize: 24, )
minFontSize: 20, : AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, time.days! < 10 ? "0${time.days.toString()}" : time.days.toString(),
), maxFontSize: 24,
AutoSizeText( minFontSize: 20,
LocaleKeys.days.tr(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
minFontSize: 7, ),
maxFontSize: 8, AutoSizeText(
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, LocaleKeys.days.tr(),
), minFontSize: 7,
], maxFontSize: 8,
), style: screenFlag == 0 ? styleTextHome : styleTextMarathon,
buildSeparator(), ),
Column( ],
children: <Widget>[ ),
time.hours == null buildSeparator(),
? AutoSizeText( Column(
"00", children: <Widget>[
maxFontSize: 24, time.hours == null
minFontSize: 20, ? AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, "00",
) maxFontSize: 24,
: AutoSizeText( minFontSize: 20,
time.hours! < 10 ? "0${time.hours.toString()}" : time.hours.toString(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
maxFontSize: 24, )
minFontSize: 20, : AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, time.hours! < 10 ? "0${time.hours.toString()}" : time.hours.toString(),
), maxFontSize: 24,
AutoSizeText( minFontSize: 20,
LocaleKeys.hours.tr(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
minFontSize: 7, ),
maxFontSize: 8, AutoSizeText(
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, LocaleKeys.hours.tr(),
), minFontSize: 7,
], maxFontSize: 8,
), style: screenFlag == 0 ? styleTextHome : styleTextMarathon,
buildSeparator(), ),
Column( ],
children: <Widget>[ ),
time.min == null buildSeparator(),
? AutoSizeText( Column(
"00", children: <Widget>[
maxFontSize: 24, time.min == null
minFontSize: 20, ? AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, "00",
) maxFontSize: 24,
: AutoSizeText( minFontSize: 20,
time.min! < 10 ? "0${time.min.toString()}" : time.min.toString(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
maxFontSize: 24, )
minFontSize: 20, : AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, time.min! < 10 ? "0${time.min.toString()}" : time.min.toString(),
), maxFontSize: 24,
AutoSizeText( minFontSize: 20,
LocaleKeys.minutes.tr(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
minFontSize: 7, ),
maxFontSize: 8, AutoSizeText(
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, LocaleKeys.minutes.tr(),
), minFontSize: 7,
], maxFontSize: 8,
), style: screenFlag == 0 ? styleTextHome : styleTextMarathon,
buildSeparator(), ),
Column( ],
children: <Widget>[ ),
time.sec == null buildSeparator(),
? AutoSizeText( Column(
"00", children: <Widget>[
maxFontSize: 24, time.sec == null
minFontSize: 20, ? AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, "00",
) maxFontSize: 24,
: AutoSizeText( minFontSize: 20,
time.sec! < 10 ? "0${time.sec.toString()}" : time.sec.toString(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
maxFontSize: 24, )
minFontSize: 20, : AutoSizeText(
style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon, time.sec! < 10 ? "0${time.sec.toString()}" : time.sec.toString(),
), maxFontSize: 24,
AutoSizeText( minFontSize: 20,
LocaleKeys.seconds.tr(), style: screenFlag == 0 ? styleDigitHome : styleDigitMarathon,
minFontSize: 7, ),
maxFontSize: 8, AutoSizeText(
style: screenFlag == 0 ? styleTextHome : styleTextMarathon, LocaleKeys.seconds.tr(),
), minFontSize: 7,
], maxFontSize: 8,
), style: screenFlag == 0 ? styleTextHome : styleTextMarathon,
], ),
],
),
],
),
); );
} }

@ -18,6 +18,7 @@ class CustomStatusWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: double.infinity, width: double.infinity,
height: 440,
decoration: MyDecorations.shadowDecoration, decoration: MyDecorations.shadowDecoration,
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20), padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
child: Column( child: Column(

@ -1,3 +1,5 @@
import 'dart:math' as math;
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.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';
@ -9,11 +11,9 @@ 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/widget_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/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_intro_screen.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.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'dart:math' as math;
class MarathonBanner extends StatelessWidget { class MarathonBanner extends StatelessWidget {
const MarathonBanner({Key? key}) : super(key: key); const MarathonBanner({Key? key}) : super(key: key);
@ -21,142 +21,179 @@ class MarathonBanner extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
MarathonProvider provider = context.read<MarathonProvider>(); MarathonProvider provider = context.read<MarathonProvider>();
return Container( return provider.marathonDetailModel.startTime != null
decoration: MyDecorations.shadowDecoration, ? Container(
height: MediaQuery.of(context).size.height * 0.11, decoration: MyDecorations.shadowDecoration,
clipBehavior: Clip.antiAlias, height: MediaQuery.of(context).size.height * 0.11,
child: Stack( clipBehavior: Clip.antiAlias,
children: [ child: Stack(
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,
),
),
Positioned(
left: -20,
top: -10,
child: Transform.rotate(
angle: 15,
child: Container(
width: 65,
height: 32,
color: MyColors.darkDigitColor,
),
),
),
SizedBox(
width: double.infinity,
height: double.infinity,
child: Row(
children: [ children: [
const Expanded( Transform(
flex: 3, alignment: Alignment.center,
child: SizedBox( transform: Matrix4.rotationY(
AppState().isArabic(context) ? math.pi : 0,
),
child: SvgPicture.asset(
"assets/images/marathon_banner_bg.svg",
fit: BoxFit.fill,
width: double.infinity, width: double.infinity,
height: double.infinity,
), ),
), ),
Expanded( AppState().isArabic(context)
flex: 5, ? Positioned(
child: SizedBox( right: -15,
width: double.infinity, top: -10,
height: double.infinity, child: Transform.rotate(
child: Row( angle: 10,
mainAxisAlignment: MainAxisAlignment.start, child: Container(
children: <Widget>[ width: 65,
Column( height: 32,
mainAxisAlignment: MainAxisAlignment.center, color: MyColors.darkDigitColor,
crossAxisAlignment: CrossAxisAlignment.start, ),
mainAxisSize: MainAxisSize.min, ),
children: <Widget>[ )
AppState().isArabic(context) ? 0.height : 5.height, : Positioned(
AutoSizeText( left: -20,
LocaleKeys.getReadyForContest.tr(), top: -10,
minFontSize: 08, child: Transform.rotate(
maxFontSize: 11, angle: 15,
style: TextStyle( child: Container(
fontStyle: FontStyle.italic, width: 65,
fontWeight: FontWeight.w600, height: 32,
color: MyColors.white.withOpacity(0.83), color: MyColors.darkDigitColor,
letterSpacing: -0.4, ),
),
),
SizedBox(
width: double.infinity,
height: double.infinity,
child: Row(
children: [
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,
AutoSizeText(
LocaleKeys.getReadyForContest.tr(),
minFontSize: 08,
maxFontSize: 11,
style: TextStyle(
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w600,
color: MyColors.white.withOpacity(0.83),
letterSpacing: -0.4,
),
),
AutoSizeText(
AppState().isArabic(context) ? provider.marathonDetailModel.titleAr ?? "" : provider.marathonDetailModel.titleEn ?? "",
style: TextStyle(
fontStyle: FontStyle.italic,
fontSize: 19,
fontWeight: FontWeight.bold,
color: MyColors.white.withOpacity(0.83),
height: 32 / 22,
),
),
3.height,
BuildCountdownTimer(
timeToMarathon: DateTime.parse(provider.marathonDetailModel.startTime!).millisecondsSinceEpoch,
provider: provider,
screenFlag: 0,
),
],
).paddingOnly(
left: AppState().isArabic(context) ? 12 : 3,
right: AppState().isArabic(context) ? 3 : 12,
)
],
),
),
),
],
),
),
AppState().isArabic(context)
? Align(
alignment: Alignment.topRight,
child: SizedBox(
height: 20,
width: 35,
child: Transform.rotate(
angle: math.pi / 4.5,
child: Text(
LocaleKeys.brainMarathon.tr(),
textAlign: TextAlign.center,
maxLines: 2,
style: const TextStyle(
color: MyColors.white,
fontWeight: FontWeight.bold,
fontSize: 6,
height: 1.2,
), ),
), ),
AutoSizeText( ),
"Saudi Arabia", ),
style: TextStyle( ).paddingOnly(top: 5)
fontStyle: FontStyle.italic, : Align(
fontSize: 19, alignment: Alignment.topLeft,
child: SizedBox(
height: 20,
width: 35,
child: Transform.rotate(
angle: -math.pi / 4.5,
child: Text(
LocaleKeys.brainMarathon.tr(),
textAlign: TextAlign.center,
maxLines: 2,
style: const TextStyle(
color: MyColors.kWhiteColor,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: MyColors.white.withOpacity(0.83), fontSize: 6,
height: 32 / 22, height: 1.2,
), ),
), ),
3.height, ),
BuildCountdownTimer( ),
timeToMarathon: dummyEndTime, ).paddingOnly(top: 5),
provider: provider, !AppState().isArabic(context)
screenFlag: 0, ? Positioned(
), right: 0,
], bottom: 0,
).paddingOnly( child: RotatedBox(
left: AppState().isArabic(context) ? 12 : 3, quarterTurns: 4,
right: AppState().isArabic(context) ? 3 : 12, child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.whiteColor),
) ).paddingAll(15),
], )
), : Positioned(
), bottom: 0,
), left: 0,
child: RotatedBox(
quarterTurns: 2,
child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.whiteColor),
).paddingAll(15),
),
], ],
).onPress(
() => Navigator.pushNamed(context, AppRoutes.marathonIntroScreen),
), ),
), )
Align( : const SizedBox();
alignment: Alignment.topLeft,
child: SizedBox(
height: 20,
width: 35,
child: Transform.rotate(
angle: -math.pi / 4.5,
child: Text(
LocaleKeys.brainMarathon.tr(),
textAlign: TextAlign.center,
maxLines: 2,
style: const TextStyle(
color: MyColors.kWhiteColor,
fontWeight: FontWeight.bold,
fontSize: 6,
height: 1.2,
),
),
),
),
).paddingOnly(top: 5),
!AppState().isArabic(context)
? Positioned(
right: 0,
bottom: 0,
child: RotatedBox(
quarterTurns: 4,
child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.whiteColor),
).paddingAll(15),
)
: Positioned(
bottom: 0,
left: 0,
child: RotatedBox(
quarterTurns: 2,
child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.whiteColor),
).paddingAll(15),
),
],
).onPress(
() => Navigator.pushNamed(context, AppRoutes.marathonIntroScreen),
),
);
} }
} }

@ -28,8 +28,6 @@ class MarathonHeader extends StatelessWidget {
color: MyColors.black, color: MyColors.black,
constraints: const BoxConstraints(), constraints: const BoxConstraints(),
onPressed: () { onPressed: () {
Provider.of<MarathonProvider>(context, listen: false)
.resetValues();
Navigator.pop(context); Navigator.pop(context);
}, },
) )

@ -1,89 +1,55 @@
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/material.dart'; import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/decorations_helper.dart'; import 'package:mohem_flutter_app/classes/decorations_helper.dart';
import 'package:mohem_flutter_app/config/routes.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/extensions/widget_extensions.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/ui/marathon/marathon_provider.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
List<bool> isSelectedOptions = [ class QuestionCard extends StatelessWidget {
false,
false,
false,
false,
];
class QuestionCard extends StatefulWidget {
final MarathonProvider provider; final MarathonProvider provider;
const QuestionCard({Key? key, required this.provider}) : super(key: key); const QuestionCard({Key? key, required this.provider}) : super(key: key);
@override
State<QuestionCard> createState() => _QuestionCardState();
}
class _QuestionCardState extends State<QuestionCard> {
final List<CardContent> questionCards = <CardContent>[];
@override
void initState() {
_loadCards();
super.initState();
}
void _loadCards() {
for (DummyQuestionModel question in questions) {
questionCards.add(
CardContent(
question: question,
provider: widget.provider,
),
);
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CupertinoPageScaffold( return CupertinoPageScaffold(
child: SizedBox( child: provider.cardContentList.isEmpty
height: 440, ? Lottie.asset(MyLottieConsts.hourGlassLottie, height: 250).paddingOnly(top: 50)
width: double.infinity, : SizedBox(
child: Consumer<MarathonProvider>( height: 440,
builder: (BuildContext context, MarathonProvider provider, _) { width: double.infinity,
return AppinioSwiper( child: Consumer<MarathonProvider>(
padding: EdgeInsets.zero, builder: (BuildContext context, MarathonProvider provider, _) {
isDisabled: true, return AppinioSwiper(
controller: provider.swiperController, duration: const Duration(milliseconds: 400),
unswipe: (int index, AppinioSwiperDirection direction) {}, padding: EdgeInsets.zero,
cards: questionCards, isDisabled: true,
onSwipe: (int index, AppinioSwiperDirection direction) { controller: provider.swiperController,
if (direction == AppinioSwiperDirection.left) { unswipe: (int index, AppinioSwiperDirection direction) {},
provider.startTimer(context); onSwipe: (int index, AppinioSwiperDirection direction) {},
} cards: provider.cardContentList,
}, );
); },
}, ),
), ),
),
); );
} }
} }
class CardContent extends StatelessWidget { class CardContent extends StatelessWidget {
final DummyQuestionModel question; const CardContent({Key? key}) : super(key: key);
final MarathonProvider provider;
const CardContent({
Key? key,
required this.question,
required this.provider,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
MarathonProvider provider = context.watch<MarathonProvider>();
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
@ -118,12 +84,12 @@ class CardContent extends StatelessWidget {
topRight: Radius.circular(10), topRight: Radius.circular(10),
), ),
), ),
child: const Center( child: Center(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: 13), padding: const EdgeInsets.symmetric(horizontal: 13),
child: Text( child: Text(
"What is the capital of Saudi Arabia?", AppState().isArabic(context) ? provider.currentQuestion.titleAr ?? "" : provider.currentQuestion.titleEn ?? "",
style: TextStyle( style: const TextStyle(
color: MyColors.white, color: MyColors.white,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -132,49 +98,21 @@ class CardContent extends StatelessWidget {
), ),
), ),
), ),
AnswerContent(question: question, provider: provider), const AnswerContent(),
], ],
), ),
); );
} }
} }
class AnswerContent extends StatefulWidget { class AnswerContent extends StatelessWidget {
final DummyQuestionModel question; const AnswerContent({Key? key}) : super(key: key);
final MarathonProvider provider;
const AnswerContent({Key? key, required this.question, required this.provider}) : super(key: key);
@override
State<AnswerContent> createState() => _AnswerContentState();
}
class _AnswerContentState extends State<AnswerContent> {
void updateOption(int index, bool value) {
isSelectedOptions[0] = false;
isSelectedOptions[1] = false;
isSelectedOptions[2] = false;
isSelectedOptions[3] = false;
isSelectedOptions[index] = value;
setState(() {});
}
Decoration getContainerColor(int index) {
if (!isSelectedOptions[index]) {
return MyDecorations.getContainersDecoration(MyColors.greyF7Color);
}
if (isSelectedOptions[index] && context.watch<MarathonProvider>().start > 0) {
return MyDecorations.getContainersDecoration(MyColors.yellowColorII);
}
return MyDecorations.getContainersDecoration(
isSelectedOptions[index] ? MyColors.greenColor : MyColors.greyF7Color,
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
MarathonProvider provider = context.watch<MarathonProvider>();
return Container( return Container(
padding: const EdgeInsets.all(13), padding: const EdgeInsets.symmetric(vertical: 31, horizontal: 13),
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: MyColors.kWhiteColor, color: MyColors.kWhiteColor,
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
@ -182,127 +120,48 @@ class _AnswerContentState extends State<AnswerContent> {
bottomRight: Radius.circular(10), bottomRight: Radius.circular(10),
), ),
), ),
child: Column( child: provider.currentQuestion.questionOptions != null
mainAxisSize: MainAxisSize.min, ? ListView.separated(
mainAxisAlignment: MainAxisAlignment.center, itemCount: provider.currentQuestion.questionOptions!.length,
crossAxisAlignment: CrossAxisAlignment.center, shrinkWrap: true,
children: <Widget>[ itemBuilder: (BuildContext context, int index) {
InkWell( return AnswerTileForText(
onTap: () { index: index,
if (widget.provider.currentQuestionNumber == 9) { onAnswerTapped: () {
widget.provider.cancelTimer(); provider.updateCurrentQuestionOptionStatus(QuestionsOptionStatus.selected, index);
widget.provider.resetValues(); },
Navigator.pushReplacementNamed(
context,
AppRoutes.marathonWinnerSelection,
);
return;
}
updateOption(0, true);
},
child: Container(
alignment: Alignment.centerLeft,
decoration: getContainerColor(0),
child: Center(
child: Text(
widget.question.opt1!,
style: TextStyle(
color: isSelectedOptions[0] ? MyColors.white : MyColors.darkTextColor,
fontWeight: FontWeight.w600,
fontSize: 16,
),
).paddingOnly(top: 17, bottom: 17),
),
),
),
const SizedBox(height: 15),
InkWell(
onTap: () {
if (widget.provider.currentQuestionNumber == 9) {
widget.provider.cancelTimer();
widget.provider.resetValues();
Navigator.pushReplacementNamed(
context,
AppRoutes.marathonWinnerSelection,
);
return;
}
updateOption(1, true);
},
child: Container(
alignment: Alignment.centerLeft,
decoration: getContainerColor(1),
child: Center(
child: Text(
widget.question.opt2!,
style: TextStyle(
color: isSelectedOptions[1] ? MyColors.white : MyColors.darkTextColor,
fontWeight: FontWeight.w600,
fontSize: 16,
),
).paddingOnly(top: 17, bottom: 17),
),
),
),
const SizedBox(height: 15),
InkWell(
onTap: () {
if (widget.provider.currentQuestionNumber == 9) {
widget.provider.cancelTimer();
widget.provider.resetValues();
Navigator.pushReplacementNamed(
context,
AppRoutes.marathonWinnerSelection,
);
return;
}
updateOption(2, true);
},
child: Container(
alignment: Alignment.centerLeft,
decoration: getContainerColor(2),
child: Center(
child: Text(
widget.question.opt3!,
style: TextStyle(
color: isSelectedOptions[2] ? MyColors.white : MyColors.darkTextColor,
fontWeight: FontWeight.w600,
fontSize: 16,
),
).paddingOnly(top: 17, bottom: 17),
),
),
),
const SizedBox(height: 15),
InkWell(
onTap: () {
if (widget.provider.currentQuestionNumber == 9) {
widget.provider.cancelTimer();
widget.provider.resetValues();
Navigator.pushReplacementNamed(
context,
AppRoutes.marathonWinnerSelection,
); );
return; },
} separatorBuilder: (BuildContext context, int index) => 15.height,
updateOption(3, true); )
}, : const SizedBox(),
child: Container( );
alignment: Alignment.centerLeft, }
decoration: getContainerColor(3), }
child: Center(
child: Text( class AnswerTileForText extends StatelessWidget {
widget.question.opt3!, final int index;
style: TextStyle( final Function() onAnswerTapped;
color: isSelectedOptions[3] ? MyColors.white : MyColors.darkTextColor,
fontWeight: FontWeight.w600, const AnswerTileForText({Key? key, required this.index, required this.onAnswerTapped}) : super(key: key);
fontSize: 16,
), @override
).paddingOnly(top: 17, bottom: 17), Widget build(BuildContext context) {
), MarathonProvider provider = context.watch<MarathonProvider>();
), return InkWell(
), onTap: () {
], onAnswerTapped();
},
child: Container(
alignment: Alignment.centerLeft,
decoration: MyDecorations.getAnswersContainerColor(provider.currentQuestion.questionOptions![index].optionStatus!),
child: Center(
child: (AppState().isArabic(context) ? provider.currentQuestion.questionOptions![index].titleAr! : provider.currentQuestion.questionOptions![index].titleEn!)
.toText16(
color: provider.currentQuestion.questionOptions![index].optionStatus == QuestionsOptionStatus.unSelected ? MyColors.darkTextColor : MyColors.white,
)
.paddingOnly(top: 17, bottom: 17),
),
), ),
); );
} }

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/models/marathon/question_model.dart';
class QuestionCardBuilder extends StatelessWidget {
final WidgetBuilder onQuestion;
final WidgetBuilder onCompleted;
final WidgetBuilder onWrongAnswer;
final WidgetBuilder onCorrectAnswer;
final WidgetBuilder onWinner;
final WidgetBuilder onSkippedAnswer;
final WidgetBuilder onFindingWinner;
final QuestionCardStatus questionCardStatus;
const QuestionCardBuilder({
Key? key,
required this.onQuestion,
required this.onCompleted,
required this.onCorrectAnswer,
required this.onWinner,
required this.onSkippedAnswer,
required this.onWrongAnswer,
required this.onFindingWinner,
required this.questionCardStatus,
}) : super(key: key);
@override
Widget build(BuildContext context) {
switch (questionCardStatus) {
case QuestionCardStatus.question:
return onQuestion(context);
case QuestionCardStatus.wrongAnswer:
return onWrongAnswer(context);
case QuestionCardStatus.correctAnswer:
return onCorrectAnswer(context);
case QuestionCardStatus.completed:
return onCompleted(context);
case QuestionCardStatus.winnerFound:
return onWinner(context);
case QuestionCardStatus.findingWinner:
return onFindingWinner(context);
case QuestionCardStatus.skippedAnswer:
return onSkippedAnswer(context);
}
}
}

@ -71,7 +71,7 @@ class _RequestSubmitScreenState extends State<RequestSubmitScreen> {
} }
void submitRequest() async { void submitRequest() async {
try { try {
Utils.showLoading(context); Utils.showLoading(context);
List<Map<String, dynamic>> list = []; List<Map<String, dynamic>> list = [];
if (attachmentFiles.isNotEmpty) { if (attachmentFiles.isNotEmpty) {
@ -133,7 +133,7 @@ class _RequestSubmitScreenState extends State<RequestSubmitScreen> {
params!.pItemId, params!.pItemId,
params!.transactionId, params!.transactionId,
); );
}else if (params!.approvalFlag == 'endEmployment') { } else if (params!.approvalFlag == 'endEmployment') {
await TerminationDffApiClient().startTermApprovalProcess( await TerminationDffApiClient().startTermApprovalProcess(
"SUBMIT", "SUBMIT",
comments.text, comments.text,

@ -96,9 +96,11 @@ class _DynamicInputScreenState extends State<DynamicInputScreen> {
SubmitEITTransactionList submitEITTransactionList = SubmitEITTransactionList submitEITTransactionList =
await MyAttendanceApiClient().submitEitTransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, empID: dynamicParams!.selectedEmp ?? ''); await MyAttendanceApiClient().submitEitTransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, empID: dynamicParams!.selectedEmp ?? '');
Utils.hideLoading(context); Utils.hideLoading(context);
await Navigator.pushNamed(context, AppRoutes.requestSubmitScreen, var res = await Navigator.pushNamed(context, AppRoutes.requestSubmitScreen,
arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submitEITTransactionList.pTRANSACTIONID!, submitEITTransactionList.pITEMKEY!, 'eit')); arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submitEITTransactionList.pTRANSACTIONID!, submitEITTransactionList.pITEMKEY!, 'eit'));
Utils.showLoading(context); if (res != null && res == true) {
Utils.showLoading(context);
}
await LeaveBalanceApiClient().cancelHrTransaction(submitEITTransactionList.pTRANSACTIONID!); await LeaveBalanceApiClient().cancelHrTransaction(submitEITTransactionList.pTRANSACTIONID!);
Utils.hideLoading(context); Utils.hideLoading(context);
} catch (ex) { } catch (ex) {

@ -74,9 +74,9 @@ class _DynamicInputScreenState extends State<DynamicInputScreenProfile> {
getBasicDetColsStructureList?.forEach((GetBasicDetColsStructureList element) { getBasicDetColsStructureList?.forEach((GetBasicDetColsStructureList element) {
element.userBasicDetail = element.userBasicDetail =
dynamicParams!.getEmployeeBasicDetailsList!.singleWhere((GetEmployeeBasicDetailsList userDetail) => userDetail.aPPLICATIONCOLUMNNAME == element.aPPLICATIONCOLUMNNAME); dynamicParams!.getEmployeeBasicDetailsList!.singleWhere((GetEmployeeBasicDetailsList userDetail) => userDetail.aPPLICATIONCOLUMNNAME == element.aPPLICATIONCOLUMNNAME);
if (element.objectValuesList != null) { if (element.objectValuesList != null && element.userBasicDetail?.vARCHAR2VALUE != '') {
ObjectValuesList dropDownListValue = element.objectValuesList!.singleWhere((ObjectValuesList dropdown) => dropdown.cODE == element.userBasicDetail!.vARCHAR2VALUE); ObjectValuesList dropDownListValue = element.objectValuesList!.singleWhere((ObjectValuesList dropdown) => dropdown.cODE == element.userBasicDetail?.vARCHAR2VALUE);
element.userBasicDetail!.sEGMENTVALUEDSP = dropDownListValue.mEANING; element.userBasicDetail?.sEGMENTVALUEDSP = dropDownListValue.mEANING;
} }
}); });
} else { } else {
@ -93,9 +93,9 @@ class _DynamicInputScreenState extends State<DynamicInputScreenProfile> {
getBasicDetColsStructureList?.forEach((GetBasicDetColsStructureList element) { getBasicDetColsStructureList?.forEach((GetBasicDetColsStructureList element) {
element.userBasicDetail = element.userBasicDetail =
dynamicParams!.getEmployeeBasicDetailsList!.singleWhere((GetEmployeeBasicDetailsList userDetail) => userDetail.aPPLICATIONCOLUMNNAME == element.aPPLICATIONCOLUMNNAME); dynamicParams!.getEmployeeBasicDetailsList!.singleWhere((GetEmployeeBasicDetailsList userDetail) => userDetail.aPPLICATIONCOLUMNNAME == element.aPPLICATIONCOLUMNNAME);
if (element.objectValuesList != null) { if (element.objectValuesList != null && element.userBasicDetail!.vARCHAR2VALUE != '') {
ObjectValuesList dropDownListValue = element.objectValuesList!.singleWhere((ObjectValuesList dropdown) => dropdown.cODE == element.userBasicDetail!.vARCHAR2VALUE); ObjectValuesList dropDownListValue = element.objectValuesList!.singleWhere((ObjectValuesList dropdown) => dropdown.cODE == element.userBasicDetail!.vARCHAR2VALUE);
element.userBasicDetail!.sEGMENTVALUEDSP = dropDownListValue.mEANING; element.userBasicDetail?.sEGMENTVALUEDSP = dropDownListValue.mEANING;
} }
}); });
} }
@ -262,7 +262,7 @@ class _DynamicInputScreenState extends State<DynamicInputScreenProfile> {
return PopupMenuButton( return PopupMenuButton(
child: DynamicTextFieldWidget( child: DynamicTextFieldWidget(
(model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""),
getBasicDetColsStructureList![index].userBasicDetail!.sEGMENTVALUEDSP ?? "", getBasicDetColsStructureList![index].userBasicDetail?.sEGMENTVALUEDSP ?? "",
isEnable: false, isEnable: false,
isPopup: true, isPopup: true,
).paddingOnly(bottom: 12), ).paddingOnly(bottom: 12),
@ -363,7 +363,7 @@ class _DynamicInputScreenState extends State<DynamicInputScreenProfile> {
Utils.showLoading(context); Utils.showLoading(context);
int numberValue = 0; int numberValue = 0;
List<Map<String, dynamic>> values = getBasicDetDffStructureList!.map((e) { List<Map<String, dynamic>> values = getBasicDetDffStructureList!.map((e) {
String tempVar = e.userBasicDetail!.vARCHAR2VALUE ?? ""; String tempVar = e.userBasicDetail?.vARCHAR2VALUE ?? "";
if (e.fORMATTYPE == "X") { if (e.fORMATTYPE == "X") {
// for date format type, date format is changed // for date format type, date format is changed

@ -1,11 +1,13 @@
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';
import 'package:mohem_flutter_app/extensions/widget_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/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/wf_history_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/wf_history_model.dart';
import 'package:mohem_flutter_app/ui/work_list/sheets/delegate_sheet.dart';
import 'package:mohem_flutter_app/ui/work_list/sheets/selected_itg_item_sheet.dart'; import 'package:mohem_flutter_app/ui/work_list/sheets/selected_itg_item_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart';
@ -109,6 +111,19 @@ class ApprovalLevelfragment extends StatelessWidget {
}).expanded, }).expanded,
Container(width: 1, height: 30, color: MyColors.lightGreyEFColor), Container(width: 1, height: 30, color: MyColors.lightGreyEFColor),
LocaleKeys.delegate.tr().toText12(color: MyColors.gradiantEndColor).center.paddingOnly(top: 6, bottom: 6).onPress(() { LocaleKeys.delegate.tr().toText12(color: MyColors.gradiantEndColor).center.paddingOnly(top: 6, bottom: 6).onPress(() {
if (history.employeeID == AppState().memberInformationList?.eMPLOYEENUMBER) {
showMyBottomSheet(context,
callBackFunc: voidCallback,
child: DelegateSheet(
title: LocaleKeys.delegate.tr(),
apiMode: "Delegate",
notificationID: null,
actionHistoryList: null,
wFHistory: wFHistory,
callBackFunc: voidCallback,
));
return;
}
showMyBottomSheet( showMyBottomSheet(
context, context,
callBackFunc: voidCallback, callBackFunc: voidCallback,
@ -135,11 +150,7 @@ class ApprovalLevelfragment extends StatelessWidget {
return MyColors.yellowColor; return MyColors.yellowColor;
} else if (code.toLowerCase() == "not doable" || code.toLowerCase() == "rejected") { } else if (code.toLowerCase() == "not doable" || code.toLowerCase() == "rejected") {
return MyColors.redColor; return MyColors.redColor;
} else if (code.toLowerCase() == "approved" || } else if (code.toLowerCase() == "approved" || code.toLowerCase() == "auto-approve" || code.toLowerCase() == "auto-approved" || code.toLowerCase() == "doable" || code.toLowerCase() == "answer") {
code.toLowerCase() == "auto-approve" ||
code.toLowerCase() == "auto-approved" ||
code.toLowerCase() == "doable" ||
code.toLowerCase() == "answer") {
return MyColors.greenColor; return MyColors.greenColor;
} else if (code.toLowerCase() == "requested information" || code.toLowerCase() == "assign" || code.toLowerCase() == "reassign") { } else if (code.toLowerCase() == "requested information" || code.toLowerCase() == "assign" || code.toLowerCase() == "reassign") {
return MyColors.orange; return MyColors.orange;

@ -191,169 +191,187 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
return Scaffold( return Scaffold(
appBar: AppBarWidget(context, title: LocaleKeys.details.tr()), appBar: AppBarWidget(context, title: LocaleKeys.details.tr()),
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: Stack( body: AnimatedSwitcher(
children: [ duration: const Duration(milliseconds: 500),
Column( switchInCurve: Curves.easeInToLinear,
children: [ transitionBuilder: (Widget child, Animation<double> animation) {
Container( Animation<Offset> custom = Tween<Offset>(
padding: const EdgeInsets.only(left: 21, right: 21, top: 16, bottom: 16), begin: const Offset(1.0, 0.0),
decoration: const BoxDecoration( end: Offset.zero,
borderRadius: BorderRadius.only( ).animate(animation);
bottomLeft: Radius.circular(25), return ClipRect(
bottomRight: Radius.circular(25), child: SlideTransition(
), position: custom,
gradient: LinearGradient( child: child,
transform: GradientRotation(.83), // textDirection: TextDirection.ltr,
begin: Alignment.topRight, ),
end: Alignment.bottomLeft, );
colors: [ },
MyColors.gradiantEndColor, child: Stack(
MyColors.gradiantStartColor, key: ValueKey(AppState().workListIndex ?? 0),
], children: [
), Column(
), children: [
child: Row(
children: [
myTab(LocaleKeys.info.tr(), 0),
(workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") ? myTab(LocaleKeys.details.tr(), 1) : myTab(LocaleKeys.request.tr(), 1),
myTab(LocaleKeys.actions.tr(), 2),
myTab(LocaleKeys.attachments.tr(), 3),
],
),
),
if ((workListData?.sUBJECT ?? "").isNotEmpty) workListData!.sUBJECT!.toText14().paddingOnly(top: 20, right: 21, left: 21),
PageView(
controller: controller,
onPageChanged: (pageIndex) {
setState(() {
tabIndex = pageIndex;
});
},
children: [
InfoFragment(
poHeaderList: getPoNotificationBody?.pOHeader ?? [],
workListData: workListData,
itemCreationHeader: getItemCreationNtfBody?.itemCreationHeader ?? [],
getStampMsNotifications: getStampMsNotifications,
getStampNsNotifications: getStampNsNotifications,
getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList,
getPhonesNotificationBodyList: getPhonesNotificationBodyList,
getBasicDetNtfBodyList: getBasicDetNtfBodyList,
getAbsenceCollectionNotificationBodyList: getAbsenceCollectionNotificationBodyList,
getContactNotificationBodyList: getContactNotificationBodyList,
getPrNotificationBodyList: getPrNotificationBody,
),
(workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP")
? DetailFragment(workListData, memberInformationListModel)
: RequestFragment(
moNotificationBodyList: getMoNotificationBodyList,
poLinesList: getPoNotificationBody?.pOLines ?? [],
itemCreationLines: getItemCreationNtfBody?.itemCreationLines ?? [],
prLinesList: getPrNotificationBody?.pRLines ?? [],
),
isActionHistoryLoaded
? actionHistoryList.isEmpty
? Utils.getNoDataWidget(context)
: ActionsFragment(
workListData!.nOTIFICATIONID,
actionHistoryList,
voidCallback: reloadWorkList,
)
: showLoadingAnimation(),
isAttachmentLoaded
? getAttachmentList.isEmpty
? Utils.getNoDataWidget(context)
: AttachmentsFragment(getAttachmentList)
: showLoadingAnimation(),
],
).expanded,
if (isApproveAvailable || isRejectAvailable || isCloseAvailable)
Container( Container(
padding: const EdgeInsets.only(top: 14, bottom: 14, left: 21, right: 21), padding: const EdgeInsets.only(left: 21, right: 21, top: 16, bottom: 16),
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.only(
border: Border( bottomLeft: Radius.circular(25),
top: BorderSide(color: MyColors.lightGreyEFColor, width: 1.0), bottomRight: Radius.circular(25),
),
gradient: LinearGradient(
transform: GradientRotation(.83),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
MyColors.gradiantEndColor,
MyColors.gradiantStartColor,
],
), ),
), ),
child: Row( child: Row(
children: [ children: [
if (isRejectAvailable) myTab(LocaleKeys.info.tr(), 0),
DefaultButton( (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") ? myTab(LocaleKeys.details.tr(), 1) : myTab(LocaleKeys.request.tr(), 1),
LocaleKeys.reject.tr(), myTab(LocaleKeys.actions.tr(), 2),
() => performAction("REJECTED"), myTab(LocaleKeys.attachments.tr(), 3),
colors: const [Color(0xffE47A7E), Color(0xffDE6D71)],
).expanded,
if (isApproveAvailable && isRejectAvailable) 8.width,
if (isApproveAvailable)
DefaultButton(
LocaleKeys.approve.tr(),
() => performAction("APPROVED"),
colors: const [Color(0xff28C884), Color(0xff1BB271)],
).expanded,
if (isCloseAvailable)
DefaultButton(
LocaleKeys.ok.tr(),
() => performAction("CLOSE"),
colors: const [Color(0xff32D892), Color(0xff1AB170)],
).expanded,
8.width,
Container(
height: 43,
width: 43,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: MyColors.lightGreyE6Color,
),
child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor),
).onPress(() {
setState(() {
showFabOptions = true;
});
})
], ],
), ),
) ),
], if ((workListData?.sUBJECT ?? "").isNotEmpty) workListData!.sUBJECT!.toText14().paddingOnly(top: 20, right: 21, left: 21),
), PageView(
IgnorePointer( controller: controller,
ignoring: !showFabOptions, onPageChanged: (int pageIndex) {
child: AnimatedOpacity( setState(() {
opacity: showFabOptions ? 1 : 0, tabIndex = pageIndex;
duration: const Duration(milliseconds: 250), });
child: Container( },
padding: const EdgeInsets.only(left: 21, right: 21, bottom: 75 - 12),
width: double.infinity,
height: double.infinity,
color: Colors.white.withOpacity(.67),
alignment: Alignment.bottomRight,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
myFab(LocaleKeys.skip.tr(), "assets/images/skip.svg").onPress(() { InfoFragment(
if (AppState().workList!.length - 1 > AppState().workListIndex!) { poHeaderList: getPoNotificationBody?.pOHeader ?? [],
AppState().setWorkListIndex = AppState().workListIndex! + 1; workListData: workListData,
workListData = null; itemCreationHeader: getItemCreationNtfBody?.itemCreationHeader ?? [],
showFabOptions = false; getStampMsNotifications: getStampMsNotifications,
tabIndex = 0; getStampNsNotifications: getStampNsNotifications,
getDataFromState(); getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList,
} else if (AppState().workList!.length - 1 == AppState().workListIndex!) { getPhonesNotificationBodyList: getPhonesNotificationBodyList,
Navigator.pop(context); getBasicDetNtfBodyList: getBasicDetNtfBodyList,
} getAbsenceCollectionNotificationBodyList: getAbsenceCollectionNotificationBodyList,
}), getContactNotificationBodyList: getContactNotificationBodyList,
12.height, getPrNotificationBodyList: getPrNotificationBody,
...viewApiButtonsList(notificationButtonsList), ),
(workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP")
? DetailFragment(workListData, memberInformationListModel)
: RequestFragment(
moNotificationBodyList: getMoNotificationBodyList,
poLinesList: getPoNotificationBody?.pOLines ?? [],
itemCreationLines: getItemCreationNtfBody?.itemCreationLines ?? [],
prLinesList: getPrNotificationBody?.pRLines ?? [],
),
isActionHistoryLoaded
? actionHistoryList.isEmpty
? Utils.getNoDataWidget(context)
: ActionsFragment(
workListData!.nOTIFICATIONID,
actionHistoryList,
voidCallback: reloadWorkList,
)
: showLoadingAnimation(),
isAttachmentLoaded
? getAttachmentList.isEmpty
? Utils.getNoDataWidget(context)
: AttachmentsFragment(getAttachmentList)
: showLoadingAnimation(),
], ],
).expanded,
if (isApproveAvailable || isRejectAvailable || isCloseAvailable)
Container(
padding: const EdgeInsets.only(top: 14, bottom: 14, left: 21, right: 21),
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(color: MyColors.lightGreyEFColor, width: 1.0),
),
),
child: Row(
children: [
if (isRejectAvailable)
DefaultButton(
LocaleKeys.reject.tr(),
() => performAction("REJECTED"),
colors: const [Color(0xffE47A7E), Color(0xffDE6D71)],
).expanded,
if (isApproveAvailable && isRejectAvailable) 8.width,
if (isApproveAvailable)
DefaultButton(
LocaleKeys.approve.tr(),
() => performAction("APPROVED"),
colors: const [Color(0xff28C884), Color(0xff1BB271)],
).expanded,
if (isCloseAvailable)
DefaultButton(
LocaleKeys.ok.tr(),
() => performAction("CLOSE"),
colors: const [Color(0xff32D892), Color(0xff1AB170)],
).expanded,
8.width,
Container(
height: 43,
width: 43,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: MyColors.lightGreyE6Color,
),
child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor),
).onPress(() {
setState(() {
showFabOptions = true;
});
})
],
),
)
],
),
IgnorePointer(
ignoring: !showFabOptions,
child: AnimatedOpacity(
opacity: showFabOptions ? 1 : 0,
duration: const Duration(milliseconds: 250),
child: Container(
padding: const EdgeInsets.only(left: 21, right: 21, bottom: 75 - 12),
width: double.infinity,
height: double.infinity,
color: Colors.white.withOpacity(.67),
alignment: Alignment.bottomRight,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
myFab(LocaleKeys.skip.tr(), "assets/images/skip.svg").onPress(() {
if (AppState().workList!.length - 1 > AppState().workListIndex!) {
AppState().setWorkListIndex = AppState().workListIndex! + 1;
workListData = null;
showFabOptions = false;
tabIndex = 0;
getDataFromState();
} else if (AppState().workList!.length - 1 == AppState().workListIndex!) {
Navigator.pop(context);
}
}),
12.height,
...viewApiButtonsList(notificationButtonsList),
],
),
), ),
), ).onPress(() {
).onPress(() { setState(() {
setState(() { showFabOptions = false;
showFabOptions = false; });
}); }),
}), ),
), ],
], ),
), ),
floatingActionButton: (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable) floatingActionButton: (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable)
? Container( ? Container(
@ -546,7 +564,7 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
Future<void> performNetworkCall(BuildContext context, {String? email, String? userId}) async { Future<void> performNetworkCall(BuildContext context, {String? email, String? userId}) async {
showDialog( showDialog(
context: context, context: context,
builder: (cxt) => ConfirmDialog( builder: (BuildContext cxt) => ConfirmDialog(
message: LocaleKeys.wantToReject.tr(), message: LocaleKeys.wantToReject.tr(),
okTitle: LocaleKeys.reject.tr(), okTitle: LocaleKeys.reject.tr(),
onTap: () async { onTap: () async {
@ -629,12 +647,12 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
print(actionMode); print(actionMode);
showDialog( showDialog(
context: context, context: context,
builder: (cxt) => AcceptRejectInputDialog( builder: (BuildContext cxt) => AcceptRejectInputDialog(
message: title != null ? null : LocaleKeys.requestedItems.tr(), message: title != null ? null : LocaleKeys.requestedItems.tr(),
title: title, title: title,
notificationGetRespond: notificationNoteInput, notificationGetRespond: notificationNoteInput,
actionMode: actionMode, actionMode: actionMode,
onTap: (note) { onTap: (String note) {
Map<String, dynamic> payload = { Map<String, dynamic> payload = {
"P_ACTION_MODE": actionMode, "P_ACTION_MODE": actionMode,
"P_APPROVER_INDEX": null, "P_APPROVER_INDEX": null,
@ -915,9 +933,9 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
apiCallCount++; apiCallCount++;
notificationButtonsList = await WorkListApiClient().getNotificationButtons(workListData!.nOTIFICATIONID!); notificationButtonsList = await WorkListApiClient().getNotificationButtons(workListData!.nOTIFICATIONID!);
if (notificationButtonsList.isNotEmpty) { if (notificationButtonsList.isNotEmpty) {
isCloseAvailable = notificationButtonsList.any((element) => element.bUTTONACTION == "CLOSE"); isCloseAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "CLOSE");
isApproveAvailable = notificationButtonsList.any((element) => element.bUTTONACTION == "APPROVED"); isApproveAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "APPROVED");
isRejectAvailable = notificationButtonsList.any((element) => element.bUTTONACTION == "REJECTED"); isRejectAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "REJECTED");
} }
apiCallCount--; apiCallCount--;
if (apiCallCount == 0) { if (apiCallCount == 0) {

@ -1,5 +1,6 @@
import 'package:easy_localization/src/public_ext.dart'; import 'package:easy_localization/src/public_ext.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/classes/date_uitl.dart'; import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart';
@ -7,6 +8,7 @@ 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/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/get_action_history_list_model.dart'; import 'package:mohem_flutter_app/models/get_action_history_list_model.dart';
import 'package:mohem_flutter_app/ui/work_list/sheets/delegate_sheet.dart';
import 'package:mohem_flutter_app/ui/work_list/sheets/selected_item_sheet.dart'; import 'package:mohem_flutter_app/ui/work_list/sheets/selected_item_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart';
@ -109,6 +111,18 @@ class ActionsFragment extends StatelessWidget {
}).expanded, }).expanded,
Container(width: 1, height: 30, color: MyColors.lightGreyEFColor), Container(width: 1, height: 30, color: MyColors.lightGreyEFColor),
LocaleKeys.delegate.tr().toText12(color: MyColors.gradiantEndColor).center.paddingOnly(top: 6, bottom: 6).onPress(() { LocaleKeys.delegate.tr().toText12(color: MyColors.gradiantEndColor).center.paddingOnly(top: 6, bottom: 6).onPress(() {
if (actionHistory.uSERNAME == AppState().memberInformationList?.eMPLOYEENUMBER) {
showMyBottomSheet(context,
callBackFunc: voidCallback,
child: DelegateSheet(
title: LocaleKeys.delegate.tr(),
apiMode: "DELEGATE",
notificationID: notificationID,
actionHistoryList: actionHistoryList,
callBackFunc: voidCallback,
));
return;
}
showMyBottomSheet( showMyBottomSheet(
context, context,
callBackFunc: voidCallback, callBackFunc: voidCallback,
@ -132,13 +146,16 @@ class ActionsFragment extends StatelessWidget {
String getActionDuration(int index) { String getActionDuration(int index) {
if (actionHistoryList[index].aCTIONCODE == "SUBMIT") { if (actionHistoryList[index].aCTIONCODE == "SUBMIT") {
return ""; return "";
} else if(actionHistoryList[index].aCTIONCODE == "PENDING") { } else if (actionHistoryList[index].aCTIONCODE == "PENDING") {
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[++index].nOTIFICATIONDATE!); if (actionHistoryList[index + 1].nOTIFICATIONDATE!.isEmpty) {
return "";
}
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index + 1].nOTIFICATIONDATE!);
Duration duration = DateTime.now().difference(dateTimeFrom); Duration duration = DateTime.now().difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration); return "Action duration: " + DateUtil.formatDuration(duration);
} else { } else {
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!); DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[++index].nOTIFICATIONDATE!); DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index + 1].nOTIFICATIONDATE!);
Duration duration = dateTimeTo.difference(dateTimeFrom); Duration duration = dateTimeTo.difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration); return "Action duration: " + DateUtil.formatDuration(duration);
} }

@ -20,7 +20,7 @@ AppBar AppBarWidget(BuildContext context,
children: [ children: [
GestureDetector( GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: Feedback.wrapForTap(() => Navigator.maybePop(context), context), onTap: Feedback.wrapForTap(() => Navigator.maybePop(context, true), context),
child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor),
), ),
4.width, 4.width,
@ -59,7 +59,7 @@ AppBar AppBarWidget(BuildContext context,
}, },
icon: const Icon(Icons.people, color: MyColors.textMixColor), icon: const Icon(Icons.people, color: MyColors.textMixColor),
), ),
...actions??[] ...actions ?? []
], ],
); );
} }

@ -5,7 +5,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.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/chat/chat_provider_model.dart'; import 'package:mohem_flutter_app/api/chat/chat_api_client.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/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';
@ -88,7 +88,12 @@ class _SearchEmployeeBottomSheetState extends State<SearchEmployeeBottomSheet> {
void fetchChatUser({bool isNeedLoading = true}) async { void fetchChatUser({bool isNeedLoading = true}) async {
try { try {
Utils.showLoading(context); Utils.showLoading(context);
chatUsersList = await ChatProviderModel().getChatMemberFromSearch(searchText, int.parse(AppState().chatDetails!.response!.id.toString())); chatUsersList = await ChatApiClient().getChatMemberFromSearch(
searchText,
int.parse(
AppState().chatDetails!.response!.id.toString(),
),
);
Utils.hideLoading(context); Utils.hideLoading(context);
setState(() {}); setState(() {});
} catch (e) { } catch (e) {
@ -236,7 +241,6 @@ class _SearchEmployeeBottomSheetState extends State<SearchEmployeeBottomSheet> {
arguments: {"targetUser": chatUsersList![index], "isNewChat": true}, arguments: {"targetUser": chatUsersList![index], "isNewChat": true},
); );
}, },
), ),
); );
}, },

@ -20,7 +20,7 @@ class ImageOptions {
if (Platform.isAndroid) { if (Platform.isAndroid) {
cameraImageAndroid(image); cameraImageAndroid(image);
} else { } else {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? "");
String fileName = _image.path; String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync(); var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes); String base64Encode = base64.encode(bytes);
@ -33,7 +33,7 @@ class ImageOptions {
if (Platform.isAndroid) { if (Platform.isAndroid) {
galleryImageAndroid(image); galleryImageAndroid(image);
} else { } else {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? "");
String fileName = _image.path; String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync(); var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes); String base64Encode = base64.encode(bytes);
@ -74,7 +74,7 @@ class ImageOptions {
if (Platform.isAndroid) { if (Platform.isAndroid) {
galleryImageAndroid(image); galleryImageAndroid(image);
} else { } else {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? "");
String fileName = _image.path; String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync(); var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes); String base64Encode = base64.encode(bytes);
@ -91,7 +91,7 @@ class ImageOptions {
if (Platform.isAndroid) { if (Platform.isAndroid) {
cameraImageAndroid(image); cameraImageAndroid(image);
} else { } else {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? "");
String fileName = _image.path; String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync(); var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes); String base64Encode = base64.encode(bytes);
@ -114,7 +114,7 @@ class ImageOptions {
} }
void galleryImageAndroid(Function(String, File) image) async { void galleryImageAndroid(Function(String, File) image) async {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? "");
String fileName = _image.path; String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync(); var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes); String base64Encode = base64.encode(bytes);
@ -124,7 +124,7 @@ void galleryImageAndroid(Function(String, File) image) async {
} }
void cameraImageAndroid(Function(String, File) image) async { void cameraImageAndroid(Function(String, File) image) async {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? "");
String fileName = _image.path; String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync(); var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes); String base64Encode = base64.encode(bytes);

@ -14,6 +14,7 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/dialogs/success_dialog.dart'; import 'package:mohem_flutter_app/ui/dialogs/success_dialog.dart';
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:mohem_flutter_app/widgets/dialogs/dialogs.dart'; import 'package:mohem_flutter_app/widgets/dialogs/dialogs.dart';
import 'package:mohem_flutter_app/widgets/location/Location.dart'; import 'package:mohem_flutter_app/widgets/location/Location.dart';
import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart'; import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart';
@ -144,14 +145,28 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
Utils.showLoading(context); Utils.showLoading(context);
try { try {
GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId, isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng); GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId, isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng);
bool status = await model.fetchAttendanceTracking(context); if(g?.messageStatus != 1) {
Utils.hideLoading(context); Utils.hideLoading(context);
showMDialog( showDialog(
context, context: context,
backgroundColor: Colors.transparent, builder: (cxt) => ConfirmDialog(
isDismissable: false, message: g?.errorEndUserMessage ?? "Unexpected error occurred",
child: SuccessDialog(widget.isFromDashboard), onTap: () {
); Navigator.pop(context);
},
),
);
} else {
bool status = await model.fetchAttendanceTracking(context);
Utils.hideLoading(context);
showMDialog(
context,
backgroundColor: Colors.transparent,
isDismissable: false,
child: SuccessDialog(widget.isFromDashboard),
);
}
} catch (ex) { } catch (ex) {
print(ex); print(ex);
Utils.hideLoading(context); Utils.hideLoading(context);
@ -166,14 +181,27 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
Utils.showLoading(context); Utils.showLoading(context);
try { try {
GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? "", isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng); GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? "", isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng);
bool status = await model.fetchAttendanceTracking(context); if(g?.messageStatus != 1) {
Utils.hideLoading(context); Utils.hideLoading(context);
showMDialog( showDialog(
context, context: context,
backgroundColor: Colors.transparent, builder: (cxt) => ConfirmDialog(
isDismissable: false, message: g?.errorEndUserMessage ?? "Unexpected error occurred",
child: SuccessDialog(widget.isFromDashboard), onTap: () {
); Navigator.pop(context);
},
),
);
} else {
bool status = await model.fetchAttendanceTracking(context);
Utils.hideLoading(context);
showMDialog(
context,
backgroundColor: Colors.transparent,
isDismissable: false,
child: SuccessDialog(widget.isFromDashboard),
);
}
} catch (ex) { } catch (ex) {
print(ex); print(ex);
Utils.hideLoading(context); Utils.hideLoading(context);

@ -188,6 +188,53 @@ class ServicesMenuShimmer extends StatelessWidget {
} }
} }
class MarathonBannerShimmer extends StatelessWidget {
const MarathonBannerShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.asset("assets/images/monthly_attendance.svg").toShimmer(),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Attendan".toText11(isBold: false).toShimmer(),
5.height,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
),
6.width,
SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer()
],
),
],
)
],
).paddingOnly(left: 10, right: 10, bottom: 10, top: 12),
);
}
}
class ChatHomeShimmer extends StatelessWidget { class ChatHomeShimmer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

@ -79,13 +79,12 @@ dependencies:
pull_to_refresh: ^2.0.0 pull_to_refresh: ^2.0.0
# lottie json animations # lottie json animations
lottie: any lottie: any
# Steps Progress
steps_indicator: ^1.3.0
# Marathon Card Swipe # Marathon Card Swipe
appinio_swiper: ^1.1.1 appinio_swiper: ^1.1.1
expandable: ^5.0.1 expandable: ^5.0.1
# networkImage
cached_network_image: ^3.2.2
#Chat #Chat
signalr_netcore: ^1.3.3 signalr_netcore: ^1.3.3
@ -95,6 +94,9 @@ dependencies:
camera: ^0.10.0+4 camera: ^0.10.0+4
#Encryption
cryptography: ^2.0.5
cryptography_flutter: ^2.0.2
video_player: ^2.4.7 video_player: ^2.4.7

Loading…
Cancel
Save