diff --git a/app/.babelrc b/app/.babelrc new file mode 100644 index 00000000..91586fcd --- /dev/null +++ b/app/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": ["react-native"], + "plugins": [ + ["module-resolver", { + root: ["./src"], + }], + ] +} diff --git a/app/package-lock.json b/app/package-lock.json index ffcf8e98..2c715c8a 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -644,6 +644,56 @@ } } }, + "@expo/vector-icons": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-8.1.0.tgz", + "integrity": "sha512-/aKa+bgp3LIcTKJWPLRYTYCL0wf/Fr4dwl4XYmNGFG092pK3McuBoDk3b8tWyZnXBnEiqnMLd6Qwr+LEX6Jc0Q==", + "requires": { + "lodash": "^4.17.4", + "react-native-vector-icons": "6.0.0" + }, + "dependencies": { + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, + "react-native-vector-icons": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-6.0.0.tgz", + "integrity": "sha512-uF3oWb3TV42uXi2apVOZHw9oy9Nr5SXDVwOo1umQWo/yYCrDzXyVfq14DzezgEbJ9jfc/yghBelj0agkXmOKlg==", + "requires": { + "lodash": "^4.0.0", + "prop-types": "^15.6.2", + "yargs": "^8.0.2" + } + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" + } + } + } + }, "absolute-path": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz", @@ -1312,6 +1362,19 @@ "babel-runtime": "^6.22.0" } }, + "babel-plugin-module-resolver": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.1.1.tgz", + "integrity": "sha512-1Q77Al4ydp6nYApJ7sQ2fmgz30WuQgJZegIYuyOdbdpxenB/bSezQ3hDPsumIXGlUS4vUIv+EwFjzzXZNWtARw==", + "dev": true, + "requires": { + "find-babel-config": "^1.1.0", + "glob": "^7.1.2", + "pkg-up": "^2.0.0", + "reselect": "^3.0.1", + "resolve": "^1.4.0" + } + }, "babel-plugin-react-transform": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-3.0.0.tgz", @@ -2099,6 +2162,11 @@ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.28.tgz", "integrity": "sha512-OJT3rzgtsYca/5WmmEuFJDPMwROVh5SSjoEX9wIrpfbbWJ4KqRzShs8Cj6jWHaatBYAeWngBA+kmmrcHSklT1g==" }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + }, "bplist-creator": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.7.tgz", @@ -2822,6 +2890,16 @@ "unpipe": "~1.0.0" } }, + "find-babel-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.1.0.tgz", + "integrity": "sha1-rMAQQ6Z0n+w0Qpvmtk9ULrtdY1U=", + "dev": true, + "requires": { + "json5": "^0.5.1", + "path-exists": "^3.0.0" + } + }, "find-cache-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", @@ -3998,20 +4076,27 @@ } }, "lbryinc": { - "version": "github:lbryio/lbryinc#82308ece97188747adbf6d71d55b6e7a6fa0bd95", - "from": "github:lbryio/lbryinc", + "version": "github:lbryio/lbryinc#4d24cef00106294d3e848b6c2b261e01382fce17", + "from": "github:lbryio/lbryinc#subscriptions", "requires": { - "lbry-redux": "github:lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2", + "bluebird": "^3.5.1", + "lbry-redux": "github:lbryio/lbry-redux#84b7d396934d57a37802aadbef71db91230a9404", "reselect": "^3.0.0" }, "dependencies": { "lbry-redux": { - "version": "github:lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2", - "from": "github:lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2", + "version": "github:lbryio/lbry-redux#84b7d396934d57a37802aadbef71db91230a9404", + "from": "github:lbryio/lbry-redux#84b7d396934d57a37802aadbef71db91230a9404", "requires": { "proxy-polyfill": "0.1.6", - "reselect": "^3.0.0" + "reselect": "^3.0.0", + "uuid": "^3.3.2" } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" } } }, @@ -4978,6 +5063,15 @@ "find-up": "^2.1.0" } }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, "plist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz", @@ -7026,6 +7120,11 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", diff --git a/app/package.json b/app/package.json index 3e0a86e2..d4a03188 100644 --- a/app/package.json +++ b/app/package.json @@ -7,8 +7,9 @@ }, "dependencies": { "base-64": "^0.1.0", + "@expo/vector-icons": "^8.1.0", "lbry-redux": "lbryio/lbry-redux", - "lbryinc": "lbryio/lbryinc", + "lbryinc": "lbryio/lbryinc#subscriptions", "moment": "^2.22.1", "react": "16.2.0", "react-native": "0.55.3", @@ -34,6 +35,7 @@ "devDependencies": { "babel-preset-env": "^1.6.1", "babel-preset-stage-2": "^6.18.0", + "babel-plugin-module-resolver": "^3.1.1", "flow-babel-webpack-plugin": "^1.1.1" } } diff --git a/app/src/component/AppNavigator.js b/app/src/component/AppNavigator.js index 266683d6..a5e6b99f 100644 --- a/app/src/component/AppNavigator.js +++ b/app/src/component/AppNavigator.js @@ -9,6 +9,7 @@ import TrendingPage from '../page/trending'; import SearchPage from '../page/search'; import SettingsPage from '../page/settings'; import SplashScreen from '../page/splash'; +import SubscriptionsPage from '../page/subscriptions'; import TransactionHistoryPage from '../page/transactionHistory'; import WalletPage from '../page/wallet'; import SearchInput from '../component/searchInput'; @@ -109,6 +110,17 @@ const myLbryStack = createStackNavigator({ } }); +const mySubscriptionsStack = createStackNavigator({ + Subscriptions: { + screen: SubscriptionsPage, + navigationOptions: ({ navigation }) => ({ + title: 'My Subscriptions', + headerLeft: menuNavigationButton(navigation), + headerTitleStyle: discoverStyle.titleText + }) + } +}); + const rewardsStack = createStackNavigator({ Rewards: { screen: RewardsPage, @@ -148,6 +160,9 @@ const drawer = createDrawerNavigator({ TrendingStack: { screen: trendingStack, navigationOptions: { title: 'Trending', drawerIcon: ({ tintColor }) => }}, + MySubscriptionsStack: { screen: mySubscriptionsStack, navigationOptions: { + title: 'My Subscriptions', drawerIcon: ({ tintColor }) => + }}, MyLBRYStack: { screen: myLbryStack, navigationOptions: { title: 'My LBRY', drawerIcon: ({ tintColor }) => }}, diff --git a/app/src/component/button/view.js b/app/src/component/button/view.js index ec3745eb..dae9c3b8 100644 --- a/app/src/component/button/view.js +++ b/app/src/component/button/view.js @@ -11,6 +11,8 @@ export default class Button extends React.PureComponent { style, text, icon, + iconColor, + solid, theme, onPress, onLayout @@ -41,9 +43,14 @@ export default class Button extends React.PureComponent { textStyles.push(buttonStyle.textLight); } + let renderIcon = (); + if (solid) { + renderIcon = (); + } + return ( - {icon && } + {icon && renderIcon} {text && (text.trim().length > 0) && {text}} ); diff --git a/app/src/component/subscribeButton/index.js b/app/src/component/subscribeButton/index.js new file mode 100644 index 00000000..fb7625e3 --- /dev/null +++ b/app/src/component/subscribeButton/index.js @@ -0,0 +1,23 @@ +import { connect } from 'react-redux'; +import { + doChannelSubscribe, + doChannelUnsubscribe, + selectSubscriptions, + makeSelectIsSubscribed, +} from 'lbryinc'; +import { doToast } from 'lbry-redux'; +import SubscribeButton from './view'; + +const select = (state, props) => ({ + subscriptions: selectSubscriptions(state), + isSubscribed: makeSelectIsSubscribed(props.uri, true)(state), +}); + +export default connect( + select, + { + doChannelSubscribe, + doChannelUnsubscribe, + doToast, + } +)(SubscribeButton); diff --git a/app/src/component/subscribeButton/view.js b/app/src/component/subscribeButton/view.js new file mode 100644 index 00000000..92013331 --- /dev/null +++ b/app/src/component/subscribeButton/view.js @@ -0,0 +1,49 @@ +import React from 'react'; +import { parseURI } from 'lbry-redux'; +import { NativeModules, Text, View, TouchableOpacity } from 'react-native'; +import Button from '../button'; +import Colors from '../../styles/colors'; + +class SubscribeButton extends React.PureComponent { + render() { + const { + uri, + isSubscribed, + doChannelSubscribe, + doChannelUnsubscribe, + style + } = this.props; + + let styles = []; + if (style) { + if (style.length) { + styles = styles.concat(style); + } else { + styles.push(style); + } + } + + const iconColor = isSubscribed ? null : Colors.Red; + const subscriptionHandler = isSubscribed ? doChannelUnsubscribe : doChannelSubscribe; + const subscriptionLabel = isSubscribed ? __('Unsubscribe') : __('Subscribe'); + const { claimName } = parseURI(uri); + + return ( +