Source

externalCode/lessonSingleScreen.js

import * as React from "react";

/**
 * @typedef {Object} PrevNextComponentProps
 * @property {Function} onQuizClick Function to execute if previous or next button is a quiz
 * @property {Function} onLessonClick Function to execute if previous or next button is a lesson
 * @property {Function} onTopicClick Function to execute if previous or next button is a topic
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {TranslationFunction} t
 * @property {?Object} prevObject Information about previous lesson/topic/quiz
 * @property {?Object} nextObject Information about next lesson/topic/quiz
 * @property {Number} courseId Course id of lesson/topic/quiz
 * @property {Function} nextLockedAlert Shows an alert with information that next object is locked
 */

/**
 * @typedef {Object} PrevNextPlaceholderProps
 * @property {Object} global App global style
 */

/**
 * @typedef {Object} LessonHeaderProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {LessonViewModel} lesson
 * @property {Object} labels Learndash labels
 * @property {TranslationFunction} t
 * @property {Number} paddingTop Default padding top applied to component
 * @property {Function} onQuizClick Function to execute if previous or next button is a quiz
 * @property {Function} onLessonClick Function to execute if previous or next button is a lesson
 * @property {Function} onTopicClick Function to execute if previous or next button is a topic
 * @property {?Object} prevObject Information about previous lesson/topic/quiz
 * @property {?Object} nextObject Information about next lesson/topic/quiz
 * @property {Number} courseId Course id of lesson/topic/quiz
 * @property {Function} nextLockedAlert Shows an alert with information that next object is locked
 * @property {React.ComponentType} backToCourse Returns default back button component
 * @property {Boolean} loading Returns `true` if screen is still loading
 * @property {CourseViewModel} course
 * @property {Boolean | React.ComponentType} renderTimer Returns `false` lesson doesn't have a timer set. Will return a component if timer for the lesson is set.
 * @property {Function} onTimePassed Function which updates the seconds passed in the lesson screen container
 * @property {NavigationService} navigation
 * @property {Boolean} hidePrevNext Returns `true` if prev/next buttons should be hidden
 * @property {Boolean | React.ComponentType} prevNext Returns `false` if hidePrevNext is `true`. Will return buttons which can navigate through previous and next screens if hidePrevNext is `false`
 */

/**
 * @typedef {Object} LessonTitleComponentProps
 * @property {LessonHeaderProps} LessonHeaderProps
 */

/**
 * @typedef {Object} LessonScreenHeaderProps
 * @property {LessonHeaderProps} LessonHeaderProps
 * @property {Object} headerLeftStyle Default styling for left section of the header
 * @property {Object} style Default styling of lesson header
 * @property {Object} headerRightAuthWrapperProps Props which can be passed to an AuthWrapper
 */

/**
 * @typedef {Function} TransformLessonActionButtonsCallback
 * @property {React.ComponentType} lessonButton Lesson action button
 * @property {Boolean} showComplete Returns `true` if "Mark Complete" button should be shown
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {LessonViewModel} lesson
 * @property {Boolean} completing Returns `true` if lesson is being completed
 * @property {Object} labels Labels in the lesson
 */

/**
 * @typedef {Object} LessonViewModel
 * @property {Number} id Lesson id
 * @property {String} title Lesson title
 * @property {String} content Lesson content
 * @property {Array} contentNative Blocks used in the lesson
 * @property {Boolean} quizCompleted Returns `true` if quiz in the lesson has been completed
 * @property {Number} quizCount Number of quizzes in the lesson
 * @property {QuizViewModel} lessonQuizzes
 * @property {Boolean} completed Returns `true` if lesson has been completed
 * @property {Boolean} requireTimer Returns `true` if lesson requires timer
 * @property {Number} timerRequiredTime Timer required time
 * @property {Number} progression User's progress in the lesson
 * @property {Boolean} hasAccess Returns `true` if logged in user has access to lesson
 * @property {Boolean} hasContentAccess Returns `true` if logged in user has access to lesson's content
 * @property {Number} topicsCount Number of topics in the lesson
 * @property {String} videoUrl Url added in video progression of the lesson
 * @property {Object} video Video details
 */

/**
 * @typedef {Object} QuizViewModel
 * @property {Number} id Quiz id
 * @property {Object} title Quiz title
 * @property {String} date Date when quiz was created
 * @property {String} date_gmt Date when quiz was created
 * @property {String} modified Date when quiz was last modified
 * @property {String} modified_gmt Date when quiz was last modified
 * @property {String} link Url to quiz
 * @property {String} slug Slug of url to quiz
 * @property {Number} author User id of author
 * @property {Number} course Course id where quiz is located
 * @property {Number} lesson Lesson id where quiz is located
 * @property {Number} topic Topic id where quiz is located
 * @property {Boolean} completed Returns `true` if quiz has been completed
 * @property {Boolean} can_take_again Returns `true` if quiz can be taken again
 */

/**
 * @typedef {Object} VideoProgressionComponentProps
 * @property {Object} lessonVideoStyle Default styling applied to lesson video
 * @property {Boolean} controls Returns `true` if controls should be displayed
 * @property {Boolean} autoplay Returns `true` if auto play should be enabled
 * @property {Function} videoCallback Helper function which can be called when the video has finished playing
 * @property {String} url Video url
 * @property {Number} width Player width
 * @property {Number} height Player height
 * @property {Object} global App global style
 * @property {Boolean} isNavActive Returns `true` if screen is active
 * @property {LessonViewModel} lesson
 * @property {Boolean} showVideo Returns `true` if video should be shown
 * @property {Boolean} videoWatched Returns `true` if video has already been watched
 * @property {Function} setVideoWatched Helper function which dispatches an action and marks the video as watched
 * @property {Function} completeLesson Helper function which dispatches an action to mark the lesson as complete
 * @property {Function} onCompleteButtonClick Helper function which considers different conditions (such as if topics inside a lesson are already completed) before calling the `completeLesson` function
 */

/**
 * @typedef {Object} AfterMaterialsComponentProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {LessonViewModel} lesson
 * @property {Object} labels Learndash labels
 * @property {TranslationFunction} t
 * @property {Function} onQuizClick Function to execute if previous or next button is a quiz
 * @property {Function} onLessonClick Function to execute if previous or next button is a lesson
 * @property {Function} onTopicClick Function to execute if previous or next button is a topic
 * @property {?Object} prevObject Information about previous lesson/topic/quiz
 * @property {?Object} nextObject Information about next lesson/topic/quiz
 * @property {Function} nextLockedAlert Shows an alert with information that next object is locked
 * @property {Boolean} loading Returns `true` if screen is still loading
 * @property {CourseViewModel} course
 * @property {NavigationService} navigation
 * @property {String} materials Lesson materials
 */

/**
 * @typedef {Object} LessonActionComponentProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {LessonViewModel} lesson
 * @property {Object} labels Learndash labels
 * @property {TranslationFunction} t
 * @property {Function} onCompleteButtonClick Helper function which considers different conditions (such as if topics inside a lesson are already completed) before calling the `completeLesson` function
 * @property {Boolean} showComplete Returns `true` if "Mark Complete" button should be shown
 * @property {Boolean} completing Returns `true` if lesson is being completed
 * @property {Boolean} completeDisabled Returns `true` if "Mark Complete" button should be disabled
 */

/**
 * @typedef {Function} TransformLessonViewModelCallback
 * @property {LessonViewModel} viewModel
 * @property {Object} lesson Lesson raw data from API
 * @return {Object} New view model
 */

/**
 * @class
 * Lesson Screen Hooks.
 * Instance name: lessonSingleScreenApi
 
   You can use this hook to customize the lesson screen such as by adding a custom call to action button and other actions.
 * @example
 * externalCodeSetup.lessonSingleScreenApi.METHOD_NAME
 */
export class LessonSingleScreenHooksApi {
	/**
	 * @deprecated
	 * Filters navigation onPress function that is used to navigate to Topic
	 */
	topicNavigationFilter = (onPress, navigation, topic, lessonId, courseId) =>
		onPress;

	/**
	 * @deprecated
	 */
	setTopicNavigationFilter = topicNavigationFilter => {
		this.topicNavigationFilter = topicNavigationFilter;
	};

	PrevNextComponent = null;

	/**
	 * You can use this to replace the previous and next buttons on the lessons single screen if you want to change the default option which always displays the prev/next buttons.
	 * @method
	 * @param {?React.ComponentType<PrevNextComponentProps>} PrevNextComponent
	 * @example <caption> Hide the previous and next buttons if you're only using one lesson in a course </caption>
	 *
	 * //In custom_code/components/PrevNext.js
	 *
	 * import React from "react";
	 * import PrevNext from "@src/components/Course/PrevNext";
	 *
	 *  const PrevNextComponent = props => {
	 *
	 *    const { onQuizClick,
	 *            onLessonClick,
	 *            onTopicClick,
	 *            global,
	 *            colors,
	 *            t,
	 *            prevObject,
	 *            nextObject,
	 *            courseId,
	 *            nextLockedAlert } = props;
	 *
	 *    if (! nextObject && ! prevObject){
	 *        return null;
	 *    }
	 *
	 *    return (
	 *        <PrevNext
	 *            {...{ onQuizClick, onLessonClick, onTopicClick }}
	 *            global={global}
	 *            colors={colors}
	 *            t={t}
	 *            prevObject={prevObject}
	 *            nextObject={nextObject}
	 *            courseId={courseId}
	 *            nextLockedAlert={nextLockedAlert}
	 *        />
	 *    );
	 * };
	 * export default PrevNextComponent;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import PrevNextComponent from './components/PrevNext';
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.lessonSingleScreenApi.setPrevNextComponent(props => <PrevNextComponent {...props} />)
	 * }
	 *
	 * @example <caption> Hide previous and next buttons </caption>
	 *
	 * ...
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.lessonSingleScreenApi.setPrevNextComponent(() => null)
	 * }
	 *
	 */
	setPrevNextComponent = PrevNextComponent => {
		this.PrevNextComponent = PrevNextComponent;
	};

	PrevNextPlaceholder = null;

	/**
	 * You can use this to replace the previous and next buttons' placeholders on the lessons single screen.
	 * The previous and next buttons' placeholders appear while the app is still loading the lesson.
	 * @method
	 * @param {?React.ComponentType<PrevNextPlaceholderProps>} PrevNextPlaceholder
	 * @example <caption> Change placeholder color </caption>
	 *
	 * externalCodeSetup.lessonSingleScreenApi.setPrevNextPlaceholder((props) => {
	 *
	 *    const {global} = props;
	 *
	 *    return <>
	 *      <View
	 *        style={[
	 *          global.wrappedButton,
	 *          global.wrappedTextButton,
	 *          { marginRight: 4, width: 64, backgroundColor: "blue" }
	 *        ]}
	 *      />
	 *      <View
	 *        style={[
	 *          global.wrappedButton,
	 *          global.wrappedTextButton,
	 *          { width: 65 , backgroundColor: "red"}
	 *        ]}
	 *      />
	 *    </>
	 * })
	 *
	 * @example <caption> Hide the placeholder even while the screen is still loading </caption>
	 *
	 * externalCodeSetup.lessonSingleScreenApi.setPrevNextPlaceholder(() => null)
	 *
	 */
	setPrevNextPlaceholder = PrevNextPlaceholder => {
		this.PrevNextPlaceholder = PrevNextPlaceholder;
	};

	transformLessonActionButtons = (
		lessonButton,
		showComplete,
		global,
		colors,
		lesson,
		completing,
		labels
	) => lessonButton;

	/**
	 * You can transform the default lesson action button by replacing it with your preferred action buttons.
	 * @param {TransformLessonActionButtonsCallback} transformLessonActionButtons
	 * @method
	 * @example <caption> Add more components for lesson action </caption>
	 *
	 * externalCodeSetup.lessonSingleScreenApi.setTransformLessonActionButtons((
	 *  lessonButton,
	 *  showComplete,
	 *  global,
	 *  colors,
	 *  lesson,
	 *  completing,
	 *  labels) => {
	 *
	 *    const Buttons =
	 *      <View style={[global.row, {backgroundColor: "#fff"}]}>
	 *
	 *        <View style={{ width:"45%", backgroundColor: "#fff", paddingHorizontal: 20, paddingVertical: 15 }}>
	 *          <AppTouchableOpacity
	 *            style={[
	 *              global.completeLessonButtonW,
	 *              { flex: 1, backgroundColor: colors.primaryButtonBg }
	 *            ]}
	 *            onPress={() => {
	 *              //Do function...
	 *            }}
	 *          >
	 *            <View style={global.row}>
	 *              <View style={global.linkWithArrow}>
	 *                <Text
	 *                  style={{color: "#fff", fontWeight: "bold"}}
	 *                >
	 *                  Questions?
	 *                </Text>
	 *              </View>
	 *            </View>
	 *          </AppTouchableOpacity>
	 *        </View>
	 *        <View style={{ width: "45%", marginLeft: "auto" }}>
	 *          {lessonButton}
	 *        </View>
	 *      </View>
	 *
	 *    return Buttons;
	 * })
	 */

	setTransformLessonActionButtons = transformLessonActionButtons => {
		this.transformLessonActionButtons = transformLessonActionButtons;
	};

	LessonTitleComponent = null;

	/**
	 * You can use this to replace the lesson's title component.
	 * For example, you can use this to change the title's background or add an ellipsis feature to it.
	 * @method
	 * @param {React.ComponentType<LessonTitleComponentProps>} LessonTitleComponent
	 * @example <caption> Change component's background and add ellipsis to text </caption>
	 *
	 * //In custom_code/components/LessonTitle.js...
	 *
	 * import React from "react";
	 * import {View, Text} from "react-native";
	 * import Animated from "react-native-reanimated";
	 *
	 * const LessonTitle = (props) => {
	 *
	 *  const {
	 *    global,
	 *    colors,
	 *    paddingTop,
	 *    lesson,
	 *    t,
	 *    labels
	 *  } = props;
	 *
	 *  const paddingBottom = 14;
	 *
	 *  let backgroundColor = colors.bodyFrontBg;
	 *  if (lesson.title.includes("Android")){
	 *    backgroundColor = "red"
	 *  }
	 *
	 *  return (
	 *    <Animated.View
	 *      style={[
	 *        {
	 *          backgroundColor: backgroundColor,
	 *          width: "100%",
	 *          shadowOffset: {width: 0, height: 1},
	 *          shadowRadius: 1,
	 *          shadowColor: "#000",
	 *          shadowOpacity: 0.05
	 *        }
	 *     ]}
	 *    >
	 *    <View
	 *      style={[
	 *        global.row,
	 *        {
	 *          justifyContent: "space-between",
	 *          alignItems: "flex-start",
	 *          paddingTop,
	 *          paddingBottom
	 *        }
	 *      ]}
	 *    >
	 *      <Animated.View
	 *        style={{
	 *          flex: 1,
	 *          paddingHorizontal: 20
	 *        }}
	 *      >
	 *        <Animated.Text
	 *          style={[
	 *            global.courseHeaderTitle,
	 *            {marginBottom: 5}
	 *          ]}
	 *          numberOfLines={1} //Adds ellipsis to lesson title
	 *        >
	 *          {lesson.title}
	 *        </Animated.Text>
	 *        <Text style={global.courseHeaderSubTitle}>
	 *          {t("lesson:count", {
	 *            label: labels.lesson,
	 *            current: lesson.order,
	 *            total: lesson.total
	 *          })}
	 *        </Text>
	 *      </Animated.View>
	 *    </View>
	 *    </Animated.View>
	 *  );
	 * };
	 *
	 * export default LessonTitle;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 * import LessonTitle from "./components/LessonTitle"
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.lessonSingleScreenApi.setLessonTitleComponent(props => <LessonTitle {...props} />)
	 * }
	 *
	 * @example <caption> Add screen header components to lesson title </caption>
	 *
	 * // In custom_code/components/LessonTitle.js...
	 * import React from "react";
	 * import { useSelector } from "react-redux";
	 * import { View, Text, StyleSheet } from "react-native";
	 * import Animated from "react-native-reanimated";
	 * import PrevNext from "@src/components/Course/PrevNext";
	 * import Icon from "@src/components/Icon";
	 * import TimeCounter from "@src/components/TimeCounterAutoPause";
	 *
	 * const LessonTitle = (props) => {
	 *
	 *   const {
	 *     title,
	 *     global,
	 *     colors,
	 *     paddingTop,
	 *     lesson,
	 *     t,
	 *     labels,
	 *     onQuizClick,
	 *     onLessonClick,
	 *     onTopicClick,
	 *     prevObject,
	 *     nextObject,
	 *     courseId,
	 *     nextLockedAlert,
	 *     backToCourse,
	 *     course,
	 *     loading,
	 *     renderTimer,
	 *     onTimePassed,
	 *     navigation
	 *   } = props;
	 *
	 *   const paddingBottom = 14;
	 *
	 *   const renderDefaultTimer = false
	 *
	 *   const isLessonCompleting = useSelector(state => state.singleLesson.completing == lesson.id);
	 *
	 *   const CustomTimer = () => {
	 *
	 *     if (loading || !lesson.requireTimer || isLessonCompleting)
	 *       return null;
	 *
	 *     return <View
	 *       style={{
	 *         flexDirection: "row",
	 *         alignItems: "center"
	 *       }}
	 *     >
	 *       <Text>My Custom Timer</Text>
	 *       <Icon
	 *         icon={require("@src/assets/img/stopwatch.png")}
	 *         webIcon={"IconArrowBack"}
	 *         tintColor={colors.textIconColor}
	 *         styles={{
	 *           marginRight: 6,
	 *           height: 20,
	 *           width: 20
	 *         }}
	 *       />
	 *       <TimeCounter
	 *         paused={!navigation.isActive}
	 *         onTimePassed={onTimePassed}
	 *         initialSeconds={0}
	 *         textProps={{ style: global.timer }}
	 *       />
	 *     </View>
	 *   }
	 *
	 *   return (
	 *     <Animated.View
	 *       style={[
	 *         {
	 *           backgroundColor: colors.bodyFrontBg,
	 *           width: "100%",
	 *           shadowOffset: { width: 0, height: 1 },
	 *           shadowRadius: 1,
	 *           shadowColor: "#000",
	 *           shadowOpacity: 0.05,
	 *           marginTop: 50
	 *         }
	 *       ]}
	 *     >
	 *       <View
	 *         style={[
	 *           global.row,
	 *           {
	 *             justifyContent: "space-between",
	 *             alignItems: "flex-start",
	 *             paddingTop,
	 *             paddingBottom
	 *           }
	 *         ]}
	 *       >
	 *         <Animated.View
	 *           style={{
	 *             flex: 1,
	 *             paddingHorizontal: 20
	 *           }}
	 *         >
	 *          //ScreenHeader components
	 *           <View style={{ flexDirection: "row", marginLeft: -20 }}>
	 *             {backToCourse}
	 *
	 *             <PrevNext
	 *               {...{ onQuizClick, onLessonClick, onTopicClick }}
	 *               global={global}
	 *               colors={colors}
	 *               t={t}
	 *               prevObject={prevObject}
	 *               nextObject={nextObject}
	 *               courseId={courseId}
	 *               nextLockedAlert={nextLockedAlert}
	 *             />
	 *
	 *             {renderDefaultTimer ? renderTimer : <CustomTimer />}
	 *
	 *           </View>
	 *           //End ScreenHeader components
	 *
	 *           <Animated.Text
	 *             style={[
	 *               global.courseHeaderTitle,
	 *               { marginBottom: 5 }
	 *             ]}
	 *             numberOfLines={1} //Adds ellipsis to lesson title
	 *           >
	 *             {lesson.title}
	 *           </Animated.Text>
	 *
	 *           <Text style={global.courseHeaderSubTitle}>
	 *             {t("lesson:count", {
	 *               label: labels.lesson,
	 *               current: lesson.order,
	 *               total: lesson.total
	 *             })}
	 *           </Text>
	 *         </Animated.View>
	 *       </View>
	 *     </Animated.View>
	 *   );
	 * };
	 *
	 * export default LessonTitle;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 * import LessonTitle from "./components/LessonTitle"
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.lessonSingleScreenApi.setLessonTitleComponent(props => <LessonTitle {...props} />)
	 * }
	 */
	setLessonTitleComponent = LessonTitleComponent => {
		this.LessonTitleComponent = LessonTitleComponent;
	};

	LessonScreenHeader = null;
	/**
	 * You can use this hook to customize the header of the Lesson Single Screen which by default, contains the back-to-course button and the previous/next buttons.
	 * @method
	 * @param {React.ComponentType<LessonScreenHeaderProps>} LessonScreenHeader
	 * @example
	 *
	 * //In custom_code/components/LessonScreenHeader.js...
	 *
	 * import React from "react";
	 * import {View} from "react-native";
	 * import Animated from "react-native-reanimated";
	 * import {DEVICE_WIDTH} from "@src/styles/global";
	 * import AuthWrapper from "@src/components/AuthWrapper";
	 *
	 * const Header = ({
	 *     headerLeftStyle,
	 *     style,
	 *     global,
	 *     backToCourse,
	 *     renderTimer,
	 *     headerRightAuthWrapperProps,
	 *     prevNext
	 * }) => {
	 *   return (
	 *     <Animated.View
	 *       style={[
	 *         global.row,
	 *         global.fakeHeader,
	 *         {
	 *           backgroundColor: "transparent",
	 *           paddingHorizontal: 10,
	 *           overflow: "hidden"
	 *         },
	 *         {
	 *           width: DEVICE_WIDTH
	 *         },
	 *         style
	 *       ]}
	 *     >
	 *       <View
	 *         style={[
	 *           {
	 *             alignItems: "center",
	 *             justifyContent: "center",
	 *             flexDirection: "row",
	 *             flex: 1,
	 *             height: "100%"
	 *           }
	 *         ]}
	 *       >
	 *         <View style={[global.headerButtonLeft, headerLeftStyle]}>
	 *           {backToCourse}
	 *         </View>
	 *         <View style={[global.headerCustomTitle]}>
	 *           {renderTimer}
	 *         </View>
	 *         <View style={[global.headerButtonRight]}>
	 *           <AuthWrapper
	 *             actionOnGuestLogin={"hide"}
	 *             {...headerRightAuthWrapperProps}
	 *           >
	 *             {prevNext}
	 *           </AuthWrapper>
	 *         </View>
	 *       </View>
	 *     </Animated.View>
	 *   );
	 * };
	 *
	 * export default Header;
	 *
	 * //In custom_code/index.js...
	 *
	 * import LessonScreenHeader from "./components/LessonScreenHeader";
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.lessonSingleScreenApi.setLessonScreenHeader(props => <LessonScreenHeader {...props}/>)
	 * }
	 */
	setLessonScreenHeader = LessonScreenHeader => {
		this.LessonScreenHeader = LessonScreenHeader;
	};

	VideoProgressionComponent = null;
	/**
	 * You can use this hook to customize the Video Progression component in the single lesson screen.
	 * For example, you can use this to change the size of the video player or add a custom function when the video finishes playing on a lesson.
	 * @method
	 * @param {React.ComponentType<VideoProgressionComponentProps>} VideoProgressionComponent
	 * @example <caption> Execute a custom callback when video has finished playing </caption>
	 *
	 * ...
	 * import AppVideo from "@src/components/Video/AppVideo";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *   externalCodeSetup.lessonSingleScreenApi.setVideoProgressionComponent(props => {
	 *     const {
	 *       lessonVideoStyle,
	 *       controls,
	 *       autoPlay,
	 *       videoCallback,
	 *       url,
	 *       width,
	 *       height,
	 *       global,
	 *       isNavActive,
	 *       lesson,
	 *       videoWatched,
	 *       setVideoWatched,
	 *       onCompleteButtonClick
	 *     } = props;
	 *
	 *     const customCallback = settings => event => {
	 *
	 *       if (event.nativeEvent.data === "ENDED") {
	 *
	 *         if (!videoWatched)
	 *           setVideoWatched();
	 *
	 *         Alert.alert(
	 *           "Video Complete",
	 *           "You have finished watching the video. Do you want to mark the lesson as complete?",
	 *           [
	 *             {
	 *               text: "Cancel",
	 *               onPress: () => console.log("Cancel Pressed"),
	 *               style: "cancel"
	 *             },
	 *             { text: "OK", onPress: () => onCompleteButtonClick() }
	 *           ]
	 *         );
	 *       }
	 *
	 *     }
	 *
	 *     return <View style={lessonVideoStyle}>
	 *       <Text>Please finish watching the video below to proceed...</Text>
	 *       <AppVideo
	 *         controls={controls}
	 *         autoPlay={autoPlay}
	 *         // videoCallback={videoCallback()}
	 *         videoCallback={customCallback(lesson.settings)}
	 *         url={url}
	 *         width={width}
	 *         height={height}
	 *         global={global}
	 *         isNavActive={isNavActive}
	 *       />
	 *     </View>
	 *   })
	 * }
	 *
	 */
	setVideoProgressionComponent = VideoProgressionComponent => {
		this.VideoProgressionComponent = VideoProgressionComponent;
	};

	AfterMaterialsComponent = null;
	/**
	 * You can use this hook to add a component at the bottom of the lesson single screen just after the component that displays the materials.
	 * @method
	 * @param {React.ComponentType<AfterMaterialsComponentProps>} AfterMaterialsComponent
	 * @example
	 *
	 * //In custom_code/components/LessonBottomComponent.js...
	 *
	 * import React from "react";
	 * import { View, Text, TouchableOpacity } from "react-native";
	 * const LessonBottomComponent = props => {
	 *
	 *     const {
	 *         colors,
	 *         course,
	 *         navigation
	 *     } = props;
	 *
	 *     const back = () => {
	 *         navigation.navigate({
	 *             routeName: "CoursesSingleScreen",
	 *             params: {
	 *                 id: course.id,
	 *                 course
	 *             },
	 *             key: course.id.toString()
	 *         })
	 *     }
	 *     return <View style={{
	 *         backgroundColor: colors.bodyFrontBg,
	 *         paddingHorizontal: 20,
	 *         paddingBottom: 20,
	 *         minHeight: 100,
	 *     }}>
	 *         <Text>This lesson is part of the {course.title.rendered} course </Text>
	 *         <TouchableOpacity onPress={back}>
	 *             <Text>
	 *                 Back To Course
	 *             </Text>
	 *         </TouchableOpacity>
	 *     </View>
	 * }
	 *
	 *  export default LessonBottomComponent;
	 *
	 *  //In custom_code/index.js...
	 *
	 *  ...
	 *
	 * import LessonBottomComponent from "./components/LessonBottomComponent";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.lessonSingleScreenApi.setAfterMaterialsComponent(props => <LessonBottomComponent {...props}/>)
	 * }
	 */
	setAfterMaterialsComponent = AfterMaterialsComponent => {
		this.AfterMaterialsComponent = AfterMaterialsComponent;
	};

	LessonActionComponent = null;
	/**
	 * You can use this hook to customize the "Mark Complete" / "Completed" button.
	 * For example, you can add your own loading animation when the "Mark Complete" button is pressed.
	 * @method
	 * @param {React.ComponentType<LessonActionComponentProps>} LessonActionComponent
	 * @example <caption> Add a "Completing..." text when marking the lesson complete </caption>
	 *
	 * //In custom_code/components/LessonActionComponent.js...
	 * import React from "react";
	 * import { View, Text, ActivityIndicator } from "react-native";
	 *
	 * import AuthWrapper from "@src/components/AuthWrapper";
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import Icon from "@src/components/Icon";
	 * import { isColorDark } from "@src/utils";
	 *
	 * const LessonActionComponent = ({
	 *     showComplete,
	 *     global,
	 *     colors,
	 *     t,
	 *     lesson,
	 *     onCompleteButtonClick,
	 *     completing,
	 *     completeDisabled,
	 *     labels
	 * }) => (<AuthWrapper actionOnGuestLogin={"hide"}>
	 *     {showComplete && (
	 *         <View
	 *             style={[
	 *                 global.row,
	 *                 {
	 *                     backgroundColor: colors.bodyFrontBg,
	 *                     borderTopColor: colors.borderColor
	 *                 },
	 *                 global.lessonActionButtonContainer
	 *             ]}
	 *         >
	 *             <AppTouchableOpacity
	 *                 style={[
	 *                     { flex: 1 },
	 *                     {
	 *                         opacity: !lesson.completed && completeDisabled ? 0.5 : 1,
	 *                         backgroundColor: !lesson.completed
	 *                             ? colors.primaryButtonBg
	 *                             : colors.bodyFrontBg
	 *                     },
	 *                     global.completeLessonButtonW
	 *                 ]}
	 *                 disabled={lesson.completed || completeDisabled}
	 *                 onPress={onCompleteButtonClick}
	 *             >
	 *                 <View style={global.row}>
	 *                     <View style={global.linkWithArrow}>
	 *                         {!lesson.completed ? (
	 *                             completing && (
	 *                                 <>
	 *                                     <Text style={{color: "#fff"}}>Completing...</Text>
	 *                                     <ActivityIndicator
	 *                                         animating={true}
	 *                                         color={colors.primaryButtonColor}
	 *                                         size="small"
	 *                                         style={global.lessonButtonLoadingIcon}
	 *                                     />
	 *                                 </>
	 *                             )
	 *                         ) : (
	 *                             <Icon
	 *                                 webIcon={""}
	 *                                 icon={require("@src/assets/img/completed-course.png")}
	 *                                 styles={global.lessonActionCompleteIcon}
	 *                             />
	 *                         )}
	 *                         <Text
	 *                             style={[
	 *                                 {
	 *                                     marginLeft: 10,
	 *                                     color: !lesson.completed
	 *                                         ? colors.primaryButtonColor
	 *                                         : isColorDark(colors.bodyFrontBg)
	 *                                             ? "white"
	 *                                             : "black"
	 *                                 },
	 *                                 !lesson.completed
	 *                                     ? global.completeLessonButton
	 *                                     : global.completeButton
	 *                             ]}
	 *                         >
	 *                             {t(
	 *                                 lesson.completed
	 *                                     ? "lesson:completed"
	 *                                     : "lesson:completeLesson",
	 *                                 { label: labels.lesson.toLowerCase() }
	 *                             )}
	 *                         </Text>
	 *                     </View>
	 *                 </View>
	 *             </AppTouchableOpacity>
	 *         </View>
	 *     )}
	 * </AuthWrapper>)
	 *
	 * export default LessonActionComponent;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import LessonActionComponent from "./components/LessonActionComponent";
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *     externalCodeSetup.lessonSingleScreenApi.setLessonActionComponent(props => <LessonActionComponent {...props} />)
	 * }
	 *
	 */
	setLessonActionComponent = LessonActionComponent => {
		this.LessonActionComponent = LessonActionComponent;
	};

	lessonViewModelFilter = (viewModel, lesson) => viewModel;

	/**
	 * Sets the callback function that can change an existing lesson view model object.
	 * @method
	 * @param {TransformLessonViewModelCallback} lessonViewModelFilter
	 * @example <caption>Remove the native blocks in a lesson</caption>
	 * externalCodeSetup.lessonSingleScreenApi.setLessonViewModelFilter((viewModel, lesson) => {
	 *     return {
	 *         ...viewModel,
	 *         contentNative: []
	 *     }
	 * })
	 */
	setLessonViewModelFilter = lessonViewModelFilter => {
		this.lessonViewModelFilter = lessonViewModelFilter;
	};
}