mirror of
https://github.com/jellyfin/jellyfin-expo.git
synced 2025-03-03 19:47:34 +00:00
commit
5a584b4c82
@ -35,7 +35,7 @@
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"react/prop-types": ["error", { "ignore": ["navigation"] }],
|
||||
"react/prop-types": ["error"],
|
||||
|
||||
"block-spacing": ["error"],
|
||||
"brace-style": ["error"],
|
||||
|
36
App.js
36
App.js
@ -23,7 +23,7 @@ export default class App extends React.Component {
|
||||
};
|
||||
|
||||
state = {
|
||||
isLoadingComplete: false
|
||||
isSplashReady: false
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
@ -36,25 +36,25 @@ export default class App extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
|
||||
if (!this.state.isSplashReady && !this.props.skipLoadingScreen) {
|
||||
return (
|
||||
<AppLoading
|
||||
startAsync={this._loadResourcesAsync}
|
||||
onError={this._handleLoadingError}
|
||||
onFinish={this._handleFinishLoading}
|
||||
onError={console.warn}
|
||||
onFinish={() => this.setState({ isSplashReady: true })}
|
||||
autoHideSplash={false}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<ThemeProvider theme={Theme}>
|
||||
<View style={styles.container}>
|
||||
{Platform.OS === 'ios' && <StatusBar barStyle="light-content" />}
|
||||
<AppNavigator />
|
||||
</View>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={Theme}>
|
||||
<View style={styles.container}>
|
||||
{Platform.OS === 'ios' && <StatusBar barStyle="light-content" />}
|
||||
<AppNavigator />
|
||||
</View>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
_loadImagesAsync = () => {
|
||||
@ -74,16 +74,6 @@ export default class App extends React.Component {
|
||||
...this._loadImagesAsync()
|
||||
]);
|
||||
};
|
||||
|
||||
_handleLoadingError = error => {
|
||||
// In this case, you might want to report the error to your error
|
||||
// reporting service, for example Sentry
|
||||
console.warn(error);
|
||||
};
|
||||
|
||||
_handleFinishLoading = () => {
|
||||
this.setState({ isLoadingComplete: true });
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* 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-native';
|
||||
import React from 'react';
|
||||
import App from '../App';
|
||||
import renderer from 'react-test-renderer';
|
||||
import NavigationTestUtils from 'react-navigation/NavigationTestUtils';
|
||||
|
||||
describe('App snapshot', () => {
|
||||
jest.useFakeTimers();
|
||||
beforeEach(() => {
|
||||
NavigationTestUtils.resetInternalState();
|
||||
});
|
||||
|
||||
it('renders the loading screen', async () => {
|
||||
const tree = renderer.create(<App />).toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders the root without loading screen', async () => {
|
||||
const tree = renderer.create(<App skipLoadingScreen />).toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -6,6 +6,7 @@
|
||||
import React from 'react';
|
||||
import { ActivityIndicator, Platform, StyleSheet } from 'react-native';
|
||||
import { Input, colors } from 'react-native-elements';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Colors from '../constants/Colors';
|
||||
@ -15,7 +16,7 @@ import JellyfinValidator from '../utils/JellyfinValidator';
|
||||
|
||||
const sanitizeHost = (url = '') => url.trim();
|
||||
|
||||
export default class ServerInput extends React.Component {
|
||||
class ServerInput extends React.Component {
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object.isRequired,
|
||||
onSuccess: PropTypes.func,
|
||||
@ -126,3 +127,11 @@ const styles = StyleSheet.create({
|
||||
borderBottomWidth: 0
|
||||
}
|
||||
});
|
||||
|
||||
// Inject the Navigation Hook as a prop to mimic the legacy behavior
|
||||
const ServerInputWithNavigation = function(props) {
|
||||
const navigation = useNavigation();
|
||||
return <ServerInput {...props} navigation={navigation} />;
|
||||
};
|
||||
|
||||
export default ServerInputWithNavigation;
|
||||
|
@ -1,28 +0,0 @@
|
||||
/**
|
||||
* 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 { Ionicons } from '@expo/vector-icons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Colors from '../constants/Colors';
|
||||
|
||||
export default class TabBarIcon extends React.Component {
|
||||
static propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
focused: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Ionicons
|
||||
name={this.props.name}
|
||||
size={26}
|
||||
style={{ marginBottom: -3 }}
|
||||
color={this.props.focused ? Colors.tabIconSelected : Colors.tabIconDefault}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@ -12,9 +12,7 @@ export default {
|
||||
backgroundColor,
|
||||
tintColor,
|
||||
headerTintColor: textColor,
|
||||
tabIconDefault: '#ccc',
|
||||
tabIconSelected: tintColor,
|
||||
tabBar: '#fefefe',
|
||||
tabText: '#ccc',
|
||||
errorBackground: 'red',
|
||||
errorText: '#fff',
|
||||
warningBackground: '#EAEB5E',
|
||||
|
@ -3,16 +3,108 @@
|
||||
* 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 { createAppContainer, createSwitchNavigator } from 'react-navigation';
|
||||
import React, { useState } from 'react';
|
||||
import { NavigationContainer, DarkTheme } from '@react-navigation/native';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
import { SplashScreen } from 'expo';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
|
||||
import MainTabNavigator from './MainTabNavigator';
|
||||
import Colors from '../constants/Colors';
|
||||
import StorageKeys from '../constants/Storage';
|
||||
import CachingStorage from '../utils/CachingStorage';
|
||||
import AddServerScreen from '../screens/AddServerScreen';
|
||||
import ServerLoadingScreen from '../screens/ServerLoadingScreen';
|
||||
import HomeScreen from '../screens/HomeScreen';
|
||||
import LoadingScreen from '../screens/LoadingScreen';
|
||||
import SettingsScreen from '../screens/SettingsScreen';
|
||||
|
||||
export default createAppContainer(createSwitchNavigator({
|
||||
ServerLoading: ServerLoadingScreen,
|
||||
AddServer: AddServerScreen,
|
||||
Main: MainTabNavigator
|
||||
}, {
|
||||
initialRouteName: 'ServerLoading'
|
||||
}));
|
||||
// Customize theme for navigator
|
||||
const theme = {
|
||||
...DarkTheme,
|
||||
colors: {
|
||||
...DarkTheme.colors,
|
||||
primary: Colors.tintColor,
|
||||
background: Colors.backgroundColor,
|
||||
text: Colors.tabText,
|
||||
border: 'transparent'
|
||||
}
|
||||
};
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
const Tab = createBottomTabNavigator();
|
||||
|
||||
function TabIcon(routeName, color, size) {
|
||||
let iconName = null;
|
||||
if (routeName === 'Home') {
|
||||
iconName = 'ios-tv';
|
||||
} else if (routeName === 'Settings') {
|
||||
iconName = 'ios-cog';
|
||||
}
|
||||
|
||||
return (
|
||||
iconName ? <Ionicons name={iconName} color={color} size={size} /> : null
|
||||
);
|
||||
}
|
||||
|
||||
function Main() {
|
||||
return (
|
||||
<Tab.Navigator
|
||||
screenOptions={({ route }) => ({
|
||||
tabBarIcon: ({ color, size }) => TabIcon(route.name, color, size)
|
||||
})}
|
||||
>
|
||||
<Tab.Screen name='Home' component={HomeScreen} />
|
||||
<Tab.Screen name='Settings' component={SettingsScreen} />
|
||||
</Tab.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
function AppNavigator() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [servers, setServers] = useState(null);
|
||||
|
||||
async function bootstrap() {
|
||||
// Fetch any saved servers
|
||||
const savedServers = await CachingStorage.getInstance().getItem(StorageKeys.Servers);
|
||||
setServers(savedServers);
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
|
||||
// Display the loading screen until bootstrapping is complete
|
||||
if (isLoading) {
|
||||
return <LoadingScreen />;
|
||||
}
|
||||
|
||||
// Ensure the splash screen is hidden when loading is finished
|
||||
SplashScreen.hide();
|
||||
|
||||
return (
|
||||
<NavigationContainer theme={theme}>
|
||||
<Stack.Navigator headerMode='screen' screenOptions={{ headerShown: false }}>
|
||||
{(servers && servers.length > 0) ?
|
||||
<Stack.Screen
|
||||
name='Main'
|
||||
component={Main}
|
||||
options={({ route }) => {
|
||||
const routeName = route.state ?
|
||||
// Get the currently active route name in the tab navigator
|
||||
route.state.routes[route.state.index].name :
|
||||
// If state doesn't exist, we need to default to `screen` param if available, or the initial screen
|
||||
// In our case, it's "Main" as that's the first screen inside the navigator
|
||||
route.params?.screen || 'Main';
|
||||
return ({
|
||||
headerShown: routeName === 'Settings',
|
||||
title: routeName
|
||||
});
|
||||
}}
|
||||
/> :
|
||||
<Stack.Screen name='AddServer' component={AddServerScreen} />
|
||||
}
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default AppNavigator;
|
||||
|
@ -1,91 +0,0 @@
|
||||
/**
|
||||
* 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 { Platform } from 'react-native';
|
||||
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
|
||||
|
||||
import Colors from '../constants/Colors';
|
||||
import TabBarIcon from '../components/TabBarIcon';
|
||||
import HomeScreen from '../screens/HomeScreen';
|
||||
import SettingsScreen from '../screens/SettingsScreen';
|
||||
|
||||
const defaultNavigationOptions = {
|
||||
headerStyle: {
|
||||
backgroundColor: Colors.backgroundColor
|
||||
},
|
||||
headerTintColor: Colors.headerTintColor
|
||||
};
|
||||
|
||||
const HomeStack = createStackNavigator({
|
||||
Home: HomeScreen
|
||||
}, {
|
||||
defaultNavigationOptions
|
||||
});
|
||||
|
||||
HomeStack.navigationOptions = ({ navigation }) => {
|
||||
const tabBarVisible = (navigation.state && navigation.state.routes[0].params) ?
|
||||
navigation.state.routes[0].params.tabBarVisible : true;
|
||||
|
||||
return {
|
||||
tabBarLabel: 'Home',
|
||||
// eslint-disable-next-line react/display-name, react/prop-types
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<TabBarIcon
|
||||
focused={focused}
|
||||
name={
|
||||
Platform.OS === 'ios'
|
||||
? 'ios-tv'
|
||||
: 'md-tv'
|
||||
}
|
||||
/>
|
||||
),
|
||||
tabBarVisible,
|
||||
tabBarOnPress: ({ navigation, defaultHandler }) => {
|
||||
const goHome = navigation.state && navigation.state.routes[0].params && navigation.state.routes[0].params.goHome;
|
||||
if (navigation.isFocused() && typeof goHome === 'function') {
|
||||
goHome();
|
||||
} else {
|
||||
defaultHandler();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const SettingsStack = createStackNavigator({
|
||||
Settings: SettingsScreen
|
||||
}, {
|
||||
defaultNavigationOptions
|
||||
});
|
||||
|
||||
SettingsStack.navigationOptions = {
|
||||
tabBarLabel: 'Settings',
|
||||
// eslint-disable-next-line react/display-name, react/prop-types
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<TabBarIcon
|
||||
focused={focused}
|
||||
name={
|
||||
Platform.OS === 'ios'
|
||||
? 'ios-cog'
|
||||
: 'md-cog'
|
||||
}
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
export default createBottomTabNavigator({
|
||||
HomeStack,
|
||||
SettingsStack
|
||||
}, {
|
||||
tabBarOptions: {
|
||||
activeTintColor: Colors.tabIconSelected,
|
||||
inactiveTintColor: Colors.tabIconDefault,
|
||||
style: {
|
||||
backgroundColor: Colors.backgroundColor
|
||||
},
|
||||
// Force toolbar label to be under the icon
|
||||
adaptive: false
|
||||
}
|
||||
});
|
@ -12,6 +12,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-community/masked-view": "0.1.6",
|
||||
"@react-navigation/bottom-tabs": "^5.2.6",
|
||||
"@react-navigation/native": "^5.1.5",
|
||||
"@react-navigation/stack": "^5.2.10",
|
||||
"expo": "^37.0.0",
|
||||
"expo-asset": "~8.1.3",
|
||||
"expo-constants": "~9.0.0",
|
||||
@ -28,8 +31,7 @@
|
||||
"react-native-reanimated": "~1.7.0",
|
||||
"react-native-safe-area-context": "0.7.3",
|
||||
"react-native-screens": "~2.2.0",
|
||||
"react-native-webview": "8.1.1",
|
||||
"react-navigation": "^3.0.9"
|
||||
"react-native-webview": "8.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^10.0.2",
|
||||
@ -39,7 +41,7 @@
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.14.3",
|
||||
"expo-cli": "^3.17.17",
|
||||
"expo-cli": "^3.18.2",
|
||||
"jest-expo": "^37.0.0"
|
||||
},
|
||||
"private": true
|
||||
|
@ -21,7 +21,6 @@ export default class AddServerScreen extends React.Component {
|
||||
/>
|
||||
</View>
|
||||
<ServerInput
|
||||
navigation={this.props.navigation}
|
||||
containerStyle={styles.serverTextContainer}
|
||||
/>
|
||||
</View>
|
||||
|
@ -7,8 +7,10 @@ import React from 'react';
|
||||
import { Platform, RefreshControl, StatusBar, StyleSheet, ScrollView, View } from 'react-native';
|
||||
import { Button, Text } from 'react-native-elements';
|
||||
import { WebView } from 'react-native-webview';
|
||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||
import Constants from 'expo-constants';
|
||||
import * as ScreenOrientation from 'expo-screen-orientation';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Colors from '../constants/Colors';
|
||||
import StorageKeys from '../constants/Storage';
|
||||
@ -31,7 +33,7 @@ ${NativeShell}
|
||||
true;
|
||||
`;
|
||||
|
||||
export default class HomeScreen extends React.Component {
|
||||
class HomeScreen extends React.Component {
|
||||
state = {
|
||||
server: null,
|
||||
serverUrl: null,
|
||||
@ -41,9 +43,10 @@ export default class HomeScreen extends React.Component {
|
||||
isRefreshing: false
|
||||
};
|
||||
|
||||
static navigationOptions = {
|
||||
header: null
|
||||
};
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object.isRequired,
|
||||
route: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
async bootstrapAsync() {
|
||||
let server = await CachingStorage.getInstance().getItem(StorageKeys.Servers);
|
||||
@ -153,22 +156,29 @@ export default class HomeScreen extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// Expose the goHome method to navigation props
|
||||
this.props.navigation.setParams({ goHome: () => this.onGoHome() });
|
||||
// Override the default tab press behavior so a second press sends the webview home
|
||||
this.props.navigation.addListener('tabPress', e => {
|
||||
if (this.props.navigation.isFocused()) {
|
||||
// Prevent default behavior
|
||||
e.preventDefault();
|
||||
|
||||
this.onGoHome();
|
||||
}
|
||||
});
|
||||
// Bootstrap component state
|
||||
this.bootstrapAsync();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (typeof this.props.navigation.state.params.activeServer != 'undefined' &&
|
||||
prevProps.navigation.state.params.activeServer !== this.props.navigation.state.params.activeServer) {
|
||||
if (typeof this.props.route.params?.activeServer != 'undefined' &&
|
||||
prevProps.route.params?.activeServer !== this.props.route.params?.activeServer) {
|
||||
this.bootstrapAsync();
|
||||
}
|
||||
if (prevState.isFullscreen !== this.state.isFullscreen) {
|
||||
// Update the screen orientation
|
||||
this.updateScreenOrientation();
|
||||
// Show/hide the bottom tab bar
|
||||
this.props.navigation.setParams({
|
||||
this.props.navigation.setOptions({
|
||||
tabBarVisible: !this.state.isFullscreen
|
||||
});
|
||||
// Show/hide the status bar
|
||||
@ -256,3 +266,10 @@ const styles = StyleSheet.create({
|
||||
textAlign: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
// Inject the Navigation Hook as a prop to mimic the legacy behavior
|
||||
const HomeScreenWithNavigation = function(props) {
|
||||
return <HomeScreen {...props} navigation={useNavigation()} route={useRoute()} />;
|
||||
};
|
||||
|
||||
export default HomeScreenWithNavigation;
|
||||
|
39
screens/LoadingScreen.js
Normal file
39
screens/LoadingScreen.js
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 * as React from 'react';
|
||||
import { ActivityIndicator, Image, StyleSheet, View } from 'react-native';
|
||||
|
||||
import Colors from '../constants/Colors';
|
||||
import { SplashScreen } from 'expo';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.backgroundColor
|
||||
},
|
||||
splash: {
|
||||
flex: 1,
|
||||
resizeMode: 'contain',
|
||||
width: undefined,
|
||||
height: undefined
|
||||
}
|
||||
});
|
||||
|
||||
function LoadingScreen() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image
|
||||
style={styles.splash}
|
||||
source={require('../assets/images/splash.png')}
|
||||
onLoad={() => SplashScreen.hide()}
|
||||
fadeDuration={0} // we need to adjust Android devices (https://facebook.github.io/react-native/docs/image#fadeduration) fadeDuration prop to `0` as it's default value is `300`
|
||||
/>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default LoadingScreen;
|
@ -1,68 +0,0 @@
|
||||
/**
|
||||
* 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 { ActivityIndicator, Image, StyleSheet, View } from 'react-native';
|
||||
import { SplashScreen } from 'expo';
|
||||
|
||||
import Colors from '../constants/Colors';
|
||||
import StorageKeys from '../constants/Storage';
|
||||
import CachingStorage from '../utils/CachingStorage';
|
||||
|
||||
export default class ServerLoadingScreen extends React.Component {
|
||||
state = { areResourcesReady: false };
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
SplashScreen.preventAutoHide();
|
||||
}
|
||||
|
||||
async getServers() {
|
||||
return await CachingStorage.getInstance().getItem(StorageKeys.Servers);
|
||||
}
|
||||
|
||||
async bootstrapAsync() {
|
||||
const servers = await this.getServers();
|
||||
const hasServer = !!servers && servers.length > 0;
|
||||
console.info('servers', servers, hasServer);
|
||||
|
||||
// Ensure the splash screen is hidden
|
||||
SplashScreen.hide();
|
||||
// Navigate to the appropriate screen
|
||||
this.props.navigation.navigate(hasServer ? 'Main' : 'AddServer');
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.bootstrapAsync();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.areResourcesReady) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image
|
||||
style={{ flex: 1, resizeMode: 'contain', width: undefined, height: undefined }}
|
||||
source={require('../assets/images/splash.png')}
|
||||
onLoadEnd={() => {
|
||||
// wait for image's content to fully load [`Image#onLoadEnd`] (https://facebook.github.io/react-native/docs/image#onloadend)
|
||||
SplashScreen.hide();
|
||||
}}
|
||||
fadeDuration={0} // we need to adjust Android devices (https://facebook.github.io/react-native/docs/image#fadeduration) fadeDuration prop to `0` as it's default value is `300`
|
||||
/>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.backgroundColor
|
||||
}
|
||||
});
|
@ -17,6 +17,8 @@ import {
|
||||
import { Button, colors, ListItem, Text, Icon, Overlay } from 'react-native-elements';
|
||||
import Constants from 'expo-constants';
|
||||
import Url from 'url';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import ServerInput from '../components/ServerInput';
|
||||
import SettingSection from '../components/SettingSection';
|
||||
@ -28,10 +30,10 @@ import JellyfinValidator from '../utils/JellyfinValidator';
|
||||
import { getAppName } from '../utils/Device';
|
||||
import { openBrowser } from '../utils/WebBrowser';
|
||||
|
||||
export default class SettingsScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Settings'
|
||||
};
|
||||
class SettingsScreen extends React.Component {
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
state = {
|
||||
isAddServerVisible: false,
|
||||
@ -166,7 +168,7 @@ export default class SettingsScreen extends React.Component {
|
||||
// Save to storage cache
|
||||
await CachingStorage.getInstance().setItem(StorageKeys.Servers, servers);
|
||||
// Navigate to the loading screen
|
||||
this.props.navigation.navigate('ServerLoading');
|
||||
this.props.navigation.navigate('Loading');
|
||||
}
|
||||
|
||||
async resetApplication() {
|
||||
@ -175,7 +177,7 @@ export default class SettingsScreen extends React.Component {
|
||||
// Reset the storage cache
|
||||
CachingStorage.instance = null;
|
||||
// Navigate to the loading screen
|
||||
this.props.navigation.navigate('ServerLoading');
|
||||
this.props.navigation.navigate('Loading');
|
||||
}
|
||||
|
||||
onDeleteServer(index) {
|
||||
@ -264,7 +266,6 @@ export default class SettingsScreen extends React.Component {
|
||||
onBackdropPress={() => this.setState({ isAddServerVisible: false })}
|
||||
>
|
||||
<ServerInput
|
||||
navigation={this.props.navigation}
|
||||
onSuccess={() => {
|
||||
this.setState({ isAddServerVisible: false });
|
||||
this.bootstrapAsync();
|
||||
@ -290,3 +291,11 @@ const styles = StyleSheet.create({
|
||||
fontSize: 15
|
||||
}
|
||||
});
|
||||
|
||||
// Inject the Navigation Hook as a prop to mimic the legacy behavior
|
||||
const SettingsScreenWithNavigation = function(props) {
|
||||
const navigation = useNavigation();
|
||||
return <SettingsScreen {...props} navigation={navigation} />;
|
||||
};
|
||||
|
||||
export default SettingsScreenWithNavigation;
|
||||
|
Loading…
x
Reference in New Issue
Block a user