diff --git a/app/package-lock.json b/app/package-lock.json index b291047e..8b048b37 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -2509,9 +2509,9 @@ } }, "create-react-context": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.3.tgz", - "integrity": "sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.2.tgz", + "integrity": "sha512-KkpaLARMhsTsgp0d2NA/R94F/eDLbhXERdIq3LvX2biCAXcDvHYoOqHfWCHf1+OLj+HKBotLG3KqaOOf+C1C+A==", "requires": { "fbjs": "^0.8.0", "gud": "^1.0.0" @@ -5161,9 +5161,9 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "query-string": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.1.0.tgz", - "integrity": "sha512-pNB/Gr8SA8ff8KpUFM36o/WFAlthgaThka5bV19AD9PNTH20Pwq5Zxodif2YyHwrctp6SkL4GqlOot0qR/wGaw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.2.0.tgz", + "integrity": "sha512-5wupExkIt8RYL4h/FE+WTg3JHk62e6fFPWtAZA9J5IWK1PfTfKkMS93HBUHcFpeYi9KsY5pFbh+ldvEyaz5MyA==", "requires": { "decode-uri-component": "^0.2.0", "strict-uri-encode": "^2.0.0" @@ -5247,6 +5247,11 @@ } } }, + "react-is": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.7.0.tgz", + "integrity": "sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g==" + }, "react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", @@ -5441,13 +5446,18 @@ } }, "react-native-safe-area-view": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/react-native-safe-area-view/-/react-native-safe-area-view-0.9.0.tgz", - "integrity": "sha512-y792ScHMzvgwquxL869S9CER4dwiFu/TuCiXdy0xBtygmScMK4eWonnUT65LvOrsSSdr8o6XEK1mbI51h6ozvQ==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-native-safe-area-view/-/react-native-safe-area-view-0.11.0.tgz", + "integrity": "sha512-N3nElaahu1Me2ltnfc9acpgt1znm6pi8DSadKy79kvdzKwvVIzw0IXueA/Hjr51eCW1BsfNw7D1SgBT9U6qEkA==", "requires": { "hoist-non-react-statics": "^2.3.1" } }, + "react-native-screens": { + "version": "1.0.0-alpha.22", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-1.0.0-alpha.22.tgz", + "integrity": "sha512-kSyAt0AeVU6N7ZonfV6dP6iZF8B7Bce+tk3eujXhzBGsLg0VSLnU7uE9VqJF0xdQrHR91ZjGgVMieo/8df9KTA==" + }, "react-native-tab-view": { "version": "0.0.77", "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz", @@ -5504,21 +5514,23 @@ } }, "react-navigation": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/react-navigation/-/react-navigation-2.12.1.tgz", - "integrity": "sha512-C+do+STPvvd/5LbaDhrZyf1P8tCeffttdlHyIRe1NgGg8Nj93FZHWOThi2hnmEZ75kXsS/JGxox4DDPqYVAxeQ==", + "version": "2.18.3", + "resolved": "https://registry.npmjs.org/react-navigation/-/react-navigation-2.18.3.tgz", + "integrity": "sha512-/5KGMG1Oj5LN/x/7AKF0MWrpX9Qe29307RxEsMCiRT/A4jCYT0DPY99Bl7ZAGtROxExEy3rwTfTrtvpIT+CU7A==", "requires": { "clamp": "^1.0.1", - "create-react-context": "^0.2.1", + "create-react-context": "0.2.2", "hoist-non-react-statics": "^2.2.0", "path-to-regexp": "^1.7.0", "query-string": "^6.1.0", + "react-is": "^16.5.2", "react-lifecycles-compat": "^3", - "react-native-safe-area-view": "^0.9.0", + "react-native-safe-area-view": "0.11.0", + "react-native-screens": "^1.0.0-alpha.11", "react-navigation-deprecated-tab-navigator": "1.3.0", "react-navigation-drawer": "0.5.0", - "react-navigation-stack": "0.2.3", - "react-navigation-tabs": "0.6.0" + "react-navigation-stack": "0.7.0", + "react-navigation-tabs": "0.8.4" } }, "react-navigation-deprecated-tab-navigator": { @@ -5538,42 +5550,33 @@ } }, "react-navigation-redux-helpers": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/react-navigation-redux-helpers/-/react-navigation-redux-helpers-2.0.5.tgz", - "integrity": "sha512-oxDpPqmXdzUJJ32ef8NY6Cu9XDJNO4DU91p0+ZgleEfaZwec9t2ua6sKwQyOfdWQPDwbJAxiXfZIAe3ao5MG6Q==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/react-navigation-redux-helpers/-/react-navigation-redux-helpers-2.0.9.tgz", + "integrity": "sha512-V1eyQ22T1znZeaou38f/JBp5DUV5X2T4hVVSlsjh8dk2unkWhaugzvrgFMF80Mzg1gH4rVE1yADyI9hzuwbbSw==", "requires": { "invariant": "^2.2.2" } }, "react-navigation-stack": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/react-navigation-stack/-/react-navigation-stack-0.2.3.tgz", - "integrity": "sha512-xjVqiI/ztcQt45jxQ3vfO8Lr+9bVq+0J/lRhMdZCvCDwiyOVuB64wx7qPNJW16pnBBLiI5h6H7uhWE3rAT0r/w==" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/react-navigation-stack/-/react-navigation-stack-0.7.0.tgz", + "integrity": "sha512-3Tbb/SsustBrM9R/qaI6XuOfyqYMVbwkeHFC8NbU890vB0aKZvjAtioWLZ18e/4LgbiOCmoTdp37z3gkGDyNDQ==" }, "react-navigation-tabs": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/react-navigation-tabs/-/react-navigation-tabs-0.6.0.tgz", - "integrity": "sha512-Ax1rujJ51R1Jrz7b5bHUAIgsYC1VrFws+d3hxlPy5dXG84iJdV5dnDFRvdQMDDfDZc+NDx2a223lAYsc3p2+XA==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/react-navigation-tabs/-/react-navigation-tabs-0.8.4.tgz", + "integrity": "sha512-CbS3xIVJVtpu+AYslv0PMLmjddJFVtU3XAhSJ9XnMrKLUJNmnQdW/L0w/Gp5qcBEF9h6bgsY3CoTtp7I6bqyOQ==", "requires": { "hoist-non-react-statics": "^2.5.0", "prop-types": "^15.6.1", "react-lifecycles-compat": "^3.0.4", - "react-native-safe-area-view": "^0.7.0", "react-native-tab-view": "^1.0.0" }, "dependencies": { - "react-native-safe-area-view": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/react-native-safe-area-view/-/react-native-safe-area-view-0.7.0.tgz", - "integrity": "sha512-SjLdW/Th0WVMhyngH4O6yC21S+O4U4AAG3QxBr7fZ2ftgjXSpKbDHAhEpxBdFwei6HsnsC2h9oYMtPpaW9nfGg==", - "requires": { - "hoist-non-react-statics": "^2.3.1" - } - }, "react-native-tab-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-1.0.2.tgz", - "integrity": "sha512-x8I43V1X7/AyMnIwnqJGMU54LqQRlV6vJ9irbls9asA/axdHIdxagPIV6Jx1ttFe/bPKhFwXL+lRYdYxGyUlWg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-1.3.1.tgz", + "integrity": "sha512-QNt6VkEW8SP1UJ7yjD5P4bOTWwHQfoIMD5CqnA06pcubdNwHR1NmjiNZsVnIvp5wAEVbW6yTHjLXOh1fzab4xg==", "requires": { "prop-types": "^15.6.1" } diff --git a/app/package.json b/app/package.json index 44ca8c69..54d7a117 100644 --- a/app/package.json +++ b/app/package.json @@ -21,8 +21,8 @@ "react-native-phone-input": "lbryio/react-native-phone-input", "react-native-vector-icons": "^5.0.0", "react-native-video": "lbryio/react-native-video#exoplayer-lbry-android", - "react-navigation": "^2.12.1", - "react-navigation-redux-helpers": "^2.0.5", + "react-navigation": "^2.18.3", + "react-navigation-redux-helpers": "^2.0.9", "react-redux": "^5.0.3", "redux": "^3.6.0", "redux-logger": "3.0.6", diff --git a/app/src/component/AppNavigator.js b/app/src/component/AppNavigator.js index a5e6b99f..6f0fa8a4 100644 --- a/app/src/component/AppNavigator.js +++ b/app/src/component/AppNavigator.js @@ -33,7 +33,9 @@ import { TextInput, ToastAndroid } from 'react-native'; -import { doDeleteCompleteBlobs } from '../redux/actions/file'; +import { doPopDrawerStack } from 'redux/actions/drawer'; +import { doDeleteCompleteBlobs } from 'redux/actions/file'; +import { selectDrawerStack } from 'redux/selectors/drawer'; import { SETTINGS, doDismissToast, doToast, selectToast } from 'lbry-redux'; import { doUserEmailVerify, @@ -43,16 +45,16 @@ import { selectEmailVerifyErrorMessage, selectUser } from 'lbryinc'; -import { makeSelectClientSetting } from '../redux/selectors/settings'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; import { decode as atob } from 'base-64'; -import { dispatchNavigateToUri } from '../utils/helper'; -import Colors from '../styles/colors'; -import Constants from '../constants'; +import { dispatchNavigateBack, dispatchNavigateToUri } from 'utils/helper'; +import Colors from 'styles/colors'; +import Constants from 'constants'; import Icon from 'react-native-vector-icons/FontAwesome5'; -import NavigationButton from '../component/navigationButton'; -import discoverStyle from '../styles/discover'; -import searchStyle from '../styles/search'; -import SearchRightHeaderIcon from '../component/searchRightHeaderIcon'; +import NavigationButton from 'component/navigationButton'; +import discoverStyle from 'styles/discover'; +import searchStyle from 'styles/search'; +import SearchRightHeaderIcon from 'component/searchRightHeaderIcon'; const menuNavigationButton = (navigation) => ({ + header: null + }) }, Search: { screen: SearchPage, navigationOptions: ({ navigation }) => ({ - drawerLockMode: 'locked-closed', headerTitleStyle: discoverStyle.titleText }) } @@ -88,6 +88,17 @@ const discoverStack = createStackNavigator({ headerMode: 'screen' }); +discoverStack.navigationOptions = ({ navigation }) => { + let drawerLockMode = 'unlocked'; + if (navigation.state.index > 0) { + drawerLockMode = 'locked-closed'; + } + + return { + drawerLockMode + }; +}; + const trendingStack = createStackNavigator({ Trending: { screen: TrendingPage, @@ -232,7 +243,7 @@ class AppWithNavigationState extends React.Component { componentWillMount() { AppState.addEventListener('change', this._handleAppStateChange); BackHandler.addEventListener('hardwareBackPress', function() { - const { dispatch, nav } = this.props; + const { dispatch, nav, drawerStack, popDrawerStack } = this.props; // There should be a better way to check this if (nav.routes.length > 0) { if (nav.routes[0].routeName === 'Main') { @@ -241,7 +252,7 @@ class AppWithNavigationState extends React.Component { mainRoute.routes[0].index > 0 /* Discover stack index */ || mainRoute.routes[4].index > 0 /* Wallet stack index */ || mainRoute.index >= 5 /* Settings and About screens */) { - dispatch(NavigationActions.back()); + dispatchNavigateBack(dispatch, nav, drawerStack, doPopDrawerStack); return true; } } @@ -374,6 +385,7 @@ const mapStateToProps = state => ({ keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state), nav: state.nav, toast: selectToast(state), + drawerStack: selectDrawerStack(state), emailToVerify: selectEmailToVerify(state), emailVerifyPending: selectEmailVerifyIsPending(state), emailVerifyErrorMessage: selectEmailVerifyErrorMessage(state), diff --git a/app/src/constants.js b/app/src/constants.js index 47645200..a4298d5a 100644 --- a/app/src/constants.js +++ b/app/src/constants.js @@ -7,10 +7,33 @@ const Constants = { ACTION_DELETE_COMPLETED_BLOBS: "DELETE_COMPLETED_BLOBS", ACTION_FIRST_RUN_PAGE_CHANGED: "FIRST_RUN_PAGE_CHANGED", - PAGE_REWARDS: 'rewards', - PAGE_SETTINGS: 'settings', - PAGE_TRENDING: 'trending', - PAGE_WALLET: 'wallet' + ACTION_PUSH_DRAWER_STACK: "PUSH_DRAWER_STACK", + ACTION_POP_DRAWER_STACK: "POP_DRAWER_STACK", + + PAGE_REWARDS: "rewards", + PAGE_SETTINGS: "settings", + PAGE_TRENDING: "trending", + PAGE_WALLET: "wallet", + + DRAWER_ROUTE_DISCOVER: "Discover", + DRAWER_ROUTE_TRENDING: "Trending", + DRAWER_ROUTE_SUBSCRIPTIONS: "Subscriptions", + DRAWER_ROUTE_MY_LBRY: "Downloads", + DRAWER_ROUTE_REWARDS: "Rewards", + DRAWER_ROUTE_WALLET: "Wallet", + DRAWER_ROUTE_SETTINGS: "Settings", + DRAWER_ROUTE_ABOUT: "About" }; export default Constants; + +export const DrawerRoutes = [ + Constants.DRAWER_ROUTE_DISCOVER, + Constants.DRAWER_ROUTE_TRENDING, + Constants.DRAWER_ROUTE_SUBSCRIPTIONS, + Constants.DRAWER_ROUTE_MY_LBRY, + Constants.DRAWER_ROUTE_REWARDS, + Constants.DRAWER_ROUTE_WALLET, + Constants.DRAWER_ROUTE_SETTINGS, + Constants.DRAWER_ROUTE_ABOUT +]; diff --git a/app/src/index.js b/app/src/index.js index 6dd4770d..94484b1a 100644 --- a/app/src/index.js +++ b/app/src/index.js @@ -22,14 +22,15 @@ import { import { authReducer, rewardsReducer, subscriptionsReducer, userReducer } from 'lbryinc'; import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; import { createLogger } from 'redux-logger'; -import { AppNavigator } from './component/AppNavigator'; +import { AppNavigator } from 'component/AppNavigator'; import { persistStore, autoRehydrate } from 'redux-persist'; import AppWithNavigationState, { reactNavigationMiddleware } from './component/AppNavigator'; import FilesystemStorage from 'redux-persist-filesystem-storage'; import createCompressor from 'redux-persist-transform-compress'; import createFilter from 'redux-persist-transform-filter'; import moment from 'moment'; -import settingsReducer from './redux/reducers/settings'; +import drawerReducer from 'redux/reducers/drawer'; +import settingsReducer from 'redux/reducers/settings'; import thunk from 'redux-thunk'; const globalExceptionHandler = (error, isFatal) => { @@ -81,6 +82,7 @@ const reducers = combineReducers({ blacklist: blacklistReducer, claims: claimsReducer, costInfo: costInfoReducer, + drawer: drawerReducer, fileInfo: fileInfoReducer, nav: navigatorReducer, notifications: notificationsReducer, diff --git a/app/src/page/about/index.js b/app/src/page/about/index.js index fd767ed9..612a0f97 100644 --- a/app/src/page/about/index.js +++ b/app/src/page/about/index.js @@ -1,16 +1,22 @@ import { connect } from 'react-redux'; import { doToast } from 'lbry-redux'; import { doFetchAccessToken, selectAccessToken, selectUserEmail } from 'lbryinc'; +import { doPushDrawerStack, doPopDrawerStack } from 'redux/actions/drawer'; +import { selectDrawerStack } from 'redux/selectors/drawer'; import AboutPage from './view'; +import Constants from 'constants'; const select = state => ({ accessToken: selectAccessToken(state), userEmail: selectUserEmail(state), + drawerStack: selectDrawerStack(state), }); const perform = dispatch => ({ fetchAccessToken: () => dispatch(doFetchAccessToken()), notify: data => dispatch(doToast(data)), + pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_ABOUT)), + popDrawerStack: () => dispatch(doPopDrawerStack()), }); export default connect(select, perform)(AboutPage); \ No newline at end of file diff --git a/app/src/page/about/view.js b/app/src/page/about/view.js index d67b586a..bedf226a 100644 --- a/app/src/page/about/view.js +++ b/app/src/page/about/view.js @@ -13,6 +13,7 @@ class AboutPage extends React.PureComponent { }; componentDidMount() { + this.props.pushDrawerStack(); if (NativeModules.VersionInfo) { NativeModules.VersionInfo.getAppVersion().then(version => { this.setState({appVersion: version}); @@ -33,14 +34,14 @@ class AboutPage extends React.PureComponent { } render() { - const { accessToken, navigation, notify, userEmail } = this.props; + const { accessToken, drawerStack, navigation, notify, popDrawerStack, userEmail } = this.props; const loading = 'Loading...'; const ver = this.state.versionInfo ? this.state.versionInfo : null; return ( navigation.goBack(navigation.state.key)} /> + onBackPressed={() => navigateBack(navigation, drawerStack, popDrawerStack)} /> Content Freedom diff --git a/app/src/page/channel/index.js b/app/src/page/channel/index.js index 54425546..c84e966a 100644 --- a/app/src/page/channel/index.js +++ b/app/src/page/channel/index.js @@ -7,11 +7,14 @@ import { makeSelectFetchingChannelClaims, makeSelectTotalPagesForChannel } from 'lbry-redux'; +import { doPopDrawerStack } from 'redux/actions/drawer'; +import { selectDrawerStack } from 'redux/selectors/drawer'; import ChannelPage from './view'; const select = (state, props) => ({ claim: makeSelectClaimForUri(props.uri)(state), claimsInChannel: makeSelectClaimsInChannelForCurrentPageState(props.uri)(state), + drawerStack: selectDrawerStack(state), fetching: makeSelectFetchingChannelClaims(props.uri)(state), totalPages: makeSelectTotalPagesForChannel(props.uri, 10)(state), // Update to use a default PAGE_SIZE constant }); @@ -19,6 +22,7 @@ const select = (state, props) => ({ const perform = dispatch => ({ fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)), fetchClaimCount: uri => dispatch(doFetchClaimCountByChannel(uri)), + popDrawerStack: () => dispatch(doPopDrawerStack()) }); export default connect(select, perform)(ChannelPage); diff --git a/app/src/page/channel/view.js b/app/src/page/channel/view.js index 8e54ea3a..62c90e27 100644 --- a/app/src/page/channel/view.js +++ b/app/src/page/channel/view.js @@ -1,6 +1,7 @@ // @flow import React from 'react'; import { ActivityIndicator, Text, View } from 'react-native'; +import { navigateBack } from 'utils/helper'; import Colors from 'styles/colors'; import Button from 'component/button'; import FileList from 'component/fileList'; @@ -41,7 +42,16 @@ class ChannelPage extends React.PureComponent { } render() { - const { fetching, claimsInChannel, claim, navigation, totalPages, uri } = this.props; + const { + fetching, + claimsInChannel, + claim, + navigation, + totalPages, + uri, + drawerStack, + popDrawerStack + } = this.props; const { name, permanent_url: permanentUrl } = claim; let contentList; @@ -69,7 +79,7 @@ class ChannelPage extends React.PureComponent { return ( - navigation.goBack(navigation.state.key)} /> + navigateBack(navigation, drawerStack, popDrawerStack)} /> {contentList} {(totalPages > 1) && diff --git a/app/src/page/downloads/index.js b/app/src/page/downloads/index.js index 11ffe215..32490a4c 100644 --- a/app/src/page/downloads/index.js +++ b/app/src/page/downloads/index.js @@ -5,6 +5,8 @@ import { selectMyClaimsWithoutChannels, selectIsFetchingFileList, } from 'lbry-redux'; +import { doPushDrawerStack } from 'redux/actions/drawer'; +import Constants from 'constants'; import DownloadsPage from './view'; const select = (state) => ({ @@ -15,6 +17,7 @@ const select = (state) => ({ const perform = dispatch => ({ fileList: () => dispatch(doFileList()), + pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_MY_LBRY)) }); export default connect(select, perform)(DownloadsPage); diff --git a/app/src/page/downloads/view.js b/app/src/page/downloads/view.js index 052a7040..3a5e780a 100644 --- a/app/src/page/downloads/view.js +++ b/app/src/page/downloads/view.js @@ -25,7 +25,9 @@ class DownloadsPage extends React.PureComponent { }; componentDidMount() { - this.props.fileList(); + const { fileList, pushDrawerStack } = this.props; + pushDrawerStack(); + fileList(); } render() { diff --git a/app/src/page/rewards/index.js b/app/src/page/rewards/index.js index b9138fdd..c45887d6 100644 --- a/app/src/page/rewards/index.js +++ b/app/src/page/rewards/index.js @@ -9,6 +9,8 @@ import { selectUser, } from 'lbryinc'; import { doToast } from 'lbry-redux'; +import { doPushDrawerStack } from 'redux/actions/drawer'; +import Constants from 'constants'; import RewardsPage from './view'; const select = state => ({ @@ -23,6 +25,7 @@ const select = state => ({ const perform = dispatch => ({ fetchRewards: () => dispatch(doRewardList()), notify: data => dispatch(doToast(data)), + pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_REWARDS)) }); export default connect(select, perform)(RewardsPage); diff --git a/app/src/page/rewards/view.js b/app/src/page/rewards/view.js index 501d28a8..053d179e 100644 --- a/app/src/page/rewards/view.js +++ b/app/src/page/rewards/view.js @@ -25,9 +25,11 @@ class RewardsPage extends React.PureComponent { }; componentDidMount() { - this.props.fetchRewards(); + const { fetchRewards, pushDrawerStack, navigation, user } = this.props; + + pushDrawerStack(); + fetchRewards(); - const { user } = this.props; this.setState({ isEmailVerified: (user && user.primary_email && user.has_verified_email), isIdentityVerified: (user && user.is_identity_verified), diff --git a/app/src/page/settings/index.js b/app/src/page/settings/index.js index 8d1ed539..24a0d638 100644 --- a/app/src/page/settings/index.js +++ b/app/src/page/settings/index.js @@ -1,16 +1,22 @@ import { connect } from 'react-redux'; import { SETTINGS } from 'lbry-redux'; -import { doSetClientSetting } from '../../redux/actions/settings'; -import { makeSelectClientSetting } from '../../redux/selectors/settings'; +import { doPushDrawerStack, doPopDrawerStack } from 'redux/actions/drawer'; +import { doSetClientSetting } from 'redux/actions/settings'; +import { selectDrawerStack } from 'redux/selectors/drawer'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; +import Constants from 'constants'; import SettingsPage from './view'; const select = state => ({ backgroundPlayEnabled: makeSelectClientSetting(SETTINGS.BACKGROUND_PLAY_ENABLED)(state), + drawerStack: selectDrawerStack(state), keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state), showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state), }); const perform = dispatch => ({ + pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SETTINGS)), + popDrawerStack: () => dispatch(doPopDrawerStack()), setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), }); diff --git a/app/src/page/settings/view.js b/app/src/page/settings/view.js index ac551b67..68d7ab8d 100644 --- a/app/src/page/settings/view.js +++ b/app/src/page/settings/view.js @@ -1,19 +1,26 @@ import React from 'react'; import { SETTINGS } from 'lbry-redux'; import { Text, View, ScrollView, Switch, NativeModules } from 'react-native'; -import PageHeader from '../../component/pageHeader'; -import settingsStyle from '../../styles/settings'; +import { navigateBack } from 'utils/helper'; +import PageHeader from 'component/pageHeader'; +import settingsStyle from 'styles/settings'; class SettingsPage extends React.PureComponent { static navigationOptions = { title: 'Settings' } + componentDidMount() { + this.props.pushDrawerStack(); + } + render() { const { backgroundPlayEnabled, + drawerStack, keepDaemonRunning, navigation, + popDrawerStack, showNsfw, setClientSetting } = this.props; @@ -24,7 +31,7 @@ class SettingsPage extends React.PureComponent { return ( navigation.goBack(navigation.state.key)} /> + onBackPressed={() => navigateBack(navigation, drawerStack, popDrawerStack)} /> diff --git a/app/src/page/subscriptions/index.js b/app/src/page/subscriptions/index.js index 19c19a4a..c96f3d67 100644 --- a/app/src/page/subscriptions/index.js +++ b/app/src/page/subscriptions/index.js @@ -14,6 +14,8 @@ import { selectFirstRunCompleted, selectShowSuggestedSubs } from 'lbryinc'; +import { doPushDrawerStack } from 'redux/actions/drawer'; +import Constants from 'constants'; import SubscriptionsPage from './view'; const select = state => ({ @@ -28,13 +30,13 @@ const select = state => ({ showSuggestedSubs: selectShowSuggestedSubs(state), }); -export default connect( - select, - { - doFetchMySubscriptions, - doSetViewMode, - doFetchRecommendedSubscriptions, - doCompleteFirstRun, - doShowSuggestedSubs, - } -)(SubscriptionsPage); +const perform = dispatch => ({ + doFetchMySubscriptions, + doSetViewMode, + doFetchRecommendedSubscriptions, + doCompleteFirstRun, + doShowSuggestedSubs, + pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SUBSCRIPTIONS)) +}); + +export default connect(select, perform)(SubscriptionsPage); diff --git a/app/src/page/subscriptions/view.js b/app/src/page/subscriptions/view.js index ebce3d3f..4dd5bba5 100644 --- a/app/src/page/subscriptions/view.js +++ b/app/src/page/subscriptions/view.js @@ -23,8 +23,10 @@ class SubscriptionsPage extends React.PureComponent { componentDidMount() { const { doFetchMySubscriptions, - doFetchRecommendedSubscriptions + doFetchRecommendedSubscriptions, + pushDrawerStack, } = this.props; + pushDrawerStack(); doFetchMySubscriptions(); //doFetchRecommendedSubscriptions(); } diff --git a/app/src/page/trending/index.js b/app/src/page/trending/index.js index 614a5ba2..65f99004 100644 --- a/app/src/page/trending/index.js +++ b/app/src/page/trending/index.js @@ -1,5 +1,7 @@ import { connect } from 'react-redux'; import { doFetchTrendingUris, selectTrendingUris, selectFetchingTrendingUris } from 'lbry-redux'; +import { doPushDrawerStack } from 'redux/actions/drawer'; +import Constants from 'constants'; import TrendingPage from './view'; const select = state => ({ @@ -9,6 +11,7 @@ const select = state => ({ const perform = dispatch => ({ fetchTrendingUris: () => dispatch(doFetchTrendingUris()), + pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_TRENDING)) }); export default connect(select, perform)(TrendingPage); \ No newline at end of file diff --git a/app/src/page/trending/view.js b/app/src/page/trending/view.js index d86f70c6..1bedc729 100644 --- a/app/src/page/trending/view.js +++ b/app/src/page/trending/view.js @@ -18,7 +18,9 @@ import UriBar from '../../component/uriBar'; class TrendingPage extends React.PureComponent { componentDidMount() { - this.props.fetchTrendingUris(); + const { fetchTrendingUris, pushDrawerStack } = this.props; + pushDrawerStack(); + fetchTrendingUris(); } render() { diff --git a/app/src/page/wallet/index.js b/app/src/page/wallet/index.js index 10a79bed..e16f11a9 100644 --- a/app/src/page/wallet/index.js +++ b/app/src/page/wallet/index.js @@ -1,7 +1,8 @@ import { connect } from 'react-redux'; -import { doSetClientSetting } from '../../redux/actions/settings'; -import { makeSelectClientSetting } from '../../redux/selectors/settings'; -import Constants from '../../constants'; +import { doSetClientSetting } from 'redux/actions/settings'; +import { makeSelectClientSetting } from 'redux/selectors/settings'; +import { doPushDrawerStack } from 'redux/actions/drawer'; +import Constants from 'constants'; import WalletPage from './view'; const select = state => ({ @@ -10,6 +11,7 @@ const select = state => ({ const perform = dispatch => ({ setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), + pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_WALLET)) }); export default connect(select, perform)(WalletPage); diff --git a/app/src/page/wallet/view.js b/app/src/page/wallet/view.js index c4813e42..92295923 100644 --- a/app/src/page/wallet/view.js +++ b/app/src/page/wallet/view.js @@ -10,6 +10,10 @@ import Constants from 'constants'; import walletStyle from 'styles/wallet'; class WalletPage extends React.PureComponent { + componentDidMount() { + this.props.pushDrawerStack(); + } + render() { const { understandsRisks, setClientSetting } = this.props; diff --git a/app/src/redux/actions/drawer.js b/app/src/redux/actions/drawer.js new file mode 100644 index 00000000..ba9e2396 --- /dev/null +++ b/app/src/redux/actions/drawer.js @@ -0,0 +1,10 @@ +import Constants from 'constants'; + +export const doPushDrawerStack = (routeName) => (dispatch) => dispatch({ + type: Constants.ACTION_PUSH_DRAWER_STACK, + data: routeName +}); + +export const doPopDrawerStack = () => (dispatch) => dispatch({ + type: Constants.ACTION_POP_DRAWER_STACK +}); diff --git a/app/src/redux/reducers/drawer.js b/app/src/redux/reducers/drawer.js new file mode 100644 index 00000000..c563440a --- /dev/null +++ b/app/src/redux/reducers/drawer.js @@ -0,0 +1,36 @@ +import Constants from 'constants'; + +const reducers = {}; +const defaultState = { + stack: [ Constants.DRAWER_ROUTE_DISCOVER ] // Discover is always the first drawer route +}; + +reducers[Constants.ACTION_PUSH_DRAWER_STACK] = (state, action) => { + const routeName = action.data; + const newStack = state.stack.slice(); + + if (routeName !== newStack[newStack.length -1]) { + newStack.push(routeName); + } + + return { + ...state, + stack: newStack + }; +}; + +reducers[Constants.ACTION_POP_DRAWER_STACK] = (state, action) => { + // We don't want to pop the Discover route, since it's always expected to be the first + const newStack = (state.stack.length === 1) ? state.stack.slice() : state.stack.slice(0, state.stack.length - 1); + + return { + ...state, + stack: newStack + } +}; + +export default function reducer(state = defaultState, action) { + const handler = reducers[action.type]; + if (handler) return handler(state, action); + return state; +} \ No newline at end of file diff --git a/app/src/redux/selectors/drawer.js b/app/src/redux/selectors/drawer.js new file mode 100644 index 00000000..f19e8de6 --- /dev/null +++ b/app/src/redux/selectors/drawer.js @@ -0,0 +1,13 @@ +import { createSelector } from 'reselect'; + +export const selectState = state => state.drawer || {}; + +export const selectDrawerStack = createSelector(selectState, (state) => state.stack); + +export const selectLastDrawerRoute = createSelector(selectState, (state) => { + if (state.stack.length) { + return state.stack[state.stack.length - 1]; + } + + return null; +}); diff --git a/app/src/utils/helper.js b/app/src/utils/helper.js index a3c67f04..331e5f87 100644 --- a/app/src/utils/helper.js +++ b/app/src/utils/helper.js @@ -1,6 +1,7 @@ import { NavigationActions, StackActions } from 'react-navigation'; import { buildURI } from 'lbry-redux'; -import Constants from '../constants'; +import { DrawerRoutes } from 'constants'; +import Constants from 'constants'; function getRouteForSpecialUri(uri) { let targetRoute; @@ -85,6 +86,41 @@ export function navigateToUri(navigation, uri, additionalParams) { navigation.navigate({ routeName: 'File', key: uri, params }); } +export function navigateBack(navigation, drawerStack, popDrawerStack) { + const shouldPopStack = DrawerRoutes.indexOf(navigation.state.routeName) > -1; + if (shouldPopStack) { + navigation.goBack(); + if (popDrawerStack) { + popDrawerStack(); + } + + navigation.navigate({ routeName: drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0] }); + return; + } + + navigation.goBack(navigation.state.key); +} + +export function dispatchNavigateBack(dispatch, nav, drawerStack, popDrawerStack) { + const drawerRouteIndex = nav.routes[0].index; + const shouldPopStack = ( + (drawerRouteIndex > 0 && drawerRouteIndex !== 5) || // not the discover nor wallet stack + (drawerRouteIndex === 5 && nav.routes[0].routes[drawerRouteIndex].index === 0) // wallet stack, and tx history page not active + ); + if (shouldPopStack) { + dispatch(NavigationActions.back()); + if (popDrawerStack) { + dispatch(popDrawerStack()); + } + + const navigateAction = NavigationActions.navigate({ routeName: drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0] }); + dispatch(navigateAction); + return; + } + + dispatch(NavigationActions.back()); +} + export function uriFromFileInfo(fileInfo) { const { name: claimName, claim_name: claimNameDownloaded, claim_id: claimId } = fileInfo; const uriParams = {}; diff --git a/p4a/pythonforandroid/toolchain.py b/p4a/pythonforandroid/toolchain.py index 30ebd65d..95822ea3 100644 --- a/p4a/pythonforandroid/toolchain.py +++ b/p4a/pythonforandroid/toolchain.py @@ -796,7 +796,7 @@ class ToolchainCL(object): error("Unknown build mode {} for apk()".format( args.build_mode)) exit(1) - output = shprint(gradlew, gradle_task, _tail=20, + output = shprint(gradlew, "--console=plain", gradle_task, _tail=20, _critical=True, _env=env) # gradle output apks somewhere else