Next RC #57
36 changed files with 434 additions and 247 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -5640,8 +5640,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lbry-redux": {
|
"lbry-redux": {
|
||||||
"version": "github:lbryio/lbry-redux#7ec72a737bcd336f000c5f5085891643110298c3",
|
"version": "github:lbryio/lbry-redux#9919a8150998822ca997cd23418f023d64d4a3da",
|
||||||
"from": "github:lbryio/lbry-redux#7ec72a737bcd336f000c5f5085891643110298c3",
|
"from": "github:lbryio/lbry-redux#9919a8150998822ca997cd23418f023d64d4a3da",
|
||||||
"requires": {
|
"requires": {
|
||||||
"proxy-polyfill": "0.1.6",
|
"proxy-polyfill": "0.1.6",
|
||||||
"reselect": "^3.0.0",
|
"reselect": "^3.0.0",
|
||||||
|
@ -5649,8 +5649,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lbryinc": {
|
"lbryinc": {
|
||||||
"version": "github:lbryio/lbryinc#c55a2c98ab92c72149c824ee5906aed4404fd89b",
|
"version": "github:lbryio/lbryinc#aebad10a9c5d725c3fedae4236d56f239a0bc1de",
|
||||||
"from": "github:lbryio/lbryinc#c55a2c98ab92c72149c824ee5906aed4404fd89b",
|
"from": "github:lbryio/lbryinc#aebad10a9c5d725c3fedae4236d56f239a0bc1de",
|
||||||
"requires": {
|
"requires": {
|
||||||
"reselect": "^3.0.0"
|
"reselect": "^3.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
"base-64": "^0.1.0",
|
"base-64": "^0.1.0",
|
||||||
"@expo/vector-icons": "^8.1.0",
|
"@expo/vector-icons": "^8.1.0",
|
||||||
"gfycat-style-urls": "^1.0.3",
|
"gfycat-style-urls": "^1.0.3",
|
||||||
"lbry-redux": "lbryio/lbry-redux#7ec72a737bcd336f000c5f5085891643110298c3",
|
"lbry-redux": "lbryio/lbry-redux#9919a8150998822ca997cd23418f023d64d4a3da",
|
||||||
"lbryinc": "lbryio/lbryinc#c55a2c98ab92c72149c824ee5906aed4404fd89b",
|
"lbryinc": "lbryio/lbryinc#aebad10a9c5d725c3fedae4236d56f239a0bc1de",
|
||||||
"lodash": ">=4.17.11",
|
"lodash": ">=4.17.11",
|
||||||
"merge": ">=1.2.1",
|
"merge": ">=1.2.1",
|
||||||
"moment": "^2.22.1",
|
"moment": "^2.22.1",
|
||||||
|
|
|
@ -29,7 +29,7 @@ import {
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { AppState, BackHandler, Linking, NativeModules, TextInput, ToastAndroid } from 'react-native';
|
import { AppState, BackHandler, Linking, NativeModules, TextInput, ToastAndroid } from 'react-native';
|
||||||
import { selectDrawerStack } from 'redux/selectors/drawer';
|
import { selectDrawerStack } from 'redux/selectors/drawer';
|
||||||
import { SETTINGS, doDismissToast, doPopulateSharedUserState, doToast, selectToast } from 'lbry-redux';
|
import { SETTINGS, doDismissToast, doPopulateSharedUserState, doPreferenceGet, doToast, selectToast } from 'lbry-redux';
|
||||||
import {
|
import {
|
||||||
Lbryio,
|
Lbryio,
|
||||||
doGetSync,
|
doGetSync,
|
||||||
|
@ -39,6 +39,7 @@ import {
|
||||||
selectEmailToVerify,
|
selectEmailToVerify,
|
||||||
selectEmailVerifyIsPending,
|
selectEmailVerifyIsPending,
|
||||||
selectEmailVerifyErrorMessage,
|
selectEmailVerifyErrorMessage,
|
||||||
|
selectHashChanged,
|
||||||
selectUser,
|
selectUser,
|
||||||
} from 'lbryinc';
|
} from 'lbryinc';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
@ -53,6 +54,8 @@ import discoverStyle from 'styles/discover';
|
||||||
import searchStyle from 'styles/search';
|
import searchStyle from 'styles/search';
|
||||||
import SearchRightHeaderIcon from 'component/searchRightHeaderIcon';
|
import SearchRightHeaderIcon from 'component/searchRightHeaderIcon';
|
||||||
|
|
||||||
|
const SYNC_GET_INTERVAL = 1000 * 60 * 5; // every 5 minutes
|
||||||
|
|
||||||
const menuNavigationButton = navigation => (
|
const menuNavigationButton = navigation => (
|
||||||
<NavigationButton
|
<NavigationButton
|
||||||
name="bars"
|
name="bars"
|
||||||
|
@ -269,9 +272,11 @@ class AppWithNavigationState extends React.Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.emailVerifyCheckInterval = null;
|
this.emailVerifyCheckInterval = null;
|
||||||
|
this.syncGetInterval = null;
|
||||||
this.state = {
|
this.state = {
|
||||||
emailVerifyDone: false,
|
emailVerifyDone: false,
|
||||||
verifyPending: false,
|
verifyPending: false,
|
||||||
|
syncHashChanged: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,8 +297,17 @@ class AppWithNavigationState extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
const { dispatch } = this.props;
|
||||||
this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000);
|
this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000);
|
||||||
Linking.addEventListener('url', this._handleUrl);
|
Linking.addEventListener('url', this._handleUrl);
|
||||||
|
|
||||||
|
// call /sync/get with interval
|
||||||
|
this.syncGetInterval = setInterval(() => {
|
||||||
|
this.setState({ syncHashChanged: false }); // reset local state
|
||||||
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(walletPassword => {
|
||||||
|
dispatch(doGetSync(walletPassword, () => this.getUserSettings()));
|
||||||
|
});
|
||||||
|
}, SYNC_GET_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkEmailVerification = () => {
|
checkEmailVerification = () => {
|
||||||
|
@ -308,19 +322,31 @@ class AppWithNavigationState extends React.Component {
|
||||||
|
|
||||||
getUserSettings = () => {
|
getUserSettings = () => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
Lbryio.call('user_settings', 'get').then(settings => {
|
doPreferenceGet(
|
||||||
dispatch(doPopulateSharedUserState(settings));
|
'shared',
|
||||||
});
|
preference => {
|
||||||
|
dispatch(doPopulateSharedUserState(preference));
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
/* failed */
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
AppState.removeEventListener('change', this._handleAppStateChange);
|
AppState.removeEventListener('change', this._handleAppStateChange);
|
||||||
BackHandler.removeEventListener('hardwareBackPress');
|
BackHandler.removeEventListener('hardwareBackPress');
|
||||||
Linking.removeEventListener('url', this._handleUrl);
|
Linking.removeEventListener('url', this._handleUrl);
|
||||||
|
if (this.emailVerifyCheckInterval > -1) {
|
||||||
|
clearInterval(this.emailVerifyCheckInterval);
|
||||||
|
}
|
||||||
|
if (this.syncGetInterval > -1) {
|
||||||
|
clearInterval(this.syncGetInterval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const { dispatch, user } = this.props;
|
const { dispatch, user, hashChanged } = this.props;
|
||||||
if (this.state.verifyPending && this.emailVerifyCheckInterval > 0 && user && user.has_verified_email) {
|
if (this.state.verifyPending && this.emailVerifyCheckInterval > 0 && user && user.has_verified_email) {
|
||||||
clearInterval(this.emailVerifyCheckInterval);
|
clearInterval(this.emailVerifyCheckInterval);
|
||||||
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'false');
|
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'false');
|
||||||
|
@ -332,6 +358,11 @@ class AppWithNavigationState extends React.Component {
|
||||||
// get user settings after email verification
|
// get user settings after email verification
|
||||||
this.getUserSettings();
|
this.getUserSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hashChanged && !this.state.syncHashChanged) {
|
||||||
|
this.setState({ syncHashChanged: true });
|
||||||
|
this.getUserSettings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUpdate(nextProps) {
|
componentWillUpdate(nextProps) {
|
||||||
|
@ -438,6 +469,7 @@ class AppWithNavigationState extends React.Component {
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
backgroundPlayEnabled: makeSelectClientSetting(SETTINGS.BACKGROUND_PLAY_ENABLED)(state),
|
backgroundPlayEnabled: makeSelectClientSetting(SETTINGS.BACKGROUND_PLAY_ENABLED)(state),
|
||||||
|
hashChanged: selectHashChanged(state),
|
||||||
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
|
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
|
||||||
nav: state.nav,
|
nav: state.nav,
|
||||||
toast: selectToast(state),
|
toast: selectToast(state),
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
doCreateChannel,
|
doCreateChannel,
|
||||||
doToast,
|
doToast,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
|
import { doGetSync } from 'lbryinc';
|
||||||
import ChannelSelector from './view';
|
import ChannelSelector from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -19,6 +20,7 @@ const perform = dispatch => ({
|
||||||
notify: data => dispatch(doToast(data)),
|
notify: data => dispatch(doToast(data)),
|
||||||
createChannel: (name, amount) => dispatch(doCreateChannel(name, amount)),
|
createChannel: (name, amount) => dispatch(doCreateChannel(name, amount)),
|
||||||
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
||||||
|
getSync: (password, callback) => dispatch(doGetSync(password, callback)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CLAIM_VALUES, isNameValid } from 'lbry-redux';
|
import { CLAIM_VALUES, isNameValid } from 'lbry-redux';
|
||||||
import { ActivityIndicator, Picker, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
import { ActivityIndicator, NativeModules, Picker, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
||||||
|
import { logPublish } from 'utils/helper';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
|
@ -117,7 +118,7 @@ export default class ChannelSelector extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCreateChannelClick = () => {
|
handleCreateChannelClick = () => {
|
||||||
const { balance, createChannel, onChannelChange, notify } = this.props;
|
const { balance, createChannel, getSync, onChannelChange, notify } = this.props;
|
||||||
const { newChannelBid, newChannelName } = this.state;
|
const { newChannelBid, newChannelName } = this.state;
|
||||||
|
|
||||||
if (newChannelName.trim().length === 0 || !isNameValid(newChannelName.substr(1), false)) {
|
if (newChannelName.trim().length === 0 || !isNameValid(newChannelName.substr(1), false)) {
|
||||||
|
@ -142,17 +143,21 @@ export default class ChannelSelector extends React.PureComponent {
|
||||||
createChannelError: undefined,
|
createChannelError: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const success = () => {
|
const success = channelClaim => {
|
||||||
this.setState({
|
this.setState({
|
||||||
creatingChannel: false,
|
creatingChannel: false,
|
||||||
addingChannel: false,
|
addingChannel: false,
|
||||||
currentSelectedValue: channelName,
|
currentSelectedValue: channelName,
|
||||||
showCreateChannel: false,
|
showCreateChannel: false,
|
||||||
});
|
});
|
||||||
|
logPublish(channelClaim);
|
||||||
|
|
||||||
if (onChannelChange) {
|
if (onChannelChange) {
|
||||||
onChannelChange(channelName);
|
onChannelChange(channelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sync wallet
|
||||||
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(password => getSync(password));
|
||||||
};
|
};
|
||||||
|
|
||||||
const failure = () => {
|
const failure = () => {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import claimListStyle from 'styles/claimList';
|
||||||
import discoverStyle from 'styles/discover';
|
import discoverStyle from 'styles/discover';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
const horizontalLimit = 7;
|
const horizontalLimit = 10;
|
||||||
const softLimit = 500;
|
const softLimit = 500;
|
||||||
|
|
||||||
class ClaimList extends React.PureComponent {
|
class ClaimList extends React.PureComponent {
|
||||||
|
|
|
@ -10,13 +10,15 @@ import {
|
||||||
makeSelectClaimIsNsfw,
|
makeSelectClaimIsNsfw,
|
||||||
makeSelectShortUrlForUri,
|
makeSelectShortUrlForUri,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectRewardContentClaimIds } from 'lbryinc';
|
import { selectBlackListedOutpoints, selectFilteredOutpoints, selectRewardContentClaimIds } from 'lbryinc';
|
||||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||||
import FileItem from './view';
|
import FileItem from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
|
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||||
claim: makeSelectClaimForUri(props.uri)(state),
|
claim: makeSelectClaimForUri(props.uri)(state),
|
||||||
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
||||||
|
filteredOutpoints: selectFilteredOutpoints(state),
|
||||||
metadata: makeSelectMetadataForUri(props.uri)(state),
|
metadata: makeSelectMetadataForUri(props.uri)(state),
|
||||||
rewardedContentClaimIds: selectRewardContentClaimIds(state),
|
rewardedContentClaimIds: selectRewardContentClaimIds(state),
|
||||||
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
|
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
|
||||||
|
|
|
@ -40,10 +40,12 @@ class FileItem extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
blackListedOutpoints,
|
||||||
claim,
|
claim,
|
||||||
title,
|
title,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
fileInfo,
|
fileInfo,
|
||||||
|
filteredOutpoints,
|
||||||
metadata,
|
metadata,
|
||||||
isResolvingUri,
|
isResolvingUri,
|
||||||
rewardedContentClaimIds,
|
rewardedContentClaimIds,
|
||||||
|
@ -58,7 +60,17 @@ class FileItem extends React.PureComponent {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (claim && claim.value_type === 'channel') {
|
if (claim && claim.value_type === 'channel') {
|
||||||
// don't display channels in the lists on the Explore page
|
// don't display channels in the lists on the Your tags page
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shouldHide = false;
|
||||||
|
if (blackListedOutpoints || filteredOutpoints) {
|
||||||
|
const outpointsToHide = blackListedOutpoints.concat(filteredOutpoints);
|
||||||
|
shouldHide = outpointsToHide.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout);
|
||||||
|
}
|
||||||
|
if (shouldHide) {
|
||||||
|
// don't display blacklisted or filtered outpoints on the Your tags page
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ class FloatingWalletBalance extends React.PureComponent<Props> {
|
||||||
<Icon name="coins" size={12} style={floatingButtonStyle.balanceIcon} />
|
<Icon name="coins" size={12} style={floatingButtonStyle.balanceIcon} />
|
||||||
{isNaN(balance) && <ActivityIndicator size="small" color={Colors.White} />}
|
{isNaN(balance) && <ActivityIndicator size="small" color={Colors.White} />}
|
||||||
{(!isNaN(balance) || balance === 0) && (
|
{(!isNaN(balance) || balance === 0) && (
|
||||||
<Text style={floatingButtonStyle.text}>{formatCredits(parseFloat(balance), 0, true)}</Text>
|
<Text style={floatingButtonStyle.text}>{formatCredits(parseFloat(balance), 1, true)}</Text>
|
||||||
)}
|
)}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -4,8 +4,10 @@ import {
|
||||||
selectSearchState as selectSearch,
|
selectSearchState as selectSearch,
|
||||||
selectSearchValue,
|
selectSearchValue,
|
||||||
selectSearchSuggestions,
|
selectSearchSuggestions,
|
||||||
|
SETTINGS,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectCurrentRoute } from 'redux/selectors/drawer';
|
import { selectCurrentRoute } from 'redux/selectors/drawer';
|
||||||
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import UriBar from './view';
|
import UriBar from './view';
|
||||||
|
|
||||||
const select = state => {
|
const select = state => {
|
||||||
|
@ -16,6 +18,7 @@ const select = state => {
|
||||||
query: selectSearchValue(state),
|
query: selectSearchValue(state),
|
||||||
currentRoute: selectCurrentRoute(state),
|
currentRoute: selectCurrentRoute(state),
|
||||||
suggestions: selectSearchSuggestions(state),
|
suggestions: selectSearchSuggestions(state),
|
||||||
|
showUriBarSuggestions: makeSelectClientSetting(SETTINGS.SHOW_URI_BAR_SUGGESTIONS)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,10 @@ class UriBarItem extends React.PureComponent {
|
||||||
icon = <Icon name="search" size={18} />;
|
icon = <Icon name="search" size={18} />;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SEARCH_TYPES.TAG:
|
||||||
|
icon = <Icon name="hashtag" size={18} />;
|
||||||
|
break;
|
||||||
|
|
||||||
case SEARCH_TYPES.FILE:
|
case SEARCH_TYPES.FILE:
|
||||||
default:
|
default:
|
||||||
icon = <Icon name="file" size={18} />;
|
icon = <Icon name="file" size={18} />;
|
||||||
|
@ -37,6 +41,7 @@ class UriBarItem extends React.PureComponent {
|
||||||
{type === SEARCH_TYPES.SEARCH && `Search for '${value}'`}
|
{type === SEARCH_TYPES.SEARCH && `Search for '${value}'`}
|
||||||
{type === SEARCH_TYPES.CHANNEL && `View the @${shorthand} channel`}
|
{type === SEARCH_TYPES.CHANNEL && `View the @${shorthand} channel`}
|
||||||
{type === SEARCH_TYPES.FILE && `View content at ${value}`}
|
{type === SEARCH_TYPES.FILE && `View content at ${value}`}
|
||||||
|
{type === SEARCH_TYPES.TAG && `Explore the '${value}' tag`}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SEARCH_TYPES, isNameValid, isURIValid, normalizeURI } from 'lbry-redux';
|
import { SEARCH_TYPES, isNameValid, isURIValid, normalizeURI } from 'lbry-redux';
|
||||||
import { FlatList, Keyboard, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
import { Dimensions, FlatList, Keyboard, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
||||||
import { navigateToUri, transformUrl } from 'utils/helper';
|
import { navigateToUri, transformUrl } from 'utils/helper';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import UriBarItem from './internal/uri-bar-item';
|
import UriBarItem from './internal/uri-bar-item';
|
||||||
|
@ -14,6 +14,8 @@ class UriBar extends React.PureComponent {
|
||||||
|
|
||||||
textInput = null;
|
textInput = null;
|
||||||
|
|
||||||
|
keyboardDidShowListener = null;
|
||||||
|
|
||||||
keyboardDidHideListener = null;
|
keyboardDidHideListener = null;
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -21,17 +23,19 @@ class UriBar extends React.PureComponent {
|
||||||
currentValue: null,
|
currentValue: null,
|
||||||
inputText: null,
|
inputText: null,
|
||||||
focused: false,
|
focused: false,
|
||||||
|
keyboardHeight: 0,
|
||||||
// TODO: Add a setting to enable / disable direct search?
|
|
||||||
directSearch: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
|
||||||
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
|
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
|
||||||
this.setSelection();
|
this.setSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
if (this.keyboardDidShowListener) {
|
||||||
|
this.keyboardDidShowListener.remove();
|
||||||
|
}
|
||||||
if (this.keyboardDidHideListener) {
|
if (this.keyboardDidHideListener) {
|
||||||
this.keyboardDidHideListener.remove();
|
this.keyboardDidHideListener.remove();
|
||||||
}
|
}
|
||||||
|
@ -49,16 +53,18 @@ class UriBar extends React.PureComponent {
|
||||||
handleChangeText = text => {
|
handleChangeText = text => {
|
||||||
const newValue = text || '';
|
const newValue = text || '';
|
||||||
clearTimeout(this.state.changeTextTimeout);
|
clearTimeout(this.state.changeTextTimeout);
|
||||||
const { updateSearchQuery, onSearchSubmitted, navigation } = this.props;
|
const { updateSearchQuery, onSearchSubmitted, showUriBarSuggestions, navigation } = this.props;
|
||||||
|
|
||||||
let timeout = setTimeout(() => {
|
updateSearchQuery(text);
|
||||||
|
|
||||||
|
let timeout = -1;
|
||||||
|
if (!showUriBarSuggestions) {
|
||||||
|
timeout = setTimeout(() => {
|
||||||
if (text.trim().length === 0) {
|
if (text.trim().length === 0) {
|
||||||
// don't do anything if the text is empty
|
// don't do anything if the text is empty
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSearchQuery(text);
|
|
||||||
|
|
||||||
if (!text.startsWith('lbry://')) {
|
if (!text.startsWith('lbry://')) {
|
||||||
// not a URI input, so this is a search, perform a direct search
|
// not a URI input, so this is a search, perform a direct search
|
||||||
if (onSearchSubmitted) {
|
if (onSearchSubmitted) {
|
||||||
|
@ -68,6 +74,7 @@ class UriBar extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, UriBar.INPUT_TIMEOUT);
|
}, UriBar.INPUT_TIMEOUT);
|
||||||
|
}
|
||||||
this.setState({ inputText: newValue, currentValue: newValue, changeTextTimeout: timeout });
|
this.setState({ inputText: newValue, currentValue: newValue, changeTextTimeout: timeout });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,18 +93,34 @@ class UriBar extends React.PureComponent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigation.navigate({ routeName: 'Search', key: 'searchPage', params: { searchQuery: value } });
|
navigation.navigate({
|
||||||
|
routeName: Constants.DRAWER_ROUTE_SEARCH,
|
||||||
|
key: 'searchPage',
|
||||||
|
params: { searchQuery: value },
|
||||||
|
});
|
||||||
|
} else if (SEARCH_TYPES.TAG === type) {
|
||||||
|
navigation.navigate({
|
||||||
|
routeName: Constants.DRAWER_ROUTE_TAG,
|
||||||
|
key: 'tagPage',
|
||||||
|
params: {
|
||||||
|
tag: value.toLowerCase(),
|
||||||
|
},
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const uri = normalizeURI(value);
|
const uri = normalizeURI(value);
|
||||||
navigateToUri(navigation, uri);
|
navigateToUri(navigation, uri);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_keyboardDidShow = evt => {
|
||||||
|
this.setState({ keyboardHeight: evt.endCoordinates.height });
|
||||||
|
};
|
||||||
|
|
||||||
_keyboardDidHide = () => {
|
_keyboardDidHide = () => {
|
||||||
if (this.textInput) {
|
if (this.textInput) {
|
||||||
this.textInput.blur();
|
this.textInput.blur();
|
||||||
}
|
}
|
||||||
this.setState({ focused: false });
|
this.setState({ focused: false, keyboardHeight: 0 });
|
||||||
};
|
};
|
||||||
|
|
||||||
setSelection() {
|
setSelection() {
|
||||||
|
@ -152,16 +175,18 @@ class UriBar extends React.PureComponent {
|
||||||
selectedItemCount,
|
selectedItemCount,
|
||||||
selectionMode,
|
selectionMode,
|
||||||
suggestions,
|
suggestions,
|
||||||
|
showUriBarSuggestions,
|
||||||
value,
|
value,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (this.state.currentValue === null) {
|
if (this.state.currentValue === null) {
|
||||||
this.setState({ currentValue: value });
|
this.setState({ currentValue: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
let style = [uriBarStyle.overlay, belowOverlay ? null : uriBarStyle.overlayElevated];
|
let style = [
|
||||||
|
uriBarStyle.overlay,
|
||||||
// TODO: Add optional setting to enable URI / search bar suggestions
|
belowOverlay ? null : uriBarStyle.overlayElevated,
|
||||||
/* if (this.state.focused) { style.push(uriBarStyle.inFocus); } */
|
this.state.focused && showUriBarSuggestions ? uriBarStyle.inFocus : null,
|
||||||
|
];
|
||||||
|
|
||||||
// TODO: selectionModeActions should be dynamically created / specified
|
// TODO: selectionModeActions should be dynamically created / specified
|
||||||
return (
|
return (
|
||||||
|
@ -248,21 +273,22 @@ class UriBar extends React.PureComponent {
|
||||||
onSubmitEditing={this.handleSubmitEditing}
|
onSubmitEditing={this.handleSubmitEditing}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{this.state.focused && !this.state.directSearch && (
|
</View>
|
||||||
<View style={uriBarStyle.suggestions}>
|
{this.state.focused && showUriBarSuggestions && (
|
||||||
<FlatList
|
<FlatList
|
||||||
style={uriBarStyle.suggestionList}
|
style={[
|
||||||
|
uriBarStyle.suggestions,
|
||||||
|
{ height: Dimensions.get('window').height - this.state.keyboardHeight - 60 },
|
||||||
|
]}
|
||||||
data={suggestions}
|
data={suggestions}
|
||||||
keyboardShouldPersistTaps={'handled'}
|
keyboardShouldPersistTaps={'handled'}
|
||||||
keyExtractor={(item, value) => item.value}
|
keyExtractor={(item, value) => `${item.value}-${item.type}`}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<UriBarItem item={item} navigation={navigation} onPress={() => this.handleItemPress(item)} />
|
<UriBarItem item={item} navigation={navigation} onPress={() => this.handleItemPress(item)} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</View>
|
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ const Constants = {
|
||||||
ABOUT_TAB: 'about',
|
ABOUT_TAB: 'about',
|
||||||
|
|
||||||
KEY_FIRST_RUN_EMAIL: 'firstRunEmail',
|
KEY_FIRST_RUN_EMAIL: 'firstRunEmail',
|
||||||
KEY_FIRST_RUN_PASSWORD: 'firstRunPassword',
|
KEY_WALLET_PASSWORD: 'firstRunPassword',
|
||||||
KEY_FIRST_USER_AUTH: 'firstUserAuth',
|
KEY_FIRST_USER_AUTH: 'firstUserAuth',
|
||||||
KEY_SHOULD_VERIFY_EMAIL: 'shouldVerifyEmail',
|
KEY_SHOULD_VERIFY_EMAIL: 'shouldVerifyEmail',
|
||||||
KEY_EMAIL_VERIFY_PENDING: 'emailVerifyPending',
|
KEY_EMAIL_VERIFY_PENDING: 'emailVerifyPending',
|
||||||
|
|
84
src/index.js
84
src/index.js
|
@ -4,6 +4,8 @@ import { Provider, connect } from 'react-redux';
|
||||||
import { AppRegistry, Text, View, NativeModules } from 'react-native';
|
import { AppRegistry, Text, View, NativeModules } from 'react-native';
|
||||||
import {
|
import {
|
||||||
Lbry,
|
Lbry,
|
||||||
|
buildSharedStateMiddleware,
|
||||||
|
blockedReducer,
|
||||||
claimsReducer,
|
claimsReducer,
|
||||||
contentReducer,
|
contentReducer,
|
||||||
fileReducer,
|
fileReducer,
|
||||||
|
@ -13,19 +15,24 @@ import {
|
||||||
searchReducer,
|
searchReducer,
|
||||||
tagsReducer,
|
tagsReducer,
|
||||||
walletReducer,
|
walletReducer,
|
||||||
|
ACTIONS as LBRY_REDUX_ACTIONS,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import {
|
import {
|
||||||
Lbryio,
|
Lbryio,
|
||||||
authReducer,
|
authReducer,
|
||||||
blacklistReducer,
|
blacklistReducer,
|
||||||
costInfoReducer,
|
costInfoReducer,
|
||||||
|
doGetSync,
|
||||||
filteredReducer,
|
filteredReducer,
|
||||||
homepageReducer,
|
homepageReducer,
|
||||||
rewardsReducer,
|
rewardsReducer,
|
||||||
|
selectUserVerifiedEmail,
|
||||||
subscriptionsReducer,
|
subscriptionsReducer,
|
||||||
syncReducer,
|
syncReducer,
|
||||||
userReducer,
|
userReducer,
|
||||||
|
LBRYINC_ACTIONS,
|
||||||
} from 'lbryinc';
|
} from 'lbryinc';
|
||||||
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import { createStore, applyMiddleware, compose } from 'redux';
|
import { createStore, applyMiddleware, compose } from 'redux';
|
||||||
import AppWithNavigationState, {
|
import AppWithNavigationState, {
|
||||||
AppNavigator,
|
AppNavigator,
|
||||||
|
@ -33,6 +40,7 @@ import AppWithNavigationState, {
|
||||||
reactNavigationMiddleware,
|
reactNavigationMiddleware,
|
||||||
} from 'component/AppNavigator';
|
} from 'component/AppNavigator';
|
||||||
import { REHYDRATE, PURGE, persistCombineReducers, persistStore } from 'redux-persist';
|
import { REHYDRATE, PURGE, persistCombineReducers, persistStore } from 'redux-persist';
|
||||||
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import getStoredStateMigrateV4 from 'redux-persist/lib/integration/getStoredStateMigrateV4';
|
import getStoredStateMigrateV4 from 'redux-persist/lib/integration/getStoredStateMigrateV4';
|
||||||
import FilesystemStorage from 'redux-persist-filesystem-storage';
|
import FilesystemStorage from 'redux-persist-filesystem-storage';
|
||||||
import createCompressor from 'redux-persist-transform-compress';
|
import createCompressor from 'redux-persist-transform-compress';
|
||||||
|
@ -42,7 +50,6 @@ import formReducer from 'redux/reducers/form';
|
||||||
import drawerReducer from 'redux/reducers/drawer';
|
import drawerReducer from 'redux/reducers/drawer';
|
||||||
import settingsReducer from 'redux/reducers/settings';
|
import settingsReducer from 'redux/reducers/settings';
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import isEqual from 'utils/deep-equal';
|
|
||||||
|
|
||||||
const globalExceptionHandler = (error, isFatal) => {
|
const globalExceptionHandler = (error, isFatal) => {
|
||||||
if (error && NativeModules.Firebase) {
|
if (error && NativeModules.Firebase) {
|
||||||
|
@ -81,6 +88,7 @@ function enableBatching(reducer) {
|
||||||
|
|
||||||
const compressor = createCompressor();
|
const compressor = createCompressor();
|
||||||
const authFilter = createFilter('auth', ['authToken']);
|
const authFilter = createFilter('auth', ['authToken']);
|
||||||
|
const blockedFilter = createFilter('blocked', ['blockedChannels']);
|
||||||
const contentFilter = createFilter('content', ['positions']);
|
const contentFilter = createFilter('content', ['positions']);
|
||||||
const saveClaimsFilter = createFilter('claims', ['claimsByUri']);
|
const saveClaimsFilter = createFilter('claims', ['claimsByUri']);
|
||||||
const subscriptionsFilter = createFilter('subscriptions', ['enabledChannelNotifications', 'subscriptions', 'latest']);
|
const subscriptionsFilter = createFilter('subscriptions', ['enabledChannelNotifications', 'subscriptions', 'latest']);
|
||||||
|
@ -89,10 +97,18 @@ const tagsFilter = createFilter('tags', ['followedTags']);
|
||||||
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
||||||
|
|
||||||
const v4PersistOptions = {
|
const v4PersistOptions = {
|
||||||
whitelist: ['auth', 'claims', 'content', 'subscriptions', 'settings', 'tags', 'wallet'],
|
whitelist: ['auth', 'blocked', 'claims', 'content', 'subscriptions', 'settings', 'tags', 'wallet'],
|
||||||
// Order is important. Needs to be compressed last or other transforms can't
|
// Order is important. Needs to be compressed last or other transforms can't
|
||||||
// read the data
|
// read the data
|
||||||
transforms: [authFilter, saveClaimsFilter, subscriptionsFilter, settingsFilter, walletFilter, compressor],
|
transforms: [
|
||||||
|
authFilter,
|
||||||
|
blockedFilter,
|
||||||
|
saveClaimsFilter,
|
||||||
|
subscriptionsFilter,
|
||||||
|
settingsFilter,
|
||||||
|
walletFilter,
|
||||||
|
compressor,
|
||||||
|
],
|
||||||
debounce: 10000,
|
debounce: 10000,
|
||||||
storage: FilesystemStorage,
|
storage: FilesystemStorage,
|
||||||
};
|
};
|
||||||
|
@ -105,6 +121,7 @@ const persistOptions = Object.assign({}, v4PersistOptions, {
|
||||||
const reducers = persistCombineReducers(persistOptions, {
|
const reducers = persistCombineReducers(persistOptions, {
|
||||||
auth: authReducer,
|
auth: authReducer,
|
||||||
blacklist: blacklistReducer,
|
blacklist: blacklistReducer,
|
||||||
|
blocked: blockedReducer,
|
||||||
claims: claimsReducer,
|
claims: claimsReducer,
|
||||||
content: contentReducer,
|
content: contentReducer,
|
||||||
costInfo: costInfoReducer,
|
costInfo: costInfoReducer,
|
||||||
|
@ -127,8 +144,45 @@ const reducers = persistCombineReducers(persistOptions, {
|
||||||
wallet: walletReducer,
|
wallet: walletReducer,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* source: the reducer name
|
||||||
|
* property: the property in the reducer-specific state
|
||||||
|
* transform: optional method to modify the value to be stored
|
||||||
|
*/
|
||||||
|
const sharedStateActions = [
|
||||||
|
LBRYINC_ACTIONS.CHANNEL_SUBSCRIBE,
|
||||||
|
LBRYINC_ACTIONS.CHANNEL_UNSUBSCRIBE,
|
||||||
|
LBRY_REDUX_ACTIONS.CREATE_CHANNEL_COMPLETED,
|
||||||
|
LBRY_REDUX_ACTIONS.TOGGLE_TAG_FOLLOW,
|
||||||
|
LBRY_REDUX_ACTIONS.TOGGLE_BLOCK_CHANNEL,
|
||||||
|
];
|
||||||
|
const sharedStateFilters = {
|
||||||
|
tags: { source: 'tags', property: 'followedTags' },
|
||||||
|
subscriptions: {
|
||||||
|
source: 'subscriptions',
|
||||||
|
property: 'subscriptions',
|
||||||
|
transform: function(value) {
|
||||||
|
return value.map(({ uri }) => uri);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
blocked: { source: 'blocked', property: 'blockedChannels' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const sharedStateCallback = ({ dispatch, getState }) => {
|
||||||
|
const state = getState();
|
||||||
|
const syncEnabled = makeSelectClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED)(state);
|
||||||
|
const emailVerified = selectUserVerifiedEmail(state);
|
||||||
|
if (syncEnabled && emailVerified) {
|
||||||
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(password =>
|
||||||
|
dispatch(doGetSync(password))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sharedStateMiddleware = buildSharedStateMiddleware(sharedStateActions, sharedStateFilters, sharedStateCallback);
|
||||||
|
|
||||||
const bulkThunk = createBulkThunkMiddleware();
|
const bulkThunk = createBulkThunkMiddleware();
|
||||||
const middleware = [thunk, bulkThunk, reactNavigationMiddleware];
|
const middleware = [sharedStateMiddleware, thunk, bulkThunk, reactNavigationMiddleware];
|
||||||
|
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
const composeEnhancers = compose;
|
const composeEnhancers = compose;
|
||||||
|
@ -147,28 +201,6 @@ const persistor = persistStore(store, persistOptions, err => {
|
||||||
});
|
});
|
||||||
window.persistor = persistor;
|
window.persistor = persistor;
|
||||||
|
|
||||||
let currentPayload;
|
|
||||||
store.subscribe(() => {
|
|
||||||
const state = store.getState();
|
|
||||||
const subscriptions = state.subscriptions.subscriptions.map(({ uri }) => uri);
|
|
||||||
const tags = state.tags.followedTags;
|
|
||||||
|
|
||||||
const newPayload = {
|
|
||||||
version: '0.1',
|
|
||||||
shared: {
|
|
||||||
subscriptions,
|
|
||||||
tags,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!isEqual(newPayload, currentPayload)) {
|
|
||||||
currentPayload = newPayload;
|
|
||||||
if (Lbryio.authToken) {
|
|
||||||
Lbryio.call('user_settings', 'set', { settings: JSON.stringify(newPayload) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Find i18n module that is compatible with react-native
|
// TODO: Find i18n module that is compatible with react-native
|
||||||
global.__ = str => str;
|
global.__ = str => str;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
doUpdateChannel,
|
doUpdateChannel,
|
||||||
doToast,
|
doToast,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
|
import { doGetSync } from 'lbryinc';
|
||||||
import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
||||||
import { doUpdateChannelFormState, doClearChannelFormState } from 'redux/actions/form';
|
import { doUpdateChannelFormState, doClearChannelFormState } from 'redux/actions/form';
|
||||||
import { selectDrawerStack } from 'redux/selectors/drawer';
|
import { selectDrawerStack } from 'redux/selectors/drawer';
|
||||||
|
@ -37,6 +38,7 @@ const perform = dispatch => ({
|
||||||
clearChannelFormState: () => dispatch(doClearChannelFormState()),
|
clearChannelFormState: () => dispatch(doClearChannelFormState()),
|
||||||
createChannel: (name, amount, optionalParams) => dispatch(doCreateChannel(name, amount, optionalParams)),
|
createChannel: (name, amount, optionalParams) => dispatch(doCreateChannel(name, amount, optionalParams)),
|
||||||
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
||||||
|
getSync: (password, callback) => dispatch(doGetSync(password, callback)),
|
||||||
updateChannel: params => dispatch(doUpdateChannel(params)),
|
updateChannel: params => dispatch(doUpdateChannel(params)),
|
||||||
updateChannelFormState: data => dispatch(doUpdateChannelFormState(data)),
|
updateChannelFormState: data => dispatch(doUpdateChannelFormState(data)),
|
||||||
pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
|
pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { navigateToUri, uploadImageAsset } from 'utils/helper';
|
import { navigateToUri, logPublish, uploadImageAsset } from 'utils/helper';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import ChannelIconItem from 'component/channelIconItem';
|
import ChannelIconItem from 'component/channelIconItem';
|
||||||
import ChannelRewardsDriver from 'component/channelRewardsDriver';
|
import ChannelRewardsDriver from 'component/channelRewardsDriver';
|
||||||
|
@ -375,7 +375,15 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCreateChannelClick = () => {
|
handleCreateChannelClick = () => {
|
||||||
const { balance, clearChannelFormState, createChannel, onChannelChange, notify, updateChannel } = this.props;
|
const {
|
||||||
|
balance,
|
||||||
|
clearChannelFormState,
|
||||||
|
createChannel,
|
||||||
|
onChannelChange,
|
||||||
|
getSync,
|
||||||
|
notify,
|
||||||
|
updateChannel,
|
||||||
|
} = this.props;
|
||||||
const {
|
const {
|
||||||
claimId,
|
claimId,
|
||||||
coverImageUrl,
|
coverImageUrl,
|
||||||
|
@ -432,7 +440,7 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
createChannelError: undefined,
|
createChannelError: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const success = () => {
|
const success = channelClaim => {
|
||||||
this.setState({
|
this.setState({
|
||||||
creatingChannel: false,
|
creatingChannel: false,
|
||||||
addingChannel: false,
|
addingChannel: false,
|
||||||
|
@ -448,6 +456,8 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
clearChannelFormState();
|
clearChannelFormState();
|
||||||
notify({ message: 'The channel was successfully created.' });
|
notify({ message: 'The channel was successfully created.' });
|
||||||
this.showChannelList();
|
this.showChannelList();
|
||||||
|
|
||||||
|
logPublish(channelClaim);
|
||||||
};
|
};
|
||||||
|
|
||||||
const failure = () => {
|
const failure = () => {
|
||||||
|
|
|
@ -517,7 +517,7 @@ class FilePage extends React.PureComponent {
|
||||||
const { claim, notify } = this.props;
|
const { claim, notify } = this.props;
|
||||||
if (claim) {
|
if (claim) {
|
||||||
const { canonical_url: canonicalUrl, short_url: shortUrl, permanent_url: permanentUrl } = claim;
|
const { canonical_url: canonicalUrl, short_url: shortUrl, permanent_url: permanentUrl } = claim;
|
||||||
const url = 'https://lbry.tv' + this.formatLbryUrlForWeb(canonicalUrl || shortUrl || permanentUrl);
|
const url = 'https://open.lbry.com' + this.formatLbryUrlForWeb(canonicalUrl || shortUrl || permanentUrl);
|
||||||
NativeModules.UtilityModule.shareUrl(url);
|
NativeModules.UtilityModule.shareUrl(url);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -950,15 +950,23 @@ class FilePage extends React.PureComponent {
|
||||||
|
|
||||||
<View style={filePageStyle.largeButtonsRow}>
|
<View style={filePageStyle.largeButtonsRow}>
|
||||||
<TouchableOpacity style={filePageStyle.largeButton} onPress={this.handleSharePress}>
|
<TouchableOpacity style={filePageStyle.largeButton} onPress={this.handleSharePress}>
|
||||||
<Icon name={'share-alt'} size={24} style={filePageStyle.largeButtonIcon} />
|
<Icon name={'share-alt'} size={20} style={filePageStyle.largeButtonIcon} />
|
||||||
<Text style={filePageStyle.largeButtonText}>Share</Text>
|
<Text style={filePageStyle.largeButtonText}>Share</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={filePageStyle.largeButton}
|
||||||
|
onPress={() => this.setState({ showTipView: true })}
|
||||||
|
>
|
||||||
|
<Icon name={'gift'} size={20} style={filePageStyle.largeButtonIcon} />
|
||||||
|
<Text style={filePageStyle.largeButtonText}>Tip</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={filePageStyle.largeButton}
|
style={filePageStyle.largeButton}
|
||||||
onPress={() => Linking.openURL(`https://lbry.com/dmca/${claim.claim_id}`)}
|
onPress={() => Linking.openURL(`https://lbry.com/dmca/${claim.claim_id}`)}
|
||||||
>
|
>
|
||||||
<Icon name={'flag'} size={24} style={filePageStyle.largeButtonIcon} />
|
<Icon name={'flag'} size={20} style={filePageStyle.largeButtonIcon} />
|
||||||
<Text style={filePageStyle.largeButtonText}>Report</Text>
|
<Text style={filePageStyle.largeButtonText}>Report</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
@ -999,12 +1007,6 @@ class FilePage extends React.PureComponent {
|
||||||
onPress={this.onSaveFilePressed}
|
onPress={this.onSaveFilePressed}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Button
|
|
||||||
style={[filePageStyle.actionButton, filePageStyle.tipButton]}
|
|
||||||
theme={'light'}
|
|
||||||
icon={'gift'}
|
|
||||||
onPress={() => this.setState({ showTipView: true })}
|
|
||||||
/>
|
|
||||||
{channelName && (
|
{channelName && (
|
||||||
<SubscribeButton
|
<SubscribeButton
|
||||||
style={filePageStyle.actionButton}
|
style={filePageStyle.actionButton}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {
|
||||||
doAuthenticate,
|
doAuthenticate,
|
||||||
doCheckSync,
|
doCheckSync,
|
||||||
doGetSync,
|
doGetSync,
|
||||||
doSetDefaultAccount,
|
|
||||||
doSyncApply,
|
doSyncApply,
|
||||||
doUserEmailNew,
|
doUserEmailNew,
|
||||||
doUserResendVerificationEmail,
|
doUserResendVerificationEmail,
|
||||||
|
@ -41,12 +40,11 @@ const select = state => ({
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
addUserEmail: email => dispatch(doUserEmailNew(email)),
|
addUserEmail: email => dispatch(doUserEmailNew(email)),
|
||||||
authenticate: (appVersion, os) => dispatch(doAuthenticate(appVersion, os)),
|
authenticate: (appVersion, os, firebaseToken) => dispatch(doAuthenticate(appVersion, os, firebaseToken)),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
syncApply: (hash, data, password) => dispatch(doSyncApply(hash, data, password)),
|
syncApply: (hash, data, password) => dispatch(doSyncApply(hash, data, password)),
|
||||||
getSync: password => dispatch(doGetSync(password)),
|
getSync: (password, callback) => dispatch(doGetSync(password, callback)),
|
||||||
checkSync: () => dispatch(doCheckSync()),
|
checkSync: () => dispatch(doCheckSync()),
|
||||||
setDefaultAccount: (success, failure) => dispatch(doSetDefaultAccount(success, failure)),
|
|
||||||
notify: data => dispatch(doToast(data)),
|
notify: data => dispatch(doToast(data)),
|
||||||
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
|
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
View,
|
View,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants';
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
import firstRunStyle from 'styles/firstRun';
|
import firstRunStyle from 'styles/firstRun';
|
||||||
|
|
||||||
|
@ -45,8 +45,8 @@ class SkipAccountPage extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Text style={firstRunStyle.rowParagraph}>
|
<Text style={firstRunStyle.rowParagraph}>
|
||||||
I understand that by uninstalling LBRY I will lose any balances or published content with no recovery
|
I understand that by uninstalling LBRY I will lose any balances or published content with no recovery option
|
||||||
option if it is not backed up manually (see wallet page)
|
if it is not backed up manually (see wallet page)
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
import { BarPasswordStrengthDisplay } from 'react-native-password-strength-meter';
|
import { BarPasswordStrengthDisplay } from 'react-native-password-strength-meter';
|
||||||
import AsyncStorage from '@react-native-community/async-storage';
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants';
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import firstRunStyle from 'styles/firstRun';
|
import firstRunStyle from 'styles/firstRun';
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
|
|
||||||
|
@ -62,7 +62,14 @@ class WalletPage extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { onPasswordChanged, onWalletViewLayout, getSyncIsPending, hasSyncedWallet, syncApplyIsPending } = this.props;
|
const {
|
||||||
|
onPasswordChanged,
|
||||||
|
onWalletViewLayout,
|
||||||
|
getSyncIsPending,
|
||||||
|
hasSyncedWallet,
|
||||||
|
syncApplyIsPending,
|
||||||
|
syncApplyStarted,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
if (!this.state.walletReady || !this.state.hasCheckedSync || getSyncIsPending) {
|
if (!this.state.walletReady || !this.state.hasCheckedSync || getSyncIsPending) {
|
||||||
|
@ -72,11 +79,11 @@ class WalletPage extends React.PureComponent {
|
||||||
<Text style={firstRunStyle.paragraph}>Retrieving your account information...</Text>
|
<Text style={firstRunStyle.paragraph}>Retrieving your account information...</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
} else if (syncApplyIsPending) {
|
} else if (syncApplyStarted || syncApplyIsPending) {
|
||||||
content = (
|
content = (
|
||||||
<View style={firstRunStyle.centered}>
|
<View style={firstRunStyle.centered}>
|
||||||
<ActivityIndicator size="large" color={Colors.White} style={firstRunStyle.waiting} />
|
<ActivityIndicator size="large" color={Colors.White} style={firstRunStyle.waiting} />
|
||||||
<Text style={firstRunStyle.paragraph}>Validating password...</Text>
|
<Text style={firstRunStyle.paragraph}>{syncApplyIsPending ? 'Validating password' : 'Synchronizing'}...</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Lbry } from 'lbry-redux';
|
||||||
import { ActivityIndicator, NativeModules, Platform, Text, View } from 'react-native';
|
import { ActivityIndicator, NativeModules, Platform, Text, View } from 'react-native';
|
||||||
import AsyncStorage from '@react-native-community/async-storage';
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants';
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import firstRunStyle from 'styles/firstRun';
|
import firstRunStyle from 'styles/firstRun';
|
||||||
|
|
||||||
class WelcomePage extends React.PureComponent {
|
class WelcomePage extends React.PureComponent {
|
||||||
|
@ -25,7 +25,7 @@ class WelcomePage extends React.PureComponent {
|
||||||
} else {
|
} else {
|
||||||
// first_user_auth because it's the first time
|
// first_user_auth because it's the first time
|
||||||
AsyncStorage.getItem(Constants.KEY_FIRST_USER_AUTH).then(firstUserAuth => {
|
AsyncStorage.getItem(Constants.KEY_FIRST_USER_AUTH).then(firstUserAuth => {
|
||||||
if ('true' !== firstUserAuth) {
|
if (firstUserAuth !== 'true') {
|
||||||
// first_user_auth
|
// first_user_auth
|
||||||
NativeModules.Firebase.track('first_user_auth', null);
|
NativeModules.Firebase.track('first_user_auth', null);
|
||||||
AsyncStorage.setItem(Constants.KEY_FIRST_USER_AUTH, 'true');
|
AsyncStorage.setItem(Constants.KEY_FIRST_USER_AUTH, 'true');
|
||||||
|
@ -47,11 +47,12 @@ class WelcomePage extends React.PureComponent {
|
||||||
const { authenticate } = this.props;
|
const { authenticate } = this.props;
|
||||||
this.setState({ authenticationStarted: true, authenticationFailed: false });
|
this.setState({ authenticationStarted: true, authenticationFailed: false });
|
||||||
NativeModules.VersionInfo.getAppVersion().then(appVersion => {
|
NativeModules.VersionInfo.getAppVersion().then(appVersion => {
|
||||||
|
NativeModules.Firebase.getMessagingToken().then(firebaseToken => {
|
||||||
Lbry.status()
|
Lbry.status()
|
||||||
.then(info => {
|
.then(info => {
|
||||||
this.setState({ sdkStarted: true });
|
this.setState({ sdkStarted: true });
|
||||||
|
|
||||||
authenticate(appVersion, Platform.OS);
|
authenticate(appVersion, Platform.OS, firebaseToken);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (this.state.statusTries >= WelcomePage.MAX_STATUS_TRIES) {
|
if (this.state.statusTries >= WelcomePage.MAX_STATUS_TRIES) {
|
||||||
|
@ -67,6 +68,7 @@ class WelcomePage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -66,7 +66,7 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
const { emailNewErrorMessage, emailNewPending, syncApplyErrorMessage, syncApplyIsPending, user } = nextProps;
|
const { emailNewErrorMessage, emailNewPending, syncApplyErrorMessage, syncApplyIsPending, user } = nextProps;
|
||||||
const { notify, isApplyingSync, setClientSetting, setDefaultAccount } = this.props;
|
const { notify, isApplyingSync, setClientSetting } = this.props;
|
||||||
|
|
||||||
if (this.state.emailSubmitted && !emailNewPending) {
|
if (this.state.emailSubmitted && !emailNewPending) {
|
||||||
this.setState({ emailSubmitted: false });
|
this.setState({ emailSubmitted: false });
|
||||||
|
@ -81,32 +81,33 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
|
|
||||||
if (this.state.syncApplyStarted && !syncApplyIsPending) {
|
if (this.state.syncApplyStarted && !syncApplyIsPending) {
|
||||||
if (syncApplyErrorMessage && syncApplyErrorMessage.trim().length > 0) {
|
if (syncApplyErrorMessage && syncApplyErrorMessage.trim().length > 0) {
|
||||||
notify({ message: syncApplyErrorMessage, syncApplyStarted: false, isError: true });
|
notify({ message: syncApplyErrorMessage, isError: true });
|
||||||
this.setState({ showBottomContainer: true });
|
this.setState({ showBottomContainer: true, syncApplyStarted: false });
|
||||||
} else {
|
} else {
|
||||||
// password successfully verified
|
// password successfully verified
|
||||||
NativeModules.UtilityModule.setSecureValue(
|
NativeModules.UtilityModule.setSecureValue(
|
||||||
Constants.KEY_FIRST_RUN_PASSWORD,
|
Constants.KEY_WALLET_PASSWORD,
|
||||||
this.state.walletPassword ? this.state.walletPassword : ''
|
this.state.walletPassword ? this.state.walletPassword : ''
|
||||||
);
|
);
|
||||||
setDefaultAccount(
|
|
||||||
() => {
|
|
||||||
setClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED, true);
|
|
||||||
|
|
||||||
|
setClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED, true);
|
||||||
|
Lbry.wallet_status().then(status => {
|
||||||
// unlock the wallet
|
// unlock the wallet
|
||||||
Lbry.account_unlock({ password: this.state.walletPassword ? this.state.walletPassword : '' })
|
if (status.is_locked) {
|
||||||
.then(() => this.closeFinalPage())
|
Lbry.wallet_unlock({ password: this.state.walletPassword ? this.state.walletPassword : '' }).then(
|
||||||
.catch(err =>
|
unlocked => {
|
||||||
notify({ message: 'The wallet could not be unlocked at this time. Please restart the app.' })
|
if (unlocked) {
|
||||||
);
|
this.closeFinalPage();
|
||||||
},
|
} else {
|
||||||
err => {
|
notify({ message: 'The wallet could not be unlocked at this time. Please restart the app.' });
|
||||||
notify({
|
}
|
||||||
message:
|
|
||||||
'The account restore operation could not be completed successfully. Please restart the app and try again.',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
// wallet not locked. close final page
|
||||||
|
this.closeFinalPage();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,9 +133,9 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
const resetAction = StackActions.reset({
|
const resetAction = StackActions.reset({
|
||||||
index: 0,
|
index: 0,
|
||||||
actions: [NavigationActions.navigate({ routeName: 'Splash', params: { launchUri: this.state.launchUri } })],
|
actions: [NavigationActions.navigate({ routeName: 'Splash', params: { launchUri: this.state.launchUrl } })],
|
||||||
});
|
});
|
||||||
navigation.dispatch(resetAction);
|
setTimeout(() => navigation.dispatch(resetAction), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLeftButtonPressed = () => {
|
handleLeftButtonPressed = () => {
|
||||||
|
@ -298,8 +299,8 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
const { getSync, setClientSetting } = this.props;
|
const { getSync, setClientSetting } = this.props;
|
||||||
if (NativeModules.UtilityModule) {
|
if (NativeModules.UtilityModule) {
|
||||||
const newPassword = this.state.walletPassword ? this.state.walletPassword : '';
|
const newPassword = this.state.walletPassword ? this.state.walletPassword : '';
|
||||||
NativeModules.UtilityModule.setSecureValue(Constants.KEY_FIRST_RUN_PASSWORD, newPassword);
|
NativeModules.UtilityModule.setSecureValue(Constants.KEY_WALLET_PASSWORD, newPassword);
|
||||||
Lbry.account_encrypt({ new_password: newPassword }).then(() => {
|
Lbry.wallet_encrypt({ new_password: newPassword }).then(() => {
|
||||||
// fresh account, new password set
|
// fresh account, new password set
|
||||||
getSync(newPassword);
|
getSync(newPassword);
|
||||||
setClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED, true);
|
setClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED, true);
|
||||||
|
@ -367,6 +368,7 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
hasSyncedWallet={hasSyncedWallet}
|
hasSyncedWallet={hasSyncedWallet}
|
||||||
getSyncIsPending={getSyncIsPending}
|
getSyncIsPending={getSyncIsPending}
|
||||||
syncApplyIsPending={syncApplyIsPending}
|
syncApplyIsPending={syncApplyIsPending}
|
||||||
|
syncApplyStarted={this.state.syncApplyStarted}
|
||||||
onWalletViewLayout={this.onWalletViewLayout}
|
onWalletViewLayout={this.onWalletViewLayout}
|
||||||
onPasswordChanged={this.onWalletPasswordChanged}
|
onPasswordChanged={this.onWalletPasswordChanged}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -43,7 +43,7 @@ import Tag from 'component/tag';
|
||||||
import TagSearch from 'component/tagSearch';
|
import TagSearch from 'component/tagSearch';
|
||||||
import UriBar from 'component/uriBar';
|
import UriBar from 'component/uriBar';
|
||||||
import publishStyle from 'styles/publish';
|
import publishStyle from 'styles/publish';
|
||||||
import { __, navigateToUri, uploadImageAsset } from 'utils/helper';
|
import { __, navigateToUri, logPublish, uploadImageAsset } from 'utils/helper';
|
||||||
|
|
||||||
const languages = {
|
const languages = {
|
||||||
en: 'English',
|
en: 'English',
|
||||||
|
@ -371,7 +371,7 @@ class PublishPage extends React.PureComponent {
|
||||||
filePath: currentMedia ? currentMedia.filePath : null,
|
filePath: currentMedia ? currentMedia.filePath : null,
|
||||||
bid: bid || 0.1,
|
bid: bid || 0.1,
|
||||||
title: title || '',
|
title: title || '',
|
||||||
thumbnail,
|
thumbnail: thumbnail || '',
|
||||||
description: description || '',
|
description: description || '',
|
||||||
language,
|
language,
|
||||||
license,
|
license,
|
||||||
|
@ -395,6 +395,11 @@ class PublishPage extends React.PureComponent {
|
||||||
|
|
||||||
handlePublishSuccess = data => {
|
handlePublishSuccess = data => {
|
||||||
const { clearPublishFormState, navigation, notify } = this.props;
|
const { clearPublishFormState, navigation, notify } = this.props;
|
||||||
|
const pendingClaim = data.outputs[0];
|
||||||
|
logPublish(pendingClaim);
|
||||||
|
|
||||||
|
// TODO: fake temp claim for claim_list_mine
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
message: `Your content was successfully published to ${this.state.uri}. It will be available in a few mintues.`,
|
message: `Your content was successfully published to ${this.state.uri}. It will be available in a few mintues.`,
|
||||||
});
|
});
|
||||||
|
@ -404,6 +409,7 @@ class PublishPage extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePublishFailure = error => {
|
handlePublishFailure = error => {
|
||||||
|
console.log(error);
|
||||||
const { notify } = this.props;
|
const { notify } = this.props;
|
||||||
notify({ message: __('Your content could not be published at this time. Please try again.') });
|
notify({ message: __('Your content could not be published at this time. Please try again.') });
|
||||||
this.setState({ publishStarted: false });
|
this.setState({ publishStarted: false });
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/a
|
||||||
import { doSetClientSetting } from 'redux/actions/settings';
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
import { selectCurrentRoute, selectDrawerStack } from 'redux/selectors/drawer';
|
import { selectCurrentRoute, selectDrawerStack } from 'redux/selectors/drawer';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import Constants from 'constants';
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import SettingsPage from './view';
|
import SettingsPage from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -13,6 +13,7 @@ const select = state => ({
|
||||||
drawerStack: selectDrawerStack(state),
|
drawerStack: selectDrawerStack(state),
|
||||||
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
|
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
|
||||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state),
|
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state),
|
||||||
|
showUriBarSuggestions: makeSelectClientSetting(SETTINGS.SHOW_URI_BAR_SUGGESTIONS)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -51,6 +51,7 @@ class SettingsPage extends React.PureComponent {
|
||||||
navigation,
|
navigation,
|
||||||
popDrawerStack,
|
popDrawerStack,
|
||||||
showNsfw,
|
showNsfw,
|
||||||
|
showUriBarSuggestions,
|
||||||
setClientSetting,
|
setClientSetting,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ class SettingsPage extends React.PureComponent {
|
||||||
<View style={settingsStyle.container}>
|
<View style={settingsStyle.container}>
|
||||||
<PageHeader title={'Settings'} onBackPressed={() => navigateBack(navigation, drawerStack, popDrawerStack)} />
|
<PageHeader title={'Settings'} onBackPressed={() => navigateBack(navigation, drawerStack, popDrawerStack)} />
|
||||||
<ScrollView style={settingsStyle.scrollContainer}>
|
<ScrollView style={settingsStyle.scrollContainer}>
|
||||||
|
<Text style={settingsStyle.sectionTitle}>Content</Text>
|
||||||
<View style={settingsStyle.row}>
|
<View style={settingsStyle.row}>
|
||||||
<View style={settingsStyle.switchText}>
|
<View style={settingsStyle.switchText}>
|
||||||
<Text style={settingsStyle.label}>Enable background media playback</Text>
|
<Text style={settingsStyle.label}>Enable background media playback</Text>
|
||||||
|
@ -79,13 +81,29 @@ class SettingsPage extends React.PureComponent {
|
||||||
|
|
||||||
<View style={settingsStyle.row}>
|
<View style={settingsStyle.row}>
|
||||||
<View style={settingsStyle.switchText}>
|
<View style={settingsStyle.switchText}>
|
||||||
<Text style={settingsStyle.label}>Show NSFW content</Text>
|
<Text style={settingsStyle.label}>Show mature content</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={settingsStyle.switchContainer}>
|
<View style={settingsStyle.switchContainer}>
|
||||||
<Switch value={showNsfw} onValueChange={value => setClientSetting(SETTINGS.SHOW_NSFW, value)} />
|
<Switch value={showNsfw} onValueChange={value => setClientSetting(SETTINGS.SHOW_NSFW, value)} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
<View style={settingsStyle.sectionDivider} />
|
||||||
|
<Text style={settingsStyle.sectionTitle}>Search</Text>
|
||||||
|
<View style={settingsStyle.row}>
|
||||||
|
<View style={settingsStyle.switchText}>
|
||||||
|
<Text style={settingsStyle.label}>Show URL suggestions</Text>
|
||||||
|
</View>
|
||||||
|
<View style={settingsStyle.switchContainer}>
|
||||||
|
<Switch
|
||||||
|
value={showUriBarSuggestions}
|
||||||
|
onValueChange={value => setClientSetting(SETTINGS.SHOW_URI_BAR_SUGGESTIONS, value)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={settingsStyle.sectionDivider} />
|
||||||
|
<Text style={settingsStyle.sectionTitle}>Other</Text>
|
||||||
<View style={settingsStyle.row}>
|
<View style={settingsStyle.row}>
|
||||||
<View style={settingsStyle.switchText}>
|
<View style={settingsStyle.switchText}>
|
||||||
<Text style={settingsStyle.label}>Keep the daemon background service running after closing the app</Text>
|
<Text style={settingsStyle.label}>Keep the daemon background service running after closing the app</Text>
|
||||||
|
|
|
@ -23,14 +23,14 @@ const select = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
authenticate: (appVersion, os) => dispatch(doAuthenticate(appVersion, os)),
|
authenticate: (appVersion, os, firebaseToken) => dispatch(doAuthenticate(appVersion, os, firebaseToken)),
|
||||||
balanceSubscribe: () => dispatch(doBalanceSubscribe()),
|
balanceSubscribe: () => dispatch(doBalanceSubscribe()),
|
||||||
blacklistedOutpointsSubscribe: () => dispatch(doBlackListedOutpointsSubscribe()),
|
blacklistedOutpointsSubscribe: () => dispatch(doBlackListedOutpointsSubscribe()),
|
||||||
filteredOutpointsSubscribe: () => dispatch(doFilteredOutpointsSubscribe()),
|
filteredOutpointsSubscribe: () => dispatch(doFilteredOutpointsSubscribe()),
|
||||||
checkSubscriptionsInit: () => dispatch(doCheckSubscriptionsInit()),
|
checkSubscriptionsInit: () => dispatch(doCheckSubscriptionsInit()),
|
||||||
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
|
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
|
||||||
fetchSubscriptions: callback => dispatch(doFetchMySubscriptions(callback)),
|
fetchSubscriptions: callback => dispatch(doFetchMySubscriptions(callback)),
|
||||||
getSync: password => dispatch(doGetSync(password)),
|
getSync: (password, callback) => dispatch(doGetSync(password, callback)),
|
||||||
notify: data => dispatch(doToast(data)),
|
notify: data => dispatch(doToast(data)),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
setEmailToVerify: email => dispatch(doUserEmailToVerify(email)),
|
setEmailToVerify: email => dispatch(doUserEmailToVerify(email)),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Lbry } from 'lbry-redux';
|
import { Lbry, doPreferenceGet } from 'lbry-redux';
|
||||||
import { Lbryio } from 'lbryinc';
|
import { Lbryio } from 'lbryinc';
|
||||||
import { ActivityIndicator, Linking, NativeModules, Platform, Text, View } from 'react-native';
|
import { ActivityIndicator, Linking, NativeModules, Platform, Text, View } from 'react-native';
|
||||||
import { NavigationActions, StackActions } from 'react-navigation';
|
import { NavigationActions, StackActions } from 'react-navigation';
|
||||||
|
@ -16,8 +16,6 @@ import splashStyle from 'styles/splash';
|
||||||
|
|
||||||
const BLOCK_HEIGHT_INTERVAL = 1000 * 60 * 2.5; // every 2.5 minutes
|
const BLOCK_HEIGHT_INTERVAL = 1000 * 60 * 2.5; // every 2.5 minutes
|
||||||
|
|
||||||
const SETTINGS_GET_INTERVAL = 1000 * 60 * 5; // every 5 minutes
|
|
||||||
|
|
||||||
const testingNetwork = 'Testing network';
|
const testingNetwork = 'Testing network';
|
||||||
const waitingForResolution = 'Waiting for name resolution';
|
const waitingForResolution = 'Waiting for name resolution';
|
||||||
|
|
||||||
|
@ -40,12 +38,6 @@ class SplashScreen extends React.PureComponent {
|
||||||
subscriptionsFetched: false,
|
subscriptionsFetched: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
if (NativeModules.DaemonServiceControl) {
|
|
||||||
NativeModules.DaemonServiceControl.startService();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStatus() {
|
updateStatus() {
|
||||||
Lbry.status().then(status => {
|
Lbry.status().then(status => {
|
||||||
this._updateStatusCallback(status);
|
this._updateStatusCallback(status);
|
||||||
|
@ -60,7 +52,7 @@ class SplashScreen extends React.PureComponent {
|
||||||
});
|
});
|
||||||
navigation.dispatch(resetAction);
|
navigation.dispatch(resetAction);
|
||||||
|
|
||||||
const launchUrl = navigation.state.params.launchUrl || this.state.launchUrl;
|
const launchUrl = navigation.state.params ? navigation.state.params.launchUrl : this.state.launchUrl;
|
||||||
if (launchUrl) {
|
if (launchUrl) {
|
||||||
if (launchUrl.startsWith('lbry://?verify=')) {
|
if (launchUrl.startsWith('lbry://?verify=')) {
|
||||||
let verification = {};
|
let verification = {};
|
||||||
|
@ -91,18 +83,19 @@ class SplashScreen extends React.PureComponent {
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
const { emailToVerify, getSync, setEmailToVerify, verifyUserEmail, verifyUserEmailFailure } = this.props;
|
const { emailToVerify, getSync, setEmailToVerify, verifyUserEmail, verifyUserEmailFailure } = this.props;
|
||||||
|
const { daemonReady, shouldAuthenticate } = this.state;
|
||||||
const { user } = nextProps;
|
const { user } = nextProps;
|
||||||
|
|
||||||
if (this.state.daemonReady && this.state.shouldAuthenticate && user && user.id) {
|
if (daemonReady && shouldAuthenticate && user && user.id) {
|
||||||
this.setState({ shouldAuthenticate: false }, () => {
|
this.setState({ shouldAuthenticate: false }, () => {
|
||||||
// user is authenticated, navigate to the main view
|
// user is authenticated, navigate to the main view
|
||||||
if (user.has_verified_email) {
|
if (user.has_verified_email) {
|
||||||
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(walletPassword => {
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(walletPassword => {
|
||||||
if (walletPassword) {
|
getSync(walletPassword, () => {
|
||||||
getSync(walletPassword);
|
this.getUserSettings();
|
||||||
}
|
|
||||||
this.navigateToMain();
|
this.navigateToMain();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,9 +106,16 @@ class SplashScreen extends React.PureComponent {
|
||||||
|
|
||||||
getUserSettings = () => {
|
getUserSettings = () => {
|
||||||
const { populateSharedUserState } = this.props;
|
const { populateSharedUserState } = this.props;
|
||||||
Lbryio.call('user_settings', 'get').then(settings => {
|
|
||||||
populateSharedUserState(settings);
|
doPreferenceGet(
|
||||||
});
|
'shared',
|
||||||
|
preference => {
|
||||||
|
populateSharedUserState(preference);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
/* failed */
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
finishSplashScreen = () => {
|
finishSplashScreen = () => {
|
||||||
|
@ -137,22 +137,20 @@ class SplashScreen extends React.PureComponent {
|
||||||
filteredOutpointsSubscribe();
|
filteredOutpointsSubscribe();
|
||||||
checkSubscriptionsInit();
|
checkSubscriptionsInit();
|
||||||
|
|
||||||
// get user settings interval
|
|
||||||
this.getUserSettings();
|
|
||||||
setInterval(() => this.getUserSettings(), SETTINGS_GET_INTERVAL);
|
|
||||||
|
|
||||||
if (user && user.id && user.has_verified_email) {
|
if (user && user.id && user.has_verified_email) {
|
||||||
// user already authenticated
|
// user already authenticated
|
||||||
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(walletPassword => {
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(walletPassword => {
|
||||||
if (walletPassword) {
|
getSync(walletPassword, err => {
|
||||||
getSync(walletPassword);
|
this.getUserSettings();
|
||||||
}
|
|
||||||
this.navigateToMain();
|
this.navigateToMain();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
NativeModules.VersionInfo.getAppVersion().then(appVersion => {
|
NativeModules.VersionInfo.getAppVersion().then(appVersion => {
|
||||||
|
NativeModules.Firebase.getMessagingToken().then(firebaseToken => {
|
||||||
this.setState({ shouldAuthenticate: true });
|
this.setState({ shouldAuthenticate: true });
|
||||||
authenticate(appVersion, Platform.OS);
|
authenticate(appVersion, Platform.OS, firebaseToken);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -181,24 +179,27 @@ class SplashScreen extends React.PureComponent {
|
||||||
isRunning: true,
|
isRunning: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Lbry.wallet_status().then(secureWalletStatus => {
|
||||||
// For now, automatically unlock the wallet if a password is set so that downloads work
|
// For now, automatically unlock the wallet if a password is set so that downloads work
|
||||||
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(password => {
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(password => {
|
||||||
if (walletStatus.is_locked) {
|
if (secureWalletStatus.is_locked) {
|
||||||
this.setState({
|
this.setState({
|
||||||
message: 'Unlocking account',
|
message: 'Unlocking account',
|
||||||
details: 'Decrypting wallet',
|
details: 'Decrypting wallet',
|
||||||
});
|
});
|
||||||
|
|
||||||
// unlock the wallet and then finish the splash screen
|
// unlock the wallet and then finish the splash screen
|
||||||
Lbry.account_unlock({ password: password || '' })
|
Lbry.wallet_unlock({ password: password || '' }).then(unlocked => {
|
||||||
.then(() => {
|
if (unlocked) {
|
||||||
this.setState({
|
this.setState({
|
||||||
message: testingNetwork,
|
message: testingNetwork,
|
||||||
details: waitingForResolution,
|
details: waitingForResolution,
|
||||||
});
|
});
|
||||||
this.finishSplashScreen();
|
this.finishSplashScreen();
|
||||||
})
|
} else {
|
||||||
.catch(() => this.handleAccountUnlockFailed());
|
this.handleAccountUnlockFailed();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
message: testingNetwork,
|
message: testingNetwork,
|
||||||
|
@ -207,6 +208,7 @@ class SplashScreen extends React.PureComponent {
|
||||||
this.finishSplashScreen();
|
this.finishSplashScreen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -249,10 +251,7 @@ class SplashScreen extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (NativeModules.Firebase) {
|
|
||||||
NativeModules.Firebase.track('app_launch', null);
|
NativeModules.Firebase.track('app_launch', null);
|
||||||
}
|
|
||||||
|
|
||||||
NativeModules.Firebase.setCurrentScreen('Splash');
|
NativeModules.Firebase.setCurrentScreen('Splash');
|
||||||
|
|
||||||
this.props.fetchRewardedContent();
|
this.props.fetchRewardedContent();
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { doToast } from 'lbry-redux';
|
||||||
import {
|
import {
|
||||||
doCheckSync,
|
doCheckSync,
|
||||||
doGetSync,
|
doGetSync,
|
||||||
doSetDefaultAccount,
|
|
||||||
doSyncApply,
|
doSyncApply,
|
||||||
doUserEmailNew,
|
doUserEmailNew,
|
||||||
doUserEmailToVerify,
|
doUserEmailToVerify,
|
||||||
|
@ -55,12 +54,11 @@ const select = state => ({
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
addUserEmail: email => dispatch(doUserEmailNew(email)),
|
addUserEmail: email => dispatch(doUserEmailNew(email)),
|
||||||
addUserPhone: (phone, countryCode) => dispatch(doUserPhoneNew(phone, countryCode)),
|
addUserPhone: (phone, countryCode) => dispatch(doUserPhoneNew(phone, countryCode)),
|
||||||
getSync: password => dispatch(doGetSync(password)),
|
getSync: (password, callback) => dispatch(doGetSync(password, callback)),
|
||||||
checkSync: () => dispatch(doCheckSync()),
|
checkSync: () => dispatch(doCheckSync()),
|
||||||
verifyPhone: verificationCode => dispatch(doUserPhoneVerify(verificationCode)),
|
verifyPhone: verificationCode => dispatch(doUserPhoneVerify(verificationCode)),
|
||||||
notify: data => dispatch(doToast(data)),
|
notify: data => dispatch(doToast(data)),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
setDefaultAccount: (success, failure) => dispatch(doSetDefaultAccount(success, failure)),
|
|
||||||
setEmailToVerify: email => dispatch(doUserEmailToVerify(email)),
|
setEmailToVerify: email => dispatch(doUserEmailToVerify(email)),
|
||||||
syncApply: (hash, data, password) => dispatch(doSyncApply(hash, data, password)),
|
syncApply: (hash, data, password) => dispatch(doSyncApply(hash, data, password)),
|
||||||
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
|
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
|
||||||
|
|
|
@ -37,7 +37,7 @@ class SyncVerifyPage extends React.PureComponent {
|
||||||
if (!hasSyncedWallet) {
|
if (!hasSyncedWallet) {
|
||||||
// fresh account with no sync
|
// fresh account with no sync
|
||||||
const newPassword = this.state.password ? this.state.password : '';
|
const newPassword = this.state.password ? this.state.password : '';
|
||||||
Lbry.account_encrypt({ new_password: newPassword }).then(() => {
|
Lbry.wallet_encrypt({ new_password: newPassword }).then(() => {
|
||||||
getSync(newPassword);
|
getSync(newPassword);
|
||||||
setClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED, true);
|
setClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED, true);
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
|
@ -50,7 +50,7 @@ class SyncVerifyPage extends React.PureComponent {
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
const { getSyncIsPending, syncApplyIsPending, syncApplyErrorMessage } = nextProps;
|
const { getSyncIsPending, syncApplyIsPending, syncApplyErrorMessage } = nextProps;
|
||||||
const { getSync, hasSyncedWallet, navigation, notify, setClientSetting, setDefaultAccount } = this.props;
|
const { getSync, hasSyncedWallet, navigation, notify, setClientSetting } = this.props;
|
||||||
if (this.state.checkSyncStarted && !getSyncIsPending) {
|
if (this.state.checkSyncStarted && !getSyncIsPending) {
|
||||||
this.setState({ syncChecked: true });
|
this.setState({ syncChecked: true });
|
||||||
}
|
}
|
||||||
|
@ -63,17 +63,12 @@ class SyncVerifyPage extends React.PureComponent {
|
||||||
// password successfully verified
|
// password successfully verified
|
||||||
if (NativeModules.UtilityModule) {
|
if (NativeModules.UtilityModule) {
|
||||||
NativeModules.UtilityModule.setSecureValue(
|
NativeModules.UtilityModule.setSecureValue(
|
||||||
Constants.KEY_FIRST_RUN_PASSWORD,
|
Constants.KEY_WALLET_PASSWORD,
|
||||||
this.state.password ? this.state.password : ''
|
this.state.password ? this.state.password : ''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
setDefaultAccount(
|
|
||||||
() => this.finishSync(true),
|
this.finishSync(true);
|
||||||
err => {
|
|
||||||
// fail silently and still finish
|
|
||||||
this.finishSync();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,14 +79,16 @@ class SyncVerifyPage extends React.PureComponent {
|
||||||
setClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED, true);
|
setClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED, true);
|
||||||
|
|
||||||
// unlock the wallet (if locked)
|
// unlock the wallet (if locked)
|
||||||
Lbry.status().then(status => {
|
Lbry.wallet_status().then(status => {
|
||||||
if (status.wallet.is_locked) {
|
if (status.is_locked) {
|
||||||
Lbry.account_unlock({ password: this.state.password ? this.state.password : '' })
|
Lbry.wallet_unlock({ password: this.state.password ? this.state.password : '' }).then(unlocked => {
|
||||||
.then(() => navigation.goBack())
|
if (unlocked) {
|
||||||
.catch(err => {
|
navigation.goBack();
|
||||||
|
} else {
|
||||||
if (notifyUnlockFailed) {
|
if (notifyUnlockFailed) {
|
||||||
notify({ message: 'The wallet could not be unlocked at this time. Please restart the app.' });
|
notify({ message: 'The wallet could not be unlocked at this time. Please restart the app.' });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
|
|
|
@ -101,7 +101,6 @@ class VerificationScreen extends React.PureComponent {
|
||||||
notify,
|
notify,
|
||||||
addUserPhone,
|
addUserPhone,
|
||||||
getSyncIsPending,
|
getSyncIsPending,
|
||||||
setDefaultAccount,
|
|
||||||
hasSyncedWallet,
|
hasSyncedWallet,
|
||||||
setSyncIsPending,
|
setSyncIsPending,
|
||||||
syncApplyIsPending,
|
syncApplyIsPending,
|
||||||
|
@ -162,7 +161,6 @@ class VerificationScreen extends React.PureComponent {
|
||||||
notify={notify}
|
notify={notify}
|
||||||
setEmailVerificationPhase={this.setEmailVerificationPhase}
|
setEmailVerificationPhase={this.setEmailVerificationPhase}
|
||||||
setClientSetting={setClientSetting}
|
setClientSetting={setClientSetting}
|
||||||
setDefaultAccount={setDefaultAccount}
|
|
||||||
setSyncIsPending={setSyncIsPending}
|
setSyncIsPending={setSyncIsPending}
|
||||||
syncApplyIsPending={syncApplyIsPending}
|
syncApplyIsPending={syncApplyIsPending}
|
||||||
syncApplyErrorMessage={syncApplyErrorMessage}
|
syncApplyErrorMessage={syncApplyErrorMessage}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
||||||
import { selectCurrentRoute } from 'redux/selectors/drawer';
|
import { selectCurrentRoute } from 'redux/selectors/drawer';
|
||||||
import { selectBalance } from 'lbry-redux';
|
import { selectBalance } from 'lbry-redux';
|
||||||
import { doCheckSync, doGetSync, selectUser, selectHasSyncedWallet } from 'lbryinc';
|
import { doCheckSync, doGetSync, selectUser, selectHasSyncedWallet } from 'lbryinc';
|
||||||
import Constants from 'constants';
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import WalletPage from './view';
|
import WalletPage from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -21,7 +21,7 @@ const select = state => ({
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
checkSync: () => dispatch(doCheckSync()),
|
checkSync: () => dispatch(doCheckSync()),
|
||||||
getSync: password => dispatch(doGetSync(password)),
|
getSync: (password, callback) => dispatch(doGetSync(password, callback)),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_WALLET)),
|
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_WALLET)),
|
||||||
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
|
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
|
||||||
|
|
|
@ -46,10 +46,8 @@ class WalletPage extends React.PureComponent {
|
||||||
|
|
||||||
const { deviceWalletSynced, getSync, user } = this.props;
|
const { deviceWalletSynced, getSync, user } = this.props;
|
||||||
if (deviceWalletSynced && user && user.has_verified_email) {
|
if (deviceWalletSynced && user && user.has_verified_email) {
|
||||||
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(walletPassword => {
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(walletPassword => {
|
||||||
if (walletPassword) {
|
|
||||||
getSync(walletPassword);
|
getSync(walletPassword);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -384,6 +384,7 @@ const filePageStyle = StyleSheet.create({
|
||||||
largeButton: {
|
largeButton: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
marginRight: 48,
|
||||||
},
|
},
|
||||||
largeButtonIcon: {
|
largeButtonIcon: {
|
||||||
color: Colors.DescriptionGrey,
|
color: Colors.DescriptionGrey,
|
||||||
|
@ -396,8 +397,10 @@ const filePageStyle = StyleSheet.create({
|
||||||
largeButtonsRow: {
|
largeButtonsRow: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
marginLeft: 20,
|
||||||
margin: 16,
|
marginRight: 20,
|
||||||
|
marginTop: 12,
|
||||||
|
marginBottom: 12,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,14 @@ const settingsStyle = StyleSheet.create({
|
||||||
fontFamily: 'Inter-UI-Regular',
|
fontFamily: 'Inter-UI-Regular',
|
||||||
lineHeight: 18,
|
lineHeight: 18,
|
||||||
},
|
},
|
||||||
|
sectionTitle: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 20,
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
sectionDivider: {
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default settingsStyle;
|
export default settingsStyle;
|
||||||
|
|
|
@ -36,7 +36,7 @@ const uriBarStyle = StyleSheet.create({
|
||||||
},
|
},
|
||||||
overlay: {
|
overlay: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'red',
|
||||||
top: 0,
|
top: 0,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
zIndex: 200,
|
zIndex: 200,
|
||||||
|
@ -54,9 +54,10 @@ const uriBarStyle = StyleSheet.create({
|
||||||
item: {
|
item: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: 12,
|
paddingLeft: 16,
|
||||||
paddingTop: 8,
|
paddingRight: 16,
|
||||||
paddingBottom: 8,
|
paddingTop: 12,
|
||||||
|
paddingBottom: 12,
|
||||||
},
|
},
|
||||||
itemContent: {
|
itemContent: {
|
||||||
marginLeft: 12,
|
marginLeft: 12,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { NavigationActions, StackActions } from 'react-navigation';
|
import { NavigationActions, StackActions } from 'react-navigation';
|
||||||
import { buildURI, isURIValid, normalizeURI } from 'lbry-redux';
|
import { buildURI, isURIValid, normalizeURI } from 'lbry-redux';
|
||||||
|
import { Lbryio } from 'lbryinc';
|
||||||
import { doPopDrawerStack, doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
import { doPopDrawerStack, doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
||||||
import Constants, { DrawerRoutes, InnerDrawerRoutes } from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants, { DrawerRoutes, InnerDrawerRoutes } from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
|
|
||||||
|
@ -290,6 +291,23 @@ export function __(str) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function logPublish(claimResult) {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
if (!__DEV__) {
|
||||||
|
const { permanent_url: uri, claim_id: claimId, txid, nout, signing_channel: signingChannel } = claimResult;
|
||||||
|
let channelClaimId;
|
||||||
|
if (signingChannel) {
|
||||||
|
channelClaimId = signingChannel.claim_id;
|
||||||
|
}
|
||||||
|
const outpoint = `${txid}:${nout}`;
|
||||||
|
const params = { uri, claim_id: claimId, outpoint };
|
||||||
|
if (channelClaimId) {
|
||||||
|
params['channel_claim_id'] = channelClaimId;
|
||||||
|
}
|
||||||
|
Lbryio.call('event', 'publish', params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function uploadImageAsset(filePath, success, failure) {
|
export function uploadImageAsset(filePath, success, failure) {
|
||||||
const makeid = () => {
|
const makeid = () => {
|
||||||
let text = '';
|
let text = '';
|
||||||
|
|
Loading…
Reference in a new issue