sync changes
This commit is contained in:
parent
bb9bde1c19
commit
6c4842a111
29 changed files with 270 additions and 170 deletions
|
@ -136,8 +136,8 @@
|
|||
"imagesloaded": "^4.1.4",
|
||||
"json-loader": "^0.5.4",
|
||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||
"lbry-redux": "lbryio/lbry-redux#210bb80f2c49f6a166a8adc602a68b7490d5d23a",
|
||||
"lbryinc": "lbryio/lbryinc#cff5dd60934c4c6080e135f47ebbece1548c658c",
|
||||
"lbry-redux": "lbryio/lbry-redux#760623f99c90407ca3f1d06f1cdd2506fb2e443a",
|
||||
"lbryinc": "lbryio/lbryinc#35df87d1e69e435e25fc12832b6b1b788f76baaa",
|
||||
"lint-staged": "^7.0.2",
|
||||
"localforage": "^1.7.1",
|
||||
"lodash-es": "^4.17.14",
|
||||
|
|
|
@ -5,13 +5,18 @@ import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user';
|
|||
import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
import { selectUnclaimedRewards } from 'redux/selectors/rewards';
|
||||
import { doFetchChannelListMine, SETTINGS } from 'lbry-redux';
|
||||
import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings';
|
||||
import {
|
||||
makeSelectClientSetting,
|
||||
selectLoadedLanguages,
|
||||
selectSyncSigninPref,
|
||||
selectThemePath,
|
||||
} from 'redux/selectors/settings';
|
||||
import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app';
|
||||
import { doSetLanguage } from 'redux/actions/settings';
|
||||
import { doSetLanguage, doUpdateSyncPref } from 'redux/actions/settings';
|
||||
import { doSyncSubscribe } from 'redux/actions/syncwrapper';
|
||||
import {
|
||||
doDownloadUpgradeRequested,
|
||||
doSignIn,
|
||||
doSyncWithPreferences,
|
||||
doGetAndPopulatePreferences,
|
||||
doAnalyticsTagSync,
|
||||
} from 'redux/actions/app';
|
||||
|
@ -22,14 +27,15 @@ const select = state => ({
|
|||
accessToken: selectAccessToken(state),
|
||||
theme: selectThemePath(state),
|
||||
language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
|
||||
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
|
||||
languages: selectLoadedLanguages(state),
|
||||
autoUpdateDownloaded: selectAutoUpdateDownloaded(state),
|
||||
isUpgradeAvailable: selectIsUpgradeAvailable(state),
|
||||
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
|
||||
syncError: selectGetSyncErrorMessage(state),
|
||||
uploadCount: selectUploadCount(state),
|
||||
rewards: selectUnclaimedRewards(state),
|
||||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
signInSyncPref: selectSyncSigninPref(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
@ -39,8 +45,9 @@ const perform = dispatch => ({
|
|||
setLanguage: language => dispatch(doSetLanguage(language)),
|
||||
signIn: () => dispatch(doSignIn()),
|
||||
requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()),
|
||||
checkSync: () => dispatch(doSyncWithPreferences()),
|
||||
updatePreferences: () => dispatch(doGetAndPopulatePreferences()),
|
||||
updateSyncPref: () => dispatch(doUpdateSyncPref()),
|
||||
syncSubscribe: () => dispatch(doSyncSubscribe()),
|
||||
setReferrer: (referrer, doClaim) => dispatch(doUserSetReferrer(referrer, doClaim)),
|
||||
});
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ export const MAIN_WRAPPER_CLASS = 'main-wrapper';
|
|||
// @if TARGET='app'
|
||||
export const IS_MAC = process.platform === 'darwin';
|
||||
// @endif
|
||||
const SYNC_INTERVAL = 1000 * 60 * 5; // 5 minutes
|
||||
|
||||
// button numbers pulled from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
||||
const MOUSE_BACK_BTN = 3;
|
||||
|
@ -67,17 +66,20 @@ type Props = {
|
|||
setLanguage: string => void,
|
||||
isUpgradeAvailable: boolean,
|
||||
autoUpdateDownloaded: boolean,
|
||||
checkSync: () => void,
|
||||
updatePreferences: () => void,
|
||||
syncEnabled: boolean,
|
||||
updatePreferences: () => Promise<any>,
|
||||
updateSyncPref: () => void,
|
||||
uploadCount: number,
|
||||
balance: ?number,
|
||||
syncError: ?string,
|
||||
syncEnabled: boolean,
|
||||
rewards: Array<Reward>,
|
||||
setReferrer: (string, boolean) => void,
|
||||
analyticsTagSync: () => void,
|
||||
isAuthenticated: boolean,
|
||||
socketConnect: () => void,
|
||||
syncSubscribe: () => void,
|
||||
syncEnabled: boolean,
|
||||
signInSyncPref: boolean,
|
||||
};
|
||||
|
||||
function App(props: Props) {
|
||||
|
@ -90,8 +92,6 @@ function App(props: Props) {
|
|||
autoUpdateDownloaded,
|
||||
isUpgradeAvailable,
|
||||
requestDownloadUpgrade,
|
||||
syncEnabled,
|
||||
checkSync,
|
||||
uploadCount,
|
||||
history,
|
||||
syncError,
|
||||
|
@ -99,15 +99,19 @@ function App(props: Props) {
|
|||
languages,
|
||||
setLanguage,
|
||||
updatePreferences,
|
||||
updateSyncPref,
|
||||
rewards,
|
||||
setReferrer,
|
||||
analyticsTagSync,
|
||||
isAuthenticated,
|
||||
syncSubscribe,
|
||||
signInSyncPref,
|
||||
} = props;
|
||||
|
||||
const appRef = useRef();
|
||||
const isEnhancedLayout = useKonamiListener();
|
||||
const [hasSignedIn, setHasSignedIn] = useState(false);
|
||||
const [readyForSync, setReadyForSync] = useState(false);
|
||||
const [readyForPrefs, setReadyForPrefs] = useState(false);
|
||||
const hasVerifiedEmail = user && user.has_verified_email;
|
||||
const isRewardApproved = user && user.is_reward_approved;
|
||||
const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail);
|
||||
|
@ -229,35 +233,40 @@ function App(props: Props) {
|
|||
}
|
||||
}, [previousRewardApproved, isRewardApproved]);
|
||||
|
||||
// Keep this at the end to ensure initial setup effects are run first
|
||||
useEffect(() => {
|
||||
if (!hasSignedIn && hasVerifiedEmail) {
|
||||
signIn();
|
||||
setHasSignedIn(true);
|
||||
}
|
||||
}, [hasVerifiedEmail, signIn, hasSignedIn]);
|
||||
|
||||
// @if TARGET='app'
|
||||
useEffect(() => {
|
||||
updatePreferences();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
if (updatePreferences && readyForPrefs) {
|
||||
updatePreferences().then(() => {
|
||||
setReadyForSync(true);
|
||||
});
|
||||
}
|
||||
}, [updatePreferences, setReadyForSync, readyForPrefs, hasVerifiedEmail]);
|
||||
// @endif
|
||||
|
||||
// ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too.
|
||||
useEffect(() => {
|
||||
if (hasVerifiedEmail && syncEnabled) {
|
||||
checkSync();
|
||||
analyticsTagSync();
|
||||
let syncInterval = setInterval(() => {
|
||||
checkSync();
|
||||
}, SYNC_INTERVAL);
|
||||
|
||||
return () => {
|
||||
clearInterval(syncInterval);
|
||||
};
|
||||
if (readyForSync && hasVerifiedEmail) {
|
||||
// Copy sync checkbox to settings and push to preferences
|
||||
// before sync if false, after sync if true so as not to change timestamp.
|
||||
if (signInSyncPref === false) {
|
||||
updateSyncPref();
|
||||
}
|
||||
syncSubscribe();
|
||||
if (signInSyncPref === true) {
|
||||
updateSyncPref();
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasVerifiedEmail, syncEnabled, checkSync]);
|
||||
}, [readyForSync, hasVerifiedEmail, signInSyncPref, updateSyncPref, syncSubscribe]);
|
||||
|
||||
// We know someone is logging in or not when we get their user object {}
|
||||
// We'll use this to determine when it's time to pull preferences
|
||||
// This will no longer work if desktop users no longer get a user object from lbryinc
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
setReadyForPrefs(true);
|
||||
}
|
||||
}, [user, setReadyForPrefs]);
|
||||
|
||||
useEffect(() => {
|
||||
if (syncError && isAuthenticated) {
|
||||
|
@ -266,6 +275,15 @@ function App(props: Props) {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [syncError, pathname, isAuthenticated]);
|
||||
|
||||
// Keep this at the end to ensure initial setup effects are run first
|
||||
useEffect(() => {
|
||||
if (!hasSignedIn && hasVerifiedEmail) {
|
||||
signIn();
|
||||
setHasSignedIn(true);
|
||||
if (IS_WEB) setReadyForSync(true);
|
||||
}
|
||||
}, [hasVerifiedEmail, signIn, hasSignedIn]);
|
||||
|
||||
// @if TARGET='web'
|
||||
useDegradedPerformance(setLbryTvApiStatus);
|
||||
// @endif
|
||||
|
|
|
@ -4,7 +4,7 @@ import { selectBalance, formatCredits, SETTINGS } from 'lbry-redux';
|
|||
import { selectGetSyncErrorMessage } from 'lbryinc';
|
||||
import { selectUserVerifiedEmail, selectUserEmail, selectEmailToVerify } from 'redux/selectors/user';
|
||||
import { doClearEmailEntry, doClearPasswordEntry } from 'redux/actions/user';
|
||||
import { doSetClientSetting, doSyncClientSettings } from 'redux/actions/settings';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import { doSignOut, doOpenModal } from 'redux/actions/app';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import Header from './view';
|
||||
|
@ -25,8 +25,7 @@ const select = state => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||
syncSettings: () => dispatch(doSyncClientSettings()),
|
||||
setClientSetting: (key, value, push) => dispatch(doSetClientSetting(key, value, push)),
|
||||
signOut: () => dispatch(doSignOut()),
|
||||
openChannelCreate: () => dispatch(doOpenModal(MODALS.CREATE_CHANNEL)),
|
||||
openSignOutModal: () => dispatch(doOpenModal(MODALS.SIGN_OUT)),
|
||||
|
|
|
@ -37,7 +37,7 @@ type Props = {
|
|||
},
|
||||
currentTheme: string,
|
||||
automaticDarkModeEnabled: boolean,
|
||||
setClientSetting: (string, boolean | string) => void,
|
||||
setClientSetting: (string, boolean | string, ?boolean) => void,
|
||||
hideBalance: boolean,
|
||||
email: ?string,
|
||||
authenticated: boolean,
|
||||
|
@ -56,7 +56,6 @@ type Props = {
|
|||
clearEmailEntry: () => void,
|
||||
clearPasswordEntry: () => void,
|
||||
hasNavigated: boolean,
|
||||
syncSettings: () => void,
|
||||
sidebarOpen: boolean,
|
||||
setSidebarOpen: boolean => void,
|
||||
isAbsoluteSideNavHidden: boolean,
|
||||
|
@ -80,7 +79,6 @@ const Header = (props: Props) => {
|
|||
clearPasswordEntry,
|
||||
emailToVerify,
|
||||
backout,
|
||||
syncSettings,
|
||||
sidebarOpen,
|
||||
setSidebarOpen,
|
||||
isAbsoluteSideNavHidden,
|
||||
|
@ -149,11 +147,10 @@ const Header = (props: Props) => {
|
|||
}
|
||||
|
||||
if (currentTheme === 'dark') {
|
||||
setClientSetting(SETTINGS.THEME, 'light');
|
||||
setClientSetting(SETTINGS.THEME, 'light', true);
|
||||
} else {
|
||||
setClientSetting(SETTINGS.THEME, 'dark');
|
||||
setClientSetting(SETTINGS.THEME, 'dark', true);
|
||||
}
|
||||
syncSettings();
|
||||
}
|
||||
|
||||
function getWalletTitle() {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectPublishFormValues, doUpdatePublishForm } from 'lbry-redux';
|
||||
import PublishPage from './view';
|
||||
import { selectUser, selectAccessToken } from '../../redux/selectors/user';
|
||||
import {doFetchAccessToken} from '../../redux/actions/user';
|
||||
import { selectUser, selectAccessToken } from 'redux/selectors/user';
|
||||
import { doFetchAccessToken } from 'redux/actions/user';
|
||||
|
||||
const select = state => ({
|
||||
...selectPublishFormValues(state),
|
||||
|
|
|
@ -3,8 +3,7 @@ import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
|||
import { selectHasNavigated, selectScrollStartingPosition, selectWelcomeVersion } from 'redux/selectors/app';
|
||||
import Router from './view';
|
||||
import { normalizeURI, makeSelectTitleForUri } from 'lbry-redux';
|
||||
import { doSetHasNavigated, doSyncWithPreferences } from 'redux/actions/app';
|
||||
import { doSyncClientSettings } from 'redux/actions/settings';
|
||||
import { doSetHasNavigated } from 'redux/actions/app';
|
||||
const select = state => {
|
||||
const { pathname, hash } = state.router.location;
|
||||
const urlPath = pathname + hash;
|
||||
|
@ -34,8 +33,6 @@ const select = state => {
|
|||
|
||||
const perform = dispatch => ({
|
||||
setHasNavigated: () => dispatch(doSetHasNavigated()),
|
||||
syncSettings: () => dispatch(doSyncClientSettings()),
|
||||
checkSync: () => dispatch(doSyncWithPreferences()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(Router);
|
||||
|
|
|
@ -97,8 +97,6 @@ type Props = {
|
|||
welcomeVersion: number,
|
||||
hasNavigated: boolean,
|
||||
setHasNavigated: () => void,
|
||||
syncSettings: () => void,
|
||||
checkSync: () => void,
|
||||
};
|
||||
|
||||
function AppRouter(props: Props) {
|
||||
|
@ -112,14 +110,11 @@ function AppRouter(props: Props) {
|
|||
welcomeVersion,
|
||||
hasNavigated,
|
||||
setHasNavigated,
|
||||
syncSettings,
|
||||
checkSync,
|
||||
} = props;
|
||||
const { entries } = history;
|
||||
const entryIndex = history.index;
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const resetScroll = urlParams.get('reset_scroll');
|
||||
const [prevPath, setPrevPath] = React.useState(pathname);
|
||||
|
||||
// For people arriving at settings page from deeplinks, know whether they can "go back"
|
||||
useEffect(() => {
|
||||
|
@ -131,27 +126,6 @@ function AppRouter(props: Props) {
|
|||
return unlisten;
|
||||
}, [hasNavigated, setHasNavigated]);
|
||||
|
||||
// Sync when no longer on a settings page, or when entering settings pages
|
||||
useEffect(() => {
|
||||
const unlisten = history.listen(location => {
|
||||
if (!location.pathname.includes(PAGES.SETTINGS) && prevPath.includes(PAGES.SETTINGS)) {
|
||||
syncSettings();
|
||||
} else if (location.pathname.includes(PAGES.SETTINGS) && !prevPath.includes(PAGES.SETTINGS)) {
|
||||
checkSync();
|
||||
}
|
||||
});
|
||||
return unlisten;
|
||||
}, [prevPath, syncSettings, checkSync]);
|
||||
|
||||
useEffect(() => {
|
||||
const unlisten = history.listen(location => {
|
||||
if (prevPath !== location.pathname && setPrevPath) {
|
||||
setPrevPath(location.pathname);
|
||||
}
|
||||
});
|
||||
return unlisten;
|
||||
}, [prevPath, setPrevPath]);
|
||||
|
||||
useEffect(() => {
|
||||
if (uri) {
|
||||
const { channelName, streamName } = parseURI(uri);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doGetSync, selectGetSyncIsPending, selectSyncApplyPasswordError } from 'lbryinc';
|
||||
import { selectGetSyncIsPending, selectSyncApplyPasswordError } from 'lbryinc';
|
||||
import { doGetSyncDesktop } from 'redux/actions/syncwrapper';
|
||||
import { selectUserEmail } from 'redux/selectors/user';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import { doSignOut, doHandleSyncComplete } from 'redux/actions/app';
|
||||
|
@ -12,7 +13,7 @@ const select = state => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
getSync: (password, cb) => dispatch(doGetSync(password, cb)),
|
||||
getSync: (cb, password) => dispatch(doGetSyncDesktop(cb, password)),
|
||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||
handleSyncComplete: (error, hasDataChanged) => dispatch(doHandleSyncComplete(error, hasDataChanged)),
|
||||
signOut: () => dispatch(doSignOut()),
|
||||
|
|
|
@ -8,7 +8,7 @@ import usePersistedState from 'effects/use-persisted-state';
|
|||
import I18nMessage from 'component/i18nMessage';
|
||||
|
||||
type Props = {
|
||||
getSync: (?string, (any, boolean) => void) => void,
|
||||
getSync: ((any, boolean) => void, ?string) => void,
|
||||
getSyncIsPending: boolean,
|
||||
email: string,
|
||||
passwordError: boolean,
|
||||
|
@ -22,13 +22,13 @@ function SyncPassword(props: Props) {
|
|||
const [rememberPassword, setRememberPassword] = usePersistedState(true);
|
||||
|
||||
function handleSubmit() {
|
||||
getSync(password, (error, hasDataChanged) => {
|
||||
getSync((error, hasDataChanged) => {
|
||||
handleSyncComplete(error, hasDataChanged);
|
||||
|
||||
if (!error) {
|
||||
setSavedPassword(password, rememberPassword);
|
||||
}
|
||||
});
|
||||
}, password);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
selectUser,
|
||||
} from 'redux/selectors/user';
|
||||
import { DAEMON_SETTINGS, SETTINGS } from 'lbry-redux';
|
||||
import { doSetClientSetting, doSetDaemonSetting } from 'redux/actions/settings';
|
||||
import { doSetSyncPref, doSetDaemonSetting } from 'redux/actions/settings';
|
||||
import { makeSelectClientSetting, selectDaemonSettings } from 'redux/selectors/settings';
|
||||
import UserEmailNew from './view';
|
||||
|
||||
|
@ -21,7 +21,7 @@ const select = state => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
setSync: value => dispatch(doSetClientSetting(SETTINGS.ENABLE_SYNC, value)),
|
||||
setSync: value => dispatch(doSetSyncPref(value)),
|
||||
setShareDiagnosticData: shouldShareData =>
|
||||
dispatch(doSetDaemonSetting(DAEMON_SETTINGS.SHARE_USAGE_DATA, shouldShareData)),
|
||||
doSignUp: (email, password) => dispatch(doUserSignUp(email, password)),
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
selectEmailNewIsPending,
|
||||
} from 'redux/selectors/user';
|
||||
import { doUserCheckIfEmailExists, doClearEmailEntry } from 'redux/actions/user';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import { doSetSyncPref } from 'redux/actions/settings';
|
||||
import UserEmailReturning from './view';
|
||||
|
||||
const select = state => ({
|
||||
|
@ -23,5 +23,5 @@ const select = state => ({
|
|||
export default connect(select, {
|
||||
doUserCheckIfEmailExists,
|
||||
doClearEmailEntry,
|
||||
doSetClientSetting,
|
||||
doSetSyncPref,
|
||||
})(UserEmailReturning);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// @flow
|
||||
import { SETTINGS } from 'lbry-redux';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import React, { useState } from 'react';
|
||||
import { FormField, Form } from 'component/common/form';
|
||||
|
@ -18,7 +17,8 @@ type Props = {
|
|||
doClearEmailEntry: () => void,
|
||||
doUserSignIn: (string, ?string) => void,
|
||||
doUserCheckIfEmailExists: string => void,
|
||||
doSetClientSetting: (string, boolean) => void,
|
||||
doSetSyncPref: boolean => void,
|
||||
doSetClientSetting: (string, boolean, ?boolean) => void,
|
||||
isPending: boolean,
|
||||
};
|
||||
|
||||
|
@ -30,7 +30,7 @@ function UserEmailReturning(props: Props) {
|
|||
emailToVerify,
|
||||
doClearEmailEntry,
|
||||
emailDoesNotExist,
|
||||
doSetClientSetting,
|
||||
doSetSyncPref,
|
||||
isPending,
|
||||
} = props;
|
||||
const { push, location } = useHistory();
|
||||
|
@ -48,7 +48,7 @@ function UserEmailReturning(props: Props) {
|
|||
|
||||
function handleSubmit() {
|
||||
// @if TARGET='app'
|
||||
doSetClientSetting(SETTINGS.ENABLE_SYNC, syncEnabled);
|
||||
doSetSyncPref(syncEnabled);
|
||||
// @endif
|
||||
doUserCheckIfEmailExists(email);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import Spinner from 'component/spinner';
|
|||
|
||||
type Props = {
|
||||
user: ?User,
|
||||
history: { push: string => void },
|
||||
history: { push: string => void, replace: string => void },
|
||||
location: { search: string },
|
||||
userFetchPending: boolean,
|
||||
doUserSignIn: string => void,
|
||||
|
@ -28,7 +28,7 @@ function UserSignIn(props: Props) {
|
|||
|
||||
React.useEffect(() => {
|
||||
if (hasVerifiedEmail || (!showEmail && !showPassword && !showLoading)) {
|
||||
history.push(redirect || '/');
|
||||
history.replace(redirect || '/');
|
||||
}
|
||||
}, [showEmail, showPassword, showLoading, hasVerifiedEmail]);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ export const PASSWORD_SAVED = 'PASSWORD_SAVED';
|
|||
export const SET_WELCOME_VERSION = 'SET_WELCOME_VERSION';
|
||||
export const SET_ALLOW_ANALYTICS = 'SET_ALLOW_ANALYTICS';
|
||||
export const SET_HAS_NAVIGATED = 'SET_HAS_NAVIGATED';
|
||||
export const SET_SYNC_LOCK = 'SET_SYNC_LOCK';
|
||||
|
||||
// Navigation
|
||||
export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH';
|
||||
|
@ -132,6 +133,7 @@ export const UPDATE_IS_NIGHT = 'UPDATE_IS_NIGHT';
|
|||
export const FINDING_FFMPEG_STARTED = 'FINDING_FFMPEG_STARTED';
|
||||
export const FINDING_FFMPEG_COMPLETED = 'FINDING_FFMPEG_COMPLETED';
|
||||
export const SYNC_CLIENT_SETTINGS = 'SYNC_CLIENT_SETTINGS';
|
||||
export const SYNC_PREFERENCE_CHANGED = 'SYNC_PREFERENCE_CHANGED';
|
||||
|
||||
// User
|
||||
export const AUTHENTICATION_STARTED = 'AUTHENTICATION_STARTED';
|
||||
|
|
26
ui/index.jsx
26
ui/index.jsx
|
@ -117,30 +117,10 @@ doAuthTokenRefresh();
|
|||
// We keep a local variable for authToken because `ipcRenderer.send` does not
|
||||
// contain a response, so there is no way to know when it's been set
|
||||
let authToken;
|
||||
Lbryio.setOverride(
|
||||
'setAuthToken',
|
||||
status =>
|
||||
new Promise(resolve => {
|
||||
Lbryio.call(
|
||||
'user',
|
||||
'new',
|
||||
{
|
||||
auth_token: '',
|
||||
language: DEFAULT_LANGUAGE,
|
||||
app_id: status.installation_id,
|
||||
},
|
||||
'post'
|
||||
).then(response => {
|
||||
if (!response.auth_token) {
|
||||
throw new Error(__('auth_token is missing from response'));
|
||||
}
|
||||
|
||||
authToken = response.auth_token;
|
||||
Lbryio.setOverride('setAuthToken', authToken => {
|
||||
setAuthToken(authToken);
|
||||
resolve(authToken);
|
||||
});
|
||||
})
|
||||
);
|
||||
return authToken;
|
||||
});
|
||||
|
||||
Lbryio.setOverride(
|
||||
'getAuthToken',
|
||||
|
|
|
@ -6,7 +6,8 @@ import {
|
|||
doClearDaemonSetting,
|
||||
doSetClientSetting,
|
||||
doSetDarkTime,
|
||||
doSyncClientSettings,
|
||||
doEnterSettingsPage,
|
||||
doExitSettingsPage,
|
||||
} from 'redux/actions/settings';
|
||||
import { doSetPlayingUri } from 'redux/actions/content';
|
||||
import { makeSelectClientSetting, selectDaemonSettings } from 'redux/selectors/settings';
|
||||
|
@ -37,7 +38,6 @@ const select = state => ({
|
|||
|
||||
const perform = dispatch => ({
|
||||
setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)),
|
||||
syncSettings: () => dispatch(doSyncClientSettings()),
|
||||
clearDaemonSetting: key => dispatch(doClearDaemonSetting(key)),
|
||||
toggle3PAnalytics: allow => dispatch(doToggle3PAnalytics(allow)),
|
||||
clearCache: () => dispatch(doClearCache()),
|
||||
|
@ -47,6 +47,8 @@ const perform = dispatch => ({
|
|||
clearPlayingUri: () => dispatch(doSetPlayingUri(null)),
|
||||
setDarkTime: (time, options) => dispatch(doSetDarkTime(time, options)),
|
||||
openModal: (id, params) => dispatch(doOpenModal(id, params)),
|
||||
enterSettings: () => dispatch(doEnterSettingsPage()),
|
||||
exitSettings: () => dispatch(doExitSettingsPage()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(SettingsPage);
|
||||
|
|
|
@ -4,7 +4,6 @@ import * as MODALS from 'constants/modal_types';
|
|||
import * as ICONS from 'constants/icons';
|
||||
import * as React from 'react';
|
||||
import { SETTINGS } from 'lbry-redux';
|
||||
|
||||
import { FormField } from 'component/common/form';
|
||||
import Button from 'component/button';
|
||||
import Page from 'component/page';
|
||||
|
@ -66,6 +65,8 @@ type Props = {
|
|||
openModal: string => void,
|
||||
language?: string,
|
||||
syncEnabled: boolean,
|
||||
enterSettings: () => void,
|
||||
exitSettings: () => void,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
@ -89,7 +90,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { isAuthenticated } = this.props;
|
||||
const { isAuthenticated, enterSettings } = this.props;
|
||||
|
||||
if (isAuthenticated || !IS_WEB) {
|
||||
this.props.updateWalletStatus();
|
||||
|
@ -99,6 +100,12 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
}
|
||||
});
|
||||
}
|
||||
enterSettings();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { exitSettings } = this.props;
|
||||
exitSettings();
|
||||
}
|
||||
|
||||
onThemeChange(event: SyntheticInputEvent<*>) {
|
||||
|
@ -211,11 +218,11 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
<Card
|
||||
title={__('Sync')}
|
||||
subtitle={
|
||||
walletEncrypted && !storedPassword
|
||||
? __("To enable this feature, check 'Save Password' the next time you start the app.")
|
||||
walletEncrypted && !storedPassword && storedPassword !== ''
|
||||
? __("To enable Sync, close LBRY completely and check 'Remember Password' during wallet unlock.")
|
||||
: null
|
||||
}
|
||||
actions={<SyncToggle disabled={walletEncrypted && !storedPassword} />}
|
||||
actions={<SyncToggle disabled={walletEncrypted && !storedPassword && storedPassword !== ''} />}
|
||||
/>
|
||||
{/* @endif */}
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ import {
|
|||
doClearDaemonSetting,
|
||||
doSetClientSetting,
|
||||
doFindFFmpeg,
|
||||
doSyncClientSettings,
|
||||
doEnterSettingsPage,
|
||||
doExitSettingsPage,
|
||||
} from 'redux/actions/settings';
|
||||
import {
|
||||
makeSelectClientSetting,
|
||||
|
@ -34,7 +35,6 @@ const select = state => ({
|
|||
|
||||
const perform = dispatch => ({
|
||||
setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)),
|
||||
syncSettings: () => dispatch(doSyncClientSettings()),
|
||||
clearDaemonSetting: key => dispatch(doClearDaemonSetting(key)),
|
||||
clearCache: () => dispatch(doClearCache()),
|
||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||
|
@ -43,6 +43,8 @@ const perform = dispatch => ({
|
|||
updateWalletStatus: () => dispatch(doWalletStatus()),
|
||||
confirmForgetPassword: modalProps => dispatch(doNotifyForgetPassword(modalProps)),
|
||||
findFFmpeg: () => dispatch(doFindFFmpeg()),
|
||||
enterSettings: () => dispatch(doEnterSettingsPage()),
|
||||
exitSettings: () => dispatch(doExitSettingsPage()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(SettingsPage);
|
||||
|
|
|
@ -55,6 +55,8 @@ type Props = {
|
|||
language?: string,
|
||||
syncEnabled: boolean,
|
||||
syncSettings: () => void,
|
||||
enterSettings: () => void,
|
||||
exitSettings: () => void,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
@ -81,7 +83,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { isAuthenticated, ffmpegStatus, daemonSettings, findFFmpeg } = this.props;
|
||||
const { isAuthenticated, ffmpegStatus, daemonSettings, findFFmpeg, enterSettings } = this.props;
|
||||
|
||||
// @if TARGET='app'
|
||||
const { available } = ffmpegStatus;
|
||||
|
@ -102,6 +104,12 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
|||
}
|
||||
});
|
||||
}
|
||||
enterSettings();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { exitSettings } = this.props;
|
||||
exitSettings();
|
||||
}
|
||||
|
||||
onFFmpegFolder(path: string) {
|
||||
|
|
|
@ -46,11 +46,11 @@ import {
|
|||
import { selectDaemonSettings } from 'redux/selectors/settings';
|
||||
import { selectUser } from 'redux/selectors/user';
|
||||
// import { selectDaemonSettings } from 'redux/selectors/settings';
|
||||
import { doGetSync } from 'lbryinc';
|
||||
import { doSyncSubscribe } from 'redux/actions/syncwrapper';
|
||||
import { doAuthenticate } from 'redux/actions/user';
|
||||
import { lbrySettings as config, version as appVersion } from 'package.json';
|
||||
import analytics, { SHARE_INTERNAL } from 'analytics';
|
||||
import { doSignOutCleanup, deleteSavedPassword, getSavedPassword } from 'util/saved-passwords';
|
||||
import { doSignOutCleanup, deleteSavedPassword } from 'util/saved-passwords';
|
||||
import { doSocketConnect } from 'redux/actions/websocket';
|
||||
import { stringifyServerParam, shouldSetSetting } from 'util/sync-settings';
|
||||
import sha256 from 'crypto-js/sha256';
|
||||
|
@ -89,6 +89,13 @@ export function doUpdateDownloadProgress(percent) {
|
|||
};
|
||||
}
|
||||
|
||||
export function doSetSyncLock(lock) {
|
||||
return {
|
||||
type: ACTIONS.SET_SYNC_LOCK,
|
||||
data: lock,
|
||||
};
|
||||
}
|
||||
|
||||
export function doSkipUpgrade() {
|
||||
return {
|
||||
type: ACTIONS.SKIP_UPGRADE,
|
||||
|
@ -622,6 +629,7 @@ export function doGetAndPopulatePreferences() {
|
|||
}
|
||||
// @endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function failCb() {
|
||||
|
@ -633,9 +641,10 @@ export function doGetAndPopulatePreferences() {
|
|||
})
|
||||
);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
doPreferenceGet(preferenceKey, successCb, failCb);
|
||||
return doPreferenceGet(preferenceKey, successCb, failCb);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -653,11 +662,5 @@ export function doHandleSyncComplete(error, hasNewData) {
|
|||
}
|
||||
|
||||
export function doSyncWithPreferences() {
|
||||
return dispatch => {
|
||||
return getSavedPassword().then(password => {
|
||||
const passwordArgument = password === null ? '' : password;
|
||||
|
||||
dispatch(doGetSync(passwordArgument, (error, hasNewData) => dispatch(doHandleSyncComplete(error, hasNewData))));
|
||||
});
|
||||
};
|
||||
return dispatch => dispatch(doSyncSubscribe());
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ import analytics from 'analytics';
|
|||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||
import { launcher } from 'util/autoLaunch';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { doGetSyncDesktop, doSyncUnsubscribe } from 'redux/actions/syncwrapper';
|
||||
import { doGetAndPopulatePreferences, doSetSyncLock } from 'redux/actions/app';
|
||||
|
||||
const { DEFAULT_LANGUAGE } = require('config');
|
||||
const { SDK_SYNC_KEYS } = SHARED_PREFERENCES;
|
||||
|
||||
|
@ -119,7 +122,7 @@ export function doSaveCustomWalletServers(servers) {
|
|||
};
|
||||
}
|
||||
|
||||
export function doSetClientSetting(key, value) {
|
||||
export function doSetClientSetting(key, value, pushPrefs) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.CLIENT_SETTING_CHANGED,
|
||||
|
@ -128,6 +131,30 @@ export function doSetClientSetting(key, value) {
|
|||
value,
|
||||
},
|
||||
});
|
||||
|
||||
if (pushPrefs) {
|
||||
dispatch(doPushSettingsToPrefs());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doUpdateSyncPref() {
|
||||
return (dispatch, getState) => {
|
||||
const { settings } = getState();
|
||||
const { syncEnabledPref } = settings || {};
|
||||
if (syncEnabledPref !== undefined) {
|
||||
dispatch(doSetClientSetting(SETTINGS.ENABLE_SYNC, syncEnabledPref, true));
|
||||
dispatch(doSetSyncPref(undefined));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doSetSyncPref(isEnabled) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: LOCAL_ACTIONS.SYNC_PREFERENCE_CHANGED,
|
||||
data: isEnabled,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -167,15 +194,36 @@ export function doSetDarkTime(value, options) {
|
|||
};
|
||||
}
|
||||
|
||||
export function doSyncClientSettings() {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
|
||||
if (syncEnabled) {
|
||||
export function doPushSettingsToPrefs() {
|
||||
return dispatch => {
|
||||
return new Promise((resolve, reject) => {
|
||||
dispatch({
|
||||
type: LOCAL_ACTIONS.SYNC_CLIENT_SETTINGS,
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doEnterSettingsPage() {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
|
||||
const hasVerifiedEmail = state.user && state.user.user && state.user.user.has_verified_email;
|
||||
dispatch(doSyncUnsubscribe());
|
||||
if (syncEnabled && hasVerifiedEmail) {
|
||||
await dispatch(doGetSyncDesktop());
|
||||
} else {
|
||||
await dispatch(doGetAndPopulatePreferences());
|
||||
}
|
||||
dispatch(doSetSyncLock(true));
|
||||
};
|
||||
}
|
||||
|
||||
export function doExitSettingsPage() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(doSetSyncLock(false));
|
||||
dispatch(doPushSettingsToPrefs());
|
||||
};
|
||||
}
|
||||
|
||||
|
|
57
ui/redux/actions/syncwrapper.js
Normal file
57
ui/redux/actions/syncwrapper.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
// @flow
|
||||
import { doGetSync, selectGetSyncIsPending, selectSetSyncIsPending } from 'lbryinc';
|
||||
import { SETTINGS } from 'lbry-redux';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { getSavedPassword } from 'util/saved-passwords';
|
||||
import { doAnalyticsTagSync, doHandleSyncComplete } from 'redux/actions/app';
|
||||
import { selectSyncIsLocked } from 'redux/selectors/app';
|
||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
|
||||
let syncTimer = null;
|
||||
const SYNC_INTERVAL = 1000 * 60 * 5; // 5 minutes
|
||||
|
||||
export const doGetSyncDesktop = (cb?: () => void, password?: string) => (dispatch: Dispatch, getState: GetState) => {
|
||||
const state = getState();
|
||||
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
|
||||
const getSyncPending = selectGetSyncIsPending(state);
|
||||
const setSyncPending = selectSetSyncIsPending(state);
|
||||
const syncLocked = selectSyncIsLocked(state);
|
||||
|
||||
return getSavedPassword().then(savedPassword => {
|
||||
const passwordArgument = password || password === '' ? password : savedPassword === null ? '' : savedPassword;
|
||||
|
||||
if (syncEnabled && !getSyncPending && !setSyncPending && !syncLocked) {
|
||||
return dispatch(doGetSync(passwordArgument, cb));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export function doSyncSubscribe() {
|
||||
return (dispatch: Dispatch, getState: GetState) => {
|
||||
if (syncTimer) clearInterval(syncTimer);
|
||||
const state = getState();
|
||||
const hasVerifiedEmail = selectUserVerifiedEmail(state);
|
||||
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
|
||||
const syncLocked = selectSyncIsLocked(state);
|
||||
if (hasVerifiedEmail && syncEnabled && !syncLocked) {
|
||||
dispatch(doGetSyncDesktop((error, hasNewData) => dispatch(doHandleSyncComplete(error, hasNewData))));
|
||||
dispatch(doAnalyticsTagSync());
|
||||
syncTimer = setInterval(() => {
|
||||
const state = getState();
|
||||
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
|
||||
if (syncEnabled) {
|
||||
dispatch(doGetSyncDesktop((error, hasNewData) => dispatch(doHandleSyncComplete(error, hasNewData))));
|
||||
dispatch(doAnalyticsTagSync());
|
||||
}
|
||||
}, SYNC_INTERVAL);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doSyncUnsubscribe() {
|
||||
return (dispatch: Dispatch) => {
|
||||
if (syncTimer) {
|
||||
clearInterval(syncTimer);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -42,6 +42,7 @@ export type AppState = {
|
|||
welcomeVersion: number,
|
||||
allowAnalytics: boolean,
|
||||
hasNavigated: boolean,
|
||||
syncLocked: boolean,
|
||||
};
|
||||
|
||||
const defaultState: AppState = {
|
||||
|
@ -76,6 +77,7 @@ const defaultState: AppState = {
|
|||
welcomeVersion: 0.0,
|
||||
allowAnalytics: false,
|
||||
hasNavigated: false,
|
||||
syncLocked: false,
|
||||
};
|
||||
|
||||
// @@router comes from react-router
|
||||
|
@ -109,6 +111,11 @@ reducers[ACTIONS.DAEMON_READY] = state =>
|
|||
daemonReady: true,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SET_SYNC_LOCK] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
syncLocked: action.data,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.PASSWORD_SAVED] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
isPasswordSaved: action.data,
|
||||
|
|
|
@ -24,6 +24,7 @@ const defaultState = {
|
|||
findingFFmpeg: false,
|
||||
loadedLanguages: [...Object.keys(window.i18n_messages), 'en'] || ['en'],
|
||||
customWalletServers: [],
|
||||
syncEnabledPref: undefined, // set this during sign in, copy it to clientSettings immediately after prefGet after signedin but before sync
|
||||
sharedPreferences: {},
|
||||
daemonSettings: {},
|
||||
daemonStatus: { ffmpeg_status: {} },
|
||||
|
@ -144,17 +145,6 @@ reducers[LBRY_REDUX_ACTIONS.SHARED_PREFERENCE_SET] = (state, action) => {
|
|||
});
|
||||
};
|
||||
|
||||
reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => {
|
||||
const { key, value } = action.data;
|
||||
const clientSettings = Object.assign({}, state.clientSettings);
|
||||
|
||||
clientSettings[key] = value;
|
||||
|
||||
return Object.assign({}, state, {
|
||||
clientSettings,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[ACTIONS.SYNC_CLIENT_SETTINGS] = state => {
|
||||
const { clientSettings } = state;
|
||||
const sharedPreferences = Object.assign({}, state.sharedPreferences);
|
||||
|
@ -163,6 +153,12 @@ reducers[ACTIONS.SYNC_CLIENT_SETTINGS] = state => {
|
|||
return Object.assign({}, state, { sharedPreferences: newSharedPreferences });
|
||||
};
|
||||
|
||||
reducers[ACTIONS.SYNC_PREFERENCE_CHANGED] = (state, action) => {
|
||||
return Object.assign({}, state, {
|
||||
syncEnabledPref: action.data,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE] = (state, action) => {
|
||||
const { clientSettings: currentClientSettings } = state;
|
||||
const { settings: sharedPreferences } = action.data;
|
||||
|
|
|
@ -80,3 +80,5 @@ export const selectAllowAnalytics = createSelector(selectState, state => state.a
|
|||
export const selectScrollStartingPosition = createSelector(selectState, state => state.currentScroll);
|
||||
|
||||
export const selectIsPasswordSaved = createSelector(selectState, state => state.isPasswordSaved);
|
||||
|
||||
export const selectSyncIsLocked = createSelector(selectState, state => state.syncLocked);
|
||||
|
|
|
@ -11,6 +11,8 @@ export const selectFfmpegStatus = createSelector(selectDaemonStatus, status => s
|
|||
|
||||
export const selectFindingFFmpeg = createSelector(selectState, state => state.findingFFmpeg || false);
|
||||
|
||||
export const selectSyncSigninPref = createSelector(selectState, state => state.syncEnabledPref || undefined);
|
||||
|
||||
export const selectClientSettings = createSelector(selectState, state => state.clientSettings || {});
|
||||
|
||||
export const selectLoadedLanguages = createSelector(selectState, state => state.loadedLanguages || {});
|
||||
|
|
17
ui/store.js
17
ui/store.js
|
@ -9,11 +9,9 @@ import thunk from 'redux-thunk';
|
|||
import { createMemoryHistory, createBrowserHistory } from 'history';
|
||||
import { routerMiddleware } from 'connected-react-router';
|
||||
import createRootReducer from './reducers';
|
||||
import { Lbry, buildSharedStateMiddleware, ACTIONS as LBRY_REDUX_ACTIONS, SETTINGS } from 'lbry-redux';
|
||||
import { doGetSync } from 'lbryinc';
|
||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
import { getSavedPassword, getAuthToken } from 'util/saved-passwords';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { Lbry, buildSharedStateMiddleware, ACTIONS as LBRY_REDUX_ACTIONS } from 'lbry-redux';
|
||||
import { doSyncSubscribe } from 'redux/actions/syncwrapper';
|
||||
import { getAuthToken } from 'util/saved-passwords';
|
||||
import { generateInitialUrl } from 'util/url';
|
||||
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
|
||||
|
||||
|
@ -152,14 +150,7 @@ const sharedStateFilters = {
|
|||
};
|
||||
|
||||
const sharedStateCb = ({ dispatch, getState }) => {
|
||||
const state = getState();
|
||||
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
|
||||
const emailVerified = selectUserVerifiedEmail(state);
|
||||
if (syncEnabled && emailVerified) {
|
||||
getSavedPassword().then(savedPassword => {
|
||||
dispatch(doGetSync(savedPassword));
|
||||
});
|
||||
}
|
||||
dispatch(doSyncSubscribe());
|
||||
};
|
||||
|
||||
const populateAuthTokenHeader = () => {
|
||||
|
|
|
@ -6411,17 +6411,17 @@ lazy-val@^1.0.4:
|
|||
yargs "^13.2.2"
|
||||
zstd-codec "^0.1.1"
|
||||
|
||||
lbry-redux@lbryio/lbry-redux#210bb80f2c49f6a166a8adc602a68b7490d5d23a:
|
||||
lbry-redux@lbryio/lbry-redux#760623f99c90407ca3f1d06f1cdd2506fb2e443a:
|
||||
version "0.0.1"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/210bb80f2c49f6a166a8adc602a68b7490d5d23a"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/760623f99c90407ca3f1d06f1cdd2506fb2e443a"
|
||||
dependencies:
|
||||
proxy-polyfill "0.1.6"
|
||||
reselect "^3.0.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
lbryinc@lbryio/lbryinc#cff5dd60934c4c6080e135f47ebbece1548c658c:
|
||||
lbryinc@lbryio/lbryinc#35df87d1e69e435e25fc12832b6b1b788f76baaa:
|
||||
version "0.0.1"
|
||||
resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/cff5dd60934c4c6080e135f47ebbece1548c658c"
|
||||
resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/35df87d1e69e435e25fc12832b6b1b788f76baaa"
|
||||
dependencies:
|
||||
reselect "^3.0.0"
|
||||
|
||||
|
|
Loading…
Reference in a new issue