sync reducer stuff

bring tags into app repo

prevent prefset until prefsReady

prefs ready on sign up

prefsReady-desktop
This commit is contained in:
jessop 2020-10-05 14:31:51 -04:00 committed by Sean Yesmunt
parent f54a0de797
commit 9d4f7dc642
38 changed files with 925 additions and 146 deletions

View file

@ -1348,6 +1348,9 @@
"Create a channel": "Create a channel", "Create a channel": "Create a channel",
"Credit Details": "Credit Details", "Credit Details": "Credit Details",
"LBRY Credits": "LBRY Credits", "LBRY Credits": "LBRY Credits",
"Mark all as read": "Mark all as read",
"Log in to %SITE_NAME% to earn rewards From Inviting Your Friends": "Log in to %SITE_NAME% to earn rewards From Inviting Your Friends",
"Confirming...": "Confirming...",
"Pinned by @%channel%": "Pinned by @%channel%", "Pinned by @%channel%": "Pinned by @%channel%",
"Pinned by creator": "Pinned by creator", "Pinned by creator": "Pinned by creator",
"Claim Your %reward_amount% Credit Invite Reward": "Claim Your %reward_amount% Credit Invite Reward", "Claim Your %reward_amount% Credit Invite Reward": "Claim Your %reward_amount% Credit Invite Reward",

View file

@ -9,7 +9,7 @@ import { doFetchChannelListMine, SETTINGS } from 'lbry-redux';
import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings';
import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded, selectModal } from 'redux/selectors/app'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded, selectModal } from 'redux/selectors/app';
import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings'; import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings';
import { doSyncSubscribe } from 'redux/actions/syncwrapper'; import { doSyncSubscribe } from 'redux/actions/sync';
import { import {
doDownloadUpgradeRequested, doDownloadUpgradeRequested,
doSignIn, doSignIn,

View file

@ -5,8 +5,8 @@ import {
selectClaimSearchByQueryLastPageReached, selectClaimSearchByQueryLastPageReached,
selectFetchingClaimSearch, selectFetchingClaimSearch,
SETTINGS, SETTINGS,
selectFollowedTags,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectFollowedTags } from 'redux/selectors/tags';
import { selectBlockedChannels } from 'redux/selectors/blocked'; import { selectBlockedChannels } from 'redux/selectors/blocked';
import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { doToggleTagFollowDesktop } from 'redux/actions/tags';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFetchingClaimSearch, SETTINGS, selectFollowedTags } from 'lbry-redux'; import { selectFetchingClaimSearch, SETTINGS } from 'lbry-redux';
import { selectFollowedTags } from 'redux/selectors/tags';
import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { doToggleTagFollowDesktop } from 'redux/actions/tags';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectTagsForUri, selectFollowedTags } from 'lbry-redux'; import { makeSelectTagsForUri } from 'lbry-redux';
import { selectFollowedTags } from 'redux/selectors/tags';
import ClaimTags from './view'; import ClaimTags from './view';
const select = (state, props) => ({ const select = (state, props) => ({
@ -7,7 +8,4 @@ const select = (state, props) => ({
followedTags: selectFollowedTags(state), followedTags: selectFollowedTags(state),
}); });
export default connect( export default connect(select, null)(ClaimTags);
select,
null
)(ClaimTags);

View file

@ -1,6 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import { selectFollowedTags, selectPurchaseUriSuccess, doClearPurchasedUriSuccess, SETTINGS } from 'lbry-redux'; import { selectPurchaseUriSuccess, doClearPurchasedUriSuccess, SETTINGS } from 'lbry-redux';
import { selectFollowedTags } from 'redux/selectors/tags';
import { selectUserVerifiedEmail, selectUser } from 'redux/selectors/user'; import { selectUserVerifiedEmail, selectUser } from 'redux/selectors/user';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSignOut } from 'redux/actions/app'; import { doSignOut } from 'redux/actions/app';

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectGetSyncIsPending, selectSyncApplyPasswordError } from 'redux/selectors/sync'; import { selectGetSyncIsPending, selectSyncApplyPasswordError } from 'redux/selectors/sync';
import { doGetSyncDesktop } from 'redux/actions/syncwrapper'; import { doGetSyncDesktop } from 'redux/actions/sync';
import { selectUserEmail } from 'redux/selectors/user'; import { selectUserEmail } from 'redux/selectors/user';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import { doSignOut, doHandleSyncComplete } from 'redux/actions/app'; import { doSignOut, doHandleSyncComplete } from 'redux/actions/app';

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUnfollowedTags, selectFollowedTags, doReplaceTags, doAddTag, doDeleteTag } from 'lbry-redux'; import { selectUnfollowedTags, selectFollowedTags } from 'redux/selectors/tags';
import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { doToggleTagFollowDesktop, doAddTag, doDeleteTag } from 'redux/actions/tags';
import DiscoveryFirstRun from './view'; import DiscoveryFirstRun from './view';
const select = (state, props) => ({ const select = (state, props) => ({
@ -8,12 +8,8 @@ const select = (state, props) => ({
followedTags: selectFollowedTags(state), followedTags: selectFollowedTags(state),
}); });
export default connect( export default connect(select, {
select, doToggleTagFollowDesktop,
{ doAddTag,
doToggleTagFollowDesktop, doDeleteTag,
doAddTag, })(DiscoveryFirstRun);
doDeleteTag,
doReplaceTags,
}
)(DiscoveryFirstRun);

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUnfollowedTags, selectFollowedTags, doReplaceTags, doAddTag, doDeleteTag } from 'lbry-redux'; import { selectUnfollowedTags, selectFollowedTags } from 'redux/selectors/tags';
import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { doToggleTagFollowDesktop, doAddTag, doDeleteTag } from 'redux/actions/tags';
import DiscoveryFirstRun from './view'; import DiscoveryFirstRun from './view';
const select = (state, props) => ({ const select = (state, props) => ({
@ -8,12 +8,8 @@ const select = (state, props) => ({
followedTags: selectFollowedTags(state), followedTags: selectFollowedTags(state),
}); });
export default connect( export default connect(select, {
select, doToggleTagFollowDesktop,
{ doAddTag,
doToggleTagFollowDesktop, doDeleteTag,
doAddTag, })(DiscoveryFirstRun);
doDeleteTag,
doReplaceTags,
}
)(DiscoveryFirstRun);

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'redux/selectors/tags';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import { doChannelSubscribe } from 'redux/actions/subscriptions'; import { doChannelSubscribe } from 'redux/actions/subscriptions';
import UserChannelFollowIntro from './view'; import UserChannelFollowIntro from './view';
@ -13,7 +13,4 @@ const perform = dispatch => ({
channelSubscribe: uri => dispatch(doChannelSubscribe(uri)), channelSubscribe: uri => dispatch(doChannelSubscribe(uri)),
}); });
export default connect( export default connect(select, perform)(UserChannelFollowIntro);
select,
perform
)(UserChannelFollowIntro);

View file

@ -22,6 +22,8 @@ import {
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { selectInterestedInYoutubeSync } from 'redux/selectors/app'; import { selectInterestedInYoutubeSync } from 'redux/selectors/app';
import { doToggleInterestedInYoutubeSync } from 'redux/actions/app'; import { doToggleInterestedInYoutubeSync } from 'redux/actions/app';
import { doSetPrefsReady } from 'redux/actions/sync';
import UserSignIn from './view'; import UserSignIn from './view';
const select = state => ({ const select = state => ({
@ -63,6 +65,7 @@ const perform = dispatch => ({
), ),
setClientSetting: (setting, value, pushToPrefs) => dispatch(doSetClientSetting(setting, value, pushToPrefs)), setClientSetting: (setting, value, pushToPrefs) => dispatch(doSetClientSetting(setting, value, pushToPrefs)),
doToggleInterestedInYoutubeSync: () => dispatch(doToggleInterestedInYoutubeSync()), doToggleInterestedInYoutubeSync: () => dispatch(doToggleInterestedInYoutubeSync()),
setPrefsReady: () => dispatch(doSetPrefsReady()),
}); });
export default connect(select, perform)(UserSignIn); export default connect(select, perform)(UserSignIn);

View file

@ -45,6 +45,7 @@ type Props = {
rewardsAcknowledged: boolean, rewardsAcknowledged: boolean,
interestedInYoutubeSync: boolean, interestedInYoutubeSync: boolean,
doToggleInterestedInYoutubeSync: () => void, doToggleInterestedInYoutubeSync: () => void,
setPrefsReady: () => void,
}; };
function UserSignUp(props: Props) { function UserSignUp(props: Props) {
@ -70,6 +71,7 @@ function UserSignUp(props: Props) {
setClientSetting, setClientSetting,
interestedInYoutubeSync, interestedInYoutubeSync,
doToggleInterestedInYoutubeSync, doToggleInterestedInYoutubeSync,
setPrefsReady,
} = props; } = props;
const { const {
location: { search, pathname }, location: { search, pathname },
@ -133,9 +135,10 @@ function UserSignUp(props: Props) {
React.useEffect(() => { React.useEffect(() => {
if (hasVerifiedEmail) { if (hasVerifiedEmail) {
setPrefsReady();
setSettingAndSync(SETTINGS.FIRST_RUN_STARTED, true); setSettingAndSync(SETTINGS.FIRST_RUN_STARTED, true);
} }
}, [hasVerifiedEmail]); }, [hasVerifiedEmail, setPrefsReady]);
React.useEffect(() => { React.useEffect(() => {
// Don't claim the reward if sync is enabled until after a sync has been completed successfully // Don't claim the reward if sync is enabled until after a sync has been completed successfully

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'redux/selectors/tags';
import UserTagFollowIntro from './view'; import UserTagFollowIntro from './view';
const select = state => ({ const select = state => ({

View file

@ -279,6 +279,11 @@ export const COMMENT_SET_CHANNEL = 'COMMENT_SET_CHANNEL';
// Blocked channels // Blocked channels
export const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL'; export const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL';
// Tags
export const TOGGLE_TAG_FOLLOW = 'TOGGLE_TAG_FOLLOW';
export const TAG_ADD = 'TAG_ADD';
export const TAG_DELETE = 'TAG_DELETE';
// Notifications // Notifications
export const WS_CONNECT = 'WS_CONNECT'; export const WS_CONNECT = 'WS_CONNECT';
export const WS_DISCONNECT = 'WS_DISCONNECT'; export const WS_DISCONNECT = 'WS_DISCONNECT';
@ -290,6 +295,7 @@ export const GET_SYNC_FAILED = 'GET_SYNC_FAILED';
export const SET_SYNC_STARTED = 'SET_SYNC_STARTED'; export const SET_SYNC_STARTED = 'SET_SYNC_STARTED';
export const SET_SYNC_FAILED = 'SET_SYNC_FAILED'; export const SET_SYNC_FAILED = 'SET_SYNC_FAILED';
export const SET_SYNC_COMPLETED = 'SET_SYNC_COMPLETED'; export const SET_SYNC_COMPLETED = 'SET_SYNC_COMPLETED';
export const SET_PREFS_READY = 'SET_PREFS_READY';
export const SET_DEFAULT_ACCOUNT = 'SET_DEFAULT_ACCOUNT'; export const SET_DEFAULT_ACCOUNT = 'SET_DEFAULT_ACCOUNT';
export const SYNC_APPLY_STARTED = 'SYNC_APPLY_STARTED'; export const SYNC_APPLY_STARTED = 'SYNC_APPLY_STARTED';
export const SYNC_APPLY_COMPLETED = 'SYNC_APPLY_COMPLETED'; export const SYNC_APPLY_COMPLETED = 'SYNC_APPLY_COMPLETED';

546
ui/constants/tags.js Normal file
View file

@ -0,0 +1,546 @@
export const DEFAULT_FOLLOWED_TAGS = [
'art',
'automotive',
'blockchain',
'comedy',
'economics',
'education',
'gaming',
'music',
'news',
'science',
'sports',
'technology',
];
export const MATURE_TAGS = [
'porn',
'porno',
'nsfw',
'mature',
'xxx',
'sex',
'creampie',
'blowjob',
'handjob',
'vagina',
'boobs',
'big boobs',
'big dick',
'pussy',
'cumshot',
'anal',
'hard fucking',
'ass',
'fuck',
'hentai',
];
const DEFAULT_ENGLISH_KNOWN_TAGS = [
'free speech',
'censorship',
'gaming',
'pop culture',
'entertainment',
'technology',
'music',
'funny',
'education',
'learning',
'news',
'gameplay',
'nature',
'beliefs',
'comedy',
'games',
'film & animation',
'game',
'weapons',
'blockchain',
'video game',
'sports',
'walkthrough',
'lbrytvpaidbeta',
'art',
'pc',
'minecraft',
'playthrough',
'economics',
'automotive',
'play',
'tutorial',
'twitch',
'how to',
'ps4',
'bitcoin',
'fortnite',
'commentary',
'lets play',
'fun',
'politics',
'travel',
'food',
'science',
'xbox',
'liberal',
'democrat',
'progressive',
'survival',
'non-profits',
'activism',
'cryptocurrency',
'playstation',
'nintendo',
'government',
'steam',
'podcast',
'gamer',
'horror',
'conservative',
'reaction',
'trailer',
'love',
'cnn',
'republican',
'political',
'hangoutsonair',
'hoa',
'msnbc',
'cbs',
'anime',
'donald trump',
'fiction',
'fox news',
'crypto',
'ethereum',
'call of duty',
'android',
'multiplayer',
'epic',
'rpg',
'adventure',
'secular talk',
'btc',
'atheist',
'atheism',
'video games',
'ps3',
'cod',
'online',
'agnostic',
'movie',
'fps',
'lets',
'mod',
'world',
'reviews',
'sharefactory',
'space',
'pokemon',
'stream',
'hilarious',
'lol',
'sony',
'god',
'dance',
'pvp',
'tech',
'strategy',
'zombies',
'fail',
'film',
'xbox360',
'animation',
'unboxing',
'money',
'wwe',
'mods',
'indie',
'pubg',
'ios',
'history',
'rap',
'mobile',
'trump',
'hack',
'flat earth',
'trap',
'humor',
'vlogging',
'fox',
'news radio',
'facebook',
'edm',
'fitness',
'vaping',
'hip hop',
'secular',
'jesus',
'song',
'vape',
'guitar',
'remix',
'mining',
'daily',
'diy',
'pets',
'videogame',
'death',
'funny moments',
'religion',
'media',
'viral',
'war',
'nbc',
'freedom',
'gold',
'family',
'meme',
'zombie',
'photography',
'chill',
'sniper',
'computer',
'iphone',
'dragon',
'bible',
'pro',
'overwatch',
'litecoin',
'gta',
'house',
'fire',
'bass',
'truth',
'crash',
'mario',
'league of legends',
'wii',
'mmorpg',
'health',
'marvel',
'racing',
'apple',
'instrumental',
'earth',
'destiny',
'satire',
'race',
'training',
'electronic',
'boss',
'roblox',
'family friendly',
'california',
'react',
'christian',
'mmo',
'twitter',
'help',
'star',
'cars',
'random',
'top 10',
'ninja',
'guns',
'linux',
'lessons',
'vegan',
'future',
'dota 2',
'studio',
'star wars',
'shooting',
'nasa',
'rock',
'league',
'subscribe',
'water',
'gta v',
'car',
'samsung',
'music video',
'skyrim',
'dog',
'comics',
'shooter game',
'bo3',
'halloween',
'liberty',
'eth',
'conspiracy',
'knife',
'fashion',
'stories',
'vapor',
'nvidia',
'cute',
'beat',
'nintendo switch',
'fantasy',
'christmas',
'world of warcraft',
'industry',
'cartoon',
'garden',
'animals',
'windows',
'happy',
'magic',
'memes',
'design',
'tactical',
'fallout 4',
'puzzle',
'parody',
'rv',
'beats',
'building',
'disney',
'drone',
'ps2',
'beach',
'metal',
'christianity',
'business',
'mix',
'bo2',
'cover',
'senate',
'4k',
'united states',
'final',
'hero',
'playing',
'dlc',
'ubisoft',
'halo',
'pc gaming',
'raw',
'investing',
'online learning',
'software',
'ark',
'mojang',
'console',
'battle royale',
'canon',
'microsoft',
'camping',
'ufo',
'progressive talk',
'switch',
'fpv',
'arcade',
'school',
'driving',
'bodybuilding',
'drama',
'retro',
'science fiction',
'eggs',
'australia',
'modded',
'rainbow',
'gamers',
'resident evil',
'drawing',
'brasil',
'england',
'hillary clinton',
'singing',
'final fantasy',
'hiphop',
'video blog',
'mature',
'quad',
'noob',
'simulation',
'illuminati',
'poetry',
'dayz',
'manga',
'howto',
'insane',
'press',
'special',
'church',
'ico',
'weird',
'libertarian',
'crafting',
'level',
'comic',
'sandbox',
'daily vlog',
'outdoor',
'black ops',
'sound',
'christ',
'duty',
'juvenile fiction',
'pc game',
'how-to',
'ww2',
'creepy',
'artist',
'galaxy',
'destiny 2',
'new music',
'quest',
'lee',
'pacman',
'super smash bros',
'day',
'survival horror',
'patreon',
'bitcoin price',
'trending',
'open world',
'wii u',
'dope',
'reaper',
'sniping',
'dubstep',
'truck',
'planet',
'dc',
'amazon',
'spirituality',
'universe',
'video game culture',
'community',
'cat',
'aliens',
'tourism',
'altcoins',
'style',
'travel trailer',
'rda',
'gun',
'secret',
'far cry 5',
'auto',
'culture',
'dj',
'mw2',
'lord',
'full time rving',
'role-playing game',
'prank',
'grand theft auto',
'master',
'wrestling',
'sci-fi',
'workout',
'ghost',
'fake news',
'silly',
'season',
'bo4',
'trading',
'extreme',
'economy',
'combat',
'plays',
'muslim',
'pubg mobile',
'clips',
'bo1',
'paypal',
'sims',
'exploration',
'light',
'ripple',
'paranormal',
'football',
'capcom',
'rta',
'discord',
'batman',
'player',
'server',
'anarchy',
'military',
'playlist',
'cosplay',
'rv park',
'rant',
'edit',
'germany',
'reading',
'chris',
'flash',
'loot',
'bitcoin gratis',
'game reviews',
'movies',
'stupid',
'latest news',
'squad gameplay',
'guru',
'timelapse',
'black ops 3',
'holiday',
'soul',
'motivation',
'mw3',
'vacation',
'sega',
'19th century',
'pop',
'sims 4',
'post',
'smok',
'island',
'scotland',
'paladins',
'warrior',
'creepypasta',
'role-playing',
'solar',
'vr',
'animal',
'peace',
'consciousness',
'dota',
'audio',
'mass effect',
'humour',
'first look',
'videogames',
'future bass',
'freestyle',
'hardcore',
'portugal',
'dantdm',
'teaser',
'lbry',
'coronavirus',
'2020protests',
'covidcuts',
'covid-19',
'LBRYFoundationBoardCandidacy',
];
const DEFAULT_SPANISH_KNOWN_TAGS = [
'español',
'tecnología',
'criptomonedas',
'economía',
'bitcoin',
'educación',
'videojuegos',
'música',
'noticias',
'ciencia',
'deportes',
'latinoamérica',
'latam',
'conspiración',
'humor',
'política',
'tutoriales',
];
export const DEFAULT_KNOWN_TAGS = [...DEFAULT_ENGLISH_KNOWN_TAGS, ...DEFAULT_SPANISH_KNOWN_TAGS];

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'redux/selectors/tags';
import { selectBlockedChannels } from 'redux/selectors/blocked'; import { selectBlockedChannels } from 'redux/selectors/blocked';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import ChannelsFollowingManagePage from './view'; import ChannelsFollowingManagePage from './view';

View file

@ -1,7 +1,8 @@
import * as CS from 'constants/claim_search'; import * as CS from 'constants/claim_search';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectClaimForUri, selectFollowedTags, doResolveUri, SETTINGS } from 'lbry-redux'; import { makeSelectClaimForUri, doResolveUri, SETTINGS } from 'lbry-redux';
import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectFollowedTags } from 'redux/selectors/tags';
import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { doToggleTagFollowDesktop } from 'redux/actions/tags';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import Tags from './view'; import Tags from './view';

View file

@ -1,6 +1,6 @@
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'redux/selectors/tags';
import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'redux/selectors/tags';
import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import DiscoverPage from './view'; import DiscoverPage from './view';

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'redux/selectors/tags';
import { selectSubscriptions, selectSuggestedChannels } from 'redux/selectors/subscriptions'; import { selectSubscriptions, selectSuggestedChannels } from 'redux/selectors/subscriptions';
import { doFetchRecommendedSubscriptions } from 'redux/actions/subscriptions'; import { doFetchRecommendedSubscriptions } from 'redux/actions/subscriptions';
@ -11,9 +11,6 @@ const select = state => ({
suggestedSubscriptions: selectSuggestedChannels(state), suggestedSubscriptions: selectSuggestedChannels(state),
}); });
export default connect( export default connect(select, {
select, doFetchRecommendedSubscriptions,
{ })(TagsEdit);
doFetchRecommendedSubscriptions,
}
)(TagsEdit);

View file

@ -1,8 +1,9 @@
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router'; import { connectRouter } from 'connected-react-router';
import { claimsReducer, fileInfoReducer, walletReducer, tagsReducer, publishReducer } from 'lbry-redux'; import { claimsReducer, fileInfoReducer, walletReducer, publishReducer } from 'lbry-redux';
import { costInfoReducer, blacklistReducer, filteredReducer, homepageReducer, statsReducer, webReducer } from 'lbryinc'; import { costInfoReducer, blacklistReducer, filteredReducer, homepageReducer, statsReducer, webReducer } from 'lbryinc';
import appReducer from 'redux/reducers/app'; import appReducer from 'redux/reducers/app';
import tagsReducer from 'redux/reducers/tags';
import contentReducer from 'redux/reducers/content'; import contentReducer from 'redux/reducers/content';
import settingsReducer from 'redux/reducers/settings'; import settingsReducer from 'redux/reducers/settings';
import subscriptionsReducer from 'redux/reducers/subscriptions'; import subscriptionsReducer from 'redux/reducers/subscriptions';

View file

@ -18,12 +18,13 @@ import {
doClearPublish, doClearPublish,
doPreferenceGet, doPreferenceGet,
doClearSupport, doClearSupport,
selectFollowedTagsList,
SHARED_PREFERENCES, SHARED_PREFERENCES,
DAEMON_SETTINGS, DAEMON_SETTINGS,
SETTINGS, SETTINGS,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectFollowedTagsList } from 'redux/selectors/tags';
import { doToast, doError, doNotificationList } from 'redux/actions/notifications'; import { doToast, doError, doNotificationList } from 'redux/actions/notifications';
import Native from 'native'; import Native from 'native';
import { import {
doFetchDaemonSettings, doFetchDaemonSettings,
@ -47,7 +48,7 @@ import {
import { selectDaemonSettings, makeSelectClientSetting } 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, doSetPrefsReady } from 'redux/actions/sync';
import { doAuthenticate } from 'redux/actions/user'; import { doAuthenticate } from 'redux/actions/user';
import { lbrySettings as config, version as appVersion } from 'package.json'; import { lbrySettings as config, version as appVersion } from 'package.json';
import analytics, { SHARE_INTERNAL } from 'analytics'; import analytics, { SHARE_INTERNAL } from 'analytics';
@ -90,13 +91,6 @@ export function doUpdateDownloadProgress(percent) {
}; };
} }
export function doSetSyncLock(lock) {
return {
type: ACTIONS.SET_SYNC_LOCK,
data: lock,
};
}
export function doSkipUpgrade() { export function doSkipUpgrade() {
return { return {
type: ACTIONS.SKIP_UPGRADE, type: ACTIONS.SKIP_UPGRADE,
@ -340,6 +334,16 @@ export function doAlertError(errorList) {
}; };
} }
export function doAlertWaitingForSync() {
return dispatch =>
dispatch(
doToast({
message: __('Hold on, we are setting up your account'),
isError: false,
})
);
}
export function doDaemonReady() { export function doDaemonReady() {
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState(); const state = getState();
@ -628,6 +632,8 @@ export function doGetAndPopulatePreferences() {
}); });
} }
// @endif // @endif
} else {
dispatch(doSetPrefsReady());
} }
return true; return true;
} }

View file

@ -1,9 +1,20 @@
// @flow // @flow
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import { selectPrefsReady } from 'redux/selectors/sync';
import { doAlertWaitingForSync } from 'redux/actions/app';
export const doToggleBlockChannel = (uri: string) => ({ export const doToggleBlockChannel = (uri: string) => (dispatch: Dispatch, getState: GetState) => {
type: ACTIONS.TOGGLE_BLOCK_CHANNEL, const state = getState();
data: { const ready = selectPrefsReady(state);
uri,
}, if (!ready) {
}); return dispatch(doAlertWaitingForSync());
}
dispatch({
type: ACTIONS.TOGGLE_BLOCK_CHANNEL,
data: {
uri,
},
});
};

View file

@ -13,7 +13,7 @@ import {
import { doError } from 'redux/actions/notifications'; import { doError } from 'redux/actions/notifications';
import { push } from 'connected-react-router'; import { push } from 'connected-react-router';
import analytics from 'analytics'; import analytics from 'analytics';
import { doOpenModal } from './app'; import { doOpenModal } from 'redux/actions/app';
export const doPublishDesktop = (filePath: string, preview?: boolean) => (dispatch: Dispatch, getState: () => {}) => { export const doPublishDesktop = (filePath: string, preview?: boolean) => (dispatch: Dispatch, getState: () => {}) => {
const publishPreview = previewResponse => { const publishPreview = previewResponse => {

View file

@ -2,7 +2,7 @@
import { Lbryio } from 'lbryinc'; import { Lbryio } from 'lbryinc';
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import * as REACTION_TYPES from 'constants/reactions'; import * as REACTION_TYPES from 'constants/reactions';
import { makeSelectMyReactionForUri } from '../selectors/reactions'; import { makeSelectMyReactionForUri } from 'redux/selectors/reactions';
import { makeSelectClaimForUri } from 'lbry-redux'; import { makeSelectClaimForUri } from 'lbry-redux';
export const doFetchReactions = (claimId: string) => (dispatch: Dispatch) => { export const doFetchReactions = (claimId: string) => (dispatch: Dispatch) => {

View file

@ -5,8 +5,9 @@ import analytics from 'analytics';
import SUPPORTED_LANGUAGES from 'constants/supported_languages'; import SUPPORTED_LANGUAGES from 'constants/supported_languages';
import { launcher } from 'util/autoLaunch'; import { launcher } from 'util/autoLaunch';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doGetSyncDesktop, doSyncUnsubscribe } from 'redux/actions/syncwrapper'; import { doGetSyncDesktop, doSyncUnsubscribe, doSetSyncLock } from 'redux/actions/sync';
import { doGetAndPopulatePreferences, doSetSyncLock } from 'redux/actions/app'; import { doAlertWaitingForSync, doGetAndPopulatePreferences } from 'redux/actions/app';
import { selectPrefsReady } from 'redux/selectors/sync';
const { DEFAULT_LANGUAGE } = require('config'); const { DEFAULT_LANGUAGE } = require('config');
const { SDK_SYNC_KEYS } = SHARED_PREFERENCES; const { SDK_SYNC_KEYS } = SHARED_PREFERENCES;
@ -57,10 +58,18 @@ export function doGetDaemonStatus() {
} }
export function doClearDaemonSetting(key) { export function doClearDaemonSetting(key) {
return dispatch => { return (dispatch, getState) => {
const state = getState();
const ready = selectPrefsReady(state);
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
const clearKey = { const clearKey = {
key, key,
}; };
// not if syncLocked
Lbry.settings_clear(clearKey).then(defaultSettings => { Lbry.settings_clear(clearKey).then(defaultSettings => {
if (SDK_SYNC_KEYS.includes(key)) { if (SDK_SYNC_KEYS.includes(key)) {
dispatch({ dispatch({
@ -85,7 +94,14 @@ export function doClearDaemonSetting(key) {
} }
// if doPopulate is applying settings, we don't want to cause a loop; doNotDispatch = true. // if doPopulate is applying settings, we don't want to cause a loop; doNotDispatch = true.
export function doSetDaemonSetting(key, value, doNotDispatch = false) { export function doSetDaemonSetting(key, value, doNotDispatch = false) {
return dispatch => { return (dispatch, getState) => {
const state = getState();
const ready = selectPrefsReady(state);
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
const newSettings = { const newSettings = {
key, key,
value: !value && value !== false ? null : value, value: !value && value !== false ? null : value,
@ -123,7 +139,14 @@ export function doSaveCustomWalletServers(servers) {
} }
export function doSetClientSetting(key, value, pushPrefs) { export function doSetClientSetting(key, value, pushPrefs) {
return dispatch => { return (dispatch, getState) => {
const state = getState();
const ready = selectPrefsReady(state);
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
dispatch({ dispatch({
type: ACTIONS.CLIENT_SETTING_CHANGED, type: ACTIONS.CLIENT_SETTING_CHANGED,
data: { data: {

View file

@ -5,6 +5,7 @@ import { Lbryio } from 'lbryinc';
import { doClaimRewardType } from 'redux/actions/rewards'; import { doClaimRewardType } from 'redux/actions/rewards';
import { selectUnreadByChannel } from 'redux/selectors/subscriptions'; import { selectUnreadByChannel } from 'redux/selectors/subscriptions';
import { parseURI } from 'lbry-redux'; import { parseURI } from 'lbry-redux';
import { doAlertWaitingForSync } from 'redux/actions/app';
export const doSetViewMode = (viewMode: ViewMode) => (dispatch: Dispatch) => export const doSetViewMode = (viewMode: ViewMode) => (dispatch: Dispatch) =>
dispatch({ dispatch({
@ -123,7 +124,13 @@ export const doRemoveUnreadSubscription = (channelUri: string, readUri: string)
export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch, getState: GetState) => { export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch, getState: GetState) => {
const { const {
settings: { daemonSettings }, settings: { daemonSettings },
sync: { prefsReady: ready },
} = getState(); } = getState();
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
const { share_usage_data: shareSetting } = daemonSettings; const { share_usage_data: shareSetting } = daemonSettings;
const isSharingData = shareSetting || IS_WEB; const isSharingData = shareSetting || IS_WEB;
@ -153,7 +160,13 @@ export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dis
export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: Dispatch, getState: GetState) => { export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: Dispatch, getState: GetState) => {
const { const {
settings: { daemonSettings }, settings: { daemonSettings },
sync: { prefsReady: ready },
} = getState(); } = getState();
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
const { share_usage_data: shareSetting } = daemonSettings; const { share_usage_data: shareSetting } = daemonSettings;
const isSharingData = shareSetting || IS_WEB; const isSharingData = shareSetting || IS_WEB;

View file

@ -1,6 +1,14 @@
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import { Lbryio } from 'lbryinc'; import { Lbryio } from 'lbryinc';
import { Lbry, doWalletEncrypt, doWalletDecrypt } from 'lbry-redux'; import { SETTINGS, Lbry, doWalletEncrypt, doWalletDecrypt } from 'lbry-redux';
import { selectGetSyncIsPending, selectSetSyncIsPending, selectSyncIsLocked } from 'redux/selectors/sync';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { getSavedPassword } from 'util/saved-passwords';
import { doAnalyticsTagSync, doHandleSyncComplete } from 'redux/actions/app';
import { selectUserVerifiedEmail } from 'redux/selectors/user';
let syncTimer = null;
const SYNC_INTERVAL = 1000 * 60 * 5; // 5 minutes
export function doSetDefaultAccount(success, failure) { export function doSetDefaultAccount(success, failure) {
return dispatch => { return dispatch => {
@ -77,6 +85,52 @@ export function doSetSync(oldHash, newHash, data) {
}; };
} }
export const doGetSyncDesktop = (cb?, password) => (dispatch, 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, 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 => {
if (syncTimer) {
clearInterval(syncTimer);
}
};
}
export function doGetSync(passedPassword, callback) { export function doGetSync(passedPassword, callback) {
const password = passedPassword === null || passedPassword === undefined ? '' : passedPassword; const password = passedPassword === null || passedPassword === undefined ? '' : passedPassword;
@ -280,3 +334,17 @@ export function doSyncEncryptAndDecrypt(oldPassword, newPassword, encrypt) {
.catch(console.error); // eslint-disable-line .catch(console.error); // eslint-disable-line
}; };
} }
export function doSetSyncLock(lock) {
return {
type: ACTIONS.SET_SYNC_LOCK,
data: lock,
};
}
export function doSetPrefsReady() {
return {
type: ACTIONS.SET_PREFS_READY,
data: true,
};
}

View file

@ -1,58 +0,0 @@
// @flow
import { doGetSync } from 'redux/actions/sync';
import { selectGetSyncIsPending, selectSetSyncIsPending } from 'redux/selectors/sync';
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';
import { SETTINGS } from 'lbry-redux';
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);
}
};
}

View file

@ -1,15 +1,42 @@
// @flow // @flow
import { doToggleTagFollow, selectFollowedTagsList } from 'lbry-redux'; import { selectFollowedTagsList } from 'redux/selectors/tags';
import { selectPrefsReady } from 'redux/selectors/sync';
import * as ACTIONS from 'constants/action_types';
import analytics from 'analytics'; import analytics from 'analytics';
import { doAlertWaitingForSync } from 'redux/actions/app';
export const doToggleTagFollowDesktop = (name: string) => (dispatch: Dispatch, getState: GetState) => { export const doToggleTagFollowDesktop = (name: string) => (dispatch: Dispatch, getState: GetState) => {
dispatch(doToggleTagFollow(name));
const state = getState(); const state = getState();
const tags = selectFollowedTagsList(state); const tags = selectFollowedTagsList(state);
const ready = selectPrefsReady(state);
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
dispatch({
type: ACTIONS.TOGGLE_TAG_FOLLOW,
data: {
name,
},
});
const stringOfTags = tags.join(','); const stringOfTags = tags.join(',');
if (stringOfTags) { if (stringOfTags) {
analytics.apiSyncTags({ content_tags: stringOfTags }); analytics.apiSyncTags({ content_tags: stringOfTags });
} }
}; };
export const doAddTag = (name: string) => ({
type: ACTIONS.TAG_ADD,
data: {
name,
},
});
export const doDeleteTag = (name: string) => ({
type: ACTIONS.TAG_DELETE,
data: {
name,
},
});

View file

@ -42,7 +42,6 @@ export type AppState = {
welcomeVersion: number, welcomeVersion: number,
allowAnalytics: boolean, allowAnalytics: boolean,
hasNavigated: boolean, hasNavigated: boolean,
syncLocked: boolean,
interestedInYoutubeSync: boolean, interestedInYoutubeSync: boolean,
}; };
@ -78,7 +77,6 @@ const defaultState: AppState = {
welcomeVersion: 0.0, welcomeVersion: 0.0,
allowAnalytics: false, allowAnalytics: false,
hasNavigated: false, hasNavigated: false,
syncLocked: false,
interestedInYoutubeSync: false, interestedInYoutubeSync: false,
}; };
@ -113,11 +111,6 @@ reducers[ACTIONS.DAEMON_READY] = state =>
daemonReady: true, daemonReady: true,
}); });
reducers[ACTIONS.SET_SYNC_LOCK] = (state, action) =>
Object.assign({}, state, {
syncLocked: action.data,
});
reducers[ACTIONS.PASSWORD_SAVED] = (state, action) => reducers[ACTIONS.PASSWORD_SAVED] = (state, action) =>
Object.assign({}, state, { Object.assign({}, state, {
isPasswordSaved: action.data, isPasswordSaved: action.data,

View file

@ -144,6 +144,12 @@ export default handleActions(
action: { data: { subscriptions: ?Array<string> } } action: { data: { subscriptions: ?Array<string> } }
) => { ) => {
const { subscriptions } = action.data; const { subscriptions } = action.data;
const incomingSubscriptions = Array.isArray(subscriptions) && subscriptions.length;
if (!incomingSubscriptions) {
return {
...state,
};
}
let newSubscriptions; let newSubscriptions;
if (!subscriptions) { if (!subscriptions) {

View file

@ -1,4 +1,5 @@
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import { ACTIONS as LBRY_REDUX_ACTIONS } from 'lbry-redux';
const reducers = {}; const reducers = {};
const defaultState = { const defaultState = {
@ -12,15 +13,35 @@ const defaultState = {
syncApplyPasswordError: false, syncApplyPasswordError: false,
getSyncIsPending: false, getSyncIsPending: false,
setSyncIsPending: false, setSyncIsPending: false,
prefsReady: false,
syncLocked: false,
hashChanged: false, hashChanged: false,
}; };
reducers[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE] = state => {
const { syncReady } = state;
if (!syncReady) {
return Object.assign({}, state, {
prefsReady: true,
});
} else {
return Object.assign({}, state);
}
};
reducers[ACTIONS.SET_PREFS_READY] = (state, action) => Object.assign({}, state, { prefsReady: action.data });
reducers[ACTIONS.GET_SYNC_STARTED] = state => reducers[ACTIONS.GET_SYNC_STARTED] = state =>
Object.assign({}, state, { Object.assign({}, state, {
getSyncIsPending: true, getSyncIsPending: true,
getSyncErrorMessage: null, getSyncErrorMessage: null,
}); });
reducers[ACTIONS.SET_SYNC_LOCK] = (state, action) =>
Object.assign({}, state, {
syncLocked: action.data,
});
reducers[ACTIONS.GET_SYNC_COMPLETED] = (state, action) => reducers[ACTIONS.GET_SYNC_COMPLETED] = (state, action) =>
Object.assign({}, state, { Object.assign({}, state, {
syncHash: action.data.syncHash, syncHash: action.data.syncHash,

82
ui/redux/reducers/tags.js Normal file
View file

@ -0,0 +1,82 @@
// @flow
import * as ACTIONS from 'constants/action_types';
import { ACTIONS as LBRY_REDUX_ACTIONS, DEFAULT_KNOWN_TAGS, DEFAULT_FOLLOWED_TAGS } from 'lbry-redux';
import { handleActions } from 'util/redux-utils';
function getDefaultKnownTags() {
return DEFAULT_FOLLOWED_TAGS.concat(DEFAULT_KNOWN_TAGS).reduce(
(tagsMap, tag) => ({
...tagsMap,
[tag]: { name: tag },
}),
{}
);
}
const defaultState: TagState = {
followedTags: [],
knownTags: getDefaultKnownTags(),
};
export default handleActions(
{
[ACTIONS.TOGGLE_TAG_FOLLOW]: (state: TagState, action: TagAction): TagState => {
const { followedTags } = state;
const { name } = action.data;
let newFollowedTags = followedTags.slice();
if (newFollowedTags.includes(name)) {
newFollowedTags = newFollowedTags.filter(tag => tag !== name);
} else {
newFollowedTags.push(name);
}
return {
...state,
followedTags: newFollowedTags,
};
},
[ACTIONS.TAG_ADD]: (state: TagState, action: TagAction) => {
const { knownTags } = state;
const { name } = action.data;
let newKnownTags = { ...knownTags };
newKnownTags[name] = { name };
return {
...state,
knownTags: newKnownTags,
};
},
[ACTIONS.TAG_DELETE]: (state: TagState, action: TagAction) => {
const { knownTags, followedTags } = state;
const { name } = action.data;
let newKnownTags = { ...knownTags };
delete newKnownTags[name];
const newFollowedTags = followedTags.filter(tag => tag !== name);
return {
...state,
knownTags: newKnownTags,
followedTags: newFollowedTags,
};
},
[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE]: (state: TagState, action: { data: { tags: ?Array<string> } }) => {
const { tags } = action.data;
if (Array.isArray(tags)) {
return {
...state,
followedTags: tags,
};
}
return {
...state,
};
},
},
defaultState
);

View file

@ -81,6 +81,4 @@ export const selectScrollStartingPosition = createSelector(selectState, state =>
export const selectIsPasswordSaved = createSelector(selectState, state => state.isPasswordSaved); export const selectIsPasswordSaved = createSelector(selectState, state => state.isPasswordSaved);
export const selectSyncIsLocked = createSelector(selectState, state => state.syncLocked);
export const selectInterestedInYoutubeSync = createSelector(selectState, state => state.interestedInYoutubeSync); export const selectInterestedInYoutubeSync = createSelector(selectState, state => state.interestedInYoutubeSync);

View file

@ -23,3 +23,7 @@ export const selectSyncApplyIsPending = createSelector(selectState, state => sta
export const selectSyncApplyErrorMessage = createSelector(selectState, state => state.syncApplyErrorMessage); export const selectSyncApplyErrorMessage = createSelector(selectState, state => state.syncApplyErrorMessage);
export const selectSyncApplyPasswordError = createSelector(selectState, state => state.syncApplyPasswordError); export const selectSyncApplyPasswordError = createSelector(selectState, state => state.syncApplyPasswordError);
export const selectSyncIsLocked = createSelector(selectState, state => state.syncLocked);
export const selectPrefsReady = createSelector(selectState, state => state.prefsReady);

View file

@ -0,0 +1,36 @@
// @flow
import { createSelector } from 'reselect';
const selectState = (state: { tags: TagState }) => state.tags || {};
export const selectKnownTagsByName = createSelector(selectState, (state: TagState): KnownTags => state.knownTags);
export const selectFollowedTagsList = createSelector(selectState, (state: TagState): Array<string> =>
state.followedTags.filter(tag => typeof tag === 'string')
);
export const selectFollowedTags = createSelector(selectFollowedTagsList, (followedTags: Array<string>): Array<Tag> =>
followedTags.map(tag => ({ name: tag.toLowerCase() })).sort((a, b) => a.name.localeCompare(b.name))
);
export const selectUnfollowedTags = createSelector(
selectKnownTagsByName,
selectFollowedTagsList,
(tagsByName: KnownTags, followedTags: Array<string>): Array<Tag> => {
const followedTagsSet = new Set(followedTags);
let tagsToReturn = [];
Object.keys(tagsByName).forEach(key => {
if (!followedTagsSet.has(key)) {
const { name } = tagsByName[key];
tagsToReturn.push({ name: name.toLowerCase() });
}
});
return tagsToReturn;
}
);
export const makeSelectIsFollowingTag = (tag: string) =>
createSelector(selectFollowedTags, followedTags => {
return followedTags.some(followedTag => followedTag.name === tag.toLowerCase());
});

View file

@ -10,7 +10,7 @@ import { createMemoryHistory, createBrowserHistory } from 'history';
import { routerMiddleware } from 'connected-react-router'; import { routerMiddleware } from 'connected-react-router';
import createRootReducer from './reducers'; import createRootReducer from './reducers';
import { Lbry, buildSharedStateMiddleware, ACTIONS as LBRY_REDUX_ACTIONS } from 'lbry-redux'; import { Lbry, buildSharedStateMiddleware, ACTIONS as LBRY_REDUX_ACTIONS } from 'lbry-redux';
import { doSyncSubscribe } from 'redux/actions/syncwrapper'; import { doSyncSubscribe } from 'redux/actions/sync';
import { getAuthToken } from 'util/saved-passwords'; import { getAuthToken } from 'util/saved-passwords';
import { generateInitialUrl } from 'util/url'; import { generateInitialUrl } from 'util/url';
import { X_LBRY_AUTH_TOKEN } from 'constants/token'; import { X_LBRY_AUTH_TOKEN } from 'constants/token';
@ -120,7 +120,7 @@ const triggerSharedStateActions = [
ACTIONS.CHANNEL_SUBSCRIBE, ACTIONS.CHANNEL_SUBSCRIBE,
ACTIONS.CHANNEL_UNSUBSCRIBE, ACTIONS.CHANNEL_UNSUBSCRIBE,
ACTIONS.TOGGLE_BLOCK_CHANNEL, ACTIONS.TOGGLE_BLOCK_CHANNEL,
LBRY_REDUX_ACTIONS.TOGGLE_TAG_FOLLOW, ACTIONS.TOGGLE_TAG_FOLLOW,
LBRY_REDUX_ACTIONS.CREATE_CHANNEL_COMPLETED, LBRY_REDUX_ACTIONS.CREATE_CHANNEL_COMPLETED,
ACTIONS.SYNC_CLIENT_SETTINGS, ACTIONS.SYNC_CLIENT_SETTINGS,
// Disabled until we can overwrite preferences // Disabled until we can overwrite preferences