Browse Source

Improve basic screen components to match linter

Arnaud Vergnet 2 years ago
parent
commit
0117b25cd8

+ 23
- 21
src/components/Screens/BasicLoadingScreen.js View File

@@ -3,6 +3,7 @@
3 3
 import * as React from 'react';
4 4
 import {View} from 'react-native';
5 5
 import {ActivityIndicator, withTheme} from 'react-native-paper';
6
+import type {CustomTheme} from '../../managers/ThemeManager';
6 7
 
7 8
 /**
8 9
  * Component used to display a header button
@@ -10,28 +11,29 @@ import {ActivityIndicator, withTheme} from 'react-native-paper';
10 11
  * @param props Props to pass to the component
11 12
  * @return {*}
12 13
  */
13
-function BasicLoadingScreen(props) {
14
-    const {colors} = props.theme;
15
-    let position = undefined;
16
-    if (props.isAbsolute !== undefined && props.isAbsolute)
17
-        position = 'absolute';
14
+function BasicLoadingScreen(props: {
15
+  theme: CustomTheme,
16
+  isAbsolute: boolean,
17
+}): React.Node {
18
+  const {theme, isAbsolute} = props;
19
+  const {colors} = theme;
20
+  let position;
21
+  if (isAbsolute != null && isAbsolute) position = 'absolute';
18 22
 
19
-    return (
20
-        <View style={{
21
-            backgroundColor: colors.background,
22
-            position: position,
23
-            top: 0,
24
-            right: 0,
25
-            width: '100%',
26
-            height: '100%',
27
-            justifyContent: 'center',
28
-        }}>
29
-            <ActivityIndicator
30
-                animating={true}
31
-                size={'large'}
32
-                color={colors.primary}/>
33
-        </View>
34
-    );
23
+  return (
24
+    <View
25
+      style={{
26
+        backgroundColor: colors.background,
27
+        position,
28
+        top: 0,
29
+        right: 0,
30
+        width: '100%',
31
+        height: '100%',
32
+        justifyContent: 'center',
33
+      }}>
34
+      <ActivityIndicator animating size="large" color={colors.primary} />
35
+    </View>
36
+  );
35 37
 }
36 38
 
37 39
 export default withTheme(BasicLoadingScreen);

+ 178
- 180
src/components/Screens/ErrorView.js View File

@@ -2,191 +2,189 @@
2 2
 
3 3
 import * as React from 'react';
4 4
 import {Button, Subheading, withTheme} from 'react-native-paper';
5
-import {StyleSheet, View} from "react-native";
6
-import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
5
+import {StyleSheet, View} from 'react-native';
6
+import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
7 7
 import i18n from 'i18n-js';
8
-import {ERROR_TYPE} from "../../utils/WebData";
9 8
 import * as Animatable from 'react-native-animatable';
10
-
11
-type Props = {
12
-    navigation: Object,
13
-    route: Object,
14
-    errorCode: number,
15
-    onRefresh: Function,
16
-    icon: string,
17
-    message: string,
18
-    showRetryButton: boolean,
19
-}
20
-
21
-type State = {
22
-    refreshing: boolean,
23
-}
24
-
25
-class ErrorView extends React.PureComponent<Props, State> {
26
-
27
-    colors: Object;
28
-
29
-    message: string;
30
-    icon: string;
31
-
32
-    showLoginButton: boolean;
33
-
34
-    static defaultProps = {
35
-        errorCode: 0,
36
-        icon: '',
37
-        message: '',
38
-        showRetryButton: true,
39
-    }
40
-
41
-    state = {
42
-        refreshing: false,
43
-    };
44
-
45
-    constructor(props) {
46
-        super(props);
47
-        this.colors = props.theme.colors;
48
-        this.icon = "";
49
-    }
50
-
51
-    generateMessage() {
52
-        this.showLoginButton = false;
53
-        if (this.props.errorCode !== 0) {
54
-            switch (this.props.errorCode) {
55
-                case ERROR_TYPE.BAD_CREDENTIALS:
56
-                    this.message = i18n.t("errors.badCredentials");
57
-                    this.icon = "account-alert-outline";
58
-                    break;
59
-                case ERROR_TYPE.BAD_TOKEN:
60
-                    this.message = i18n.t("errors.badToken");
61
-                    this.icon = "account-alert-outline";
62
-                    this.showLoginButton = true;
63
-                    break;
64
-                case ERROR_TYPE.NO_CONSENT:
65
-                    this.message = i18n.t("errors.noConsent");
66
-                    this.icon = "account-remove-outline";
67
-                    break;
68
-                case ERROR_TYPE.TOKEN_SAVE:
69
-                    this.message = i18n.t("errors.tokenSave");
70
-                    this.icon = "alert-circle-outline";
71
-                    break;
72
-                case ERROR_TYPE.BAD_INPUT:
73
-                    this.message = i18n.t("errors.badInput");
74
-                    this.icon = "alert-circle-outline";
75
-                    break;
76
-                case ERROR_TYPE.FORBIDDEN:
77
-                    this.message = i18n.t("errors.forbidden");
78
-                    this.icon = "lock";
79
-                    break;
80
-                case ERROR_TYPE.CONNECTION_ERROR:
81
-                    this.message = i18n.t("errors.connectionError");
82
-                    this.icon = "access-point-network-off";
83
-                    break;
84
-                case ERROR_TYPE.SERVER_ERROR:
85
-                    this.message = i18n.t("errors.serverError");
86
-                    this.icon = "server-network-off";
87
-                    break;
88
-                default:
89
-                    this.message = i18n.t("errors.unknown");
90
-                    this.icon = "alert-circle-outline";
91
-                    break;
92
-            }
93
-            this.message += "\n\nCode " + this.props.errorCode;
94
-        } else {
95
-            this.message = this.props.message;
96
-            this.icon = this.props.icon;
97
-        }
98
-
99
-    }
100
-
101
-    getRetryButton() {
102
-        return <Button
103
-            mode={'contained'}
104
-            icon={'refresh'}
105
-            onPress={this.props.onRefresh}
106
-            style={styles.button}
107
-        >
108
-            {i18n.t("general.retry")}
109
-        </Button>;
110
-    }
111
-
112
-    goToLogin = () => {
113
-        this.props.navigation.navigate("login",
114
-            {
115
-                screen: 'login',
116
-                params: {nextScreen: this.props.route.name}
117
-            })
118
-    };
119
-
120
-    getLoginButton() {
121
-        return <Button
122
-            mode={'contained'}
123
-            icon={'login'}
124
-            onPress={this.goToLogin}
125
-            style={styles.button}
126
-        >
127
-            {i18n.t("screens.login.title")}
128
-        </Button>;
129
-    }
130
-
131
-    render() {
132
-        this.generateMessage();
133
-        return (
134
-            <Animatable.View
135
-                style={{
136
-                ...styles.outer,
137
-                backgroundColor: this.colors.background
138
-            }}
139
-                animation={"zoomIn"}
140
-                duration={200}
141
-                useNativeDriver
142
-            >
143
-                <View style={styles.inner}>
144
-                    <View style={styles.iconContainer}>
145
-                        <MaterialCommunityIcons
146
-                            name={this.icon}
147
-                            size={150}
148
-                            color={this.colors.textDisabled}/>
149
-                    </View>
150
-                    <Subheading style={{
151
-                        ...styles.subheading,
152
-                        color: this.colors.textDisabled
153
-                    }}>
154
-                        {this.message}
155
-                    </Subheading>
156
-                    {this.props.showRetryButton
157
-                        ? (this.showLoginButton
158
-                            ? this.getLoginButton()
159
-                            : this.getRetryButton())
160
-                        : null}
161
-                </View>
162
-            </Animatable.View>
163
-        );
164
-    }
165
-}
9
+import {StackNavigationProp} from '@react-navigation/stack';
10
+import {ERROR_TYPE} from '../../utils/WebData';
11
+import type {CustomTheme} from '../../managers/ThemeManager';
12
+
13
+type PropsType = {
14
+  navigation: StackNavigationProp,
15
+  theme: CustomTheme,
16
+  route: {name: string},
17
+  onRefresh?: () => void,
18
+  errorCode?: number,
19
+  icon?: string,
20
+  message?: string,
21
+  showRetryButton?: boolean,
22
+};
166 23
 
167 24
 const styles = StyleSheet.create({
168
-    outer: {
169
-        height: '100%',
170
-    },
171
-    inner: {
172
-        marginTop: 'auto',
173
-        marginBottom: 'auto',
174
-    },
175
-    iconContainer: {
176
-        marginLeft: 'auto',
177
-        marginRight: 'auto',
178
-        marginBottom: 20
179
-    },
180
-    subheading: {
181
-        textAlign: 'center',
182
-        paddingHorizontal: 20
183
-    },
184
-    button: {
185
-        marginTop: 10,
186
-        marginLeft: 'auto',
187
-        marginRight: 'auto',
188
-    }
25
+  outer: {
26
+    height: '100%',
27
+  },
28
+  inner: {
29
+    marginTop: 'auto',
30
+    marginBottom: 'auto',
31
+  },
32
+  iconContainer: {
33
+    marginLeft: 'auto',
34
+    marginRight: 'auto',
35
+    marginBottom: 20,
36
+  },
37
+  subheading: {
38
+    textAlign: 'center',
39
+    paddingHorizontal: 20,
40
+  },
41
+  button: {
42
+    marginTop: 10,
43
+    marginLeft: 'auto',
44
+    marginRight: 'auto',
45
+  },
189 46
 });
190 47
 
48
+class ErrorView extends React.PureComponent<PropsType> {
49
+  static defaultProps = {
50
+    onRefresh: (): void => null,
51
+    errorCode: 0,
52
+    icon: '',
53
+    message: '',
54
+    showRetryButton: true,
55
+  };
56
+
57
+  message: string;
58
+
59
+  icon: string;
60
+
61
+  showLoginButton: boolean;
62
+
63
+  constructor(props: PropsType) {
64
+    super(props);
65
+    this.icon = '';
66
+  }
67
+
68
+  getRetryButton(): React.Node {
69
+    const {props} = this;
70
+    return (
71
+      <Button
72
+        mode="contained"
73
+        icon="refresh"
74
+        onPress={props.onRefresh}
75
+        style={styles.button}>
76
+        {i18n.t('general.retry')}
77
+      </Button>
78
+    );
79
+  }
80
+
81
+  getLoginButton(): React.Node {
82
+    return (
83
+      <Button
84
+        mode="contained"
85
+        icon="login"
86
+        onPress={this.goToLogin}
87
+        style={styles.button}>
88
+        {i18n.t('screens.login.title')}
89
+      </Button>
90
+    );
91
+  }
92
+
93
+  goToLogin = () => {
94
+    const {props} = this;
95
+    props.navigation.navigate('login', {
96
+      screen: 'login',
97
+      params: {nextScreen: props.route.name},
98
+    });
99
+  };
100
+
101
+  generateMessage() {
102
+    const {props} = this;
103
+    this.showLoginButton = false;
104
+    if (props.errorCode !== 0) {
105
+      switch (props.errorCode) {
106
+        case ERROR_TYPE.BAD_CREDENTIALS:
107
+          this.message = i18n.t('errors.badCredentials');
108
+          this.icon = 'account-alert-outline';
109
+          break;
110
+        case ERROR_TYPE.BAD_TOKEN:
111
+          this.message = i18n.t('errors.badToken');
112
+          this.icon = 'account-alert-outline';
113
+          this.showLoginButton = true;
114
+          break;
115
+        case ERROR_TYPE.NO_CONSENT:
116
+          this.message = i18n.t('errors.noConsent');
117
+          this.icon = 'account-remove-outline';
118
+          break;
119
+        case ERROR_TYPE.TOKEN_SAVE:
120
+          this.message = i18n.t('errors.tokenSave');
121
+          this.icon = 'alert-circle-outline';
122
+          break;
123
+        case ERROR_TYPE.BAD_INPUT:
124
+          this.message = i18n.t('errors.badInput');
125
+          this.icon = 'alert-circle-outline';
126
+          break;
127
+        case ERROR_TYPE.FORBIDDEN:
128
+          this.message = i18n.t('errors.forbidden');
129
+          this.icon = 'lock';
130
+          break;
131
+        case ERROR_TYPE.CONNECTION_ERROR:
132
+          this.message = i18n.t('errors.connectionError');
133
+          this.icon = 'access-point-network-off';
134
+          break;
135
+        case ERROR_TYPE.SERVER_ERROR:
136
+          this.message = i18n.t('errors.serverError');
137
+          this.icon = 'server-network-off';
138
+          break;
139
+        default:
140
+          this.message = i18n.t('errors.unknown');
141
+          this.icon = 'alert-circle-outline';
142
+          break;
143
+      }
144
+      this.message += `\n\nCode ${props.errorCode}`;
145
+    } else {
146
+      this.message = props.message;
147
+      this.icon = props.icon;
148
+    }
149
+  }
150
+
151
+  render(): React.Node {
152
+    const {props} = this;
153
+    this.generateMessage();
154
+    let button;
155
+    if (this.showLoginButton) button = this.getLoginButton();
156
+    else if (props.showRetryButton) button = this.getRetryButton();
157
+    else button = null;
158
+
159
+    return (
160
+      <Animatable.View
161
+        style={{
162
+          ...styles.outer,
163
+          backgroundColor: props.theme.colors.background,
164
+        }}
165
+        animation="zoomIn"
166
+        duration={200}
167
+        useNativeDriver>
168
+        <View style={styles.inner}>
169
+          <View style={styles.iconContainer}>
170
+            <MaterialCommunityIcons
171
+              name={this.icon}
172
+              size={150}
173
+              color={props.theme.colors.textDisabled}
174
+            />
175
+          </View>
176
+          <Subheading
177
+            style={{
178
+              ...styles.subheading,
179
+              color: props.theme.colors.textDisabled,
180
+            }}>
181
+            {this.message}
182
+          </Subheading>
183
+          {button}
184
+        </View>
185
+      </Animatable.View>
186
+    );
187
+  }
188
+}
191 189
 
192 190
 export default withTheme(ErrorView);

+ 232
- 218
src/components/Screens/WebViewScreen.js View File

@@ -1,233 +1,247 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import WebView from "react-native-webview";
5
-import BasicLoadingScreen from "./BasicLoadingScreen";
6
-import ErrorView from "./ErrorView";
7
-import {ERROR_TYPE} from "../../utils/WebData";
8
-import MaterialHeaderButtons, {Item} from '../Overrides/CustomHeaderButton';
9
-import {Divider, HiddenItem, OverflowMenu} from "react-navigation-header-buttons";
4
+import WebView from 'react-native-webview';
5
+import {
6
+  Divider,
7
+  HiddenItem,
8
+  OverflowMenu,
9
+} from 'react-navigation-header-buttons';
10 10
 import i18n from 'i18n-js';
11
-import {Animated, BackHandler, Linking} from "react-native";
12
-import {withCollapsible} from "../../utils/withCollapsible";
13
-import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
14
-import {withTheme} from "react-native-paper";
15
-import type {CustomTheme} from "../../managers/ThemeManager";
16
-import {StackNavigationProp} from "@react-navigation/stack";
17
-import {Collapsible} from "react-navigation-collapsible";
18
-
19
-type Props = {
20
-    navigation: StackNavigationProp,
21
-    theme: CustomTheme,
22
-    url: string,
23
-    customJS: string,
24
-    customPaddingFunction: null | (padding: number) => string,
25
-    collapsibleStack: Collapsible,
26
-    onMessage: Function,
27
-    onScroll: Function,
28
-    showAdvancedControls: boolean,
29
-}
11
+import {Animated, BackHandler, Linking} from 'react-native';
12
+import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
13
+import {withTheme} from 'react-native-paper';
14
+import {StackNavigationProp} from '@react-navigation/stack';
15
+import {Collapsible} from 'react-navigation-collapsible';
16
+import type {CustomTheme} from '../../managers/ThemeManager';
17
+import {withCollapsible} from '../../utils/withCollapsible';
18
+import MaterialHeaderButtons, {Item} from '../Overrides/CustomHeaderButton';
19
+import {ERROR_TYPE} from '../../utils/WebData';
20
+import ErrorView from './ErrorView';
21
+import BasicLoadingScreen from './BasicLoadingScreen';
22
+
23
+type PropsType = {
24
+  navigation: StackNavigationProp,
25
+  theme: CustomTheme,
26
+  url: string,
27
+  collapsibleStack: Collapsible,
28
+  onMessage: (event: {nativeEvent: {data: string}}) => void,
29
+  onScroll: (event: SyntheticEvent<EventTarget>) => void,
30
+  customJS?: string,
31
+  customPaddingFunction?: null | ((padding: number) => string),
32
+  showAdvancedControls?: boolean,
33
+};
30 34
 
31 35
 const AnimatedWebView = Animated.createAnimatedComponent(WebView);
32 36
 
33 37
 /**
34 38
  * Class defining a webview screen.
35 39
  */
36
-class WebViewScreen extends React.PureComponent<Props> {
37
-
38
-    static defaultProps = {
39
-        customJS: '',
40
-        showAdvancedControls: true,
41
-        customPaddingFunction: null,
42
-    };
43
-
44
-    webviewRef: { current: null | WebView };
45
-
46
-    canGoBack: boolean;
47
-
48
-    constructor() {
49
-        super();
50
-        this.webviewRef = React.createRef();
51
-        this.canGoBack = false;
52
-    }
53
-
54
-    /**
55
-     * Creates header buttons and listens to events after mounting
56
-     */
57
-    componentDidMount() {
58
-        this.props.navigation.setOptions({
59
-            headerRight: this.props.showAdvancedControls
60
-                ? this.getAdvancedButtons
61
-                : this.getBasicButton,
62
-        });
63
-        this.props.navigation.addListener(
64
-            'focus',
65
-            () =>
66
-                BackHandler.addEventListener(
67
-                    'hardwareBackPress',
68
-                    this.onBackButtonPressAndroid
69
-                )
70
-        );
71
-        this.props.navigation.addListener(
72
-            'blur',
73
-            () =>
74
-                BackHandler.removeEventListener(
75
-                    'hardwareBackPress',
76
-                    this.onBackButtonPressAndroid
77
-                )
78
-        );
79
-    }
80
-
81
-    /**
82
-     * Goes back on the webview or on the navigation stack if we cannot go back anymore
83
-     *
84
-     * @returns {boolean}
85
-     */
86
-    onBackButtonPressAndroid = () => {
87
-        if (this.canGoBack) {
88
-            this.onGoBackClicked();
89
-            return true;
90
-        }
91
-        return false;
92
-    };
93
-
94
-    /**
95
-     * Gets header refresh and open in browser buttons
96
-     *
97
-     * @return {*}
98
-     */
99
-    getBasicButton = () => {
100
-        return (
101
-            <MaterialHeaderButtons>
102
-                <Item
103
-                    title="refresh"
104
-                    iconName="refresh"
105
-                    onPress={this.onRefreshClicked}/>
106
-                <Item
107
-                    title={i18n.t("general.openInBrowser")}
108
-                    iconName="open-in-new"
109
-                    onPress={this.onOpenClicked}/>
110
-            </MaterialHeaderButtons>
111
-        );
112
-    };
113
-
114
-    /**
115
-     * Creates advanced header control buttons.
116
-     * These buttons allows the user to refresh, go back, go forward and open in the browser.
117
-     *
118
-     * @returns {*}
119
-     */
120
-    getAdvancedButtons = () => {
121
-        return (
122
-            <MaterialHeaderButtons>
123
-                <Item
124
-                    title="refresh"
125
-                    iconName="refresh"
126
-                    onPress={this.onRefreshClicked}
127
-                />
128
-                <OverflowMenu
129
-                    style={{marginHorizontal: 10}}
130
-                    OverflowIcon={
131
-                        <MaterialCommunityIcons
132
-                            name="dots-vertical"
133
-                            size={26}
134
-                            color={this.props.theme.colors.text}
135
-                        />}
136
-                >
137
-                    <HiddenItem
138
-                        title={i18n.t("general.goBack")}
139
-                        onPress={this.onGoBackClicked}/>
140
-                    <HiddenItem
141
-                        title={i18n.t("general.goForward")}
142
-                        onPress={this.onGoForwardClicked}/>
143
-                    <Divider/>
144
-                    <HiddenItem
145
-                        title={i18n.t("general.openInBrowser")}
146
-                        onPress={this.onOpenClicked}/>
147
-                </OverflowMenu>
148
-            </MaterialHeaderButtons>
149
-        );
40
+class WebViewScreen extends React.PureComponent<PropsType> {
41
+  static defaultProps = {
42
+    customJS: '',
43
+    showAdvancedControls: true,
44
+    customPaddingFunction: null,
45
+  };
46
+
47
+  webviewRef: {current: null | WebView};
48
+
49
+  canGoBack: boolean;
50
+
51
+  constructor() {
52
+    super();
53
+    this.webviewRef = React.createRef();
54
+    this.canGoBack = false;
55
+  }
56
+
57
+  /**
58
+   * Creates header buttons and listens to events after mounting
59
+   */
60
+  componentDidMount() {
61
+    const {props} = this;
62
+    props.navigation.setOptions({
63
+      headerRight: props.showAdvancedControls
64
+        ? this.getAdvancedButtons
65
+        : this.getBasicButton,
66
+    });
67
+    props.navigation.addListener('focus', () => {
68
+      BackHandler.addEventListener(
69
+        'hardwareBackPress',
70
+        this.onBackButtonPressAndroid,
71
+      );
72
+    });
73
+    props.navigation.addListener('blur', () => {
74
+      BackHandler.removeEventListener(
75
+        'hardwareBackPress',
76
+        this.onBackButtonPressAndroid,
77
+      );
78
+    });
79
+  }
80
+
81
+  /**
82
+   * Goes back on the webview or on the navigation stack if we cannot go back anymore
83
+   *
84
+   * @returns {boolean}
85
+   */
86
+  onBackButtonPressAndroid = (): boolean => {
87
+    if (this.canGoBack) {
88
+      this.onGoBackClicked();
89
+      return true;
150 90
     }
151
-
152
-    /**
153
-     * Callback to use when refresh button is clicked. Reloads the webview.
154
-     */
155
-    onRefreshClicked = () => {
156
-        if (this.webviewRef.current != null)
157
-            this.webviewRef.current.reload();
158
-    }
159
-    onGoBackClicked = () => {
160
-        if (this.webviewRef.current != null)
161
-            this.webviewRef.current.goBack();
162
-    }
163
-    onGoForwardClicked = () => {
164
-        if (this.webviewRef.current != null)
165
-            this.webviewRef.current.goForward();
166
-    }
167
-    onOpenClicked = () => Linking.openURL(this.props.url);
168
-
169
-    /**
170
-     * Injects the given javascript string into the web page
171
-     *
172
-     * @param script The script to inject
173
-     */
174
-    injectJavaScript = (script: string) => {
175
-        if (this.webviewRef.current != null)
176
-            this.webviewRef.current.injectJavaScript(script);
177
-    }
178
-
179
-    /**
180
-     * Gets the loading indicator
181
-     *
182
-     * @return {*}
183
-     */
184
-    getRenderLoading = () => <BasicLoadingScreen isAbsolute={true}/>;
185
-
186
-    /**
187
-     * Gets the javascript needed to generate a padding on top of the page
188
-     * This adds padding to the body and runs the custom padding function given in props
189
-     *
190
-     * @param padding The padding to add in pixels
191
-     * @returns {string}
192
-     */
193
-    getJavascriptPadding(padding: number) {
194
-        const customPadding = this.props.customPaddingFunction != null ? this.props.customPaddingFunction(padding) : "";
195
-        return (
196
-            "document.getElementsByTagName('body')[0].style.paddingTop = '" + padding + "px';" +
197
-            customPadding +
198
-            "true;"
199
-        );
200
-    }
201
-
202
-    onScroll = (event: Object) => {
203
-        if (this.props.onScroll)
204
-            this.props.onScroll(event);
205
-    }
206
-
207
-    render() {
208
-        const {containerPaddingTop, onScrollWithListener} = this.props.collapsibleStack;
209
-        return (
210
-            <AnimatedWebView
211
-                ref={this.webviewRef}
212
-                source={{uri: this.props.url}}
213
-                startInLoadingState={true}
214
-                injectedJavaScript={this.props.customJS}
215
-                javaScriptEnabled={true}
216
-                renderLoading={this.getRenderLoading}
217
-                renderError={() => <ErrorView
218
-                    errorCode={ERROR_TYPE.CONNECTION_ERROR}
219
-                    onRefresh={this.onRefreshClicked}
220
-                />}
221
-                onNavigationStateChange={navState => {
222
-                    this.canGoBack = navState.canGoBack;
223
-                }}
224
-                onMessage={this.props.onMessage}
225
-                onLoad={() => this.injectJavaScript(this.getJavascriptPadding(containerPaddingTop))}
226
-                // Animations
227
-                onScroll={onScrollWithListener(this.onScroll)}
91
+    return false;
92
+  };
93
+
94
+  /**
95
+   * Gets header refresh and open in browser buttons
96
+   *
97
+   * @return {*}
98
+   */
99
+  getBasicButton = (): React.Node => {
100
+    return (
101
+      <MaterialHeaderButtons>
102
+        <Item
103
+          title="refresh"
104
+          iconName="refresh"
105
+          onPress={this.onRefreshClicked}
106
+        />
107
+        <Item
108
+          title={i18n.t('general.openInBrowser')}
109
+          iconName="open-in-new"
110
+          onPress={this.onOpenClicked}
111
+        />
112
+      </MaterialHeaderButtons>
113
+    );
114
+  };
115
+
116
+  /**
117
+   * Creates advanced header control buttons.
118
+   * These buttons allows the user to refresh, go back, go forward and open in the browser.
119
+   *
120
+   * @returns {*}
121
+   */
122
+  getAdvancedButtons = (): React.Node => {
123
+    const {props} = this;
124
+    return (
125
+      <MaterialHeaderButtons>
126
+        <Item
127
+          title="refresh"
128
+          iconName="refresh"
129
+          onPress={this.onRefreshClicked}
130
+        />
131
+        <OverflowMenu
132
+          style={{marginHorizontal: 10}}
133
+          OverflowIcon={
134
+            <MaterialCommunityIcons
135
+              name="dots-vertical"
136
+              size={26}
137
+              color={props.theme.colors.text}
228 138
             />
229
-        );
230
-    }
139
+          }>
140
+          <HiddenItem
141
+            title={i18n.t('general.goBack')}
142
+            onPress={this.onGoBackClicked}
143
+          />
144
+          <HiddenItem
145
+            title={i18n.t('general.goForward')}
146
+            onPress={this.onGoForwardClicked}
147
+          />
148
+          <Divider />
149
+          <HiddenItem
150
+            title={i18n.t('general.openInBrowser')}
151
+            onPress={this.onOpenClicked}
152
+          />
153
+        </OverflowMenu>
154
+      </MaterialHeaderButtons>
155
+    );
156
+  };
157
+
158
+  /**
159
+   * Gets the loading indicator
160
+   *
161
+   * @return {*}
162
+   */
163
+  getRenderLoading = (): React.Node => <BasicLoadingScreen isAbsolute />;
164
+
165
+  /**
166
+   * Gets the javascript needed to generate a padding on top of the page
167
+   * This adds padding to the body and runs the custom padding function given in props
168
+   *
169
+   * @param padding The padding to add in pixels
170
+   * @returns {string}
171
+   */
172
+  getJavascriptPadding(padding: number): string {
173
+    const {props} = this;
174
+    const customPadding =
175
+      props.customPaddingFunction != null
176
+        ? props.customPaddingFunction(padding)
177
+        : '';
178
+    return `document.getElementsByTagName('body')[0].style.paddingTop = '${padding}px';${customPadding}true;`;
179
+  }
180
+
181
+  /**
182
+   * Callback to use when refresh button is clicked. Reloads the webview.
183
+   */
184
+  onRefreshClicked = () => {
185
+    if (this.webviewRef.current != null) this.webviewRef.current.reload();
186
+  };
187
+
188
+  onGoBackClicked = () => {
189
+    if (this.webviewRef.current != null) this.webviewRef.current.goBack();
190
+  };
191
+
192
+  onGoForwardClicked = () => {
193
+    if (this.webviewRef.current != null) this.webviewRef.current.goForward();
194
+  };
195
+
196
+  onOpenClicked = () => {
197
+    const {url} = this.props;
198
+    Linking.openURL(url);
199
+  };
200
+
201
+  onScroll = (event: SyntheticEvent<EventTarget>) => {
202
+    const {onScroll} = this.props;
203
+    if (onScroll) onScroll(event);
204
+  };
205
+
206
+  /**
207
+   * Injects the given javascript string into the web page
208
+   *
209
+   * @param script The script to inject
210
+   */
211
+  injectJavaScript = (script: string) => {
212
+    if (this.webviewRef.current != null)
213
+      this.webviewRef.current.injectJavaScript(script);
214
+  };
215
+
216
+  render(): React.Node {
217
+    const {props} = this;
218
+    const {containerPaddingTop, onScrollWithListener} = props.collapsibleStack;
219
+    return (
220
+      <AnimatedWebView
221
+        ref={this.webviewRef}
222
+        source={{uri: props.url}}
223
+        startInLoadingState
224
+        injectedJavaScript={props.customJS}
225
+        javaScriptEnabled
226
+        renderLoading={this.getRenderLoading}
227
+        renderError={(): React.Node => (
228
+          <ErrorView
229
+            errorCode={ERROR_TYPE.CONNECTION_ERROR}
230
+            onRefresh={this.onRefreshClicked}
231
+          />
232
+        )}
233
+        onNavigationStateChange={(navState: {canGoBack: boolean}) => {
234
+          this.canGoBack = navState.canGoBack;
235
+        }}
236
+        onMessage={props.onMessage}
237
+        onLoad={() => {
238
+          this.injectJavaScript(this.getJavascriptPadding(containerPaddingTop));
239
+        }}
240
+        // Animations
241
+        onScroll={onScrollWithListener(this.onScroll)}
242
+      />
243
+    );
244
+  }
231 245
 }
232 246
 
233 247
 export default withCollapsible(withTheme(WebViewScreen));

Loading…
Cancel
Save