From cbe251829fa4137ec1a031bf8608c6210d5aec9a Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Thu, 24 Nov 2022 14:58:53 +0300 Subject: [PATCH] Added HubConnection Code --- lib/api/marathon/marathon_api_client.dart | 81 ++++++++- lib/classes/consts.dart | 6 +- lib/models/marathon/marathon_model.dart | 188 +++++++++++++++++++-- lib/ui/login/login_screen.dart | 4 +- lib/ui/marathon/marathon_intro_screen.dart | 45 ++--- lib/ui/marathon/marathon_provider.dart | 11 +- pubspec.yaml | 6 +- 7 files changed, 297 insertions(+), 44 deletions(-) diff --git a/lib/api/marathon/marathon_api_client.dart b/lib/api/marathon/marathon_api_client.dart index 1b8a435..3c111e7 100644 --- a/lib/api/marathon/marathon_api_client.dart +++ b/lib/api/marathon/marathon_api_client.dart @@ -1,18 +1,23 @@ import 'dart:convert'; 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:signalr_netcore/http_connection_options.dart'; +import 'package:signalr_netcore/hub_connection.dart'; +import 'package:signalr_netcore/hub_connection_builder.dart'; class MarathonApiClient { Future getMarathonToken() async { String employeeUserName = AppState().getUserName ?? ""; String employeeSession = AppState().postParamsObject?.pSessionId.toString() ?? ""; - Map jsonObject = {"userName": employeeUserName, "password": employeeSession}; + Map jsonObject = {"userName": employeeUserName, "password": employeeSession}; Response response = await ApiClient().postJsonForResponse(ApiConsts.marathonParticipantLoginUrl, jsonObject); var json = jsonDecode(response.body); @@ -21,8 +26,8 @@ class MarathonApiClient { if (marathonModel.statusCode == 200) { if (marathonModel.data != null && marathonModel.isSuccessful == true) { - print("bearerToken: ${marathonModel.data["token"]}"); AppState().setMarathonToken = marathonModel.data["token"] ?? ""; + print("bearer: ${AppState().getMarathonToken}"); return marathonModel.data["token"] ?? ""; } else { //TODO : DO ERROR HANDLING HERE @@ -42,7 +47,6 @@ class MarathonApiClient { if (marathonModel.statusCode == 200) { if (marathonModel.data != null && marathonModel.isSuccessful == true) { - print("projectID: ${marathonModel.data[0]["id"]}"); AppState().setMarathonProjectId = marathonModel.data[0]["id"] ?? ""; return marathonModel.data[0]["id"] ?? ""; } else { @@ -66,6 +70,77 @@ class MarathonApiClient { MarathonDetailModel marathonDetailModel = MarathonDetailModel.fromJson(marathonGenericModel.data); + AppState().setMarathonProjectId = marathonDetailModel.projects!.id!; + return marathonDetailModel; } + + late HubConnection hubConnection; + L.Logger logger = L.Logger(); + + Future buildHubConnection() 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("Hi jee"); + + await hubConnection.invoke( + "AddParticipant", + args: [ + { + "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "", + "employeeName": AppState().memberInformationList!.eMPLOYEENAME ?? "", + "marathonId": AppState().getMarathonProjectId, + } + ], + ).catchError((e) { + logger.i("Error in AddParticipant: $e"); + }); + + await hubConnection.invoke( + "SendQuestionToParticipant", + args: [ + { + "marathonId": AppState().getMarathonProjectId, + } + ], + ).catchError((e) { + logger.i("Error in SendQuestionToParticipant: $e"); + }); + + hubConnection.on("OnSendQuestionToParticipant", onSendQuestionToParticipant); + } + } + + Future onSendQuestionToParticipant(List? arguments) async { + + logger.i(arguments); + } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 6c24049..9c9045a 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -1,7 +1,7 @@ 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/"; @@ -29,7 +29,7 @@ class ApiConsts { 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 = "MarathonBroadCast"; + static String marathonHubConnectionUrl = marathonBaseUrl + "MarathonBroadCast"; } class SharedPrefsConsts { diff --git a/lib/models/marathon/marathon_model.dart b/lib/models/marathon/marathon_model.dart index e2f5e4d..3fb60b9 100644 --- a/lib/models/marathon/marathon_model.dart +++ b/lib/models/marathon/marathon_model.dart @@ -12,9 +12,9 @@ class MarathonDetailModel { int? marathoneStatusId; String? scheduleTime; int? selectedLanguage; - List? projects; - List? sponsors; - List? questions; + Projects? projects; + List? sponsors; + List? questions; MarathonDetailModel( {id, @@ -48,18 +48,25 @@ class MarathonDetailModel { marathoneStatusId = json['marathoneStatusId']; scheduleTime = json['scheduleTime']; selectedLanguage = json['selectedLanguage']; - projects = json['projects']; - sponsors = json['sponsors']; + projects = json['projects'] != null + ? Projects.fromJson(json['projects']) + : null; + if (json['sponsors'] != null) { + sponsors = []; + json['sponsors'].forEach((v) { + sponsors!.add( Sponsors.fromJson(v)); + }); + } if (json['questions'] != null) { - questions = []; + questions = []; json['questions'].forEach((v) { - // questions!.add( Null.fromJson(v)); + questions!.add( Questions.fromJson(v)); }); } } Map toJson() { - Map data = new Map(); + Map data = {}; data['id'] = id; data['titleEn'] = titleEn; data['titleAr'] = titleAr; @@ -73,11 +80,172 @@ class MarathonDetailModel { data['marathoneStatusId'] = marathoneStatusId; data['scheduleTime'] = scheduleTime; data['selectedLanguage'] = selectedLanguage; - data['projects'] = projects; - data['sponsors'] = sponsors; + if (projects != null) { + data['projects'] = projects!.toJson(); + } + if (sponsors != null) { + data['sponsors'] = sponsors!.map((v) => v.toJson()).toList(); + } if (questions != null) { data['questions'] = questions!.map((v) => v.toJson()).toList(); } return data; } } + +class Projects { + String? id; + String? nameEn; + String? nameAr; + String? projectCode; + + Projects({id, nameEn, nameAr, projectCode}); + + Projects.fromJson(Map json) { + id = json['id']; + nameEn = json['nameEn']; + nameAr = json['nameAr']; + projectCode = json['projectCode']; + } + + Map toJson() { + Map data = {}; + data['id'] = id; + data['nameEn'] = nameEn; + data['nameAr'] = nameAr; + data['projectCode'] = projectCode; + return data; + } +} + +class Sponsors { + String? id; + String? nameEn; + Null? nameAr; + String? image; + Null? video; + Null? logo; + List? sponsorPrizes; + + Sponsors( + {id, + nameEn, + nameAr, + image, + video, + logo, + sponsorPrizes}); + + Sponsors.fromJson(Map json) { + id = json['id']; + nameEn = json['nameEn']; + nameAr = json['nameAr']; + image = json['image']; + video = json['video']; + logo = json['logo']; + if (json['sponsorPrizes'] != null) { + sponsorPrizes = []; + json['sponsorPrizes'].forEach((v) { + sponsorPrizes!.add( SponsorPrizes.fromJson(v)); + }); + } + } + + Map toJson() { + Map data = {}; + data['id'] = id; + data['nameEn'] = nameEn; + data['nameAr'] = nameAr; + data['image'] = image; + data['video'] = video; + data['logo'] = logo; + if (sponsorPrizes != null) { + data['sponsorPrizes'] = + sponsorPrizes!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class SponsorPrizes { + String? id; + String? marathonPrizeEn; + String? marathonPrizeAr; + + SponsorPrizes({id, marathonPrizeEn, marathonPrizeAr}); + + SponsorPrizes.fromJson(Map json) { + id = json['id']; + marathonPrizeEn = json['marathonPrizeEn']; + marathonPrizeAr = json['marathonPrizeAr']; + } + + Map toJson() { + Map data = new Map(); + data['id'] = id; + data['marathonPrizeEn'] = marathonPrizeEn; + data['marathonPrizeAr'] = marathonPrizeAr; + return data; + } +} + +class Questions { + String? id; + String? titleEn; + String? titleAr; + String? marathonId; + int? questionTypeId; + int? questionTime; + int? nextQuestGap; + int? gapType; + String? gapValue; + String? gapImage; + int? questOptionsLimit; + List? questionOptions; + + Questions( + {id, + titleEn, + titleAr, + marathonId, + questionTypeId, + questionTime, + nextQuestGap, + gapType, + gapValue, + gapImage, + questOptionsLimit, + questionOptions}); + + Questions.fromJson(Map json) { + id = json['id']; + titleEn = json['titleEn']; + titleAr = json['titleAr']; + marathonId = json['marathonId']; + questionTypeId = json['questionTypeId']; + questionTime = json['questionTime']; + nextQuestGap = json['nextQuestGap']; + gapType = json['gapType']; + gapValue = json['gapValue']; + gapImage = json['gapImage']; + questOptionsLimit = json['questOptionsLimit']; + questionOptions = json['questionOptions']; + } + + Map toJson() { + Map data = {}; + data['id'] = id; + data['titleEn'] = titleEn; + data['titleAr'] = titleAr; + data['marathonId'] = marathonId; + data['questionTypeId'] = questionTypeId; + data['questionTime'] = questionTime; + data['nextQuestGap'] = nextQuestGap; + data['gapType'] = gapType; + data['gapValue'] = gapValue; + data['gapImage'] = gapImage; + data['questOptionsLimit'] = questOptionsLimit; + data['questionOptions'] = questionOptions; + return data; + } +} diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 20fa8bc..97282d3 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -142,8 +142,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@12345"; + username.text = "15153"; // Tamer User + password.text = "Abcd@12345"; // 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 0f655ab..edb0f77 100644 --- a/lib/ui/marathon/marathon_intro_screen.dart +++ b/lib/ui/marathon/marathon_intro_screen.dart @@ -6,7 +6,6 @@ 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/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'; @@ -78,29 +77,36 @@ class MarathonDetailsCard extends StatelessWidget { ) ], ), - if (provider.itsMarathonTime) ...[ + 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.prize.tr().toText16(color: MyColors.grey77Color, isBold: true), - " LED 55\" Android TV".toText16(color: MyColors.greenColor, isBold: true), - ], - ), - Row( - children: [ - LocaleKeys.sponsoredBy.tr().toText16(color: MyColors.grey77Color), - " Extra".toText16(color: MyColors.darkTextColor, isBold: true), + "${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.asset( - "assets/images/logos/main_mohemm_logo.png", + Image.network( + provider.marathonDetailModel.sponsors!.first.image!, height: 40, - fit: BoxFit.fill, width: 150, + fit: BoxFit.fill, + errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { + return const Center(); + }, ) ], ), @@ -123,7 +129,6 @@ class MarathonTimerCard extends StatelessWidget { required this.timeToMarathon, }) : super(key: key); - @override Widget build(BuildContext context) { return Container( @@ -214,10 +219,10 @@ class MarathonFooter extends StatelessWidget { @override Widget build(BuildContext context) { return provider.itsMarathonTime - ? DefaultButton( - LocaleKeys.joinMarathon.tr(), - () => Navigator.pushNamed(context, AppRoutes.marathonScreen), - ).insideContainer + ? DefaultButton(LocaleKeys.joinMarathon.tr(), () { + provider.connectSignalrAndJoinMarathon(); + // Navigator.pushNamed(context, AppRoutes.marathonScreen); + }, ).insideContainer : Container( color: Colors.white, child: Column( @@ -226,7 +231,9 @@ class MarathonFooter extends StatelessWidget { buildNoteForDemo(), DefaultButton( LocaleKeys.joinDemoMarathon.tr(), - () {}, + () { + provider.connectSignalrAndJoinMarathon(); + }, color: MyColors.yellowColorII, ).insideContainer, ], diff --git a/lib/ui/marathon/marathon_provider.dart b/lib/ui/marathon/marathon_provider.dart index 25642ee..50bd38b 100644 --- a/lib/ui/marathon/marathon_provider.dart +++ b/lib/ui/marathon/marathon_provider.dart @@ -114,18 +114,17 @@ class MarathonProvider extends ChangeNotifier { Future getMarathonDetailsFromApi() async { isLoading = true; - + notifyListeners(); await MarathonApiClient().getMarathonToken().whenComplete(() async { - print("loading before : $isLoading"); - marathonDetailModel = await MarathonApiClient().getMarathonDetails(); isLoading = false; - print("loading after: $isLoading"); - notifyListeners(); - }); + } + Future connectSignalrAndJoinMarathon() async { + await MarathonApiClient().buildHubConnection(); } + } diff --git a/pubspec.yaml b/pubspec.yaml index f5742bb..f898345 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -79,13 +79,17 @@ dependencies: pull_to_refresh: ^2.0.0 # lottie json animations lottie: any + + # Steps Progress steps_indicator: ^1.3.0 + # Marathon Card Swipe appinio_swiper: ^1.1.1 expandable: ^5.0.1 - +# networkImage + cached_network_image: ^3.2.2 #Chat signalr_netcore: ^1.3.3