Source

externalCode/learnTopicSingleScreen.ts

import * as React from "react";
import {
	Course,
	Lesson,
	LearnTopic,
	TLearnTopicViewModel,
	TTranslationFunction
} from "./types";
import {NavigationService} from "./types";

export const API_NAME = "learnTopicSingleScreenApi";

/**
 * LearnTopicAfterContentRendererProps
 */

type LearnTopicAfterContentRendererProps = {
	topic: LearnTopic,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,

	navigation: NavigationService
};

/**
 * TransformTopicActionButtonsCallback
 */
type TransformTopicActionButtonsCallback = {
	/**
	 * Topic action button
	 */
	TopicButton: JSX.Element,
	/**
	 * Returns `true` if "Mark Complete" button should be shown
	 */
	showComplete: boolean,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	topic: TLearnTopicViewModel,
	/**
	 * Returns `true` if topic is being completed
	 */
	completing: boolean,
	/**
	 * Learndash labels
	 */
	labels: Record<any, any>,
	/**
	 * Marks the topic as complete
	 */
	handleComplete: Function
};

/**
 * showMarkAsCompleteProps
 */
type showMarkAsCompleteProps = {
	topic: LearnTopic
};

/**
 * LearnTopicPrevNextComponentProps
 */
type LearnTopicPrevNextComponentProps = {
	/**
	 * Function to execute if previous or next button is a quiz
	 */
	onQuizClick: Function,
	/**
	 * Function to execute if previous or next button is a lesson
	 */
	onLessonClick: Function,
	/**
	 * Function to execute if previous or next button is a topic
	 */
	onTopicClick: Function,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	t: TTranslationFunction,
	/**
	 * Data about previous lesson/topic/quiz
	 */
	prevObject: Record<any, any>,
	/**
	 * Data about next lesson/topic/quiz
	 */
	nextObject: Record<any, any>,
	/**
	 * Course id of lesson/topic/quiz
	 */
	courseId: number,
	/**
	 * Shows an alert with information that next object is locked
	 */
	nextLockedAlert: Function
};

/**
 * LearnTopicHeaderProps
 */
type LearnTopicHeaderProps = {
	topic: TLearnTopicViewModel,
	lessonOrder: number,
	paddingTop: number,
	setHeaderHeight: Function,

	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Learndash labels
	 */
	labels: Record<any, any>,
	/**
	 * Function to execute if previous or next button is a quiz
	 */
	onQuizClick: Function,
	/**
	 * Function to execute if previous or next button is a lesson
	 */
	onLessonClick: Function,
	/**
	 * Function to execute if previous or next button is a topic
	 */
	onTopicClick: Function,
	/**
	 * Data about previous lesson/topic/quiz
	 */
	prevObject: Record<any, any>,
	/**
	 * Data about next lesson/topic/quiz
	 */
	nextObject: Record<any, any>,

	/**
	 * Course id of lesson/topic/quiz
	 */
	courseId: number,
	/**
	 * Shows an alert with information that next object is locked
	 */
	nextLockedAlert: Function,
	/**
	 * Returns default back button component
	 */
	backToCourse: React.ComponentType,
	course: Course,
	/**
	 * Returns `true` if data is loading
	 */
	loading: boolean,
	/**
	 * Returns `false` if topic doesn't have a timer set. Returns a component if a timer for the topic is set.
	 */
	renderTimer: boolean | React.ComponentType,
	/**
	 * Function which updates the seconds passed in the topic screen container
	 */
	onTimePassed: Function,
	navigation: NavigationService,
	/**
	 * Returns `true` if prev/next buttons should be hidden
	 */
	hidePrevNext: boolean,
	/**
	 * Returns `false` if hidePrevNext is `true`. Returns buttons which can navigate through previous and next screens if hidePrevNext is `false`
	 */
	prevNext: boolean | React.ComponentType
};

/**
 * LearnTopicScreenHeaderProps
 */
type LearnTopicScreenHeaderProps = {
	/**
	 *  Default styling for left section of the header
	 */
	headerLeftStyle: Record<any, any>,
	/**
	 * Default styling of lesson header
	 */
	style: Record<any, any>,
	/**
	 * Props which can be passed to an AuthWrapper
	 */
	headerRightAuthWrapperProps: Record<any, any>,

	topic: TLearnTopicViewModel,
	lessonOrder: number,
	paddingTop: number,
	setHeaderHeight: Function,

	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	labels: Record<any, any>,
	/**
	 * Function to execute if previous or next button is a quiz
	 */
	onQuizClick: Function,
	/**
	 * Function to execute if previous or next button is a lesson
	 */
	onLessonClick: Function,
	/**
	 * Function to execute if previous or next button is a topic
	 */
	onTopicClick: Function,
	/**
	 * Data about previous lesson/topic/quiz
	 */
	prevObject: Record<any, any>,
	/**
	 * Data about next lesson/topic/quiz
	 */
	nextObject: Record<any, any>,

	/**
	 * Course id of lesson/topic/quiz
	 */
	courseId: number,
	/**
	 * Shows an alert with information that next object is locked
	 */
	nextLockedAlert: Function,
	/**
	 * Returns default back button component
	 */
	backToCourse: React.ComponentType,
	course: Course,
	/**
	 * Returns `true` if data is loading
	 */
	loading: boolean,
	/**
	 * Returns `false` if topic doesn't have a timer set. Returns a component if a timer for the topic is set.
	 */
	renderTimer: boolean | React.ComponentType,
	/**
	 * Function which updates the seconds passed in the topic screen container
	 */
	onTimePassed: Function,
	navigation: NavigationService,
	/**
	 * Returns `true` if prev/next buttons should be hidden
	 */
	hidePrevNext: boolean,
	/**
	 * Returns `false` if hidePrevNext is `true`. Returns buttons which can navigate through previous and next screens if hidePrevNext is `false`
	 */
	prevNext: boolean | React.ComponentType
};

/**
 * LearnTopicVideoProgressionComponentProps
 */
type LearnTopicVideoProgressionComponentProps = {
	/**
	 * Default styling applied to topic video
	 */
	topicVideoStyle: Record<any, any>,
	/**
	 * Returns `true` if controls should be displayed
	 */
	controls: boolean,
	/**
	 *  Returns `true` if auto play should be enabled
	 */
	autoPlay: boolean,
	/**
	 * Helper function which can be called when the video has finished playing
	 */
	videoCallback: Function,
	/**
	 * Video url
	 */
	url: string,
	/**
	 * Player width
	 */
	width: number,
	/**
	 * Player height
	 */
	height: number,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * Returns `true` if screen is active
	 */
	isNavActive: boolean,

	topic: TLearnTopicViewModel,
	/**
	 * Returns `true` if video should be shown
	 */
	showVideo: boolean,
	/**
	 * Returns `true` if video has already been watched
	 */
	videoWatched: boolean,
	/**
	 * Dispatches an action and marks the video as watched
	 */
	setVideoWatched: Function,
	/**
	 * Dispatches an action to mark the topic as complete
	 */
	completeTopic: Function,
	/**
	 * Function which considers different conditions (such as if quizzes inside a topic are already completed) before calling the `completeTopic` function
	 */
	onCompleteTopicClick: Function
};

/**
 * LearnTopicAfterMaterialsComponentProps
 */
type LearnTopicAfterMaterialsComponentProps = {
	topic: TLearnTopicViewModel,
	lessonOrder: number,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	labels: Record<any, any>,
	lesson: Lesson,

	t: TTranslationFunction,
	/**
	 * Function to execute if previous or next button is a quiz
	 */
	onQuizClick: Function,
	/**
	 * Function to execute if previous or next button is a lesson
	 */
	onLessonClick: Function,
	/**
	 * Function to execute if previous or next button is a topic
	 */
	onTopicClick: Function,
	/**
	 * Data about previous lesson/topic/quiz
	 */
	prevObject: Record<any, any>,
	/**
	 * Data about next lesson/topic/quiz
	 */
	nextObject: Record<any, any>,

	/**
	 * Shows an alert with information that next object is locked
	 */
	nextLockedAlert: Function,

	course: Course,
	/**
	 * Returns `true` if data is loading
	 */
	loading: boolean,
	navigation: NavigationService,
	/**
	 * Topic material
	 */
	materials: string
};

/**
 * LearnTopicActionComponentProps
 */
type LearnTopicActionComponentProps = {
	/**
	 * Returns `true` if "Mark Complete" button should be shown
	 */
	showComplete: boolean,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	t: TTranslationFunction,
	topicVM: TLearnTopicViewModel,
	/**
	 * Helper function which considers different conditions (such as if quizzes inside a topic are already completed) before calling the `completeTopic` function
	 */
	onCompleteTopicClick: Function,
	/**
	 *  Returns `true` if topic is being completed
	 */
	completing: boolean,
	/**
	 * Returns `true` if "Mark Complete" button should be disabled
	 */
	completeDisabled: boolean,
	/**
	 * Data about previous lesson/topic/quiz
	 */
	prevObject: Record<any, any>,
	/**
	 * Data about next lesson/topic/quiz
	 */
	nextObject: Record<any, any>,
	/**
	 * Function to execute if previous or next button is a quiz
	 */
	onQuizClick: Function,
	/**
	 * Function to execute if previous or next button is a lesson
	 */
	onLessonClick: Function,
	/**
	 * Function to execute if previous or next button is a topic
	 */
	onTopicClick: Function
};

/**
 * LearnTopicOfflineComponentProps
 */
type LearnTopicOfflineComponentProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	t: TTranslationFunction,

	/**
	 * Default container style
	 */
	containerStyle: Record<any, any>,

	/**
	 * Default style of EmptyList component
	 */
	emptyListStyle: Record<any, any>
};

/**
 * LearnTopicWebViewContentComponentProps
 */
type LearnTopicWebViewContentComponentProps = {
	/**
	 * Returns `true` if device is connected to an internet network
	 */
	online: boolean,
	t: TTranslationFunction,
	/**
	 * The default function used for determining how to handle webview requests.
	 */
	onShouldStartLoadWithRequest: Function,
	/**
	 * Default height
	 */
	height: number,
	/**
	 * Contains data of the web site to be loaded in the webview
	 */
	source: Record<any, any>,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Modal which shows up when the "Read More" component is pressed
	 */
	ModalHeaderComponent: React.FC
};

/**
 * LearnTopicMaterialsSectionTitleProps
 */
type LearnTopicMaterialsSectionTitleProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	t: TTranslationFunction
};

/**
 * AssignmentsHeaderProps
 */
type AssignmentsHeaderProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	t: TTranslationFunction,
	/**
	 * Total number of assignments uploaded
	 */
	totalAssignments: number,
	/**
	 * Number of assignments approved
	 */
	approved: number
};

/**
 * AssignmentItemIconProps
 */
type AssignmentItemIconProps = {
	/**
	 * Default icon for the item
	 */
	icon: number,
	/**
	 * Default style for the item
	 */
	styles: Record<any, any>
};

/**
 * AssignmentItemTitleProps
 */
type AssignmentItemTitleProps = {
	/**
	 * Assignment item title
	 */
	title: string,
	/**
	 * Default style for the item
	 */
	style: Record<any, any>
};

/**
 * AssignmentItemStatusProps
 */
type AssignmentItemStatusProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * Assignment item status
	 */
	text: string,
	/**
	 * Default container style
	 */
	containerStyle: Record<any, any>,
	/**
	 * Default text style
	 */
	textStyle: Record<any, any>
};

/**
 * AssignmentItemCommentProps
 */
type AssignmentItemCommentProps = {
	/**
	 * Opens the comments modal
	 */
	pressHandler: Function,
	/**
	 * Default button color
	 */
	tintColor: string,
	/**
	 * Default container style
	 */
	containerStyle: Record<any, any> | undefined,
	/**
	 * Number of comments
	 */
	count: number,
	/**
	 * Button size
	 */
	size: string,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * Can be used to determine if button should use light or dark style
	 */
	lightMode: boolean | undefined
};

/**
 * AssignmentItemDownloadProps
 */
type AssignmentItemDownloadProps = {
	/**
	 * Downloads the assignment item
	 */
	pressHandler: Function,

	/**
	 * Default button color
	 */
	tintColor: string,
	/**
	 * Default container style
	 */
	containerStyle: Record<any, any> | undefined,
	/**
	 * Number of comments
	 */
	count: number,
	/**
	 * Button size
	 */
	size: string,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * Can be used to determine if button should use light or dark style
	 */
	lightMode: boolean | undefined
};

/**
 * AssignmentItemDownloadProgressProps
 */
type AssignmentItemDownloadProgressProps = {
	/**
	 * Download progress
	 */
	progress: number,
	/**
	 * Unfilled color of the ProgressCircle component
	 */
	unfilledColor: string,
	/**
	 * Color of the ProgressCircle component
	 */
	tintColor: string
};

/**
 * MaterialsComponentProps
 */
type MaterialsComponentProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,

	t: TTranslationFunction,

	/**
	 * Contents of course materials field
	 */
	materials: string,
	/**
	 * Default styles for different HTML tags
	 */
	tagsStyles: Record<any, any>,
	/**
	 * Default styles for course materials
	 */
	materialsStyles: Record<any, any>,
	/**
	 * Function to set a font style
	 */
	baseFontStyle: Function,
	navigation: NavigationService,
	/**
	 * Handles link press for the HTML component
	 */
	onLinkPress: Function
};

/**
 * TransformLearnTopicViewModelCallback
 */
type TransformLearnTopicViewModelCallback = {
	viewModel: TLearnTopicViewModel,
	topic: LearnTopic
};

/**
 * @class
 * Learn Topic Screen Hooks.
 * Instance name: learnTopicSingleScreenApi
 
   You can use this hook to customize the learn topic screen such as by adding a component by the topic content.
 * @example
 * externalCodeSetup.learnTopicSingleScreenApi.METHOD_NAME
 */
export class LearnTopicSingleScreenHooksApi {
	afterContentRenderer: (
		topic: LearnTopic,
		global: Record<any, any>,
		colors: Record<any, any>,
		navigation: NavigationService
	) => JSX.Element | null = () => null;

	/**
	 * It adds a component after the topic content so you can customize the information to be displayed.
	 * @method
	 * @param {LearnTopicAfterContentRendererProps} renderFunction
	 * @example
	 *  externalCodeSetup.learnTopicSingleScreenApi.setAfterContentRenderer((topicObject, global, colors, navigation) => (
	 *    <TouchableOpacity onPress={() => navigation.navigate("CoursesScreen")}>
	 *     <Text style={{fontSize: 12}}> Tap to go back to courses list</Text>
	 *    </TouchableOpacity>
	 *  ))
	 */
	setAfterContentRenderer = (
		renderFunction: (
			topic: LearnTopic,
			global: Record<any, any>,
			colors: Record<any, any>,
			navigation: NavigationService
		) => JSX.Element | null
	) => {
		this.afterContentRenderer = renderFunction;
	};

	transformTopicActionButtons = (
		TopicButton: JSX.Element,
		showComplete: boolean,
		global: Record<any, any>,
		colors: Record<any, any>,
		topic: TLearnTopicViewModel,
		completing: boolean,
		labels: Record<any, any>,
		handleComplete: Function
	) => TopicButton;

	/**
	 * You can transform the default learn topic action button by replacing it with your preferred action buttons.
	 * For example, you can add an inline button to the topic screen for marking topic completion.
	 * @param {TransformTopicActionButtonsCallback} transformTopicActionButtons
	 * @method
	 * @example <caption> Add more components for topic action </caption>
	 *
	 * externalCodeSetup.learnTopicSingleScreenApi.setTransformTopicActionButtons((
	 *   TopicButton,
	 *   showComplete,
	 *   global,
	 *   colors,
	 *   topic,
	 *   completing,
	 *   labels,
	 *   handleComplete) => {
	 *
	 *   const Buttons =
	 *     <View style={[global.row, { backgroundColor: "#fff" }]}>
	 *
	 *       <View style={{ width: "45%", backgroundColor: "#fff", paddingHorizontal: 20, paddingVertical: 15 }}>
	 *         <AppTouchableOpacity
	 *           style={[
	 *             global.completeTopicButtonW,
	 *             { 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" }}>
	 *         {TopicButton}
	 *       </View>
	 *     </View>
	 *
	 *   return Buttons;
	 * })
	 */

	setTransformTopicActionButtons = (
		transformTopicActionButtons: (
			TopicButton: JSX.Element,
			showComplete: boolean,
			global: Record<any, any>,
			colors: Record<any, any>,
			topic: TLearnTopicViewModel,
			completing: boolean,
			labels: Record<any, any>,
			handleComplete: Function
		) => JSX.Element
	) => {
		this.transformTopicActionButtons = transformTopicActionButtons;
	};

	showMarkAsComplete = (topic: LearnTopic) => true;

	/**
	 * Use this to hide or show the mark as complete component.
	 * @method
	 * @param {showMarkAsCompleteProps} showMarkAsComplete
	 * @example
	 * externalCodeSetup.learnTopicSingleScreenApi.setShowMarkAsComplete((topic) => false);
	 */
	setShowMarkAsComplete = (
		showMarkAsComplete: (topic: LearnTopic) => boolean
	) => {
		this.showMarkAsComplete = showMarkAsComplete;
	};

	PrevNextComponent: React.ComponentType<
		LearnTopicPrevNextComponentProps
	> | null = null;

	/**
	 * You can use this to replace the previous and next buttons on the learn topic single screen if you want to change the default option which always displays the prev/next buttons.
	 * @method
	 * @param {React.ComponentType<LearnTopicPrevNextComponentProps>} PrevNextComponent
	 * @example <caption> Remove previous and next buttons if there is no previous and next objects. Otherwise, return the default previous and next buttons </caption>
	 *
	 * //In custom_code/components/PrevNext.js
	 *
	 * import React from "react";
	 * import { Text, View, StyleSheet } from "react-native";
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import Icon from "@src/components/Icon";
	 * import { shadeColor } from "@src/utils";
	 *
	 * export const onObjectClick = (
	 *    object,
	 *    onQuizClick,
	 *    onTopicClick,
	 *    onLessonClick
	 * ) => {
	 *    if (!!!object) {
	 *        return false;
	 *    }
	 *    switch (object.type) {
	 *        case "quiz":
	 *            onQuizClick(object.parentType, object.parent)(object);
	 *            break;
	 *        case "topic":
	 *            onTopicClick(object, object.parent);
	 *            break;
	 *        case "lesson":
	 *            onLessonClick(object);
	 *            break;
	 *    }
	 * };
	 *
	 * const PrevNext = ({
	 *    global,
	 *    colors,
	 *    t,
	 *	    prevObject,
	 *    nextObject,
	 *    courseId,
	 *    onQuizClick,
	 *    onLessonClick,
	 *    onTopicClick,
	 *    nextLockedAlert
	 * }) => {
	 *
	 *    if (!nextObject && !prevObject) {
	 *        return null;
	 *    }
	 *
	 *    return (
	 *        <View style={[global.row]}>
	 *            <AppTouchableOpacity
	 *                style={[
	 *                    global.wrappedButton,
	 *                    global.wrappedTextButton,
	 *                    { marginRight: 4 }
	 *                ]}
	 *                onPress={() => {
	 *                    if (prevObject !== "disabled") {
	 *                        onObjectClick(prevObject, onQuizClick, onTopicClick, onLessonClick);
	 *                    }
	 *                }}
	 *            >
	 *                <View style={global.row}>
	 *                    <View style={global.linkWithArrow}>
	 *                        <Text
	 *                            style={[
	 *                                global.wrappedTextButtonLabel,
	 *                                {
	 *                                    color:
	 *                                        !!!prevObject || prevObject === "disabled"
	 *                                            ? shadeColor(colors.headerIconColor, 0.4)
	 *                                            : colors.headerIconColor
	 *                                }
	 *                            ]}
	 *                        >
	 *                            {t("lesson:prevButtonText")}
	 *                        </Text>
	 *                    </View>
	 *                </View>
	 *            </AppTouchableOpacity>
	 *
	 *            <AppTouchableOpacity
	 *                style={[global.wrappedButton, global.wrappedTextButton]}
	 *                onPress={() => {
	 *                    if (nextObject !== "disabled") {
	 *                        onObjectClick(nextObject, onQuizClick, onTopicClick, onLessonClick);
	 *                    } else if (typeof nextLockedAlert === "function") {
	 *                        nextLockedAlert();
	 *                    }
	 *                }}
	 *            >
	 *                <View style={global.row}>
	 *                    <View style={global.linkWithArrow}>
	 *                        <Text
	 *                            style={[
	 *                                global.wrappedTextButtonLabel,
	 *                                {
	 *                                    color:
	 *                                        !!!nextObject || nextObject === "disabled"
	 *                                            ? shadeColor(colors.headerIconColor, 0.4)
	 *                                            : colors.headerIconColor
	 *                                }
	 *                            ]}
	 *                        >
	 *                            {t("lesson:nextButtonText")}
	 *                        </Text>
	 *                    </View>
	 *                </View>
	 *            </AppTouchableOpacity>
	 *        </View>
	 *    );
	 * };
	 *
	 * export default PrevNext;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import PrevNextComponent from './components/PrevNext';
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.learnTopicSingleScreenApi.setPrevNextComponent((props) => <PrevNextComponent {...props} />);
	 * }
	 *
	 */
	setPrevNextComponent = (
		PrevNextComponent: React.ComponentType<
			LearnTopicPrevNextComponentProps
		> | null
	) => {
		this.PrevNextComponent = PrevNextComponent;
	};

	LearnTopicTitleComponent: React.ComponentType<
		LearnTopicHeaderProps
	> | null = null;

	/**
	 * You can use this to replace the topic's title component.
	 * For example, you can use this to change the subtitle's color.
	 * @method
	 * @param {React.ComponentType<LearnTopicHeaderProps>} LearnTopicTitleComponent
	 * @example <caption> Change subtitle colors </caption>
	 *
	 * //In custom_code/components/TopicTitle.js...
	 * import React from "react";
	 * import {View, Text} from "react-native";
	 * import Animated from "react-native-reanimated";
	 *
	 * const TopicTitle = ({
	 *  topic,
	 *  global,
	 *  colors,
	 *  paddingTop,
	 *  setHeaderHeight,
	 *  t,
	 *  labels,
	 *  lessonOrder
	 * }) => {
	 *
	 *   const paddingBottom = 14;
	 *
	 *   return (
	 *     <Animated.View
	 *       style={[
	 *        {
	 *          backgroundColor: colors.bodyFrontBg,
	 *          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
	 *         }
	 *       ]}
	 *       onLayout={event => {
	 *         const {height} = event.nativeEvent.layout;
	 *         typeof setHeaderHeight === "function" && setHeaderHeight(height);
	 *       }}
	 *     >
	 *       <Animated.View
	 *         style={{
	 *           flex: 1,
	 *           paddingHorizontal: 20
	 *         }}
	 *       >
	 *         <Animated.Text
	 *           style={[
	 *             global.courseHeaderTitle,
	 *             {marginBottom: 5}
	 *           ]}
	 *         >
	 *           {topic.title}
	 *         </Animated.Text>
	 *
	 *         <View style={global.row}>
	 *           <Text style={[global.courseHeaderSubTitle, {color: "red"}]}>
	 *             {t("lessonTopic:lessoncount", {
	 *               lesson: labels.lesson,
	 *               current: lessonOrder + 1
	 *             })}
	 *           </Text>
	 *           <View
	 *             style={{
	 *               width: 3,
	 *               height: 3,
	 *               marginTop: 2,
	 *               marginLeft: 5,
	 *               marginRight: 4,
	 *               backgroundColor: "#8D8F97",
	 *               borderRadius: 2,
	 *               opacity: 0.45
	 *             }}
	 *           />
	 *             <Text style={[global.courseHeaderSubTitle, {color: "blue"}]}>
	 *               {t("lessonTopic:count", {
	 *                 topic: labels.topic,
	 *                 current: topic.order
	 *               })}
	 *             </Text>
	 *           </View>
	 *         </Animated.View>
	 *       </View>
	 *     </Animated.View>
	 *   );
	 * };
	 *
	 * export default TopicTitle;
	 *
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import TopicTitle from "./components/TopicTitle";
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.learnTopicSingleScreenApi.setLearnTopicTitleComponent(props => <TopicTitle {...props} />)
	 * }
	 */
	setLearnTopicTitleComponent = (
		LearnTopicTitleComponent: React.ComponentType<LearnTopicHeaderProps> | null
	) => {
		this.LearnTopicTitleComponent = LearnTopicTitleComponent;
	};

	LearnTopicScreenHeader: React.ComponentType<
		LearnTopicScreenHeaderProps
	> | null = null;
	/**
	 * You can use this hook to customize the header of the Learn Topic Single Screen which by default, contains the back-to-course button and the previous/next buttons.
	 * @method
	 * @param {React.ComponentType<LearnTopicScreenHeaderProps>} LearnTopicScreenHeader
	 * @example
	 *
	 * //In custom_code/components/LearnTopicHeader.js...
	 *
	 * import React from "react";
	 * import {View, Text} 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,
	 *     topic
	 * }) => {
	 *   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%",
	 *
	 *             backgroundColor: "cyan",
	 *             borderRadius: 20
	 *           }
	 *         ]}
	 *       >
	 *         <View style={[global.headerButtonLeft, headerLeftStyle]}>
	 *           {backToCourse}
	 *         </View>
	 *
	 *         <View>
	 *           <Text>
	 *             {topic.title}
	 *           </Text>
	 *         </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 LearnTopicHeader from "./components/LearnTopicHeader"
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.learnTopicSingleScreenApi.setLearnTopicScreenHeader(props => <LearnTopicHeader {...props} />)
	 * }
	 */
	setLearnTopicScreenHeader = (
		LearnTopicScreenHeader: React.ComponentType<
			LearnTopicScreenHeaderProps
		> | null
	) => {
		this.LearnTopicScreenHeader = LearnTopicScreenHeader;
	};

	VideoProgressionComponent: React.ComponentType<
		LearnTopicVideoProgressionComponentProps
	> | null = null;
	/**
	 * You can use this hook to customize the Video Progression component in the single topic 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 topic
	 * @method
	 * @param {React.ComponentType<LearnTopicVideoProgressionComponentProps>} 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.learnTopicSingleScreenApi.setVideoProgressionComponent(props => {
	 *     const {
	 *       topicVideoStyle,
	 *       controls,
	 *       autoPlay,
	 *       videoCallback,
	 *       url,
	 *       width,
	 *       height,
	 *       global,
	 *       isNavActive,
	 *       topic,
	 *       videoWatched,
	 *       setVideoWatched,
	 *       onCompleteTopicClick
	 *     } = 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 topic as complete?",
	 *           [
	 *             {
	 *               text: "Cancel",
	 *               onPress: () => console.log("Cancel Pressed"),
	 *               style: "cancel"
	 *             },
	 *             { text: "OK", onPress: () => onCompleteTopicClick() }
	 *           ]
	 *         );
	 *       }
	 *
	 *     }
	 *
	 *     return <View style={topicVideoStyle}>
	 *       <AppVideo
	 *         controls={controls}
	 *         autoPlay={autoPlay}
	 *         // videoCallback={videoCallback()}
	 *         videoCallback={customCallback(topic.settings)}
	 *         url={url}
	 *         width={width}
	 *         height={height}
	 *         global={global}
	 *         isNavActive={isNavActive}
	 *       />
	 *     </View>
	 *   })
	 * }
	 *
	 */
	setVideoProgressionComponent = (
		VideoProgressionComponent: React.ComponentType<
			LearnTopicVideoProgressionComponentProps
		> | null
	) => {
		this.VideoProgressionComponent = VideoProgressionComponent;
	};

	AfterMaterialsComponent: React.ComponentType<
		LearnTopicAfterMaterialsComponentProps
	> | null = null;
	/**
	 * You can use this hook to add a component at the bottom of the topic single screen just after the component that displays the materials.
	 * @method
	 * @param {React.ComponentType<LearnTopicAfterMaterialsComponentProps>} AfterMaterialsComponent
	 * @example
	 *
	 * //In custom_code/components/TopicBottomComponent.js...
	 *
	 * import React from "react";
	 * import { View, Text, TouchableOpacity } from "react-native";
	 *
	 * const TopicBottomComponent = props => {
	 *
	 *     const {
	 *         colors,
	 *         course,
	 *         materials,
	 *         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 TopicBottomComponent;
	 *
	 *  //In custom_code/index.js...
	 *
	 *  ...
	 *
	 * import TopicBottomComponent from "./components/TopicBottomComponent";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.learnTopicSingleScreenApi.setAfterMaterialsComponent(props => <TopicBottomComponent {...props}/>)
	 * }
	 */
	setAfterMaterialsComponent = (
		AfterMaterialsComponent: React.ComponentType<
			LearnTopicAfterMaterialsComponentProps
		> | null
	) => {
		this.AfterMaterialsComponent = AfterMaterialsComponent;
	};

	LearnTopicActionComponent: React.ComponentType<
		LearnTopicActionComponentProps
	> | null = 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<LearnTopicActionComponentProps>} LearnTopicActionComponent
	 * @example
	 *
	 * //In custom_code/components/LearnTopicActionComponent.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 LearnTopicActionComponent = ({
	 *   showComplete,
	 *   global,
	 *   colors,
	 *   t,
	 *   topicVM,
	 *   onCompleteTopicClick,
	 *   completing,
	 *   completeDisabled
	 * }) => (
	 *   <AuthWrapper actionOnGuestLogin={"hide"}>
	 *     {showComplete && (
	 *       <View
	 *         style={[
	 *           global.row,
	 *           {
	 *             backgroundColor: colors.bodyFrontBg,
	 *             borderTopColor: colors.borderColor
	 *           },
	 *           global.learnTopicActionButtonContainer
	 *         ]}
	 *       >
	 *         <AppTouchableOpacity
	 *           style={[
	 *             {flex: 1},
	 *             {
	 *               opacity: !topicVM.completed && completeDisabled ? 0.5 : 1,
	 *               backgroundColor: !topicVM.completed
	 *                 ? colors.primaryButtonBg
	 *                 : colors.bodyFrontBg
	 *             },
	 *             global.completeTopicButtonW
	 *           ]}
	 *           disabled={topicVM.completed || completeDisabled}
	 *           onPress={onCompleteTopicClick}
	 *         >
	 *           <View style={global.row}>
	 *             <View style={global.linkWithArrow}>
	 *               {!topicVM.completed ? (
	 *                 completing && (
	 *                   <ActivityIndicator
	 *                     animating={true}
	 *                     color={colors.primaryButtonColor}
	 *                     size="small"
	 *                     style={global.learnTopicButtonLoadingIcon}
	 *                   />
	 *                 )
	 *               ) : (
	 *                 <Icon
	 *                   webIcon={""}
	 *                   icon={{fontIconName: "check", weight: 200}}
	 *                   styles={global.learnTopicActionCompleteIcon}
	 *                 />
	 *               )}
	 *               <Text
	 *                 style={[
	 *                   {
	 *                     marginLeft: 10,
	 *                     color: !topicVM.completed
	 *                       ? colors.primaryButtonColor
	 *                       : isColorDark(colors.bodyFrontBg)
	 *                         ? "white"
	 *                         : "black"
	 *                   },
	 *                   global.completeTopicButton
	 *                 ]}
	 *               >
	 *                 {t(
	 *                   topicVM.completed
	 *                     ? "lessonTopic:completed"
	 *                     : "lessonTopic:markAsComplete"
	 *                 )}
	 *               </Text>
	 *             </View>
	 *           </View>
	 *         </AppTouchableOpacity>
	 *       </View>
	 *     )}
	 *   </AuthWrapper>
	 * );
	 *
	 * export default LearnTopicActionComponent;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import LearnTopicActionComponent from "./components/LearnTopicActionComponent";
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setLearnTopicActionComponent(props => <LearnTopicActionComponent {...props} />)
	 * }
	 */
	setLearnTopicActionComponent = (
		LearnTopicActionComponent: React.ComponentType<
			LearnTopicActionComponentProps
		> | null
	) => {
		this.LearnTopicActionComponent = LearnTopicActionComponent;
	};

	OfflineComponent: React.ComponentType<
		LearnTopicOfflineComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the component that displays a "This content is not available offline" message if a webview is used for rendering the topic content while the device is offline.
	 * @method
	 * @param {React.ComponentType<LearnTopicOfflineComponentProps>} OfflineComponent
	 * @example
	 *
	 * ...
	 *
	 * import EmptyList from "@src/components/EmptyList";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setOfflineComponent(
	 *         ({containerStyle, t, global, emptyListStyle}) => (
	 *             <View style={containerStyle}>
	 *                 <EmptyList
	 *                     emptyText={{
	 *                         title: t("common:contentOfflineMessage"),
	 *                         icon: {fontIconName: "wifi-slash", weight: 400}
	 *                     }}
	 *                     global={global}
	 *                     style={emptyListStyle}
	 *                 />
	 *             </View>
	 *         )
	 *     );
	 * }
	 */
	setOfflineComponent = (
		OfflineComponent: React.ComponentType<
			LearnTopicOfflineComponentProps
		> | null
	) => {
		this.OfflineComponent = OfflineComponent;
	};

	WebViewContentComponent: React.ComponentType<
		LearnTopicWebViewContentComponentProps
	> | null = null;

	/**
	 * You can use this hook to replace the webview being used in the topic content.
	 * For example, you can choose to replace it with the default react-native webview.
	 * @method
	 * @param {React.ComponentType<LearnTopicWebViewContentComponentProps>} WebViewContentComponent
	 * @example
	 *
	 * ...
	 *
	 * import WebViewWithMore from "@src/components/WebViewWithMore";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setWebViewContentComponent(
	 *         ({
	 *             online,
	 *             t,
	 *             onShouldStartLoadWithRequest,
	 *             height,
	 *             source,
	 *             global,
	 *             colors,
	 *             ModalHeaderComponent
	 *         }) => (
	 *             <WebViewWithMore
	 *                 online={online}
	 *                 t={t}
	 *                 onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
	 *                 height={height}
	 *                 source={source}
	 *                 global={global}
	 *                 colors={colors}
	 *                 ModalHeaderComponent={ModalHeaderComponent}
	 *             />
	 *         )
	 *     );
	 * }
	 */
	setWebViewContentComponent = (
		WebViewContentComponent: React.ComponentType<
			LearnTopicWebViewContentComponentProps
		> | null
	) => {
		this.WebViewContentComponent = WebViewContentComponent;
	};

	LearnTopicMaterialsSectionTitle: React.ComponentType<
		LearnTopicMaterialsSectionTitleProps
	> | null = null;

	/**
	 * You can use this hook to customize the component that displays the "Materials" text.
	 * @method
	 * @param {React.ComponentType<LearnTopicMaterialsSectionTitleProps>} LearnTopicMaterialsSectionTitle
	 * @example
	 *
	 * ...
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *   externalCodeSetup.learnTopicSingleScreenApi.setLearnTopicMaterialsSectionTitle(
	 *       ({global, t}) => (
	 *           <Text
	 *               style={{
	 *                   ...global.courseRoundBoxTitleAbove,
	 *                   marginBottom: 20
	 *               }}
	 *           >
	 *               {t("lesson:materials")}
	 *            </Text>
	 *       )
	 *   );
	 * }
	 */
	setLearnTopicMaterialsSectionTitle = (
		LearnTopicMaterialsSectionTitle: React.ComponentType<
			LearnTopicMaterialsSectionTitleProps
		> | null
	) => {
		this.LearnTopicMaterialsSectionTitle = LearnTopicMaterialsSectionTitle;
	};

	AssignmentsHeader: React.ComponentType<AssignmentsHeaderProps> | null = null;

	/**
	 *
	 * You can use this hook to customize the assignments title and the component that displays the total approved assignments.
	 * @method
	 * @param {React.ComponentType<AssignmentsHeaderProps>} AssignmentsHeader
	 * @example
	 *
	 * ...
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setAssignmentsHeader(
	 *         ({global, t, totalAssignments, approved}) => (
	 *             <View style={{...global.row, flex: 1, marginBottom: 15}}>
	 *                 <Text style={[global.assignmentHeading, {flex: 1}]}>
	 *                     {t("assignment:heading")}
	 *                 </Text>
	 *                 {totalAssignments !== 0 && (
	 *                     <Text style={[global.assignmentDesc]}>
	 *                         {t("assignment:approvedOutOfTotal", {
	 *                             total: totalAssignments,
	 *                             approved
	 *                         })}
	 *                     </Text>
	 *                 )}
	 *             </View>
	 *         )
	 *     );
	 * }
	 */
	setAssignmentsHeader = (
		AssignmentsHeader: React.ComponentType<AssignmentsHeaderProps> | null
	) => {
		this.AssignmentsHeader = AssignmentsHeader;
	};

	AssignmentItemIcon: React.ComponentType<
		AssignmentItemIconProps
	> | null = null;

	/**
	 * You can use this to change the icon beside the assignment title.
	 * For example, you can use this to remove or modify the default icon.
	 * @method
	 * @param {React.ComponentType<AssignmentItemIconProps>} AssignmentItemIcon
	 * @example
	 *
	 * ...
	 *
	 * import Icon from "@src/components/Icon";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setAssignmentItemIcon(
	 *         ({icon, styles}) => <Icon icon={icon} styles={styles} />
	 *     );
	 * }
	 */
	setAssignmentItemIcon = (
		AssignmentItemIcon: React.ComponentType<AssignmentItemIconProps> | null
	) => {
		this.AssignmentItemIcon = AssignmentItemIcon;
	};

	AssignmentItemTitle: React.ComponentType<
		AssignmentItemTitleProps
	> | null = null;

	/**
	 * You can use this to customize the AssignmentItemTitle component.
	 * For example, you can use this to change the font color or size of the title.
	 * @method
	 * @param {React.ComponentType<AssignmentItemTitleProps>} AssignmentItemTitle
	 * @example
	 *
	 * ...
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setAssignmentItemTitle(({
	 *         title,
	 *         style
	 *     }) => <Text style={style}>{title}</Text>)
	 * }
	 */
	setAssignmentItemTitle = (
		AssignmentItemTitle: React.ComponentType<AssignmentItemTitleProps> | null
	) => {
		this.AssignmentItemTitle = AssignmentItemTitle;
	};

	AssignmentItemStatus: React.ComponentType<
		AssignmentItemStatusProps
	> | null = null;

	/**
	 * You can use this to customize the AssignmentItemStatus component.
	 * @method
	 * @param {React.ComponentType<AssignmentItemStatusProps>} AssignmentItemStatus
	 * @example
	 *
	 * ...
	 *
	 * import {BubbleIcon} from "@src/components/BubbleIcon";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setAssignmentItemStatus(
	 *         ({global, text, containerStyle, textStyle}) => (
	 *             <BubbleIcon
	 *                 {...{
	 *                     global,
	 *                     text,
	 *                     containerStyle,
	 *                     textStyle
	 *                 }}
	 *             />
	 *         )
	 *     );
	 * }
	 */
	setAssignmentItemStatus = (
		AssignmentItemStatus: React.ComponentType<AssignmentItemStatusProps> | null
	) => {
		this.AssignmentItemStatus = AssignmentItemStatus;
	};

	AssignmentItemComment: React.ComponentType<
		AssignmentItemCommentProps
	> | null = null;

	/**
	 * You can use this to customize the AssignmentItemComment button.
	 * @method
	 * @param {React.ComponentType<AssignmentItemCommentProps>} AssignmentItemComment
	 * @example
	 *
	 * ...
	 *
	 * import AssignmentCommentButton from "@src/components/Course/Assignment/AssignmentCommentButton";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setAssignmentItemComment(
	 *         ({
	 *             pressHandler,
	 *             tintColor,
	 *             containerStyle,
	 *             count,
	 *             size,
	 *             global,
	 *             lightMode
	 *         }) => (
	 *             <AssignmentCommentButton
	 *                 {...{
	 *                     pressHandler,
	 *                     tintColor,
	 *                     containerStyle,
	 *                     count,
	 *                     size,
	 *                     global,
	 *                     lightMode
	 *                 }}
	 *             />
	 *         )
	 *     );
	 * }
	 */
	setAssignmentItemComment = (
		AssignmentItemComment: React.ComponentType<
			AssignmentItemCommentProps
		> | null
	) => {
		this.AssignmentItemComment = AssignmentItemComment;
	};

	AssignmentItemDownload: React.ComponentType<
		AssignmentItemDownloadProps
	> | null = null;

	/**
	 * You can use this to customize the AssignmentItemDownload button.
	 * For example, you can change the icon and add a confirmation modal before allowing the user to download the assignment file.
	 * @method
	 * @param {React.ComponentType<AssignmentItemDownloadProps>} AssignmentItemDownload
	 * @example
	 *
	 * ...
	 *
	 * import AssignmentDownloadButton from "@src/components/Course/Assignment/AssignmentDownloadButton";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setAssignmentItemDownload(
	 *         ({pressHandler, tintColor, containerStyle, size, global, lightMode}) => (
	 *             <AssignmentDownloadButton
	 *                 {...{
	 *                     pressHandler,
	 *                     tintColor,
	 *                     containerStyle,
	 *                     size,
	 *                     global,
	 *                     lightMode
	 *                 }}
	 *             />
	 *         )
	 *     );
	 * }
	 *
	 */
	setAssignmentItemDownload = (
		AssignmentItemDownload: React.ComponentType<
			AssignmentItemDownloadProps
		> | null
	) => {
		this.AssignmentItemDownload = AssignmentItemDownload;
	};

	AssignmentItemDownloadProgress: React.ComponentType<
		AssignmentItemDownloadProgressProps
	> | null = null;

	/**
	 * You can use this to customize the progress indicator which is showed when the assignment item is being downloaded.
	 * @method
	 * @param {React.ComponentType<AssignmentItemDownloadProgressProps>} AssignmentItemDownloadProgress
	 * @example
	 *
	 * ...
	 *
	 * import AssignmentDownloadProgress from "@src/components/Course/Assignment/AssignmentDownloadProgress";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setAssignmentItemDownloadProgress(
	 *         ({progress, unfilledColor, tintColor}) => (
	 *             <AssignmentDownloadProgress
	 *                 {...{
	 *                     progress,
	 *                     unfilledColor,
	 *                     tintColor
	 *                 }}
	 *             />
	 *         )
	 *     );
	 * }
	 *
	 */
	setAssignmentItemDownloadProgress = (
		AssignmentItemDownloadProgress: React.ComponentType<
			AssignmentItemDownloadProgressProps
		> | null
	) => {
		this.AssignmentItemDownloadProgress = AssignmentItemDownloadProgress;
	};

	MaterialsComponent: React.ComponentType<
		MaterialsComponentProps
	> | null = null;

	/**
	 * You can use this to customize the component that displays the materials of the topic.
	 * @method
	 * @param {React.ComponentType<MaterialsComponentProps>} MaterialsComponent
	 * @example
	 *
	 * ...
	 *
	 * import {
	 *   Dimensions,
	 * } from "react-native";
	 * import HTML from "react-native-render-html";
	 * import {RenderListPrefix} from "@src/components/Course/CourseMaterials"
	 * const ent = require("ent");
	 * const DEVICE_WIDTH = Dimensions.get("window").width;
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.learnTopicSingleScreenApi.setMaterialsComponent((props) => {
	 *
	 *         const {
	 *             tagsStyles,
	 *             materialsStyles,
	 *             baseFontStyle,
	 *             materials,
	 *             onLinkPress,
	 *             global,
	 *             colors
	 *         } = props;
	 *
	 *         return (
	 *                 <HTML
	 *                     tagsStyles={{...tagsStyles, ...materialsStyles}}
	 *                     baseFontStyle={baseFontStyle(15)}
	 *                     html={ent.decode(materials)}
	 *                     imagesMaxWidth={DEVICE_WIDTH - 32}
	 *                     onLinkPress={onLinkPress}
	 *                     listsPrefixesRenderers={{
	 *                         ul: (attrib, children, styles, passProps) => (
	 *                             <RenderListPrefix
	 *                                 parent={"ul"}
	 *                                 colors={colors}
	 *                                 global={global}
	 *                                 passProps={passProps}
	 *                             />
	 *                         ),
	 *                         ol: (attrib, children, styles, passProps) => (
	 *                             <RenderListPrefix
	 *                                 parent={"ol"}
	 *                                 colors={colors}
	 *                                 global={global}
	 *                                 passProps={passProps}
	 *                             />
	 *                         )
	 *                     }}
	 *                 />
	 *             )
	 *     });
	 * }
	 */
	setMaterialsComponent = (
		MaterialsComponent: React.ComponentType<MaterialsComponentProps> | null
	) => {
		this.MaterialsComponent = MaterialsComponent;
	};

	learnTopicViewModelFilter = (
		viewModel: TLearnTopicViewModel | Record<any, any>
	) => viewModel;

	/**
	 * Sets the callback function that can change an existing learn topic view model object.
	 * @method
	 * @param {TransformLearnTopicViewModelCallback} learnTopicViewModelFilter
	 * @example <caption>Remove the native blocks in a lesson topic</caption>
	 * externalCodeSetup.learnTopicSingleScreenApi.setLearnTopicViewModelFilter((viewModel, topic) => {
	 *     return {
	 *         ...viewModel,
	 *         contentNative: []
	 *     }
	 * })
	 */
	setLearnTopicViewModelFilter = (
		learnTopicViewModelFilter: (
			viewModel: TLearnTopicViewModel | Record<any, any>
		) => TLearnTopicViewModel | Record<any, any>
	) => {
		this.learnTopicViewModelFilter = learnTopicViewModelFilter;
	};
}