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 (
+