Merge pull request #2353 from ecency/nt/app-startup

Nt/app startup - Part 1
This commit is contained in:
Feruz M 2022-07-06 19:37:00 +03:00 committed by GitHub
commit af35a3aedd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 653 additions and 446 deletions

View File

@ -1,5 +1,6 @@
#import "RNSplashScreen.h"
#import "AppDelegate.h"
#import "RNSplashScreen.h"
#import <AppCenterReactNativeShared/AppCenterReactNativeShared.h>
#import <AppCenterReactNative.h>
#import <AppCenterReactNativeAnalytics.h>

View File

@ -361,8 +361,8 @@ PODS:
- React-Core
- react-native-safe-area-context (3.1.9):
- React-Core
- react-native-splash-screen (3.2.0):
- React
- react-native-splash-screen (3.3.0):
- React-Core
- react-native-udp (2.7.0):
- React
- react-native-version-number (0.3.6):
@ -791,7 +791,7 @@ SPEC CHECKSUMS:
react-native-receive-sharing-intent: feba0a332a07977549a85aa58b496eb44368366a
react-native-restart: aaad36f3ed7031daac3565f4a79d67e4f3884a50
react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-udp: ff9d13e523f2b58e6bc5d4d32321ac60671b5dc9
react-native-version-number: b415bbec6a13f2df62bf978e85bc0d699462f37f
react-native-video: a4c2635d0802f983594b7057e1bce8f442f0ad28
@ -833,4 +833,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 0282022703ad578ab2d9afbf3147ba3b373b4311
COCOAPODS: 1.11.2
COCOAPODS: 1.11.3

View File

@ -128,7 +128,7 @@
"react-native-scrollable-tab-view": "ecency/react-native-scrollable-tab-view",
"react-native-slider": "^0.11.0",
"react-native-snap-carousel": "^3.8.0",
"react-native-splash-screen": "^3.2.0",
"react-native-splash-screen": "^3.3.0",
"react-native-svg": "^12.1.1",
"react-native-swiper": "^1.6.0-rc.3",
"react-native-tcp": "^4.0.0",

View File

@ -4,14 +4,14 @@ import { withNavigation } from 'react-navigation';
// Constants
import { default as ROUTES } from '../../../constants/routeNames';
import { useAppDispatch, useAppSelector } from '../../../hooks';
import { hidePostsThumbnails } from '../../../redux/actions/uiAction';
import { setHidePostsThumbnails } from '../../../redux/actions/applicationActions';
// Components
import BasicHeaderView from '../view/basicHeaderView';
const BasicHeaderContainer = (props) => {
const dispatch = useAppDispatch();
const isHideImages = useAppSelector((state) => state.ui.hidePostsThumbnails);
const isHideImages = useAppSelector((state) => state.application.hidePostsThumbnails);
const _handleOnPressBackButton = () => {
const { navigation, isNewPost, handleOnBackPress } = props;
@ -30,7 +30,7 @@ const BasicHeaderContainer = (props) => {
};
const _handleViewModeToggle = () => {
dispatch(hidePostsThumbnails(!isHideImages));
dispatch(setHidePostsThumbnails(!isHideImages));
};
return (

View File

@ -8,8 +8,8 @@ import { useDispatch, useSelector } from 'react-redux';
import HeaderView from '../view/headerView';
import { AccountContainer, ThemeContainer } from '../../../containers';
import { hidePostsThumbnails } from '../../../redux/actions/uiAction';
import { parseReputation } from '../../../utils/user';
import { setHidePostsThumbnails } from '../../../redux/actions/applicationActions';
const HeaderContainer = ({
selectedUser,
@ -22,7 +22,7 @@ const HeaderContainer = ({
const dispatch = useDispatch();
//redux properties
const isHideImages = useSelector((state) => state.ui.hidePostsThumbnails);
const isHideImages = useSelector((state) => state.application.hidePostsThumbnails);
const _handleOpenDrawer = () => {
if (has(navigation, 'openDrawer') && typeof get(navigation, 'openDrawer') === 'function') {
@ -39,7 +39,7 @@ const HeaderContainer = ({
};
const _handleViewModeTogglePress = () => {
dispatch(hidePostsThumbnails(!isHideImages));
dispatch(setHidePostsThumbnails(!isHideImages));
};
return (

View File

@ -25,7 +25,6 @@ import {
setOtherPosts,
setInitPosts,
} from '../../../redux/actions/postsAction';
import { hidePostsThumbnails } from '../../../redux/actions/uiAction';
import { fetchLeaderboard, followUser, unfollowUser } from '../../../redux/actions/userAction';
import {
subscribeCommunity,
@ -34,6 +33,7 @@ import {
} from '../../../redux/actions/communitiesAction';
import useIsMountedRef from '../../../customHooks/useIsMountedRef';
import { setHidePostsThumbnails } from '../../../redux/actions/applicationActions';
const PostsContainer = ({
changeForceLoadPostState,
@ -59,7 +59,7 @@ const PostsContainer = ({
const nsfw = useSelector((state) => state.application.nsfw);
const initPosts = useSelector((state) => state.posts.initPosts);
const isConnected = useSelector((state) => state.application.isConnected);
const isHideImages = useSelector((state) => state.ui.hidePostsThumbnails);
const isHideImages = useSelector((state) => state.application.hidePostsThumbnails);
const username = useSelector((state) => state.account.currentAccount.name);
const isLoggedIn = useSelector((state) => state.application.isLoggedIn);
const isAnalytics = useSelector((state) => state.application.isAnalytics);
@ -467,7 +467,7 @@ const PostsContainer = ({
};
const _handleImagesHide = () => {
dispatch(hidePostsThumbnails(!isHideImages));
dispatch(setHidePostsThumbnails(!isHideImages));
};
const _getPromotePosts = async () => {

View File

@ -37,7 +37,7 @@ const postsListContainer = ({
const [imageHeights, setImageHeights] = useState(new Map<string, number>());
const isHideImages = useSelector((state) => state.ui.hidePostsThumbnails);
const isHideImages = useSelector((state) => state.application.hidePostsThumbnails);
const posts = useSelector((state) => {
return isFeedScreen
? state.posts.feedPosts

View File

@ -20,7 +20,7 @@ const CommentsTabContent = ({isOwnProfile, username, type, onScroll, selectedUse
const intl = useIntl();
const isHideImage = useAppSelector(state => state.ui.hidePostsThumbnails);
const isHideImage = useAppSelector(state => state.application.hidePostsThumbnails);
const isAnalytics = useAppSelector(state => state.application.isAnalytics);
const [data, setData] = useState([]);

View File

@ -2,7 +2,7 @@ import React, { useRef, useState } from "react";
import { useIntl } from "react-intl";
import { useDispatch, useSelector } from "react-redux";
import { CustomiseFiltersModal, FilterBar } from "../..";
import { hidePostsThumbnails } from "../../../redux/actions/uiAction";
import { setHidePostsThumbnails } from "../../../redux/actions/applicationActions";
import { CustomiseFiltersModalRef } from "../../customiseFiltersModal/customiseFiltersModal";
export interface TabItem {
@ -42,7 +42,7 @@ export const StackedTabBar = ({
const customiseModalRef = useRef<CustomiseFiltersModalRef>();
//redux properties
const isHideImages = useSelector((state) => state.ui.hidePostsThumbnails);
const isHideImages = useSelector((state) => state.application.hidePostsThumbnails);
const [selectedFilterIndex, setSelectedFilterIndex] = useState(initialFirstStackIndex);
const [selectedSecondStackIndex, setSelectedSecondStackIndex] = useState(0);
@ -57,7 +57,7 @@ export const StackedTabBar = ({
}
const _onToggleImagesPress = () => {
dispatch(hidePostsThumbnails(!isHideImages))
dispatch(setHidePostsThumbnails(!isHideImages))
}
return (

View File

@ -783,7 +783,9 @@
"line2_body":"Utilizing blockchain, censorship-free, decentralized and rewarding.",
"line3_heading":"Join Ecency communities!",
"line3_body":"Build community you own, get rewarded and reward others.",
"get_started":"Get started!"
"get_started":"Get started!",
"terms_description": "By accepting, you agree to our Terms of Service and Privacy Policies.",
"terms_text": "Read Here!"
},
"time":{
"second":"seconds",

View File

@ -606,7 +606,7 @@ const mapStateToProps = (state) => ({
isAnalytics: state.application.isAnalytics,
activeBottomTab: state.ui.activeBottomTab,
currentAccount: state.account.currentAccount,
isHideImage: state.ui.hidePostsThumbnails,
isHideImage: state.application.hidePostsThumbnails,
});
export default connect(mapStateToProps)(injectIntl(withNavigation(ProfileContainer)));

View File

@ -1,7 +1,6 @@
import getSymbolFromCurrency from 'currency-symbol-map';
import { getCurrencyRate } from '../../providers/ecency/ecency';
import {
ACTIVE_APPLICATION,
CHANGE_COMMENT_NOTIFICATION,
CHANGE_FOLLOW_NOTIFICATION,
CHANGE_MENTION_NOTIFICATION,
@ -28,6 +27,11 @@ import {
SET_PIN_CODE,
IS_PIN_CODE_OPEN,
IS_RENDER_REQUIRED,
SET_LAST_APP_VERSION,
SET_COLOR_THEME,
SET_SETTINGS_MIGRATED,
HIDE_POSTS_THUMBNAILS,
SET_TERMS_ACCEPTED
} from '../constants/constants';
export const login = (payload) => ({
@ -47,7 +51,7 @@ export const isLoginDone = () => ({
type: IS_LOGIN_DONE,
});
export const openPinCodeModal = (payload) => ({
export const openPinCodeModal = (payload = null) => ({
payload,
type: OPEN_PIN_CODE_MODAL,
});
@ -56,9 +60,6 @@ export const closePinCodeModal = () => ({
type: CLOSE_PIN_CODE_MODAL,
});
export const activeApplication = () => ({
type: ACTIVE_APPLICATION,
});
// Settings actions
export const setLanguage = (payload) => ({
@ -135,6 +136,11 @@ export const isDarkTheme = (payload) => ({
type: IS_DARK_THEME,
});
export const setColorTheme = (payload:number) => ({
payload,
type: SET_COLOR_THEME
})
export const isPinCodeOpen = (payload) => ({
payload,
type: IS_PIN_CODE_OPEN,
@ -183,3 +189,24 @@ export const isRenderRequired = (payload) => ({
type: IS_RENDER_REQUIRED,
});
export const setLastAppVersion = (versionNumber:string) => ({
payload:versionNumber,
type: SET_LAST_APP_VERSION
})
export const setSettingsMigrated = (isMigrated:boolean) => ({
payload:isMigrated,
type: SET_SETTINGS_MIGRATED
})
export const setHidePostsThumbnails = (shouldHide:boolean) => ({
payload:shouldHide,
type: HIDE_POSTS_THUMBNAILS,
});
export const setIsTermsAccepted = (isTermsAccepted:boolean) => ({
payload:isTermsAccepted,
type: SET_TERMS_ACCEPTED
})

View File

@ -1,9 +1,7 @@
import { AlertButton } from 'react-native';
import {
TOAST_NOTIFICATION,
UPDATE_ACTIVE_BOTTOM_TAB,
HIDE_POSTS_THUMBNAILS,
RC_OFFER,
TOGGLE_ACCOUNTS_BOTTOM_SHEET,
SHOW_ACTION_MODAL,
@ -58,10 +56,6 @@ export const setRcOffer = (payload:boolean) => ({
type: RC_OFFER,
});
export const hidePostsThumbnails = (payload:boolean) => ({
payload,
type: HIDE_POSTS_THUMBNAILS,
});
export const toggleAccountsBottomSheet = (payload:boolean) => ({
payload,

View File

@ -4,7 +4,6 @@ export const FETCH_USER_SUCCESS = 'FETCH_USER_SUCCESS';
export const SET_USER_DATA = 'SET_USER_DATA';
// Applicaiton
export const ACTIVE_APPLICATION = 'ACTIVE_APPLICATION';
export const CLOSE_PIN_CODE_MODAL = 'CLOSE_PIN_CODE_MODAL';
export const IS_CONNECTED = 'IS_CONNECTED';
export const IS_ANALYTICS = 'IS_ANALYTICS';
@ -33,6 +32,10 @@ export const CHANGE_MENTION_NOTIFICATION = 'CHANGE_MENTION_NOTIFICATION';
export const CHANGE_REBLOG_NOTIFICATION = 'CHANGE_REBLOG_NOTIFICATION';
export const CHANGE_TRANSFERS_NOTIFICATION = 'CHANGE_TRANSFERS_NOTIFICATION';
export const CHANGE_ALL_NOTIFICATION_SETTINGS = 'CHANGE_ALL_NOTIFICATION_SETTINGS';
export const SET_LAST_APP_VERSION = 'SET_LAST_APP_VERSION';
export const SET_COLOR_THEME = 'SET_COLOR_THEME';
export const SET_SETTINGS_MIGRATED = 'SET_SETTINGS_MIGRATED';
export const SET_TERMS_ACCEPTED = 'SET_TERMS_ACCEPTED';
// Accounts
export const ADD_OTHER_ACCOUNT = 'ADD_OTHER_ACCOUNT';

View File

@ -1,5 +1,4 @@
import {
ACTIVE_APPLICATION,
CHANGE_COMMENT_NOTIFICATION,
CHANGE_FOLLOW_NOTIFICATION,
CHANGE_MENTION_NOTIFICATION,
@ -26,19 +25,63 @@ import {
SET_PIN_CODE,
IS_PIN_CODE_OPEN,
IS_RENDER_REQUIRED,
SET_LAST_APP_VERSION,
SET_COLOR_THEME,
SET_SETTINGS_MIGRATED,
HIDE_POSTS_THUMBNAILS,
SET_TERMS_ACCEPTED,
} from '../constants/constants';
const initialState = {
interface State {
api: string;
currency: {
currency: string,
currencyRate: number,
currencySymbol: string,
},
isConnected: boolean|null, // internet connectivity
isDarkTheme: boolean;
colorTheme: number;
isDefaultFooter: boolean; //TODO: remove present of isDefaultFooter as it's no longer in use
isLoggedIn: boolean; // Has any logged in user.
isAnalytics: boolean;
isLoginDone: boolean;
isLogingOut: boolean;
isNotificationOpen: boolean;
isPinCodeRequire: boolean;
pinCodeNavigation: any,
language: string,
loading: boolean; // It is lock to all screen and shows loading animation.
notificationDetails: {
commentNotification: boolean,
followNotification: boolean,
mentionNotification: boolean,
reblogNotification: boolean,
transfersNotification: boolean,
voteNotification: boolean,
},
upvotePercent: number;
nsfw: string;
pin: string|null;
isPinCodeOpen: boolean;
isRenderRequired: boolean;
lastAppVersion:string;
settingsMigrated: boolean;
hidePostsThumbnails: boolean;
isTermsAccepted: boolean;
}
const initialState:State = {
api: 'rpc.ecency.com',
currency: {
currency: 'usd',
currencyRate: 1,
currencySymbol: '$',
},
isActive: false,
isConnected: null, // internet connectivity
isDarkTheme: false,
isDefaultFooter: true,
colorTheme: 0, //values mapped from => src/constants/options/theme.ts
isDefaultFooter: true, //TODO: remove present of isDefaultFooter as it's no longer in use
isLoggedIn: false, // Has any logged in user.
isAnalytics: false,
isLoginDone: false,
@ -61,7 +104,10 @@ const initialState = {
pin: null,
isPinCodeOpen: true,
isRenderRequired: false,
lastAppVersion:'',
settingsMigrated: false,
hidePostsThumbnails: false,
isTermsAccepted: false,
};
export default function (state = initialState, action) {
@ -107,11 +153,6 @@ export default function (state = initialState, action) {
...state,
isPinCodeRequire: false,
};
case ACTIVE_APPLICATION:
return {
...state,
isActive: true,
};
case SET_API:
return Object.assign({}, state, {
api: action.payload,
@ -187,6 +228,11 @@ export default function (state = initialState, action) {
return Object.assign({}, state, {
isDarkTheme: action.payload,
});
case SET_COLOR_THEME:
return {
...state,
colorTheme:action.payload
};
case IS_PIN_CODE_OPEN:
return Object.assign({}, state, {
isPinCodeOpen: action.payload,
@ -212,6 +258,30 @@ export default function (state = initialState, action) {
return Object.assign({}, state, {
isRenderRequired: action.payload,
});
case SET_LAST_APP_VERSION:
return {
...state,
lastAppVersion:action.payload
}
case SET_SETTINGS_MIGRATED:
return {
...state,
settingsMigrated:action.payload
}
case HIDE_POSTS_THUMBNAILS:
return {
...state,
hidePostsThumbnails:action.payload
}
case SET_TERMS_ACCEPTED:
return {
...state,
isTermsAccepted:action.payload
}
default:
return state;

View File

@ -1,7 +1,6 @@
import {
UPDATE_ACTIVE_BOTTOM_TAB,
TOAST_NOTIFICATION,
HIDE_POSTS_THUMBNAILS,
RC_OFFER,
TOGGLE_ACCOUNTS_BOTTOM_SHEET,
SHOW_ACTION_MODAL,
@ -17,7 +16,6 @@ import { orientations } from '../constants/orientationsConstants';
interface UiState {
activeBottomTab:string;
toastNotification:string;
hidePostsThumbnails:boolean;
rcOffer:boolean;
isVisibleAccountsBottomSheet:boolean;
actionModalVisible:boolean;
@ -31,7 +29,6 @@ interface UiState {
const initialState:UiState = {
activeBottomTab: 'HomeTabbar',
toastNotification: '',
hidePostsThumbnails: false,
rcOffer: false,
isVisibleAccountsBottomSheet: false,
actionModalVisible: false,
@ -92,12 +89,6 @@ export default function (state = initialState, action) {
rcOffer: action.payload,
};
case HIDE_POSTS_THUMBNAILS:
return {
...state,
hidePostsThumbnails: action.payload,
};
case TOGGLE_ACCOUNTS_BOTTOM_SHEET:
return {
...state,

View File

@ -5,7 +5,6 @@ import AsyncStorage from '@react-native-community/async-storage';
import Reactotron from '../../../reactotron-config';
import reducer from '../reducers';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const transformCacheVoteMap = createTransform(
(inboundState:any) => ({
@ -40,7 +39,7 @@ const persistConfig = {
// Storage Method (React Native)
storage: AsyncStorage,
// Blacklist (Don't Save Specific Reducers)
blacklist: ['nav', 'application', 'communities', 'user'],
blacklist: ['nav', 'communities', 'user', 'ui'],
timeout: 0,
transforms:[
transformCacheVoteMap,

View File

@ -1,10 +1,9 @@
import React, { Component, Fragment } from 'react';
import { StatusBar, Platform, View, Alert, Text, Modal, TouchableHighlight } from 'react-native';
import { StatusBar, Platform, View, Alert } 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';
@ -14,7 +13,6 @@ import {
toastNotification as toastNotificationAction,
setRcOffer,
} from '../../../redux/actions/uiAction';
import { getVersionForWelcomeModal } from '../../../realm/realm';
import ROUTES from '../../../constants/routeNames';
@ -32,7 +30,6 @@ import {
// Themes (Styles)
import darkTheme from '../../../themes/darkTheme';
import lightTheme from '../../../themes/lightTheme';
import parseVersionNumber from '../../../utils/parseVersionNumber';
const Navigation = createAppContainer(AppNavitation);
@ -41,24 +38,14 @@ class ApplicationScreen extends Component {
super(props);
this.state = {
isShowToastNotification: false,
showWelcomeModal: false,
};
}
componentDidMount() {
const { appVersion } = VersionNumber;
getVersionForWelcomeModal().then((version) => {
if (version < parseVersionNumber(appVersion)) {
this.setState({ showWelcomeModal: true });
}
});
}
componentDidUpdate(prevProps) {
const { rcOffer, dispatch, intl } = this.props;
const { rcOffer: rcOfferPrev } = prevProps;
//TODO: display action modal instead
if (!rcOfferPrev && rcOffer) {
setTimeout(() => {
Alert.alert(
@ -109,25 +96,19 @@ class ApplicationScreen extends Component {
}
render() {
const {
isConnected,
isDarkTheme,
toastNotification,
isReady,
foregroundNotificationData,
navigation,
} = this.props;
const { isShowToastNotification, showWelcomeModal } = this.state;
const { isConnected, isDarkTheme, toastNotification, foregroundNotificationData } = this.props;
const { isShowToastNotification } = this.state;
const barStyle = isDarkTheme ? 'light-content' : 'dark-content';
const barColor = isDarkTheme ? '#1e2835' : '#fff';
return (
<View pointerEvents={isReady ? 'auto' : 'none'} style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
{Platform.os === 'ios' ? (
<StatusBar barStyle={barStyle} />
) : (
<StatusBar barStyle={barStyle} backgroundColor={barColor} />
)}
<Fragment>
{!isConnected && <NoInternetConnection />}
<Navigation
@ -135,32 +116,6 @@ class ApplicationScreen extends Component {
setTopLevelNavigator(navigatorRef);
}}
/>
<Modal
animationType="slide"
visible={false}
presentationStyle="pageSheet"
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}
>
<View
style={{
backgroundColor: 'white',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
this.setState({ showWelcomeModal: !showWelcomeModal });
}}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</Modal>
</Fragment>
{isShowToastNotification && (

View File

@ -0,0 +1,83 @@
import { Appearance } from 'react-native';
// Constants
import THEME_OPTIONS from '../../../constants/options/theme';
// Services
import {
getSettings,
} from '../../../realm/realm';
import {
isDarkTheme,
changeNotificationSettings,
changeAllNotificationSettings,
setApi,
setCurrency,
setLanguage,
setUpvotePercent,
setNsfw,
isDefaultFooter,
isPinCodeOpen,
setColorTheme,
setSettingsMigrated,
} from '../../../redux/actions/applicationActions';
import {
hideActionModal,
hideProfileModal,
setRcOffer,
toastNotification,
} from '../../../redux/actions/uiAction';
//migrates settings from realm to redux once and do no user realm for settings again;
export const migrateSettings = async (dispatch: any, settingsMigrated: boolean) => {
if (settingsMigrated) {
return;
}
//reset certain properties
dispatch(hideActionModal());
dispatch(hideProfileModal());
dispatch(toastNotification(''));
dispatch(setRcOffer(false));
const settings = await getSettings();
if (settings) {
const isDarkMode = Appearance.getColorScheme() === 'dark';
dispatch(isDarkTheme(settings.isDarkTheme !== null ? settings.isDarkTheme : isDarkMode));
dispatch(setColorTheme(THEME_OPTIONS.findIndex(item => item.value === settings.isDarkTheme)));
if (settings.isPinCodeOpen !== '') await dispatch(isPinCodeOpen(settings.isPinCodeOpen));
if (settings.language !== '') dispatch(setLanguage(settings.language));
if (settings.server !== '') dispatch(setApi(settings.server));
if (settings.upvotePercent !== '') {
dispatch(setUpvotePercent(Number(settings.upvotePercent)));
}
if (settings.isDefaultFooter !== '') dispatch(isDefaultFooter(settings.isDefaultFooter)); //TODO: remove as not being used
if (settings.nsfw !== '') dispatch(setNsfw(settings.nsfw));
dispatch(setCurrency(settings.currency !== '' ? settings.currency : 'usd'));
if (settings.notification !== '') {
dispatch(
changeNotificationSettings({
type: 'notification',
action: settings.notification,
}),
);
dispatch(changeAllNotificationSettings(settings));
}
await dispatch(setSettingsMigrated(true))
}
}
export default {
migrateSettings
}

View File

@ -0,0 +1,77 @@
import React, { useEffect, useRef } from 'react'
import { AppState } from 'react-native';
import { Modal } from '../../../components';
import { useAppDispatch, useAppSelector } from '../../../hooks'
import { getExistUser } from '../../../realm/realm';
import { openPinCodeModal } from '../../../redux/actions/applicationActions';
import PinCode from '../../pinCode';
interface PinCodeModalProps {
welcomeModalVisible: boolean;
}
const PinCodeModal = ({ welcomeModalVisible }: PinCodeModalProps) => {
const dispatch = useAppDispatch();
const pinCodeTimer = useRef<any>(null);
const appState = useRef(AppState.currentState);
const isPinCodeRequire = useAppSelector(state => state.application.isPinCodeRequire);
const isPinCodeOpen = useAppSelector(state => state.application.isPinCodeOpen);
useEffect(() => {
AppState.addEventListener('change', _handleAppStateChange);
return _unmount
}, [])
const _unmount = () => {
AppState.removeEventListener('change', _handleAppStateChange);
}
const _handleAppStateChange = (nextAppState) => {
getExistUser().then((isExistUser) => {
if (isExistUser) {
if (appState.current.match(/active|forground/) && nextAppState === 'inactive') {
_startPinCodeTimer();
}
if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
if (isPinCodeOpen && pinCodeTimer.current) {
clearTimeout(pinCodeTimer.current);
}
}
}
});
appState.current = nextAppState;
};
const _startPinCodeTimer = () => {
if (isPinCodeOpen) {
pinCodeTimer.current = setTimeout(() => {
dispatch(openPinCodeModal());
}, 1 * 60 * 1000);
}
};
return (
<Modal
isOpen={isPinCodeRequire && !welcomeModalVisible}
isFullScreen
swipeToClose={false}
backButtonClose={false}
style={{ margin: 0 }}
>
<PinCode />
</Modal>
)
}
export default PinCodeModal

View File

@ -0,0 +1,156 @@
import React, { useState, useEffect } from 'react';
import { useIntl } from 'react-intl';
import { Text, Image, View, SafeAreaView, TouchableOpacity, Linking } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import { ScrollView } from 'react-native-gesture-handler';
import VersionNumber from 'react-native-version-number';
import { CheckBox, Icon, MainButton, Modal } from '../../../components';
import { useAppDispatch, useAppSelector } from '../../../hooks';
import { setLastAppVersion, setIsTermsAccepted } from '../../../redux/actions/applicationActions';
import parseVersionNumber from '../../../utils/parseVersionNumber';
import LaunchScreen from '../../launch';
import styles from './welcomeStyles';
const WelcomeModal = ({ onModalVisibilityChange }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const lastAppVersion = useAppSelector(state => state.application.lastAppVersion)
const isTermsAccepted = useAppSelector(state => state.application.isTermsAccepted);
const [showAnimation, setShowAnimation] = useState(true);
const [showWelcomeModal, setShowWelcomeModal] = useState(false);
const [isConsentChecked, setIsConsentChecked] = useState(isTermsAccepted);
const [appVersion] = useState(VersionNumber.appVersion);
useEffect(() => {
_compareAppVersion()
}, [])
const _compareAppVersion = () => {
if (!lastAppVersion || (parseVersionNumber(lastAppVersion) < parseVersionNumber(appVersion))) {
_showWelcomeModal();
}
}
const _showWelcomeModal = () => {
setShowWelcomeModal(true);
onModalVisibilityChange(true);
setShowAnimation(true);
setTimeout(() => {
setShowAnimation(false);
}, 3550);
}
const _handleButtonPress = () => {
dispatch(setLastAppVersion(appVersion))
dispatch(setIsTermsAccepted(isConsentChecked));
setShowWelcomeModal(false);
onModalVisibilityChange(false);
}
const _onCheckPress = (value, isCheck) => {
setIsConsentChecked(isCheck);
};
const _renderInfo = (iconName, headingIntlId, bodyIntlId) => (
<View style={styles.sectionRow}>
<Icon
iconType="SimpleLineIcons"
name={iconName}
color={EStyleSheet.value('$primaryBlue')}
size={30}
/>
<View>
<Text style={styles.sectionTitle}>{intl.formatMessage({ id: headingIntlId })}</Text>
<Text style={styles.sectionText}>{intl.formatMessage({ id: bodyIntlId })}</Text>
</View>
</View>
);
const _renderConsent = () => (
<View style={styles.consentContainer}>
<CheckBox isChecked={isConsentChecked} clicked={_onCheckPress} style={styles.checkStyle} />
<TouchableOpacity onPress={() => Linking.openURL('https://ecency.com/terms-of-service')}>
<View style={styles.consentTextContainer}>
<Text style={styles.termsDescText}>
{intl.formatMessage({
id: 'welcome.terms_description',
})}
<Text style={styles.termsLinkText}>
{' '}
{intl.formatMessage({
id: 'welcome.terms_text',
})}
</Text>
</Text>
</View>
</TouchableOpacity>
</View>
);
const _renderContent = () => (
<SafeAreaView style={styles.root}>
<View style={styles.container}>
<Image
style={styles.mascot}
resizeMode="contain"
source={require('../../../assets/love_mascot.png')}
/>
<View style={styles.topText}>
<Text style={styles.welcomeText}>{intl.formatMessage({ id: 'welcome.label' })}</Text>
<Text style={styles.ecencyText}>{intl.formatMessage({ id: 'welcome.title' })}</Text>
</View>
<ScrollView contentContainerStyle={styles.contentContainer} >
<TouchableOpacity disabled={!isConsentChecked} onPress={_handleButtonPress} >
{_renderInfo('question', 'welcome.line1_heading', 'welcome.line1_body')}
{_renderInfo('emotsmile', 'welcome.line2_heading', 'welcome.line2_body')}
{_renderInfo('people', 'welcome.line3_heading', 'welcome.line3_body')}
</TouchableOpacity>
</ScrollView>
<View style={styles.bottomContainer}>
{_renderConsent()}
<MainButton
onPress={_handleButtonPress}
isDisable={!isConsentChecked}
isLoading={false}
style={{ alignSelf: 'center', paddingHorizontal: 30 }}
text={intl.formatMessage({ id: 'welcome.get_started' })}
/>
</View>
</View>
{showAnimation && <LaunchScreen />}
</SafeAreaView>
);
return (
<Modal
isOpen={showWelcomeModal}
isFullScreen
swipeToClose={false}
backButtonClose={false}
style={{ margin: 0 }}
>
{_renderContent()}
</Modal>)
};
export default WelcomeModal;

View File

@ -20,6 +20,11 @@ export default EStyleSheet.create({
paddingBottom: 20,
paddingHorizontal: 40,
},
contentContainer: {
flexGrow: 1,
justifyContent: 'center',
},
welcomeText: {
fontSize: scalePx(34),
color: '$primaryBlack',
@ -47,8 +52,10 @@ export default EStyleSheet.create({
topText: {
marginTop: 40,
},
bottomButton: {
paddingTop: 10,
bottomContainer: {
marginTop: 8,
borderTopWidth: EStyleSheet.hairlineWidth,
borderColor: '$iconColor',
},
sectionRow: {
flexDirection: 'row',
@ -69,4 +76,28 @@ export default EStyleSheet.create({
flex1: {
flex: 1,
},
consentContainer: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 32,
marginBottom: 40,
},
checkStyle: {
backgroundColor: '$white',
marginRight: 12,
},
consentTextContainer: {
flexDirection: 'row',
flex: 1,
flexWrap: 'wrap',
},
termsDescText: {
fontSize: 14,
color: '$primaryBlack',
},
termsLinkText: {
fontSize: 14,
fontWeight: '700',
color: '$primaryBlue',
},
});

View File

@ -10,12 +10,12 @@ import { NavigationActions } from 'react-navigation';
import { bindActionCreators } from 'redux';
import EStyleSheet from 'react-native-extended-stylesheet';
import { isEmpty, some } from 'lodash';
import { useDarkMode } from 'react-native-dynamic';
import messaging from '@react-native-firebase/messaging';
import PushNotification from 'react-native-push-notification';
import VersionNumber from 'react-native-version-number';
import ReceiveSharingIntent from 'react-native-receive-sharing-intent';
import Matomo from 'react-native-matomo-sdk';
import SplashScreen from 'react-native-splash-screen'
// Constants
import AUTH_TYPE from '../../../constants/authType';
@ -25,8 +25,6 @@ import postUrlParser from '../../../utils/postUrlParser';
// Services
import {
getAuthStatus,
getExistUser,
getSettings,
getUserData,
removeUserData,
getUserDataWithUsername,
@ -34,8 +32,6 @@ import {
setAuthStatus,
removeSCAccount,
setExistUser,
getVersionForWelcomeModal,
setVersionForWelcomeModal,
getLastUpdateCheck,
setLastUpdateCheck,
getTheme,
@ -49,10 +45,8 @@ import {
} from '../../../providers/hive/auth';
import {
setPushToken,
markActivityAsRead,
markNotifications,
getUnreadNotificationCount,
getLatestQuotes,
} from '../../../providers/ecency/ecency';
import { fetchLatestAppVersion } from '../../../providers/github/github';
import { navigate } from '../../../navigation/service';
@ -64,34 +58,20 @@ import {
updateUnreadActivityCount,
removeOtherAccount,
fetchGlobalProperties,
removeAllOtherAccount,
} from '../../../redux/actions/accountAction';
import {
activeApplication,
isDarkTheme,
changeNotificationSettings,
changeAllNotificationSettings,
login,
logoutDone,
openPinCodeModal,
setApi,
setConnectivityStatus,
setAnalyticsStatus,
setCurrency,
setLanguage,
setUpvotePercent,
setNsfw,
isDefaultFooter,
isPinCodeOpen,
setPinCode as savePinCode,
isRenderRequired,
logout,
} from '../../../redux/actions/applicationActions';
import {
hideActionModal,
hideProfileModal,
setAvatarCacheStamp,
setRcOffer,
showActionModal,
toastNotification,
updateActiveBottomTab,
@ -105,10 +85,11 @@ import darkTheme from '../../../themes/darkTheme';
import lightTheme from '../../../themes/lightTheme';
import persistAccountGenerator from '../../../utils/persistAccountGenerator';
import parseVersionNumber from '../../../utils/parseVersionNumber';
import { getTimeFromNow, setMomentLocale } from '../../../utils/time';
import { setMomentLocale } from '../../../utils/time';
import parseAuthUrl from '../../../utils/parseAuthUrl';
import { purgeExpiredCache } from '../../../redux/actions/cacheActions';
import { fetchSubscribedCommunities } from '../../../redux/actions/communitiesAction';
import MigrationHelpers from '../children/migrationHelpers';
// Workaround
let previousAppState = 'background';
@ -123,25 +104,20 @@ export const setPreviousAppState = () => {
let firebaseOnNotificationOpenedAppListener = null;
let firebaseOnMessageListener = null;
let removeAppearanceListener = null;
let scAccounts = [];
class ApplicationContainer extends Component {
constructor(props) {
super(props);
this.state = {
isRenderRequire: true,
isReady: false,
isIos: Platform.OS !== 'android',
isThemeReady: false,
appState: AppState.currentState,
showWelcomeModal: false,
foregroundNotificationData: null,
};
}
componentDidMount = () => {
const { isIos } = this.state;
const { appVersion } = VersionNumber;
const { dispatch, isAnalytics } = this.props;
this._setNetworkListener();
@ -163,22 +139,9 @@ class ApplicationContainer extends Component {
//set avatar cache stamp to invalidate previous session avatars
dispatch(setAvatarCacheStamp(new Date().getTime()));
getVersionForWelcomeModal().then((version) => {
if (version < parseVersionNumber(appVersion)) {
getUserData().then((accounts) => {
this.setState({ showWelcomeModal: true });
if (accounts && accounts.length > 0) {
accounts.forEach((account) => {
if (get(account, 'authType', '') === AUTH_TYPE.STEEM_CONNECT) {
scAccounts.push(account);
}
});
}
});
}
});
SplashScreen.hide();
setMomentLocale();
this._fetchApp();
ReceiveSharingIntent.getReceivedFiles(
() => {
@ -235,7 +198,7 @@ class ApplicationContainer extends Component {
if (!isIos) BackHandler.removeEventListener('hardwareBackPress', this._onBackPress);
// NetInfo.isConnected.removeEventListener('connectionChange', this._handleConntectionChange);
//TOOD: listen for back press and cancel all pending api requests;
Linking.removeEventListener('url', this._handleOpenURL);
@ -439,22 +402,10 @@ class ApplicationContainer extends Component {
);
};
_handleAppStateChange = (nextAppState) => {
const { appState } = this.state;
const { isPinCodeOpen: _isPinCodeOpen } = this.props;
getExistUser().then((isExistUser) => {
if (isExistUser) {
if (appState.match(/active|forground/) && nextAppState === 'inactive') {
this._startPinCodeTimer();
}
if (appState.match(/inactive|background/) && nextAppState === 'active') {
if (_isPinCodeOpen) {
clearTimeout(this._pinCodeTimer);
}
}
}
});
if (appState.match(/inactive|background/) && nextAppState === 'active') {
this._refreshGlobalProps();
}
@ -464,24 +415,16 @@ class ApplicationContainer extends Component {
});
};
_startPinCodeTimer = () => {
const { dispatch, isPinCodeOpen: _isPinCodeOpen } = this.props;
if (_isPinCodeOpen) {
this._pinCodeTimer = setTimeout(() => {
dispatch(openPinCodeModal());
}, 1 * 60 * 1000);
}
};
_fetchApp = async () => {
await this._getSettings();
this.setState({
isReady: true,
});
const {dispatch, settingsMigrated} = this.props;
await MigrationHelpers.migrateSettings(dispatch, settingsMigrated)
this._refreshGlobalProps();
await this._getUserDataFromRealm();
this._compareAndPromptForUpdate();
this._registerDeviceForNotifications();
dispatch(purgeExpiredCache());
};
_pushNavigate = (notification) => {
@ -647,7 +590,6 @@ class ApplicationContainer extends Component {
const { currentUsername } = res;
if (res) {
dispatch(activeApplication());
dispatch(login(true));
const userData = await getUserData();
@ -696,11 +638,11 @@ class ApplicationContainer extends Component {
// TODO:
await switchAccount(realmObject[0].username);
}
const isExistUser = await getExistUser();
realmObject[0].name = currentUsername;
// If in dev mode pin code does not show
if ((!isExistUser || !pinCode) && _isPinCodeOpen) {
if (_isPinCodeOpen) {
dispatch(openPinCodeModal());
} else if (!_isPinCodeOpen) {
const encryptedPin = encryptKey(Config.DEFAULT_PIN, Config.PIN_KEY);
@ -709,13 +651,13 @@ class ApplicationContainer extends Component {
if (isConnected) {
this._fetchUserDataFromDsteem(realmObject[0]);
}
return realmObject[0];
}
dispatch(updateCurrentAccount({}));
dispatch(activeApplication());
return null;
};
@ -788,6 +730,7 @@ class ApplicationContainer extends Component {
dispatch(updateCurrentAccount(accountData));
dispatch(fetchSubscribedCommunities(realmObject.username));
this._connectNotificationServer(accountData.name);
//TODO: better update device push token here after access token refresh
} catch (err) {
Alert.alert(
`${intl.formatMessage({ id: 'alert.fetch_error' })} \n${err.message.substr(0, 20)}`,
@ -795,63 +738,34 @@ class ApplicationContainer extends Component {
}
};
_getSettings = async () => {
const { dispatch, otherAccounts } = this.props;
//reset certain properties
dispatch(hideActionModal());
dispatch(hideProfileModal());
dispatch(toastNotification(''));
dispatch(purgeExpiredCache());
dispatch(setRcOffer(false));
const settings = await getSettings();
//update notification settings and update push token for each signed accoutn useing access tokens
_registerDeviceForNotifications = (settings?:any) => {
const { otherAccounts, notificationDetails, isNotificationsEnabled } = this.props;
const isEnabled = settings ? !!settings.notification : isNotificationsEnabled;
settings = settings || notificationDetails;
if (settings) {
const isDarkMode = Appearance.getColorScheme() === 'dark';
dispatch(isDarkTheme(settings.isDarkTheme !== null ? settings.isDarkTheme : isDarkMode));
this.setState({
isThemeReady: true,
});
if (settings.isPinCodeOpen !== '') await dispatch(isPinCodeOpen(settings.isPinCodeOpen));
if (settings.language !== '') dispatch(setLanguage(settings.language));
if (settings.server !== '') dispatch(setApi(settings.server));
if (settings.upvotePercent !== '') {
dispatch(setUpvotePercent(Number(settings.upvotePercent)));
//updateing fcm token with settings;
otherAccounts.forEach((account) => {
//since there can be more than one accounts, process access tokens separate
const encAccessToken = account?.local?.accessToken;
//decrypt access token
let accessToken = null;
if (encAccessToken) {
//NOTE: default pin decryption works also for custom pin as other account
//keys are not yet being affected by changed pin, which I think we should dig more
accessToken = decryptKey(encAccessToken, Config.DEFAULT_PIN);
}
if (settings.isDefaultFooter !== '') dispatch(isDefaultFooter(settings.isDefaultFooter));
if (settings.notification !== '') {
console.log('Notification Settings', settings.notification, otherAccounts);
dispatch(
changeNotificationSettings({
type: 'notification',
action: settings.notification,
}),
);
dispatch(changeAllNotificationSettings(settings));
//updateing fcm token with settings;
otherAccounts.forEach((account) => {
//since there can be more than one accounts, process access tokens separate
const encAccessToken = account.local.accessToken;
//decrypt access token
let accessToken = null;
if (encAccessToken) {
//NOTE: default pin decryption works also for custom pin as other account
//keys are not yet being affected by changed pin, which I think we should dig more
accessToken = decryptKey(encAccessToken, Config.DEFAULT_PIN);
}
this._enableNotification(account.name, settings.notification, settings, accessToken);
});
}
if (settings.nsfw !== '') dispatch(setNsfw(settings.nsfw));
await dispatch(setCurrency(settings.currency !== '' ? settings.currency : 'usd'));
}
this._enableNotification(account.name, isEnabled, settings, accessToken);
});
};
_connectNotificationServer = (username) => {
/* eslint no-undef: "warn" */
const ws = new WebSocket(`${Config.ACTIVITY_WEBSOCKET_URL}?user=${username}`);
@ -988,13 +902,6 @@ class ApplicationContainer extends Component {
dispatch(fetchSubscribedCommunities(_currentAccount.username));
};
_handleWelcomeModalButtonPress = () => {
const { appVersion } = VersionNumber;
setVersionForWelcomeModal(appVersion);
this.setState({ showWelcomeModal: false });
};
UNSAFE_componentWillReceiveProps(nextProps) {
const {
@ -1050,13 +957,7 @@ class ApplicationContainer extends Component {
isPinCodeRequire,
rcOffer,
} = this.props;
const {
isRenderRequire,
isReady,
isThemeReady,
showWelcomeModal,
foregroundNotificationData,
} = this.state;
const { isRenderRequire, foregroundNotificationData } = this.state;
return (
children &&
@ -1064,15 +965,11 @@ class ApplicationContainer extends Component {
isConnected,
isDarkTheme: _isDarkTheme,
isPinCodeRequire,
isReady,
isRenderRequire,
isThemeReady,
locale: selectedLanguage,
rcOffer,
toastNotification,
showWelcomeModal,
foregroundNotificationData,
handleWelcomeModalButtonPress: this._handleWelcomeModalButtonPress,
})
);
}
@ -1085,15 +982,17 @@ export default connect(
selectedLanguage: state.application.language,
isPinCodeOpen: state.application.isPinCodeOpen,
isLogingOut: state.application.isLogingOut,
isLoggedIn: state.application.isLoggedIn,
isLoggedIn: state.application.isLoggedIn, //TODO: remove as is not being used in this class
isConnected: state.application.isConnected,
nav: state.nav.routes,
isPinCodeRequire: state.application.isPinCodeRequire,
isActiveApp: state.application.isActive,
api: state.application.api,
isGlobalRenderRequired: state.application.isRenderRequired,
isAnalytics: state.application.isAnalytics,
lastUpdateCheck: state.application.lastUpdateCheck,
settingsMigrated: state.application.settingsMigrated,
isNotificationsEnabled: state.application.isNotificationOpen,
notificationDetails: state.application.notificationDetails,
// Account
unreadActivityCount: state.account.currentAccount.unread_activity_count,

View File

@ -1,100 +0,0 @@
import React, { Fragment, useEffect, useState } from 'react';
import { Dimensions } from 'react-native';
import SplashScreen from 'react-native-splash-screen';
import { OrientationLocker, PORTRAIT, LANDSCAPE } from 'react-native-orientation-locker';
import { useDispatch } from 'react-redux';
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';
import ErrorBoundary from './screen/errorBoundary';
import { setDeviceOrientation } from '../../redux/actions/uiAction';
const Application = () => {
const dispatch = useDispatch();
const [showAnimation, setShowAnimation] = useState(process.env.NODE_ENV !== 'development');
useEffect(() => {
SplashScreen.hide();
if (showAnimation) {
setTimeout(() => {
setShowAnimation(false);
}, 3550);
}
}, [showAnimation]);
const _handleDeviceOrientationChange = (orientation) => {
console.log('device orientation changed at index : ', orientation);
dispatch(setDeviceOrientation(orientation));
};
return (
<ApplicationContainer>
{({
isConnected,
isDarkTheme,
isPinCodeRequire,
isReady,
isRenderRequire,
isThemeReady,
locale,
rcOffer,
toastNotification,
showWelcomeModal,
handleWelcomeModalButtonPress,
foregroundNotificationData,
}) => {
const _isAppReady = !showAnimation && isReady && isRenderRequire && isThemeReady;
return (
<ErrorBoundary>
<OrientationLocker
orientation={PORTRAIT}
onChange={(orientation) => console.log('orientation changed : ', orientation)}
onDeviceChange={_handleDeviceOrientationChange}
/>
<Modal
isOpen={showWelcomeModal && _isAppReady}
isFullScreen
swipeToClose={false}
backButtonClose={false}
style={{ margin: 0 }}
>
<WelcomeScreen handleButtonPress={handleWelcomeModalButtonPress} />
</Modal>
<Modal
isOpen={isPinCodeRequire && !showWelcomeModal}
isFullScreen
swipeToClose={false}
backButtonClose={false}
style={{ margin: 0 }}
>
<PinCode />
</Modal>
{isThemeReady && isRenderRequire && (
<ApplicationScreen
isConnected={isConnected}
locale={locale}
toastNotification={toastNotification}
isReady={isReady}
isDarkTheme={isDarkTheme}
rcOffer={rcOffer}
foregroundNotificationData={foregroundNotificationData}
/>
)}
{!_isAppReady && <LaunchScreen />}
</ErrorBoundary>
);
}}
</ApplicationContainer>
);
};
export default Application;
export { ApplicationContainer, ApplicationScreen };

View File

@ -0,0 +1,68 @@
import React, { useState } from 'react';
import { OrientationLocker, PORTRAIT } from 'react-native-orientation-locker';
import { useDispatch } from 'react-redux';
import ApplicationContainer from './container/applicationContainer';
import WelcomeModal from './children/welcomeModal';
import ApplicationScreen from './children/applicationScreen';
import ErrorBoundary from './children/errorBoundary';
import { setDeviceOrientation } from '../../redux/actions/uiAction';
import PinCodeModal from './children/pinCodeModal';
const Application = () => {
const dispatch = useDispatch();
const [welcomeModalVisible, setWelcomeModalVisible] = useState(false);
const _handleDeviceOrientationChange = (orientation) => {
console.log('device orientation changed at index : ', orientation);
dispatch(setDeviceOrientation(orientation));
};
return (
<ApplicationContainer>
{({
isConnected,
isDarkTheme,
isPinCodeRequire,
isRenderRequire,
locale,
rcOffer,
toastNotification,
foregroundNotificationData,
}) => {
return (
<ErrorBoundary>
<OrientationLocker
orientation={PORTRAIT}
onChange={(orientation) => console.log('orientation changed : ', orientation)}
onDeviceChange={_handleDeviceOrientationChange}
/>
<WelcomeModal onModalVisibilityChange={setWelcomeModalVisible} />
<PinCodeModal welcomeModalVisible={welcomeModalVisible} />
{isRenderRequire && (
<ApplicationScreen
isConnected={isConnected}
locale={locale}
toastNotification={toastNotification}
isDarkTheme={isDarkTheme}
rcOffer={rcOffer}
foregroundNotificationData={foregroundNotificationData}
/>
)}
</ErrorBoundary>
);
}}
</ApplicationContainer>
);
};
export default Application;
export { ApplicationContainer, ApplicationScreen };

View File

@ -1,60 +0,0 @@
import React from 'react';
import { useIntl } from 'react-intl';
import { Text, Image, View, SafeAreaView, TouchableOpacity } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import { Icon, MainButton } from '../../../components';
import styles from './welcomeStyles';
const WelcomeScreen = ({ handleButtonPress }) => {
const intl = useIntl();
const _renderInfo = (iconName, headingIntlId, bodyIntlId) => (
<View style={styles.sectionRow}>
<Icon
iconType="SimpleLineIcons"
name={iconName}
color={EStyleSheet.value('$primaryBlue')}
size={30}
/>
<View>
<Text style={styles.sectionTitle}>{intl.formatMessage({ id: headingIntlId })}</Text>
<Text style={styles.sectionText}>{intl.formatMessage({ id: bodyIntlId })}</Text>
</View>
</View>
);
return (
<SafeAreaView style={styles.root}>
<TouchableOpacity onPress={handleButtonPress} style={styles.container}>
<Image
style={styles.mascot}
resizeMode="contain"
source={require('../../../assets/love_mascot.png')}
/>
<View style={styles.topText}>
<Text style={styles.welcomeText}>{intl.formatMessage({ id: 'welcome.label' })}</Text>
<Text style={styles.ecencyText}>{intl.formatMessage({ id: 'welcome.title' })}</Text>
</View>
<View>
{_renderInfo('question', 'welcome.line1_heading', 'welcome.line1_body')}
{_renderInfo('emotsmile', 'welcome.line2_heading', 'welcome.line2_body')}
{_renderInfo('people', 'welcome.line3_heading', 'welcome.line3_body')}
</View>
<View style={styles.bottomButton}>
<MainButton
onPress={handleButtonPress}
isDisable={false}
isLoading={false}
style={{ alignSelf: 'center', paddingHorizontal: 30 }}
text={intl.formatMessage({ id: 'welcome.get_started' })}
/>
</View>
</TouchableOpacity>
</SafeAreaView>
);
};
export default WelcomeScreen;

View File

@ -1,10 +1,9 @@
import React, { Fragment, useEffect } from 'react';
import { SafeAreaView } from 'react-native';
import { useSelector } from 'react-redux';
import React, { Fragment, useState, useEffect } from 'react';
import { ActivityIndicator, SafeAreaView } from 'react-native';
import get from 'lodash/get';
// Components
import { Posts, Header, TabbedPosts } from '../../../components';
import { Header, TabbedPosts } from '../../../components';
// Container
import { AccountContainer } from '../../../containers';
@ -23,22 +22,37 @@ const FeedScreen = () => {
const mainTabs = useAppSelector((state) => state.customTabs.mainTabs || getDefaultFilters('main'));
const filterOptions = mainTabs.map((key) => getFilterMap('main')[key]);
const [lazyLoad, setLazyLoad] = useState(false);
const _lazyLoadContent = () => {
if(!lazyLoad){
setTimeout(() => {
setLazyLoad(true);
}, 100)
}
}
return (
<AccountContainer>
{({ currentAccount }) => (
<Fragment>
<Header enableViewModeToggle={true} />
<SafeAreaView style={styles.container}>
<TabbedPosts
key={JSON.stringify(filterOptions)} //this hack of key change resets tabbedposts whenever filters chanage, effective to remove filter change android bug
filterOptions={filterOptions}
filterOptionsValue={mainTabs}
getFor={get(currentAccount, 'name', null) ? 'feed' : 'hot'}
selectedOptionIndex={get(currentAccount, 'name', null) ? 0 : 2}
feedUsername={get(currentAccount, 'name', null)}
isFeedScreen={true}
pageType='main'
/>
<SafeAreaView style={styles.container} onLayout={_lazyLoadContent}>
{lazyLoad && (
<TabbedPosts
key={JSON.stringify(filterOptions)} //this hack of key change resets tabbedposts whenever filters chanage, effective to remove filter change android bug
filterOptions={filterOptions}
filterOptionsValue={mainTabs}
getFor={get(currentAccount, 'name', null) ? 'feed' : 'hot'}
selectedOptionIndex={get(currentAccount, 'name', null) ? 0 : 2}
feedUsername={get(currentAccount, 'name', null)}
isFeedScreen={true}
pageType='main'
/>
)}
</SafeAreaView>
</Fragment>
)}

View File

@ -1,10 +1,11 @@
import React from 'react';
import { View, Appearance } from 'react-native';
import { View } from 'react-native';
import LottieView from 'lottie-react-native';
import styles from './launchStyles';
import { useAppSelector } from '../../../hooks';
const LaunchScreen = () => {
const isDarkMode = Appearance.getColorScheme() === 'dark';
const isDarkMode = useAppSelector((state) => state.application.isDarkTheme);
return (
<View style={isDarkMode ? styles.darkContainer : styles.container}>
<LottieView

View File

@ -42,6 +42,7 @@ import {
login,
logoutDone,
closePinCodeModal,
setColorTheme,
} from '../../../redux/actions/applicationActions';
import { toastNotification } from '../../../redux/actions/uiAction';
import { setPushToken, getNodes } from '../../../providers/ecency/ecency';
@ -91,12 +92,6 @@ class SettingsContainer extends Component {
serverList: SERVER_LIST,
}),
);
getTheme().then((themeSetting) => {
this.setState({
themeSetting,
});
});
}
// Component Functions
@ -127,11 +122,9 @@ class SettingsContainer extends Component {
const systemTheme = Appearance.getColorScheme();
dispatch(isDarkTheme(setting === null ? systemTheme === 'dark' : setting));
dispatch(setColorTheme(action));
setTheme(setting); //TODO: remove before merging
setTheme(setting);
this.setState({
themeSetting: setting,
});
break;
default:
@ -269,6 +262,7 @@ class SettingsContainer extends Component {
type: actionType,
}),
);
//TODO: remove setting notification settings
setNotificationSettings({
action,
type: actionType,
@ -468,7 +462,8 @@ class SettingsContainer extends Component {
};
render() {
const { serverList, isNotificationMenuOpen, isLoading, themeSetting } = this.state;
const { serverList, isNotificationMenuOpen, isLoading } = this.state;
const { colorTheme } = this.props;
return (
<SettingsScreen
@ -477,7 +472,7 @@ class SettingsContainer extends Component {
isNotificationMenuOpen={isNotificationMenuOpen}
handleOnButtonPress={this._handleButtonPress}
isLoading={isLoading}
themeSetting={themeSetting}
colorThemeIndex={colorTheme}
{...this.props}
/>
);
@ -486,6 +481,7 @@ class SettingsContainer extends Component {
const mapStateToProps = (state) => ({
isDarkTheme: state.application.isDarkTheme,
colorTheme: state.application.colorTheme,
isPinCodeOpen: state.application.isPinCodeOpen,
pinCode: state.application.pin,
isDefaultFooter: state.application.isDefaultFooter,

View File

@ -22,7 +22,7 @@ const SettingsScreen = ({
handleOnChange,
intl,
isDarkTheme,
themeSetting,
colorThemeIndex,
isPinCodeOpen,
isLoggedIn,
isNotificationSettingsOpen,
@ -129,7 +129,7 @@ const SettingsScreen = ({
id: item.key,
}),
)}
selectedOptionIndex={THEME_OPTIONS.findIndex((item) => item.value === themeSetting)}
selectedOptionIndex={colorThemeIndex}
handleOnChange={handleOnChange}
/>

View File

@ -9049,10 +9049,10 @@ react-native-snap-carousel@^3.8.0:
prop-types "^15.6.1"
react-addons-shallow-compare "15.6.2"
react-native-splash-screen@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz#d47ec8557b1ba988ee3ea98d01463081b60fff45"
integrity sha512-Ls9qiNZzW/OLFoI25wfjjAcrf2DZ975hn2vr6U9gyuxi2nooVbzQeFoQS5vQcbCt9QX5NY8ASEEAtlLdIa6KVg==
react-native-splash-screen@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.3.0.tgz#3af71ed17afe50fee69590a45aec399d071ead02"
integrity sha512-rGjt6HkoSXxMqH4SQUJ1gnPQlPJV8+J47+4yhgTIan4bVvAwJhEeJH7wWt9hXSdH4+VfwTS0GTaflj1Tw83IhA==
react-native-svg@^12.1.1:
version "12.1.1"