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 "AppDelegate.h"
#import "RNSplashScreen.h"
#import <AppCenterReactNativeShared/AppCenterReactNativeShared.h> #import <AppCenterReactNativeShared/AppCenterReactNativeShared.h>
#import <AppCenterReactNative.h> #import <AppCenterReactNative.h>
#import <AppCenterReactNativeAnalytics.h> #import <AppCenterReactNativeAnalytics.h>

View File

@ -361,8 +361,8 @@ PODS:
- React-Core - React-Core
- react-native-safe-area-context (3.1.9): - react-native-safe-area-context (3.1.9):
- React-Core - React-Core
- react-native-splash-screen (3.2.0): - react-native-splash-screen (3.3.0):
- React - React-Core
- react-native-udp (2.7.0): - react-native-udp (2.7.0):
- React - React
- react-native-version-number (0.3.6): - react-native-version-number (0.3.6):
@ -791,7 +791,7 @@ SPEC CHECKSUMS:
react-native-receive-sharing-intent: feba0a332a07977549a85aa58b496eb44368366a react-native-receive-sharing-intent: feba0a332a07977549a85aa58b496eb44368366a
react-native-restart: aaad36f3ed7031daac3565f4a79d67e4f3884a50 react-native-restart: aaad36f3ed7031daac3565f4a79d67e4f3884a50
react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94 react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-udp: ff9d13e523f2b58e6bc5d4d32321ac60671b5dc9 react-native-udp: ff9d13e523f2b58e6bc5d4d32321ac60671b5dc9
react-native-version-number: b415bbec6a13f2df62bf978e85bc0d699462f37f react-native-version-number: b415bbec6a13f2df62bf978e85bc0d699462f37f
react-native-video: a4c2635d0802f983594b7057e1bce8f442f0ad28 react-native-video: a4c2635d0802f983594b7057e1bce8f442f0ad28
@ -833,4 +833,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 0282022703ad578ab2d9afbf3147ba3b373b4311 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-scrollable-tab-view": "ecency/react-native-scrollable-tab-view",
"react-native-slider": "^0.11.0", "react-native-slider": "^0.11.0",
"react-native-snap-carousel": "^3.8.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-svg": "^12.1.1",
"react-native-swiper": "^1.6.0-rc.3", "react-native-swiper": "^1.6.0-rc.3",
"react-native-tcp": "^4.0.0", "react-native-tcp": "^4.0.0",

View File

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

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@ const CommentsTabContent = ({isOwnProfile, username, type, onScroll, selectedUse
const intl = useIntl(); 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 isAnalytics = useAppSelector(state => state.application.isAnalytics);
const [data, setData] = useState([]); const [data, setData] = useState([]);

View File

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

View File

@ -783,7 +783,9 @@
"line2_body":"Utilizing blockchain, censorship-free, decentralized and rewarding.", "line2_body":"Utilizing blockchain, censorship-free, decentralized and rewarding.",
"line3_heading":"Join Ecency communities!", "line3_heading":"Join Ecency communities!",
"line3_body":"Build community you own, get rewarded and reward others.", "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":{ "time":{
"second":"seconds", "second":"seconds",

View File

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

View File

@ -1,7 +1,6 @@
import getSymbolFromCurrency from 'currency-symbol-map'; import getSymbolFromCurrency from 'currency-symbol-map';
import { getCurrencyRate } from '../../providers/ecency/ecency'; import { getCurrencyRate } from '../../providers/ecency/ecency';
import { import {
ACTIVE_APPLICATION,
CHANGE_COMMENT_NOTIFICATION, CHANGE_COMMENT_NOTIFICATION,
CHANGE_FOLLOW_NOTIFICATION, CHANGE_FOLLOW_NOTIFICATION,
CHANGE_MENTION_NOTIFICATION, CHANGE_MENTION_NOTIFICATION,
@ -28,6 +27,11 @@ import {
SET_PIN_CODE, SET_PIN_CODE,
IS_PIN_CODE_OPEN, IS_PIN_CODE_OPEN,
IS_RENDER_REQUIRED, IS_RENDER_REQUIRED,
SET_LAST_APP_VERSION,
SET_COLOR_THEME,
SET_SETTINGS_MIGRATED,
HIDE_POSTS_THUMBNAILS,
SET_TERMS_ACCEPTED
} from '../constants/constants'; } from '../constants/constants';
export const login = (payload) => ({ export const login = (payload) => ({
@ -47,7 +51,7 @@ export const isLoginDone = () => ({
type: IS_LOGIN_DONE, type: IS_LOGIN_DONE,
}); });
export const openPinCodeModal = (payload) => ({ export const openPinCodeModal = (payload = null) => ({
payload, payload,
type: OPEN_PIN_CODE_MODAL, type: OPEN_PIN_CODE_MODAL,
}); });
@ -56,9 +60,6 @@ export const closePinCodeModal = () => ({
type: CLOSE_PIN_CODE_MODAL, type: CLOSE_PIN_CODE_MODAL,
}); });
export const activeApplication = () => ({
type: ACTIVE_APPLICATION,
});
// Settings actions // Settings actions
export const setLanguage = (payload) => ({ export const setLanguage = (payload) => ({
@ -135,6 +136,11 @@ export const isDarkTheme = (payload) => ({
type: IS_DARK_THEME, type: IS_DARK_THEME,
}); });
export const setColorTheme = (payload:number) => ({
payload,
type: SET_COLOR_THEME
})
export const isPinCodeOpen = (payload) => ({ export const isPinCodeOpen = (payload) => ({
payload, payload,
type: IS_PIN_CODE_OPEN, type: IS_PIN_CODE_OPEN,
@ -183,3 +189,24 @@ export const isRenderRequired = (payload) => ({
type: IS_RENDER_REQUIRED, 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 { import {
TOAST_NOTIFICATION, TOAST_NOTIFICATION,
UPDATE_ACTIVE_BOTTOM_TAB, UPDATE_ACTIVE_BOTTOM_TAB,
HIDE_POSTS_THUMBNAILS,
RC_OFFER, RC_OFFER,
TOGGLE_ACCOUNTS_BOTTOM_SHEET, TOGGLE_ACCOUNTS_BOTTOM_SHEET,
SHOW_ACTION_MODAL, SHOW_ACTION_MODAL,
@ -58,10 +56,6 @@ export const setRcOffer = (payload:boolean) => ({
type: RC_OFFER, type: RC_OFFER,
}); });
export const hidePostsThumbnails = (payload:boolean) => ({
payload,
type: HIDE_POSTS_THUMBNAILS,
});
export const toggleAccountsBottomSheet = (payload:boolean) => ({ export const toggleAccountsBottomSheet = (payload:boolean) => ({
payload, payload,

View File

@ -4,7 +4,6 @@ export const FETCH_USER_SUCCESS = 'FETCH_USER_SUCCESS';
export const SET_USER_DATA = 'SET_USER_DATA'; export const SET_USER_DATA = 'SET_USER_DATA';
// Applicaiton // Applicaiton
export const ACTIVE_APPLICATION = 'ACTIVE_APPLICATION';
export const CLOSE_PIN_CODE_MODAL = 'CLOSE_PIN_CODE_MODAL'; export const CLOSE_PIN_CODE_MODAL = 'CLOSE_PIN_CODE_MODAL';
export const IS_CONNECTED = 'IS_CONNECTED'; export const IS_CONNECTED = 'IS_CONNECTED';
export const IS_ANALYTICS = 'IS_ANALYTICS'; 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_REBLOG_NOTIFICATION = 'CHANGE_REBLOG_NOTIFICATION';
export const CHANGE_TRANSFERS_NOTIFICATION = 'CHANGE_TRANSFERS_NOTIFICATION'; export const CHANGE_TRANSFERS_NOTIFICATION = 'CHANGE_TRANSFERS_NOTIFICATION';
export const CHANGE_ALL_NOTIFICATION_SETTINGS = 'CHANGE_ALL_NOTIFICATION_SETTINGS'; 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 // Accounts
export const ADD_OTHER_ACCOUNT = 'ADD_OTHER_ACCOUNT'; export const ADD_OTHER_ACCOUNT = 'ADD_OTHER_ACCOUNT';

View File

@ -1,5 +1,4 @@
import { import {
ACTIVE_APPLICATION,
CHANGE_COMMENT_NOTIFICATION, CHANGE_COMMENT_NOTIFICATION,
CHANGE_FOLLOW_NOTIFICATION, CHANGE_FOLLOW_NOTIFICATION,
CHANGE_MENTION_NOTIFICATION, CHANGE_MENTION_NOTIFICATION,
@ -26,19 +25,63 @@ import {
SET_PIN_CODE, SET_PIN_CODE,
IS_PIN_CODE_OPEN, IS_PIN_CODE_OPEN,
IS_RENDER_REQUIRED, IS_RENDER_REQUIRED,
SET_LAST_APP_VERSION,
SET_COLOR_THEME,
SET_SETTINGS_MIGRATED,
HIDE_POSTS_THUMBNAILS,
SET_TERMS_ACCEPTED,
} from '../constants/constants'; } 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', api: 'rpc.ecency.com',
currency: { currency: {
currency: 'usd', currency: 'usd',
currencyRate: 1, currencyRate: 1,
currencySymbol: '$', currencySymbol: '$',
}, },
isActive: false,
isConnected: null, // internet connectivity isConnected: null, // internet connectivity
isDarkTheme: false, 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. isLoggedIn: false, // Has any logged in user.
isAnalytics: false, isAnalytics: false,
isLoginDone: false, isLoginDone: false,
@ -61,7 +104,10 @@ const initialState = {
pin: null, pin: null,
isPinCodeOpen: true, isPinCodeOpen: true,
isRenderRequired: false, isRenderRequired: false,
lastAppVersion:'',
settingsMigrated: false,
hidePostsThumbnails: false,
isTermsAccepted: false,
}; };
export default function (state = initialState, action) { export default function (state = initialState, action) {
@ -107,11 +153,6 @@ export default function (state = initialState, action) {
...state, ...state,
isPinCodeRequire: false, isPinCodeRequire: false,
}; };
case ACTIVE_APPLICATION:
return {
...state,
isActive: true,
};
case SET_API: case SET_API:
return Object.assign({}, state, { return Object.assign({}, state, {
api: action.payload, api: action.payload,
@ -187,6 +228,11 @@ export default function (state = initialState, action) {
return Object.assign({}, state, { return Object.assign({}, state, {
isDarkTheme: action.payload, isDarkTheme: action.payload,
}); });
case SET_COLOR_THEME:
return {
...state,
colorTheme:action.payload
};
case IS_PIN_CODE_OPEN: case IS_PIN_CODE_OPEN:
return Object.assign({}, state, { return Object.assign({}, state, {
isPinCodeOpen: action.payload, isPinCodeOpen: action.payload,
@ -213,6 +259,30 @@ export default function (state = initialState, action) {
isRenderRequired: action.payload, 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: default:
return state; return state;
} }

View File

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

View File

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

View File

@ -1,10 +1,9 @@
import React, { Component, Fragment } from 'react'; 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 EStyleSheet from 'react-native-extended-stylesheet';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createAppContainer } from 'react-navigation'; import { createAppContainer } from 'react-navigation';
import { injectIntl } from 'react-intl'; import { injectIntl } from 'react-intl';
import VersionNumber from 'react-native-version-number';
import AppNavitation from '../../../navigation/routes'; import AppNavitation from '../../../navigation/routes';
import { setTopLevelNavigator, navigate } from '../../../navigation/service'; import { setTopLevelNavigator, navigate } from '../../../navigation/service';
@ -14,7 +13,6 @@ import {
toastNotification as toastNotificationAction, toastNotification as toastNotificationAction,
setRcOffer, setRcOffer,
} from '../../../redux/actions/uiAction'; } from '../../../redux/actions/uiAction';
import { getVersionForWelcomeModal } from '../../../realm/realm';
import ROUTES from '../../../constants/routeNames'; import ROUTES from '../../../constants/routeNames';
@ -32,7 +30,6 @@ import {
// Themes (Styles) // Themes (Styles)
import darkTheme from '../../../themes/darkTheme'; import darkTheme from '../../../themes/darkTheme';
import lightTheme from '../../../themes/lightTheme'; import lightTheme from '../../../themes/lightTheme';
import parseVersionNumber from '../../../utils/parseVersionNumber';
const Navigation = createAppContainer(AppNavitation); const Navigation = createAppContainer(AppNavitation);
@ -41,24 +38,14 @@ class ApplicationScreen extends Component {
super(props); super(props);
this.state = { this.state = {
isShowToastNotification: false, isShowToastNotification: false,
showWelcomeModal: false,
}; };
} }
componentDidMount() {
const { appVersion } = VersionNumber;
getVersionForWelcomeModal().then((version) => {
if (version < parseVersionNumber(appVersion)) {
this.setState({ showWelcomeModal: true });
}
});
}
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { rcOffer, dispatch, intl } = this.props; const { rcOffer, dispatch, intl } = this.props;
const { rcOffer: rcOfferPrev } = prevProps; const { rcOffer: rcOfferPrev } = prevProps;
//TODO: display action modal instead
if (!rcOfferPrev && rcOffer) { if (!rcOfferPrev && rcOffer) {
setTimeout(() => { setTimeout(() => {
Alert.alert( Alert.alert(
@ -109,25 +96,19 @@ class ApplicationScreen extends Component {
} }
render() { render() {
const { const { isConnected, isDarkTheme, toastNotification, foregroundNotificationData } = this.props;
isConnected, const { isShowToastNotification } = this.state;
isDarkTheme,
toastNotification,
isReady,
foregroundNotificationData,
navigation,
} = this.props;
const { isShowToastNotification, showWelcomeModal } = this.state;
const barStyle = isDarkTheme ? 'light-content' : 'dark-content'; const barStyle = isDarkTheme ? 'light-content' : 'dark-content';
const barColor = isDarkTheme ? '#1e2835' : '#fff'; const barColor = isDarkTheme ? '#1e2835' : '#fff';
return ( return (
<View pointerEvents={isReady ? 'auto' : 'none'} style={{ flex: 1 }}> <View style={{ flex: 1 }}>
{Platform.os === 'ios' ? ( {Platform.os === 'ios' ? (
<StatusBar barStyle={barStyle} /> <StatusBar barStyle={barStyle} />
) : ( ) : (
<StatusBar barStyle={barStyle} backgroundColor={barColor} /> <StatusBar barStyle={barStyle} backgroundColor={barColor} />
)} )}
<Fragment> <Fragment>
{!isConnected && <NoInternetConnection />} {!isConnected && <NoInternetConnection />}
<Navigation <Navigation
@ -135,32 +116,6 @@ class ApplicationScreen extends Component {
setTopLevelNavigator(navigatorRef); 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> </Fragment>
{isShowToastNotification && ( {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, paddingBottom: 20,
paddingHorizontal: 40, paddingHorizontal: 40,
}, },
contentContainer: {
flexGrow: 1,
justifyContent: 'center',
},
welcomeText: { welcomeText: {
fontSize: scalePx(34), fontSize: scalePx(34),
color: '$primaryBlack', color: '$primaryBlack',
@ -47,8 +52,10 @@ export default EStyleSheet.create({
topText: { topText: {
marginTop: 40, marginTop: 40,
}, },
bottomButton: { bottomContainer: {
paddingTop: 10, marginTop: 8,
borderTopWidth: EStyleSheet.hairlineWidth,
borderColor: '$iconColor',
}, },
sectionRow: { sectionRow: {
flexDirection: 'row', flexDirection: 'row',
@ -69,4 +76,28 @@ export default EStyleSheet.create({
flex1: { flex1: {
flex: 1, 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 { bindActionCreators } from 'redux';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
import { isEmpty, some } from 'lodash'; import { isEmpty, some } from 'lodash';
import { useDarkMode } from 'react-native-dynamic';
import messaging from '@react-native-firebase/messaging'; import messaging from '@react-native-firebase/messaging';
import PushNotification from 'react-native-push-notification'; import PushNotification from 'react-native-push-notification';
import VersionNumber from 'react-native-version-number'; import VersionNumber from 'react-native-version-number';
import ReceiveSharingIntent from 'react-native-receive-sharing-intent'; import ReceiveSharingIntent from 'react-native-receive-sharing-intent';
import Matomo from 'react-native-matomo-sdk'; import Matomo from 'react-native-matomo-sdk';
import SplashScreen from 'react-native-splash-screen'
// Constants // Constants
import AUTH_TYPE from '../../../constants/authType'; import AUTH_TYPE from '../../../constants/authType';
@ -25,8 +25,6 @@ import postUrlParser from '../../../utils/postUrlParser';
// Services // Services
import { import {
getAuthStatus, getAuthStatus,
getExistUser,
getSettings,
getUserData, getUserData,
removeUserData, removeUserData,
getUserDataWithUsername, getUserDataWithUsername,
@ -34,8 +32,6 @@ import {
setAuthStatus, setAuthStatus,
removeSCAccount, removeSCAccount,
setExistUser, setExistUser,
getVersionForWelcomeModal,
setVersionForWelcomeModal,
getLastUpdateCheck, getLastUpdateCheck,
setLastUpdateCheck, setLastUpdateCheck,
getTheme, getTheme,
@ -49,10 +45,8 @@ import {
} from '../../../providers/hive/auth'; } from '../../../providers/hive/auth';
import { import {
setPushToken, setPushToken,
markActivityAsRead,
markNotifications, markNotifications,
getUnreadNotificationCount, getUnreadNotificationCount,
getLatestQuotes,
} from '../../../providers/ecency/ecency'; } from '../../../providers/ecency/ecency';
import { fetchLatestAppVersion } from '../../../providers/github/github'; import { fetchLatestAppVersion } from '../../../providers/github/github';
import { navigate } from '../../../navigation/service'; import { navigate } from '../../../navigation/service';
@ -64,34 +58,20 @@ import {
updateUnreadActivityCount, updateUnreadActivityCount,
removeOtherAccount, removeOtherAccount,
fetchGlobalProperties, fetchGlobalProperties,
removeAllOtherAccount,
} from '../../../redux/actions/accountAction'; } from '../../../redux/actions/accountAction';
import { import {
activeApplication,
isDarkTheme, isDarkTheme,
changeNotificationSettings,
changeAllNotificationSettings,
login, login,
logoutDone, logoutDone,
openPinCodeModal, openPinCodeModal,
setApi,
setConnectivityStatus, setConnectivityStatus,
setAnalyticsStatus, setAnalyticsStatus,
setCurrency,
setLanguage,
setUpvotePercent,
setNsfw,
isDefaultFooter,
isPinCodeOpen,
setPinCode as savePinCode, setPinCode as savePinCode,
isRenderRequired, isRenderRequired,
logout, logout,
} from '../../../redux/actions/applicationActions'; } from '../../../redux/actions/applicationActions';
import { import {
hideActionModal,
hideProfileModal,
setAvatarCacheStamp, setAvatarCacheStamp,
setRcOffer,
showActionModal, showActionModal,
toastNotification, toastNotification,
updateActiveBottomTab, updateActiveBottomTab,
@ -105,10 +85,11 @@ import darkTheme from '../../../themes/darkTheme';
import lightTheme from '../../../themes/lightTheme'; import lightTheme from '../../../themes/lightTheme';
import persistAccountGenerator from '../../../utils/persistAccountGenerator'; import persistAccountGenerator from '../../../utils/persistAccountGenerator';
import parseVersionNumber from '../../../utils/parseVersionNumber'; import parseVersionNumber from '../../../utils/parseVersionNumber';
import { getTimeFromNow, setMomentLocale } from '../../../utils/time'; import { setMomentLocale } from '../../../utils/time';
import parseAuthUrl from '../../../utils/parseAuthUrl'; import parseAuthUrl from '../../../utils/parseAuthUrl';
import { purgeExpiredCache } from '../../../redux/actions/cacheActions'; import { purgeExpiredCache } from '../../../redux/actions/cacheActions';
import { fetchSubscribedCommunities } from '../../../redux/actions/communitiesAction'; import { fetchSubscribedCommunities } from '../../../redux/actions/communitiesAction';
import MigrationHelpers from '../children/migrationHelpers';
// Workaround // Workaround
let previousAppState = 'background'; let previousAppState = 'background';
@ -123,25 +104,20 @@ export const setPreviousAppState = () => {
let firebaseOnNotificationOpenedAppListener = null; let firebaseOnNotificationOpenedAppListener = null;
let firebaseOnMessageListener = null; let firebaseOnMessageListener = null;
let removeAppearanceListener = null; let removeAppearanceListener = null;
let scAccounts = [];
class ApplicationContainer extends Component { class ApplicationContainer extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
isRenderRequire: true, isRenderRequire: true,
isReady: false,
isIos: Platform.OS !== 'android', isIos: Platform.OS !== 'android',
isThemeReady: false,
appState: AppState.currentState, appState: AppState.currentState,
showWelcomeModal: false,
foregroundNotificationData: null, foregroundNotificationData: null,
}; };
} }
componentDidMount = () => { componentDidMount = () => {
const { isIos } = this.state; const { isIos } = this.state;
const { appVersion } = VersionNumber;
const { dispatch, isAnalytics } = this.props; const { dispatch, isAnalytics } = this.props;
this._setNetworkListener(); this._setNetworkListener();
@ -163,22 +139,9 @@ class ApplicationContainer extends Component {
//set avatar cache stamp to invalidate previous session avatars //set avatar cache stamp to invalidate previous session avatars
dispatch(setAvatarCacheStamp(new Date().getTime())); dispatch(setAvatarCacheStamp(new Date().getTime()));
getVersionForWelcomeModal().then((version) => { SplashScreen.hide();
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);
}
});
}
});
}
});
setMomentLocale(); setMomentLocale();
this._fetchApp();
ReceiveSharingIntent.getReceivedFiles( ReceiveSharingIntent.getReceivedFiles(
() => { () => {
@ -235,7 +198,7 @@ class ApplicationContainer extends Component {
if (!isIos) BackHandler.removeEventListener('hardwareBackPress', this._onBackPress); 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); Linking.removeEventListener('url', this._handleOpenURL);
@ -439,22 +402,10 @@ class ApplicationContainer extends Component {
); );
}; };
_handleAppStateChange = (nextAppState) => { _handleAppStateChange = (nextAppState) => {
const { appState } = this.state; 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') { if (appState.match(/inactive|background/) && nextAppState === 'active') {
this._refreshGlobalProps(); 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 () => { _fetchApp = async () => {
await this._getSettings(); const {dispatch, settingsMigrated} = this.props;
this.setState({
isReady: true, await MigrationHelpers.migrateSettings(dispatch, settingsMigrated)
});
this._refreshGlobalProps(); this._refreshGlobalProps();
await this._getUserDataFromRealm(); await this._getUserDataFromRealm();
this._compareAndPromptForUpdate(); this._compareAndPromptForUpdate();
this._registerDeviceForNotifications();
dispatch(purgeExpiredCache());
}; };
_pushNavigate = (notification) => { _pushNavigate = (notification) => {
@ -647,7 +590,6 @@ class ApplicationContainer extends Component {
const { currentUsername } = res; const { currentUsername } = res;
if (res) { if (res) {
dispatch(activeApplication());
dispatch(login(true)); dispatch(login(true));
const userData = await getUserData(); const userData = await getUserData();
@ -696,11 +638,11 @@ class ApplicationContainer extends Component {
// TODO: // TODO:
await switchAccount(realmObject[0].username); await switchAccount(realmObject[0].username);
} }
const isExistUser = await getExistUser();
realmObject[0].name = currentUsername; realmObject[0].name = currentUsername;
// If in dev mode pin code does not show // If in dev mode pin code does not show
if ((!isExistUser || !pinCode) && _isPinCodeOpen) { if (_isPinCodeOpen) {
dispatch(openPinCodeModal()); dispatch(openPinCodeModal());
} else if (!_isPinCodeOpen) { } else if (!_isPinCodeOpen) {
const encryptedPin = encryptKey(Config.DEFAULT_PIN, Config.PIN_KEY); const encryptedPin = encryptKey(Config.DEFAULT_PIN, Config.PIN_KEY);
@ -709,13 +651,13 @@ class ApplicationContainer extends Component {
if (isConnected) { if (isConnected) {
this._fetchUserDataFromDsteem(realmObject[0]); this._fetchUserDataFromDsteem(realmObject[0]);
} }
return realmObject[0]; return realmObject[0];
} }
dispatch(updateCurrentAccount({})); dispatch(updateCurrentAccount({}));
dispatch(activeApplication());
return null; return null;
}; };
@ -788,6 +730,7 @@ class ApplicationContainer extends Component {
dispatch(updateCurrentAccount(accountData)); dispatch(updateCurrentAccount(accountData));
dispatch(fetchSubscribedCommunities(realmObject.username)); dispatch(fetchSubscribedCommunities(realmObject.username));
this._connectNotificationServer(accountData.name); this._connectNotificationServer(accountData.name);
//TODO: better update device push token here after access token refresh
} catch (err) { } catch (err) {
Alert.alert( Alert.alert(
`${intl.formatMessage({ id: 'alert.fetch_error' })} \n${err.message.substr(0, 20)}`, `${intl.formatMessage({ id: 'alert.fetch_error' })} \n${err.message.substr(0, 20)}`,
@ -795,46 +738,20 @@ 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;
if (settings) { const isEnabled = settings ? !!settings.notification : isNotificationsEnabled;
const isDarkMode = Appearance.getColorScheme() === 'dark'; settings = settings || notificationDetails;
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)));
}
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; //updateing fcm token with settings;
otherAccounts.forEach((account) => { otherAccounts.forEach((account) => {
//since there can be more than one accounts, process access tokens separate //since there can be more than one accounts, process access tokens separate
const encAccessToken = account.local.accessToken; const encAccessToken = account?.local?.accessToken;
//decrypt access token //decrypt access token
let accessToken = null; let accessToken = null;
if (encAccessToken) { if (encAccessToken) {
@ -843,15 +760,12 @@ class ApplicationContainer extends Component {
accessToken = decryptKey(encAccessToken, Config.DEFAULT_PIN); accessToken = decryptKey(encAccessToken, Config.DEFAULT_PIN);
} }
this._enableNotification(account.name, settings.notification, settings, accessToken); this._enableNotification(account.name, isEnabled, settings, accessToken);
}); });
}
if (settings.nsfw !== '') dispatch(setNsfw(settings.nsfw));
await dispatch(setCurrency(settings.currency !== '' ? settings.currency : 'usd'));
}
}; };
_connectNotificationServer = (username) => { _connectNotificationServer = (username) => {
/* eslint no-undef: "warn" */ /* eslint no-undef: "warn" */
const ws = new WebSocket(`${Config.ACTIVITY_WEBSOCKET_URL}?user=${username}`); const ws = new WebSocket(`${Config.ACTIVITY_WEBSOCKET_URL}?user=${username}`);
@ -988,13 +902,6 @@ class ApplicationContainer extends Component {
dispatch(fetchSubscribedCommunities(_currentAccount.username)); dispatch(fetchSubscribedCommunities(_currentAccount.username));
}; };
_handleWelcomeModalButtonPress = () => {
const { appVersion } = VersionNumber;
setVersionForWelcomeModal(appVersion);
this.setState({ showWelcomeModal: false });
};
UNSAFE_componentWillReceiveProps(nextProps) { UNSAFE_componentWillReceiveProps(nextProps) {
const { const {
@ -1050,13 +957,7 @@ class ApplicationContainer extends Component {
isPinCodeRequire, isPinCodeRequire,
rcOffer, rcOffer,
} = this.props; } = this.props;
const { const { isRenderRequire, foregroundNotificationData } = this.state;
isRenderRequire,
isReady,
isThemeReady,
showWelcomeModal,
foregroundNotificationData,
} = this.state;
return ( return (
children && children &&
@ -1064,15 +965,11 @@ class ApplicationContainer extends Component {
isConnected, isConnected,
isDarkTheme: _isDarkTheme, isDarkTheme: _isDarkTheme,
isPinCodeRequire, isPinCodeRequire,
isReady,
isRenderRequire, isRenderRequire,
isThemeReady,
locale: selectedLanguage, locale: selectedLanguage,
rcOffer, rcOffer,
toastNotification, toastNotification,
showWelcomeModal,
foregroundNotificationData, foregroundNotificationData,
handleWelcomeModalButtonPress: this._handleWelcomeModalButtonPress,
}) })
); );
} }
@ -1085,15 +982,17 @@ export default connect(
selectedLanguage: state.application.language, selectedLanguage: state.application.language,
isPinCodeOpen: state.application.isPinCodeOpen, isPinCodeOpen: state.application.isPinCodeOpen,
isLogingOut: state.application.isLogingOut, 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, isConnected: state.application.isConnected,
nav: state.nav.routes, nav: state.nav.routes,
isPinCodeRequire: state.application.isPinCodeRequire, isPinCodeRequire: state.application.isPinCodeRequire,
isActiveApp: state.application.isActive,
api: state.application.api, api: state.application.api,
isGlobalRenderRequired: state.application.isRenderRequired, isGlobalRenderRequired: state.application.isRenderRequired,
isAnalytics: state.application.isAnalytics, isAnalytics: state.application.isAnalytics,
lastUpdateCheck: state.application.lastUpdateCheck, lastUpdateCheck: state.application.lastUpdateCheck,
settingsMigrated: state.application.settingsMigrated,
isNotificationsEnabled: state.application.isNotificationOpen,
notificationDetails: state.application.notificationDetails,
// Account // Account
unreadActivityCount: state.account.currentAccount.unread_activity_count, 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 React, { Fragment, useState, useEffect } from 'react';
import { SafeAreaView } from 'react-native'; import { ActivityIndicator, SafeAreaView } from 'react-native';
import { useSelector } from 'react-redux';
import get from 'lodash/get'; import get from 'lodash/get';
// Components // Components
import { Posts, Header, TabbedPosts } from '../../../components'; import { Header, TabbedPosts } from '../../../components';
// Container // Container
import { AccountContainer } from '../../../containers'; import { AccountContainer } from '../../../containers';
@ -23,12 +22,24 @@ const FeedScreen = () => {
const mainTabs = useAppSelector((state) => state.customTabs.mainTabs || getDefaultFilters('main')); const mainTabs = useAppSelector((state) => state.customTabs.mainTabs || getDefaultFilters('main'));
const filterOptions = mainTabs.map((key) => getFilterMap('main')[key]); const filterOptions = mainTabs.map((key) => getFilterMap('main')[key]);
const [lazyLoad, setLazyLoad] = useState(false);
const _lazyLoadContent = () => {
if(!lazyLoad){
setTimeout(() => {
setLazyLoad(true);
}, 100)
}
}
return ( return (
<AccountContainer> <AccountContainer>
{({ currentAccount }) => ( {({ currentAccount }) => (
<Fragment> <Fragment>
<Header enableViewModeToggle={true} /> <Header enableViewModeToggle={true} />
<SafeAreaView style={styles.container}> <SafeAreaView style={styles.container} onLayout={_lazyLoadContent}>
{lazyLoad && (
<TabbedPosts <TabbedPosts
key={JSON.stringify(filterOptions)} //this hack of key change resets tabbedposts whenever filters chanage, effective to remove filter change android bug key={JSON.stringify(filterOptions)} //this hack of key change resets tabbedposts whenever filters chanage, effective to remove filter change android bug
filterOptions={filterOptions} filterOptions={filterOptions}
@ -39,6 +50,9 @@ const FeedScreen = () => {
isFeedScreen={true} isFeedScreen={true}
pageType='main' pageType='main'
/> />
)}
</SafeAreaView> </SafeAreaView>
</Fragment> </Fragment>
)} )}

View File

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

View File

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

View File

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

View File

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