-
-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #119 from thornbill/refactor-home-screen
Refactor HomeScreen and fix pull to refresh
- Loading branch information
Showing
10 changed files
with
363 additions
and
271 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/** | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
import React, { useEffect, useRef, useState } from 'react'; | ||
import { useNavigation } from '@react-navigation/native'; | ||
import { action } from 'mobx'; | ||
import { observer } from 'mobx-react'; | ||
import Constants from 'expo-constants'; | ||
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake'; | ||
|
||
import { useStores } from '../hooks/useStores'; | ||
import { getAppName, getSafeDeviceName } from '../utils/Device'; | ||
import NativeShell from '../utils/NativeShell'; | ||
import { openBrowser } from '../utils/WebBrowser'; | ||
import RefreshWebView from './RefreshWebView'; | ||
|
||
const injectedJavaScript = ` | ||
window.ExpoAppInfo = { | ||
appName: '${getAppName()}', | ||
appVersion: '${Constants.nativeAppVersion}', | ||
deviceId: '${Constants.deviceId}', | ||
deviceName: '${getSafeDeviceName().replace(/'/g, '\\\'')}' | ||
}; | ||
${NativeShell} | ||
true; | ||
`; | ||
|
||
const NativeShellWebView = observer((props) => { | ||
const { rootStore } = useStores(); | ||
const navigation = useNavigation(); | ||
const [isRefreshing, setIsRefreshing] = useState(false); | ||
const webview = useRef(null); | ||
|
||
const server = rootStore.serverStore.servers[rootStore.settingStore.activeServer]; | ||
|
||
useEffect(() => { | ||
navigation.addListener('tabPress', e => { | ||
if (navigation.isFocused()) { | ||
// Prevent default behavior | ||
e.preventDefault(); | ||
// Call the web router to navigate home | ||
webview.current?.injectJavaScript('window.Emby && window.Emby.Page && typeof window.Emby.Page.goHome === "function" && window.Emby.Page.goHome();'); | ||
} | ||
}); | ||
}, []); | ||
|
||
const onRefresh = () => { | ||
// Disable pull to refresh when in fullscreen | ||
if (rootStore.isFullscreen) return; | ||
setIsRefreshing(true); | ||
webview.current?.reload(); | ||
setIsRefreshing(false); | ||
}; | ||
|
||
const onMessage = action(({ nativeEvent: state }) => { | ||
try { | ||
const { event, data } = JSON.parse(state.data); | ||
switch (event) { | ||
case 'enableFullscreen': | ||
rootStore.isFullscreen = true; | ||
break; | ||
case 'disableFullscreen': | ||
rootStore.isFullscreen = false; | ||
break; | ||
case 'openUrl': | ||
console.log('Opening browser for external url', data.url); | ||
openBrowser(data.url); | ||
break; | ||
case 'updateMediaSession': | ||
// Keep the screen awake when music is playing | ||
if (rootStore.settingStore.isScreenLockEnabled) { | ||
activateKeepAwake(); | ||
} | ||
break; | ||
case 'hideMediaSession': | ||
// When music session stops disable keep awake | ||
if (rootStore.settingStore.isScreenLockEnabled) { | ||
deactivateKeepAwake(); | ||
} | ||
break; | ||
case 'console.debug': | ||
// console.debug('[Browser Console]', data); | ||
break; | ||
case 'console.error': | ||
console.error('[Browser Console]', data); | ||
break; | ||
case 'console.info': | ||
// console.info('[Browser Console]', data); | ||
break; | ||
case 'console.log': | ||
// console.log('[Browser Console]', data); | ||
break; | ||
case 'console.warn': | ||
console.warn('[Browser Console]', data); | ||
break; | ||
default: | ||
console.debug('[HomeScreen.onMessage]', event, data); | ||
} | ||
} catch (ex) { | ||
console.warn('Exception handling message', state.data); | ||
} | ||
}); | ||
|
||
return ( | ||
<RefreshWebView | ||
ref={webview} | ||
source={{ uri: server.urlString }} | ||
// Inject javascript for NativeShell | ||
injectedJavaScriptBeforeContentLoaded={injectedJavaScript} | ||
onMessage={onMessage} | ||
isRefreshing={isRefreshing} | ||
onRefresh={onRefresh} | ||
// Pass through additional props | ||
{...props} | ||
// Make scrolling feel faster | ||
decelerationRate='normal' | ||
// Media playback options to fix video player | ||
allowsInlineMediaPlayback={true} | ||
mediaPlaybackRequiresUserAction={false} | ||
// Use WKWebView on iOS | ||
useWebKit={true} | ||
/> | ||
); | ||
}); | ||
|
||
export default NativeShellWebView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
import React from 'react'; | ||
import { StyleSheet, View } from 'react-native'; | ||
import { Button, Text } from 'react-native-elements'; | ||
import { useTranslation } from 'react-i18next'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import Colors from '../constants/Colors'; | ||
import { getIconName } from '../utils/Icons'; | ||
|
||
const OfflineErrorView = ({ onRetry }) => { | ||
const { t } = useTranslation(); | ||
|
||
return ( | ||
<View style={styles.container}> | ||
<Text style={styles.error}>{t('home.offline')}</Text> | ||
<Button | ||
buttonStyle={{ | ||
marginLeft: 15, | ||
marginRight: 15 | ||
}} | ||
icon={{ | ||
name: getIconName('refresh'), | ||
type: 'ionicon' | ||
}} | ||
title={t('home.retry')} | ||
onPress={onRetry} | ||
/> | ||
</View>); | ||
}; | ||
|
||
OfflineErrorView.propTypes = { | ||
onRetry: PropTypes.func.isRequired | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
backgroundColor: Colors.backgroundColor | ||
}, | ||
error: { | ||
fontSize: 17, | ||
paddingBottom: 17, | ||
textAlign: 'center' | ||
} | ||
}); | ||
|
||
export default OfflineErrorView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/** | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
import React, { useState } from 'react'; | ||
import { WebView } from 'react-native-webview'; | ||
import { RefreshControl, Dimensions, StyleSheet } from 'react-native'; | ||
import { ScrollView } from 'react-native-gesture-handler'; | ||
import PropTypes from 'prop-types'; | ||
|
||
const RefreshWebView = React.forwardRef( | ||
function RefreshWebView({ isRefreshing, onRefresh, refreshControlProps, ...webViewProps }, ref) { | ||
const [height, setHeight] = useState(Dimensions.get('screen').height); | ||
const [isEnabled, setEnabled] = useState(typeof onRefresh === 'function'); | ||
|
||
return ( | ||
<ScrollView | ||
onLayout={(e) => setHeight(e.nativeEvent.layout.height)} | ||
refreshControl={ | ||
<RefreshControl | ||
onRefresh={onRefresh} | ||
refreshing={isRefreshing} | ||
enabled={isEnabled} | ||
{...refreshControlProps} | ||
/> | ||
} | ||
style={styles.view}> | ||
<WebView | ||
ref={ref} | ||
{...webViewProps} | ||
onScroll={(e) => | ||
setEnabled( | ||
typeof onRefresh === 'function' && | ||
e.nativeEvent.contentOffset.y === 0 | ||
) | ||
} | ||
style={{ | ||
...styles.view, | ||
height, | ||
...webViewProps.style | ||
}} | ||
/> | ||
</ScrollView> | ||
); | ||
} | ||
); | ||
|
||
RefreshWebView.propTypes = { | ||
isRefreshing: PropTypes.bool.isRequired, | ||
onRefresh: PropTypes.func, | ||
refreshControlProps: PropTypes.any | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
view: { | ||
flex: 1, | ||
height: '100%' | ||
} | ||
}); | ||
|
||
export default RefreshWebView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.