Source

externalCode/screenHook.js

import * as React from "react";
import {Image} from "react-native";

/**
 * @typedef {Object} BackButtonComponentProps
 * @property {NavigationService} navigation
 * @property {String} headerColor
 * @property {RNStyleValue} styles Back button default styling
 * @property {Boolean|undefined} delay Returns `true` for default setting is to delay rendering
 * @property {Boolean|undefined} withUnderlay Returns `true` if button should be rendered with an underlay
 * @property {String} text Default text
 * @property {Record<any,any>} textStyle Default text style
 * @property {Number} textMaxWidth Defaul text max width
 * @property {Record<any,any>} colors App colors
 * @property {Function} afterAction Action after the screen has navigated to the previous screen
 * @property {Function|undefined}  handlePressParam Default behavior when button is pressed
 * @property {Object|undefined} containerStyle Container style
 * @property {String|undefined} fontIconName Font name of icon
 * @property {Number|undefined} fontIconWeight Font weight of icon
 */

/**
 * @typedef {Object} ProgressListItemComponentProps
 * @property {Object} item
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {Function} onPress onPress handler
 * @property {Boolean} allowNavigation
 */

/**
 * @typedef {Object} ProgressCircleComponentProps
 * @param {boolean} isCompleted
 * @param {number} progress,
 * @param {Object} colors,
 * @param {number} size,
 * @param {number} thickness,
 * @param {string} unfilledColor,
 * @param {string} progressColor,
 * @param {LocalImageSource} checkIcon
 */

/**
 * @typedef {Object} ProgressBarComponentProps
 * @param {number} progress
 * @param {number} width
 * @param {number} height
 * @param {string} color
 * @param {string} unfilledColor
 * @param {RNStyleValue} style
 */

/**
 * @typedef {Function} AssetFilterCallback
 * @param {string} path
 * @param {LocalImageSource} source
 * @returns {LocalImageSource}
 */

/**
 * @typedef {Function} TransformContentHeadersCallback
 * @param {Object} headers
 * @param {String} rootSiteUrl
 * @param {String} url
 * @param {String} accessToken
 * @return {Object} - New headers object
 */

/**
 * @typedef {Object} MoreScreenRendererProps
 * @property {Object} screenProps
 * @property {NavigationService} navigation
 * @property {Object} settings App settings
 * @property {MemberViewModel} user
 * @property {Object} menuSettings Information about the menu such as items in the tab bar and in the more screen
 * @property {Object} auth Logged-in user information
 * @property {Function} onMenuItemPress Default navigation function or what was set in moreScreenApi.navigationHandler hook
 * @property {Object} sections Menu items in more screen
 */

/**
 * @class
 * Screen Hooks.
 * Instance name: screenHooksApi
  
   You can use these hooks to customize different screen options such as hiding the user’s profile menu in the More screen, hiding the admin/author component and more.
 * @example
 * externalCodeSetup.screenHooksApi.METHOD_NAME
 */
export class ScreenHooksApi {
	/* Version control screen */

	versionControlIconRenderer = null;
	/**
	 * Renders a component above the title on the Version control screen
	 * @deprecated
	 */
	setVersionControlIconRenderer = asset => {
		this.versionControlIconRenderer = asset;
	};

	/* SocialLoginScreen */

	// default order in which the soical login buttons are displayed
	socialLoginButtonsOrder = ["apple", "twitter", "facebook", "google"];

	/**
	 * Rearrange social login buttons
	 * @deprecated
	 * @param {Array<string>} list
	 */

	setSocialLoginButtonsOrder = newOrder => {
		this.socialLoginButtonsOrder = newOrder;
	};

	/**
	 * @ignore
	 */
	addHomeScreenWidget = (widgetId, component, options) => {
		console.warn("homescreen is obsolete, use app pages instead");
	};

	notificationsWidgetIconRenderer = null;

	//UsersWidget icon in HomeScreen
	usersWidgetIconRenderer = null;

	//Activities icon in HomeScreen
	activitiesWidgetIconRenderer = null;

	// Always show Guthenberg blocks
	forceShowBlocks = false;

	/**
	 * You can set it to `true` to force using Gutenberg blocks on LearnDash screens. Default is `false`.
	 * @method
	 * @param {Boolean} forceShowBlocks
	 * @example
	 * externalCodeSetup.screenHooksApi.forceShowBlocks(true)
	 */
	setForceShowBlocks = forceShowBlocks => {
		this.forceShowBlocks = forceShowBlocks;
	};

	musicController = null;

	courseSingleHideAdmin = false;
	/**
	 * You can use it to hide the admin/author component on the Single Course screen.
	 * @method
	 * @example
	 * externalCodeSetup.screenHooksApi.hideCourseSingleAdmin()
	 */
	hideCourseSingleAdmin = () => {
		this.courseSingleHideAdmin = true;
	};

	// MoreScreen

	customMoreScreenRenderer = null;
	/**
	 * Lets you provide your own component for rendering More Screen content
	 * @method
	 * @param {MoreScreenRendererProps} MoreScreenRendererProps
	 * @example
	 * externalCodeSetup.screenHooksApi.setCustomMoreScreenRenderer((props) => {
	 *
	 *   const {user} = props;
	 *
	 *    if (user.followers < 100){
	 *      return <View style={{flex: 1, alignSelf: "center", justifyContent: "center"}}>
	 *
	 *          <Text> More features available when you reach 100 followers!</Text>
	 *
	 *      </View>
	 *    }
	 *
	 *    //Return a more screen here as an else statement...
	 *
	 * });
	 */
	setCustomMoreScreenRenderer = renderer => {
		this.customMoreScreenRenderer = renderer;
	};
	// Determines whether profile menu item appears on MoreScreen
	moreScreenShowProfile = true;
	/**
	 * Hides the user's profile menu item in the "More" Screen
	 * @method
	 * @example
	 * externalCodeSetup.screenHooksApi.disableProfileInMoreScreen();
	 */
	disableProfileInMoreScreen = () => {
		this.moreScreenShowProfile = false;
	};

	// Sets header max height
	setMusicController = component => (this.musicController = component);

	// Back Button
	BackButtonComponent = null;

	/**
	 * Replaces the back button component in all app screens
	 * @method
	 * @param {BackButtonComponentProps} BackButtonComponent
	 * @example
	 * externalCodeSetup.screenHooksApi.setBackButtonRenderer(props => {
	 *  return <Button title="Back" onPress={() => props.navigation.goBack()} />
	 * });
	 *
	 * @example <caption> Navigate to a user's profile </caption>
	 *
	 * //In custom_code/components/BackButton.js
	 *
	 * import React from "react";
	 * import { Button } from "react-native";
	 * import { useSelector } from "react-redux";
	 * import {CommonActions} from "@react-navigation/native";
	 *
	 * const BackButton = (props) => {
	 *    const state = useSelector((state) => state);
	 *
	 *    //Get a user object from the redux state..
	 *    //In this case, redirect to own profile
	 *    const user = state.user.userObject;
	 *
	 *    const toProfile = () => {
	 *
	 *        //Modify back button in a specific screen only. In this case, "Books" screen
	 *        if (props.navigation.state?.params?.item?.label === "Books") {
	 *            props.navigation.dispatch(
	 *                CommonActions.navigate({
	 *                    name: "ProfileScreen",
	 *                    params: { user: user }
	 *                })
	 *            );
	 *        } else {
	 *            props.navigation.goBack()
	 *        }
	 *
	 *    }
	 *
	 *    return <Button title="Back" onPress={() => toProfile()} />
	 * }
	 *
	 * export default BackButton;
	 *
	 * //In custom_code/index.js
	 *
	 * import BackButton from "./components/BackButton";
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.screenHooksApi.setBackButtonRenderer(props => <BackButton {...props} />);
	 * }
	 */
	setBackButtonRenderer = BackButtonComponent => {
		this.BackButtonComponent = BackButtonComponent;
	};

	// filters and changes assets "require"
	assetFilter = (path, required) => required;

	/**
	 * You can use this to replace the user and lock icon in the "username or email" field and "password" field in the login screen.
	 * @method
	 * @param {AssetFilterCallback} assetFilter
	 * @example
	 * externalCodeSetup.screenHooksApi.setAssetFilter((path, source) => {
	 *  if (path === "../assets/img/user.png") {
	 *    return require("../assets/img/about.png")
	 *  }
	 *  return source
	 * })
	 */
	setAssetFilter = assetFilter => {
		this.assetFilter = assetFilter;
	};

	ProgressListItemComponent = null;
	/**
	 * Overrides the progress item component used in certain screens such as Course Quizzes Screen.
	 * @method
	 * @param {React.ComponentType<ProgressListItemComponentProps>} ProgressListItemComponent
	 * @example
	 * externalCodeSetup.screenHooksApi.setProgressListItemComponent(props => {
	 *
	 *   const {item} = props;
	 *
	 *    return <View style={{margin: 10}}>
	 *      <Text>{item.title}</Text>
	 *      <Text>{item.author.name}</Text>
	 *      <Text>{item.link}</Text>
	 *    </View>
	 * })
	 */
	setProgressListItemComponent = ProgressListItemComponent =>
		(this.ProgressListItemComponent = ProgressListItemComponent);

	ProgressCircleComponent = null;
	/**
	 * @ignore
	 * Reason for ignore: ProgressCircleComponent is only used in CourseMenu.js but CourseMenu.js is not being used anywhere
	 * Custom component for rendering progress circle on items on Learhdash related screens, like lesson or topic item
	 * @method
	 * @param {React.ComponentType<ProgressCircleComponentProps>} ProgressCircleComponent
	 */
	setProgressCircleComponent = ProgressCircleComponent => {
		this.ProgressCircleComponent = ProgressCircleComponent;
	};

	ProgressBarComponent = null;
	/**
	 * @ignore
	 * Reason for ignore: ProgressBarComponent is not being used anywhere
	 * Custom component for rendering progress bar on courses
	 * @method
	 * @param {React.ComponentType<ProgressBarComponentProps>} ProgressBarComponent
	 */
	setProgressBarComponent = ProgressBarComponent =>
		(this.ProgressBarComponent = ProgressBarComponent);

	buildEmbedUrlHeaders = (headers, rootSiteUrl, url, accessToken) => headers;

	/**
	 * If Gutenberg blocks are not used, then the course, lesson, topic and blog content fallbacks to show html to WebView.
	 * Use this method to pass additional headers to WebView if needed.
	 * @method
	 * @param {TransformContentHeadersCallback} buildEmbedUrlHeaders
	 * @example
	 * externalCodeSetup.screenHooksApi.setBuildEmbedUrlHeaders(props => {
	 *   return {
	 *    ...props,
	 *    customHeader: "customHeader"
	 *   }
	 * })
	 */
	setBuildEmbedUrlHeaders = buildEmbedUrlHeaders => {
		this.buildEmbedUrlHeaders = buildEmbedUrlHeaders;
	};

	// Courses Widget Wrapper Switch set Count
	wrapperSwitchCountCoursesWidget = count => count;
	/**
	 * By default, the course widget component uses horizontal ScrollView if the total count of courses is equal or greater than 3.
	 * You can use this hook to set if the app will wrap the courses with horizontal ScrollView or just a View component.
	 * For example, if `wrapperSwitchCountCoursesWidget` is set to `1` while total count of courses is `10`, then the app will use the View component to wrap the widget.
	 * @method
	 * @param {Number} wrapperSwitchCountCoursesWidget
	 * @example
	 * externalCodeSetup.screenHooksApi.setWrapperSwitchCountCoursesWidget(1)
	 */
	setWrapperSwitchCountCoursesWidget = wrapperSwitchCountCoursesWidget =>
		(this.wrapperSwitchCountCoursesWidget = wrapperSwitchCountCoursesWidget);
}