From c9a4a983574e2a40a555a712a1b7e9bb376b438e Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 24 Jun 2020 17:01:48 -0400 Subject: [PATCH 1/3] Migrate to mobx for global app state --- App.js | 33 ++++++- babel.config.js | 2 +- components/ServerInput.js | 25 ++--- hooks/useStores.js | 16 ++++ navigation/AppNavigator.js | 30 ++---- package.json | 4 + screens/HomeScreen.js | 30 +++--- screens/SettingsScreen.js | 51 +++++----- stores/ServerStore.js | 23 +++++ stores/SettingStore.js | 16 ++++ utils/CachingStorage.js | 4 + yarn.lock | 188 +++++++++++++++++++++++++++++++++++++ 12 files changed, 342 insertions(+), 80 deletions(-) create mode 100644 hooks/useStores.js create mode 100644 stores/ServerStore.js create mode 100644 stores/SettingStore.js diff --git a/App.js b/App.js index ae5af339..d5223348 100644 --- a/App.js +++ b/App.js @@ -3,10 +3,14 @@ * 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 'mobx-react-lite/batchingForReactNative'; + import React, { useEffect, useState } from 'react'; -import { Platform, StatusBar } from 'react-native'; +import { AsyncStorage, Platform, StatusBar } from 'react-native'; import { ThemeProvider } from 'react-native-elements'; import { SafeAreaProvider } from 'react-native-safe-area-context'; +import { observer } from 'mobx-react'; +import { create } from 'mobx-persist'; import { AppLoading } from 'expo'; import { Asset } from 'expo-asset'; import * as Font from 'expo-font'; @@ -14,17 +18,40 @@ import * as ScreenOrientation from 'expo-screen-orientation'; import { Ionicons } from '@expo/vector-icons'; import PropTypes from 'prop-types'; +import { useStores } from './hooks/useStores'; +import StorageKeys from './constants/Storage'; import AppNavigator from './navigation/AppNavigator'; +import CachingStorage from './utils/CachingStorage'; import Theme from './utils/Theme'; -function App({ skipLoadingScreen }) { +const hydrate = create({ + storage: AsyncStorage +}); + +const App = observer(({ skipLoadingScreen }) => { const [isSplashReady, setIsSplashReady] = useState(false); + const { serverStore, settingStore } = useStores(); + + const hydrateStores = async () => { + // Use data from old location as the initial values + // TODO: Remove this for next release + const servers = await CachingStorage.getInstance().getItem(StorageKeys.Servers); + const activeServer = await CachingStorage.getInstance().getItem(StorageKeys.ActiveServer); + hydrate('servers', serverStore, servers || []); + hydrate('settings', settingStore, { activeServer: activeServer || 0 }); + + // Remove old data values + await AsyncStorage.multiRemove(Object.values(StorageKeys)); + }; useEffect(() => { // Lock portrait orientation on iPhone if (Platform.OS === 'ios' && !Platform.isPad) { ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP); } + + // Hydrate mobx data stores + hydrateStores(); }, []); const loadImagesAsync = () => { @@ -64,7 +91,7 @@ function App({ skipLoadingScreen }) { ); -} +}); App.propTypes = { skipLoadingScreen: PropTypes.bool diff --git a/babel.config.js b/babel.config.js index f38a9e8c..a9294a43 100644 --- a/babel.config.js +++ b/babel.config.js @@ -6,6 +6,6 @@ module.exports = function(api) { api.cache(true); return { - presets: ['babel-preset-expo'] + presets: ['babel-preset-expo', 'mobx'] }; }; diff --git a/components/ServerInput.js b/components/ServerInput.js index 1f861d27..ca7d0aa6 100644 --- a/components/ServerInput.js +++ b/components/ServerInput.js @@ -7,18 +7,21 @@ 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 { observer } from 'mobx-react'; import PropTypes from 'prop-types'; +import { useStores } from '../hooks/useStores'; import Colors from '../constants/Colors'; -import StorageKeys from '../constants/Storage'; -import CachingStorage from '../utils/CachingStorage'; import JellyfinValidator from '../utils/JellyfinValidator'; const sanitizeHost = (url = '') => url.trim(); +@observer class ServerInput extends React.Component { static propTypes = { navigation: PropTypes.object.isRequired, + serverStore: PropTypes.object.isRequired, + settingStore: PropTypes.object.isRequired, onSuccess: PropTypes.func, successScreen: PropTypes.string } @@ -67,11 +70,9 @@ class ServerInput extends React.Component { return; } - // Save the server details to app storage - let servers = await CachingStorage.getInstance().getItem(StorageKeys.Servers) || []; - servers = servers.concat([{ url }]); - await CachingStorage.getInstance().setItem(StorageKeys.Servers, servers); - await CachingStorage.getInstance().setItem(StorageKeys.ActiveServer, servers.length - 1); + // Save the server details + this.props.serverStore.addServer({ url }); + this.props.settingStore.activeServer = this.props.serverStore.servers.length - 1; // Call the success callback if present if (this.props.onSuccess) { this.props.onSuccess(); @@ -81,7 +82,7 @@ class ServerInput extends React.Component { index: 0, routes: [{ name: this.props.successScreen || 'Main', - props: { activeServer: servers.length - 1 } + props: { activeServer: this.props.settingStore.activeServer } }] }); } else { @@ -135,9 +136,9 @@ const styles = StyleSheet.create({ }); // Inject the Navigation Hook as a prop to mimic the legacy behavior -const ServerInputWithNavigation = function(props) { - const navigation = useNavigation(); - return ; -}; +const ServerInputWithNavigation = observer((props) => { + const stores = useStores(); + return ; +}); export default ServerInputWithNavigation; diff --git a/hooks/useStores.js b/hooks/useStores.js new file mode 100644 index 00000000..19f557ed --- /dev/null +++ b/hooks/useStores.js @@ -0,0 +1,16 @@ +/** + * 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 { createContext, useContext } from 'react'; + +import ServerStore from '../stores/ServerStore'; +import SettingStore from '../stores/SettingStore'; + +export const storesContext = createContext({ + serverStore: new ServerStore(), + settingStore: new SettingStore() +}); + +export const useStores = () => useContext(storesContext); diff --git a/navigation/AppNavigator.js b/navigation/AppNavigator.js index 685e1bae..877f2588 100644 --- a/navigation/AppNavigator.js +++ b/navigation/AppNavigator.js @@ -3,19 +3,18 @@ * 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 React from 'react'; import { NavigationContainer, DarkTheme } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { observer } from 'mobx-react'; import { SplashScreen } from 'expo'; import { Ionicons } from '@expo/vector-icons'; +import { useStores } from '../hooks/useStores'; import Colors from '../constants/Colors'; -import StorageKeys from '../constants/Storage'; -import CachingStorage from '../utils/CachingStorage'; import AddServerScreen from '../screens/AddServerScreen'; import HomeScreen from '../screens/HomeScreen'; -import LoadingScreen from '../screens/LoadingScreen'; import SettingsScreen from '../screens/SettingsScreen'; // Customize theme for navigator @@ -63,23 +62,8 @@ function Main() { ); } -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 ; - } +const AppNavigator = observer(() => { + const { serverStore } = useStores(); // Ensure the splash screen is hidden when loading is finished SplashScreen.hide(); @@ -87,7 +71,7 @@ function AppNavigator() { return ( 0) ? 'Main' : 'AddServer'} + initialRouteName={(serverStore.servers.length > 0) ? 'Main' : 'AddServer'} headerMode='screen' screenOptions={{ headerShown: false }} > @@ -111,6 +95,6 @@ function AppNavigator() { ); -} +}); export default AppNavigator; diff --git a/package.json b/package.json index 0c2fc724..d6d16017 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,9 @@ "expo-keep-awake": "~8.1.0", "expo-screen-orientation": "~1.0.0", "expo-web-browser": "~8.1.0", + "mobx": "^5.15.4", + "mobx-persist": "^0.4.1", + "mobx-react": "^6.2.2", "prop-types": "^15.7.2", "react": "16.9.0", "react-lifecycles-compat": "^3.0.4", @@ -37,6 +40,7 @@ "devDependencies": { "babel-eslint": "^10.0.2", "babel-preset-expo": "^8.1.0", + "babel-preset-mobx": "^2.0.0", "eslint": "^6.1.0", "eslint-plugin-eslint-comments": "^3.1.2", "eslint-plugin-import": "^2.20.2", diff --git a/screens/HomeScreen.js b/screens/HomeScreen.js index f9d97eaa..9ec6f2f3 100644 --- a/screens/HomeScreen.js +++ b/screens/HomeScreen.js @@ -9,14 +9,14 @@ import { Button, Text } from 'react-native-elements'; import { SafeAreaView } from 'react-native-safe-area-context'; import { WebView } from 'react-native-webview'; import { useNavigation, useRoute } from '@react-navigation/native'; +import { observer } from 'mobx-react'; import Constants from 'expo-constants'; import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake'; import * as ScreenOrientation from 'expo-screen-orientation'; import PropTypes from 'prop-types'; +import { useStores } from '../hooks/useStores'; import Colors from '../constants/Colors'; -import StorageKeys from '../constants/Storage'; -import CachingStorage from '../utils/CachingStorage'; import { getAppName, getSafeDeviceName } from '../utils/Device'; import JellyfinValidator from '../utils/JellyfinValidator'; import NativeShell from '../utils/NativeShell'; @@ -35,6 +35,7 @@ ${NativeShell} true; `; +@observer class HomeScreen extends React.Component { state = { server: null, @@ -47,21 +48,25 @@ class HomeScreen extends React.Component { static propTypes = { navigation: PropTypes.object.isRequired, - route: PropTypes.object.isRequired + route: PropTypes.object.isRequired, + serverStore: PropTypes.object.isRequired, + settingStore: PropTypes.object.isRequired } async bootstrapAsync() { - let server = await CachingStorage.getInstance().getItem(StorageKeys.Servers); - let activeServer = await CachingStorage.getInstance().getItem(StorageKeys.ActiveServer) || 0; + const servers = this.props.serverStore.servers; + let activeServer = this.props.settingStore.activeServer; // If the activeServer is greater than the length of the server array, reset it to 0 - if (activeServer && server.length && activeServer > server.length - 1) { - await CachingStorage.getInstance().setItem(StorageKeys.ActiveServer, 0); + if (activeServer && servers.length && activeServer > servers.length - 1) { + // TODO: Verify this updates the store + this.props.settingStore.activeServer = 0; activeServer = 0; } - if (server.length > 0) { - server = server[activeServer]; + let server; + if (servers.length > 0) { + server = servers[activeServer]; } const serverUrl = JellyfinValidator.getServerUrl(server); @@ -287,8 +292,9 @@ const styles = StyleSheet.create({ }); // Inject the Navigation Hook as a prop to mimic the legacy behavior -const HomeScreenWithNavigation = function(props) { - return ; -}; +const HomeScreenWithNavigation = observer((props) => { + const stores = useStores(); + return ; +}); export default HomeScreenWithNavigation; diff --git a/screens/SettingsScreen.js b/screens/SettingsScreen.js index 66b94fb4..8f34e7c8 100644 --- a/screens/SettingsScreen.js +++ b/screens/SettingsScreen.js @@ -16,24 +16,27 @@ import { } from 'react-native'; import { Button, colors, ListItem, Text, Icon, Overlay } from 'react-native-elements'; import { SafeAreaView } from 'react-native-safe-area-context'; +import { useNavigation } from '@react-navigation/native'; +import { observer } from 'mobx-react'; import Constants from 'expo-constants'; import Url from 'url'; -import { useNavigation } from '@react-navigation/native'; import PropTypes from 'prop-types'; +import { useStores } from '../hooks/useStores'; import ServerInput from '../components/ServerInput'; import SettingsSection from '../components/SettingsSection'; import Colors from '../constants/Colors'; import Links from '../constants/Links'; -import StorageKeys from '../constants/Storage'; -import CachingStorage from '../utils/CachingStorage'; import JellyfinValidator from '../utils/JellyfinValidator'; import { getAppName } from '../utils/Device'; import { openBrowser } from '../utils/WebBrowser'; +@observer class SettingsScreen extends React.Component { static propTypes = { - navigation: PropTypes.object.isRequired + navigation: PropTypes.object.isRequired, + serverStore: PropTypes.object.isRequired, + settingStore: PropTypes.object.isRequired } state = { @@ -80,7 +83,7 @@ class SettingsScreen extends React.Component { }} subtitle={subtitle} leftElement={( - index === this.state.activeServer ? ( + index === this.props.settingStore.activeServer ? ( { - this.setState({ - activeServer: index - }); - await CachingStorage.getInstance().setItem(StorageKeys.ActiveServer, index); + this.props.settingStore.activeServer = index; this.props.navigation.navigate('Home', { activeServer: index }); }} />); }; async bootstrapAsync() { - const activeServer = await CachingStorage.getInstance().getItem(StorageKeys.ActiveServer) || 0; - let servers = await CachingStorage.getInstance().getItem(StorageKeys.Servers); + let { servers } = this.props.serverStore; servers = servers.map(async (server) => { let serverUrl; @@ -156,21 +155,16 @@ class SettingsScreen extends React.Component { console.log('bootstrapAsync', servers); this.setState({ - activeServer, servers }); } async deleteServer(index) { - // Get the current list of servers - const servers = this.state.servers; - // Remove one server at index - servers.splice(index, 1); - // Save to storage cache - await CachingStorage.getInstance().setItem(StorageKeys.ActiveServer, 0); - await CachingStorage.getInstance().setItem(StorageKeys.Servers, servers); + // Remove server and update active server + this.props.serverStore.removeServer(index); + this.props.settingStore.activeServer = 0; - if (servers.length > 0) { + if (this.props.serverStore.servers.length > 0) { // More servers exist, update state and navigate home this.bootstrapAsync(); this.props.navigation.navigate('Home', { activeServer: 0 }); @@ -181,10 +175,9 @@ class SettingsScreen extends React.Component { } async resetApplication() { - // Remove all storage items used in the app - await AsyncStorage.multiRemove(Object.values(StorageKeys)); - // Reset the storage cache - CachingStorage.instance = null; + // Reset data in stores + this.props.serverStore.servers = []; + this.props.settingStore.activeServer = 0; // Navigate to the loading screen this.props.navigation.navigate('AddServer'); } @@ -230,7 +223,7 @@ class SettingsScreen extends React.Component { data={this.state.servers} renderItem={this._renderServer} scrollEnabled={false} - extraData={this.state.activeServer} + extraData={this.props.settingStore.activeServer} /> ) : ( @@ -302,9 +295,9 @@ const styles = StyleSheet.create({ }); // Inject the Navigation Hook as a prop to mimic the legacy behavior -const SettingsScreenWithNavigation = function(props) { - const navigation = useNavigation(); - return ; -}; +const SettingsScreenWithNavigation = observer((props) => { + const stores = useStores(); + return ; +}); export default SettingsScreenWithNavigation; diff --git a/stores/ServerStore.js b/stores/ServerStore.js new file mode 100644 index 00000000..67f75d02 --- /dev/null +++ b/stores/ServerStore.js @@ -0,0 +1,23 @@ +/** + * 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 { action, observable } from 'mobx'; +import { persist } from 'mobx-persist'; + +export default class ServerStore { + @persist('list') + @observable + servers = [] + + @action + addServer(server) { + this.servers.push(server); + } + + @action + removeServer(index) { + this.servers.splice(index, 1); + } +} diff --git a/stores/SettingStore.js b/stores/SettingStore.js new file mode 100644 index 00000000..b633d13e --- /dev/null +++ b/stores/SettingStore.js @@ -0,0 +1,16 @@ +/** + * 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 { observable } from 'mobx'; +import { persist } from 'mobx-persist'; + +/** + * Data store for application settings + */ +export default class SettingStore { + @persist + @observable + activeServer = 0 +} diff --git a/utils/CachingStorage.js b/utils/CachingStorage.js index 13ddf03d..97b599e8 100644 --- a/utils/CachingStorage.js +++ b/utils/CachingStorage.js @@ -5,6 +5,10 @@ */ import { AsyncStorage } from 'react-native'; +/** + * AsyncStorage wrapper with in memory caching + * @deprecated + */ export default class CachingStorage { static instance = null; diff --git a/yarn.lock b/yarn.lock index cbb180a3..b3d1e534 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,6 +16,13 @@ dependencies: "@babel/highlight" "^7.8.3" +"@babel/code-frame@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.3.tgz#324bcfd8d35cd3d47dae18cde63d752086435e9a" + integrity sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg== + dependencies: + "@babel/highlight" "^7.10.3" + "@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0": version "7.9.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c" @@ -57,6 +64,16 @@ lodash "^4.17.13" source-map "^0.5.0" +"@babel/generator@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.3.tgz#32b9a0d963a71d7a54f5f6c15659c3dbc2a523a5" + integrity sha512-drt8MUHbEqRzNR0xnF8nMehbY11b1SDkRw03PSNH/3Rb2Z35oxkddVSi3rcaak0YJQ86PCuE7Qx1jSFhbLNBMA== + dependencies: + "@babel/types" "^7.10.3" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" @@ -100,6 +117,18 @@ levenary "^1.1.1" semver "^5.5.0" +"@babel/helper-create-class-features-plugin@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.3.tgz#2783daa6866822e3d5ed119163b50f0fc3ae4b35" + integrity sha512-iRT9VwqtdFmv7UheJWthGc/h2s7MqoweBF9RUj77NFZsg9VfISvBTum3k6coAhJ8RWv2tj3yUjA03HxPd0vfpQ== + dependencies: + "@babel/helper-function-name" "^7.10.3" + "@babel/helper-member-expression-to-functions" "^7.10.3" + "@babel/helper-optimise-call-expression" "^7.10.3" + "@babel/helper-plugin-utils" "^7.10.3" + "@babel/helper-replace-supers" "^7.10.1" + "@babel/helper-split-export-declaration" "^7.10.1" + "@babel/helper-create-class-features-plugin@^7.8.3": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.9.5.tgz#79753d44017806b481017f24b02fd4113c7106ea" @@ -138,6 +167,15 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-function-name@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.3.tgz#79316cd75a9fa25ba9787ff54544307ed444f197" + integrity sha512-FvSj2aiOd8zbeqijjgqdMDSyxsGHaMt5Tr0XjQsGKHD3/1FP3wksjnLAWzxw7lvXiej8W1Jt47SKTZ6upQNiRw== + dependencies: + "@babel/helper-get-function-arity" "^7.10.3" + "@babel/template" "^7.10.3" + "@babel/types" "^7.10.3" + "@babel/helper-function-name@^7.8.3", "@babel/helper-function-name@^7.9.5": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" @@ -147,6 +185,13 @@ "@babel/template" "^7.8.3" "@babel/types" "^7.9.5" +"@babel/helper-get-function-arity@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.3.tgz#3a28f7b28ccc7719eacd9223b659fdf162e4c45e" + integrity sha512-iUD/gFsR+M6uiy69JA6fzM5seno8oE85IYZdbVVEuQaZlEzMO2MXblh+KSPJgsZAUx0EEbWXU0yJaW7C9CdAVg== + dependencies: + "@babel/types" "^7.10.3" + "@babel/helper-get-function-arity@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" @@ -161,6 +206,13 @@ dependencies: "@babel/types" "^7.8.3" +"@babel/helper-member-expression-to-functions@^7.10.1", "@babel/helper-member-expression-to-functions@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.3.tgz#bc3663ac81ac57c39148fef4c69bf48a77ba8dd6" + integrity sha512-q7+37c4EPLSjNb2NmWOjNwj0+BOyYlssuQ58kHEWk1Z78K5i8vTUsteq78HMieRPQSl/NtpQyJfdjt3qZ5V2vw== + dependencies: + "@babel/types" "^7.10.3" + "@babel/helper-member-expression-to-functions@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" @@ -188,6 +240,13 @@ "@babel/types" "^7.9.0" lodash "^4.17.13" +"@babel/helper-optimise-call-expression@^7.10.1", "@babel/helper-optimise-call-expression@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.3.tgz#f53c4b6783093195b0f69330439908841660c530" + integrity sha512-kT2R3VBH/cnSz+yChKpaKRJQJWxdGoc6SjioRId2wkeV3bK0wLLioFpJROrX0U4xr/NmxSSAWT/9Ih5snwIIzg== + dependencies: + "@babel/types" "^7.10.3" + "@babel/helper-optimise-call-expression@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" @@ -200,6 +259,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== +"@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.3.tgz#aac45cccf8bc1873b99a85f34bceef3beb5d3244" + integrity sha512-j/+j8NAWUTxOtx4LKHybpSClxHoq6I91DQ/mKgAXn5oNUPIUiGppjPIX3TDtJWPrdfP9Kfl7e4fgVMiQR9VE/g== + "@babel/helper-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" @@ -218,6 +282,16 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-replace-supers@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz#ec6859d20c5d8087f6a2dc4e014db7228975f13d" + integrity sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.10.1" + "@babel/helper-optimise-call-expression" "^7.10.1" + "@babel/traverse" "^7.10.1" + "@babel/types" "^7.10.1" + "@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" @@ -236,6 +310,13 @@ "@babel/template" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-split-export-declaration@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" + integrity sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g== + dependencies: + "@babel/types" "^7.10.1" + "@babel/helper-split-export-declaration@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" @@ -243,6 +324,11 @@ dependencies: "@babel/types" "^7.8.3" +"@babel/helper-validator-identifier@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz#60d9847f98c4cea1b279e005fdb7c28be5412d15" + integrity sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw== + "@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" @@ -276,11 +362,25 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.3.tgz#c633bb34adf07c5c13156692f5922c81ec53f28d" + integrity sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw== + dependencies: + "@babel/helper-validator-identifier" "^7.10.3" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": version "7.9.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== +"@babel/parser@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.3.tgz#7e71d892b0d6e7d04a1af4c3c79d72c1f10f5315" + integrity sha512-oJtNJCMFdIMwXGmx+KxuaD7i3b8uS7TTFYW/FNG2BT8m+fmGHoiPYoH0Pe3gya07WuFmM5FCDIr1x0irkD/hyA== + "@babel/plugin-external-helpers@^7.0.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.8.3.tgz#5a94164d9af393b2820a3cdc407e28ebf237de4b" @@ -305,6 +405,15 @@ "@babel/helper-create-class-features-plugin" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-proposal-decorators@^7.0.0": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.3.tgz#2fc6b5696028adccfcd14bc826c184c578b857f8" + integrity sha512-Rzwn5tcYFTdWWK3IrhMZkMDjzFQLIGYqHvv9XuzNnEB91Y6gHr/JjazYV1Yec9g0yMLhy1p/21eiW1P7f5UN4A== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.3" + "@babel/helper-plugin-utils" "^7.10.3" + "@babel/plugin-syntax-decorators" "^7.10.1" + "@babel/plugin-proposal-decorators@^7.6.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz#2156860ab65c5abf068c3f67042184041066543e" @@ -401,6 +510,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-syntax-decorators@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.1.tgz#16b869c4beafc9a442565147bda7ce0967bd4f13" + integrity sha512-a9OAbQhKOwSle1Vr0NJu/ISg1sPfdEkfRKWpgPuzhnWWzForou2gIeUIIwjAMHRekhhpJ7eulZlYs0H14Cbi+g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.1" + "@babel/plugin-syntax-decorators@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.8.3.tgz#8d2c15a9f1af624b0025f961682a9d53d3001bda" @@ -922,6 +1038,15 @@ "@babel/parser" "^7.8.6" "@babel/types" "^7.8.6" +"@babel/template@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.3.tgz#4d13bc8e30bf95b0ce9d175d30306f42a2c9a7b8" + integrity sha512-5BjI4gdtD+9fHZUsaxPHPNpwa+xRkDO7c7JbhYn2afvrkDu5SfAAbi9AIMXw2xEhO/BR35TqiW97IqNvCo/GqA== + dependencies: + "@babel/code-frame" "^7.10.3" + "@babel/parser" "^7.10.3" + "@babel/types" "^7.10.3" + "@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2" @@ -937,6 +1062,21 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.10.1": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.3.tgz#0b01731794aa7b77b214bcd96661f18281155d7e" + integrity sha512-qO6623eBFhuPm0TmmrUFMT1FulCmsSeJuVGhiLodk2raUDFhhTECLd9E9jC4LBIWziqt4wgF6KuXE4d+Jz9yug== + dependencies: + "@babel/code-frame" "^7.10.3" + "@babel/generator" "^7.10.3" + "@babel/helper-function-name" "^7.10.3" + "@babel/helper-split-export-declaration" "^7.10.1" + "@babel/parser" "^7.10.3" + "@babel/types" "^7.10.3" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" @@ -946,6 +1086,15 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.10.1", "@babel/types@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.3.tgz#6535e3b79fea86a6b09e012ea8528f935099de8e" + integrity sha512-nZxaJhBXBQ8HVoIcGsf9qWep3Oh3jCENK54V4mRF7qaJabVsAYdbTtmSD8WmAp1R6ytPiu5apMwSXyxB1WlaBA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.3" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -3347,6 +3496,16 @@ babel-preset-jest@^24.9.0: "@babel/plugin-syntax-object-rest-spread" "^7.0.0" babel-plugin-jest-hoist "^24.9.0" +babel-preset-mobx@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/babel-preset-mobx/-/babel-preset-mobx-2.0.0.tgz#968ce0000880afcc5cbb78ecbaac37984b193df2" + integrity sha512-hde0Tcc8P4iij+jlc2ieO3B0RYgWczMhVMEF2i46TkqUBHw9oKOcF0PQ3TA62FRqhs8Td5cISGKoq7ziSXEYgA== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-decorators" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-regenerator" "^7.0.0" + babel-runtime@6.26.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" @@ -9602,6 +9761,30 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mobx-persist@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mobx-persist/-/mobx-persist-0.4.1.tgz#fe5790eda04e0ee0b91c512d1347104e09363f9a" + integrity sha512-cPxVuZTY5neesxOV/Z25SF4+/NbC6wfHOe9HT5XoSEkAALNxNE41yDK48peJQ3iK14m0G2ywQRklCXeV3wftnQ== + dependencies: + serializr "^1.1.11" + +mobx-react-lite@2: + version "2.0.7" + resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-2.0.7.tgz#1bfb3b4272668e288047cf0c7940b14e91cba284" + integrity sha512-YKAh2gThC6WooPnVZCoC+rV1bODAKFwkhxikzgH18wpBjkgTkkR9Sb0IesQAH5QrAEH/JQVmy47jcpQkf2Au3Q== + +mobx-react@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.2.2.tgz#45e8e7c4894cac8399bba0a91060d7cfb8ea084b" + integrity sha512-Us6V4ng/iKIRJ8pWxdbdysC6bnS53ZKLKlVGBqzHx6J+gYPYbOotWvhHZnzh/W5mhpYXxlXif4kL2cxoWJOplQ== + dependencies: + mobx-react-lite "2" + +mobx@^5.15.4: + version "5.15.4" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.15.4.tgz#9da1a84e97ba624622f4e55a0bf3300fb931c2ab" + integrity sha512-xRFJxSU2Im3nrGCdjSuOTFmxVDGeqOHL+TyADCGbT0k4HHqGmx5u2yaHNryvoORpI4DfbzjJ5jPmuv+d7sioFw== + moment@^2.10.6: version "2.24.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" @@ -12310,6 +12493,11 @@ serialize-javascript@^2.1.2: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== +serializr@^1.1.11: + version "1.5.4" + resolved "https://registry.yarnpkg.com/serializr/-/serializr-1.5.4.tgz#3ddf1cb7b4465c9c3f72bab0cbc41e09dbe50c33" + integrity sha512-ImLlkNfNSSv9d7Ah1j/yrPk1FHbRC1zkD7URcgx/8M1eYHGUxGf/Ig/d8ML04ifqN7QesyYKsfLYA4xjAVAR/g== + serve-index@^1.7.2: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" From bfc99c628e8eccaf49805f9c8263587ea7e81475 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 24 Jun 2020 18:03:21 -0400 Subject: [PATCH 2/3] Remove unused import --- screens/SettingsScreen.js | 1 - 1 file changed, 1 deletion(-) diff --git a/screens/SettingsScreen.js b/screens/SettingsScreen.js index 8f34e7c8..a4311a26 100644 --- a/screens/SettingsScreen.js +++ b/screens/SettingsScreen.js @@ -7,7 +7,6 @@ import React from 'react'; import { ActivityIndicator, Alert, - AsyncStorage, FlatList, Platform, ScrollView, From f11774d7f70b9fa5e4bfe606de154cb647e52537 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 30 Jun 2020 11:27:02 -0400 Subject: [PATCH 3/3] Replace mobx-persist with mobx-sync --- App.js | 35 +++++++++++++++++++++++------------ components/ServerInput.js | 9 ++++----- hooks/useStores.js | 6 ++---- navigation/AppNavigator.js | 4 ++-- package.json | 2 +- screens/HomeScreen.js | 10 ++++------ screens/SettingsScreen.js | 21 ++++++++++----------- stores/RootStore.js | 16 ++++++++++++++++ stores/ServerStore.js | 2 -- stores/SettingStore.js | 2 -- yarn.lock | 24 ++++++++++++------------ 11 files changed, 74 insertions(+), 57 deletions(-) create mode 100644 stores/RootStore.js diff --git a/App.js b/App.js index d5223348..de20af4f 100644 --- a/App.js +++ b/App.js @@ -10,7 +10,7 @@ import { AsyncStorage, Platform, StatusBar } from 'react-native'; import { ThemeProvider } from 'react-native-elements'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { observer } from 'mobx-react'; -import { create } from 'mobx-persist'; +import { AsyncTrunk } from 'mobx-sync'; import { AppLoading } from 'expo'; import { Asset } from 'expo-asset'; import * as Font from 'expo-font'; @@ -24,24 +24,35 @@ import AppNavigator from './navigation/AppNavigator'; import CachingStorage from './utils/CachingStorage'; import Theme from './utils/Theme'; -const hydrate = create({ - storage: AsyncStorage -}); - const App = observer(({ skipLoadingScreen }) => { const [isSplashReady, setIsSplashReady] = useState(false); - const { serverStore, settingStore } = useStores(); + const { rootStore } = useStores(); + + const trunk = new AsyncTrunk(rootStore, { + storage: AsyncStorage + }); const hydrateStores = async () => { - // Use data from old location as the initial values + // Migrate servers and settings // TODO: Remove this for next release const servers = await CachingStorage.getInstance().getItem(StorageKeys.Servers); - const activeServer = await CachingStorage.getInstance().getItem(StorageKeys.ActiveServer); - hydrate('servers', serverStore, servers || []); - hydrate('settings', settingStore, { activeServer: activeServer || 0 }); + if (servers) { + const activeServer = await CachingStorage.getInstance().getItem(StorageKeys.ActiveServer) || 0; + + // Initialize the store with the existing servers and settings + await trunk.init({ + serverStore: { servers }, + settingStore: { activeServer } + }); + + // Remove old data values + AsyncStorage.multiRemove(Object.values(StorageKeys)); + } else { + // No servers saved in the old method, initialize normally + await trunk.init(); + } - // Remove old data values - await AsyncStorage.multiRemove(Object.values(StorageKeys)); + rootStore.storeLoaded = true; }; useEffect(() => { diff --git a/components/ServerInput.js b/components/ServerInput.js index ca7d0aa6..0ee3df7b 100644 --- a/components/ServerInput.js +++ b/components/ServerInput.js @@ -20,8 +20,7 @@ const sanitizeHost = (url = '') => url.trim(); class ServerInput extends React.Component { static propTypes = { navigation: PropTypes.object.isRequired, - serverStore: PropTypes.object.isRequired, - settingStore: PropTypes.object.isRequired, + rootStore: PropTypes.object.isRequired, onSuccess: PropTypes.func, successScreen: PropTypes.string } @@ -71,8 +70,8 @@ class ServerInput extends React.Component { } // Save the server details - this.props.serverStore.addServer({ url }); - this.props.settingStore.activeServer = this.props.serverStore.servers.length - 1; + this.props.rootStore.serverStore.addServer({ url }); + this.props.rootStore.settingStore.activeServer = this.props.rootStore.serverStore.servers.length - 1; // Call the success callback if present if (this.props.onSuccess) { this.props.onSuccess(); @@ -82,7 +81,7 @@ class ServerInput extends React.Component { index: 0, routes: [{ name: this.props.successScreen || 'Main', - props: { activeServer: this.props.settingStore.activeServer } + props: { activeServer: this.props.rootStore.settingStore.activeServer } }] }); } else { diff --git a/hooks/useStores.js b/hooks/useStores.js index 19f557ed..c9b17afb 100644 --- a/hooks/useStores.js +++ b/hooks/useStores.js @@ -5,12 +5,10 @@ */ import { createContext, useContext } from 'react'; -import ServerStore from '../stores/ServerStore'; -import SettingStore from '../stores/SettingStore'; +import RootStore from '../stores/RootStore'; export const storesContext = createContext({ - serverStore: new ServerStore(), - settingStore: new SettingStore() + rootStore: new RootStore() }); export const useStores = () => useContext(storesContext); diff --git a/navigation/AppNavigator.js b/navigation/AppNavigator.js index 877f2588..3ad1b1d4 100644 --- a/navigation/AppNavigator.js +++ b/navigation/AppNavigator.js @@ -63,7 +63,7 @@ function Main() { } const AppNavigator = observer(() => { - const { serverStore } = useStores(); + const { rootStore } = useStores(); // Ensure the splash screen is hidden when loading is finished SplashScreen.hide(); @@ -71,7 +71,7 @@ const AppNavigator = observer(() => { return ( 0) ? 'Main' : 'AddServer'} + initialRouteName={(rootStore.serverStore.servers.length > 0) ? 'Main' : 'AddServer'} headerMode='screen' screenOptions={{ headerShown: false }} > diff --git a/package.json b/package.json index d6d16017..a4ac88ee 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "expo-screen-orientation": "~1.0.0", "expo-web-browser": "~8.1.0", "mobx": "^5.15.4", - "mobx-persist": "^0.4.1", "mobx-react": "^6.2.2", + "mobx-sync": "^3.0.0", "prop-types": "^15.7.2", "react": "16.9.0", "react-lifecycles-compat": "^3.0.4", diff --git a/screens/HomeScreen.js b/screens/HomeScreen.js index 9ec6f2f3..9c3401c1 100644 --- a/screens/HomeScreen.js +++ b/screens/HomeScreen.js @@ -49,18 +49,16 @@ class HomeScreen extends React.Component { static propTypes = { navigation: PropTypes.object.isRequired, route: PropTypes.object.isRequired, - serverStore: PropTypes.object.isRequired, - settingStore: PropTypes.object.isRequired + rootStore: PropTypes.object.isRequired } async bootstrapAsync() { - const servers = this.props.serverStore.servers; - let activeServer = this.props.settingStore.activeServer; + const servers = this.props.rootStore.serverStore.servers; + let activeServer = this.props.rootStore.settingStore.activeServer; // If the activeServer is greater than the length of the server array, reset it to 0 if (activeServer && servers.length && activeServer > servers.length - 1) { - // TODO: Verify this updates the store - this.props.settingStore.activeServer = 0; + this.props.rootStore.settingStore.activeServer = 0; activeServer = 0; } diff --git a/screens/SettingsScreen.js b/screens/SettingsScreen.js index a4311a26..9aa45387 100644 --- a/screens/SettingsScreen.js +++ b/screens/SettingsScreen.js @@ -34,8 +34,7 @@ import { openBrowser } from '../utils/WebBrowser'; class SettingsScreen extends React.Component { static propTypes = { navigation: PropTypes.object.isRequired, - serverStore: PropTypes.object.isRequired, - settingStore: PropTypes.object.isRequired + rootStore: PropTypes.object.isRequired } state = { @@ -82,7 +81,7 @@ class SettingsScreen extends React.Component { }} subtitle={subtitle} leftElement={( - index === this.props.settingStore.activeServer ? ( + index === this.props.rootStore.settingStore.activeServer ? ( { - this.props.settingStore.activeServer = index; + this.props.rootStore.settingStore.activeServer = index; this.props.navigation.navigate('Home', { activeServer: index }); }} />); }; async bootstrapAsync() { - let { servers } = this.props.serverStore; + let { servers } = this.props.rootStore.serverStore; servers = servers.map(async (server) => { let serverUrl; @@ -160,10 +159,10 @@ class SettingsScreen extends React.Component { async deleteServer(index) { // Remove server and update active server - this.props.serverStore.removeServer(index); - this.props.settingStore.activeServer = 0; + this.props.rootStore.serverStore.removeServer(index); + this.props.rootStore.settingStore.activeServer = 0; - if (this.props.serverStore.servers.length > 0) { + if (this.props.rootStore.serverStore.servers.length > 0) { // More servers exist, update state and navigate home this.bootstrapAsync(); this.props.navigation.navigate('Home', { activeServer: 0 }); @@ -175,8 +174,8 @@ class SettingsScreen extends React.Component { async resetApplication() { // Reset data in stores - this.props.serverStore.servers = []; - this.props.settingStore.activeServer = 0; + this.props.rootStore.serverStore.servers = []; + this.props.rootStore.settingStore.activeServer = 0; // Navigate to the loading screen this.props.navigation.navigate('AddServer'); } @@ -222,7 +221,7 @@ class SettingsScreen extends React.Component { data={this.state.servers} renderItem={this._renderServer} scrollEnabled={false} - extraData={this.props.settingStore.activeServer} + extraData={this.props.rootStore.settingStore.activeServer} /> ) : ( diff --git a/stores/RootStore.js b/stores/RootStore.js new file mode 100644 index 00000000..3fa361fd --- /dev/null +++ b/stores/RootStore.js @@ -0,0 +1,16 @@ +/** + * 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 { ignore } from 'mobx-sync'; + +import ServerStore from "./ServerStore"; +import SettingStore from "./SettingStore"; + +export default class RootStore { + @ignore + storeLoaded = false + serverStore = new ServerStore() + settingStore = new SettingStore() +} diff --git a/stores/ServerStore.js b/stores/ServerStore.js index 67f75d02..3dbfdf42 100644 --- a/stores/ServerStore.js +++ b/stores/ServerStore.js @@ -4,10 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { action, observable } from 'mobx'; -import { persist } from 'mobx-persist'; export default class ServerStore { - @persist('list') @observable servers = [] diff --git a/stores/SettingStore.js b/stores/SettingStore.js index b633d13e..96a5f313 100644 --- a/stores/SettingStore.js +++ b/stores/SettingStore.js @@ -4,13 +4,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { observable } from 'mobx'; -import { persist } from 'mobx-persist'; /** * Data store for application settings */ export default class SettingStore { - @persist @observable activeServer = 0 } diff --git a/yarn.lock b/yarn.lock index b3d1e534..e842763c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9761,13 +9761,6 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mobx-persist@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/mobx-persist/-/mobx-persist-0.4.1.tgz#fe5790eda04e0ee0b91c512d1347104e09363f9a" - integrity sha512-cPxVuZTY5neesxOV/Z25SF4+/NbC6wfHOe9HT5XoSEkAALNxNE41yDK48peJQ3iK14m0G2ywQRklCXeV3wftnQ== - dependencies: - serializr "^1.1.11" - mobx-react-lite@2: version "2.0.7" resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-2.0.7.tgz#1bfb3b4272668e288047cf0c7940b14e91cba284" @@ -9780,6 +9773,13 @@ mobx-react@^6.2.2: dependencies: mobx-react-lite "2" +mobx-sync@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mobx-sync/-/mobx-sync-3.0.0.tgz#fbbd267442757cf264ee2124730cf57a0f6bd479" + integrity sha512-j8DbDB58VfaNH8n+cIIj8yPZjPWOdPz1cUtpaI2NHKzArtZ3S7GZD9MbQJyU7rBIq5+ajfLzuEKF0ruynYPj4A== + dependencies: + tslib "^2.0.0" + mobx@^5.15.4: version "5.15.4" resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.15.4.tgz#9da1a84e97ba624622f4e55a0bf3300fb931c2ab" @@ -12493,11 +12493,6 @@ serialize-javascript@^2.1.2: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== -serializr@^1.1.11: - version "1.5.4" - resolved "https://registry.yarnpkg.com/serializr/-/serializr-1.5.4.tgz#3ddf1cb7b4465c9c3f72bab0cbc41e09dbe50c33" - integrity sha512-ImLlkNfNSSv9d7Ah1j/yrPk1FHbRC1zkD7URcgx/8M1eYHGUxGf/Ig/d8ML04ifqN7QesyYKsfLYA4xjAVAR/g== - serve-index@^1.7.2: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" @@ -13652,6 +13647,11 @@ tslib@^1.10.0, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== +tslib@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3" + integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g== + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"