fix sync clean wallet bug

remove previous changes,keep syncpref in wallet, change anon wallet pref key to local

sync choices wip

dont relocate syncenable setting

bump

no prefs on web unauth

bugfix redux bump

pull after sync change

bump
This commit is contained in:
jessop 2020-09-11 14:35:50 -04:00 committed by Sean Yesmunt
parent 2ad7088553
commit 3b23f09bed
25 changed files with 402 additions and 105 deletions

View file

@ -136,7 +136,7 @@
"imagesloaded": "^4.1.4", "imagesloaded": "^4.1.4",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#437c54f164b4132c0d5c6ede60c7b02703f1e9d5", "lbry-redux": "lbryio/lbry-redux#e10295b5ec2ef42426755ed9fd50bd250b0d76dd",
"lbryinc": "lbryio/lbryinc#9440717a00d2fbb2e3226aaa2388f4698f324be2", "lbryinc": "lbryio/lbryinc#9440717a00d2fbb2e3226aaa2388f4698f324be2",
"lint-staged": "^7.0.2", "lint-staged": "^7.0.2",
"localforage": "^1.7.1", "localforage": "^1.7.1",

View file

@ -1292,5 +1292,20 @@
"%comment_count% comments - %comment_count_change% this week": "%comment_count% comments - %comment_count_change% this week", "%comment_count% comments - %comment_count_change% this week": "%comment_count% comments - %comment_count_change% this week",
"Invite": "Invite", "Invite": "Invite",
"Remove File": "Remove File", "Remove File": "Remove File",
"You are currently following %followingCount% tag": "You are currently following %followingCount% tag",
"DO a thing": "DO a thing",
"DO IT": "DO IT",
"Not Yet": "Not Yet",
"I understand": "I understand",
"Enabling Sync": "Enabling Sync",
"Enable Sync": "Enable Sync",
"Bring my stuff!": "Bring my stuff!",
"Disable Sync": "Disable Sync",
"Enable": "Enable",
"Continuing will import the profile in your cloud wallet into your local wallet.": "Continuing will import the profile in your cloud wallet into your local wallet.",
"": "",
"Getting your profiles...": "Getting your profiles...",
"Enabling sync will switch to your cloud profile.": "Enabling sync will switch to your cloud profile.",
"Disabling sync will switch to your local profile.": "Disabling sync will switch to your local profile.",
"--end--": "--end--" "--end--": "--end--"
} }

View file

@ -5,14 +5,9 @@ import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user';
import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectUnclaimedRewards } from 'redux/selectors/rewards'; import { selectUnclaimedRewards } from 'redux/selectors/rewards';
import { doFetchChannelListMine, SETTINGS } from 'lbry-redux'; import { doFetchChannelListMine, SETTINGS } from 'lbry-redux';
import { import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings';
makeSelectClientSetting,
selectLoadedLanguages,
selectSyncSigninPref,
selectThemePath,
} from 'redux/selectors/settings';
import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app';
import { doSetLanguage, doUpdateSyncPrefIfFalse } from 'redux/actions/settings'; import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings';
import { doSyncSubscribe } from 'redux/actions/syncwrapper'; import { doSyncSubscribe } from 'redux/actions/syncwrapper';
import { import {
doDownloadUpgradeRequested, doDownloadUpgradeRequested,
@ -35,7 +30,6 @@ const select = state => ({
uploadCount: selectUploadCount(state), uploadCount: selectUploadCount(state),
rewards: selectUnclaimedRewards(state), rewards: selectUnclaimedRewards(state),
isAuthenticated: selectUserVerifiedEmail(state), isAuthenticated: selectUserVerifiedEmail(state),
signInSyncPref: selectSyncSigninPref(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
@ -46,7 +40,7 @@ const perform = dispatch => ({
signIn: () => dispatch(doSignIn()), signIn: () => dispatch(doSignIn()),
requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()), requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()),
updatePreferences: () => dispatch(doGetAndPopulatePreferences()), updatePreferences: () => dispatch(doGetAndPopulatePreferences()),
pushPrefsIfSyncFalse: () => dispatch(doUpdateSyncPrefIfFalse()), getWalletSyncPref: () => dispatch(doGetWalletSyncPreference()),
syncSubscribe: () => dispatch(doSyncSubscribe()), syncSubscribe: () => dispatch(doSyncSubscribe()),
setReferrer: (referrer, doClaim) => dispatch(doUserSetReferrer(referrer, doClaim)), setReferrer: (referrer, doClaim) => dispatch(doUserSetReferrer(referrer, doClaim)),
}); });

View file

@ -67,7 +67,7 @@ type Props = {
isUpgradeAvailable: boolean, isUpgradeAvailable: boolean,
autoUpdateDownloaded: boolean, autoUpdateDownloaded: boolean,
updatePreferences: () => Promise<any>, updatePreferences: () => Promise<any>,
pushPrefsIfSyncFalse: () => void, getWalletSyncPref: () => Promise<any>,
uploadCount: number, uploadCount: number,
balance: ?number, balance: ?number,
syncError: ?string, syncError: ?string,
@ -79,7 +79,6 @@ type Props = {
socketConnect: () => void, socketConnect: () => void,
syncSubscribe: () => void, syncSubscribe: () => void,
syncEnabled: boolean, syncEnabled: boolean,
signInSyncPref: boolean,
}; };
function App(props: Props) { function App(props: Props) {
@ -99,12 +98,11 @@ function App(props: Props) {
languages, languages,
setLanguage, setLanguage,
updatePreferences, updatePreferences,
pushPrefsIfSyncFalse, getWalletSyncPref,
rewards, rewards,
setReferrer, setReferrer,
isAuthenticated, isAuthenticated,
syncSubscribe, syncSubscribe,
signInSyncPref,
} = props; } = props;
const appRef = useRef(); const appRef = useRef();
@ -112,7 +110,7 @@ function App(props: Props) {
const [hasSignedIn, setHasSignedIn] = useState(false); const [hasSignedIn, setHasSignedIn] = useState(false);
const [readyForSync, setReadyForSync] = useState(false); const [readyForSync, setReadyForSync] = useState(false);
const [readyForPrefs, setReadyForPrefs] = useState(false); const [readyForPrefs, setReadyForPrefs] = useState(false);
const hasVerifiedEmail = user && user.has_verified_email; const hasVerifiedEmail = user && Boolean(user.has_verified_email);
const isRewardApproved = user && user.is_reward_approved; const isRewardApproved = user && user.is_reward_approved;
const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail); const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail);
const previousRewardApproved = usePrevious(isRewardApproved); const previousRewardApproved = usePrevious(isRewardApproved);
@ -235,34 +233,26 @@ function App(props: Props) {
// @if TARGET='app' // @if TARGET='app'
useEffect(() => { useEffect(() => {
if (updatePreferences && readyForPrefs) { if (updatePreferences && getWalletSyncPref && readyForPrefs) {
updatePreferences().then(() => { getWalletSyncPref()
// will pull and U_S_P; usp will make sure prefBox applied if false .then(() => updatePreferences())
setReadyForSync(true); .then(() => {
}); setReadyForSync(true);
});
} }
}, [updatePreferences, setReadyForSync, readyForPrefs, hasVerifiedEmail]); }, [updatePreferences, getWalletSyncPref, setReadyForSync, readyForPrefs, hasVerifiedEmail]);
// @endif // @endif
// ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too. // ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too.
useEffect(() => { useEffect(() => {
// signInSyncPref is cleared after sharedState loop. // signInSyncPref is cleared after sharedState loop.
if (readyForSync && hasVerifiedEmail && signInSyncPref === undefined) { if (readyForSync && hasVerifiedEmail) {
// On sign-in, we get and apply all the information on whether to sync // In case we are syncing.
// the checkbox, previous wallet settings, store rehydrate, etc
// Our app is up to date with the wallet
// Because the checkbox is applied last, make sure the wallet remembers if false:
// @if TARGET='app'
pushPrefsIfSyncFalse();
// @endif
// And try this in case we are syncing.
syncSubscribe(); syncSubscribe();
} }
// eslint-disable-next-line react-hooks/exhaustive-deps }, [readyForSync, hasVerifiedEmail, syncSubscribe]);
}, [readyForSync, hasVerifiedEmail, signInSyncPref, pushPrefsIfSyncFalse, syncSubscribe]);
// We know someone is logging in or not when we get their user object {} // 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 // 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 // This will no longer work if desktop users no longer get a user object from lbryinc
useEffect(() => { useEffect(() => {

View file

@ -0,0 +1,34 @@
import { SETTINGS } from 'lbry-redux';
import { connect } from 'react-redux';
import { selectUserVerifiedEmail } from 'redux/selectors/user';
import {
selectGetSyncErrorMessage,
selectHasSyncedWallet,
selectGetSyncIsPending,
selectHashChanged,
doCheckSync,
doGetSync,
} from 'lbryinc';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetWalletSyncPreference } from 'redux/actions/settings';
import SyncToggle from './view';
import { doGetAndPopulatePreferences } from 'redux/actions/app';
const select = state => ({
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
hasSyncedWallet: selectHasSyncedWallet(state),
hasSyncChanged: selectHashChanged(state),
verifiedEmail: selectUserVerifiedEmail(state),
getSyncError: selectGetSyncErrorMessage(state),
getSyncPending: selectGetSyncIsPending(state),
language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
});
const perform = dispatch => ({
setSyncEnabled: value => dispatch(doSetWalletSyncPreference(value)),
checkSync: () => dispatch(doCheckSync()),
getSync: (pw, cb) => dispatch(doGetSync(pw, cb)),
updatePreferences: () => dispatch(doGetAndPopulatePreferences()),
});
export default connect(select, perform)(SyncToggle);

View file

@ -0,0 +1,234 @@
// @flow
import React from 'react';
import Button from 'component/button';
import { getSavedPassword } from 'util/saved-passwords';
import Card from 'component/common/card';
import { withRouter } from 'react-router';
import Spinner from 'component/spinner';
import { Lbry } from 'lbry-redux';
import ErrorText from 'component/common/error-text';
type Props = {
setSyncEnabled: boolean => void,
syncEnabled: boolean,
getSyncError: ?string,
getSyncPending: boolean,
getSync: (pw: string, cb: () => void) => void,
checkSync: () => void,
closeModal: () => void,
updatePreferences: () => void,
mode: string,
};
const ENABLE_MODE = 'enable';
// steps
const FETCH_FOR_ENABLE = 'fetch-for-enable';
const FETCH_FOR_DISABLE = 'fetch-for-disable';
const CONFIRM = 'confirm';
const INITIAL = 'initial';
const ERROR = 'error';
const SHARED_KEY = 'shared';
const LOCAL_KEY = 'local';
function SyncEnableFlow(props: Props) {
const {
setSyncEnabled,
getSyncError,
getSyncPending,
getSync,
checkSync,
mode,
closeModal,
updatePreferences,
} = props;
const [step, setStep] = React.useState(INITIAL);
const [prefDict, setPrefDict]: [any, (any) => void] = React.useState();
const [password, setPassword] = React.useState('');
const [error, setError] = React.useState();
const handleSyncToggle = async () => {
const shared = prefDict.shared;
const local = prefDict.local;
let finalPrefs;
if (shared && local) {
if (mode === ENABLE_MODE) {
finalPrefs = makeMergedPrefs(local, shared);
} else {
finalPrefs = makeMergedPrefs(shared, local);
}
} else {
finalPrefs = local || shared || null;
}
// set busy (disable button)
if (finalPrefs) {
await Lbry.preference_set({ key: mode === ENABLE_MODE ? SHARED_KEY : LOCAL_KEY, value: finalPrefs });
}
await setSyncEnabled(mode === ENABLE_MODE);
await updatePreferences();
closeModal();
};
const makeMergedPrefs = (from, to) => {
const mergedTo = to;
const toPrefs = to.value;
const fromPrefs = from.value;
if (!fromPrefs) {
return to;
}
const mergedBlockListSet = new Set(toPrefs.blocked || []);
const mergedSubscriptionsSet = new Set(toPrefs.subscriptions || []);
const mergedTagsSet = new Set(toPrefs.tags || []);
const fromBlocklist = fromPrefs.blocked || [];
const fromSubscriptions = fromPrefs.subscriptions || [];
const fromTags = fromPrefs.tags || [];
if (fromBlocklist.length) {
fromBlocklist.forEach(el => mergedBlockListSet.add(el));
}
if (fromSubscriptions.length) {
fromSubscriptions.forEach(el => mergedSubscriptionsSet.add(el));
}
if (fromTags.length) {
fromTags.forEach(el => mergedTagsSet.add(el));
}
toPrefs.blocked = Array.from(mergedBlockListSet);
toPrefs.subscriptions = Array.from(mergedSubscriptionsSet);
toPrefs.tags = Array.from(mergedTagsSet);
mergedTo.value = toPrefs;
return mergedTo;
};
React.useEffect(() => {
if (mode) {
checkSync();
if (mode === ENABLE_MODE) {
setStep(FETCH_FOR_ENABLE);
} else {
setStep(FETCH_FOR_DISABLE);
}
}
}, [mode]);
React.useEffect(() => {
getSavedPassword()
.then(pw => setPassword(pw || ''))
.catch(e => {
setError(e && e.message ? e.message : e);
});
}, []);
React.useEffect(() => {
if (step === FETCH_FOR_ENABLE) {
getSync(password, (e, hasChanged) => {
if (e) {
setStep(ERROR);
setError(e && e.message ? e.message : e);
} else {
Lbry.preference_get().then(result => {
const prefs = {};
if (result[SHARED_KEY]) prefs[SHARED_KEY] = result[SHARED_KEY];
if (result[LOCAL_KEY]) prefs[LOCAL_KEY] = result[LOCAL_KEY];
setPrefDict(prefs);
setStep(CONFIRM);
});
}
});
}
if (step === FETCH_FOR_DISABLE) {
Lbry.preference_get().then(result => {
const prefs = {};
if (result[SHARED_KEY]) prefs[SHARED_KEY] = result[SHARED_KEY];
if (result[LOCAL_KEY]) prefs[LOCAL_KEY] = result[LOCAL_KEY];
setPrefDict(prefs);
setStep(CONFIRM);
});
}
}, [step, setPrefDict, setStep, password]);
if (getSyncPending) {
return (
<div>
<Spinner />
</div>
);
}
return (
<Card
title={mode === ENABLE_MODE ? 'Enable Sync' : 'Disable Sync'}
body={
<div>
{step === INITIAL && (
<>
<h1>{__(`Please wait...`)}</h1>
<Spinner />
</>
)}
{(step === FETCH_FOR_ENABLE || step === FETCH_FOR_DISABLE) && (
<>
<h1>{__(`Getting your profiles...`)}</h1>
<Spinner />
</>
)}
{step === CONFIRM && mode === ENABLE_MODE && (
<>
<h1>{__(`Enabling sync will switch to your cloud profile.`)}</h1>
</>
)}
{step === CONFIRM && mode !== ENABLE_MODE && (
<>
<h1>{__(`Disabling sync will switch to your local profile.`)}</h1>
</>
)}
{(error || getSyncError) && (
<>
<h1>{__(`Something went wrong...`)}</h1>
<ErrorText>{error || (getSyncError && String(getSyncError)) || __('Unknown error')}</ErrorText>
</>
)}
</div>
}
actions={
<>
{step === CONFIRM && (
<div className={'card__actions'}>
<Button
button="primary"
name={'syncbutton'}
label={mode === ENABLE_MODE ? __('Enable Sync') : __('Disable Sync')}
onClick={() => handleSyncToggle()}
/>
<Button button="link" name={'cancel'} label={__('Cancel')} onClick={() => closeModal()} />
</div>
)}
{(step === FETCH_FOR_ENABLE || step === FETCH_FOR_DISABLE) && (
<div className={'card__actions'}>
<Button
button="primary"
name={'syncbutton'}
label={mode === ENABLE_MODE ? __('Enable Sync') : __('Disable Sync')}
onClick={() => handleSyncToggle()}
disabled
/>
<Button button="link" name={'cancel'} label={__('Cancel')} onClick={() => closeModal()} />
</div>
)}
{(error || getSyncError) && (
<div className={'card__actions'}>
<Button button="primary" name={'cancel'} label={__('Close')} onClick={() => closeModal()} />
</div>
)}
</>
}
/>
);
}
export default withRouter(SyncEnableFlow);

View file

@ -3,7 +3,8 @@ import { connect } from 'react-redux';
import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectGetSyncErrorMessage } from 'lbryinc'; import { selectGetSyncErrorMessage } from 'lbryinc';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetWalletSyncPreference } from 'redux/actions/settings';
import { doOpenModal } from 'redux/actions/app';
import SyncToggle from './view'; import SyncToggle from './view';
const select = state => ({ const select = state => ({
@ -14,7 +15,8 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
setSyncEnabled: value => dispatch(doSetClientSetting(SETTINGS.ENABLE_SYNC, value)), setSyncEnabled: value => dispatch(doSetWalletSyncPreference(value)),
openModal: (id, props) => dispatch(doOpenModal(id, props)),
}); });
export default connect(select, perform)(SyncToggle); export default connect(select, perform)(SyncToggle);

View file

@ -1,9 +1,10 @@
// @flow // @flow
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
import * as MODALS from 'constants/modal_types';
import React from 'react'; import React from 'react';
import Button from 'component/button'; import Button from 'component/button';
import { FormField } from 'component/common/form';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import { FormField } from 'component/common/form';
type Props = { type Props = {
setSyncEnabled: boolean => void, setSyncEnabled: boolean => void,
@ -13,23 +14,20 @@ type Props = {
location: UrlLocation, location: UrlLocation,
getSyncError: ?string, getSyncError: ?string,
disabled: boolean, disabled: boolean,
openModal: (string, any) => void,
}; };
function SyncToggle(props: Props) { function SyncToggle(props: Props) {
const { const {
setSyncEnabled,
syncEnabled,
verifiedEmail, verifiedEmail,
getSyncError, getSyncError,
history, history,
location: { pathname }, location: { pathname },
disabled = false, openModal,
syncEnabled,
disabled,
} = props; } = props;
function handleChange() {
setSyncEnabled(!syncEnabled);
}
if (getSyncError) { if (getSyncError) {
history.push(`/$/${PAGES.AUTH}?redirect=${pathname}&immediate=true`); history.push(`/$/${PAGES.AUTH}?redirect=${pathname}&immediate=true`);
return null; return null;
@ -48,7 +46,7 @@ function SyncToggle(props: Props) {
name="sync_toggle" name="sync_toggle"
label={__('Sync your balance and preferences across devices.')} label={__('Sync your balance and preferences across devices.')}
checked={syncEnabled} checked={syncEnabled}
onChange={handleChange} onChange={() => openModal(MODALS.SYNC_ENABLE, { mode: syncEnabled ? 'disable' : 'enable' })}
disabled={disabled} disabled={disabled}
/> />
)} )}

View file

@ -7,8 +7,8 @@ import {
selectUser, selectUser,
} from 'redux/selectors/user'; } from 'redux/selectors/user';
import { DAEMON_SETTINGS, SETTINGS } from 'lbry-redux'; import { DAEMON_SETTINGS, SETTINGS } from 'lbry-redux';
import { doSetSyncPref, doSetDaemonSetting } from 'redux/actions/settings'; import { doSetWalletSyncPreference, doSetDaemonSetting } from 'redux/actions/settings';
import { makeSelectClientSetting, selectDaemonSettings } from 'redux/selectors/settings'; import { selectDaemonSettings, makeSelectClientSetting } from 'redux/selectors/settings';
import UserEmailNew from './view'; import UserEmailNew from './view';
const select = state => ({ const select = state => ({
@ -21,7 +21,7 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
setSync: value => dispatch(doSetSyncPref(value)), setSync: value => dispatch(doSetWalletSyncPreference(value)),
setShareDiagnosticData: shouldShareData => setShareDiagnosticData: shouldShareData =>
dispatch(doSetDaemonSetting(DAEMON_SETTINGS.SHARE_USAGE_DATA, shouldShareData)), dispatch(doSetDaemonSetting(DAEMON_SETTINGS.SHARE_USAGE_DATA, shouldShareData)),
doSignUp: (email, password) => dispatch(doUserSignUp(email, password)), doSignUp: (email, password) => dispatch(doUserSignUp(email, password)),

View file

@ -8,7 +8,7 @@ import {
selectEmailNewIsPending, selectEmailNewIsPending,
} from 'redux/selectors/user'; } from 'redux/selectors/user';
import { doUserCheckIfEmailExists, doClearEmailEntry } from 'redux/actions/user'; import { doUserCheckIfEmailExists, doClearEmailEntry } from 'redux/actions/user';
import { doSetSyncPref } from 'redux/actions/settings'; import { doSetWalletSyncPreference } from 'redux/actions/settings';
import UserEmailReturning from './view'; import UserEmailReturning from './view';
const select = state => ({ const select = state => ({
@ -23,5 +23,5 @@ const select = state => ({
export default connect(select, { export default connect(select, {
doUserCheckIfEmailExists, doUserCheckIfEmailExists,
doClearEmailEntry, doClearEmailEntry,
doSetSyncPref, doSetWalletSyncPreference,
})(UserEmailReturning); })(UserEmailReturning);

View file

@ -17,7 +17,7 @@ type Props = {
doClearEmailEntry: () => void, doClearEmailEntry: () => void,
doUserSignIn: (string, ?string) => void, doUserSignIn: (string, ?string) => void,
doUserCheckIfEmailExists: string => void, doUserCheckIfEmailExists: string => void,
doSetSyncPref: boolean => void, doSetWalletSyncPreference: boolean => void,
doSetClientSetting: (string, boolean, ?boolean) => void, doSetClientSetting: (string, boolean, ?boolean) => void,
isPending: boolean, isPending: boolean,
}; };
@ -30,7 +30,7 @@ function UserEmailReturning(props: Props) {
emailToVerify, emailToVerify,
doClearEmailEntry, doClearEmailEntry,
emailDoesNotExist, emailDoesNotExist,
doSetSyncPref, doSetWalletSyncPreference,
isPending, isPending,
} = props; } = props;
const { push, location } = useHistory(); const { push, location } = useHistory();
@ -48,7 +48,7 @@ function UserEmailReturning(props: Props) {
function handleSubmit() { function handleSubmit() {
// @if TARGET='app' // @if TARGET='app'
doSetSyncPref(syncEnabled); doSetWalletSyncPreference(syncEnabled);
// @endif // @endif
doUserCheckIfEmailExists(email); doUserCheckIfEmailExists(email);
} }

View file

@ -133,7 +133,6 @@ export const UPDATE_IS_NIGHT = 'UPDATE_IS_NIGHT';
export const FINDING_FFMPEG_STARTED = 'FINDING_FFMPEG_STARTED'; export const FINDING_FFMPEG_STARTED = 'FINDING_FFMPEG_STARTED';
export const FINDING_FFMPEG_COMPLETED = 'FINDING_FFMPEG_COMPLETED'; export const FINDING_FFMPEG_COMPLETED = 'FINDING_FFMPEG_COMPLETED';
export const SYNC_CLIENT_SETTINGS = 'SYNC_CLIENT_SETTINGS'; export const SYNC_CLIENT_SETTINGS = 'SYNC_CLIENT_SETTINGS';
export const SYNC_PREFERENCE_CHANGED = 'SYNC_PREFERENCE_CHANGED';
// User // User
export const AUTHENTICATION_STARTED = 'AUTHENTICATION_STARTED'; export const AUTHENTICATION_STARTED = 'AUTHENTICATION_STARTED';

View file

@ -39,5 +39,6 @@ export const REPOST = 'repost';
export const SIGN_OUT = 'sign_out'; export const SIGN_OUT = 'sign_out';
export const LIQUIDATE_SUPPORTS = 'liquidate_supports'; export const LIQUIDATE_SUPPORTS = 'liquidate_supports';
export const CONFIRM_AGE = 'confirm_age'; export const CONFIRM_AGE = 'confirm_age';
export const SYNC_ENABLE = 'SYNC_ENABLE';
export const REMOVE_BLOCKED = 'remove_blocked'; export const REMOVE_BLOCKED = 'remove_blocked';
export const IMAGE_UPLOAD = 'image_upload'; export const IMAGE_UPLOAD = 'image_upload';

View file

@ -38,6 +38,7 @@ import ModalSignOut from 'modal/modalSignOut';
import ModalSupportsLiquidate from 'modal/modalSupportsLiquidate'; import ModalSupportsLiquidate from 'modal/modalSupportsLiquidate';
import ModalConfirmAge from 'modal/modalConfirmAge'; import ModalConfirmAge from 'modal/modalConfirmAge';
import ModalFileSelection from 'modal/modalFileSelection'; import ModalFileSelection from 'modal/modalFileSelection';
import ModalSyncEnable from 'modal/modalSyncEnable';
import ModalImageUpload from 'modal/modalImageUpload'; import ModalImageUpload from 'modal/modalImageUpload';
type Props = { type Props = {
@ -140,6 +141,8 @@ function ModalRouter(props: Props) {
return <ModalRemoveBlocked {...modalProps} />; return <ModalRemoveBlocked {...modalProps} />;
case MODALS.IMAGE_UPLOAD: case MODALS.IMAGE_UPLOAD:
return <ModalImageUpload {...modalProps} />; return <ModalImageUpload {...modalProps} />;
case MODALS.SYNC_ENABLE:
return <ModalSyncEnable {...modalProps} />;
default: default:
return null; return null;
} }

View file

@ -0,0 +1,11 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import ModalSyncEnable from './view';
const perform = dispatch => () => ({
closeModal: () => {
dispatch(doHideModal());
},
});
export default connect(null, perform)(ModalSyncEnable);

View file

@ -0,0 +1,21 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
import SyncToggleFlow from 'component/syncEnableFlow';
type Props = {
closeModal: () => void,
mode: string,
};
const ModalSyncEnable = (props: Props) => {
const { closeModal, mode } = props;
return (
<Modal isOpen type="card" onAborted={closeModal}>
<SyncToggleFlow closeModal={closeModal} mode={mode} />
</Modal>
);
};
export default ModalSyncEnable;

View file

@ -33,7 +33,6 @@ const select = state => ({
hideReposts: makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state), hideReposts: makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state),
darkModeTimes: makeSelectClientSetting(SETTINGS.DARK_MODE_TIMES)(state), darkModeTimes: makeSelectClientSetting(SETTINGS.DARK_MODE_TIMES)(state),
language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state), language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({

View file

@ -64,7 +64,6 @@ type Props = {
setDarkTime: (string, {}) => void, setDarkTime: (string, {}) => void,
openModal: string => void, openModal: string => void,
language?: string, language?: string,
syncEnabled: boolean,
enterSettings: () => void, enterSettings: () => void,
exitSettings: () => void, exitSettings: () => void,
}; };

View file

@ -53,7 +53,6 @@ type Props = {
findingFFmpeg: boolean, findingFFmpeg: boolean,
findFFmpeg: () => void, findFFmpeg: () => void,
language?: string, language?: string,
syncEnabled: boolean,
syncSettings: () => void, syncSettings: () => void,
enterSettings: () => void, enterSettings: () => void,
exitSettings: () => void, exitSettings: () => void,

View file

@ -21,6 +21,7 @@ import {
selectFollowedTagsList, selectFollowedTagsList,
SHARED_PREFERENCES, SHARED_PREFERENCES,
DAEMON_SETTINGS, DAEMON_SETTINGS,
SETTINGS,
} from 'lbry-redux'; } from 'lbry-redux';
import { doToast, doError, doNotificationList } from 'redux/actions/notifications'; import { doToast, doError, doNotificationList } from 'redux/actions/notifications';
import Native from 'native'; import Native from 'native';
@ -43,7 +44,7 @@ import {
selectModal, selectModal,
selectAllowAnalytics, selectAllowAnalytics,
} from 'redux/selectors/app'; } from 'redux/selectors/app';
import { selectDaemonSettings } from 'redux/selectors/settings'; import { selectDaemonSettings, makeSelectClientSetting } from 'redux/selectors/settings';
import { selectUser } from 'redux/selectors/user'; import { selectUser } from 'redux/selectors/user';
// import { selectDaemonSettings } from 'redux/selectors/settings'; // import { selectDaemonSettings } from 'redux/selectors/settings';
import { doSyncSubscribe } from 'redux/actions/syncwrapper'; import { doSyncSubscribe } from 'redux/actions/syncwrapper';
@ -596,9 +597,11 @@ export function doGetAndPopulatePreferences() {
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState(); const state = getState();
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
const hasVerifiedEmail = state.user && state.user.user && state.user.user.has_verified_email;
let preferenceKey; let preferenceKey;
// @if TARGET='app' // @if TARGET='app'
preferenceKey = state.user && state.user.user && state.user.user.has_verified_email ? 'shared' : 'anon'; preferenceKey = syncEnabled && hasVerifiedEmail ? 'shared' : 'local';
// @endif // @endif
// @if TARGET='web' // @if TARGET='web'
preferenceKey = 'shared'; preferenceKey = 'shared';

View file

@ -131,34 +131,12 @@ export function doSetClientSetting(key, value, pushPrefs) {
value, value,
}, },
}); });
if (pushPrefs) { if (pushPrefs) {
dispatch(doPushSettingsToPrefs()); dispatch(doPushSettingsToPrefs());
} }
}; };
} }
export function doUpdateSyncPrefIfFalse() {
// This is only called after manual signin to update the wallet
// that the sync preference is false
return (dispatch, getState) => {
const state = getState();
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
if (syncEnabled === false) {
dispatch(doPushSettingsToPrefs());
}
};
}
export function doSetSyncPref(isEnabled) {
return dispatch => {
dispatch({
type: LOCAL_ACTIONS.SYNC_PREFERENCE_CHANGED,
data: isEnabled,
});
};
}
export function doUpdateIsNight() { export function doUpdateIsNight() {
return { return {
type: ACTIONS.UPDATE_IS_NIGHT, type: ACTIONS.UPDATE_IS_NIGHT,
@ -195,6 +173,32 @@ export function doSetDarkTime(value, options) {
}; };
} }
export function doGetWalletSyncPreference() {
const SYNC_KEY = 'enable-sync';
return dispatch => {
return Lbry.preference_get({ key: SYNC_KEY }).then(result => {
const enabled = result && result[SYNC_KEY];
if (enabled !== null) {
dispatch(doSetClientSetting(SETTINGS.ENABLE_SYNC, enabled));
}
return enabled;
});
};
}
export function doSetWalletSyncPreference(pref) {
const SYNC_KEY = 'enable-sync';
return dispatch => {
return Lbry.preference_set({ key: SYNC_KEY, value: pref }).then(result => {
const enabled = result && result[SYNC_KEY];
if (enabled !== null) {
dispatch(doSetClientSetting(SETTINGS.ENABLE_SYNC, enabled));
}
return enabled;
});
};
}
export function doPushSettingsToPrefs() { export function doPushSettingsToPrefs() {
return dispatch => { return dispatch => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -211,6 +215,9 @@ export function doEnterSettingsPage() {
const state = getState(); const state = getState();
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state); const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
const hasVerifiedEmail = state.user && state.user.user && state.user.user.has_verified_email; const hasVerifiedEmail = state.user && state.user.user && state.user.user.has_verified_email;
if (IS_WEB && !hasVerifiedEmail) {
return;
}
dispatch(doSyncUnsubscribe()); dispatch(doSyncUnsubscribe());
if (syncEnabled && hasVerifiedEmail) { if (syncEnabled && hasVerifiedEmail) {
await dispatch(doGetSyncDesktop()); await dispatch(doGetSyncDesktop());
@ -223,6 +230,11 @@ export function doEnterSettingsPage() {
export function doExitSettingsPage() { export function doExitSettingsPage() {
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState();
const hasVerifiedEmail = state.user && state.user.user && state.user.user.has_verified_email;
if (IS_WEB && !hasVerifiedEmail) {
return;
}
dispatch(doSetSyncLock(false)); dispatch(doSetSyncLock(false));
dispatch(doPushSettingsToPrefs()); dispatch(doPushSettingsToPrefs());
// syncSubscribe is restarted in store.js sharedStateCB if necessary // syncSubscribe is restarted in store.js sharedStateCB if necessary

View file

@ -1,11 +1,11 @@
// @flow // @flow
import { doGetSync, selectGetSyncIsPending, selectSetSyncIsPending } from 'lbryinc'; import { doGetSync, selectGetSyncIsPending, selectSetSyncIsPending } from 'lbryinc';
import { SETTINGS } from 'lbry-redux'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { makeSelectClientSetting, selectSyncSigninPref } from 'redux/selectors/settings';
import { getSavedPassword } from 'util/saved-passwords'; import { getSavedPassword } from 'util/saved-passwords';
import { doAnalyticsTagSync, doHandleSyncComplete } from 'redux/actions/app'; import { doAnalyticsTagSync, doHandleSyncComplete } from 'redux/actions/app';
import { selectSyncIsLocked } from 'redux/selectors/app'; import { selectSyncIsLocked } from 'redux/selectors/app';
import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { SETTINGS } from 'lbry-redux';
let syncTimer = null; let syncTimer = null;
const SYNC_INTERVAL = 1000 * 60 * 5; // 5 minutes const SYNC_INTERVAL = 1000 * 60 * 5; // 5 minutes
@ -31,10 +31,9 @@ export function doSyncSubscribe() {
if (syncTimer) clearInterval(syncTimer); if (syncTimer) clearInterval(syncTimer);
const state = getState(); const state = getState();
const hasVerifiedEmail = selectUserVerifiedEmail(state); const hasVerifiedEmail = selectUserVerifiedEmail(state);
const signInSyncPref = selectSyncSigninPref(state);
const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state); const syncEnabled = makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state);
const syncLocked = selectSyncIsLocked(state); const syncLocked = selectSyncIsLocked(state);
if (hasVerifiedEmail && syncEnabled && !syncLocked && signInSyncPref !== false) { if (hasVerifiedEmail && syncEnabled && !syncLocked) {
dispatch(doGetSyncDesktop((error, hasNewData) => dispatch(doHandleSyncComplete(error, hasNewData)))); dispatch(doGetSyncDesktop((error, hasNewData) => dispatch(doHandleSyncComplete(error, hasNewData))));
dispatch(doAnalyticsTagSync()); dispatch(doAnalyticsTagSync());
syncTimer = setInterval(() => { syncTimer = setInterval(() => {

View file

@ -24,7 +24,6 @@ const defaultState = {
findingFFmpeg: false, findingFFmpeg: false,
loadedLanguages: [...Object.keys(window.i18n_messages), 'en'] || ['en'], loadedLanguages: [...Object.keys(window.i18n_messages), 'en'] || ['en'],
customWalletServers: [], customWalletServers: [],
syncEnabledPref: undefined, // set this during sign in, copy it to clientSettings immediately after prefGet after signedin but before sync
sharedPreferences: {}, sharedPreferences: {},
daemonSettings: {}, daemonSettings: {},
daemonStatus: { ffmpeg_status: {} }, daemonStatus: { ffmpeg_status: {} },
@ -153,28 +152,15 @@ reducers[ACTIONS.SYNC_CLIENT_SETTINGS] = state => {
return Object.assign({}, state, { sharedPreferences: newSharedPreferences }); 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) => { reducers[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE] = (state, action) => {
const { clientSettings: currentClientSettings, syncEnabledPref } = state; const { clientSettings: currentClientSettings } = state;
const { settings: sharedPreferences } = action.data; const { settings: sharedPreferences } = action.data;
// we have to update the signin sync checkbox in here
// where we can simulataneously set the checkbox temp value to undefined, and
// update the sync setting before sync happens
// temp box must be undefined to trigger the items in the syncSubscribe effect
const syncSettingOrEmpty = syncEnabledPref !== undefined ? { enable_sync: syncEnabledPref } : {};
const selectedSettings = sharedPreferences ? getSubsetFromKeysArray(sharedPreferences, clientSyncKeys) : {}; const selectedSettings = sharedPreferences ? getSubsetFromKeysArray(sharedPreferences, clientSyncKeys) : {};
const mergedClientSettings = { ...currentClientSettings, ...selectedSettings, ...syncSettingOrEmpty }; const mergedClientSettings = { ...currentClientSettings, ...selectedSettings };
const newSharedPreferences = sharedPreferences || {}; const newSharedPreferences = sharedPreferences || {};
return Object.assign({}, state, { return Object.assign({}, state, {
sharedPreferences: newSharedPreferences, sharedPreferences: newSharedPreferences,
clientSettings: mergedClientSettings, clientSettings: mergedClientSettings,
syncEnabledPref: undefined,
}); });
}; };

View file

@ -11,8 +11,6 @@ export const selectFfmpegStatus = createSelector(selectDaemonStatus, status => s
export const selectFindingFFmpeg = createSelector(selectState, state => state.findingFFmpeg || false); export const selectFindingFFmpeg = createSelector(selectState, state => state.findingFFmpeg || false);
export const selectSyncSigninPref = createSelector(selectState, state => state.syncEnabledPref);
export const selectClientSettings = createSelector(selectState, state => state.clientSettings || {}); export const selectClientSettings = createSelector(selectState, state => state.clientSettings || {});
export const selectLoadedLanguages = createSelector(selectState, state => state.loadedLanguages || {}); export const selectLoadedLanguages = createSelector(selectState, state => state.loadedLanguages || {});

View file

@ -6411,9 +6411,9 @@ lazy-val@^1.0.4:
yargs "^13.2.2" yargs "^13.2.2"
zstd-codec "^0.1.1" zstd-codec "^0.1.1"
lbry-redux@lbryio/lbry-redux#437c54f164b4132c0d5c6ede60c7b02703f1e9d5: lbry-redux@lbryio/lbry-redux#e10295b5ec2ef42426755ed9fd50bd250b0d76dd:
version "0.0.1" version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/437c54f164b4132c0d5c6ede60c7b02703f1e9d5" resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/e10295b5ec2ef42426755ed9fd50bd250b0d76dd"
dependencies: dependencies:
proxy-polyfill "0.1.6" proxy-polyfill "0.1.6"
reselect "^3.0.0" reselect "^3.0.0"