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"