You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
352 lines
12 KiB
Dart
352 lines
12 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
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_insert_model.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<Datum>? data;
|
|
PatientEducationJourneyListModel? nabedJourneyResponse;
|
|
PatientEducationJourneyModel? courseData;
|
|
List<Topic>? courseTopics;
|
|
Consultation? consultation;
|
|
|
|
List<Data>? playedData = [];
|
|
|
|
//Main Video Controller & Timer
|
|
VideoPlayerState _videoState = VideoPlayerState.paused;
|
|
|
|
VideoPlayerState get videoState => _videoState;
|
|
VideoPlayerController? controller;
|
|
Timer? timer;
|
|
|
|
// Learning Page
|
|
|
|
Future<dynamic> fetchPatientCoursesList() async {
|
|
print("====== Api Initiated =========");
|
|
Map<String, dynamic> 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<dynamic> fetchPatientCourseById() async {
|
|
print("====== Api Initiated =========");
|
|
Map<String, dynamic> 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 {
|
|
setVideoState(VideoPlayerState.loading);
|
|
notifyListeners();
|
|
|
|
try {
|
|
final videoUrl = content.video?.flavor?.downloadable ?? "";
|
|
if (videoUrl.isEmpty) {
|
|
Utils.showErrorToast("No video URL provided.");
|
|
setVideoState(VideoPlayerState.paused);
|
|
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);
|
|
notifyListeners();
|
|
}
|
|
});
|
|
} catch (e) {
|
|
Utils.showErrorToast("Error loading video: $e");
|
|
controller = null;
|
|
setVideoState(VideoPlayerState.paused);
|
|
notifyListeners();
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
Future<void> uploadStats() async {
|
|
// if(courseTopics != null) {
|
|
// Future.forEach(courseTopics!, (topic) {
|
|
// Future.forEach(topic.contents!, (content){
|
|
// content.controller
|
|
// });
|
|
// });
|
|
// }
|
|
|
|
if (courseTopics != null) {
|
|
await Future.forEach(courseTopics!, (topic) async {
|
|
await Future.forEach(topic.contents!, (content) {
|
|
print(content.controller?.value);
|
|
playedData!.add(new Data(
|
|
type: "content_watch",
|
|
consultationId: 2660,
|
|
contentClassId: 46,
|
|
contentId: 322,
|
|
topicId: 6,
|
|
percentage: content.controller?.value.position.inSeconds ?? 0,
|
|
flavorId: 1,
|
|
srcType: "educate-external",
|
|
screenType: "journey_screen",
|
|
));
|
|
});
|
|
});
|
|
}
|
|
print("===============");
|
|
print(playedData.toString());
|
|
print("===============");
|
|
}
|
|
|
|
// 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<void> clearData() async {
|
|
data = courseData = nabedJourneyResponse = selectedJourney = courseTopics = consultation = timer = controller = null;
|
|
}
|
|
|
|
Future<void> clear() async {
|
|
if (controller != null) controller!.dispose();
|
|
courseData = courseTopics = timer = controller = null;
|
|
}
|
|
}
|
|
|
|
enum VideoPlayerState { playing, paused, completed, loading }
|
|
|
|
IconData getVideoIcon(VideoPlayerState state) {
|
|
switch (state) {
|
|
case VideoPlayerState.loading:
|
|
return Icons.hourglass_top;
|
|
case VideoPlayerState.playing:
|
|
return Icons.pause;
|
|
case VideoPlayerState.paused:
|
|
return Icons.play_arrow;
|
|
case VideoPlayerState.completed:
|
|
return Icons.replay;
|
|
default:
|
|
return Icons.play_arrow;
|
|
}
|
|
}
|