Merge branch 'master' into development_aamir

merge-requests/116/head
Aamir Muhammad 2 years ago
commit 35f814b74a

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

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

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

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

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

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

@ -131,8 +131,9 @@ extension EmailValidator on String {
style: TextStyle(fontSize: 19, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.14),
);
Widget toText20({Color? color, bool isBold = false}) => Text(
Widget toText20({Color? color, bool isBold = false, bool isCentered = false}) => Text(
this,
textAlign: isCentered ? TextAlign.center : null,
style: TextStyle(fontSize: 20, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4),
);

File diff suppressed because it is too large Load Diff

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

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

@ -16,25 +16,28 @@ class MarathonDetailModel {
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});
int? marathonBufferTime;
MarathonDetailModel({
id,
titleEn,
titleAr,
descEn,
descAr,
winDeciderTime,
winnersCount,
questGapTime,
startTime,
endTime,
marathoneStatusId,
scheduleTime,
selectedLanguage,
projects,
sponsors,
questions,
totalQuestions,
marathonBufferTime,
});
MarathonDetailModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -50,22 +53,21 @@ class MarathonDetailModel {
marathoneStatusId = json['marathoneStatusId'];
scheduleTime = json['scheduleTime'];
selectedLanguage = json['selectedLanguage'];
projects = json['projects'] != null
? Projects.fromJson(json['projects'])
: null;
projects = json['projects'] != null ? Projects.fromJson(json['projects']) : null;
if (json['sponsors'] != null) {
sponsors = <Sponsors>[];
json['sponsors'].forEach((v) {
sponsors!.add( Sponsors.fromJson(v));
sponsors!.add(Sponsors.fromJson(v));
});
}
if (json['questions'] != null) {
questions = <Questions>[];
json['questions'].forEach((v) {
questions!.add( Questions.fromJson(v));
questions!.add(Questions.fromJson(v));
});
}
totalQuestions = json["totalQuestions"];
marathonBufferTime = json["marathonBufferTime"];
}
Map<String, dynamic> toJson() {
@ -93,6 +95,7 @@ class MarathonDetailModel {
data['questions'] = questions!.map((v) => v.toJson()).toList();
}
data['totalQuestions'] = totalQuestions;
data['marathonBufferTime'] = marathonBufferTime;
return data;
}
@ -132,14 +135,7 @@ class Sponsors {
String? logo;
List<SponsorPrizes>? sponsorPrizes;
Sponsors(
{id,
nameEn,
nameAr,
image,
video,
logo,
sponsorPrizes});
Sponsors({id, nameEn, nameAr, image, video, logo, sponsorPrizes});
Sponsors.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -151,13 +147,13 @@ class Sponsors {
if (json['sponsorPrizes'] != null) {
sponsorPrizes = <SponsorPrizes>[];
json['sponsorPrizes'].forEach((v) {
sponsorPrizes!.add( SponsorPrizes.fromJson(v));
sponsorPrizes!.add(SponsorPrizes.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['nameEn'] = nameEn;
data['nameAr'] = nameAr;
@ -165,8 +161,7 @@ class Sponsors {
data['video'] = video;
data['logo'] = logo;
if (sponsorPrizes != null) {
data['sponsorPrizes'] =
sponsorPrizes!.map((v) => v.toJson()).toList();
data['sponsorPrizes'] = sponsorPrizes!.map((v) => v.toJson()).toList();
}
return data;
}
@ -186,7 +181,7 @@ class SponsorPrizes {
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['marathonPrizeEn'] = marathonPrizeEn;
data['marathonPrizeAr'] = marathonPrizeAr;
@ -208,19 +203,7 @@ class Questions {
int? questOptionsLimit;
List? questionOptions;
Questions(
{id,
titleEn,
titleAr,
marathonId,
questionTypeId,
questionTime,
nextQuestGap,
gapType,
gapValue,
gapImage,
questOptionsLimit,
questionOptions});
Questions({id, titleEn, titleAr, marathonId, questionTypeId, questionTime, nextQuestGap, gapType, gapValue, gapImage, questOptionsLimit, questionOptions});
Questions.fromJson(Map<String, dynamic> json) {
id = json['id'];

@ -32,6 +32,8 @@ import 'package:signalr_netcore/signalr_client.dart';
late HubConnection chatHubConnection;
class DashboardScreen extends StatefulWidget {
DashboardScreen({Key? key}) : super(key: key);

@ -165,6 +165,9 @@ class _LoginScreenState extends State<LoginScreen> {
// username.text = "206535"; // Hashim User
// password.text = "Namira786";
// 13777
// Ab12345cd
}
if (isAppOpenBySystem!) checkFirebaseToken();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save