diff --git a/assets/images/congrats.gif b/assets/images/congrats.gif new file mode 100644 index 0000000..32818b2 Binary files /dev/null and b/assets/images/congrats.gif differ diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 59c0814..c4d6d65 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -502,7 +502,12 @@ "favorite": "مفضلتي", "searchfromchat": "البحث من الدردشة", "yourAnswerCorrect": "إجابتك صحيحة", - "youMissedTheQuestion": "فاتك !! أنت خارج اللعبة. لكن يمكنك المتابعة.", - "wrongAnswer": "إجابة خاطئة! أنت خارج اللعبة. لكن يمكنك المتابعة." - + "youMissedTheQuestion": "نفد منك الوقت. أنت خارج اللعبة. لكن يمكنك الاستمرار وكمشاهد.", + "wrongAnswer": "إجابتك غير صحيحة. أنت خارج اللعبة. لكن يمكنك الاستمرار وكمشاهد.", + "oops": "أوه!!!", + "winner": "الفائز", + "youWantToLeaveMarathon": "هل أنت متأكد أنك تريد العودة؟ سوف تخرج من المسابقة.", + "ourSponsor": "راعينا:", + "startingIn": "يبدأ في", + "youAreOutOfContest": "أنت خارج المسابقة." } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b0ab50e..48a1db5 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -499,10 +499,16 @@ "codeExpire": "The verification code has been expired", "allQuestionsCorrect": "You have answered all questions correct", "typeheretoreply": "Type here to reply", - "favorite" : "My Favorites", + "favorite": "My Favorites", "searchfromchat": "Search from chat", "yourAnswerCorrect": "Your answer is correct", - "youMissedTheQuestion": "You Missed !! You are out of the game. But you can follow up.", - "wrongAnswer": "Wrong Answer! You are out of the game. But you can follow up." + "youMissedTheQuestion": "You ran out of time. You are out of the game. But you can continue and as a viewer.", + "wrongAnswer": "Your answer is Incorrect. You are out of the game. But you can continue and as a viewer.", + "oops": "Ooopsss!!!!", + "winner": "WINNER", + "youWantToLeaveMarathon": "Are you sure you want to go back? You will be out of the contest.", + "ourSponsor": "Our Sponsor:", + "startingIn": "Starting in", + "youAreOutOfContest": "You are out of the contest." } \ No newline at end of file diff --git a/assets/lottie/marathon_waiting.json b/assets/lottie/marathon_waiting.json new file mode 100644 index 0000000..83e4756 --- /dev/null +++ b/assets/lottie/marathon_waiting.json @@ -0,0 +1 @@ +{"nm":"Loading_003","mn":"","layers":[{"ty":0,"nm":"2","mn":"","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"tt":0,"hasMask":false,"td":0,"ao":0,"ks":{"a":{"a":0,"k":[250,250,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":500,"h":500,"refId":"comp_0","ind":0},{"ty":0,"nm":"1","mn":"","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"tt":0,"hasMask":false,"td":0,"ao":0,"ks":{"a":{"a":0,"k":[250,250,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":60,"ix":11},"r":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[-31],"t":4},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[-31],"t":207.000008431283}],"ix":10}},"ef":[],"w":500,"h":500,"refId":"comp_1","ind":1}],"ddd":0,"h":500,"w":500,"meta":{"a":"","k":"","d":"","g":"@lottiefiles/toolkit-js 0.17.4","tc":"#ffffff"},"v":"5.2.1","fr":29.9700012207031,"op":202.000008227629,"ip":9.00000036657752,"assets":[{"nm":"","mn":"","layers":[{"ty":4,"nm":"Layer 3 Outlines 3","mn":"","sr":1,"st":5.00000020365417,"op":605.000024642155,"ip":-19.0000007738859,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"tt":0,"hasMask":false,"td":1,"ao":0,"ks":{"a":{"a":0,"k":[186.018,192.618,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[97.292,100.917,100],"t":4},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[104.224,99.892,100],"t":108},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[97.292,100.917,100],"t":209.000008512745}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[252.209,249.449,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[310.866],"t":4},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[-49],"t":209.000008512745}],"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[51.471,-19.6],[51.29,75.368],[-11.48,42.136],[-85.813,28.535],[-16.737,-1.394],[-18.031,-37.988],[22.567,-60.623]],"o":[[-20.195,7.689],[-24.566,-36.096],[23.791,-87.319],[15.938,-5.3],[41.874,3.489],[28.123,59.252],[-20.321,54.592]],"v":[[18.613,169.26],[-146.062,126.343],[-172.423,1.333],[1.405,-192.793],[62.244,-200.318],[155.78,-124.529],[159.191,64.737]]},"ix":2}},{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":2,"cix":2,"np":0,"it":[{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.098,0.1137,0.1451],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100.261,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[184.153,201.962],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":0},{"ty":4,"nm":"Layer 5 Outlines 3","mn":"","sr":1,"st":5.00000020365417,"op":605.000024642155,"ip":-19.0000007738859,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"tt":2,"hasMask":false,"td":0,"ao":0,"ks":{"a":{"a":0,"k":[216.251,216.449,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[252.209,249.449,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":1,"it":[{"ty":"sh","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 4","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[119.432,0],[0,-119.541],[-119.432,0],[0,119.542]],"o":[[-119.432,0],[0,119.542],[119.432,0],[0,-119.541]],"v":[[0,-216.449],[-216.25,0],[0,216.449],[216.251,0]]},"ix":2}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gf","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[65.201,-74.966],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.16862745098039217,0.7215686274509804,0.6588235294117647,0.455,0.13725490196078433,0.615686274509804,0.5607843137254902,0.999,0.11372549019607843,0.5725490196078431,0.6666666666666666],"ix":9}},"t":1,"a":{"a":0,"k":0},"s":{"a":0,"k":[-130.068,76.804],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[216.251,216.449],"ix":2},"r":{"a":0,"k":-149.651,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}],"id":"comp_0","fr":30},{"nm":"","mn":"","layers":[{"ty":4,"nm":"Layer 3 Outlines 3","mn":"","sr":1,"st":5.00000020365417,"op":605.000024642155,"ip":-19.0000007738859,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"tt":0,"hasMask":false,"td":1,"ao":0,"ks":{"a":{"a":0,"k":[186.018,192.618,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[97.292,100.917,100],"t":4},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[104.224,99.892,100],"t":108},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[97.292,100.917,100],"t":209.000008512745}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[252.209,249.449,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[-49],"t":4},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[310.866],"t":209.000008512745}],"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[51.471,-19.6],[51.29,75.368],[-11.48,42.136],[-85.813,28.535],[-16.737,-1.394],[-18.031,-37.988],[22.567,-60.623]],"o":[[-20.195,7.689],[-24.566,-36.096],[23.791,-87.319],[15.938,-5.3],[41.874,3.489],[28.123,59.252],[-20.321,54.592]],"v":[[18.613,169.26],[-146.062,126.343],[-172.423,1.333],[1.405,-192.793],[62.244,-200.318],[155.78,-124.529],[159.191,64.737]]},"ix":2}},{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":2,"cix":2,"np":0,"it":[{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.098,0.1137,0.1451],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100.261,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[184.153,201.962],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":0},{"ty":4,"nm":"Layer 5 Outlines 3","mn":"","sr":1,"st":5.00000020365417,"op":605.000024642155,"ip":-19.0000007738859,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"tt":2,"hasMask":false,"td":0,"ao":0,"ks":{"a":{"a":0,"k":[216.251,216.449,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[252.209,249.449,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":1,"it":[{"ty":"sh","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 4","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[119.432,0],[0,-119.541],[-119.432,0],[0,119.542]],"o":[[-119.432,0],[0,119.542],[119.432,0],[0,-119.541]],"v":[[0,-216.449],[-216.25,0],[0,216.449],[216.251,0]]},"ix":2}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gf","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[65.201,-74.966],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.07058823529411765,0.3411764705882353,0.396078431372549,0.424,0.07058823529411765,0.3411764705882353,0.396078431372549,1,0.07058823529411765,0.3411764705882353,0.396078431372549],"ix":9}},"t":1,"a":{"a":0,"k":0},"s":{"a":0,"k":[-130.068,76.804],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[216.251,216.449],"ix":2},"r":{"a":0,"k":-149.651,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}],"id":"comp_1","fr":30}]} \ No newline at end of file diff --git a/lib/api/items_for_sale/items_for_sale_api_client.dart b/lib/api/items_for_sale/items_for_sale_api_client.dart index 436ae6e..eae6ffb 100644 --- a/lib/api/items_for_sale/items_for_sale_api_client.dart +++ b/lib/api/items_for_sale/items_for_sale_api_client.dart @@ -66,6 +66,41 @@ class ItemsForSaleApiClient { }, url, postParams); } + Future updateItemsForSale(int itemSaleID) async { + List getItemsForSaleList = []; + + String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateItemForSale"; + + // request.fields['itemSaleID'] = itemSaleID.toString(); + // request.fields['Channel'] = "31"; + // request.fields['isActive'] = "false"; + // request.fields['LogInToken'] = loginTokenID!; + // request.fields['Token'] = tokenID!; + // request.fields['MobileNo'] = empMobNum!; + // request.fields['EmployeeNumber'] = empNum!; + // request.fields['employeeNumber'] = empNum; + + Map postParams = { + "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, + "employeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, + "MobileNo": AppState().memberInformationList?.eMPLOYEEMOBILENUMBER, + "itemSaleID": itemSaleID.toString(), + "Channel": "31", + "isActive": "false", + "Token": AppState().postParamsObject?.tokenID + }; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((response) { + var body = json.decode(response['Mohemm_ITG_ResponseItem']); + + // body['result']['data'].forEach((v) { + // getItemsForSaleList.add(new GetItemsForSaleList.fromJson(v)); + // }); + return getItemsForSaleList; + }, url, postParams); + } + Future> getEmployeePostedAds() async { List employeePostedAdsList = []; diff --git a/lib/api/marathon/marathon_api_client.dart b/lib/api/marathon/marathon_api_client.dart index 1ec117d..132ec30 100644 --- a/lib/api/marathon/marathon_api_client.dart +++ b/lib/api/marathon/marathon_api_client.dart @@ -1,22 +1,19 @@ 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 { + late HubConnection hubConnection; + L.Logger logger = L.Logger(); + Future getMarathonToken() async { String employeeUserName = AppState().getUserName ?? ""; String employeeSession = AppState().postParamsObject?.pSessionId.toString() ?? ""; @@ -55,11 +52,9 @@ class MarathonApiClient { 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 ""; } } @@ -70,9 +65,14 @@ class MarathonApiClient { Response response = await ApiClient().getJsonForResponse(ApiConsts.marathonUpcomingUrl + payrollString, token: AppState().getMarathonToken ?? await getMarathonToken()); var json = jsonDecode(response.body); + logger.i("json in getMarathonDetails: $json"); MarathonGenericModel marathonGenericModel = MarathonGenericModel.fromJson(json); + if (marathonGenericModel.data == null) { + return MarathonDetailModel(); + } + MarathonDetailModel marathonDetailModel = MarathonDetailModel.fromJson(marathonGenericModel.data); AppState().setMarathonProjectId = marathonDetailModel.id!; @@ -80,99 +80,165 @@ class MarathonApiClient { return marathonDetailModel; } - late HubConnection hubConnection; - L.Logger logger = L.Logger(); + Future joinMarathonAsParticipant() async { + Map jsonObject = { + "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "", + "employeeName": AppState().memberInformationList!.eMPLOYEENAME ?? "", + "marathonId": AppState().getMarathonProjectId!, + }; - Future 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: [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: [ - { - "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "", - "employeeName": AppState().memberInformationList!.eMPLOYEENAME ?? "", - "marathonId": AppState().getMarathonProjectId, - } - ], - ).catchError((e) { - logger.i("Error in AddParticipant: $e"); - }); - - context.read().addItemToList(ApiConsts.dummyQuestion); - - await hubConnection.invoke( - "SendQuestionToParticipant", - args: [ - { - "marathonId": "${AppState().getMarathonProjectId}", - } - ], - ).catchError((e) { - logger.i("Error in SendQuestionToParticipant: $e"); - }); - - try { - hubConnection.on("OnSendQuestionToParticipant", (List? arguments) { - onSendQuestionToParticipant(arguments, context); - }); - } catch (e, s) { - logger.i("Error in OnSendQuestionToParticipant"); - } + 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 + return true; + } - try { - hubConnection.on("OnParticipantJoin", (List? arguments) { - onParticipantJoin(arguments, context); - }); - } catch (e, s) { - logger.i("Error in OnParticipantJoin"); + if (marathonModel.statusCode == 200) { + if (marathonModel.data != null && marathonModel.isSuccessful == true) { + logger.i("joinMarathonAsParticipant: ${marathonModel.data}"); + return true; + } else { + return false; } + } else { + return false; } } - Future onSendQuestionToParticipant(List? arguments, BuildContext context) async { - logger.i("onSendQuestionToParticipant arguments: $arguments"); + Future getNextQuestion({required String? questionId, required String marathonId}) async { + Map jsonObject = { + "questionId": questionId, + "marathonId": marathonId, + }; - if (arguments != null) { - Map data = arguments.first! as Map; - var json = data["data"]; - QuestionModel newQuestion = QuestionModel.fromJson(json); - context.read().onNewQuestionReceived(newQuestion); + Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonNextQuestionUrl, jsonObject, token: AppState().getMarathonToken ?? await getMarathonToken()); + + var json = jsonDecode(response.body); + + var data = json["data"]; + + if (data != null) { + QuestionModel newQuestion = QuestionModel.fromJson(data); + return newQuestion; + } else { + return null; } } - Future onParticipantJoin(List? arguments, BuildContext context) async { - logger.i("OnParticipantJoin arguments: $arguments"); - context.watch().totalMarathoners++; + Future submitSelectedOption({required String? selectedAnswerId}) async { + Map jsonObject = {"selectedOptionId": selectedAnswerId}; + + Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonSubmitAnswerUrl, jsonObject, token: AppState().getMarathonToken ?? await getMarathonToken()); + + var json = jsonDecode(response.body); + logger.i("json: $json"); + + MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json); + + if (marathonModel.isSuccessful == null) { + return false; + } + + return marathonModel.isSuccessful!; } + +// Future buildHubConnection(BuildContext context, String prizeId) 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: [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: [ +// { +// "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "", +// "employeeName": AppState().memberInformationList!.eMPLOYEENAME ?? "", +// "marathonId": AppState().getMarathonProjectId, +// "prizeId": "8577B2E8-5DD7-43F0-10DD-08DACB0AC064", +// } +// ], +// ).catchError((e) { +// logger.i("Error in AddParticipant: $e"); +// }); +// +// context.read().addItemToList(ApiConsts.dummyQuestion); +// +// await hubConnection.invoke( +// "SendQuestionToParticipant", +// args: [ +// { +// "marathonId": "${AppState().getMarathonProjectId}", +// } +// ], +// ).catchError((e) { +// Utils.confirmDialog(context, e.toString()); +// logger.i("Error in SendQuestionToParticipant: $e"); +// }); +// +// try { +// hubConnection.on("OnSendQuestionToParticipant", (List? arguments) { +// onSendQuestionToParticipant(arguments, context); +// }); +// } catch (e, s) { +// logger.i("Error in OnSendQuestionToParticipant"); +// } +// +// try { +// hubConnection.on("OnParticipantJoin", (List? arguments) { +// onParticipantJoin(arguments, context); +// }); +// } catch (e, s) { +// logger.i("Error in OnParticipantJoin"); +// } +// } +// } +// +// Future onSendQuestionToParticipant(List? arguments, BuildContext context) async { +// logger.i("onSendQuestionToParticipant arguments: $arguments"); +// +// if (arguments != null) { +// Map data = arguments.first! as Map; +// var json = data["data"]; +// QuestionModel newQuestion = QuestionModel.fromJson(json); +// AppRoutes.navigatorKey.currentContext!.read().onNewQuestionReceived(newQuestion); +// } +// } +// +// Future onParticipantJoin(List? arguments, BuildContext context) async { +// logger.i("OnParticipantJoin arguments: $arguments"); +// context.watch().totalMarathoners++; +// } } diff --git a/lib/api/my_attendance_api_client.dart b/lib/api/my_attendance_api_client.dart index 9bb16a8..5833413 100644 --- a/lib/api/my_attendance_api_client.dart +++ b/lib/api/my_attendance_api_client.dart @@ -70,7 +70,7 @@ class MyAttendanceApiClient { }, url, postParams); } - Future getDefaultValue(String pSegmentName, String pDescFlexContextCode, String pDescFlexName, List> list, String? empID) async { + Future getDefaultValue(String pSegmentName, String pDescFlexContextCode, String pDescFlexName, List> list, {String? empID}) async { String url = "${ApiConsts.erpRest}GET_DEFAULT_VALUE"; Map postParams = { "P_SELECTED_RESP_ID": -999, @@ -82,7 +82,7 @@ class MyAttendanceApiClient { "GetValueSetValuesTBL": list, }; postParams.addAll(AppState().postParamsJson); - if (empID!.isNotEmpty) { + if (empID != null && empID!.isNotEmpty) { postParams['P_SELECTED_EMPLOYEE_NUMBER'] = empID; } return await ApiClient().postJsonForObject((json) { diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 841f29c..1230c8b 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -2,8 +2,8 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server - //static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server - static String baseUrl = "https://hmgwebservices.com"; // Live server + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server + // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; @@ -23,19 +23,23 @@ class ApiConsts { static String chatSingleUserHistoryUrl = chatServerBaseApiUrl + "UserChatHistory/"; static String chatMediaImageUploadUrl = chatServerBaseApiUrl + "shared/"; static String chatFavUser = chatServerBaseApiUrl + "FavUser/"; - static String chatUserImages = chatServerBaseUrl + "empservice/api/employee/"; + static String chatUserImages = chatServerBaseUrl + "empservice/api/employee/"; + //Brain Marathon Constants - static String marathonBaseUrl = "https://18.188.181.12/service/"; - static String marathonParticipantLoginUrl = marathonBaseUrl + "api/auth/participantlogin"; - static String marathonProjectGetUrl = marathonBaseUrl + "api/Project/Project_Get"; - static String marathonUpcomingUrl = marathonBaseUrl + "api/marathon/upcoming/"; - static String marathonHubConnectionUrl = marathonBaseUrl + "MarathonBroadCast"; + static String marathonBaseUrl = "https://marathoon.com/service/api/"; + static String marathonParticipantLoginUrl = marathonBaseUrl + "auth/participantlogin"; + static String marathonProjectGetUrl = marathonBaseUrl + "Project/Project_Get"; + static String marathonUpcomingUrl = marathonBaseUrl + "marathon/upcoming/"; + static String marathonJoinParticipantUrl = marathonBaseUrl + "participant/participant_join"; + static String marathonNextQuestionUrl = marathonBaseUrl + "question/next"; + static String marathonSubmitAnswerUrl = marathonBaseUrl + "question/submit"; + static String marathonQualifiersUrl = marathonBaseUrl + "winner/getWinner/"; + static String marathonSelectedWinner = marathonBaseUrl + "winner/getSelectedWinner/"; //DummyCards for the UI static CardContent dummyQuestion = const CardContent(); - } class SharedPrefsConsts { diff --git a/lib/classes/date_uitl.dart b/lib/classes/date_uitl.dart index f37fbea..a1e52d9 100644 --- a/lib/classes/date_uitl.dart +++ b/lib/classes/date_uitl.dart @@ -40,7 +40,7 @@ class DateUtil { } static DateTime convertSimpleStringDateToDate(String date) { - return DateFormat("MM/dd/yyyy hh:mm:ss a").parse(date); + return DateFormat("MM/dd/yyyy hh:mm:ss").parse(date); } static DateTime convertSimpleStringDateToDateddMMyyyy(String date) { diff --git a/lib/classes/lottie_consts.dart b/lib/classes/lottie_consts.dart index 24dc423..7846f6c 100644 --- a/lib/classes/lottie_consts.dart +++ b/lib/classes/lottie_consts.dart @@ -4,6 +4,7 @@ class MyLottieConsts { static const String celebrate2Lottie = "assets/lottie/celebrate2.json"; static const String winnerLottie = "assets/lottie/winner3.json"; static const String allQuestions = "assets/lottie/all_questions.json"; + 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"; } diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 7e7e83c..33d9830 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -9,6 +9,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; @@ -20,6 +21,7 @@ import 'package:mohem_flutter_app/widgets/loading_dialog.dart'; import 'package:nfc_manager/nfc_manager.dart'; import 'package:nfc_manager/platform_tags.dart'; import 'package:shared_preferences/shared_preferences.dart'; + // ignore_for_file: avoid_annotating_with_dynamic class Utils { @@ -289,7 +291,7 @@ class Utils { String formattedDate; if (date.isNotEmpty) { formattedDate = date.split('T')[0]; - if(!formattedDate.contains("00:00:00")) { + if (!formattedDate.contains("00:00:00")) { formattedDate = formattedDate + ' 00:00:00'; } } else { @@ -298,6 +300,10 @@ class Utils { return formattedDate; } + static String formatDateDefault(String date) { + return DateFormat('yyyy-MM-dd').format(DateFormat('dd-MMM-yyyy').parseLoose(date)); + } + static Future selectDate(BuildContext context, DateTime selectedDate) async { if (!Platform.isIOS) { await showCupertinoModalPopup( @@ -326,8 +332,7 @@ class Utils { return selectedDate; } - static void readNFc({required Function(String) onRead}) { - + static void readNFc({required Function(String) onRead}) { NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { print(tag.data); var f; diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 7cf8a35..d1b6b08 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -9,7 +9,6 @@ import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/ui/landing/itg/its_add_screen_video_image.dart'; import 'package:mohem_flutter_app/ui/landing/itg/survey_screen.dart'; -import 'package:mohem_flutter_app/ui/landing/today_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/landing/today_attendance_screen2.dart'; import 'package:mohem_flutter_app/ui/leave_balance/add_leave_balance_screen.dart'; import 'package:mohem_flutter_app/ui/leave_balance/leave_balance_screen.dart'; @@ -21,6 +20,8 @@ import 'package:mohem_flutter_app/ui/login/verify_last_login_screen.dart'; import 'package:mohem_flutter_app/ui/login/verify_login_screen.dart'; 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/marathon_winner_selection.dart'; import 'package:mohem_flutter_app/ui/marathon/winner_screen.dart'; import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart'; @@ -73,6 +74,8 @@ import 'package:mohem_flutter_app/ui/work_list/worklist_detail_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/worklist_settings.dart'; class AppRoutes { + static GlobalKey navigatorKey = GlobalKey(); + static const String splash = "/splash"; static const String registerSelection = "/registerSelection"; static const String loginVerifyAccount = "/loginVerifyAccount"; @@ -185,6 +188,8 @@ class AppRoutes { static const String marathonScreen = "/marathonScreen"; static const String marathonWinnerSelection = "/marathonWinnerSelection"; static const String marathonWinnerScreen = "/marathonWinnerScreen"; + static const String marathonSponsorVideoScreen = "/marathonSponsorVideoScreen"; + static const String marathonWaitingScreen = "/marathonWaitingScreen"; static final Map routes = { login: (BuildContext context) => LoginScreen(), @@ -293,5 +298,7 @@ class AppRoutes { marathonScreen: (BuildContext context) => MarathonScreen(), marathonWinnerSelection: (BuildContext context) => MarathonWinnerSelection(), marathonWinnerScreen: (BuildContext context) => WinnerScreen(), + marathonSponsorVideoScreen: (BuildContext context) => const SponsorVideoScreen(), + marathonWaitingScreen: (BuildContext context) => const MarathonWaitingScreen(), }; } diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 3546f6b..3261149 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -118,8 +118,9 @@ extension EmailValidator on String { style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 17, letterSpacing: -0.68, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); - Widget toText18({Color? color, bool isBold = false}) => Text( + Widget toText18({Color? color, bool isBold = false, bool isCentered = false}) => Text( this, + textAlign: isCentered ? TextAlign.center : null, style: TextStyle(fontSize: 18, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.08), ); diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 2f7efcc..1d28232 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -490,5 +490,11 @@ abstract class LocaleKeys { static const yourAnswerCorrect = 'yourAnswerCorrect'; static const youMissedTheQuestion = 'youMissedTheQuestion'; static const wrongAnswer = 'wrongAnswer'; + static const oops = 'oops'; + static const winner = 'winner'; + static const youWantToLeaveMarathon = 'youWantToLeaveMarathon'; + static const ourSponsor = 'ourSponsor'; + static const startingIn = 'startingIn'; + static const youAreOutOfContest = 'youAreOutOfContest'; } diff --git a/lib/main.dart b/lib/main.dart index 4d686b8..4709be1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,11 +3,11 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; -import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/generated/codegen_loader.g.dart'; import 'package:mohem_flutter_app/models/post_params_model.dart'; +import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/provider/eit_provider_model.dart'; import 'package:mohem_flutter_app/theme/app_theme.dart'; @@ -92,6 +92,7 @@ class MyApp extends StatelessWidget { MonthYearPickerLocalizations.delegate, ); return MaterialApp( + navigatorKey: AppRoutes.navigatorKey, builder: (BuildContext context, Widget? child) { return MediaQuery( data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), @@ -249,3 +250,4 @@ class MyApp extends StatelessWidget { // }); // } // } + diff --git a/lib/models/marathon/marathon_model.dart b/lib/models/marathon/marathon_model.dart index b32530c..6fd1f5c 100644 --- a/lib/models/marathon/marathon_model.dart +++ b/lib/models/marathon/marathon_model.dart @@ -126,10 +126,10 @@ class Projects { class Sponsors { String? id; String? nameEn; - Null? nameAr; + String? nameAr; String? image; - Null? video; - Null? logo; + String? video; + String? logo; List? sponsorPrizes; Sponsors( @@ -186,7 +186,7 @@ class SponsorPrizes { } Map toJson() { - Map data = new Map(); + Map data = {}; data['id'] = id; data['marathonPrizeEn'] = marathonPrizeEn; data['marathonPrizeAr'] = marathonPrizeAr; diff --git a/lib/models/marathon/question_model.dart b/lib/models/marathon/question_model.dart index 0bb42cd..4501947 100644 --- a/lib/models/marathon/question_model.dart +++ b/lib/models/marathon/question_model.dart @@ -14,6 +14,7 @@ class QuestionModel { String? gapText; String? gapImage; int? questOptionsLimit; + int? remainingParticipantCount; List? questionOptions; QuestionModel({ @@ -28,6 +29,7 @@ class QuestionModel { String? gapText, String? gapImage, int? questOptionsLimit, + int? remainingParticipantCount, List? questionOptions, }); @@ -43,6 +45,7 @@ class QuestionModel { gapText = json['gapText']; gapImage = json['gapImage']; questOptionsLimit = json['questOptionsLimit']; + remainingParticipantCount = json['remainingParticipantCount']; if (json['questionOptions'] != null) { questionOptions = []; json['questionOptions'].forEach((v) { @@ -64,6 +67,7 @@ class QuestionModel { data['gapText'] = gapText; data['gapImage'] = gapImage; data['questOptionsLimit'] = questOptionsLimit; + data['remainingParticipantCount'] = remainingParticipantCount; if (questionOptions != null) { data['questionOptions'] = questionOptions!.map((v) => v.toJson()).toList(); } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index f06a405..4e6988b 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -6,7 +6,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; @@ -322,9 +321,11 @@ class _DashboardScreenState extends State { ), ], ).paddingOnly(left: 21, right: 21, top: 7), - context.watch().isLoading ? MarathonBannerShimmer().paddingAll(20) : MarathonBanner().paddingAll(20), + context.watch().isLoading + ? const MarathonBannerShimmer().paddingAll(20) + : MarathonBanner(isMarathonUpcoming: context.watch().isUpComingMarathon).paddingAll(20), ServicesWidget(), - // 8.height, + 8.height, Container( width: double.infinity, padding: const EdgeInsets.only(top: 31), diff --git a/lib/ui/landing/widget/app_drawer.dart b/lib/ui/landing/widget/app_drawer.dart index ac70035..4160fde 100644 --- a/lib/ui/landing/widget/app_drawer.dart +++ b/lib/ui/landing/widget/app_drawer.dart @@ -69,28 +69,28 @@ class _AppDrawerState extends State { ).expanded ], ).paddingOnly(left: 14, right: 14, top: 21, bottom: 21), - Row( - children: [ - Row( - children: [ - LocaleKeys.english.tr().toText14(color: AppState().isArabic(context) ? null : MyColors.textMixColor).onPress(() { - context.setLocale(const Locale("en", "US")); - postLanguageChange(context); - }), - Container( - width: 1, - color: MyColors.darkWhiteColor, - height: 16, - margin: const EdgeInsets.only(left: 10, right: 10), - ), - LocaleKeys.arabic.tr().toText14(color: !AppState().isArabic(context) ? null : MyColors.textMixColor).onPress(() { - context.setLocale(const Locale("ar", "SA")); - postLanguageChange(context); - }), - ], - ), - ], - ).paddingOnly(left: 14, right: 14, bottom: 14), + // Row( + // children: [ + // Row( + // children: [ + // LocaleKeys.english.tr().toText14(color: AppState().isArabic(context) ? null : MyColors.textMixColor).onPress(() { + // context.setLocale(const Locale("en", "US")); + // postLanguageChange(context); + // }), + // Container( + // width: 1, + // color: MyColors.darkWhiteColor, + // height: 16, + // margin: const EdgeInsets.only(left: 10, right: 10), + // ), + // LocaleKeys.arabic.tr().toText14(color: !AppState().isArabic(context) ? null : MyColors.textMixColor).onPress(() { + // context.setLocale(const Locale("ar", "SA")); + // postLanguageChange(context); + // }), + // ], + // ), + // ], + // ).paddingOnly(left: 14, right: 14, bottom: 14), const Divider( height: 1, thickness: 1, diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index e6b4838..e225459 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -143,8 +143,8 @@ class _LoginScreenState extends State { isAppOpenBySystem = (ModalRoute.of(context)!.settings.arguments ?? true) as bool; if (!kReleaseMode) { // username.text = "15444"; // Maha User - username.text = "15153"; // Tamer User - password.text = "Abcd@1234"; + // username.text = "15153"; // Tamer User + // password.text = "Abcd@1234"; // username.text = "206535"; // Hashim User // password.text = "Namira786"; diff --git a/lib/ui/marathon/marathon_intro_screen.dart b/lib/ui/marathon/marathon_intro_screen.dart index d85a82f..f47b47e 100644 --- a/lib/ui/marathon/marathon_intro_screen.dart +++ b/lib/ui/marathon/marathon_intro_screen.dart @@ -1,21 +1,13 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:lottie/lottie.dart'; -import 'package:mohem_flutter_app/app_state/app_state.dart'; -import 'package:mohem_flutter_app/classes/colors.dart'; -import 'package:mohem_flutter_app/classes/date_uitl.dart'; -import 'package:mohem_flutter_app/classes/decorations_helper.dart'; -import 'package:mohem_flutter_app/classes/lottie_consts.dart'; -import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; -import 'package:mohem_flutter_app/extensions/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/ui/marathon/marathon_provider.dart'; -import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_details_card.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_footer.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_timer_card.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; -import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:provider/provider.dart'; class MarathonIntroScreen extends StatelessWidget { @@ -33,7 +25,10 @@ class MarathonIntroScreen extends StatelessWidget { children: [ MarathonDetailsCard(provider: provider), 10.height, - MarathonTimerCard(provider: provider, timeToMarathon: DateTime.parse(provider.marathonDetailModel.startTime!).millisecondsSinceEpoch,), + MarathonTimerCard( + provider: provider, + timeToMarathon: DateTime.parse(provider.marathonDetailModel.startTime!).millisecondsSinceEpoch, + ), ], ).expanded, 1.divider, @@ -43,180 +38,3 @@ class MarathonIntroScreen extends StatelessWidget { ); } } - -class MarathonDetailsCard extends StatelessWidget { - final MarathonProvider provider; - - const MarathonDetailsCard({Key? key, required this.provider}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - width: double.infinity, - decoration: MyDecorations.shadowDecoration, - padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 14), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.contestTopicAbout.tr().toText16(color: MyColors.grey77Color), - "${AppState().isArabic(context) ? provider.marathonDetailModel.titleAr : provider.marathonDetailModel.titleEn}".toText20(color: MyColors.textMixColor, isBold: true), - Row( - children: [ - Flexible( - child: "${AppState().isArabic(context) ? provider.marathonDetailModel.descAr : provider.marathonDetailModel.descEn}".toText14(color: MyColors.grey77Color), - ) - ], - ), - if (provider.itsMarathonTime && provider.marathonDetailModel.sponsors != null) ...[ - 5.height, - provider.marathonDetailModel.sponsors?.first.sponsorPrizes != null - ? Row( - children: [ - "${LocaleKeys.prize.tr()} ".toText16(color: MyColors.grey77Color, isBold: true), - "${AppState().isArabic(context) ? provider.marathonDetailModel.sponsors?.first.sponsorPrizes?.first.marathonPrizeAr : provider.marathonDetailModel.sponsors?.first.sponsorPrizes?.first.marathonPrizeAr}" - .toText16(color: MyColors.greenColor, isBold: true), - ], - ) - : const SizedBox(), - Row( - children: [ - "${LocaleKeys.sponsoredBy.tr()} ".toText16(color: MyColors.grey77Color), - "${AppState().isArabic(context) ? provider.marathonDetailModel.sponsors?.first.nameAr : provider.marathonDetailModel.sponsors?.first.nameEn}" - .toText16(color: MyColors.darkTextColor, isBold: true), - ], - ), - 10.height, - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.network( - provider.marathonDetailModel.sponsors!.first.image!, - height: 40, - width: 150, - fit: BoxFit.fill, - errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { - return const Center(); - }, - ) - ], - ), - ] - ], - ), - ], - ), - ); - } -} - -class MarathonTimerCard extends StatelessWidget { - final int timeToMarathon; - final MarathonProvider provider; - - const MarathonTimerCard({ - Key? key, - required this.provider, - required this.timeToMarathon, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - width: double.infinity, - decoration: MyDecorations.shadowDecoration, - padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 14), - child: Column( - children: [ - Row( - children: [ - "${LocaleKeys.gameDate.tr()} ".toText16(color: MyColors.grey77Color), - DateUtil.getMonthDayYearDateFormatted(DateTime.parse(provider.marathonDetailModel.startTime!)).toText16(color: MyColors.darkTextColor, isBold: true), - ], - ), - Row( - children: [ - "${LocaleKeys.gameTime.tr()} ".toText16(color: MyColors.grey77Color), - DateUtil.formatDateToTimeLang(DateTime.parse(provider.marathonDetailModel.startTime!), AppState().isArabic(context)).toText16(color: MyColors.darkTextColor, isBold: true), - ], - ), - Lottie.asset(MyLottieConsts.hourGlassLottie, height: 200), - BuildCountdownTimer(timeToMarathon: timeToMarathon, provider: provider, screenFlag: 1), - ], - ), - ); - } -} - -class MarathonFooter extends StatelessWidget { - final MarathonProvider provider; - - const MarathonFooter({ - Key? key, - required this.provider, - }) : super(key: key); - - Widget buildNoteForDemo() { - return RichText( - text: TextSpan( - children: [ - TextSpan( - text: LocaleKeys.note.tr(), - style: const TextStyle(color: MyColors.darkTextColor, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.bold), - ), - TextSpan( - text: " " + LocaleKeys.demoMarathonNoteP1.tr(), - style: const TextStyle(color: MyColors.grey77Color, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.w500), - ), - TextSpan( - text: " " + LocaleKeys.demoMarathonNoteP2.tr(), - style: const TextStyle(color: MyColors.darkTextColor, fontSize: 17, fontWeight: FontWeight.bold), - ), - TextSpan( - text: " " + LocaleKeys.demoMarathonNoteP3.tr(), - style: const TextStyle(color: MyColors.grey77Color, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.w500), - ) - ], - ), - ).paddingOnly(right: 21, left: 21, top: 11, bottom: 0); - } - - @override - Widget build(BuildContext context) { - return !provider.itsMarathonTime - ? DefaultButton( - LocaleKeys.joinMarathon.tr(), - () async { - Utils.showLoading(context); - try { - provider.resetValues(); - await provider.connectSignalrAndJoinMarathon(context); - } catch (e, s) { - Utils.confirmDialog(context, e.toString()); - print(s); - } - Utils.hideLoading(context); - Navigator.pushNamed(context, AppRoutes.marathonScreen); - }, - ).insideContainer - : Container( - color: Colors.white, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - buildNoteForDemo(), - DefaultButton( - LocaleKeys.joinDemoMarathon.tr(), - () { - provider.connectSignalrAndJoinMarathon(context); - }, - color: MyColors.yellowColorII, - ).insideContainer, - ], - ), - ); - } -} diff --git a/lib/ui/marathon/marathon_provider.dart b/lib/ui/marathon/marathon_provider.dart index b629b36..1cf8efd 100644 --- a/lib/ui/marathon/marathon_provider.dart +++ b/lib/ui/marathon/marathon_provider.dart @@ -2,62 +2,46 @@ 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/classes/utils.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/models/marathon/marathon_model.dart'; import 'package:mohem_flutter_app/models/marathon/question_model.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; +import 'package:video_player/video_player.dart'; class MarathonProvider extends ChangeNotifier { + //****************VARIABLES********** + final AppinioSwiperController swiperController = AppinioSwiperController(); MarathonDetailModel marathonDetailModel = MarathonDetailModel(); List cardContentList = []; QuestionModel currentQuestion = QuestionModel(); - + List answerStatusesList = []; QuestionCardStatus questionCardStatus = QuestionCardStatus.question; int? selectedOptionIndex; - int currentQuestionTime = 0; - - void onNewQuestionReceived(QuestionModel newQuestion) { - if (currentQuestionNumber > 0) { - swipeCardLeft(); - } - selectedOptionIndex = null; - currentQuestionNumber++; - currentQuestion = newQuestion; - cardContentList.add(const CardContent()); - currentQuestionTime = newQuestion.questionTime!; - questionCardStatus = QuestionCardStatus.question; - notifyListeners(); - } + String? selectedOptionId; + int totalQualifiers = 0; - void addItemToList(CardContent value) { - cardContentList.add(value); - notifyListeners(); - } + bool _isLoading = false; - void updateCurrentQuestionOptionStatus(QuestionsOptionStatus status, int index) { - for (int i = 0; i < currentQuestion.questionOptions!.length; i++) { - currentQuestion.questionOptions![i].optionStatus = QuestionsOptionStatus.unSelected; - } - currentQuestion.questionOptions![index].optionStatus = status; - selectedOptionIndex = index; - notifyListeners(); - } + bool get isLoading => _isLoading; - void updateQuestionCardStatus(QuestionCardStatus status) { - questionCardStatus = status; + set isLoading(bool value) { + _isLoading = value; notifyListeners(); } - bool _isLoading = false; + bool _isUpComingMarathon = true; - bool get isLoading => _isLoading; + bool get isUpComingMarathon => _isUpComingMarathon; - set isLoading(bool value) { - _isLoading = value; + set isUpComingMarathon(bool value) { + _isUpComingMarathon = value; notifyListeners(); } @@ -79,6 +63,13 @@ class MarathonProvider extends ChangeNotifier { notifyListeners(); } + bool isUserOutOfGame = false; + + set updateIsUserOutOfGame(bool value) { + isUserOutOfGame = value; + notifyListeners(); + } + int _currentQuestionNumber = 0; int get currentQuestionNumber => _currentQuestionNumber; @@ -88,7 +79,7 @@ class MarathonProvider extends ChangeNotifier { notifyListeners(); } - int _totalMarathoners = 23; + int _totalMarathoners = 0; int get totalMarathoners => _totalMarathoners; @@ -97,8 +88,202 @@ class MarathonProvider extends ChangeNotifier { notifyListeners(); } - void swipeCardLeft() { - swiperController.swipeLeft(); + //****************SPONSOR VIDEO PLAYER********** + + late VideoPlayerController videoController; + + Future initializeVideoPlayer() async { + // videoController = VideoPlayerController.network(marathonDetailModel.sponsors!.first.video!)..initialize(); + videoController = VideoPlayerController.network("http://clips.vorwaerts-gmbh.de/VfE_html5.mp4"); + await videoController.initialize(); + await videoController.play(); + await videoController.setVolume(1.0); + await videoController.setLooping(false); + totalSponsorVideoSeconds = videoController.value.duration.inSeconds; + notifyListeners(); + } + + void disposeVideoPlayer() { + videoController.dispose(); + notifyListeners(); + } + + //****************TIMERS********** + + int totalSponsorVideoSeconds = 0; + Timer timerForSponsorVideo = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); + + void startTimerForSponsorVideo() { + const Duration oneSec = Duration(seconds: 1); + timerForSponsorVideo = Timer.periodic( + oneSec, + (Timer timer) async { + if (totalSponsorVideoSeconds == 0) { + timer.cancel(); + notifyListeners(); + return; + } else { + totalSponsorVideoSeconds--; + } + + notifyListeners(); + }, + ); + } + + int totalSecondsToWaitForMarathon = 20; + Timer timerToWaitForMarathon = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); + + void startTimerToMarathon(BuildContext context) { + const Duration oneSec = Duration(seconds: 1); + timerToWaitForMarathon = Timer.periodic( + oneSec, + (Timer timer) async { + if (totalSecondsToWaitForMarathon == 0) { + } else { + totalSecondsToWaitForMarathon--; + } + notifyListeners(); + }, + ); + } + + int totalCurrentQuestionTime = 0; + int currentGapTime = 0; + Timer timerForQuestion = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); + + void startTimerForQuestion() { + const Duration oneSec = Duration(seconds: 1); + 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 + if (totalCurrentQuestionTime - currentGapTime == currentQuestion.questionTime! - 2) { + getCorrectAnswerAndUpdateAnswerColor(); + } + + if (totalCurrentQuestionTime == currentGapTime) { + updateCardStatusToAnswer(); + + await callSubmitOptionApi().then((bool value) async { + if (value) { + await callNextQuestionApi(); + } + }); + } + + if (totalCurrentQuestionTime == 0) { + updateCardData(); + if (currentQuestionNumber == marathonDetailModel.totalQuestions! - 1) { + updateQuestionCardStatus(QuestionCardStatus.findingWinner); + timer.cancel(); + cancelTimer(); + notifyListeners(); + } + return; + } else { + totalCurrentQuestionTime--; + } + + notifyListeners(); + }, + ); + } + + int totalSecondsToWaitForWinner = 30; + Timer timerForWinnerSelection = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); + + void startTimerForWinnerSelection() { + const Duration oneSec = Duration(seconds: 1); + timerForWinnerSelection = Timer.periodic( + oneSec, + (Timer timer) async { + if (totalSecondsToWaitForWinner == 0) { + timer.cancel(); + updateQuestionCardStatus(QuestionCardStatus.winnerFound); + return; + } else { + totalSecondsToWaitForWinner--; + } + + notifyListeners(); + }, + ); + } + + //****************FUNCTIONS********* + + Future callSubmitOptionApi() async { + return await MarathonApiClient().submitSelectedOption(selectedAnswerId: selectedOptionId); + } + + // TODO: here I need to add a logic where I should call this function for Api but for the 1st question it should behave differently + // TODO: Verify the callings!!! + Future callNextQuestionApi() async { + if (currentQuestionNumber < marathonDetailModel.totalQuestions!) { + if (currentQuestionNumber == 0) { + currentQuestion = (await MarathonApiClient().getNextQuestion(questionId: null, marathonId: marathonDetailModel.id!))!; + if (Utils.isLoading) { + Utils.hideLoading(AppRoutes.navigatorKey.currentContext!); + } + startTimerForQuestion(); + updateCardData(); + + Navigator.pushReplacementNamed(AppRoutes.navigatorKey.currentContext!, AppRoutes.marathonScreen); + } else { + currentQuestion = (await MarathonApiClient().getNextQuestion(questionId: currentQuestion.id, marathonId: marathonDetailModel.id!))!; + } + notifyListeners(); + } + } + + void updateCardData() { + if (currentQuestionNumber > 0) { + print("swiped it away!!"); + swipeCardLeft(); + } + selectedOptionIndex = null; + currentQuestionNumber++; + cardContentList.add(const CardContent()); + totalCurrentQuestionTime = currentQuestion.questionTime! + currentQuestion.nextQuestGap!; + currentGapTime = currentQuestion.nextQuestGap!; + totalMarathoners = currentQuestion.remainingParticipantCount!; + questionCardStatus = QuestionCardStatus.question; + } + + void populateQuestionStatusesList() { + if (marathonDetailModel.totalQuestions != null) { + for (int i = 0; i < marathonDetailModel.totalQuestions! - 1; i++) { + answerStatusesList.add(QuestionCardStatus.question); + } + notifyListeners(); + } + } + + void updateAnswerStatusesList(QuestionCardStatus status) { + answerStatusesList[currentQuestionNumber - 1] = status; + notifyListeners(); + } + + void addItemToList(CardContent value) { + cardContentList.add(value); + notifyListeners(); + } + + void updateCurrentQuestionOptionStatus(QuestionsOptionStatus status, int index) { + for (int i = 0; i < currentQuestion.questionOptions!.length; i++) { + currentQuestion.questionOptions![i].optionStatus = QuestionsOptionStatus.unSelected; + } + currentQuestion.questionOptions![index].optionStatus = status; + selectedOptionIndex = index; + notifyListeners(); + } + + void updateQuestionCardStatus(QuestionCardStatus status) { + if (status == QuestionCardStatus.wrongAnswer || status == QuestionCardStatus.skippedAnswer) { + updateIsUserOutOfGame = true; + } + questionCardStatus = status; notifyListeners(); } @@ -120,59 +305,36 @@ class MarathonProvider extends ChangeNotifier { if (selectedOptionIndex != null) { if (currentQuestion.questionOptions![selectedOptionIndex!].isCorrectOption!) { updateQuestionCardStatus(QuestionCardStatus.correctAnswer); + updateAnswerStatusesList(QuestionCardStatus.correctAnswer); } else { updateQuestionCardStatus(QuestionCardStatus.wrongAnswer); + updateAnswerStatusesList(QuestionCardStatus.wrongAnswer); } } else { updateQuestionCardStatus(QuestionCardStatus.skippedAnswer); + updateAnswerStatusesList(QuestionCardStatus.skippedAnswer); } } - Timer timerU = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); - - void startTimer(BuildContext context) { - const Duration oneSec = Duration(seconds: 1); - timerU = Timer.periodic( - oneSec, - (Timer timer) async { - if (currentQuestionTime == 2) { - getCorrectAnswerAndUpdateAnswerColor(); - } - if (currentQuestionTime == 0) { - updateCardStatusToAnswer(); - // if (currentQuestionNumber == 9) { - // timer.cancel(); - // cancelTimer(); - // isMarathonCompleted = true; - // await Future.delayed(const Duration(seconds: 2)).whenComplete( - // () => Navigator.pushReplacementNamed(context, AppRoutes.marathonWinnerSelection), - // ); - // - // resetValues(); - // - // return; - // } - // timer.cancel(); - } else { - currentQuestionTime--; - } - notifyListeners(); - }, - ); + void swipeCardLeft() { + swiperController.swipeLeft(); + notifyListeners(); } - void resetValues() { + void resetValues() async { _currentQuestionNumber = 0; cardContentList.clear(); - timerU.cancel(); + timerForWinnerSelection.cancel(); + timerForQuestion.cancel(); _isMarathonCompleted = false; - currentQuestionTime = 0; + totalCurrentQuestionTime = 0; currentQuestion = QuestionModel(); + notifyListeners(); } void cancelTimer() { - timerU.cancel(); + timerForQuestion.cancel(); notifyListeners(); } @@ -181,12 +343,51 @@ class MarathonProvider extends ChangeNotifier { notifyListeners(); await MarathonApiClient().getMarathonToken().whenComplete(() async { marathonDetailModel = await MarathonApiClient().getMarathonDetails(); + if (marathonDetailModel.id == null) { + isUpComingMarathon = false; + notifyListeners(); + return; + } + populateQuestionStatusesList(); isLoading = false; notifyListeners(); }); } - Future connectSignalrAndJoinMarathon(BuildContext context) async { - await MarathonApiClient().buildHubConnection(context); + Future buildConnectionWithSignalR(BuildContext context) async { + Utils.showLoading(context); + try { + resetValues(); + // await MarathonApiClient().buildHubConnection(context, marathonDetailModel.sponsors!.first.sponsorPrizes!.first.id!); + } catch (e) { + if (kDebugMode) { + print("error in buildConnectionWithSignalR: ${e.toString()}"); + } + Utils.hideLoading(context); + Utils.confirmDialog(context, e.toString()); + } + } + + Future onJoinMarathonPressed(BuildContext context) async { + //TODO: here we need to put a check to make sure we should not display sponsor when remaining time to marathon is less than 30 seconds plus video duration e.g. 30 seconds + video duration time + // if (marathonDetailModel.sponsors!.first.video != null && marathonDetailModel.sponsors!.first.video != "") { + if (false) { + await initializeVideoPlayer().then((_) { + startTimerForSponsorVideo(); + Navigator.pushNamed(context, AppRoutes.marathonSponsorVideoScreen); + }); + } else { + try { + Utils.showLoading(context); + bool isJoined = await MarathonApiClient().joinMarathonAsParticipant(); + if (isJoined) { + print("joined"); + callNextQuestionApi(); + } + } catch (e, s) { + Utils.hideLoading(context); + Utils.confirmDialog(context, e.toString()); + } + } } } diff --git a/lib/ui/marathon/marathon_screen.dart b/lib/ui/marathon/marathon_screen.dart index 79d61fe..e14f8c9 100644 --- a/lib/ui/marathon/marathon_screen.dart +++ b/lib/ui/marathon/marathon_screen.dart @@ -2,16 +2,22 @@ import 'dart:async'; 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/app_state/app_state.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/classes/utils.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/models/marathon/question_model.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/custom_status_widget.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_progress_container.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_qualifiers_container.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/question_card_builder.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; @@ -20,46 +26,164 @@ import 'package:provider/provider.dart'; class MarathonScreen extends StatelessWidget { const MarathonScreen({Key? key}) : super(key: key); + Widget getSuccessWidget({required int? gapType, required String? gapImage, required String? gapText}) { + if (gapType == 1) { + if (gapText == null) { + return Image.asset(MyLottieConsts.congratsGif, height: 200); + } + return gapText.toText18(color: MyColors.darkTextColor, isCentered: true); + } + if (gapType == 2) { + if (gapImage == null) { + return Image.asset(MyLottieConsts.congratsGif, height: 200); + } + return Image.network(gapImage, height: 200); + } + return Image.asset(MyLottieConsts.congratsGif, height: 200); + } + + Widget getWinnerWidget(BuildContext context, {required MarathonProvider provider}) { + return Container( + width: double.infinity, + decoration: MyDecorations.shadowDecoration, + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: 200, + child: Stack( + children: [ + 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: LocaleKeys.winner.tr().toText32(color: MyColors.white, isBold: true).paddingOnly(top: 07), + ) + ], + ), + ), + 12.height, + "Muhammad Shrouff".toText22(color: MyColors.grey3AColor), + "837436".toText22(color: MyColors.grey57Color), + 80.height, + if (provider.marathonDetailModel.sponsors != null && provider.marathonDetailModel.sponsors!.isNotEmpty) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + "${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( + provider.marathonDetailModel.sponsors!.first.image!, + height: 40, + width: 150, + fit: BoxFit.fill, + errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { + return const Center(); + }, + ) + ], + ], + ), + ); + } + + Widget getNameContainer(BuildContext context) { + return Container( + height: 50, + padding: const EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: MyColors.greenColor, + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + (AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr!) + .toText17(isBold: true, color: MyColors.white), + AppState().memberInformationList!.eMPLOYEENUMBER!.toText17(isBold: true, color: MyColors.white), + ], + ), + ).paddingOnly(left: 20, right: 20, top: 12, bottom: 20); + } + @override Widget build(BuildContext context) { MarathonProvider provider = context.watch(); return WillPopScope( child: Scaffold( - appBar: AppBarWidget(context, title: LocaleKeys.brainMarathon.tr()), + appBar: AppBarWidget( + context, + title: LocaleKeys.brainMarathon.tr(), + onHomeTapped: () { + Utils.confirmDialog(context, LocaleKeys.youWantToLeaveMarathon.tr()); + }, + onBackTapped: () { + Utils.confirmDialog(context, LocaleKeys.youWantToLeaveMarathon.tr()); + }, + ), body: SingleChildScrollView( child: Column( children: [ 20.height, - MarathonProgressContainer(provider: provider).paddingOnly(left: 21, right: 21), + if (provider.questionCardStatus == QuestionCardStatus.findingWinner) ...[ + QualifiersContainer(provider: provider).paddingOnly(left: 21, right: 21), + ] else if (provider.questionCardStatus == QuestionCardStatus.winnerFound) + ...[] + else ...[ + MarathonProgressContainer(provider: provider).paddingOnly(left: 21, right: 21), + ], + if (provider.questionCardStatus == QuestionCardStatus.findingWinner) ...[ + getNameContainer(context), + ], QuestionCardBuilder( onQuestion: (BuildContext context) => QuestionCard(provider: provider), onCompleted: (BuildContext context) => CustomStatusWidget( asset: Lottie.asset(MyLottieConsts.allQuestions, height: 200), title: LocaleKeys.congrats.tr().toText22(color: MyColors.greenColor), - subTitle: LocaleKeys.allQuestionsCorrect.toText18(color: MyColors.darkTextColor), + subTitle: LocaleKeys.allQuestionsCorrect.toText18(color: MyColors.darkTextColor, isCentered: true), ), onCorrectAnswer: (BuildContext context) => CustomStatusWidget( - asset: Lottie.asset(MyLottieConsts.allQuestions, height: 200), + asset: getSuccessWidget(gapType: provider.currentQuestion.gapType, gapImage: provider.currentQuestion.gapImage, gapText: provider.currentQuestion.gapText), title: LocaleKeys.congrats.tr().toText22(color: MyColors.greenColor), - subTitle: LocaleKeys.yourAnswerCorrect.toText18(color: MyColors.darkTextColor), + subTitle: LocaleKeys.yourAnswerCorrect.toText18(color: MyColors.darkTextColor, isCentered: true), ), - onWinner: (BuildContext context) => QuestionCard(provider: provider), + onWinner: (BuildContext context) => getWinnerWidget(context, provider: provider), onWrongAnswer: (BuildContext context) => CustomStatusWidget( asset: Image.asset(MyLottieConsts.wrongAnswerGif, height: 200), - title: const Text(""), - subTitle: LocaleKeys.wrongAnswer.tr().toText18(color: MyColors.darkTextColor), + title: LocaleKeys.oops.tr().toText22(color: MyColors.redColor), + subTitle: LocaleKeys.wrongAnswer.tr().toText18(color: MyColors.darkTextColor, isCentered: true), ), onSkippedAnswer: (BuildContext context) => CustomStatusWidget( asset: Image.asset(MyLottieConsts.wrongAnswerGif, height: 200), - title: const Text(""), - subTitle: LocaleKeys.youMissedTheQuestion.tr().toText18(color: MyColors.darkTextColor), + title: LocaleKeys.oops.tr().toText22(color: MyColors.redColor), + subTitle: LocaleKeys.youMissedTheQuestion.tr().toText18(color: MyColors.darkTextColor, isCentered: true), ), - questionCardStatus: provider.questionCardStatus, onFindingWinner: (BuildContext context) => CustomStatusWidget( asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168), title: LocaleKeys.fingersCrossed.tr().toText22(color: MyColors.greenColor), - subTitle: LocaleKeys.winnerSelectedRandomly.tr().toText18(color: MyColors.darkTextColor), + subTitle: LocaleKeys.winnerSelectedRandomly.tr().toText18(color: MyColors.darkTextColor, isCentered: true), ), + questionCardStatus: provider.questionCardStatus, ).paddingOnly(top: 12, left: 21, right: 21), ], ), @@ -72,127 +196,3 @@ class MarathonScreen extends StatelessWidget { ); } } - -class MarathonProgressContainer extends StatefulWidget { - final MarathonProvider provider; - - const MarathonProgressContainer({Key? key, required this.provider}) : super(key: key); - - @override - State createState() => _MarathonProgressContainerState(); -} - -class _MarathonProgressContainerState extends State { - @override - void initState() { - scheduleMicrotask(() { - widget.provider.startTimer(context); - }); - super.initState(); - } - - @override - void dispose() { - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Container( - width: double.infinity, - decoration: MyDecorations.shadowDecoration, - padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 13), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - decoration: BoxDecoration(color: MyColors.greenColor, borderRadius: BorderRadius.circular(5)), - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 8), - child: "${widget.provider.currentQuestionNumber.toString()} / ${widget.provider.marathonDetailModel.totalQuestions.toString()} ${LocaleKeys.question.tr()}" - .toText12(color: MyColors.white), - ), - "${widget.provider.totalMarathoners} ${LocaleKeys.marathoners.tr()}".toText14(), - "00:${widget.provider.currentQuestionTime < 10 ? "0${widget.provider.currentQuestionTime}" : widget.provider.currentQuestionTime}" - .toText18(color: widget.provider.currentQuestionTime < 5 ? MyColors.redColor : MyColors.black), - ], - ), - 12.height, - stepper(widget.provider.currentQuestionNumber), - 8.height, - Row( - children: [ - "${((widget.provider.currentQuestionNumber / widget.provider.marathonDetailModel.totalQuestions!) * 100).toInt()}% ${LocaleKeys.completed.tr()}".toText14(), - ], - ), - ], - ), - ); - } - - Widget stepper(int value) { - return SizedBox( - width: double.infinity, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - for (int i = 0; i < 10; i++) - if (value <= i) roundContainer(MyColors.lightGreyDeColor, i != 0) else roundContainer(MyColors.greenColor, i != 0) - ], - ), - ); - } - - Widget roundContainer(Color color, bool isNeedLeftBorder) { - if (isNeedLeftBorder) { - return Row( - children: [ - Divider(thickness: 6, color: color).expanded, - Container( - width: 10, - height: 10, - decoration: BoxDecoration(shape: BoxShape.circle, color: color), - ), - ], - ).expanded; - } - - return Container( - width: 10, - height: 10, - decoration: BoxDecoration(shape: BoxShape.circle, color: color), - ); - } -} - -// InkWell( -// onTap: () { -// Navigator.pushReplacementNamed( -// context, -// AppRoutes.marathonWinnerSelection, -// ); -// }, -// child: CustomStatusWidget( -// asset: Lottie.asset( -// MyLottieConsts.allQuestions, -// height: 200, -// ), -// title: Text( -// LocaleKeys.congrats.tr(), -// style: const TextStyle( -// height: 23 / 24, -// color: MyColors.greenColor, -// fontSize: 27, -// letterSpacing: -1, -// fontWeight: FontWeight.w600, -// ), -// ), -// subTitle: Text( -// LocaleKeys.allQuestionsCorrect.tr(), -// textAlign: TextAlign.center, -// style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: MyColors.darkTextColor, letterSpacing: -1.08), -// ), -// ).paddingOnly(top: 12, left: 21, right: 21), -// ) diff --git a/lib/ui/marathon/marathon_sponsor_video_screen.dart b/lib/ui/marathon/marathon_sponsor_video_screen.dart new file mode 100644 index 0000000..c81f59b --- /dev/null +++ b/lib/ui/marathon/marathon_sponsor_video_screen.dart @@ -0,0 +1,91 @@ +import 'dart:async'; +import 'dart:ui' as ui; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; +import 'package:provider/provider.dart'; +import 'package:video_player/video_player.dart'; + +class SponsorVideoScreen extends StatelessWidget { + const SponsorVideoScreen({Key? key}) : super(key: key); + + Future onSponsorVideoClosed(BuildContext context) async { + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + MarathonProvider provider = context.watch(); + return WillPopScope( + onWillPop: () { + provider.videoController.dispose(); + return Future.value(true); + }, + child: Scaffold( + backgroundColor: MyColors.black, + body: SafeArea( + child: Stack( + children: [ + Align( + child: provider.videoController.value.isInitialized + ? AspectRatio( + aspectRatio: provider.videoController.value.aspectRatio, + child: VideoPlayer(provider.videoController), + ) + : Container(color: Colors.white), + ), + Align( + alignment: Alignment.topRight, + child: Container( + decoration: BoxDecoration( + color: MyColors.white, + shape: provider.totalSponsorVideoSeconds == 0 ? BoxShape.circle : BoxShape.rectangle, + borderRadius: provider.totalSponsorVideoSeconds == 0 ? null : BorderRadius.circular(15), + ), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 8), + child: provider.totalSponsorVideoSeconds == 0 + ? InkWell( + onTap: () { + Navigator.pop(context); + provider.videoController.dispose(); + provider.buildConnectionWithSignalR(AppRoutes.navigatorKey.currentState!.overlay!.context); + }, + child: const Icon(Icons.close, size: 12), + ) + : Directionality( + textDirection: ui.TextDirection.ltr, + child: ("${LocaleKeys.ourSponsor.tr()} ${provider.totalSponsorVideoSeconds < 10 ? "0" : ""}${provider.totalSponsorVideoSeconds}").toText12(color: MyColors.darkTextColor), + ), + ), + ).paddingOnly(top: 20, right: 18), + Align( + alignment: Alignment.topLeft, + child: InkWell( + onTap: () { + Navigator.pop(context); + provider.videoController.dispose(); + provider.buildConnectionWithSignalR(AppRoutes.navigatorKey.currentState!.overlay!.context); + }, + child: Container( + decoration: BoxDecoration(color: MyColors.white, borderRadius: BorderRadius.circular(15)), + padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 6), + child: Directionality( + textDirection: ui.TextDirection.ltr, + child: LocaleKeys.skip.tr().toText11(color: MyColors.darkTextColor), + ), + ), + ), + ).paddingOnly(top: 20, left: 18), + ], + ), + ), + ), + ); + } +} diff --git a/lib/ui/marathon/marathon_waiting_screen.dart b/lib/ui/marathon/marathon_waiting_screen.dart new file mode 100644 index 0000000..27f0c08 --- /dev/null +++ b/lib/ui/marathon/marathon_waiting_screen.dart @@ -0,0 +1,62 @@ +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/classes/utils.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/ui/marathon/marathon_provider.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:provider/provider.dart'; + +class MarathonWaitingScreen extends StatelessWidget { + const MarathonWaitingScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + MarathonProvider provider = context.watch(); + return Scaffold( + appBar: AppBarWidget( + context, + title: LocaleKeys.brainMarathon.tr(), + onHomeTapped: () { + Utils.confirmDialog(context, LocaleKeys.youWantToLeaveMarathon.tr()); + }, + onBackTapped: () { + Utils.confirmDialog(context, LocaleKeys.youWantToLeaveMarathon.tr()); + }, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: double.infinity, + margin: const EdgeInsets.all(21), + decoration: MyDecorations.shadowDecoration, + child: Stack( + children: [ + Align( + child: Lottie.asset(MyLottieConsts.marathonWaiting, height: 200), + ), + Align( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + LocaleKeys.startingIn.tr().toText16(), + "00:${provider.totalSecondsToWaitForMarathon < 10 ? "0${provider.totalSecondsToWaitForMarathon}" : provider.totalSecondsToWaitForMarathon}" + .toText18(color: provider.totalSecondsToWaitForMarathon < 5 ? MyColors.redColor : MyColors.black), + ], + ), + ), + ], + ), + ).expanded, + ], + ), + ); + } +} diff --git a/lib/ui/marathon/marathon_winner_selection.dart b/lib/ui/marathon/marathon_winner_selection.dart index 1f56801..ed49f04 100644 --- a/lib/ui/marathon/marathon_winner_selection.dart +++ b/lib/ui/marathon/marathon_winner_selection.dart @@ -1,10 +1,7 @@ -import 'dart:async'; - 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/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; @@ -13,6 +10,7 @@ import 'package:mohem_flutter_app/extensions/widget_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/custom_status_widget.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_qualifiers_container.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:provider/provider.dart'; @@ -28,7 +26,7 @@ class MarathonWinnerSelection extends StatelessWidget { child: Column( children: [ 20.height, - QualifiersContainer(provider: provider).paddingOnly(left: 21, right: 21), + QualifiersContainer(provider: provider,).paddingOnly(left: 21, right: 21), 12.height, InkWell( onTap: () { @@ -90,60 +88,3 @@ class MarathonWinnerSelection extends StatelessWidget { ); } } - -class QualifiersContainer extends StatefulWidget { - final MarathonProvider provider; - - const QualifiersContainer({Key? key, required this.provider}) : super(key: key); - - @override - State createState() => _QualifiersContainerState(); -} - -class _QualifiersContainerState extends State { - final int totalQuestions = 10; - - final int currentQuestion = 04; - - @override - void initState() { - scheduleMicrotask(() { - // widget.provider.startTimer(context); - }); - super.initState(); - } - - @override - void dispose() { - // widget.provider.cancelTimer(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Container( - width: double.infinity, - decoration: MyDecorations.shadowDecoration, - padding: const EdgeInsets.only(top: 14,left: 18,right: 14,bottom: 18), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - LocaleKeys.winnerSelection.tr().toText21(color: MyColors.grey3AColor), - // "00:${widget.provider.start < 10 ? "0${widget.provider.start}" : widget.provider.start}".toText18(color: MyColors.redColor), - ], - ), - 10.height, - Row( - children: [ - "18".toText30(color: MyColors.greenColor, isBold: true),2.width, - LocaleKeys.qualifiers.tr().toText16(color: MyColors.greenColor), - ], - ), - ], - ), - ); - } -} diff --git a/lib/ui/marathon/widgets/custom_status_widget.dart b/lib/ui/marathon/widgets/custom_status_widget.dart index 8287bb4..44b44aa 100644 --- a/lib/ui/marathon/widgets/custom_status_widget.dart +++ b/lib/ui/marathon/widgets/custom_status_widget.dart @@ -22,6 +22,7 @@ class CustomStatusWidget extends StatelessWidget { decoration: MyDecorations.shadowDecoration, padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20), child: Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ asset, 50.height, diff --git a/lib/ui/marathon/widgets/marathon_banner.dart b/lib/ui/marathon/widgets/marathon_banner.dart index e711319..d805362 100644 --- a/lib/ui/marathon/widgets/marathon_banner.dart +++ b/lib/ui/marathon/widgets/marathon_banner.dart @@ -16,7 +16,9 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer.dart'; import 'package:provider/provider.dart'; class MarathonBanner extends StatelessWidget { - const MarathonBanner({Key? key}) : super(key: key); + final bool isMarathonUpcoming; + + const MarathonBanner({Key? key, required this.isMarathonUpcoming}) : super(key: key); @override Widget build(BuildContext context) { @@ -76,7 +78,7 @@ class MarathonBanner extends StatelessWidget { height: double.infinity, ), ), - Expanded( + Expanded( flex: AppState().isArabic(context) ? 4 : 5, child: SizedBox( width: double.infinity, diff --git a/lib/ui/marathon/widgets/marathon_details_card.dart b/lib/ui/marathon/widgets/marathon_details_card.dart new file mode 100644 index 0000000..b74b78b --- /dev/null +++ b/lib/ui/marathon/widgets/marathon_details_card.dart @@ -0,0 +1,82 @@ + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/decorations_helper.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'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; + + + +class MarathonDetailsCard extends StatelessWidget { + final MarathonProvider provider; + + const MarathonDetailsCard({Key? key, required this.provider}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + decoration: MyDecorations.shadowDecoration, + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 14), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.contestTopicAbout.tr().toText16(color: MyColors.grey77Color), + "${AppState().isArabic(context) ? provider.marathonDetailModel.titleAr : provider.marathonDetailModel.titleEn}".toText20(color: MyColors.textMixColor, isBold: true), + Row( + children: [ + Flexible( + child: "${AppState().isArabic(context) ? provider.marathonDetailModel.descAr : provider.marathonDetailModel.descEn}".toText14(color: MyColors.grey77Color), + ) + ], + ), + if (provider.itsMarathonTime && provider.marathonDetailModel.sponsors != null) ...[ + 5.height, + provider.marathonDetailModel.sponsors?.first.sponsorPrizes != null + ? Row( + children: [ + "${LocaleKeys.prize.tr()} ".toText16(color: MyColors.grey77Color, isBold: true), + "${AppState().isArabic(context) ? provider.marathonDetailModel.sponsors?.first.sponsorPrizes?.first.marathonPrizeAr : provider.marathonDetailModel.sponsors?.first.sponsorPrizes?.first.marathonPrizeAr}" + .toText16(color: MyColors.greenColor, isBold: true), + ], + ) + : const SizedBox(), + Row( + children: [ + "${LocaleKeys.sponsoredBy.tr()} ".toText16(color: MyColors.grey77Color), + "${AppState().isArabic(context) ? provider.marathonDetailModel.sponsors?.first.nameAr : provider.marathonDetailModel.sponsors?.first.nameEn}" + .toText16(color: MyColors.darkTextColor, isBold: true), + ], + ), + 10.height, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.network( + provider.marathonDetailModel.sponsors!.first.image!, + height: 40, + width: 150, + fit: BoxFit.fill, + errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { + return const Center(); + }, + ) + ], + ), + ] + ], + ), + ], + ), + ); + } +} + diff --git a/lib/ui/marathon/widgets/marathon_footer.dart b/lib/ui/marathon/widgets/marathon_footer.dart new file mode 100644 index 0000000..b5083c0 --- /dev/null +++ b/lib/ui/marathon/widgets/marathon_footer.dart @@ -0,0 +1,66 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.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/ui/marathon/marathon_provider.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; + +class MarathonFooter extends StatelessWidget { + final MarathonProvider provider; + + const MarathonFooter({ + Key? key, + required this.provider, + }) : super(key: key); + + Widget buildNoteForDemo() { + return RichText( + text: TextSpan( + children: [ + TextSpan( + text: LocaleKeys.note.tr(), + style: const TextStyle(color: MyColors.darkTextColor, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.bold), + ), + TextSpan( + text: " " + LocaleKeys.demoMarathonNoteP1.tr(), + style: const TextStyle(color: MyColors.grey77Color, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.w500), + ), + TextSpan( + text: " " + LocaleKeys.demoMarathonNoteP2.tr(), + style: const TextStyle(color: MyColors.darkTextColor, fontSize: 17, fontWeight: FontWeight.bold), + ), + TextSpan( + text: " " + LocaleKeys.demoMarathonNoteP3.tr(), + style: const TextStyle(color: MyColors.grey77Color, fontSize: 17, letterSpacing: -0.64, fontWeight: FontWeight.w500), + ) + ], + ), + ).paddingOnly(right: 21, left: 21, top: 11, bottom: 0); + } + + @override + Widget build(BuildContext context) { + return DefaultButton( + LocaleKeys.joinMarathon.tr(), + !provider.itsMarathonTime ? () => provider.onJoinMarathonPressed(context) : null, + ).insideContainer; + } +} + +//Container( +// color: Colors.white, +// child: Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// buildNoteForDemo(), +// DefaultButton( +// LocaleKeys.joinDemoMarathon.tr(), +// () { +// provider.connectSignalrAndJoinMarathon(context); +// }, +// color: MyColors.yellowColorII, +// ).insideContainer, +// ], +// ), +// ); diff --git a/lib/ui/marathon/widgets/marathon_progress_container.dart b/lib/ui/marathon/widgets/marathon_progress_container.dart new file mode 100644 index 0000000..c0dae6c --- /dev/null +++ b/lib/ui/marathon/widgets/marathon_progress_container.dart @@ -0,0 +1,115 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/decorations_helper.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/models/marathon/question_model.dart'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; + +class MarathonProgressContainer extends StatelessWidget { + final MarathonProvider provider; + + const MarathonProgressContainer({Key? key, required this.provider}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + decoration: MyDecorations.shadowDecoration, + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 13), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + decoration: BoxDecoration(color: MyColors.greenColor, borderRadius: BorderRadius.circular(5)), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 8), + child: "${provider.currentQuestionNumber.toString()} / ${provider.marathonDetailModel.totalQuestions.toString()} ${LocaleKeys.question.tr()}".toText12(color: MyColors.white), + ), + "${provider.totalMarathoners} ${LocaleKeys.marathoners.tr()}".toText14(), + provider.questionCardStatus == QuestionCardStatus.question + ? "00:${(provider.totalCurrentQuestionTime - provider.currentGapTime) < 10 ? "0${provider.totalCurrentQuestionTime - provider.currentGapTime}" : provider.totalCurrentQuestionTime - provider.currentGapTime}" + .toText18(color: provider.totalCurrentQuestionTime - provider.currentGapTime < 5 ? MyColors.redColor : MyColors.black) + : const SizedBox(), + ], + ), + 12.height, + stepper(provider.currentQuestionNumber, provider.answerStatusesList, provider.marathonDetailModel.totalQuestions!, provider.isUserOutOfGame), + 8.height, + Row( + children: [ + "${((provider.currentQuestionNumber / provider.marathonDetailModel.totalQuestions!) * 100).toInt()}% ${LocaleKeys.completed.tr()}".toText14(), + ], + ), + ], + ), + ); + } + + Color getStepColor(QuestionCardStatus status, bool isOutOfGame) { + if (isOutOfGame) { + return MyColors.redColor; + } + switch (status) { + case QuestionCardStatus.question: + return MyColors.yellowColorII; + case QuestionCardStatus.wrongAnswer: + return MyColors.redColor; + case QuestionCardStatus.correctAnswer: + return MyColors.greenColor; + case QuestionCardStatus.skippedAnswer: + return MyColors.redColor; + case QuestionCardStatus.completed: + return MyColors.lightGreyDeColor; + case QuestionCardStatus.findingWinner: + return MyColors.lightGreyDeColor; + case QuestionCardStatus.winnerFound: + return MyColors.lightGreyDeColor; + } + } + + Widget stepper(int value, List statusesList, int totalQuestions, bool isOutOfGame) { + return SizedBox( + width: double.infinity, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + for (int i = 0; i < totalQuestions - 1; i++) + if (value <= i) + roundContainer(MyColors.lightGreyDeColor, i != 0) + else + roundContainer( + getStepColor(statusesList[i], isOutOfGame), + i != 0, + ) + ], + ), + ); + } + + Widget roundContainer(Color color, bool isNeedLeftBorder) { + if (isNeedLeftBorder) { + return Row( + children: [ + Divider(thickness: 6, color: color).expanded, + Container( + width: 10, + height: 10, + decoration: BoxDecoration(shape: BoxShape.circle, color: color), + ), + ], + ).expanded; + } + + return Container( + width: 10, + height: 10, + decoration: BoxDecoration(shape: BoxShape.circle, color: color), + ); + } +} diff --git a/lib/ui/marathon/widgets/marathon_qualifiers_container.dart b/lib/ui/marathon/widgets/marathon_qualifiers_container.dart new file mode 100644 index 0000000..0308027 --- /dev/null +++ b/lib/ui/marathon/widgets/marathon_qualifiers_container.dart @@ -0,0 +1,54 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/decorations_helper.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'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; + +class QualifiersContainer extends StatefulWidget { + final MarathonProvider provider; + + const QualifiersContainer({Key? key, required this.provider}) : super(key: key); + + @override + State createState() => _QualifiersContainerState(); +} + +class _QualifiersContainerState extends State { + @override + void initState() { + widget.provider.startTimerForWinnerSelection(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + decoration: MyDecorations.shadowDecoration, + padding: const EdgeInsets.only(top: 14, left: 18, right: 14, bottom: 18), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.winnerSelection.tr().toText21(color: MyColors.grey3AColor), + "00:${widget.provider.totalSecondsToWaitForWinner < 10 ? "0${widget.provider.totalSecondsToWaitForWinner}" : widget.provider.totalSecondsToWaitForWinner}".toText18(color: MyColors.redColor), + ], + ), + 10.height, + Row( + children: [ + widget.provider.totalQualifiers.toString().toText30(color: MyColors.greenColor, isBold: true), + 2.width, + LocaleKeys.qualifiers.tr().toText16(color: MyColors.greenColor), + ], + ), + ], + ), + ); + } +} diff --git a/lib/ui/marathon/widgets/marathon_timer_card.dart b/lib/ui/marathon/widgets/marathon_timer_card.dart new file mode 100644 index 0000000..e831738 --- /dev/null +++ b/lib/ui/marathon/widgets/marathon_timer_card.dart @@ -0,0 +1,51 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:lottie/lottie.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.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/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'; + + +class MarathonTimerCard extends StatelessWidget { + final int timeToMarathon; + final MarathonProvider provider; + + const MarathonTimerCard({ + Key? key, + required this.provider, + required this.timeToMarathon, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + decoration: MyDecorations.shadowDecoration, + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 14), + child: Column( + children: [ + Row( + children: [ + "${LocaleKeys.gameDate.tr()} ".toText16(color: MyColors.grey77Color), + DateUtil.getMonthDayYearDateFormatted(DateTime.parse(provider.marathonDetailModel.startTime!)).toText16(color: MyColors.darkTextColor, isBold: true), + ], + ), + Row( + children: [ + "${LocaleKeys.gameTime.tr()} ".toText16(color: MyColors.grey77Color), + DateUtil.formatDateToTimeLang(DateTime.parse(provider.marathonDetailModel.startTime!), AppState().isArabic(context)).toText16(color: MyColors.darkTextColor, isBold: true), + ], + ), + Lottie.asset(MyLottieConsts.hourGlassLottie, height: 200), + BuildCountdownTimer(timeToMarathon: timeToMarathon, provider: provider, screenFlag: 1), + ], + ), + ); + } +} diff --git a/lib/ui/marathon/widgets/question_card.dart b/lib/ui/marathon/widgets/question_card.dart index af538f8..4009983 100644 --- a/lib/ui/marathon/widgets/question_card.dart +++ b/lib/ui/marathon/widgets/question_card.dart @@ -145,21 +145,32 @@ class AnswerTileForText extends StatelessWidget { const AnswerTileForText({Key? key, required this.index, required this.onAnswerTapped}) : super(key: key); + Color getAnswerTextColor(QuestionsOptionStatus status) { + switch (status) { + case QuestionsOptionStatus.correct: + return MyColors.white; + case QuestionsOptionStatus.wrong: + return MyColors.white; + case QuestionsOptionStatus.selected: + return MyColors.white; + case QuestionsOptionStatus.unSelected: + return MyColors.darkTextColor; + } + } + @override Widget build(BuildContext context) { MarathonProvider provider = context.watch(); return InkWell( onTap: () { - onAnswerTapped(); + provider.isUserOutOfGame ? null : onAnswerTapped() ; }, child: Container( alignment: Alignment.centerLeft, decoration: MyDecorations.getAnswersContainerColor(provider.currentQuestion.questionOptions![index].optionStatus!), child: Center( child: (AppState().isArabic(context) ? provider.currentQuestion.questionOptions![index].titleAr! : provider.currentQuestion.questionOptions![index].titleEn!) - .toText16( - color: provider.currentQuestion.questionOptions![index].optionStatus == QuestionsOptionStatus.unSelected ? MyColors.darkTextColor : MyColors.white, - ) + .toText16(color: provider.isUserOutOfGame ? MyColors.darkTextColor : getAnswerTextColor(provider.currentQuestion.questionOptions![index].optionStatus!)) .paddingOnly(top: 17, bottom: 17), ), ), diff --git a/lib/ui/misc/request_submit_screen.dart b/lib/ui/misc/request_submit_screen.dart index a4ffdcb..f05bacb 100644 --- a/lib/ui/misc/request_submit_screen.dart +++ b/lib/ui/misc/request_submit_screen.dart @@ -22,6 +22,7 @@ import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/button/simple_button.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; +import 'package:mohem_flutter_app/widgets/image_picker.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; class RequestSubmitScreenParams { @@ -48,6 +49,7 @@ class _RequestSubmitScreenState extends State { List approverList = []; List attachmentFiles = []; + List attachments = []; @override void initState() { @@ -72,16 +74,16 @@ class _RequestSubmitScreenState extends State { Utils.showLoading(context); List> list = []; if (attachmentFiles.isNotEmpty) { - attachmentFiles.asMap().forEach((index, value) async { - String type = value.path.split('.').last; - String name = value.path.split('/').last; - List fileContent = await value.readAsBytes(); - String encodedFile = base64Encode(fileContent); + attachments.asMap().forEach((index, value) async { + String type = attachmentFiles[index].path.split('.').last; + String name = attachmentFiles[index].path.split('/').last; + // List fileContent = await value.readAsBytes(); + // String encodedFile = base64Encode(fileContent); list.add(AttachmentModel( attachmentID: index, pFILECONTENTTYPE: type, pFILENAME: name, - pFILEDATA: encodedFile, + pFILEDATA: value, pTRANSACTIONID: params!.transactionId, ).toJson()); }); @@ -261,12 +263,18 @@ class _RequestSubmitScreenState extends State { title.toText16().expanded, 6.width, SimpleButton(LocaleKeys.add.tr(), () async { - FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true); - if (result != null) { - attachmentFiles = attachmentFiles + result.paths.map((path) => File(path!)).toList(); - attachmentFiles = attachmentFiles.toSet().toList(); - setState(() {}); - } + ImageOptions.showImageOptionsNew(context, false, (String image, File file) { + setState(() { + attachmentFiles.add(file); + attachments.add(image); + Navigator.of(context).pop(); + }); + }); + // if (result != null) { + // attachmentFiles = attachmentFiles + result.paths.map((path) => File(path!)).toList(); + // attachmentFiles = attachmentFiles.toSet().toList(); + // setState(() {}); + // } }, fontSize: 14), ], ), diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart index 72aa190..08d2be7 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart @@ -50,6 +50,18 @@ class _DynamicInputScreenState extends State { descFlexConTextTitle = genericResponseModel!.pDESCFLEXCONTEXTNAME ?? ""; getEitDffStructureList = genericResponseModel?.getEITDFFStructureList ?? []; //getEitDffStructureList = getEitDffStructureList!.where((element) => element.dISPLAYFLAG != "N").toList(); + if (dynamicParams!.collectionNotificationList != null && dynamicParams!.collectionNotificationList!.isNotEmpty) { + getEitDffStructureList!.forEach((element) { + dynamicParams!.collectionNotificationList!.forEach((element2) { + if (element.sEGMENTNAME == element2.segmentName) { + element.fieldAnswer = element2.varchar2Value; + element.eSERVICESDV ??= ESERVICESDV(); + element.eSERVICESDV!.pIDCOLUMNNAME = element2.varchar2Value; + } + }); + }); + } + Utils.hideLoading(context); setState(() {}); } catch (ex) { @@ -116,15 +128,22 @@ class _DynamicInputScreenState extends State { try { Utils.showLoading(context); for (int i = 0; i < (structureList.cHILDSEGMENTSVSSplited?.length ?? 0); i++) { + List> values = []; String segmentId = structureList.cHILDSEGMENTSVSSplited![i]; if (dESCFLEXCONTEXTCODE.isEmpty) dESCFLEXCONTEXTCODE = structureList.dESCFLEXCONTEXTCODE!; List filteredList = getEitDffStructureList?.where((element) => element.cHILDSEGMENTSVSSplited!.contains(segmentId)).toList() ?? []; - List> values = filteredList + + if (filteredList.isEmpty && structureList.cHILDSEGMENTSVSSplited!.isNotEmpty) { + segmentId = structureList.cHILDSEGMENTSVSSplited![0]; + filteredList = getEitDffStructureList?.where((element) => element.cHILDSEGMENTSVSSplited!.contains(segmentId)).toList() ?? []; + } + values = filteredList .map((e) => GetSetValuesRequestModel( sEGMENTNAME: e.sEGMENTNAME, vALUECOLUMNNAME: e.eSERVICESDV!.pVALUECOLUMNNAME, dESCRIPTION: "", iDCOLUMNNAME: e.eSERVICESDV!.pIDCOLUMNNAME, fLEXVALUESETNAME: e.fLEXVALUESETNAME) .toJson()) .toList(); + List eServicesResponseModel = await MyAttendanceApiClient().getValueSetValues(segmentId, structureList.dESCFLEXCONTEXTCODE!, structureList.dESCFLEXNAME!, values, empID: dynamicParams!.selectedEmp ?? '', parentValue: structureList.eSERVICESDV!.pVALUECOLUMNNAME); List abc = genericResponseModel?.getEITDFFStructureList ?? []; @@ -164,9 +183,28 @@ class _DynamicInputScreenState extends State { List> getSetList = getDefaultValuesIonicLogic(parent); if (getSetList.isNotEmpty) { - ESERVICESDV defaultValue = await MyAttendanceApiClient().getDefaultValue(segmentId, structureList.dESCFLEXCONTEXTCODE!, structureList.dESCFLEXNAME!, getSetList, dynamicParams!.selectedEmp); + ESERVICESDV defaultValue = + await MyAttendanceApiClient().getDefaultValue(segmentId, structureList.dESCFLEXCONTEXTCODE!, structureList.dESCFLEXNAME!, getSetList, empID: dynamicParams!.selectedEmp); int index = getEitDffStructureList!.indexWhere((element) => element.sEGMENTNAME == segmentId); getEitDffStructureList![index].eSERVICESDV = defaultValue; + GetEITDFFStructureList defaultValueCheck = getEitDffStructureList!.where((GetEITDFFStructureList element) => element.sEGMENTNAME == segmentId).toList().first; + + if (defaultValueCheck.cHILDSEGMENTSDVSplited!.isNotEmpty && defaultValueCheck.rEADONLY == 'Y') { + getDefaultValues(defaultValueCheck); + Utils.hideLoading(context); + + // GetEITDFFStructureList? parent = getEitDffStructureList!.firstWhere((element) => element.sEGMENTNAME == segmentId); + // List> getSetList = getDefaultValuesIonicLogic(parent); + // ESERVICESDV defaultValue = await MyAttendanceApiClient().getDefaultValue(segmentId, defaultValueCheck.dESCFLEXCONTEXTCODE!, defaultValueCheck.dESCFLEXNAME!, getSetList); + // int index = getEitDffStructureList!.indexWhere((element) => element.sEGMENTNAME == segmentId); + // getEitDffStructureList![index].eSERVICESDV = defaultValue; + } else if (defaultValueCheck.cHILDSEGMENTSVSSplited!.isNotEmpty && defaultValueCheck.rEADONLY == 'Y') { + calGetValueSetValues(defaultValueCheck); + Utils.hideLoading(context); + } + } else if (values.isNotEmpty) { + ESERVICESDV defaultValue = await MyAttendanceApiClient().getDefaultValue(segmentId, structureList.dESCFLEXCONTEXTCODE!, structureList.dESCFLEXNAME!, values); + int index = getEitDffStructureList!.indexWhere((element) => element.sEGMENTNAME == segmentId); } } await Future.delayed(const Duration(seconds: 1)); @@ -307,7 +345,7 @@ class _DynamicInputScreenState extends State { idColName = val; if (getEitDffStructureList![j].fORMATTYPE == "X") { - idColName = Utils.formatDateNew(idColName!); + idColName = Utils.formatDateDefault(idColName!); // commenting to test // DateTime date = DateFormat('yyyy-MM-dd').parse(idColName!); // idColName = DateFormat('yyyy-MM-dd HH:mm:ss').format(date); @@ -326,7 +364,7 @@ class _DynamicInputScreenState extends State { if (getEitDffStructureList![j].rEADONLY != "Y") { var data = getEitDffStructureList![j].eSERVICESDV; - // let x = document.getElementById(getEitDffStructureList![j].aPPLICATIONCOLUMNNAME) as HTMLSelectElement; + //let x = document.getElementById(getEitDffStructureList![j].aPPLICATIONCOLUMNNAME) as HTMLSelectElement; String? text = data?.pIDCOLUMNNAME; //x.options[x.selectedIndex] ? x.options[x.selectedIndex].text : ""; String? val = data?.pVALUECOLUMNNAME; //x.options[x.selectedIndex] ? x.options[x.selectedIndex].value : null; if ((val ?? "").isEmpty && parentsList[i].isRequired == "REQUIRED") { diff --git a/lib/ui/my_team/subordinate_leave.dart b/lib/ui/my_team/subordinate_leave.dart index f08193c..e2fb999 100644 --- a/lib/ui/my_team/subordinate_leave.dart +++ b/lib/ui/my_team/subordinate_leave.dart @@ -99,7 +99,7 @@ class _SubordinateLeaveState extends State { itemBuilder: (BuildContext context, int index) { var diffDays = DateUtil.convertStringToDate(getSubordinatesLeavesTotalList[index].dATEEND!) .difference(DateUtil.convertStringToDate(getSubordinatesLeavesTotalList[index].dATESTART!)) - .inDays; + .inDays + 1; return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/ui/profile/personal_info.dart b/lib/ui/profile/personal_info.dart index b715cdc..79d0995 100644 --- a/lib/ui/profile/personal_info.dart +++ b/lib/ui/profile/personal_info.dart @@ -43,7 +43,7 @@ class PersonalInfo extends StatelessWidget { LocaleKeys.Payroll.tr().toText13(color: MyColors.lightGrayColor), (memberInformationList.pAYROLLNAME ?? "").toText16(), ], - ).objectContainerView(center: false).paddingAll(21), + ).objectContainerView().paddingAll(21), ), ); } diff --git a/lib/ui/screens/announcements/announcements.dart b/lib/ui/screens/announcements/announcements.dart index d43c12c..941ff65 100644 --- a/lib/ui/screens/announcements/announcements.dart +++ b/lib/ui/screens/announcements/announcements.dart @@ -95,7 +95,7 @@ class _AnnouncementsState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - (AppState().isArabic(context) ? _foundAnnouncements[index].titleAR! : getAnnouncementsObject[index].titleEN!).toText13(), + (AppState().isArabic(context) ? _foundAnnouncements[index].titleAR! : _foundAnnouncements[index].titleEN!).toText13(), 8.height, _foundAnnouncements[index].created!.toText10(color: MyColors.grey98Color) ], diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index f9f8d91..da1b60f 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -528,7 +528,7 @@ class _WorkListScreenState extends State { 10.height, Row( children: [ - DateUtil.formatDateToDate(DateUtil.convertSimpleStringDateToDate(workData.bEGINDATE!), false).toText10(color: MyColors.lightTextColor).expanded, + DateUtil.formatDateToDate(DateUtil.convertSimpleStringDateToDateddMMyyyy(workData.bEGINDATE!), false).toText10(color: MyColors.lightTextColor).expanded, RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.darkIconColor)), ], ), diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 9ae62fd..8b22041 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -147,7 +147,9 @@ class _WorkListDetailScreenState extends State { getPRNotification(); } - controller.jumpToPage(0); + if (controller.hasClients) { + controller.jumpToPage(0); + } // List dataToFetch = await Future.wait([ // @@ -231,9 +233,9 @@ class _WorkListDetailScreenState extends State { ), child: Row( children: [ - myTab(LocaleKeys.info.tr(), 0), - (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") ? myTab(LocaleKeys.details.tr(), 1) : myTab(LocaleKeys.request.tr(), 1), - myTab(LocaleKeys.actions.tr(), 2), + (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") ? myTab(LocaleKeys.details.tr(), 0) : myTab(LocaleKeys.request.tr(), 0), + myTab(LocaleKeys.actions.tr(), 1), + myTab(LocaleKeys.info.tr(), 2), myTab(LocaleKeys.attachments.tr(), 3), ], ), @@ -241,25 +243,12 @@ class _WorkListDetailScreenState extends State { if ((workListData?.sUBJECT ?? "").isNotEmpty) workListData!.sUBJECT!.toText14().paddingOnly(top: 20, right: 21, left: 21), PageView( controller: controller, - onPageChanged: (int pageIndex) { + onPageChanged: (pageIndex) { setState(() { tabIndex = pageIndex; }); }, children: [ - InfoFragment( - poHeaderList: getPoNotificationBody?.pOHeader ?? [], - workListData: workListData, - itemCreationHeader: getItemCreationNtfBody?.itemCreationHeader ?? [], - getStampMsNotifications: getStampMsNotifications, - getStampNsNotifications: getStampNsNotifications, - getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList, - getPhonesNotificationBodyList: getPhonesNotificationBodyList, - getBasicDetNtfBodyList: getBasicDetNtfBodyList, - getAbsenceCollectionNotificationBodyList: getAbsenceCollectionNotificationBodyList, - getContactNotificationBodyList: getContactNotificationBodyList, - getPrNotificationBodyList: getPrNotificationBody, - ), (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") ? DetailFragment(workListData, memberInformationListModel) : RequestFragment( @@ -277,6 +266,19 @@ class _WorkListDetailScreenState extends State { voidCallback: reloadWorkList, ) : showLoadingAnimation(), + InfoFragment( + poHeaderList: getPoNotificationBody?.pOHeader ?? [], + workListData: workListData, + itemCreationHeader: getItemCreationNtfBody?.itemCreationHeader ?? [], + getStampMsNotifications: getStampMsNotifications, + getStampNsNotifications: getStampNsNotifications, + getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList, + getPhonesNotificationBodyList: getPhonesNotificationBodyList, + getBasicDetNtfBodyList: getBasicDetNtfBodyList, + getAbsenceCollectionNotificationBodyList: getAbsenceCollectionNotificationBodyList, + getContactNotificationBodyList: getContactNotificationBodyList, + getPrNotificationBodyList: getPrNotificationBody, + ), isAttachmentLoaded ? getAttachmentList.isEmpty ? Utils.getNoDataWidget(context) @@ -565,7 +567,7 @@ class _WorkListDetailScreenState extends State { Future performNetworkCall(BuildContext context, {String? email, String? userId}) async { showDialog( context: context, - builder: (BuildContext cxt) => ConfirmDialog( + builder: (cxt) => ConfirmDialog( message: LocaleKeys.wantToReject.tr(), okTitle: LocaleKeys.reject.tr(), onTap: () async { @@ -648,12 +650,12 @@ class _WorkListDetailScreenState extends State { print(actionMode); showDialog( context: context, - builder: (BuildContext cxt) => AcceptRejectInputDialog( + builder: (cxt) => AcceptRejectInputDialog( message: title != null ? null : LocaleKeys.requestedItems.tr(), title: title, notificationGetRespond: notificationNoteInput, actionMode: actionMode, - onTap: (String note) { + onTap: (note) { Map payload = { "P_ACTION_MODE": actionMode, "P_APPROVER_INDEX": null, @@ -936,9 +938,9 @@ class _WorkListDetailScreenState extends State { apiCallCount++; notificationButtonsList = await WorkListApiClient().getNotificationButtons(workListData!.nOTIFICATIONID!); if (notificationButtonsList.isNotEmpty) { - isCloseAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "CLOSE"); - isApproveAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "APPROVED"); - isRejectAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "REJECTED"); + isCloseAvailable = notificationButtonsList.any((element) => element.bUTTONACTION == "CLOSE"); + isApproveAvailable = notificationButtonsList.any((element) => element.bUTTONACTION == "APPROVED"); + isRejectAvailable = notificationButtonsList.any((element) => element.bUTTONACTION == "REJECTED"); } apiCallCount--; if (apiCallCount == 0) { diff --git a/lib/ui/work_list/worklist_fragments/detail_fragment.dart b/lib/ui/work_list/worklist_fragments/detail_fragment.dart index 43b5d7d..03e2272 100644 --- a/lib/ui/work_list/worklist_fragments/detail_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/detail_fragment.dart @@ -46,6 +46,7 @@ class _DetailFragmentState extends State { ], ).objectContainerView(), 12.height, + widget.memberInformationListModel != null ? Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, @@ -69,7 +70,7 @@ class _DetailFragmentState extends State { isItLast: true, ), ], - ).objectContainerView(), + ).objectContainerView() : Container(), ], ).paddingAll(21), ); diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 6f0d7fd..199074a 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -8,7 +8,14 @@ import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; AppBar AppBarWidget(BuildContext context, - {required String title, bool showHomeButton = true, bool showNotificationButton = false, bool showMemberButton = false, String? image, List? actions}) { + {required String title, + bool showHomeButton = true, + bool showNotificationButton = false, + bool showMemberButton = false, + String? image, + List? actions, + void Function()? onHomeTapped, + void Function()? onBackTapped}) { return AppBar( leadingWidth: 0, // leading: GestureDetector( @@ -21,7 +28,9 @@ AppBar AppBarWidget(BuildContext context, children: [ GestureDetector( behavior: HitTestBehavior.opaque, - onTap: Feedback.wrapForTap(() => Navigator.maybePop(context), context), + onTap: Feedback.wrapForTap(() { + (onBackTapped == null ? Navigator.maybePop(context) : onBackTapped()); + }, context), child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), ), 4.width, @@ -43,7 +52,7 @@ AppBar AppBarWidget(BuildContext context, if (showHomeButton) IconButton( onPressed: () { - Navigator.popUntil(context, ModalRoute.withName(AppRoutes.dashboard)); + onHomeTapped == null ? Navigator.popUntil(context, ModalRoute.withName(AppRoutes.dashboard)) : onHomeTapped(); }, icon: const Icon(Icons.home, color: MyColors.darkIconColor), ),