import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart'; import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; import 'package:diplomaticquarterapp/models/course/education_journey_list_model.dart'; import 'package:diplomaticquarterapp/models/course/education_journey_model.dart'; import 'package:diplomaticquarterapp/pages/learning/question_sheet.dart'; import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; class CourseServiceProvider with ChangeNotifier { AppSharedPreferences sharedPref = AppSharedPreferences(); AppGlobal appGlobal = AppGlobal(); AuthenticatedUser authUser = AuthenticatedUser(); AuthProvider authProvider = AuthProvider(); bool isDataLoaded = false; int? selectedJourney; List? data; PatientEducationJourneyListModel? nabedJourneyResponse; PatientEducationJourneyModel? courseData; List? courseTopics; Consultation? consultation; //Main Video Controller & Timer VideoPlayerState _videoState = VideoPlayerState.paused; VideoPlayerState get videoState => _videoState; VideoPlayerController? controller; Timer? timer; // Learning Page Future fetchPatientCoursesList() async { print("====== Api Initiated ========="); Map request; if (await this.sharedPref.getObject(USER_PROFILE) != null) { var data = AuthenticatedUser.fromJson(await this.sharedPref.getObject(USER_PROFILE)); authUser = data; } request = {"Channel": 3, "TokenID": "@dm!n", "PatientID": 22335}; dynamic localRes; await BaseAppClient().post(GET_PATIENT_COURSES_LIST, onSuccess: (response, statusCode) async { print("====== Api Response ========="); print("${response["NabedJourneyResponseResult"]}"); localRes = PatientEducationJourneyListModel.fromJson(response); }, onFailure: (String error, int statusCode) { throw error; }, body: request); return localRes; } void getCourses(BuildContext context) async { GifLoaderDialogUtils.showMyDialog(context); dynamic response = await fetchPatientCoursesList(); GifLoaderDialogUtils.hideDialog(context); if (response.nabedJourneyResponseResult != null) { nabedJourneyResponse = response; isDataLoaded = true; data = nabedJourneyResponse!.nabedJourneyResponseResult!.data; } notifyListeners(); } // Detailed Page Future fetchPatientCourseById() async { print("====== Api Initiated ========="); Map request; if (await this.sharedPref.getObject(USER_PROFILE) != null) { var data = AuthenticatedUser.fromJson(await this.sharedPref.getObject(USER_PROFILE)); authUser = data; } request = {"Channel": 3, "TokenID": "@dm!n", "JourneyID": selectedJourney}; dynamic localRes; await BaseAppClient().post(GET_PATIENT_COURSE_BY_ID, onSuccess: (response, statusCode) async { print("====== Api Response ========="); print("${response}"); localRes = response; }, onFailure: (String error, int statusCode) { throw error; }, body: request); return localRes; } void getCourseById(BuildContext context) async { GifLoaderDialogUtils.showMyDialog(context); dynamic response = await fetchPatientCourseById(); GifLoaderDialogUtils.hideDialog(context); if (response != null) { courseData = PatientEducationJourneyModel.fromRawJson(jsonEncode(response)); courseTopics = courseData!.nabedJourneyByIdResponseResult!.contentClasses!.first.topics; consultation = courseData!.nabedJourneyByIdResponseResult!.consultation; } notifyListeners(); } Future navigate(BuildContext context, int journey, {required Function(Object? val) onBack}) async { selectedJourney = journey; Navigator.of(context).pushNamed(COURSES_DETAILED_PAGE).then((val) { onBack(val); }); } String getDurationOfVideo(int duration) { final durationInSeconds = duration; final minutes = durationInSeconds ~/ 60; final seconds = durationInSeconds % 60; return "$minutes:${seconds.toString().padLeft(2, '0')} mins"; } void playVideo(BuildContext context, {required Content content}) async { print("OnTap"); if (_videoState == VideoPlayerState.playing) { controller?.pause(); setVideoState(VideoPlayerState.paused); } else { try { final videoUrl = content.video?.flavor?.downloadable ?? ""; if (videoUrl.isEmpty) { Utils.showErrorToast("No video URL provided."); return; } controller = VideoPlayerController.networkUrl( Uri.parse(videoUrl), formatHint: VideoFormat.hls, ); await controller!.initialize(); controller!.play(); setVideoState(VideoPlayerState.playing); notifyListeners(); content.controller = controller; controller!.addListener(() { if (controller!.value.isPlaying && timer == null) { _startTimer(context, content: content); } else if (!controller!.value.isPlaying && timer != null) { stopTimer(); } if (controller!.value.hasError) { Utils.showErrorToast("Failed to load video."); controller = null; setVideoState(VideoPlayerState.paused); } }); } catch (e) { Utils.showErrorToast("Error loading video: $e"); controller = null; setVideoState(VideoPlayerState.paused); } } } void setVideoState(VideoPlayerState state) { _videoState = state; notifyListeners(); } void _startTimer(BuildContext context, {required Content content}) { timer = Timer.periodic(Duration(seconds: 1), (timer) async { if (controller != null && _videoState == VideoPlayerState.playing) { final position = await controller!.position; if (position != null) { print("Current position: ${position.inSeconds} seconds"); notifyListeners(); if (position.inSeconds == content.question!.triggerAt) { controller!.pause(); setVideoState(VideoPlayerState.paused); QuestionSheetAction? action = await showQuestionSheet(context, content: content); if (action == QuestionSheetAction.skip) { controller!.play(); setVideoState(VideoPlayerState.playing); } else if (action == QuestionSheetAction.rewatch) { playVideo(context, content: content); } } } } }); } void stopTimer() { timer?.cancel(); timer = null; } // void playVideo(BuildContext context, {required Content content}) async { // print("OnTap"); // if (_videoState == VideoPlayerState.playing) { // controller?.pause(); // setVideoState(VideoPlayerState.paused); // } else { // try { // controller = VideoPlayerController.networkUrl( // Uri.parse( // Platform.isIOS ? content.video!.flavor!.downloadable! : content.video!.flavor!.downloadable!, // ), // formatHint: VideoFormat.hls) // ..initialize() // ..play(); // notifyListeners(); // content.controller = controller; // notifyListeners(); // controller!.addListener(() { // if (controller!.value.isPlaying && timer == null) { // startTimer(context, content: content); // notifyListeners(); // } else if (!controller!.value.isPlaying && timer != null) { // stopTimer(); // notifyListeners(); // } // }); // // controller!.addListener(() { // if (controller!.value.hasError) { // Utils.showErrorToast("Failed to load video."); // controller = null; // setVideoState(VideoPlayerState.paused); // notifyListeners(); // } // }); // notifyListeners(); // } catch (e) { // Utils.showErrorToast("Error loading video: $e"); // controller = null; // setVideoState(VideoPlayerState.paused); // notifyListeners(); // } // controller?.play(); // setVideoState(VideoPlayerState.playing); // } // } // // // void setVideoState(VideoPlayerState state) { // _videoState = state; // notifyListeners(); // } // // void startTimer(BuildContext context, {required Content content}) { // timer = Timer.periodic(Duration(seconds: 1), (timer) async { // if (controller != null && _videoState == VideoPlayerState.playing) { // final position = await controller!.position; // if (position != null) { // print("Current position: ${position.inSeconds} seconds"); // if (position.inSeconds == content.question!.triggerAt) { // print("position: ${position.inSeconds} - ${content.question!.triggerAt} seconds"); // controller!.pause(); // setVideoState(VideoPlayerState.paused); // QuestionSheetAction? action = await showQuestionSheet(context, content: content); // if (action == QuestionSheetAction.skip) { // print("Skip"); // controller!.play(); // } else if (action == QuestionSheetAction.rewatch) { // print("Re-watch"); // playVideo(context, content: content); // } // } // notifyListeners(); // } // } // }); // } // // void stopTimer() { // timer?.cancel(); // timer = null; // } void onComplete() { stopTimer(); setVideoState(VideoPlayerState.completed); } Future clearData() async { data = courseData = nabedJourneyResponse = selectedJourney = courseTopics = consultation = timer = controller = null; } Future clear() async { if (controller != null) controller!.dispose(); courseData = courseTopics = timer = controller = null; } } enum VideoPlayerState { playing, paused, completed, }