diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 42b33f9e3..deae18d85 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -661,4 +661,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 84e32ce5543427579b8c72d77fd175fe29268d92 -COCOAPODS: 1.9.3 +COCOAPODS: 1.8.4 diff --git a/package.json b/package.json index c448cee57..095940117 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "react-native-image-zoom-viewer": "^2.2.27", "react-native-keyboard-aware-scroll-view": "^0.9.1", "react-native-linear-gradient": "^2.4.2", + "react-native-modal": "^11.5.6", "react-native-modal-dropdown": "esteemapp/react-native-modal-dropdown", "react-native-modal-translucent": "^5.0.0", "react-native-navigation-bar-color": "^1.0.0", diff --git a/src/realm/realm.js b/src/realm/realm.js index 246e07a4c..8945403a5 100644 --- a/src/realm/realm.js +++ b/src/realm/realm.js @@ -107,6 +107,15 @@ export const removeAllUserData = async () => { } }; +export const removeAllSCAccounts = async () => { + try { + await setItemToStorage(SC_ACCOUNTS, []); + return true; + } catch (error) { + return error; + } +}; + export const setDraftPost = async (fields, username) => { try { let draft = await getItemFromStorage(DRAFT_SCHEMA); @@ -593,6 +602,18 @@ export const getSCAccount = async (username) => { } }; +export const getAllSCAccounts = async () => { + try { + const scAccountStr = await getItemFromStorage(SC_ACCOUNTS); + if (scAccountStr && scAccountStr.length > 0) { + return scAccountStr; + } + return []; + } catch (error) { + return error; + } +}; + export const removeSCAccount = async (username) => { try { let scAccount = await getItemFromStorage(SC_ACCOUNTS); @@ -621,3 +642,33 @@ export const getStorageType = async () => { return error; } }; + +export const getVersionForWelcomeModal = async () => { + try { + const application = await getItemFromStorage(APPLICATION_SCHEMA); + if (application.versionForWelcomeModal) { + return application.versionForWelcomeModal; + } + return 0; + } catch (error) { + return error; + } +}; + +export const setVersionForWelcomeModal = async (version) => { + try { + const application = await getItemFromStorage(APPLICATION_SCHEMA); + if (application) { + application.versionForWelcomeModal = version; + await setItemToStorage(APPLICATION_SCHEMA, application); + return application; + } + const applicationData = { + versionForWelcomeModal: version, + }; + await setItemToStorage(APPLICATION_SCHEMA, { ...applicationData }); + return applicationData; + } catch (error) { + return error; + } +}; diff --git a/src/redux/actions/accountAction.js b/src/redux/actions/accountAction.js index aec0c41a5..992104357 100644 --- a/src/redux/actions/accountAction.js +++ b/src/redux/actions/accountAction.js @@ -3,6 +3,7 @@ import { ADD_OTHER_ACCOUNT, FETCH_ACCOUNT_FAIL, REMOVE_OTHER_ACCOUNT, + REMOVE_ALL_OTHER_ACCOUNT, SET_GLOBAL_PROPS, UPDATE_CURRENT_ACCOUNT, UPDATE_UNREAD_ACTIVITY_COUNT, @@ -41,6 +42,10 @@ export const removeOtherAccount = (data) => ({ payload: data, }); +export const removeAllOtherAccount = () => ({ + type: REMOVE_ALL_OTHER_ACCOUNT, +}); + export const setGlobalProps = (data) => ({ type: SET_GLOBAL_PROPS, payload: data, diff --git a/src/redux/constants/constants.js b/src/redux/constants/constants.js index bf034816e..42f335932 100644 --- a/src/redux/constants/constants.js +++ b/src/redux/constants/constants.js @@ -38,6 +38,7 @@ export const ADD_OTHER_ACCOUNT = 'ADD_OTHER_ACCOUNT'; export const FETCH_ACCOUNT_FAIL = 'FETCH_ACCOUNT_FAIL'; export const FETCHING_ACCOUNT = 'FETCHING_ACCOUNT'; export const REMOVE_OTHER_ACCOUNT = 'REMOVE_OTHER_ACCOUNT'; +export const REMOVE_ALL_OTHER_ACCOUNT = 'REMOVE_ALL_OTHER_ACCOUNT'; export const UPDATE_CURRENT_ACCOUNT = 'UPDATE_CURRENT_ACCOUNT'; export const UPDATE_UNREAD_ACTIVITY_COUNT = 'UPDATE_UNREAD_ACTIVITY_COUNT'; export const SET_PIN_CODE = 'SET_PIN_CODE'; diff --git a/src/redux/reducers/accountReducer.js b/src/redux/reducers/accountReducer.js index fab593b43..ee863a8ad 100644 --- a/src/redux/reducers/accountReducer.js +++ b/src/redux/reducers/accountReducer.js @@ -7,6 +7,7 @@ import { UPDATE_CURRENT_ACCOUNT, UPDATE_UNREAD_ACTIVITY_COUNT, REMOVE_OTHER_ACCOUNT, + REMOVE_ALL_OTHER_ACCOUNT, LOGOUT_FAIL, SET_GLOBAL_PROPS, } from '../constants/constants'; @@ -63,6 +64,12 @@ export default function (state = initialState, action) { otherAccounts: state.otherAccounts.filter((item) => item.username !== action.payload), }; + case REMOVE_ALL_OTHER_ACCOUNT: + return { + ...state, + otherAccounts: [], + }; + case UPDATE_CURRENT_ACCOUNT: return { ...state, diff --git a/src/screens/application/container/applicationContainer.js b/src/screens/application/container/applicationContainer.js index b36acbede..2ffeddccb 100644 --- a/src/screens/application/container/applicationContainer.js +++ b/src/screens/application/container/applicationContainer.js @@ -16,6 +16,7 @@ import { } from 'react-native-dark-mode'; import messaging from '@react-native-firebase/messaging'; import PushNotification from 'react-native-push-notification'; +import VersionNumber from 'react-native-version-number'; // Constants import AUTH_TYPE from '../../../constants/authType'; @@ -34,6 +35,10 @@ import { setAuthStatus, removeSCAccount, setExistUser, + getVersionForWelcomeModal, + setVersionForWelcomeModal, + getAllSCAccounts, + removeAllSCAccounts, } from '../../../realm/realm'; import { getUser, getPost } from '../../../providers/steem/dsteem'; import { switchAccount } from '../../../providers/steem/auth'; @@ -47,6 +52,7 @@ import { updateUnreadActivityCount, removeOtherAccount, fetchGlobalProperties, + removeAllOtherAccount, } from '../../../redux/actions/accountAction'; import { activeApplication, @@ -87,6 +93,7 @@ export const setPreviousAppState = () => { let firebaseOnNotificationOpenedAppListener = null; let firebaseOnMessageListener = null; +let scAccounts = []; class ApplicationContainer extends Component { constructor(props) { @@ -97,11 +104,14 @@ class ApplicationContainer extends Component { isIos: Platform.OS !== 'android', isThemeReady: false, appState: AppState.currentState, + showWelcomeModal: false, }; } componentDidMount = () => { const { isIos } = this.state; + const { appVersion } = VersionNumber; + this._setNetworkListener(); Linking.addEventListener('url', this._handleOpenURL); @@ -123,6 +133,15 @@ class ApplicationContainer extends Component { this._createPushListener(); if (!isIos) BackHandler.addEventListener('hardwareBackPress', this._onBackPress); + + getVersionForWelcomeModal().then((version) => { + if (version < parseFloat(appVersion)) { + this.setState({ showWelcomeModal: true }); + getAllSCAccounts().then((accounts) => { + scAccounts = accounts; + }); + } + }); }; componentDidUpdate(prevProps, prevState) { @@ -644,6 +663,41 @@ class ApplicationContainer extends Component { dispatch(updateCurrentAccount(_currentAccount)); }; + _handleWelcomeModalButtonPress = () => { + const { dispatch, otherAccounts } = this.props; + const { appVersion } = VersionNumber; + + const accountsWithoutSC = otherAccounts.filter( + (account) => !scAccounts.includes(account.username), + ); + + // setVersionForWelcomeModal(appVersion); + + if (scAccounts.length > 0) { + scAccounts.forEach((el) => { + dispatch(removeOtherAccount(el.username)); + }); + removeAllSCAccounts().then(() => { + if (accountsWithoutSC.length > 0) { + this._switchAccount(accountsWithoutSC(0)); + } else { + dispatch(updateCurrentAccount({})); + dispatch(login(false)); + removePinCode(); + setAuthStatus({ isLoggedIn: false }); + setExistUser(false); + dispatch(removeAllOtherAccount()); + dispatch(logoutDone()); + } + + navigate({ routeName: ROUTES.SCREENS.LOGIN }); + this.setState({ showWelcomeModal: false }); + }); + } else { + this.setState({ showWelcomeModal: false }); + } + }; + UNSAFE_componentWillReceiveProps(nextProps) { const { isDarkTheme: _isDarkTheme, @@ -698,7 +752,7 @@ class ApplicationContainer extends Component { isPinCodeRequire, rcOffer, } = this.props; - const { isRenderRequire, isReady, isThemeReady } = this.state; + const { isRenderRequire, isReady, isThemeReady, showWelcomeModal } = this.state; return ( children && @@ -712,6 +766,8 @@ class ApplicationContainer extends Component { locale: selectedLanguage, rcOffer, toastNotification, + showWelcomeModal, + handleWelcomeModalButtonPress: this._handleWelcomeModalButtonPress, }) ); } diff --git a/src/screens/application/index.js b/src/screens/application/index.js index 7f6b7e457..e547aa7d6 100644 --- a/src/screens/application/index.js +++ b/src/screens/application/index.js @@ -1,9 +1,11 @@ import React, { Fragment, useEffect, useState } from 'react'; +import { Text } from 'react-native'; import SplashScreen from 'react-native-splash-screen'; -import ApplicationScreen from './screen/applicationScreen'; -import ApplicationContainer from './container/applicationContainer'; -import Launch from '../launch'; +import ApplicationContainer from './container/applicationContainer'; +import WelcomeScreen from './screen/welcomeScreen'; +import ApplicationScreen from './screen/applicationScreen'; +import LaunchScreen from '../launch'; import { Modal } from '../../components'; import { PinCode } from '../pinCode'; @@ -31,7 +33,11 @@ const Application = () => { locale, rcOffer, toastNotification, + showWelcomeModal, + handleWelcomeModalButtonPress, }) => { + const _isAppReady = !showAnimation && isReady && isRenderRequire && isThemeReady; + console.log('_isAppReady :>> ', _isAppReady); return ( { > + console.log('handleOnModalClose :>> ')} + onDismiss={() => console.log('onDismiss :>> ')} + onRequestClose={() => { + console.log('onRequestClose :>> '); + }} + > + + {isThemeReady && isRenderRequire && ( { rcOffer={rcOffer} /> )} - {(showAnimation || !isReady || !isRenderRequire || !isThemeReady) && } + {!_isAppReady && } ); }} diff --git a/src/screens/application/screen/applicationScreen.js b/src/screens/application/screen/applicationScreen.js index e8f7e85ef..494924e01 100644 --- a/src/screens/application/screen/applicationScreen.js +++ b/src/screens/application/screen/applicationScreen.js @@ -1,9 +1,10 @@ import React, { Component, Fragment } from 'react'; -import { StatusBar, Platform, View, Alert } from 'react-native'; +import { StatusBar, Platform, View, Alert, Text, Modal, TouchableHighlight } from 'react-native'; import EStyleSheet from 'react-native-extended-stylesheet'; import { connect } from 'react-redux'; import { createAppContainer } from 'react-navigation'; import { injectIntl } from 'react-intl'; +import VersionNumber from 'react-native-version-number'; import AppNavitation from '../../../navigation/routes'; import { setTopLevelNavigator, navigate } from '../../../navigation/service'; @@ -13,6 +14,7 @@ import { toastNotification as toastNotificationAction, setRcOffer, } from '../../../redux/actions/uiAction'; +import { getVersionForWelcomeModal } from '../../../realm/realm'; import ROUTES from '../../../constants/routeNames'; @@ -30,9 +32,20 @@ class ApplicationScreen extends Component { super(props); this.state = { isShowToastNotification: false, + showWelcomeModal: false, }; } + componentDidMount() { + const { appVersion } = VersionNumber; + + getVersionForWelcomeModal().then((version) => { + if (version < parseFloat(appVersion)) { + this.setState({ showWelcomeModal: true }); + } + }); + } + componentDidUpdate(prevProps) { const { rcOffer, dispatch, intl } = this.props; const { rcOffer: rcOfferPrev } = prevProps; @@ -88,7 +101,7 @@ class ApplicationScreen extends Component { render() { const { isConnected, isDarkTheme, toastNotification, isReady } = this.props; - const { isShowToastNotification } = this.state; + const { isShowToastNotification, showWelcomeModal } = this.state; const barStyle = isDarkTheme ? 'light-content' : 'dark-content'; const barColor = isDarkTheme ? '#1e2835' : '#fff'; @@ -106,6 +119,32 @@ class ApplicationScreen extends Component { setTopLevelNavigator(navigatorRef); }} /> + { + Alert.alert('Modal has been closed.'); + }} + > + + Hello World! + { + this.setState({ showWelcomeModal: !showWelcomeModal }); + }} + > + Hide Modal + + + {isShowToastNotification && ( diff --git a/src/screens/application/screen/welcomeScreen.js b/src/screens/application/screen/welcomeScreen.js new file mode 100644 index 000000000..0c4a11679 --- /dev/null +++ b/src/screens/application/screen/welcomeScreen.js @@ -0,0 +1,71 @@ +import React from 'react'; +import { Text, Image, View } from 'react-native'; +import EStyleSheet from 'react-native-extended-stylesheet'; + +import { Icon, MainButton } from '../../../components'; + +import styles from './welcomeStyles'; + +const WelcomeScreen = ({ handleButtonPress }) => { + return ( + + + + Welcome to + Ecency + + + + + Lorem ipsum dolor + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer a tellus eget arcu + + + + + + + Lorem ipsum dolor + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer a tellus eget arcu + + + + + + + Lorem ipsum dolor + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer a tellus eget arcu + + + + + + ); +}; + +export default WelcomeScreen; diff --git a/src/screens/application/screen/welcomeStyles.js b/src/screens/application/screen/welcomeStyles.js new file mode 100644 index 000000000..6fa3b009f --- /dev/null +++ b/src/screens/application/screen/welcomeStyles.js @@ -0,0 +1,33 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + container: { + flex: 1, + justifyContent: 'space-between', + paddingVertical: '5%', + paddingHorizontal: 40, + }, + welcomeText: { + fontSize: 34, + }, + ecencyText: { + fontSize: 34, + color: '$primaryBlue', + }, + sectionRow: { + flexDirection: 'row', + }, + sectionTitle: { + fontSize: 17, + fontWeight: '600', + marginLeft: 10, + }, + sectionText: { + fontSize: 15, + marginLeft: 10, + marginRight: 45, + }, + flex1: { + flex: 1, + }, +}); diff --git a/yarn.lock b/yarn.lock index a8aed7ec8..462914933 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7427,6 +7427,13 @@ react-native-actionsheet@esteemapp/react-native-actionsheet: version "2.4.2" resolved "https://codeload.github.com/esteemapp/react-native-actionsheet/tar.gz/c74540db08a4c2049ee9c8a8077b5c476b536e2c" +react-native-animatable@1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/react-native-animatable/-/react-native-animatable-1.3.3.tgz#a13a4af8258e3bb14d0a9d839917e9bb9274ec8a" + integrity sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w== + dependencies: + prop-types "^15.7.2" + react-native-autoheight-webview@^1.3.4, react-native-autoheight-webview@^1.4.1: version "1.5.1" resolved "https://registry.yarnpkg.com/react-native-autoheight-webview/-/react-native-autoheight-webview-1.5.1.tgz#67cbfb672212d93dedecf723d1914cbc40287545" @@ -7540,6 +7547,14 @@ react-native-modal-translucent@^5.0.0: resolved "https://registry.yarnpkg.com/react-native-modal-translucent/-/react-native-modal-translucent-5.0.0.tgz#8b35cfa4189dce776c77a925b00ad19d965bd0a2" integrity sha512-xhJAlq4uCE7jPEIPxGS1WNiRIm5DCrZEO3SF88moTOm6b4/wfFEANf+lMsVkQf9b9dsQ6Em4nq4uAoejtbHb2A== +react-native-modal@^11.5.6: + version "11.5.6" + resolved "https://registry.yarnpkg.com/react-native-modal/-/react-native-modal-11.5.6.tgz#bb25a78c35a5e24f45de060e5f64284397d38a87" + integrity sha512-APGNfbvgC4hXbJqcSADu79GLoMKIHUmgR3fDQ7rCGZNBypkStSP8imZ4PKK/OzIZZfjGU9aP49jhMgGbhY9KHA== + dependencies: + prop-types "^15.6.2" + react-native-animatable "1.3.3" + react-native-navigation-bar-color@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/react-native-navigation-bar-color/-/react-native-navigation-bar-color-1.0.0.tgz#04ff752a58049af93ceea9ccf266b8d3fbc6514a"