diff --git a/src/components/Screens/BasicLoadingScreen.js b/src/components/Screens/BasicLoadingScreen.js
index 01ad378..2b21eb3 100644
--- a/src/components/Screens/BasicLoadingScreen.js
+++ b/src/components/Screens/BasicLoadingScreen.js
@@ -3,6 +3,7 @@
import * as React from 'react';
import {View} from 'react-native';
import {ActivityIndicator, withTheme} from 'react-native-paper';
+import type {CustomTheme} from '../../managers/ThemeManager';
/**
* Component used to display a header button
@@ -10,28 +11,29 @@ import {ActivityIndicator, withTheme} from 'react-native-paper';
* @param props Props to pass to the component
* @return {*}
*/
-function BasicLoadingScreen(props) {
- const {colors} = props.theme;
- let position = undefined;
- if (props.isAbsolute !== undefined && props.isAbsolute)
- position = 'absolute';
+function BasicLoadingScreen(props: {
+ theme: CustomTheme,
+ isAbsolute: boolean,
+}): React.Node {
+ const {theme, isAbsolute} = props;
+ const {colors} = theme;
+ let position;
+ if (isAbsolute != null && isAbsolute) position = 'absolute';
- return (
-
-
-
- );
+ return (
+
+
+
+ );
}
export default withTheme(BasicLoadingScreen);
diff --git a/src/components/Screens/ErrorView.js b/src/components/Screens/ErrorView.js
index 141181c..3383c7a 100644
--- a/src/components/Screens/ErrorView.js
+++ b/src/components/Screens/ErrorView.js
@@ -2,191 +2,189 @@
import * as React from 'react';
import {Button, Subheading, withTheme} from 'react-native-paper';
-import {StyleSheet, View} from "react-native";
-import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
+import {StyleSheet, View} from 'react-native';
+import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import i18n from 'i18n-js';
-import {ERROR_TYPE} from "../../utils/WebData";
import * as Animatable from 'react-native-animatable';
+import {StackNavigationProp} from '@react-navigation/stack';
+import {ERROR_TYPE} from '../../utils/WebData';
+import type {CustomTheme} from '../../managers/ThemeManager';
-type Props = {
- navigation: Object,
- route: Object,
- errorCode: number,
- onRefresh: Function,
- icon: string,
- message: string,
- showRetryButton: boolean,
-}
-
-type State = {
- refreshing: boolean,
-}
-
-class ErrorView extends React.PureComponent {
-
- colors: Object;
-
- message: string;
- icon: string;
-
- showLoginButton: boolean;
-
- static defaultProps = {
- errorCode: 0,
- icon: '',
- message: '',
- showRetryButton: true,
- }
-
- state = {
- refreshing: false,
- };
-
- constructor(props) {
- super(props);
- this.colors = props.theme.colors;
- this.icon = "";
- }
-
- generateMessage() {
- this.showLoginButton = false;
- if (this.props.errorCode !== 0) {
- switch (this.props.errorCode) {
- case ERROR_TYPE.BAD_CREDENTIALS:
- this.message = i18n.t("errors.badCredentials");
- this.icon = "account-alert-outline";
- break;
- case ERROR_TYPE.BAD_TOKEN:
- this.message = i18n.t("errors.badToken");
- this.icon = "account-alert-outline";
- this.showLoginButton = true;
- break;
- case ERROR_TYPE.NO_CONSENT:
- this.message = i18n.t("errors.noConsent");
- this.icon = "account-remove-outline";
- break;
- case ERROR_TYPE.TOKEN_SAVE:
- this.message = i18n.t("errors.tokenSave");
- this.icon = "alert-circle-outline";
- break;
- case ERROR_TYPE.BAD_INPUT:
- this.message = i18n.t("errors.badInput");
- this.icon = "alert-circle-outline";
- break;
- case ERROR_TYPE.FORBIDDEN:
- this.message = i18n.t("errors.forbidden");
- this.icon = "lock";
- break;
- case ERROR_TYPE.CONNECTION_ERROR:
- this.message = i18n.t("errors.connectionError");
- this.icon = "access-point-network-off";
- break;
- case ERROR_TYPE.SERVER_ERROR:
- this.message = i18n.t("errors.serverError");
- this.icon = "server-network-off";
- break;
- default:
- this.message = i18n.t("errors.unknown");
- this.icon = "alert-circle-outline";
- break;
- }
- this.message += "\n\nCode " + this.props.errorCode;
- } else {
- this.message = this.props.message;
- this.icon = this.props.icon;
- }
-
- }
-
- getRetryButton() {
- return ;
- }
-
- goToLogin = () => {
- this.props.navigation.navigate("login",
- {
- screen: 'login',
- params: {nextScreen: this.props.route.name}
- })
- };
-
- getLoginButton() {
- return ;
- }
-
- render() {
- this.generateMessage();
- return (
-
-
-
-
-
-
- {this.message}
-
- {this.props.showRetryButton
- ? (this.showLoginButton
- ? this.getLoginButton()
- : this.getRetryButton())
- : null}
-
-
- );
- }
-}
+type PropsType = {
+ navigation: StackNavigationProp,
+ theme: CustomTheme,
+ route: {name: string},
+ onRefresh?: () => void,
+ errorCode?: number,
+ icon?: string,
+ message?: string,
+ showRetryButton?: boolean,
+};
const styles = StyleSheet.create({
- outer: {
- height: '100%',
- },
- inner: {
- marginTop: 'auto',
- marginBottom: 'auto',
- },
- iconContainer: {
- marginLeft: 'auto',
- marginRight: 'auto',
- marginBottom: 20
- },
- subheading: {
- textAlign: 'center',
- paddingHorizontal: 20
- },
- button: {
- marginTop: 10,
- marginLeft: 'auto',
- marginRight: 'auto',
- }
+ outer: {
+ height: '100%',
+ },
+ inner: {
+ marginTop: 'auto',
+ marginBottom: 'auto',
+ },
+ iconContainer: {
+ marginLeft: 'auto',
+ marginRight: 'auto',
+ marginBottom: 20,
+ },
+ subheading: {
+ textAlign: 'center',
+ paddingHorizontal: 20,
+ },
+ button: {
+ marginTop: 10,
+ marginLeft: 'auto',
+ marginRight: 'auto',
+ },
});
+class ErrorView extends React.PureComponent {
+ static defaultProps = {
+ onRefresh: (): void => null,
+ errorCode: 0,
+ icon: '',
+ message: '',
+ showRetryButton: true,
+ };
+
+ message: string;
+
+ icon: string;
+
+ showLoginButton: boolean;
+
+ constructor(props: PropsType) {
+ super(props);
+ this.icon = '';
+ }
+
+ getRetryButton(): React.Node {
+ const {props} = this;
+ return (
+
+ );
+ }
+
+ getLoginButton(): React.Node {
+ return (
+
+ );
+ }
+
+ goToLogin = () => {
+ const {props} = this;
+ props.navigation.navigate('login', {
+ screen: 'login',
+ params: {nextScreen: props.route.name},
+ });
+ };
+
+ generateMessage() {
+ const {props} = this;
+ this.showLoginButton = false;
+ if (props.errorCode !== 0) {
+ switch (props.errorCode) {
+ case ERROR_TYPE.BAD_CREDENTIALS:
+ this.message = i18n.t('errors.badCredentials');
+ this.icon = 'account-alert-outline';
+ break;
+ case ERROR_TYPE.BAD_TOKEN:
+ this.message = i18n.t('errors.badToken');
+ this.icon = 'account-alert-outline';
+ this.showLoginButton = true;
+ break;
+ case ERROR_TYPE.NO_CONSENT:
+ this.message = i18n.t('errors.noConsent');
+ this.icon = 'account-remove-outline';
+ break;
+ case ERROR_TYPE.TOKEN_SAVE:
+ this.message = i18n.t('errors.tokenSave');
+ this.icon = 'alert-circle-outline';
+ break;
+ case ERROR_TYPE.BAD_INPUT:
+ this.message = i18n.t('errors.badInput');
+ this.icon = 'alert-circle-outline';
+ break;
+ case ERROR_TYPE.FORBIDDEN:
+ this.message = i18n.t('errors.forbidden');
+ this.icon = 'lock';
+ break;
+ case ERROR_TYPE.CONNECTION_ERROR:
+ this.message = i18n.t('errors.connectionError');
+ this.icon = 'access-point-network-off';
+ break;
+ case ERROR_TYPE.SERVER_ERROR:
+ this.message = i18n.t('errors.serverError');
+ this.icon = 'server-network-off';
+ break;
+ default:
+ this.message = i18n.t('errors.unknown');
+ this.icon = 'alert-circle-outline';
+ break;
+ }
+ this.message += `\n\nCode ${props.errorCode}`;
+ } else {
+ this.message = props.message;
+ this.icon = props.icon;
+ }
+ }
+
+ render(): React.Node {
+ const {props} = this;
+ this.generateMessage();
+ let button;
+ if (this.showLoginButton) button = this.getLoginButton();
+ else if (props.showRetryButton) button = this.getRetryButton();
+ else button = null;
+
+ return (
+
+
+
+
+
+
+ {this.message}
+
+ {button}
+
+
+ );
+ }
+}
export default withTheme(ErrorView);
diff --git a/src/components/Screens/WebViewScreen.js b/src/components/Screens/WebViewScreen.js
index 8dfb5f8..9dc715a 100644
--- a/src/components/Screens/WebViewScreen.js
+++ b/src/components/Screens/WebViewScreen.js
@@ -1,233 +1,247 @@
// @flow
import * as React from 'react';
-import WebView from "react-native-webview";
-import BasicLoadingScreen from "./BasicLoadingScreen";
-import ErrorView from "./ErrorView";
-import {ERROR_TYPE} from "../../utils/WebData";
-import MaterialHeaderButtons, {Item} from '../Overrides/CustomHeaderButton';
-import {Divider, HiddenItem, OverflowMenu} from "react-navigation-header-buttons";
+import WebView from 'react-native-webview';
+import {
+ Divider,
+ HiddenItem,
+ OverflowMenu,
+} from 'react-navigation-header-buttons';
import i18n from 'i18n-js';
-import {Animated, BackHandler, Linking} from "react-native";
-import {withCollapsible} from "../../utils/withCollapsible";
-import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
-import {withTheme} from "react-native-paper";
-import type {CustomTheme} from "../../managers/ThemeManager";
-import {StackNavigationProp} from "@react-navigation/stack";
-import {Collapsible} from "react-navigation-collapsible";
+import {Animated, BackHandler, Linking} from 'react-native';
+import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
+import {withTheme} from 'react-native-paper';
+import {StackNavigationProp} from '@react-navigation/stack';
+import {Collapsible} from 'react-navigation-collapsible';
+import type {CustomTheme} from '../../managers/ThemeManager';
+import {withCollapsible} from '../../utils/withCollapsible';
+import MaterialHeaderButtons, {Item} from '../Overrides/CustomHeaderButton';
+import {ERROR_TYPE} from '../../utils/WebData';
+import ErrorView from './ErrorView';
+import BasicLoadingScreen from './BasicLoadingScreen';
-type Props = {
- navigation: StackNavigationProp,
- theme: CustomTheme,
- url: string,
- customJS: string,
- customPaddingFunction: null | (padding: number) => string,
- collapsibleStack: Collapsible,
- onMessage: Function,
- onScroll: Function,
- showAdvancedControls: boolean,
-}
+type PropsType = {
+ navigation: StackNavigationProp,
+ theme: CustomTheme,
+ url: string,
+ collapsibleStack: Collapsible,
+ onMessage: (event: {nativeEvent: {data: string}}) => void,
+ onScroll: (event: SyntheticEvent) => void,
+ customJS?: string,
+ customPaddingFunction?: null | ((padding: number) => string),
+ showAdvancedControls?: boolean,
+};
const AnimatedWebView = Animated.createAnimatedComponent(WebView);
/**
* Class defining a webview screen.
*/
-class WebViewScreen extends React.PureComponent {
+class WebViewScreen extends React.PureComponent {
+ static defaultProps = {
+ customJS: '',
+ showAdvancedControls: true,
+ customPaddingFunction: null,
+ };
- static defaultProps = {
- customJS: '',
- showAdvancedControls: true,
- customPaddingFunction: null,
- };
+ webviewRef: {current: null | WebView};
- webviewRef: { current: null | WebView };
+ canGoBack: boolean;
- canGoBack: boolean;
+ constructor() {
+ super();
+ this.webviewRef = React.createRef();
+ this.canGoBack = false;
+ }
- constructor() {
- super();
- this.webviewRef = React.createRef();
- this.canGoBack = false;
+ /**
+ * Creates header buttons and listens to events after mounting
+ */
+ componentDidMount() {
+ const {props} = this;
+ props.navigation.setOptions({
+ headerRight: props.showAdvancedControls
+ ? this.getAdvancedButtons
+ : this.getBasicButton,
+ });
+ props.navigation.addListener('focus', () => {
+ BackHandler.addEventListener(
+ 'hardwareBackPress',
+ this.onBackButtonPressAndroid,
+ );
+ });
+ props.navigation.addListener('blur', () => {
+ BackHandler.removeEventListener(
+ 'hardwareBackPress',
+ this.onBackButtonPressAndroid,
+ );
+ });
+ }
+
+ /**
+ * Goes back on the webview or on the navigation stack if we cannot go back anymore
+ *
+ * @returns {boolean}
+ */
+ onBackButtonPressAndroid = (): boolean => {
+ if (this.canGoBack) {
+ this.onGoBackClicked();
+ return true;
}
+ return false;
+ };
- /**
- * Creates header buttons and listens to events after mounting
- */
- componentDidMount() {
- this.props.navigation.setOptions({
- headerRight: this.props.showAdvancedControls
- ? this.getAdvancedButtons
- : this.getBasicButton,
- });
- this.props.navigation.addListener(
- 'focus',
- () =>
- BackHandler.addEventListener(
- 'hardwareBackPress',
- this.onBackButtonPressAndroid
- )
- );
- this.props.navigation.addListener(
- 'blur',
- () =>
- BackHandler.removeEventListener(
- 'hardwareBackPress',
- this.onBackButtonPressAndroid
- )
- );
- }
+ /**
+ * Gets header refresh and open in browser buttons
+ *
+ * @return {*}
+ */
+ getBasicButton = (): React.Node => {
+ return (
+
+
+
+
+ );
+ };
- /**
- * Goes back on the webview or on the navigation stack if we cannot go back anymore
- *
- * @returns {boolean}
- */
- onBackButtonPressAndroid = () => {
- if (this.canGoBack) {
- this.onGoBackClicked();
- return true;
- }
- return false;
- };
-
- /**
- * Gets header refresh and open in browser buttons
- *
- * @return {*}
- */
- getBasicButton = () => {
- return (
-
- -
-
-
-
- );
- };
-
- /**
- * Creates advanced header control buttons.
- * These buttons allows the user to refresh, go back, go forward and open in the browser.
- *
- * @returns {*}
- */
- getAdvancedButtons = () => {
- return (
-
-
- }
- >
-
-
-
-
-
-
- );
- }
-
- /**
- * Callback to use when refresh button is clicked. Reloads the webview.
- */
- onRefreshClicked = () => {
- if (this.webviewRef.current != null)
- this.webviewRef.current.reload();
- }
- onGoBackClicked = () => {
- if (this.webviewRef.current != null)
- this.webviewRef.current.goBack();
- }
- onGoForwardClicked = () => {
- if (this.webviewRef.current != null)
- this.webviewRef.current.goForward();
- }
- onOpenClicked = () => Linking.openURL(this.props.url);
-
- /**
- * Injects the given javascript string into the web page
- *
- * @param script The script to inject
- */
- injectJavaScript = (script: string) => {
- if (this.webviewRef.current != null)
- this.webviewRef.current.injectJavaScript(script);
- }
-
- /**
- * Gets the loading indicator
- *
- * @return {*}
- */
- getRenderLoading = () => ;
-
- /**
- * Gets the javascript needed to generate a padding on top of the page
- * This adds padding to the body and runs the custom padding function given in props
- *
- * @param padding The padding to add in pixels
- * @returns {string}
- */
- getJavascriptPadding(padding: number) {
- const customPadding = this.props.customPaddingFunction != null ? this.props.customPaddingFunction(padding) : "";
- return (
- "document.getElementsByTagName('body')[0].style.paddingTop = '" + padding + "px';" +
- customPadding +
- "true;"
- );
- }
-
- onScroll = (event: Object) => {
- if (this.props.onScroll)
- this.props.onScroll(event);
- }
-
- render() {
- const {containerPaddingTop, onScrollWithListener} = this.props.collapsibleStack;
- return (
- }
- onNavigationStateChange={navState => {
- this.canGoBack = navState.canGoBack;
- }}
- onMessage={this.props.onMessage}
- onLoad={() => this.injectJavaScript(this.getJavascriptPadding(containerPaddingTop))}
- // Animations
- onScroll={onScrollWithListener(this.onScroll)}
+ /**
+ * Creates advanced header control buttons.
+ * These buttons allows the user to refresh, go back, go forward and open in the browser.
+ *
+ * @returns {*}
+ */
+ getAdvancedButtons = (): React.Node => {
+ const {props} = this;
+ return (
+
+
+
- );
- }
+ }>
+
+
+
+
+
+
+ );
+ };
+
+ /**
+ * Gets the loading indicator
+ *
+ * @return {*}
+ */
+ getRenderLoading = (): React.Node => ;
+
+ /**
+ * Gets the javascript needed to generate a padding on top of the page
+ * This adds padding to the body and runs the custom padding function given in props
+ *
+ * @param padding The padding to add in pixels
+ * @returns {string}
+ */
+ getJavascriptPadding(padding: number): string {
+ const {props} = this;
+ const customPadding =
+ props.customPaddingFunction != null
+ ? props.customPaddingFunction(padding)
+ : '';
+ return `document.getElementsByTagName('body')[0].style.paddingTop = '${padding}px';${customPadding}true;`;
+ }
+
+ /**
+ * Callback to use when refresh button is clicked. Reloads the webview.
+ */
+ onRefreshClicked = () => {
+ if (this.webviewRef.current != null) this.webviewRef.current.reload();
+ };
+
+ onGoBackClicked = () => {
+ if (this.webviewRef.current != null) this.webviewRef.current.goBack();
+ };
+
+ onGoForwardClicked = () => {
+ if (this.webviewRef.current != null) this.webviewRef.current.goForward();
+ };
+
+ onOpenClicked = () => {
+ const {url} = this.props;
+ Linking.openURL(url);
+ };
+
+ onScroll = (event: SyntheticEvent) => {
+ const {onScroll} = this.props;
+ if (onScroll) onScroll(event);
+ };
+
+ /**
+ * Injects the given javascript string into the web page
+ *
+ * @param script The script to inject
+ */
+ injectJavaScript = (script: string) => {
+ if (this.webviewRef.current != null)
+ this.webviewRef.current.injectJavaScript(script);
+ };
+
+ render(): React.Node {
+ const {props} = this;
+ const {containerPaddingTop, onScrollWithListener} = props.collapsibleStack;
+ return (
+ (
+
+ )}
+ onNavigationStateChange={(navState: {canGoBack: boolean}) => {
+ this.canGoBack = navState.canGoBack;
+ }}
+ onMessage={props.onMessage}
+ onLoad={() => {
+ this.injectJavaScript(this.getJavascriptPadding(containerPaddingTop));
+ }}
+ // Animations
+ onScroll={onScrollWithListener(this.onScroll)}
+ />
+ );
+ }
}
export default withCollapsible(withTheme(WebViewScreen));