Mobile subscriptions (#382)
* add subscribe button to file page * add My Subscriptions page * get module resolve babel plugin working to eliminate ugly imports
This commit is contained in:
parent
0cc2b4e368
commit
6991b99ea9
18 changed files with 414 additions and 28 deletions
8
app/.babelrc
Normal file
8
app/.babelrc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"presets": ["react-native"],
|
||||||
|
"plugins": [
|
||||||
|
["module-resolver", {
|
||||||
|
root: ["./src"],
|
||||||
|
}],
|
||||||
|
]
|
||||||
|
}
|
111
app/package-lock.json
generated
111
app/package-lock.json
generated
|
@ -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": {
|
"absolute-path": {
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz",
|
||||||
|
@ -1312,6 +1362,19 @@
|
||||||
"babel-runtime": "^6.22.0"
|
"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": {
|
"babel-plugin-react-transform": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-3.0.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.28.tgz",
|
||||||
"integrity": "sha512-OJT3rzgtsYca/5WmmEuFJDPMwROVh5SSjoEX9wIrpfbbWJ4KqRzShs8Cj6jWHaatBYAeWngBA+kmmrcHSklT1g=="
|
"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": {
|
"bplist-creator": {
|
||||||
"version": "0.0.7",
|
"version": "0.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.7.tgz",
|
||||||
|
@ -2822,6 +2890,16 @@
|
||||||
"unpipe": "~1.0.0"
|
"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": {
|
"find-cache-dir": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
|
||||||
|
@ -3998,20 +4076,27 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lbryinc": {
|
"lbryinc": {
|
||||||
"version": "github:lbryio/lbryinc#82308ece97188747adbf6d71d55b6e7a6fa0bd95",
|
"version": "github:lbryio/lbryinc#4d24cef00106294d3e848b6c2b261e01382fce17",
|
||||||
"from": "github:lbryio/lbryinc",
|
"from": "github:lbryio/lbryinc#subscriptions",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lbry-redux": "github:lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2",
|
"bluebird": "^3.5.1",
|
||||||
|
"lbry-redux": "github:lbryio/lbry-redux#84b7d396934d57a37802aadbef71db91230a9404",
|
||||||
"reselect": "^3.0.0"
|
"reselect": "^3.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lbry-redux": {
|
"lbry-redux": {
|
||||||
"version": "github:lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2",
|
"version": "github:lbryio/lbry-redux#84b7d396934d57a37802aadbef71db91230a9404",
|
||||||
"from": "github:lbryio/lbry-redux#2375860d6269d0369418879c2531b1d48c4e47f2",
|
"from": "github:lbryio/lbry-redux#84b7d396934d57a37802aadbef71db91230a9404",
|
||||||
"requires": {
|
"requires": {
|
||||||
"proxy-polyfill": "0.1.6",
|
"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"
|
"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": {
|
"plist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
|
||||||
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
|
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
|
||||||
},
|
},
|
||||||
|
"y18n": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
|
||||||
|
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
|
||||||
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base-64": "^0.1.0",
|
"base-64": "^0.1.0",
|
||||||
|
"@expo/vector-icons": "^8.1.0",
|
||||||
"lbry-redux": "lbryio/lbry-redux",
|
"lbry-redux": "lbryio/lbry-redux",
|
||||||
"lbryinc": "lbryio/lbryinc",
|
"lbryinc": "lbryio/lbryinc#subscriptions",
|
||||||
"moment": "^2.22.1",
|
"moment": "^2.22.1",
|
||||||
"react": "16.2.0",
|
"react": "16.2.0",
|
||||||
"react-native": "0.55.3",
|
"react-native": "0.55.3",
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-preset-env": "^1.6.1",
|
"babel-preset-env": "^1.6.1",
|
||||||
"babel-preset-stage-2": "^6.18.0",
|
"babel-preset-stage-2": "^6.18.0",
|
||||||
|
"babel-plugin-module-resolver": "^3.1.1",
|
||||||
"flow-babel-webpack-plugin": "^1.1.1"
|
"flow-babel-webpack-plugin": "^1.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import TrendingPage from '../page/trending';
|
||||||
import SearchPage from '../page/search';
|
import SearchPage from '../page/search';
|
||||||
import SettingsPage from '../page/settings';
|
import SettingsPage from '../page/settings';
|
||||||
import SplashScreen from '../page/splash';
|
import SplashScreen from '../page/splash';
|
||||||
|
import SubscriptionsPage from '../page/subscriptions';
|
||||||
import TransactionHistoryPage from '../page/transactionHistory';
|
import TransactionHistoryPage from '../page/transactionHistory';
|
||||||
import WalletPage from '../page/wallet';
|
import WalletPage from '../page/wallet';
|
||||||
import SearchInput from '../component/searchInput';
|
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({
|
const rewardsStack = createStackNavigator({
|
||||||
Rewards: {
|
Rewards: {
|
||||||
screen: RewardsPage,
|
screen: RewardsPage,
|
||||||
|
@ -148,6 +160,9 @@ const drawer = createDrawerNavigator({
|
||||||
TrendingStack: { screen: trendingStack, navigationOptions: {
|
TrendingStack: { screen: trendingStack, navigationOptions: {
|
||||||
title: 'Trending', drawerIcon: ({ tintColor }) => <Icon name="fire" size={20} style={{ color: tintColor }} />
|
title: 'Trending', drawerIcon: ({ tintColor }) => <Icon name="fire" size={20} style={{ color: tintColor }} />
|
||||||
}},
|
}},
|
||||||
|
MySubscriptionsStack: { screen: mySubscriptionsStack, navigationOptions: {
|
||||||
|
title: 'My Subscriptions', drawerIcon: ({ tintColor }) => <Icon name="rss-square" size={20} style={{ color: tintColor }} />
|
||||||
|
}},
|
||||||
MyLBRYStack: { screen: myLbryStack, navigationOptions: {
|
MyLBRYStack: { screen: myLbryStack, navigationOptions: {
|
||||||
title: 'My LBRY', drawerIcon: ({ tintColor }) => <Icon name="folder" size={20} style={{ color: tintColor }} />
|
title: 'My LBRY', drawerIcon: ({ tintColor }) => <Icon name="folder" size={20} style={{ color: tintColor }} />
|
||||||
}},
|
}},
|
||||||
|
|
|
@ -11,6 +11,8 @@ export default class Button extends React.PureComponent {
|
||||||
style,
|
style,
|
||||||
text,
|
text,
|
||||||
icon,
|
icon,
|
||||||
|
iconColor,
|
||||||
|
solid,
|
||||||
theme,
|
theme,
|
||||||
onPress,
|
onPress,
|
||||||
onLayout
|
onLayout
|
||||||
|
@ -41,9 +43,14 @@ export default class Button extends React.PureComponent {
|
||||||
textStyles.push(buttonStyle.textLight);
|
textStyles.push(buttonStyle.textLight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let renderIcon = (<Icon name={icon} size={18} color={iconColor ? iconColor : ('light' === theme ? Colors.DarkGrey : Colors.White)} />);
|
||||||
|
if (solid) {
|
||||||
|
renderIcon = (<Icon name={icon} size={18} color={iconColor ? iconColor : ('light' === theme ? Colors.DarkGrey : Colors.White)} solid />);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity disabled={disabled} style={styles} onPress={onPress} onLayout={onLayout}>
|
<TouchableOpacity disabled={disabled} style={styles} onPress={onPress} onLayout={onLayout}>
|
||||||
{icon && <Icon name={icon} size={18} color={'light' === theme ? Colors.DarkGrey : Colors.White} />}
|
{icon && renderIcon}
|
||||||
{text && (text.trim().length > 0) && <Text style={textStyles}>{text}</Text>}
|
{text && (text.trim().length > 0) && <Text style={textStyles}>{text}</Text>}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
|
|
23
app/src/component/subscribeButton/index.js
Normal file
23
app/src/component/subscribeButton/index.js
Normal file
|
@ -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);
|
49
app/src/component/subscribeButton/view.js
Normal file
49
app/src/component/subscribeButton/view.js
Normal file
|
@ -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 (
|
||||||
|
<Button
|
||||||
|
style={styles}
|
||||||
|
theme={"light"}
|
||||||
|
icon={"heart"}
|
||||||
|
iconColor={iconColor}
|
||||||
|
solid={isSubscribed ? false : true}
|
||||||
|
text={subscriptionLabel}
|
||||||
|
onPress={() => {
|
||||||
|
subscriptionHandler({
|
||||||
|
channelName: claimName,
|
||||||
|
uri,
|
||||||
|
});
|
||||||
|
}} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SubscribeButton;
|
|
@ -19,7 +19,7 @@ import {
|
||||||
searchReducer,
|
searchReducer,
|
||||||
walletReducer
|
walletReducer
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { authReducer, rewardsReducer, userReducer } from 'lbryinc';
|
import { authReducer, rewardsReducer, subscriptionsReducer, userReducer } from 'lbryinc';
|
||||||
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
|
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
|
||||||
import { createLogger } from 'redux-logger';
|
import { createLogger } from 'redux-logger';
|
||||||
import { AppNavigator } from './component/AppNavigator';
|
import { AppNavigator } from './component/AppNavigator';
|
||||||
|
@ -87,6 +87,7 @@ const reducers = combineReducers({
|
||||||
rewards: rewardsReducer,
|
rewards: rewardsReducer,
|
||||||
settings: settingsReducer,
|
settings: settingsReducer,
|
||||||
search: searchReducer,
|
search: searchReducer,
|
||||||
|
subscriptions: subscriptionsReducer,
|
||||||
user: userReducer,
|
user: userReducer,
|
||||||
wallet: walletReducer
|
wallet: walletReducer
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
View,
|
View,
|
||||||
ScrollView
|
ScrollView
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { navigateToUri } from '../../utils/helper';
|
import { navigateToUri, uriFromFileInfo } from '../../utils/helper';
|
||||||
import Colors from '../../styles/colors';
|
import Colors from '../../styles/colors';
|
||||||
import PageHeader from '../../component/pageHeader';
|
import PageHeader from '../../component/pageHeader';
|
||||||
import FileListItem from '../../component/fileListItem';
|
import FileListItem from '../../component/fileListItem';
|
||||||
|
@ -28,14 +28,6 @@ class DownloadsPage extends React.PureComponent {
|
||||||
this.props.fileList();
|
this.props.fileList();
|
||||||
}
|
}
|
||||||
|
|
||||||
uriFromFileInfo(fileInfo) {
|
|
||||||
const { name: claimName, claim_name: claimNameDownloaded, claim_id: claimId } = fileInfo;
|
|
||||||
const uriParams = {};
|
|
||||||
uriParams.contentName = claimName || claimNameDownloaded;
|
|
||||||
uriParams.claimId = claimId;
|
|
||||||
return buildURI(uriParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fetching, fileInfos, navigation } = this.props;
|
const { fetching, fileInfos, navigation } = this.props;
|
||||||
const hasDownloads = fileInfos && Object.values(fileInfos).length > 0;
|
const hasDownloads = fileInfos && Object.values(fileInfos).length > 0;
|
||||||
|
@ -59,9 +51,9 @@ class DownloadsPage extends React.PureComponent {
|
||||||
renderItem={ ({item}) => (
|
renderItem={ ({item}) => (
|
||||||
<FileListItem
|
<FileListItem
|
||||||
style={fileListStyle.item}
|
style={fileListStyle.item}
|
||||||
uri={this.uriFromFileInfo(item)}
|
uri={uriFromFileInfo(item)}
|
||||||
navigation={navigation}
|
navigation={navigation}
|
||||||
onPress={() => navigateToUri(navigation, this.uriFromFileInfo(item), { autoplay: true })} />
|
onPress={() => navigateToUri(navigation, uriFromFileInfo(item), { autoplay: true })} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
data={fileInfos.sort((a, b) => {
|
data={fileInfos.sort((a, b) => {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
makeSelectIsUriResolving,
|
makeSelectIsUriResolving,
|
||||||
makeSelectCostInfoForUri,
|
makeSelectCostInfoForUri,
|
||||||
makeSelectFileInfoForUri,
|
makeSelectFileInfoForUri,
|
||||||
|
makeSelectChannelForClaimUri,
|
||||||
makeSelectClaimForUri,
|
makeSelectClaimForUri,
|
||||||
makeSelectContentTypeForUri,
|
makeSelectContentTypeForUri,
|
||||||
makeSelectMetadataForUri,
|
makeSelectMetadataForUri,
|
||||||
|
@ -32,6 +33,7 @@ const select = (state, props) => {
|
||||||
//tab: makeSelectCurrentParam('tab')(state),
|
//tab: makeSelectCurrentParam('tab')(state),
|
||||||
fileInfo: makeSelectFileInfoForUri(selectProps.uri)(state),
|
fileInfo: makeSelectFileInfoForUri(selectProps.uri)(state),
|
||||||
rewardedContentClaimIds: selectRewardContentClaimIds(state, selectProps),
|
rewardedContentClaimIds: selectRewardContentClaimIds(state, selectProps),
|
||||||
|
channelUri: makeSelectChannelForClaimUri(selectProps.uri, true)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import FloatingWalletBalance from '../../component/floatingWalletBalance';
|
||||||
import Link from '../../component/link';
|
import Link from '../../component/link';
|
||||||
import MediaPlayer from '../../component/mediaPlayer';
|
import MediaPlayer from '../../component/mediaPlayer';
|
||||||
import RelatedContent from '../../component/relatedContent';
|
import RelatedContent from '../../component/relatedContent';
|
||||||
|
import SubscribeButton from '../../component/subscribeButton';
|
||||||
import UriBar from '../../component/uriBar';
|
import UriBar from '../../component/uriBar';
|
||||||
import Video from 'react-native-video';
|
import Video from 'react-native-video';
|
||||||
import filePageStyle from '../../styles/filePage';
|
import filePageStyle from '../../styles/filePage';
|
||||||
|
@ -332,6 +333,7 @@ class FilePage extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
claim,
|
claim,
|
||||||
|
channelUri,
|
||||||
fileInfo,
|
fileInfo,
|
||||||
metadata,
|
metadata,
|
||||||
contentType,
|
contentType,
|
||||||
|
@ -403,7 +405,6 @@ class FilePage extends React.PureComponent {
|
||||||
value && value.publisherSignature && value.publisherSignature.certificateId;
|
value && value.publisherSignature && value.publisherSignature.certificateId;
|
||||||
const canSendTip = this.state.tipAmount > 0;
|
const canSendTip = this.state.tipAmount > 0;
|
||||||
|
|
||||||
|
|
||||||
const playerStyle = [filePageStyle.player,
|
const playerStyle = [filePageStyle.player,
|
||||||
this.state.isLandscape ? filePageStyle.containedPlayerLandscape :
|
this.state.isLandscape ? filePageStyle.containedPlayerLandscape :
|
||||||
(this.state.fullscreenMode ? filePageStyle.fullscreenPlayer : filePageStyle.containedPlayer)];
|
(this.state.fullscreenMode ? filePageStyle.fullscreenPlayer : filePageStyle.containedPlayer)];
|
||||||
|
@ -494,11 +495,16 @@ class FilePage extends React.PureComponent {
|
||||||
|
|
||||||
{showActions &&
|
{showActions &&
|
||||||
<View style={filePageStyle.actions}>
|
<View style={filePageStyle.actions}>
|
||||||
{<Button style={filePageStyle.actionButton}
|
<View style={filePageStyle.socialActions}>
|
||||||
theme={"light"}
|
{channelName && <SubscribeButton
|
||||||
icon={"gift"}
|
style={[filePageStyle.actionButton, filePageStyle.subscribeButton]}
|
||||||
text={"Send a tip"}
|
uri={channelUri} name={channelName} />}
|
||||||
onPress={() => this.setState({ showTipView: true })} />}
|
{<Button style={filePageStyle.actionButton}
|
||||||
|
theme={"light"}
|
||||||
|
icon={"gift"}
|
||||||
|
text={"Send a tip"}
|
||||||
|
onPress={() => this.setState({ showTipView: true })} />}
|
||||||
|
</View>
|
||||||
{showFileActions &&
|
{showFileActions &&
|
||||||
<View style={filePageStyle.fileActions}>
|
<View style={filePageStyle.fileActions}>
|
||||||
{completed && <Button style={filePageStyle.actionButton}
|
{completed && <Button style={filePageStyle.actionButton}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { connect } from 'react-redux';
|
||||||
import { doBalanceSubscribe, doBlackListedOutpointsSubscribe, doToast } from 'lbry-redux';
|
import { doBalanceSubscribe, doBlackListedOutpointsSubscribe, doToast } from 'lbry-redux';
|
||||||
import {
|
import {
|
||||||
doAuthenticate,
|
doAuthenticate,
|
||||||
|
doCheckSubscriptionsInit,
|
||||||
doFetchRewardedContent,
|
doFetchRewardedContent,
|
||||||
doUserEmailToVerify,
|
doUserEmailToVerify,
|
||||||
doUserEmailVerify,
|
doUserEmailVerify,
|
||||||
|
@ -21,6 +22,7 @@ const perform = dispatch => ({
|
||||||
authenticate: (appVersion, os) => dispatch(doAuthenticate(appVersion, os)),
|
authenticate: (appVersion, os) => dispatch(doAuthenticate(appVersion, os)),
|
||||||
balanceSubscribe: () => dispatch(doBalanceSubscribe()),
|
balanceSubscribe: () => dispatch(doBalanceSubscribe()),
|
||||||
blacklistedOutpointsSubscribe: () => dispatch(doBlackListedOutpointsSubscribe()),
|
blacklistedOutpointsSubscribe: () => dispatch(doBlackListedOutpointsSubscribe()),
|
||||||
|
checkSubscriptionsInit: () => dispatch(doCheckSubscriptionsInit()),
|
||||||
deleteCompleteBlobs: () => dispatch(doDeleteCompleteBlobs()),
|
deleteCompleteBlobs: () => dispatch(doDeleteCompleteBlobs()),
|
||||||
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
|
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
|
||||||
notify: data => dispatch(doToast(data)),
|
notify: data => dispatch(doToast(data)),
|
||||||
|
|
|
@ -144,12 +144,14 @@ class SplashScreen extends React.PureComponent {
|
||||||
authenticate,
|
authenticate,
|
||||||
balanceSubscribe,
|
balanceSubscribe,
|
||||||
blacklistedOutpointsSubscribe,
|
blacklistedOutpointsSubscribe,
|
||||||
|
checkSubscriptionsInit,
|
||||||
navigation,
|
navigation,
|
||||||
notify
|
notify
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
balanceSubscribe();
|
balanceSubscribe();
|
||||||
blacklistedOutpointsSubscribe();
|
blacklistedOutpointsSubscribe();
|
||||||
|
checkSubscriptionsInit();
|
||||||
NativeModules.VersionInfo.getAppVersion().then(appVersion => {
|
NativeModules.VersionInfo.getAppVersion().then(appVersion => {
|
||||||
this.setState({ shouldAuthenticate: true });
|
this.setState({ shouldAuthenticate: true });
|
||||||
authenticate(appVersion, Platform.OS);
|
authenticate(appVersion, Platform.OS);
|
||||||
|
|
40
app/src/page/subscriptions/index.js
Normal file
40
app/src/page/subscriptions/index.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
doFetchMySubscriptions,
|
||||||
|
doSetViewMode,
|
||||||
|
doFetchRecommendedSubscriptions,
|
||||||
|
doCompleteFirstRun,
|
||||||
|
doShowSuggestedSubs,
|
||||||
|
selectSubscriptionClaims,
|
||||||
|
selectSubscriptions,
|
||||||
|
selectSubscriptionsBeingFetched,
|
||||||
|
selectIsFetchingSubscriptions,
|
||||||
|
selectUnreadSubscriptions,
|
||||||
|
selectViewMode,
|
||||||
|
selectFirstRunCompleted,
|
||||||
|
selectShowSuggestedSubs
|
||||||
|
} from 'lbryinc';
|
||||||
|
import SubscriptionsPage from './view';
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
loading:
|
||||||
|
selectIsFetchingSubscriptions(state) ||
|
||||||
|
Boolean(Object.keys(selectSubscriptionsBeingFetched(state)).length),
|
||||||
|
subscribedChannels: selectSubscriptions(state),
|
||||||
|
allSubscriptions: selectSubscriptionClaims(state),
|
||||||
|
unreadSubscriptions: selectUnreadSubscriptions(state),
|
||||||
|
viewMode: selectViewMode(state),
|
||||||
|
firstRunCompleted: selectFirstRunCompleted(state),
|
||||||
|
showSuggestedSubs: selectShowSuggestedSubs(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
{
|
||||||
|
doFetchMySubscriptions,
|
||||||
|
doSetViewMode,
|
||||||
|
doFetchRecommendedSubscriptions,
|
||||||
|
doCompleteFirstRun,
|
||||||
|
doShowSuggestedSubs,
|
||||||
|
}
|
||||||
|
)(SubscriptionsPage);
|
89
app/src/page/subscriptions/view.js
Normal file
89
app/src/page/subscriptions/view.js
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import React from 'react';
|
||||||
|
import NavigationActions from 'react-navigation';
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
AsyncStorage,
|
||||||
|
FlatList,
|
||||||
|
NativeModules,
|
||||||
|
SectionList,
|
||||||
|
Text,
|
||||||
|
View
|
||||||
|
} from 'react-native';
|
||||||
|
import { buildURI } from 'lbry-redux';
|
||||||
|
import { uriFromFileInfo } from 'utils/helper';
|
||||||
|
import moment from 'moment';
|
||||||
|
import Colors from 'styles/colors';
|
||||||
|
import discoverStyle from 'styles/discover';
|
||||||
|
import subscriptionsStyle from 'styles/subscriptions';
|
||||||
|
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
||||||
|
import FileItem from 'component/fileItem';
|
||||||
|
import UriBar from 'component/uriBar';
|
||||||
|
|
||||||
|
class SubscriptionsPage extends React.PureComponent {
|
||||||
|
componentDidMount() {
|
||||||
|
const {
|
||||||
|
doFetchMySubscriptions,
|
||||||
|
doFetchRecommendedSubscriptions
|
||||||
|
} = this.props;
|
||||||
|
doFetchMySubscriptions();
|
||||||
|
doFetchRecommendedSubscriptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
subscribedChannels,
|
||||||
|
allSubscriptions,
|
||||||
|
loading,
|
||||||
|
viewMode,
|
||||||
|
doSetViewMode,
|
||||||
|
loadingSuggested,
|
||||||
|
firstRunCompleted,
|
||||||
|
doCompleteFirstRun,
|
||||||
|
doShowSuggestedSubs,
|
||||||
|
showSuggestedSubs,
|
||||||
|
unreadSubscriptions,
|
||||||
|
navigation
|
||||||
|
} = this.props;
|
||||||
|
const numberOfSubscriptions = subscribedChannels ? subscribedChannels.length : 0;
|
||||||
|
const hasSubscriptions = numberOfSubscriptions > 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={subscriptionsStyle.container}>
|
||||||
|
|
||||||
|
{hasSubscriptions && !loading &&
|
||||||
|
<FlatList
|
||||||
|
style={subscriptionsStyle.scrollContainer}
|
||||||
|
contentContainerStyle={subscriptionsStyle.scrollPadding}
|
||||||
|
renderItem={ ({item}) => (
|
||||||
|
<FileItem
|
||||||
|
style={subscriptionsStyle.fileItem}
|
||||||
|
mediaStyle={discoverStyle.fileItemMedia}
|
||||||
|
key={item}
|
||||||
|
uri={uriFromFileInfo(item)}
|
||||||
|
navigation={navigation} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
data={allSubscriptions}
|
||||||
|
keyExtractor={(item, index) => uriFromFileInfo(item)} />}
|
||||||
|
|
||||||
|
{hasSubscriptions && loading &&
|
||||||
|
<View style={subscriptionsStyle.busyContainer}>
|
||||||
|
<ActivityIndicator size="large" color={Colors.LbryGreen} style={subscriptionsStyle.loading} />
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
|
||||||
|
{!hasSubscriptions &&
|
||||||
|
<View style={subscriptionsStyle.busyContainer}>
|
||||||
|
<Text style={subscriptionsStyle.infoText}>
|
||||||
|
You are not subscribed to any channels. Feel free to discover new channels that you can subscribe to.
|
||||||
|
</Text>
|
||||||
|
</View>}
|
||||||
|
|
||||||
|
<FloatingWalletBalance navigation={navigation} />
|
||||||
|
<UriBar navigation={navigation} />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SubscriptionsPage;
|
|
@ -154,11 +154,18 @@ const filePageStyle = StyleSheet.create({
|
||||||
fileActions: {
|
fileActions: {
|
||||||
alignSelf: 'flex-end'
|
alignSelf: 'flex-end'
|
||||||
},
|
},
|
||||||
|
socialActions: {
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
actionButton: {
|
actionButton: {
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
backgroundColor: Colors.White,
|
backgroundColor: Colors.White,
|
||||||
paddingLeft: 24,
|
paddingLeft: 16,
|
||||||
paddingRight: 24
|
paddingRight: 16
|
||||||
|
},
|
||||||
|
subscribeButton: {
|
||||||
|
marginRight: 8
|
||||||
},
|
},
|
||||||
loading: {
|
loading: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|
33
app/src/styles/subscriptions.js
Normal file
33
app/src/styles/subscriptions.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
const subscriptionsStyle = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
busyContainer: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
|
padding: 16
|
||||||
|
},
|
||||||
|
scrollContainer: {
|
||||||
|
flex: 1,
|
||||||
|
marginBottom: 60
|
||||||
|
},
|
||||||
|
scrollPadding: {
|
||||||
|
paddingTop: 24
|
||||||
|
},
|
||||||
|
infoText: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
fileItem: {
|
||||||
|
marginLeft: 24,
|
||||||
|
marginRight: 24,
|
||||||
|
marginBottom: 24
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default subscriptionsStyle;
|
|
@ -1,4 +1,5 @@
|
||||||
import { NavigationActions, StackActions } from 'react-navigation';
|
import { NavigationActions, StackActions } from 'react-navigation';
|
||||||
|
import { buildURI } from 'lbry-redux';
|
||||||
import Constants from '../constants';
|
import Constants from '../constants';
|
||||||
|
|
||||||
function getRouteForSpecialUri(uri) {
|
function getRouteForSpecialUri(uri) {
|
||||||
|
@ -83,3 +84,11 @@ export function navigateToUri(navigation, uri, additionalParams) {
|
||||||
|
|
||||||
navigation.navigate({ routeName: 'File', key: uri, params });
|
navigation.navigate({ routeName: 'File', key: uri, params });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function uriFromFileInfo(fileInfo) {
|
||||||
|
const { name: claimName, claim_name: claimNameDownloaded, claim_id: claimId } = fileInfo;
|
||||||
|
const uriParams = {};
|
||||||
|
uriParams.contentName = claimName || claimNameDownloaded;
|
||||||
|
uriParams.claimId = claimId;
|
||||||
|
return buildURI(uriParams);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue