Merge branch 'master' into fatima
# Conflicts: # lib/classes/consts.dart # lib/ui/leave_balance/add_leave_balance_screen.dartfatima
commit
85be372ad8
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
@ -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>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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++;
|
||||
}
|
||||
}
|
||||
@ -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,150 +1,237 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
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/extensions/int_extensions.dart';
|
||||
import 'package:mohem_flutter_app/extensions/string_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 {
|
||||
const ChatBubble(
|
||||
{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;
|
||||
ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key);
|
||||
final String dateTime;
|
||||
final bool isReplied;
|
||||
final String userName;
|
||||
final SingleUserChatModel cItem;
|
||||
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
// padding: EdgeInsets.zero,
|
||||
padding: EdgeInsets.only(
|
||||
left: isCurrentUser ? 110 : 20,
|
||||
right: isCurrentUser ? 20 : 110,
|
||||
bottom: 9,
|
||||
),
|
||||
makeAssign();
|
||||
return isCurrentUser ? currentUser(context) : receiptUser(context);
|
||||
}
|
||||
|
||||
child: Align(
|
||||
alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: MyColors.white,
|
||||
gradient: isCurrentUser
|
||||
? null
|
||||
: const LinearGradient(
|
||||
transform: GradientRotation(
|
||||
.46,
|
||||
),
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
colors: <Color>[
|
||||
MyColors.gradiantEndColor,
|
||||
MyColors.gradiantStartColor,
|
||||
Widget currentUser(context) {
|
||||
return 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),
|
||||
),
|
||||
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),
|
||||
],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(
|
||||
10,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: isReplied ? 8 : 5,
|
||||
right: 8,
|
||||
left: 8,
|
||||
bottom: 5,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
if (isReplied)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
5.0,
|
||||
),
|
||||
child: Container(
|
||||
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),
|
||||
),
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
).expanded,
|
||||
if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 ||
|
||||
cItem.userChatReplyResponse!.fileTypeId == 3 ||
|
||||
cItem.userChatReplyResponse!.fileTypeId == 4)
|
||||
// Container(
|
||||
// padding: EdgeInsets.all(0), // Border width
|
||||
// decoration: BoxDecoration(color: Colors.red, borderRadius: const BorderRadius.all(Radius.circular(8))),
|
||||
// child: ClipRRect(
|
||||
// borderRadius: const BorderRadius.all(
|
||||
// Radius.circular(8),
|
||||
// ),
|
||||
// child: SizedBox.fromSize(
|
||||
// size: Size.fromRadius(8), // Image radius
|
||||
// child: showImage(
|
||||
// isReplyPreview: true,
|
||||
// fileName: cItem.userChatReplyResponse!.contant!,
|
||||
// fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg"),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
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(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
dateTime.toText12(
|
||||
color: isCurrentUser ? MyColors.grey41Color.withOpacity(.5) : MyColors.white.withOpacity(0.7),
|
||||
),
|
||||
if (isCurrentUser) 5.width,
|
||||
// if (isCurrentUser)
|
||||
// Icon(
|
||||
// isDelivered ? Icons.done_all : Icons.done_all,
|
||||
// color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor,
|
||||
// size: 14,
|
||||
// ),
|
||||
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,
|
||||
if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 ||
|
||||
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()),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue