From 63655270f2b9c7ddf0d88bddccc334c402b6c320 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 20 Sep 2019 17:46:07 +0100 Subject: [PATCH 1/5] sync user settings --- package-lock.json | 4 +- package.json | 2 +- src/index.js | 35 +++++++----- src/page/splash/index.js | 3 +- src/page/splash/view.js | 20 +++++++ src/utils/deep-equal.js | 117 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 162 insertions(+), 19 deletions(-) create mode 100644 src/utils/deep-equal.js diff --git a/package-lock.json b/package-lock.json index a4d8aeb..d93ab7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5574,8 +5574,8 @@ } }, "lbry-redux": { - "version": "github:lbryio/lbry-redux#3133ea60b0302c162f7b6f67cc858997f1d2ab52", - "from": "github:lbryio/lbry-redux#3133ea60b0302c162f7b6f67cc858997f1d2ab52", + "version": "github:lbryio/lbry-redux#e5443aafcfa7450c97e4edf838859352be6ca220", + "from": "github:lbryio/lbry-redux#e5443aafcfa7450c97e4edf838859352be6ca220", "requires": { "proxy-polyfill": "0.1.6", "reselect": "^3.0.0", diff --git a/package.json b/package.json index 37ce2c8..fb0a3b7 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "base-64": "^0.1.0", "@expo/vector-icons": "^8.1.0", "gfycat-style-urls": "^1.0.3", - "lbry-redux": "lbryio/lbry-redux#123efacf4d45289ebda9dc291976d475de227a55", + "lbry-redux": "lbryio/lbry-redux#e5443aafcfa7450c97e4edf838859352be6ca220", "lbryinc": "lbryio/lbryinc#b9f354ae50bd57691765a7d042c5054167878bf4", "lodash": ">=4.17.11", "merge": ">=1.2.1", diff --git a/src/index.js b/src/index.js index 9b92508..b911e04 100644 --- a/src/index.js +++ b/src/index.js @@ -15,6 +15,7 @@ import { walletReducer, } from 'lbry-redux'; import { + Lbryio, authReducer, blacklistReducer, costInfoReducer, @@ -41,6 +42,7 @@ import formReducer from 'redux/reducers/form'; import drawerReducer from 'redux/reducers/drawer'; import settingsReducer from 'redux/reducers/settings'; import thunk from 'redux-thunk'; +import isEqual from 'utils/deep-equal'; const globalExceptionHandler = (error, isFatal) => { if (error && NativeModules.Firebase) { @@ -145,22 +147,25 @@ const persistor = persistStore(store, persistOptions, err => { }); window.persistor = persistor; -/* -const persistFilter = { - 'auth': ['authToken'], - 'claims': ['byId', 'claimsByUri'], - 'content': ['positions'], - 'subscriptions': ['enabledChannelNotifications', 'subscriptions'], - 'settings': ['clientSettings'], - 'tags': ['followedTags'], - 'wallet': ['receiveAddress'] -}; - +let currentPayload; store.subscribe(() => { - const state = (({ auth, claims, content, subscriptions, settings, tags, wallet }) => - ({ auth, claims, content, subscriptions, settings, tags, wallet }))(store.getState()); - NativeModules.StatePersistor.update(state, persistFilter); -}); */ + const state = store.getState(); + const subscriptions = state.subscriptions.subscriptions.map(({ uri }) => uri); + const tags = state.tags.followedTags; + + const newPayload = { + version: '0', + shared: { + subscriptions, + tags, + }, + }; + + if (!isEqual(newPayload, currentPayload)) { + currentPayload = newPayload; + Lbryio.call('user_settings', 'set', { settings: JSON.stringify(newPayload) }); + } +}); // TODO: Find i18n module that is compatible with react-native global.__ = str => str; diff --git a/src/page/splash/index.js b/src/page/splash/index.js index d3b644e..031aaf8 100644 --- a/src/page/splash/index.js +++ b/src/page/splash/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { doBalanceSubscribe, doUpdateBlockHeight, doToast } from 'lbry-redux'; +import { doBalanceSubscribe, doUpdateBlockHeight, doPopulateSharedUserState, doToast } from 'lbry-redux'; import { doAuthenticate, doBlackListedOutpointsSubscribe, @@ -34,6 +34,7 @@ const perform = dispatch => ({ notify: data => dispatch(doToast(data)), setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), setEmailToVerify: email => dispatch(doUserEmailToVerify(email)), + populateSharedUserState: settings => dispatch(doPopulateSharedUserState(settings)), updateBlockHeight: () => dispatch(doUpdateBlockHeight()), verifyUserEmail: (token, recaptcha) => dispatch(doUserEmailVerify(token, recaptcha)), verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)), diff --git a/src/page/splash/view.js b/src/page/splash/view.js index 567cfec..d20bba0 100644 --- a/src/page/splash/view.js +++ b/src/page/splash/view.js @@ -1,5 +1,6 @@ import React from 'react'; import { Lbry } from 'lbry-redux'; +import { Lbryio } from 'lbryinc'; import { ActivityIndicator, Linking, NativeModules, Platform, Text, View } from 'react-native'; import { NavigationActions, StackActions } from 'react-navigation'; import { decode as atob } from 'base-64'; @@ -15,6 +16,8 @@ import splashStyle from 'styles/splash'; 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 waitingForResolution = 'Waiting for name resolution'; @@ -108,6 +111,19 @@ class SplashScreen extends React.PureComponent { } } + getUserSettings = () => { + const { populateSharedUserState } = this.props; + Lbryio.call('user_settings', 'get') + .then(settings => { + console.log('***populate with settings***'); + console.log(settings); + populateSharedUserState(settings); + }) + .catch(err => { + console.log(err); + }); + }; + finishSplashScreen = () => { const { authenticate, @@ -127,6 +143,10 @@ class SplashScreen extends React.PureComponent { filteredOutpointsSubscribe(); checkSubscriptionsInit(); + // get user settings interval + this.getUserSettings(); + setInterval(() => this.getUserSettings(), SETTINGS_GET_INTERVAL); + if (user && user.id && user.has_verified_email) { // user already authenticated NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(walletPassword => { diff --git a/src/utils/deep-equal.js b/src/utils/deep-equal.js new file mode 100644 index 0000000..1925763 --- /dev/null +++ b/src/utils/deep-equal.js @@ -0,0 +1,117 @@ +/* eslint-disable */ +// underscore's deep equal function +// https://github.com/jashkenas/underscore/blob/master/underscore.js#L1189 + +export default function isEqual(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // `null` or `undefined` only equal to itself (strict comparison). + if (a == null || b == null) return false; + // `NaN`s are equivalent, but non-reflexive. + if (a !== a) return b !== b; + // Exhaust primitive checks + var type = typeof a; + if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; + return deepEq(a, b, aStack, bStack); +} + +function deepEq(a, b, aStack, bStack) { + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN. + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + case '[object Symbol]': + return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); + } + + var areArrays = className === '[object Array]'; + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, + bCtor = b.constructor; + if ( + aCtor !== bCtor && + !( + typeof aCtor === 'function' && + aCtor instanceof aCtor && + typeof bCtor === 'function' && + bCtor instanceof bCtor + ) && + ('constructor' in a && 'constructor' in b) + ) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!isEqual(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var keys = Object.keys(a), + key; + length = keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (Object.keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = keys[length]; + if (!(has(b, key) && isEqual(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; +} + +function has(obj, path) { + return obj != null && hasOwnProperty.call(obj, path); +} +/* eslint-enable */ -- 2.45.2 From deb863a94c84de93ce88b22c5d34d84ae6e5bbd5 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Mon, 23 Sep 2019 09:41:02 +0100 Subject: [PATCH 2/5] fix errors and user shared state --- package-lock.json | 8 ++++---- package.json | 4 ++-- src/component/channelSelector/view.js | 2 +- src/index.js | 6 ++++-- src/page/publish/view.js | 4 +--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index d93ab7b..cf1269f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5574,8 +5574,8 @@ } }, "lbry-redux": { - "version": "github:lbryio/lbry-redux#e5443aafcfa7450c97e4edf838859352be6ca220", - "from": "github:lbryio/lbry-redux#e5443aafcfa7450c97e4edf838859352be6ca220", + "version": "github:lbryio/lbry-redux#f6d24c54baf5ff4e67aba90684dc6e55fe9cbecc", + "from": "github:lbryio/lbry-redux#f6d24c54baf5ff4e67aba90684dc6e55fe9cbecc", "requires": { "proxy-polyfill": "0.1.6", "reselect": "^3.0.0", @@ -5583,8 +5583,8 @@ } }, "lbryinc": { - "version": "github:lbryio/lbryinc#b9f354ae50bd57691765a7d042c5054167878bf4", - "from": "github:lbryio/lbryinc#b9f354ae50bd57691765a7d042c5054167878bf4", + "version": "github:lbryio/lbryinc#745d3cba93b7956fc16fb56df1fe265bc25ebc87", + "from": "github:lbryio/lbryinc#745d3cba93b7956fc16fb56df1fe265bc25ebc87", "requires": { "reselect": "^3.0.0" } diff --git a/package.json b/package.json index fb0a3b7..3a8e1fe 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,8 @@ "base-64": "^0.1.0", "@expo/vector-icons": "^8.1.0", "gfycat-style-urls": "^1.0.3", - "lbry-redux": "lbryio/lbry-redux#e5443aafcfa7450c97e4edf838859352be6ca220", - "lbryinc": "lbryio/lbryinc#b9f354ae50bd57691765a7d042c5054167878bf4", + "lbry-redux": "lbryio/lbry-redux#f6d24c54baf5ff4e67aba90684dc6e55fe9cbecc", + "lbryinc": "lbryio/lbryinc#745d3cba93b7956fc16fb56df1fe265bc25ebc87", "lodash": ">=4.17.11", "merge": ">=1.2.1", "moment": "^2.22.1", diff --git a/src/component/channelSelector/view.js b/src/component/channelSelector/view.js index e5e8c29..1faf7b6 100644 --- a/src/component/channelSelector/view.js +++ b/src/component/channelSelector/view.js @@ -26,7 +26,7 @@ export default class ChannelSelector extends React.PureComponent { } componentDidMount() { - const { channels, channelName, fetchChannelListMine, fetchingChannels } = this.props; + const { channels = [], channelName, fetchChannelListMine, fetchingChannels } = this.props; if (!channels.length && !fetchingChannels) { fetchChannelListMine(); } diff --git a/src/index.js b/src/index.js index b911e04..4013fe2 100644 --- a/src/index.js +++ b/src/index.js @@ -154,7 +154,7 @@ store.subscribe(() => { const tags = state.tags.followedTags; const newPayload = { - version: '0', + version: '0.1', shared: { subscriptions, tags, @@ -163,7 +163,9 @@ store.subscribe(() => { if (!isEqual(newPayload, currentPayload)) { currentPayload = newPayload; - Lbryio.call('user_settings', 'set', { settings: JSON.stringify(newPayload) }); + if (Lbryio.authToken) { + Lbryio.call('user_settings', 'set', { settings: JSON.stringify(newPayload) }); + } } }); diff --git a/src/page/publish/view.js b/src/page/publish/view.js index 5d5d2f2..465fb16 100644 --- a/src/page/publish/view.js +++ b/src/page/publish/view.js @@ -611,8 +611,6 @@ class PublishPage extends React.PureComponent { }); }; - handleUploadPressed = () => {}; - getRandomFileId = () => { // generate a random id for a photo or recorded video between 1 and 20 (for creating thumbnails) const id = Math.floor(Math.random() * (20 - 2)) + 1; @@ -832,7 +830,7 @@ class PublishPage extends React.PureComponent { -- 2.45.2 From 2cc4177bbecf5dfc7929c1e8f85224afb39f90c4 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Mon, 23 Sep 2019 16:46:36 +0100 Subject: [PATCH 3/5] remove console.log calls --- src/page/splash/view.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/page/splash/view.js b/src/page/splash/view.js index d20bba0..0355a83 100644 --- a/src/page/splash/view.js +++ b/src/page/splash/view.js @@ -113,15 +113,9 @@ class SplashScreen extends React.PureComponent { getUserSettings = () => { const { populateSharedUserState } = this.props; - Lbryio.call('user_settings', 'get') - .then(settings => { - console.log('***populate with settings***'); - console.log(settings); - populateSharedUserState(settings); - }) - .catch(err => { - console.log(err); - }); + Lbryio.call('user_settings', 'get').then(settings => { + populateSharedUserState(settings); + }); }; finishSplashScreen = () => { -- 2.45.2 From bd23736c37bb8420f85260ad6e7331fbcbda7279 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Mon, 23 Sep 2019 16:49:49 +0100 Subject: [PATCH 4/5] fix typo --- src/page/publish/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page/publish/view.js b/src/page/publish/view.js index 465fb16..2d30069 100644 --- a/src/page/publish/view.js +++ b/src/page/publish/view.js @@ -830,7 +830,7 @@ class PublishPage extends React.PureComponent { -- 2.45.2 From 0ddeaf0f27019e57377cfbf9b6dabf377168f308 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Mon, 23 Sep 2019 17:13:36 +0100 Subject: [PATCH 5/5] fix: publish button disabled for file uploads --- src/page/publish/view.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/page/publish/view.js b/src/page/publish/view.js index 2d30069..584a3f8 100644 --- a/src/page/publish/view.js +++ b/src/page/publish/view.js @@ -411,7 +411,11 @@ class PublishPage extends React.PureComponent { if (publishFormValues.thumbnail && !this.state.uploadedThumbnailUri) { const { thumbnail } = publishFormValues; updatePublishFormState({ currentThumbnailUri: thumbnail, uploadedThumbnailUri: thumbnail }); - this.setState({ currentThumbnailUri: thumbnail, uploadedThumbnailUri: thumbnail }); + this.setState({ + currentThumbnailUri: thumbnail, + uploadedThumbnailUri: thumbnail, + uploadThumbnailStarted: false, + }); } } @@ -1117,7 +1121,7 @@ class PublishPage extends React.PureComponent {