Preferences #56

Closed
akinwale wants to merge 4 commits from preferences into master
11 changed files with 81 additions and 48 deletions

8
package-lock.json generated
View file

@ -5640,8 +5640,8 @@
} }
}, },
"lbry-redux": { "lbry-redux": {
"version": "github:lbryio/lbry-redux#7ec72a737bcd336f000c5f5085891643110298c3", "version": "github:lbryio/lbry-redux#f06e1e64a8587a183bd7333f628fca821fe81fa4",
"from": "github:lbryio/lbry-redux#7ec72a737bcd336f000c5f5085891643110298c3", "from": "github:lbryio/lbry-redux#f06e1e64a8587a183bd7333f628fca821fe81fa4",
"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#02d8571cd7fafd00d1a60f133d884eb8c5f1a306",
"from": "github:lbryio/lbryinc#c55a2c98ab92c72149c824ee5906aed4404fd89b", "from": "github:lbryio/lbryinc#02d8571cd7fafd00d1a60f133d884eb8c5f1a306",
"requires": { "requires": {
"reselect": "^3.0.0" "reselect": "^3.0.0"
} }

View file

@ -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#f06e1e64a8587a183bd7333f628fca821fe81fa4",
"lbryinc": "lbryio/lbryinc#c55a2c98ab92c72149c824ee5906aed4404fd89b", "lbryinc": "lbryio/lbryinc#02d8571cd7fafd00d1a60f133d884eb8c5f1a306",
"lodash": ">=4.17.11", "lodash": ">=4.17.11",
"merge": ">=1.2.1", "merge": ">=1.2.1",
"moment": "^2.22.1", "moment": "^2.22.1",

View file

@ -29,7 +29,7 @@ import {
import { connect } from 'react-redux'; import { connect } from 'react-redux';
kauffj commented 2019-10-11 22:47:33 +02:00 (Migrated from github.com)
Review

none of the logic in this file appears to affect the presentation or rendering of this component

is there a design that would separate this out more cleanly? maybe just make it it's own component?

none of the logic in this file appears to affect the presentation or rendering of this component is there a design that would separate this out more cleanly? maybe just make it it's own component?
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"
@ -272,6 +275,7 @@ class AppWithNavigationState extends React.Component {
this.state = { this.state = {
emailVerifyDone: false, emailVerifyDone: false,
verifyPending: false, verifyPending: false,
syncHashChanged: false,
}; };
} }
@ -292,8 +296,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
setInterval(() => {
this.setState({ syncHashChanged: false }); // reset local state
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(walletPassword => {
dispatch(doGetSync(walletPassword));
});
}, SYNC_GET_INTERVAL);
} }
checkEmailVerification = () => { checkEmailVerification = () => {
@ -308,8 +321,8 @@ class AppWithNavigationState extends React.Component {
getUserSettings = () => { getUserSettings = () => {
const { dispatch } = this.props; const { dispatch } = this.props;
Lbryio.call('user_settings', 'get').then(settings => { doPreferenceGet('shared', null, null, preference => {
dispatch(doPopulateSharedUserState(settings)); dispatch(doPopulateSharedUserState(preference));
}); });
}; };
@ -320,7 +333,7 @@ class AppWithNavigationState extends React.Component {
} }
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);
kauffj commented 2019-10-11 22:48:15 +02:00 (Migrated from github.com)
Review

you should probably store the result of this setInterval call and call clearInterval on unmount

you should probably store the result of this `setInterval` call and call `clearInterval` on unmount
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'false'); AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'false');
@ -332,6 +345,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 +456,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),

View file

@ -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 => dispatch(doGetSync(password)),
}); });
export default connect( export default connect(

View file

@ -1,6 +1,6 @@
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 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 +117,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)) {
@ -153,6 +153,9 @@ export default class ChannelSelector extends React.PureComponent {
if (onChannelChange) { if (onChannelChange) {
onChannelChange(channelName); onChannelChange(channelName);
} }
// sync wallet
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(password => getSync(password));
}; };
const failure = () => { const failure = () => {

View file

@ -13,6 +13,7 @@ import {
searchReducer, searchReducer,
tagsReducer, tagsReducer,
walletReducer, walletReducer,
sharedStateSubscriber,
} from 'lbry-redux'; } from 'lbry-redux';
import { import {
Lbryio, Lbryio,
@ -147,25 +148,28 @@ const persistor = persistStore(store, persistOptions, err => {
}); });
window.persistor = persistor; window.persistor = persistor;
let currentPayload; /**
store.subscribe(() => { * source: the reducer name
const state = store.getState(); * property: the property in the reducer-specific state
const subscriptions = state.subscriptions.subscriptions.map(({ uri }) => uri); * transform: optional method to modify the value to be stored
const tags = state.tags.followedTags; */
const sharedStateFilters = {
const newPayload = { tags: { source: 'tags', property: 'followedTags' },
version: '0.1', subscriptions: {
shared: { source: 'subscriptions',
subscriptions, property: 'subscriptions',
tags, transform: function(value) {
return value.map(({ uri }) => uri);
}, },
}; },
};
if (!isEqual(newPayload, currentPayload)) { store.subscribe(() => {
currentPayload = newPayload; try {
if (Lbryio.authToken) { const state = store.getState();
Lbryio.call('user_settings', 'set', { settings: JSON.stringify(newPayload) }); sharedStateSubscriber(state, sharedStateFilters, '0.1');
} } catch (e) {
// handle gracefully?
} }
}); });

View file

@ -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 => dispatch(doGetSync(password)),
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)),

View file

@ -376,7 +376,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,
@ -439,6 +447,9 @@ 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();
// sync wallet
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(password => getSync(password));
}; };
const failure = () => { const failure = () => {

View file

@ -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>

View file

@ -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';
@ -98,9 +96,7 @@ class SplashScreen extends React.PureComponent {
// 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_FIRST_RUN_PASSWORD).then(walletPassword => {
if (walletPassword) {
getSync(walletPassword); getSync(walletPassword);
}
this.navigateToMain(); this.navigateToMain();
}); });
return; return;
@ -113,8 +109,9 @@ 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', null, null, preference => {
populateSharedUserState(preference);
}); });
}; };
@ -139,14 +136,11 @@ class SplashScreen extends React.PureComponent {
// get user settings interval // get user settings interval
this.getUserSettings(); 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_FIRST_RUN_PASSWORD).then(walletPassword => {
if (walletPassword) {
getSync(walletPassword); getSync(walletPassword);
}
this.navigateToMain(); this.navigateToMain();
}); });
} else { } else {

View file

@ -47,9 +47,7 @@ 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_FIRST_RUN_PASSWORD).then(walletPassword => {
if (walletPassword) {
getSync(walletPassword); getSync(walletPassword);
}
}); });
} }
}; };