diff --git a/package.json b/package.json index f18ddc8dc..976987947 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "find-process": "^1.1.0", "formik": "^0.10.4", "keytar": "^4.2.1", + "lbry-redux": "lbryio/lbry-redux", "localforage": "^1.7.1", "mixpanel-browser": "^2.17.1", "moment": "^2.22.0", @@ -60,7 +61,7 @@ "react-modal": "^3.1.7", "react-paginate": "^5.2.1", "react-redux": "^5.0.3", - "react-simplemde-editor": "^3.6.11", + "react-simplemde-editor": "3.6.11", "react-transition-group": "1.x", "redux": "^3.6.0", "redux-logger": "^3.0.1", diff --git a/src/renderer/component/app/index.js b/src/renderer/component/app/index.js index 9589e9280..d78487976 100644 --- a/src/renderer/component/app/index.js +++ b/src/renderer/component/app/index.js @@ -1,12 +1,8 @@ import { connect } from 'react-redux'; -import { - selectPageTitle, - selectHistoryIndex, - selectActiveHistoryEntry, -} from 'redux/selectors/navigation'; +import { selectPageTitle, selectHistoryIndex, selectActiveHistoryEntry } from 'lbry-redux'; +import { doRecordScroll } from 'redux/actions/navigation'; import { selectUser } from 'redux/selectors/user'; import { doAlertError } from 'redux/actions/app'; -import { doRecordScroll } from 'redux/actions/navigation'; import App from './view'; const select = state => ({ diff --git a/src/renderer/component/button/index.js b/src/renderer/component/button/index.js index edebcbce1..478015d09 100644 --- a/src/renderer/component/button/index.js +++ b/src/renderer/component/button/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { connect } from 'react-redux'; import { doNavigate } from 'redux/actions/navigation'; import Button from './view'; diff --git a/src/renderer/component/cardMedia/view.jsx b/src/renderer/component/cardMedia/view.jsx index a0d4b6d4e..28f526ee3 100644 --- a/src/renderer/component/cardMedia/view.jsx +++ b/src/renderer/component/cardMedia/view.jsx @@ -22,9 +22,7 @@ const autoThumbColors = [ ]; class CardMedia extends React.PureComponent { - getAutoThumbClass = () => { - return autoThumbColors[Math.floor(Math.random() * autoThumbColors.length)]; - }; + getAutoThumbClass = () => autoThumbColors[Math.floor(Math.random() * autoThumbColors.length)]; render() { const { thumbnail, nsfw } = this.props; diff --git a/src/renderer/component/channelTile/index.js b/src/renderer/component/channelTile/index.js index 51a4835f6..c272fc2bf 100644 --- a/src/renderer/component/channelTile/index.js +++ b/src/renderer/component/channelTile/index.js @@ -1,10 +1,7 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { doResolveUri, makeSelectClaimForUri, makeSelectIsUriResolving } from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; -import { doResolveUri } from 'redux/actions/content'; import { makeSelectTotalItemsForChannel } from 'redux/selectors/content'; -import { makeSelectIsUriResolving } from 'redux/selectors/content'; import ChannelTile from './view'; const select = (state, props) => ({ diff --git a/src/renderer/component/common/busy-indicator.jsx b/src/renderer/component/common/busy-indicator.jsx index ee95a00ca..759e91b5c 100644 --- a/src/renderer/component/common/busy-indicator.jsx +++ b/src/renderer/component/common/busy-indicator.jsx @@ -5,12 +5,10 @@ type Props = { message: ?string, }; -const BusyIndicator = (props: Props) => { - return ( - - {props.message} - - ); -}; +const BusyIndicator = (props: Props) => ( + + {props.message} + +); export default BusyIndicator; diff --git a/src/renderer/component/common/category-list.jsx b/src/renderer/component/common/category-list.jsx index f20b355bc..4b1589cee 100644 --- a/src/renderer/component/common/category-list.jsx +++ b/src/renderer/component/common/category-list.jsx @@ -1,6 +1,6 @@ // @flow import React from 'react'; -import { normalizeURI } from 'lbryURI'; +import { normalizeURI } from 'lbry-redux'; import ToolTip from 'component/common/tooltip'; import FileCard from 'component/fileCard'; import Button from 'component/button'; diff --git a/src/renderer/component/common/truncated-text.jsx b/src/renderer/component/common/truncated-text.jsx index d5f4f5961..8736ae530 100644 --- a/src/renderer/component/common/truncated-text.jsx +++ b/src/renderer/component/common/truncated-text.jsx @@ -6,12 +6,10 @@ type Props = { children: React.Node, }; -const TruncatedText = (props: Props) => { - return ( - - {props.children} - - ); -}; +const TruncatedText = (props: Props) => ( + + {props.children} + +); export default TruncatedText; diff --git a/src/renderer/component/dateTime/index.js b/src/renderer/component/dateTime/index.js index 06009a4ca..adae8f658 100644 --- a/src/renderer/component/dateTime/index.js +++ b/src/renderer/component/dateTime/index.js @@ -1,7 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { makeSelectBlockDate } from 'redux/selectors/wallet'; -import { doFetchBlock } from 'redux/actions/wallet'; +import { doFetchBlock, makeSelectBlockDate } from 'lbry-redux'; import DateTime from './view'; const select = (state, props) => ({ diff --git a/src/renderer/component/fileActions/index.js b/src/renderer/component/fileActions/index.js index b848342c0..92d388a3b 100644 --- a/src/renderer/component/fileActions/index.js +++ b/src/renderer/component/fileActions/index.js @@ -1,9 +1,10 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; -import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info'; -import { doOpenModal } from 'redux/actions/app'; -import { makeSelectClaimIsMine } from 'redux/selectors/claims'; +import { + doOpenModal, + makeSelectCostInfoForUri, + makeSelectFileInfoForUri, + makeSelectClaimIsMine, +} from 'lbry-redux'; import FileActions from './view'; const select = (state, props) => ({ diff --git a/src/renderer/component/fileCard/index.js b/src/renderer/component/fileCard/index.js index c7334c1b8..dcb4774f9 100644 --- a/src/renderer/component/fileCard/index.js +++ b/src/renderer/component/fileCard/index.js @@ -1,10 +1,14 @@ import { connect } from 'react-redux'; +import { + doResolveUri, + makeSelectClaimForUri, + makeSelectMetadataForUri, + makeSelectFileInfoForUri, + makeSelectIsUriResolving, +} from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; -import { doResolveUri } from 'redux/actions/content'; +import { selectRewardContentClaimIds } from 'redux/selectors/content'; import { selectShowNsfw } from 'redux/selectors/settings'; -import { makeSelectClaimForUri, makeSelectMetadataForUri } from 'redux/selectors/claims'; -import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; -import { makeSelectIsUriResolving, selectRewardContentClaimIds } from 'redux/selectors/content'; import { selectPendingPublish } from 'redux/selectors/publish'; import FileCard from './view'; diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx index faf1d2eef..88bb99946 100644 --- a/src/renderer/component/fileCard/view.jsx +++ b/src/renderer/component/fileCard/view.jsx @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { normalizeURI } from 'lbryURI'; +import { normalizeURI } from 'lbry-redux'; import Button from 'component/button'; import CardMedia from 'component/cardMedia'; import TruncatedText from 'component/common/truncated-text'; diff --git a/src/renderer/component/fileDetails/index.js b/src/renderer/component/fileDetails/index.js index 9b877dec9..18541f6da 100644 --- a/src/renderer/component/fileDetails/index.js +++ b/src/renderer/component/fileDetails/index.js @@ -1,13 +1,12 @@ -import React from 'react'; import { connect } from 'react-redux'; import { makeSelectClaimForUri, makeSelectContentTypeForUri, makeSelectMetadataForUri, -} from 'redux/selectors/claims'; + makeSelectFileInfoForUri, +} from 'lbry-redux'; +import { doOpenFileInFolder } from 'redux/actions/file'; import FileDetails from './view'; -import { doOpenFileInFolder } from 'redux/actions/file_info'; -import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; const select = (state, props) => ({ claim: makeSelectClaimForUri(props.uri)(state), diff --git a/src/renderer/component/fileDetails/view.jsx b/src/renderer/component/fileDetails/view.jsx index 3912729ad..226eb949a 100644 --- a/src/renderer/component/fileDetails/view.jsx +++ b/src/renderer/component/fileDetails/view.jsx @@ -1,7 +1,7 @@ // @flow import * as React from 'react'; import ReactMarkdown from 'react-markdown'; -import lbry from 'lbry'; +import { Lbry } from 'lbry-redux'; import Button from 'component/button'; import path from 'path'; @@ -31,7 +31,7 @@ const FileDetails = (props: Props) => { } const { description, language, license } = metadata; - const mediaType = lbry.getMediaType(contentType); + const mediaType = Lbry.getMediaType(contentType); const downloadPath = fileInfo ? path.normalize(fileInfo.download_path) : null; diff --git a/src/renderer/component/fileDownloadLink/index.js b/src/renderer/component/fileDownloadLink/index.js index e13b4b3d4..d36f4c896 100644 --- a/src/renderer/component/fileDownloadLink/index.js +++ b/src/renderer/component/fileDownloadLink/index.js @@ -1,13 +1,12 @@ -import React from 'react'; import { connect } from 'react-redux'; import { makeSelectFileInfoForUri, makeSelectDownloadingForUri, makeSelectLoadingForUri, -} from 'redux/selectors/file_info'; -import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info'; + makeSelectCostInfoForUri, +} from 'lbry-redux'; import { doFetchAvailability } from 'redux/actions/availability'; -import { doOpenFileInShell } from 'redux/actions/file_info'; +import { doOpenFileInShell } from 'redux/actions/file'; import { doPurchaseUri, doStartDownload } from 'redux/actions/content'; import { doPause } from 'redux/actions/media'; import FileDownloadLink from './view'; diff --git a/src/renderer/component/fileList/index.js b/src/renderer/component/fileList/index.js index bfaff712a..0bcb519e5 100644 --- a/src/renderer/component/fileList/index.js +++ b/src/renderer/component/fileList/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; import FileList from './view'; -import { selectClaimsById } from 'redux/selectors/claims'; +import { selectClaimsById } from 'lbry-redux'; const select = state => ({ claimsById: selectClaimsById(state), diff --git a/src/renderer/component/fileList/view.jsx b/src/renderer/component/fileList/view.jsx index 3f31e8b0f..ffe8ecbff 100644 --- a/src/renderer/component/fileList/view.jsx +++ b/src/renderer/component/fileList/view.jsx @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { buildURI } from 'lbryURI'; +import { buildURI } from 'lbry-redux'; import { FormField } from 'component/common/form'; import FileCard from 'component/fileCard'; diff --git a/src/renderer/component/fileListSearch/index.js b/src/renderer/component/fileListSearch/index.js index 328295768..77ab70d07 100644 --- a/src/renderer/component/fileListSearch/index.js +++ b/src/renderer/component/fileListSearch/index.js @@ -1,7 +1,10 @@ import { connect } from 'react-redux'; -import { doSearch } from 'redux/actions/search'; -import { makeSelectSearchUris, selectIsSearching } from 'redux/selectors/search'; -import { selectSearchDownloadUris } from 'redux/selectors/file_info'; +import { + doSearch, + makeSelectSearchUris, + selectIsSearching, + selectSearchDownloadUris, +} from 'lbry-redux'; import FileListSearch from './view'; const select = (state, props) => ({ diff --git a/src/renderer/component/fileListSearch/view.jsx b/src/renderer/component/fileListSearch/view.jsx index 25694d1c7..48324f763 100644 --- a/src/renderer/component/fileListSearch/view.jsx +++ b/src/renderer/component/fileListSearch/view.jsx @@ -2,7 +2,7 @@ import React from 'react'; import FileTile from 'component/fileTile'; import ChannelTile from 'component/channelTile'; -import { parseURI } from 'lbryURI'; +import { parseURI } from 'lbry-redux'; import debounce from 'util/debounce'; const SEARCH_DEBOUNCE_TIME = 800; diff --git a/src/renderer/component/filePrice/index.js b/src/renderer/component/filePrice/index.js index 93eaee79d..8351dc6f1 100644 --- a/src/renderer/component/filePrice/index.js +++ b/src/renderer/component/filePrice/index.js @@ -1,11 +1,10 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doFetchCostInfoForUri } from 'redux/actions/cost_info'; import { + doFetchCostInfoForUri, makeSelectCostInfoForUri, makeSelectFetchingCostInfoForUri, -} from 'redux/selectors/cost_info'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; + makeSelectClaimForUri, +} from 'lbry-redux'; import FilePrice from './view'; const select = (state, props) => ({ diff --git a/src/renderer/component/fileTile/index.js b/src/renderer/component/fileTile/index.js index a85de00e9..6bb7a2895 100644 --- a/src/renderer/component/fileTile/index.js +++ b/src/renderer/component/fileTile/index.js @@ -1,11 +1,14 @@ -import React from 'react'; import { connect } from 'react-redux'; +import { + doResolveUri, + makeSelectClaimForUri, + makeSelectMetadataForUri, + makeSelectFileInfoForUri, + makeSelectIsUriResolving, +} from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; -import { doResolveUri } from 'redux/actions/content'; -import { makeSelectClaimForUri, makeSelectMetadataForUri } from 'redux/selectors/claims'; -import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; import { selectShowNsfw } from 'redux/selectors/settings'; -import { makeSelectIsUriResolving, selectRewardContentClaimIds } from 'redux/selectors/content'; +import { selectRewardContentClaimIds } from 'redux/selectors/content'; import FileTile from './view'; const select = (state, props) => ({ diff --git a/src/renderer/component/fileTile/view.jsx b/src/renderer/component/fileTile/view.jsx index 7761b9f4e..a88f5feb4 100644 --- a/src/renderer/component/fileTile/view.jsx +++ b/src/renderer/component/fileTile/view.jsx @@ -1,7 +1,7 @@ // @flow import * as React from 'react'; import * as icons from 'constants/icons'; -import { normalizeURI, isURIClaimable, parseURI } from 'lbryURI'; +import { normalizeURI, isURIClaimable, parseURI } from 'lbry-redux'; import CardMedia from 'component/cardMedia'; import TruncatedText from 'component/common/truncated-text'; import FilePrice from 'component/filePrice'; diff --git a/src/renderer/component/header/index.js b/src/renderer/component/header/index.js index b10483149..0b5c8066f 100644 --- a/src/renderer/component/header/index.js +++ b/src/renderer/component/header/index.js @@ -1,9 +1,9 @@ import { connect } from 'react-redux'; -import { doDownloadUpgradeRequested } from 'redux/actions/app'; +import { selectBalance } from 'lbry-redux'; +import { formatCredits } from 'util/formatCredits'; import { doNavigate } from 'redux/actions/navigation'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; -import { selectBalance } from 'redux/selectors/wallet'; -import { formatCredits } from 'util/formatCredits'; +import { doDownloadUpgradeRequested } from 'redux/actions/app'; import Header from './view'; const select = state => ({ diff --git a/src/renderer/component/nsfwOverlay/index.js b/src/renderer/component/nsfwOverlay/index.js index 1343bd7c7..515a0ecd6 100644 --- a/src/renderer/component/nsfwOverlay/index.js +++ b/src/renderer/component/nsfwOverlay/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { connect } from 'react-redux'; import { doNavigate } from 'redux/actions/navigation'; import NsfwOverlay from './view'; diff --git a/src/renderer/component/page/index.js b/src/renderer/component/page/index.js index 0bf9f77fe..f9111f85e 100644 --- a/src/renderer/component/page/index.js +++ b/src/renderer/component/page/index.js @@ -1,15 +1,15 @@ import { connect } from 'react-redux'; import { + selectBalance, selectPageTitle, selectIsBackDisabled, selectIsForwardDisabled, selectNavLinks, -} from 'redux/selectors/navigation'; +} from 'lbry-redux'; import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation'; import { doDownloadUpgrade } from 'redux/actions/app'; import { selectIsUpgradeAvailable } from 'redux/selectors/app'; import { formatCredits } from 'util/formatCredits'; -import { selectBalance } from 'redux/selectors/wallet'; import Page from './view'; const select = state => ({ diff --git a/src/renderer/component/publishForm/index.js b/src/renderer/component/publishForm/index.js index 3eb2a7bc4..dfb124897 100644 --- a/src/renderer/component/publishForm/index.js +++ b/src/renderer/component/publishForm/index.js @@ -1,5 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; +import { selectBalance } from 'lbry-redux'; import PublishForm from './view'; export default connect(null, null)(PublishForm); diff --git a/src/renderer/component/publishForm/view.jsx b/src/renderer/component/publishForm/view.jsx index 60fa0aff3..ff3850a2c 100644 --- a/src/renderer/component/publishForm/view.jsx +++ b/src/renderer/component/publishForm/view.jsx @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { isNameValid, buildURI, regexInvalidURI } from 'lbryURI'; +import { isNameValid, buildURI, regexInvalidURI } from 'lbry-redux'; import { Form, FormField, FormRow, FormFieldPrice, Submit } from 'component/common/form'; import Button from 'component/button'; import ChannelSection from 'component/selectChannel'; diff --git a/src/renderer/component/rewardLink/index.js b/src/renderer/component/rewardLink/index.js index 2fc1654a4..9ecfe0dba 100644 --- a/src/renderer/component/rewardLink/index.js +++ b/src/renderer/component/rewardLink/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { connect } from 'react-redux'; import { makeSelectClaimRewardError, diff --git a/src/renderer/component/router/index.js b/src/renderer/component/router/index.js index df1adc161..0e2a262cb 100644 --- a/src/renderer/component/router/index.js +++ b/src/renderer/component/router/index.js @@ -1,7 +1,6 @@ -import React from 'react'; import { connect } from 'react-redux'; -import Router from './view.jsx'; -import { selectCurrentPage, selectCurrentParams } from 'redux/selectors/navigation.js'; +import { selectCurrentPage, selectCurrentParams } from 'lbry-redux'; +import Router from './view'; const select = state => ({ params: selectCurrentParams(state), diff --git a/src/renderer/component/selectChannel/index.js b/src/renderer/component/selectChannel/index.js index 66d208875..45314beef 100644 --- a/src/renderer/component/selectChannel/index.js +++ b/src/renderer/component/selectChannel/index.js @@ -1,8 +1,7 @@ import { connect } from 'react-redux'; import SelectChannel from './view'; -import { selectMyChannelClaims, selectFetchingMyChannels } from 'redux/selectors/claims'; +import { selectBalance, selectMyChannelClaims, selectFetchingMyChannels } from 'lbry-redux'; import { doFetchChannelListMine, doCreateChannel } from 'redux/actions/content'; -import { selectBalance } from 'redux/selectors/wallet'; const select = state => ({ channels: selectMyChannelClaims(state), diff --git a/src/renderer/component/selectChannel/view.jsx b/src/renderer/component/selectChannel/view.jsx index 88182c49c..2c1f9ed22 100644 --- a/src/renderer/component/selectChannel/view.jsx +++ b/src/renderer/component/selectChannel/view.jsx @@ -1,6 +1,6 @@ // @flow import React from 'react'; -import { isNameValid } from 'lbryURI'; +import { isNameValid } from 'lbry-redux'; import { FormRow, FormField } from 'component/common/form'; import BusyIndicator from 'component/common/busy-indicator'; import Button from 'component/button'; diff --git a/src/renderer/component/shapeShift/index.js b/src/renderer/component/shapeShift/index.js index 0c0cb5409..16ac8d4a7 100644 --- a/src/renderer/component/shapeShift/index.js +++ b/src/renderer/component/shapeShift/index.js @@ -6,8 +6,7 @@ import { clearShapeShift, getActiveShift, } from 'redux/actions/shape_shift'; -import { doShowSnackBar } from 'redux/actions/app'; -import { selectReceiveAddress } from 'redux/selectors/wallet'; +import { doShowSnackBar, selectReceiveAddress } from 'lbry-redux'; import { selectShapeShift } from 'redux/selectors/shape_shift'; import ShapeShift from './view'; diff --git a/src/renderer/component/sideBar/index.js b/src/renderer/component/sideBar/index.js index 124d8466a..12c0de26b 100644 --- a/src/renderer/component/sideBar/index.js +++ b/src/renderer/component/sideBar/index.js @@ -1,10 +1,6 @@ import { connect } from 'react-redux'; import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation'; -import { - selectIsBackDisabled, - selectIsForwardDisabled, - selectNavLinks, -} from 'redux/selectors/navigation'; +import { selectIsBackDisabled, selectIsForwardDisabled, selectNavLinks } from 'lbry-redux'; import { selectNotifications } from 'redux/selectors/subscriptions'; import SideBar from './view'; diff --git a/src/renderer/component/splash/view.jsx b/src/renderer/component/splash/view.jsx index 89c5c82f4..bdbadc247 100644 --- a/src/renderer/component/splash/view.jsx +++ b/src/renderer/component/splash/view.jsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import lbry from 'lbry'; +import { Lbry } from 'lbry-redux'; import LoadScreen from './internal/load-screen'; import ModalIncompatibleDaemon from 'modal/modalIncompatibleDaemon'; import ModalUpgrade from 'modal/modalUpgrade'; @@ -31,7 +31,7 @@ export class SplashScreen extends React.PureComponent { } updateStatus() { - lbry.status().then(status => { + Lbry.status().then(status => { this._updateStatusCallback(status); }); } @@ -50,7 +50,7 @@ export class SplashScreen extends React.PureComponent { isRunning: true, }); - lbry.resolve({ uri: 'lbry://one' }).then(() => { + Lbry.resolve({ uri: 'lbry://one' }).then(() => { // Only leave the load screen if the daemon version matched; // otherwise we'll notify the user at the end of the load screen. @@ -83,8 +83,7 @@ export class SplashScreen extends React.PureComponent { componentDidMount() { const { checkDaemonVersion } = this.props; - lbry - .connect() + Lbry.connect() .then(checkDaemonVersion) .then(() => { this.updateStatus(); diff --git a/src/renderer/component/subHeader/index.js b/src/renderer/component/subHeader/index.js deleted file mode 100644 index f445734c5..000000000 --- a/src/renderer/component/subHeader/index.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import { selectCurrentPage, selectHeaderLinks } from 'redux/selectors/navigation'; -import { doNavigate } from 'redux/actions/navigation'; -import { selectNotifications } from 'redux/selectors/subscriptions'; -import SubHeader from './view'; - -const select = (state, props) => ({ - currentPage: selectCurrentPage(state), - subLinks: selectHeaderLinks(state), - notifications: selectNotifications(state), -}); - -const perform = dispatch => ({ - navigate: path => dispatch(doNavigate(path)), -}); - -export default connect(select, perform)(SubHeader); diff --git a/src/renderer/component/subHeader/view.jsx b/src/renderer/component/subHeader/view.jsx deleted file mode 100644 index 8ede92169..000000000 --- a/src/renderer/component/subHeader/view.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import Link from 'component/link'; -import classnames from 'classnames'; -import * as NOTIFICATION_TYPES from 'constants/notification_types'; - -const SubHeader = props => { - const { subLinks, currentPage, navigate, fullWidth, smallMargin, notifications } = props; - - const badges = Object.keys(notifications).reduce( - (acc, cur) => (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING ? acc : acc + 1), - 0 - ); - - const links = []; - - for (const link of Object.keys(subLinks)) { - links.push( - navigate(`/${link}`, event)} - key={link} - className={link == currentPage ? 'sub-header-selected' : 'sub-header-unselected'} - > - {subLinks[link] === 'Subscriptions' && badges - ? `Subscriptions (${badges})` - : subLinks[link]} - - ); - } - - return ( - - ); -}; - -export default SubHeader; diff --git a/src/renderer/component/transactionList/index.js b/src/renderer/component/transactionList/index.js index 54b7b755f..4c43bcc79 100644 --- a/src/renderer/component/transactionList/index.js +++ b/src/renderer/component/transactionList/index.js @@ -1,9 +1,7 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doNavigate } from 'redux/actions/navigation'; -import { doOpenModal } from 'redux/actions/app'; import { selectClaimedRewardsByTransactionId } from 'redux/selectors/rewards'; -import { selectAllMyClaimsByOutpoint } from 'redux/selectors/claims'; +import { doNavigate } from 'redux/actions/navigation'; +import { doOpenModal, selectAllMyClaimsByOutpoint } from 'lbry-redux'; import TransactionList from './view'; const select = state => ({ diff --git a/src/renderer/component/transactionList/internal/transaction-list-item.jsx b/src/renderer/component/transactionList/internal/transaction-list-item.jsx index c713be1c8..264db8669 100644 --- a/src/renderer/component/transactionList/internal/transaction-list-item.jsx +++ b/src/renderer/component/transactionList/internal/transaction-list-item.jsx @@ -4,7 +4,7 @@ import ButtonTransaction from 'component/common/transaction-link'; import CreditAmount from 'component/common/credit-amount'; import DateTime from 'component/dateTime'; import Button from 'component/button'; -import { buildURI } from 'lbryURI'; +import { buildURI } from 'lbry-redux'; import * as txnTypes from 'constants/transaction_types'; import type { Transaction } from '../view'; diff --git a/src/renderer/component/transactionListRecent/index.js b/src/renderer/component/transactionListRecent/index.js index c01590705..3a59bc82f 100644 --- a/src/renderer/component/transactionListRecent/index.js +++ b/src/renderer/component/transactionListRecent/index.js @@ -1,13 +1,10 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doFetchTransactions } from 'redux/actions/wallet'; import { - selectBalance, + doFetchTransactions, selectRecentTransactions, selectHasTransactions, selectIsFetchingTransactions, -} from 'redux/selectors/wallet'; - +} from 'lbry-redux'; import TransactionListRecent from './view'; const select = state => ({ diff --git a/src/renderer/component/uriIndicator/index.js b/src/renderer/component/uriIndicator/index.js index 298a90696..8524965d5 100644 --- a/src/renderer/component/uriIndicator/index.js +++ b/src/renderer/component/uriIndicator/index.js @@ -1,9 +1,10 @@ -import React from 'react'; -import { normalizeURI } from 'lbryURI'; import { connect } from 'react-redux'; -import { doResolveUri } from 'redux/actions/content'; -import { makeSelectIsUriResolving } from 'redux/selectors/content'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { + normalizeURI, + doResolveUri, + makeSelectIsUriResolving, + makeSelectClaimForUri, +} from 'lbry-redux'; import UriIndicator from './view'; const select = (state, props) => ({ diff --git a/src/renderer/component/uriIndicator/view.jsx b/src/renderer/component/uriIndicator/view.jsx index b4e3b3707..499b11fba 100644 --- a/src/renderer/component/uriIndicator/view.jsx +++ b/src/renderer/component/uriIndicator/view.jsx @@ -1,7 +1,7 @@ // @flow import React from 'react'; import Button from 'component/button'; -import { buildURI } from 'lbryURI'; +import { buildURI } from 'lbry-redux'; import classnames from 'classnames'; // import Icon from 'component/common/icon'; diff --git a/src/renderer/component/userVerify/index.js b/src/renderer/component/userVerify/index.js index bf0a4f6e1..e5ad16583 100644 --- a/src/renderer/component/userVerify/index.js +++ b/src/renderer/component/userVerify/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { connect } from 'react-redux'; import { doNavigate } from 'redux/actions/navigation'; import { doUserIdentityVerify } from 'redux/actions/user'; diff --git a/src/renderer/component/video/index.js b/src/renderer/component/video/index.js index 573dba1a9..671f931be 100644 --- a/src/renderer/component/video/index.js +++ b/src/renderer/component/video/index.js @@ -1,21 +1,21 @@ -import React from 'react'; import { connect } from 'react-redux'; import { doChangeVolume } from 'redux/actions/app'; import { selectVolume } from 'redux/selectors/app'; import { doPlayUri, doSetPlayingUri } from 'redux/actions/content'; import { doPlay, doPause, savePosition } from 'redux/actions/media'; -import { makeSelectMetadataForUri, makeSelectContentTypeForUri } from 'redux/selectors/claims'; import { + makeSelectMetadataForUri, + makeSelectContentTypeForUri, + makeSelectCostInfoForUri, + makeSelectClaimForUri, makeSelectFileInfoForUri, makeSelectLoadingForUri, makeSelectDownloadingForUri, -} from 'redux/selectors/file_info'; -import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info'; +} from 'lbry-redux'; import { selectShowNsfw } from 'redux/selectors/settings'; import { selectMediaPaused, makeSelectMediaPositionForUri } from 'redux/selectors/media'; -import Video from './view'; import { selectPlayingUri } from 'redux/selectors/content'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import Video from './view'; const select = (state, props) => ({ claim: makeSelectClaimForUri(props.uri)(state), diff --git a/src/renderer/component/video/view.jsx b/src/renderer/component/video/view.jsx index 965bedd03..1cfda4078 100644 --- a/src/renderer/component/video/view.jsx +++ b/src/renderer/component/video/view.jsx @@ -1,6 +1,6 @@ // @flow import React from 'react'; -import lbry from 'lbry'; +import { Lbry } from 'lbry-redux'; import classnames from 'classnames'; import VideoPlayer from './internal/player'; import VideoPlayButton from './internal/play-button'; @@ -75,7 +75,7 @@ class Video extends React.PureComponent { const isPlaying = playingUri === uri; const isReadyToPlay = fileInfo && fileInfo.written_bytes > 0; const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw; - const mediaType = lbry.getMediaType(contentType, fileInfo && fileInfo.file_name); + const mediaType = Lbry.getMediaType(contentType, fileInfo && fileInfo.file_name); let loadStatusMessage = ''; diff --git a/src/renderer/component/walletAddress/index.js b/src/renderer/component/walletAddress/index.js index 738892973..8955c6651 100644 --- a/src/renderer/component/walletAddress/index.js +++ b/src/renderer/component/walletAddress/index.js @@ -1,7 +1,10 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCheckAddressIsMine, doGetNewAddress } from 'redux/actions/wallet'; -import { selectReceiveAddress, selectGettingNewAddress } from 'redux/selectors/wallet'; +import { + doCheckAddressIsMine, + doGetNewAddress, + selectReceiveAddress, + selectGettingNewAddress, +} from 'lbry-redux'; import WalletAddress from './view'; const select = state => ({ diff --git a/src/renderer/component/walletBalance/index.js b/src/renderer/component/walletBalance/index.js index 0e1b4439c..9f69e655b 100644 --- a/src/renderer/component/walletBalance/index.js +++ b/src/renderer/component/walletBalance/index.js @@ -1,6 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { selectBalance } from 'redux/selectors/wallet'; +import { selectBalance } from 'lbry-redux'; import WalletBalance from './view'; const select = state => ({ diff --git a/src/renderer/component/walletSend/index.js b/src/renderer/component/walletSend/index.js index 2643c5b57..44a743ef1 100644 --- a/src/renderer/component/walletSend/index.js +++ b/src/renderer/component/walletSend/index.js @@ -1,6 +1,5 @@ import { connect } from 'react-redux'; -import { doSendDraftTransaction } from 'redux/actions/wallet'; -import { selectBalance } from 'redux/selectors/wallet'; +import { doSendDraftTransaction, selectBalance } from 'lbry-redux'; import WalletSend from './view'; const perform = dispatch => ({ diff --git a/src/renderer/component/walletSendTip/index.js b/src/renderer/component/walletSendTip/index.js index 7677f0a7a..dc304f2e7 100644 --- a/src/renderer/component/walletSendTip/index.js +++ b/src/renderer/component/walletSendTip/index.js @@ -1,7 +1,10 @@ import { connect } from 'react-redux'; -import { doSendSupport } from 'redux/actions/wallet'; -import { makeSelectTitleForUri, makeSelectClaimForUri } from 'redux/selectors/claims'; -import { selectIsSendingSupport } from 'redux/selectors/wallet'; +import { + doSendSupport, + makeSelectTitleForUri, + makeSelectClaimForUri, + selectIsSendingSupport, +} from 'lbry-redux'; import WalletSendTip from './view'; const select = (state, props) => ({ diff --git a/src/renderer/component/wunderbar/index.js b/src/renderer/component/wunderbar/index.js index 9491c46f3..a694e5508 100644 --- a/src/renderer/component/wunderbar/index.js +++ b/src/renderer/component/wunderbar/index.js @@ -1,8 +1,11 @@ import * as MODALS from 'constants/modal_types'; import { connect } from 'react-redux'; -import { normalizeURI } from 'lbryURI'; -import { selectState as selectSearch, selectWunderBarAddress } from 'redux/selectors/search'; -import { doUpdateSearchQuery } from 'redux/actions/search'; +import { normalizeURI } from 'lbry-redux'; +import { + selectSearchState as selectSearch, + selectWunderBarAddress, + doUpdateSearchQuery, +} from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; import { doOpenModal } from 'redux/actions/app'; import Wunderbar from './view'; diff --git a/src/renderer/component/wunderbar/view.jsx b/src/renderer/component/wunderbar/view.jsx index 583ed54e6..74549bbbd 100644 --- a/src/renderer/component/wunderbar/view.jsx +++ b/src/renderer/component/wunderbar/view.jsx @@ -1,7 +1,7 @@ // @flow import React from 'react'; import classnames from 'classnames'; -import { normalizeURI } from 'lbryURI'; +import { normalizeURI } from 'lbry-redux'; import Icon from 'component/common/icon'; import { parseQueryParams } from 'util/query_params'; import * as icons from 'constants/icons'; diff --git a/src/renderer/jsonrpc.js b/src/renderer/jsonrpc.js deleted file mode 100644 index 184065122..000000000 --- a/src/renderer/jsonrpc.js +++ /dev/null @@ -1,86 +0,0 @@ -const jsonrpc = {}; - -jsonrpc.call = ( - connectionString, - method, - params, - callback, - errorCallback, - connectFailedCallback -) => { - function checkAndParse(response) { - if (response.status >= 200 && response.status < 300) { - return response.json(); - } - return response.json().then(json => { - let error; - if (json.error) { - error = new Error(json.error.message); - } else { - error = new Error('Protocol error with unknown response signature'); - } - return Promise.reject(error); - }); - } - - const counter = parseInt(sessionStorage.getItem('JSONRPCCounter') || 0, 10); - const url = connectionString; - const options = { - method: 'POST', - body: JSON.stringify({ - jsonrpc: '2.0', - method, - params, - id: counter, - }), - }; - - sessionStorage.setItem('JSONRPCCounter', counter + 1); - - return fetch(url, options) - .then(checkAndParse) - .then(response => { - const error = response.error || (response.result && response.result.error); - - if (!error && typeof callback === 'function') { - return callback(response.result); - } - - if (error && typeof errorCallback === 'function') { - return errorCallback(error); - } - - const errorEvent = new CustomEvent('unhandledError', { - detail: { - connectionString, - method, - params, - code: error.code, - message: error.message || error, - data: error.data, - }, - }); - document.dispatchEvent(errorEvent); - - return Promise.resolve(); - }) - .catch(error => { - if (connectFailedCallback) { - return connectFailedCallback(error); - } - - const errorEvent = new CustomEvent('unhandledError', { - detail: { - connectionString, - method, - params, - code: error.response && error.response.status, - message: __('Connection to API server failed'), - }, - }); - document.dispatchEvent(errorEvent); - return Promise.resolve(); - }); -}; - -export default jsonrpc; diff --git a/src/renderer/lbry.js b/src/renderer/lbry.js deleted file mode 100644 index 8da232e24..000000000 --- a/src/renderer/lbry.js +++ /dev/null @@ -1,151 +0,0 @@ -import { ipcRenderer } from 'electron'; -import jsonrpc from 'jsonrpc'; - -const CHECK_DAEMON_STARTED_TRY_NUMBER = 200; - -const Lbry = { - isConnected: false, - daemonConnectionString: 'http://localhost:5279', - pendingPublishTimeout: 20 * 60 * 1000, -}; - -function apiCall(method, params, resolve, reject) { - return jsonrpc.call(Lbry.daemonConnectionString, method, params, resolve, reject, reject); -} - -const lbryProxy = new Proxy(Lbry, { - get(target, name) { - if (name in target) { - return target[name]; - } - - return (params = {}) => - new Promise((resolve, reject) => { - apiCall(name, params, resolve, reject); - }); - }, -}); - -function getLocal(key, fallback = undefined) { - const itemRaw = localStorage.getItem(key); - return itemRaw === null ? fallback : JSON.parse(itemRaw); -} - -function setLocal(key, value) { - localStorage.setItem(key, JSON.stringify(value)); -} - -// core -Lbry.connectPromise = null; -Lbry.connect = () => { - if (Lbry.connectPromise === null) { - Lbry.connectPromise = new Promise((resolve, reject) => { - let tryNum = 0; - - // Check every half second to see if the daemon is accepting connections - function checkDaemonStarted() { - tryNum += 1; - lbryProxy - .status() - .then(resolve) - .catch(() => { - if (tryNum <= CHECK_DAEMON_STARTED_TRY_NUMBER) { - setTimeout(checkDaemonStarted, tryNum < 50 ? 400 : 1000); - } else { - reject(new Error('Unable to connect to LBRY')); - } - }); - } - - checkDaemonStarted(); - }); - } - - return Lbry.connectPromise; -}; - -Lbry.imagePath = file => `${staticResourcesPath}/img/${file}`; - -Lbry.getAppVersionInfo = () => - new Promise(resolve => { - ipcRenderer.once('version-info-received', (event, versionInfo) => { - resolve(versionInfo); - }); - ipcRenderer.send('version-info-requested'); - }); - -Lbry.getMediaType = (contentType, fileName) => { - if (contentType) { - return /^[^/]+/.exec(contentType)[0]; - } else if (fileName) { - const dotIndex = fileName.lastIndexOf('.'); - if (dotIndex === -1) { - return 'unknown'; - } - - const ext = fileName.substr(dotIndex + 1); - if (/^mp4|m4v|webm|flv|f4v|ogv$/i.test(ext)) { - return 'video'; - } else if (/^mp3|m4a|aac|wav|flac|ogg|opus$/i.test(ext)) { - return 'audio'; - } else if (/^html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|epub|org$/i.test(ext)) { - return 'document'; - } - return 'unknown'; - } - return 'unknown'; -}; - -/** - * Wrappers for API methods to simulate missing or future behavior. Unlike the old-style stubs, - * these are designed to be transparent wrappers around the corresponding API methods. - */ - -/** - * Returns results from the file_list API method, plus dummy entries for pending publishes. - * (If a real publish with the same claim name is found, the pending publish will be ignored and removed.) - */ -Lbry.file_list = (params = {}) => - new Promise((resolve, reject) => { - const { claim_name: claimName, channel_name: channelName, outpoint } = params; - - apiCall( - 'file_list', - params, - fileInfos => { - resolve(fileInfos); - }, - reject - ); - }); - -Lbry.claim_list_mine = (params = {}) => - new Promise((resolve, reject) => { - apiCall( - 'claim_list_mine', - params, - claims => { - resolve(claims); - }, - reject - ); - }); - -Lbry.resolve = (params = {}) => - new Promise((resolve, reject) => { - apiCall( - 'resolve', - params, - data => { - if ('uri' in params) { - // If only a single URI was requested, don't nest the results in an object - resolve(data && data[params.uri] ? data[params.uri] : {}); - } else { - resolve(data || {}); - } - }, - reject - ); - }); - -export default lbryProxy; diff --git a/src/renderer/lbryURI.js b/src/renderer/lbryURI.js deleted file mode 100644 index 9fd136b92..000000000 --- a/src/renderer/lbryURI.js +++ /dev/null @@ -1,230 +0,0 @@ -const channelNameMinLength = 1; -const claimIdMaxLength = 40; - -export const regexInvalidURI = /[^A-Za-z0-9-]/g; -export const regexAddress = /^b(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; - -/** - * Parses a LBRY name into its component parts. Throws errors with user-friendly - * messages for invalid names. - * - * N.B. that "name" indicates the value in the name position of the URI. For - * claims for channel content, this will actually be the channel name, and - * the content name is in the path (e.g. lbry://@channel/content) - * - * In most situations, you'll want to use the contentName and channelName keys - * and ignore the name key. - * - * Returns a dictionary with keys: - * - name (string): The value in the "name" position in the URI. Note that this - * could be either content name or channel name; see above. - * - path (string, if persent) - * - claimSequence (int, if present) - * - bidPosition (int, if present) - * - claimId (string, if present) - * - isChannel (boolean) - * - contentName (string): For anon claims, the name; for channel claims, the path - * - channelName (string, if present): Channel name without @ - */ -export function parseURI(URI, requireProto = false) { - // Break into components. Empty sub-matches are converted to null - const componentsRegex = new RegExp( - '^((?:lbry://)?)' + // protocol - '([^:$#/]*)' + // claim name (stops at the first separator or end) - '([:$#]?)([^/]*)' + // modifier separator, modifier (stops at the first path separator or end) - '(/?)(.*)' // path separator, path - ); - const [proto, claimName, modSep, modVal, pathSep, path] = componentsRegex - .exec(URI) - .slice(1) - .map(match => match || null); - - let contentName; - - // Validate protocol - if (requireProto && !proto) { - throw new Error(__('LBRY URIs must include a protocol prefix (lbry://).')); - } - - // Validate and process name - if (!claimName) { - throw new Error(__('URI does not include name.')); - } - - const isChannel = claimName.startsWith('@'); - const channelName = isChannel ? claimName.slice(1) : claimName; - - if (isChannel) { - if (!channelName) { - throw new Error(__('No channel name after @.')); - } - - if (channelName.length < channelNameMinLength) { - throw new Error(__(`Channel names must be at least %s characters.`, channelNameMinLength)); - } - - contentName = path; - } - - const nameBadChars = (channelName || claimName).match(regexInvalidURI); - if (nameBadChars) { - throw new Error( - __( - `Invalid character %s in name: %s.`, - nameBadChars.length === 1 ? '' : 's', - nameBadChars.join(', ') - ) - ); - } - - // Validate and process modifier (claim ID, bid position or claim sequence) - let claimId; - let claimSequence; - let bidPosition; - if (modSep) { - if (!modVal) { - throw new Error(__(`No modifier provided after separator %s.`, modSep)); - } - - if (modSep === '#') { - claimId = modVal; - } else if (modSep === ':') { - claimSequence = modVal; - } else if (modSep === '$') { - bidPosition = modVal; - } - } - - if ( - claimId && - (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/)) && - !claimId.match(/^pending/) // ought to be dropped when savePendingPublish drops hack - ) { - throw new Error(__(`Invalid claim ID %s.`, claimId)); - } - - if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) { - throw new Error(__('Claim sequence must be a number.')); - } - - if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]*$/)) { - throw new Error(__('Bid position must be a number.')); - } - - // Validate and process path - if (path) { - if (!isChannel) { - throw new Error(__('Only channel URIs may have a path.')); - } - - const pathBadChars = path.match(regexInvalidURI); - if (pathBadChars) { - throw new Error(__(`Invalid character in path: %s`, pathBadChars.join(', '))); - } - - contentName = path; - } else if (pathSep) { - throw new Error(__('No path provided after /')); - } - - return { - claimName, - path, - isChannel, - ...(contentName ? { contentName } : {}), - ...(channelName ? { channelName } : {}), - ...(claimSequence ? { claimSequence: parseInt(claimSequence, 10) } : {}), - ...(bidPosition ? { bidPosition: parseInt(bidPosition, 10) } : {}), - ...(claimId ? { claimId } : {}), - ...(path ? { path } : {}), - }; -} - -/** - * Takes an object in the same format returned by parse() and builds a URI. - * - * The channelName key will accept names with or without the @ prefix. - */ -export function buildURI(URIObj, includeProto = true) { - const { claimId, claimSequence, bidPosition, contentName, channelName } = URIObj; - - let { claimName, path } = URIObj; - - if (channelName) { - const channelNameFormatted = channelName.startsWith('@') ? channelName : `@${channelName}`; - if (!claimName) { - claimName = channelNameFormatted; - } else if (claimName !== channelNameFormatted) { - throw new Error( - __( - 'Received a channel content URI, but claim name and channelName do not match. "name" represents the value in the name position of the URI (lbry://name...), which for channel content will be the channel name. In most cases, to construct a channel URI you should just pass channelName and contentName.' - ) - ); - } - } - - if (contentName) { - if (!claimName) { - claimName = contentName; - } else if (!path) { - path = contentName; - } - if (path && path !== contentName) { - throw new Error( - __( - 'Path and contentName do not match. Only one is required; most likely you wanted contentName.' - ) - ); - } - } - - return ( - (includeProto ? 'lbry://' : '') + - claimName + - (claimId ? `#${claimId}` : '') + - (claimSequence ? `:${claimSequence}` : '') + - (bidPosition ? `${bidPosition}` : '') + - (path ? `/${path}` : '') - ); -} - -/* Takes a parseable LBRY URI and converts it to standard, canonical format */ -export function normalizeURI(URI) { - if (URI.match(/pending_claim/)) return URI; - - const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI); - return buildURI({ claimName, path, claimSequence, bidPosition, claimId }); -} - -export function isURIValid(URI) { - let parts; - try { - parts = parseURI(normalizeURI(URI)); - } catch (error) { - return false; - } - return parts && parts.claimName; -} - -export function isNameValid(claimName, checkCase = true) { - const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i'); - return regexp.test(claimName); -} - -export function isURIClaimable(URI) { - let parts; - try { - parts = parseURI(normalizeURI(URI)); - } catch (error) { - return false; - } - return ( - parts && - parts.claimName && - !parts.claimId && - !parts.bidPosition && - !parts.claimSequence && - !parts.isChannel && - !parts.path - ); -} diff --git a/src/renderer/lbryio.js b/src/renderer/lbryio.js index a666a2b28..a80ab27f1 100644 --- a/src/renderer/lbryio.js +++ b/src/renderer/lbryio.js @@ -1,38 +1,16 @@ import { ipcRenderer } from 'electron'; -import Lbry from 'lbry'; +import { Lbry } from 'lbry-redux'; import querystring from 'querystring'; const Lbryio = { enabled: true, authenticationPromise: null, - exchangePromise: null, - exchangeLastFetched: null, }; const CONNECTION_STRING = process.env.LBRY_APP_API_URL ? process.env.LBRY_APP_API_URL.replace(/\/*$/, '/') // exactly one slash at the end : 'https://api.lbry.io/'; -const EXCHANGE_RATE_TIMEOUT = 20 * 60 * 1000; - -Lbryio.getExchangeRates = () => { - if ( - !Lbryio.exchangeLastFetched || - Date.now() - Lbryio.exchangeLastFetched > EXCHANGE_RATE_TIMEOUT - ) { - Lbryio.exchangePromise = new Promise((resolve, reject) => { - Lbryio.call('lbc', 'exchange_rate', {}, 'get', true) - .then(({ lbc_usd: LBC_USD, lbc_btc: LBC_BTC, btc_usd: BTC_USD }) => { - const rates = { LBC_USD, LBC_BTC, BTC_USD }; - resolve(rates); - }) - .catch(reject); - }); - Lbryio.exchangeLastFetched = Date.now(); - } - return Lbryio.exchangePromise; -}; - Lbryio.call = (resource, action, params = {}, method = 'get') => { if (!Lbryio.enabled) { console.log(__('Internal API disabled')); diff --git a/src/renderer/modal/modalAffirmPurchase/index.js b/src/renderer/modal/modalAffirmPurchase/index.js index f3e5fc161..509cfc53f 100644 --- a/src/renderer/modal/modalAffirmPurchase/index.js +++ b/src/renderer/modal/modalAffirmPurchase/index.js @@ -1,8 +1,6 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; import { doLoadVideo, doSetPlayingUri } from 'redux/actions/content'; -import { makeSelectMetadataForUri } from 'redux/selectors/claims'; +import { doCloseModal, makeSelectMetadataForUri } from 'lbry-redux'; import ModalAffirmPurchase from './view'; const select = (state, props) => ({ diff --git a/src/renderer/modal/modalAuthFailure/index.js b/src/renderer/modal/modalAuthFailure/index.js index ed408365f..b947bddfa 100644 --- a/src/renderer/modal/modalAuthFailure/index.js +++ b/src/renderer/modal/modalAuthFailure/index.js @@ -1,6 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; +import { doCloseModal } from 'lbry-redux'; import ModalAuthFailure from './view'; const select = state => ({}); diff --git a/src/renderer/modal/modalCreditIntro/index.js b/src/renderer/modal/modalCreditIntro/index.js index 247d2ff5d..a8d956403 100644 --- a/src/renderer/modal/modalCreditIntro/index.js +++ b/src/renderer/modal/modalCreditIntro/index.js @@ -1,9 +1,8 @@ import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation'; import { doSetClientSetting } from 'redux/actions/settings'; import { selectUserIsRewardApproved } from 'redux/selectors/user'; -import { selectBalance } from 'redux/selectors/wallet'; +import { selectBalance, doCloseModal } from 'lbry-redux'; import { selectUnclaimedRewardValue } from 'redux/selectors/rewards'; import * as settings from 'constants/settings'; import ModalCreditIntro from './view'; diff --git a/src/renderer/modal/modalEmailCollection/index.js b/src/renderer/modal/modalEmailCollection/index.js index 242b9e509..96d98a815 100644 --- a/src/renderer/modal/modalEmailCollection/index.js +++ b/src/renderer/modal/modalEmailCollection/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import * as settings from 'constants/settings'; import { connect } from 'react-redux'; import { doCloseModal } from 'redux/actions/app'; diff --git a/src/renderer/modal/modalError/index.js b/src/renderer/modal/modalError/index.js index 570827151..baf5f3399 100644 --- a/src/renderer/modal/modalError/index.js +++ b/src/renderer/modal/modalError/index.js @@ -1,6 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; +import { doCloseModal } from 'lbry-redux'; import ModalError from './view'; const perform = dispatch => ({ diff --git a/src/renderer/modal/modalError/view.jsx b/src/renderer/modal/modalError/view.jsx index c42d04c8f..5fbf9ab77 100644 --- a/src/renderer/modal/modalError/view.jsx +++ b/src/renderer/modal/modalError/view.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import lbry from 'lbry'; +import Native from 'native'; import { ExpandableModal } from 'modal/modal'; class ModalError extends React.PureComponent { @@ -8,7 +8,7 @@ class ModalError extends React.PureComponent { const errorObj = typeof error === 'string' ? { message: error } : error; - const error_key_labels = { + const errorKeyLabels = { connectionString: __('API connection string'), method: __('Method'), params: __('Parameters'), @@ -20,7 +20,7 @@ class ModalError extends React.PureComponent { const errorInfoList = []; for (const key of Object.keys(errorObj)) { const val = typeof errorObj[key] === 'string' ? errorObj[key] : JSON.stringify(errorObj[key]); - const label = error_key_labels[key]; + const label = errorKeyLabels[key]; errorInfoList.push(
  • {label}: {val} @@ -42,7 +42,11 @@ class ModalError extends React.PureComponent {
    - +

    {__( diff --git a/src/renderer/modal/modalFileTimeout/index.js b/src/renderer/modal/modalFileTimeout/index.js index 2d8d280fc..b63d598d3 100644 --- a/src/renderer/modal/modalFileTimeout/index.js +++ b/src/renderer/modal/modalFileTimeout/index.js @@ -1,10 +1,8 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; -import { makeSelectMetadataForUri } from 'redux/selectors/claims'; +import { doCloseModal, makeSelectMetadataForUri } from 'lbry-redux'; import ModalFileTimeout from './view'; -const select = state => ({ +const select = (state, props) => ({ metadata: makeSelectMetadataForUri(props.uri)(state), }); diff --git a/src/renderer/modal/modalFirstReward/index.js b/src/renderer/modal/modalFirstReward/index.js index 77d8ac376..0ccf49732 100644 --- a/src/renderer/modal/modalFirstReward/index.js +++ b/src/renderer/modal/modalFirstReward/index.js @@ -1,11 +1,10 @@ -import React from 'react'; import rewards from 'rewards'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; +import { doCloseModal } from 'lbry-redux'; import { makeSelectRewardByType } from 'redux/selectors/rewards'; import ModalFirstReward from './view'; -const select = (state, props) => { +const select = state => { const selectReward = makeSelectRewardByType(); return { diff --git a/src/renderer/modal/modalPhoneCollection/index.js b/src/renderer/modal/modalPhoneCollection/index.js index d3ae17bc6..323d70dc0 100644 --- a/src/renderer/modal/modalPhoneCollection/index.js +++ b/src/renderer/modal/modalPhoneCollection/index.js @@ -4,8 +4,8 @@ import { connect } from 'react-redux'; import { doCloseModal } from 'redux/actions/app'; import { doSetClientSetting } from 'redux/actions/settings'; import { selectPhoneToVerify, selectUser } from 'redux/selectors/user'; -import ModalPhoneCollection from './view'; import { doNavigate } from 'redux/actions/navigation'; +import ModalPhoneCollection from './view'; const select = state => ({ phone: selectPhoneToVerify(state), diff --git a/src/renderer/modal/modalRemoveFile/index.js b/src/renderer/modal/modalRemoveFile/index.js index 76fac9580..d83fe60e0 100644 --- a/src/renderer/modal/modalRemoveFile/index.js +++ b/src/renderer/modal/modalRemoveFile/index.js @@ -1,9 +1,11 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; -import { doDeleteFileAndGoBack } from 'redux/actions/file_info'; -import { makeSelectTitleForUri, makeSelectClaimIsMine } from 'redux/selectors/claims'; -import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; +import { doDeleteFileAndGoBack } from 'redux/actions/file'; +import { + doCloseModal, + makeSelectTitleForUri, + makeSelectClaimIsMine, + makeSelectFileInfoForUri, +} from 'lbry-redux'; import ModalRemoveFile from './view'; const select = (state, props) => ({ diff --git a/src/renderer/modal/modalRevokeClaim/index.js b/src/renderer/modal/modalRevokeClaim/index.js index 7a47859f4..bd7d3e1cd 100644 --- a/src/renderer/modal/modalRevokeClaim/index.js +++ b/src/renderer/modal/modalRevokeClaim/index.js @@ -1,8 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; -import { doAbandonClaim } from 'redux/actions/content'; -import { selectTransactionItems } from 'redux/selectors/wallet'; +import { doCloseModal, doAbandonClaim, selectTransactionItems } from 'lbry-redux'; import ModalRevokeClaim from './view'; const select = state => ({ diff --git a/src/renderer/modal/modalRewardApprovalRequired/index.js b/src/renderer/modal/modalRewardApprovalRequired/index.js index 21091f5d8..613b09497 100644 --- a/src/renderer/modal/modalRewardApprovalRequired/index.js +++ b/src/renderer/modal/modalRewardApprovalRequired/index.js @@ -1,6 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; +import { doCloseModal } from 'lbry-redux'; import { doAuthNavigate } from 'redux/actions/navigation'; import ModalRewardApprovalRequired from './view'; diff --git a/src/renderer/modal/modalRouter/index.js b/src/renderer/modal/modalRouter/index.js index cea033096..ed1ae6920 100644 --- a/src/renderer/modal/modalRouter/index.js +++ b/src/renderer/modal/modalRouter/index.js @@ -1,13 +1,14 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doOpenModal } from 'redux/actions/app'; import * as settings from 'constants/settings'; import { selectCurrentModal, selectModalProps, selectModalsAllowed } from 'redux/selectors/app'; -import { selectCurrentPage } from 'redux/selectors/navigation'; -import { selectCostForCurrentPageUri } from 'redux/selectors/cost_info'; +import { + doOpenModal, + selectCostForCurrentPageUri, + selectBalance, + selectCurrentPage, +} from 'lbry-redux'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import { selectUser, selectUserIsVerificationCandidate } from 'redux/selectors/user'; -import { selectBalance } from 'redux/selectors/wallet'; import ModalRouter from './view'; diff --git a/src/renderer/modal/modalTransactionFailed/index.js b/src/renderer/modal/modalTransactionFailed/index.js index 7809b05ee..c01c8e56e 100644 --- a/src/renderer/modal/modalTransactionFailed/index.js +++ b/src/renderer/modal/modalTransactionFailed/index.js @@ -1,6 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doCloseModal } from 'redux/actions/app'; +import { doCloseModal } from 'lbry-redux'; import ModalTransactionFailed from './view'; const select = state => ({}); diff --git a/src/renderer/modal/modalWelcome/index.js b/src/renderer/modal/modalWelcome/index.js index 0688d6a07..f6a33fa0f 100644 --- a/src/renderer/modal/modalWelcome/index.js +++ b/src/renderer/modal/modalWelcome/index.js @@ -1,8 +1,6 @@ -import React from 'react'; import * as settings from 'constants/settings'; -import * as modals from 'constants/modal_types'; import { connect } from 'react-redux'; -import { doCloseModal, doOpenModal } from 'redux/actions/app'; +import { doCloseModal } from 'lbry-redux'; import { doSetClientSetting } from 'redux/actions/settings'; import ModalWelcome from './view'; diff --git a/src/renderer/native.js b/src/renderer/native.js new file mode 100644 index 000000000..4b6dbf3e3 --- /dev/null +++ b/src/renderer/native.js @@ -0,0 +1,15 @@ +import { ipcRenderer } from 'electron'; + +const Native = {}; + +Native.getAppVersionInfo = () => + new Promise(resolve => { + ipcRenderer.once('version-info-received', (event, versionInfo) => { + resolve(versionInfo); + }); + ipcRenderer.send('version-info-requested'); + }); + +Native.imagePath = file => `${staticResourcesPath}/img/${file}`; + +export default Native; diff --git a/src/renderer/page/auth/index.js b/src/renderer/page/auth/index.js index 63d9b15f7..7964ef405 100644 --- a/src/renderer/page/auth/index.js +++ b/src/renderer/page/auth/index.js @@ -1,7 +1,6 @@ -import React from 'react'; -import { doNavigate } from 'redux/actions/navigation'; +import { selectPathAfterAuth } from 'lbry-redux'; import { connect } from 'react-redux'; -import { selectPathAfterAuth } from 'redux/selectors/navigation'; +import { doNavigate } from 'redux/actions/navigation'; import { selectAuthenticationIsPending, selectEmailToVerify, diff --git a/src/renderer/page/channel/index.js b/src/renderer/page/channel/index.js index 38fabedfe..5cf33426b 100644 --- a/src/renderer/page/channel/index.js +++ b/src/renderer/page/channel/index.js @@ -1,12 +1,12 @@ -import React from 'react'; import { connect } from 'react-redux'; import { doFetchClaimsByChannel, doFetchClaimCountByChannel } from 'redux/actions/content'; import { makeSelectClaimForUri, makeSelectClaimsInChannelForCurrentPage, makeSelectFetchingChannelClaims, -} from 'redux/selectors/claims'; -import { makeSelectCurrentParam, selectCurrentParams } from 'redux/selectors/navigation'; + makeSelectCurrentParam, + selectCurrentParams, +} from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; import { makeSelectTotalPagesForChannel } from 'redux/selectors/content'; import { doOpenModal } from 'redux/actions/app'; diff --git a/src/renderer/page/file/index.js b/src/renderer/page/file/index.js index 5e618c4c9..b8bd7c471 100644 --- a/src/renderer/page/file/index.js +++ b/src/renderer/page/file/index.js @@ -1,21 +1,21 @@ import { connect } from 'react-redux'; import { doNavigate } from 'redux/actions/navigation'; -import { doFetchFileInfo } from 'redux/actions/file_info'; -import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content'; -import { doFetchCostInfoForUri } from 'redux/actions/cost_info'; import { doCheckSubscription } from 'redux/actions/subscriptions'; import { + doFetchFileInfo, + doFetchCostInfoForUri, + makeSelectClaimIsMine, + makeSelectCostInfoForUri, + makeSelectFileInfoForUri, makeSelectClaimForUri, makeSelectContentTypeForUri, makeSelectMetadataForUri, - makeSelectClaimIsMine, -} from 'redux/selectors/claims'; -import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info'; +} from 'lbry-redux'; import { selectShowNsfw } from 'redux/selectors/settings'; +import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectMediaPaused } from 'redux/selectors/media'; import { doOpenModal } from 'redux/actions/app'; -import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { doPrepareEdit } from 'redux/actions/publish'; import FilePage from './view'; diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx index 98ee33ffa..ee9a7f6c8 100644 --- a/src/renderer/page/file/view.jsx +++ b/src/renderer/page/file/view.jsx @@ -1,7 +1,6 @@ // @flow import * as React from 'react'; -import lbry from 'lbry'; -import { buildURI, normalizeURI } from 'lbryURI'; +import { Lbry, buildURI, normalizeURI } from 'lbry-redux'; import Video from 'component/video'; import Thumbnail from 'component/common/thumbnail'; import FilePrice from 'component/filePrice'; @@ -111,7 +110,7 @@ class FilePage extends React.Component { const isRewardContent = rewardedContentClaimIds.includes(claim.claim_id); const shouldObscureThumbnail = obscureNsfw && metadata.nsfw; const { height, channel_name: channelName, value } = claim; - const mediaType = lbry.getMediaType(contentType); + const mediaType = Lbry.getMediaType(contentType); const isPlayable = Object.values(player.mime).indexOf(contentType) !== -1 || mediaType === 'audio'; const channelClaimId = diff --git a/src/renderer/page/fileListDownloaded/index.js b/src/renderer/page/fileListDownloaded/index.js index 9fc0fb685..86482f664 100644 --- a/src/renderer/page/fileListDownloaded/index.js +++ b/src/renderer/page/fileListDownloaded/index.js @@ -1,6 +1,5 @@ import { connect } from 'react-redux'; -import { selectFileInfosDownloaded } from 'redux/selectors/file_info'; -import { selectMyClaimsWithoutChannels } from 'redux/selectors/claims'; +import { selectFileInfosDownloaded, selectMyClaimsWithoutChannels } from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; import FileListDownloaded from './view'; diff --git a/src/renderer/page/fileListPublished/index.js b/src/renderer/page/fileListPublished/index.js index 8b7546b73..643b27a6c 100644 --- a/src/renderer/page/fileListPublished/index.js +++ b/src/renderer/page/fileListPublished/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { selectMyClaimsWithoutChannels } from 'redux/selectors/claims'; +import { selectMyClaimsWithoutChannels } from 'lbry-redux'; import { selectPendingPublishesLessEdits } from 'redux/selectors/publish'; import { doNavigate } from 'redux/actions/navigation'; import { doCheckPendingPublishes } from 'redux/actions/publish'; diff --git a/src/renderer/page/help/index.js b/src/renderer/page/help/index.js index 7138061ed..6a59becb9 100644 --- a/src/renderer/page/help/index.js +++ b/src/renderer/page/help/index.js @@ -1,6 +1,5 @@ -import React from 'react'; -import { doAuthNavigate } from 'redux/actions/navigation'; import { connect } from 'react-redux'; +import { doAuthNavigate } from 'redux/actions/navigation'; import { doFetchAccessToken } from 'redux/actions/user'; import { selectAccessToken, selectUser } from 'redux/selectors/user'; import HelpPage from './view'; diff --git a/src/renderer/page/help/view.jsx b/src/renderer/page/help/view.jsx index 32271091a..4bfd88963 100644 --- a/src/renderer/page/help/view.jsx +++ b/src/renderer/page/help/view.jsx @@ -1,6 +1,7 @@ // @TODO: Customize advice based on OS import React from 'react'; -import lbry from 'lbry.js'; +import { Lbry } from 'lbry-redux'; +import Native from 'native'; import Button from 'component/button'; import BusyIndicator from 'component/common/busy-indicator'; import Icon from 'component/common/icon'; @@ -23,18 +24,18 @@ class HelpPage extends React.PureComponent { } componentDidMount() { - lbry.getAppVersionInfo().then(({ remoteVersion, localVersion, upgradeAvailable }) => { + Native.getAppVersionInfo().then(({ remoteVersion, localVersion, upgradeAvailable }) => { this.setState({ uiVersion: localVersion, upgradeAvailable, }); }); - lbry.version().then(info => { + Lbry.version().then(info => { this.setState({ versionInfo: info, }); }); - lbry.status({ session_status: true }).then(info => { + Lbry.status({ session_status: true }).then(info => { this.setState({ lbryId: info.lbry_id, }); @@ -50,18 +51,21 @@ class HelpPage extends React.PureComponent { } render() { - let ver, osName, platform, newVerLink; + let ver; + let osName; + let platform; + let newVerLink; const { accessToken, doAuth, user } = this.props; if (this.state.versionInfo) { ver = this.state.versionInfo; - if (ver.os_system == 'Darwin') { - osName = parseInt(ver.os_release.match(/^\d+/)) < 16 ? 'Mac OS X' : 'Mac OS'; + if (ver.os_system === 'Darwin') { + osName = parseInt(ver.os_release.match(/^\d+/), 10) < 16 ? 'Mac OS X' : 'Mac OS'; platform = `${osName} ${ver.os_release}`; newVerLink = 'https://lbry.io/get/lbry.dmg'; - } else if (ver.os_system == 'Linux') { + } else if (ver.os_system === 'Linux') { platform = `Linux (${ver.platform})`; newVerLink = 'https://lbry.io/get/lbry.deb'; } else { diff --git a/src/renderer/page/publish/index.js b/src/renderer/page/publish/index.js index fea673cbc..864ab0df5 100644 --- a/src/renderer/page/publish/index.js +++ b/src/renderer/page/publish/index.js @@ -1,17 +1,26 @@ import { connect } from 'react-redux'; -import { doNavigate } from 'redux/actions/navigation'; -import { selectMyClaims, selectClaimsByUri } from 'redux/selectors/claims'; -import { selectResolvingUris } from 'redux/selectors/content'; -import { selectPublishFormValues } from 'redux/selectors/publish'; -import { doResolveUri } from 'redux/actions/content'; -import { selectBalance } from 'redux/selectors/wallet'; +import { doClaimRewardType } from 'redux/actions/rewards'; import { - doClearPublish, - doUpdatePublishForm, - doPublish, - doPrepareEdit, -} from 'redux/actions/publish'; -import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info'; + doHistoryBack, + doResolveUri, + makeSelectCostInfoForUri, + selectMyClaims, + selectFetchingMyChannels, + selectMyChannelClaims, + selectClaimsByUri, + selectResolvingUris, + selectBalance, +} from 'lbry-redux'; +import { + doFetchClaimListMine, + doFetchChannelListMine, + doCreateChannel, +} from 'redux/actions/content'; +import { doNavigate } from 'redux/actions/navigation'; +import rewards from 'rewards'; +import { selectPublishFormValues } from 'redux/selectors/publish'; +import { doClearPublish, doUpdatePublishForm, doPublish } from 'redux/actions/publish'; +import { doPrepareEdit } from 'redux/actions/publish'; import PublishPage from './view'; const select = (state, props) => { diff --git a/src/renderer/page/report/view.jsx b/src/renderer/page/report/view.jsx index c94e4e308..37b651603 100644 --- a/src/renderer/page/report/view.jsx +++ b/src/renderer/page/report/view.jsx @@ -1,9 +1,8 @@ import React from 'react'; import Button from 'component/button'; -import { FormRow, FormField } from 'component/common/form'; +import { FormRow } from 'component/common/form'; +import { Lbry } from 'lbry-redux'; import { doShowSnackBar } from 'redux/actions/app'; -import lbry from 'lbry'; -import Page from 'component/page'; class ReportPage extends React.Component { constructor(props) { @@ -27,7 +26,7 @@ class ReportPage extends React.Component { this.setState({ submitting: true, }); - lbry.report_bug({ message }).then(() => { + Lbry.report_bug({ message }).then(() => { this.setState({ submitting: false, }); diff --git a/src/renderer/page/rewards/index.js b/src/renderer/page/rewards/index.js index c0c7c6b64..8efdfe1d3 100644 --- a/src/renderer/page/rewards/index.js +++ b/src/renderer/page/rewards/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { connect } from 'react-redux'; import { selectFetchingRewards, selectUnclaimedRewards } from 'redux/selectors/rewards'; import { selectUser } from 'redux/selectors/user'; diff --git a/src/renderer/page/search/index.js b/src/renderer/page/search/index.js index 7946f5378..75d1f6b00 100644 --- a/src/renderer/page/search/index.js +++ b/src/renderer/page/search/index.js @@ -1,8 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; -import { selectIsSearching, selectSearchValue } from 'redux/selectors/search'; +import { selectIsSearching, selectSearchValue, doUpdateSearchQuery } from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; -import { doUpdateSearchQuery } from 'redux/actions/search'; import SearchPage from './view'; const select = state => ({ diff --git a/src/renderer/page/search/view.jsx b/src/renderer/page/search/view.jsx index 48273e7a4..03c6a55a7 100644 --- a/src/renderer/page/search/view.jsx +++ b/src/renderer/page/search/view.jsx @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { isURIValid, normalizeURI } from 'lbryURI'; +import { isURIValid, normalizeURI } from 'lbry-redux'; import FileTile from 'component/fileTile'; import FileListSearch from 'component/fileListSearch'; import ToolTip from 'component/common/tooltip'; diff --git a/src/renderer/page/show/index.js b/src/renderer/page/show/index.js index 8a3871668..cdb0c981c 100644 --- a/src/renderer/page/show/index.js +++ b/src/renderer/page/show/index.js @@ -1,8 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doResolveUri } from 'redux/actions/content'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; -import { makeSelectIsUriResolving } from 'redux/selectors/content'; +import { doResolveUri, makeSelectClaimForUri, makeSelectIsUriResolving } from 'lbry-redux'; import ShowPage from './view'; const select = (state, props) => ({ diff --git a/src/renderer/page/transactionHistory/index.js b/src/renderer/page/transactionHistory/index.js index 2323994f1..b31414474 100644 --- a/src/renderer/page/transactionHistory/index.js +++ b/src/renderer/page/transactionHistory/index.js @@ -1,7 +1,9 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doFetchTransactions } from 'redux/actions/wallet'; -import { selectTransactionItems, selectIsFetchingTransactions } from 'redux/selectors/wallet'; +import { + doFetchTransactions, + selectTransactionItems, + selectIsFetchingTransactions, +} from 'lbry-redux'; import TransactionHistoryPage from './view'; const select = state => ({ diff --git a/src/renderer/redux/actions/app.js b/src/renderer/redux/actions/app.js index f9c868baf..41c8b3b52 100644 --- a/src/renderer/redux/actions/app.js +++ b/src/renderer/redux/actions/app.js @@ -1,19 +1,16 @@ import { execSync } from 'child_process'; import isDev from 'electron-is-dev'; -import Lbry from 'lbry'; import path from 'path'; -import * as ACTIONS from 'constants/action_types'; import * as MODALS from 'constants/modal_types'; import { ipcRenderer, remote } from 'electron'; +import { ACTIONS, Lbry, doBalanceSubscribe, doFetchFileInfosAndPublishedClaims } from 'lbry-redux'; +import Native from 'native'; import { doFetchRewardedContent } from 'redux/actions/content'; -import { doFetchFileInfosAndPublishedClaims } from 'redux/actions/file_info'; -import { doAuthNavigate } from 'redux/actions/navigation'; import { doFetchDaemonSettings } from 'redux/actions/settings'; +import { doAuthNavigate } from 'redux/actions/navigation'; import { doAuthenticate } from 'redux/actions/user'; -import { doBalanceSubscribe } from 'redux/actions/wallet'; import { doPause } from 'redux/actions/media'; import { doCheckSubscriptions } from 'redux/actions/subscriptions'; - import { selectCurrentModal, selectIsUpgradeSkipped, @@ -240,7 +237,7 @@ export function doCheckUpgradeAvailable() { }); }; - Lbry.getAppVersionInfo().then(success, fail); + Native.getAppVersionInfo().then(success, fail); }; } @@ -303,13 +300,6 @@ export function doDaemonReady() { }; } -export function doShowSnackBar(data) { - return { - type: ACTIONS.SHOW_SNACKBAR, - data, - }; -} - export function doRemoveSnackBarSnack() { return { type: ACTIONS.REMOVE_SNACKBAR_SNACK, diff --git a/src/renderer/redux/actions/content.js b/src/renderer/redux/actions/content.js index afa1ad2ef..43b404bfc 100644 --- a/src/renderer/redux/actions/content.js +++ b/src/renderer/redux/actions/content.js @@ -1,12 +1,8 @@ -import * as ACTIONS from 'constants/action_types'; import * as MODALS from 'constants/modal_types'; -import * as SETTINGS from 'constants/settings'; import * as NOTIFICATION_TYPES from 'constants/notification_types'; import { ipcRenderer } from 'electron'; -import Lbry from 'lbry'; import Lbryio from 'lbryio'; -import { normalizeURI, buildURI } from 'lbryURI'; -import { doAlertError, doOpenModal } from 'redux/actions/app'; +import { doAlertError } from 'redux/actions/app'; import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards'; import { doNavigate } from 'redux/actions/navigation'; import { @@ -16,68 +12,29 @@ import { } from 'redux/actions/subscriptions'; import { selectNotifications } from 'redux/selectors/subscriptions'; import { selectBadgeNumber } from 'redux/selectors/app'; -import { selectMyClaimsRaw } from 'redux/selectors/claims'; -import { selectResolvingUris } from 'redux/selectors/content'; -import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info'; import { + ACTIONS, + SETTINGS, + Lbry, + Lbryapi, + buildURI, + batchActions, + doResolveUris, + doFetchClaimListMine, + doOpenModal, + makeSelectCostInfoForUri, makeSelectFileInfoForUri, selectDownloadingByOutpoint, selectTotalDownloadProgress, -} from 'redux/selectors/file_info'; + selectBalance, +} from 'lbry-redux'; import { makeSelectClientSetting } from 'redux/selectors/settings'; -import { selectBalance } from 'redux/selectors/wallet'; -import batchActions from 'util/batchActions'; import setBadge from 'util/setBadge'; import setProgressBar from 'util/setProgressBar'; import analytics from 'analytics'; const DOWNLOAD_POLL_INTERVAL = 250; -export function doResolveUris(uris) { - return (dispatch, getState) => { - const normalizedUris = uris.map(normalizeURI); - const state = getState(); - - // Filter out URIs that are already resolving - const resolvingUris = selectResolvingUris(state); - const urisToResolve = normalizedUris.filter(uri => !resolvingUris.includes(uri)); - - if (urisToResolve.length === 0) { - return; - } - - dispatch({ - type: ACTIONS.RESOLVE_URIS_STARTED, - data: { uris: normalizedUris }, - }); - - const resolveInfo = {}; - Lbry.resolve({ uris: urisToResolve }).then(result => { - Object.entries(result).forEach(([uri, uriResolveInfo]) => { - const fallbackResolveInfo = { - claim: null, - claimsInChannel: null, - certificate: null, - }; - - const { claim, certificate, claims_in_channel: claimsInChannel } = - uriResolveInfo && !uriResolveInfo.error ? uriResolveInfo : fallbackResolveInfo; - - resolveInfo[uri] = { claim, certificate, claimsInChannel }; - }); - - dispatch({ - type: ACTIONS.RESOLVE_URIS_COMPLETED, - data: { resolveInfo }, - }); - }); - }; -} - -export function doResolveUri(uri) { - return doResolveUris([uri]); -} - export function doFetchFeaturedUris() { return dispatch => { dispatch({ @@ -374,7 +331,7 @@ export function doPurchaseUri(uri, specificCostInfo) { attemptPlay(cost, instantPurchaseMax.amount); } else { // Need to convert currency of instant purchase maximum before trying to play - Lbryio.getExchangeRates().then(({ LBC_USD }) => { + Lbryapi.getExchangeRates().then(({ LBC_USD }) => { attemptPlay(cost, instantPurchaseMax.amount / LBC_USD); }); } @@ -457,23 +414,6 @@ export function doFetchClaimCountByChannel(uri) { }; } -export function doFetchClaimListMine() { - return dispatch => { - dispatch({ - type: ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED, - }); - - Lbry.claim_list_mine().then(claims => { - dispatch({ - type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED, - data: { - claims, - }, - }); - }); - }; -} - export function doPlayUri(uri) { return dispatch => { dispatch(doSetPlayingUri(uri)); @@ -526,43 +466,20 @@ export function doCreateChannel(name, amount) { }; } -export function doAbandonClaim(txid, nout) { - return (dispatch, getState) => { - const state = getState(); - const myClaims = selectMyClaimsRaw(state); - const { claim_id: claimId, name } = myClaims.find( - claim => claim.txid === txid && claim.nout === nout - ); +export function doPublish(params) { + return dispatch => + new Promise((resolve, reject) => { + const success = claim => { + resolve(claim); - dispatch({ - type: ACTIONS.ABANDON_CLAIM_STARTED, - data: { - claimId, - }, + if (claim === true) dispatch(doFetchClaimListMine()); + else + setTimeout(() => dispatch(doFetchClaimListMine()), 20000, { + once: true, + }); + }; + const failure = err => reject(err); + + Lbry.publishDeprecated(params, null, success, failure); }); - - const errorCallback = () => { - dispatch(doOpenModal(MODALS.TRANSACTION_FAILED)); - }; - - const successCallback = results => { - if (results.txid) { - dispatch({ - type: ACTIONS.ABANDON_CLAIM_SUCCEEDED, - data: { - claimId, - }, - }); - dispatch(doResolveUri(buildURI({ claimName: name, claimId }))); - dispatch(doFetchClaimListMine()); - } else { - dispatch(doOpenModal(MODALS.TRANSACTION_FAILED)); - } - }; - - Lbry.claim_abandon({ - txid, - nout, - }).then(successCallback, errorCallback); - }; } diff --git a/src/renderer/redux/actions/cost_info.js b/src/renderer/redux/actions/cost_info.js deleted file mode 100644 index 7e9966f05..000000000 --- a/src/renderer/redux/actions/cost_info.js +++ /dev/null @@ -1,38 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; -import Lbryio from 'lbryio'; -import { selectClaimsByUri } from 'redux/selectors/claims'; - -// eslint-disable-next-line import/prefer-default-export -export function doFetchCostInfoForUri(uri) { - return (dispatch, getState) => { - const state = getState(); - const claim = selectClaimsByUri(state)[uri]; - - if (!claim) return; - - function resolve(costInfo) { - dispatch({ - type: ACTIONS.FETCH_COST_INFO_COMPLETED, - data: { - uri, - costInfo, - }, - }); - } - - const fee = - claim.value && claim.value.stream && claim.value.stream.metadata - ? claim.value.stream.metadata.fee - : undefined; - - if (fee === undefined) { - resolve({ cost: 0, includesData: true }); - } else if (fee.currency === 'LBC') { - resolve({ cost: fee.amount, includesData: true }); - } else { - Lbryio.getExchangeRates().then(({ LBC_USD }) => { - resolve({ cost: fee.amount / LBC_USD, includesData: true }); - }); - } - }; -} diff --git a/src/renderer/redux/actions/file_info.js b/src/renderer/redux/actions/file.js similarity index 50% rename from src/renderer/redux/actions/file_info.js rename to src/renderer/redux/actions/file.js index 9ed4c9a6f..303de9b30 100644 --- a/src/renderer/redux/actions/file_info.js +++ b/src/renderer/redux/actions/file.js @@ -1,73 +1,17 @@ import * as ACTIONS from 'constants/action_types'; import { shell } from 'electron'; -import Lbry from 'lbry'; -import { doCloseModal } from 'redux/actions/app'; -import { doAbandonClaim, doFetchClaimListMine } from 'redux/actions/content'; -import { doHistoryBack } from 'redux/actions/navigation'; import { - selectClaimsByUri, - selectIsFetchingClaimListMine, + Lbry, + batchActions, + doAbandonClaim, selectMyClaimsOutpoints, -} from 'redux/selectors/claims'; -import { selectFileInfosByOutpoint, - selectIsFetchingFileList, selectTotalDownloadProgress, - selectUrisLoading, -} from 'redux/selectors/file_info'; -import batchActions from 'util/batchActions'; +} from 'lbry-redux'; +import { doCloseModal } from 'redux/actions/app'; +import { doHistoryBack } from 'redux/actions/navigation'; import setProgressBar from 'util/setProgressBar'; -export function doFetchFileInfo(uri) { - return (dispatch, getState) => { - const state = getState(); - const claim = selectClaimsByUri(state)[uri]; - const outpoint = claim ? `${claim.txid}:${claim.nout}` : null; - const alreadyFetching = !!selectUrisLoading(state)[uri]; - - if (!alreadyFetching) { - dispatch({ - type: ACTIONS.FETCH_FILE_INFO_STARTED, - data: { - outpoint, - }, - }); - - Lbry.file_list({ outpoint, full_status: true }).then(fileInfos => { - dispatch({ - type: ACTIONS.FETCH_FILE_INFO_COMPLETED, - data: { - outpoint, - fileInfo: fileInfos && fileInfos.length ? fileInfos[0] : null, - }, - }); - }); - } - }; -} - -export function doFileList() { - return (dispatch, getState) => { - const state = getState(); - const isFetching = selectIsFetchingFileList(state); - - if (!isFetching) { - dispatch({ - type: ACTIONS.FILE_LIST_STARTED, - }); - - Lbry.file_list().then(fileInfos => { - dispatch({ - type: ACTIONS.FILE_LIST_SUCCEEDED, - data: { - fileInfos, - }, - }); - }); - } - }; -} - export function doOpenFileInFolder(path) { return () => { shell.showItemInFolder(path); @@ -127,14 +71,3 @@ export function doDeleteFileAndGoBack(fileInfo, deleteFromComputer, abandonClaim dispatch(batchActions(...actions)); }; } - -export function doFetchFileInfosAndPublishedClaims() { - return (dispatch, getState) => { - const state = getState(); - const isFetchingClaimListMine = selectIsFetchingClaimListMine(state); - const isFetchingFileInfo = selectIsFetchingFileList(state); - - if (!isFetchingClaimListMine) dispatch(doFetchClaimListMine()); - if (!isFetchingFileInfo) dispatch(doFileList()); - }; -} diff --git a/src/renderer/redux/actions/media.js b/src/renderer/redux/actions/media.js index f554d054d..1b7d0b85f 100644 --- a/src/renderer/redux/actions/media.js +++ b/src/renderer/redux/actions/media.js @@ -1,8 +1,6 @@ // @flow import * as actions from 'constants/action_types'; -import type { Action, Dispatch } from 'redux/reducers/media'; -import lbry from 'lbry'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import type { Dispatch } from 'redux/reducers/media'; export const doPlay = () => (dispatch: Dispatch) => dispatch({ diff --git a/src/renderer/redux/actions/navigation.js b/src/renderer/redux/actions/navigation.js index 81be11261..dceceea82 100644 --- a/src/renderer/redux/actions/navigation.js +++ b/src/renderer/redux/actions/navigation.js @@ -1,5 +1,4 @@ -import * as ACTIONS from 'constants/action_types'; -import { selectHistoryIndex, selectHistoryStack } from 'redux/selectors/navigation'; +import { ACTIONS, selectHistoryIndex, selectHistoryStack } from 'lbry-redux'; import { toQueryString } from 'util/query_params'; import analytics from 'analytics'; diff --git a/src/renderer/redux/actions/publish.js b/src/renderer/redux/actions/publish.js index f592df6fb..9b6d946ce 100644 --- a/src/renderer/redux/actions/publish.js +++ b/src/renderer/redux/actions/publish.js @@ -1,8 +1,6 @@ // @flow -import Lbry from 'lbry'; -import * as ACTIONS from 'constants/action_types'; import * as MODALS from 'constants/modal_types'; -import { selectMyClaimsWithoutChannels } from 'redux/selectors/claims'; +import { ACTIONS, Lbry, selectMyClaimsWithoutChannels } from 'lbry-redux'; import { selectPendingPublishes } from 'redux/selectors/publish'; import { doOpenModal } from 'redux/actions/app'; import type { diff --git a/src/renderer/redux/actions/search.js b/src/renderer/redux/actions/search.js deleted file mode 100644 index 3aac1bf09..000000000 --- a/src/renderer/redux/actions/search.js +++ /dev/null @@ -1,176 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; -import * as SEARCH_TYPES from 'constants/search'; -import { normalizeURI, buildURI, parseURI } from 'lbryURI'; -import { doResolveUri } from 'redux/actions/content'; -import { doNavigate } from 'redux/actions/navigation'; -import { selectCurrentPage } from 'redux/selectors/navigation'; -import { makeSelectSearchUris } from 'redux/selectors/search'; -import batchActions from 'util/batchActions'; -import handleFetchResponse from 'util/handle-fetch'; - -export const doSearch = rawQuery => (dispatch, getState) => { - const state = getState(); - const query = rawQuery.replace(/^lbry:\/\//i, ''); - - if (!query) { - dispatch({ - type: ACTIONS.SEARCH_FAIL, - }); - return; - } - - // If we have already searched for something, we don't need to do anything - const urisForQuery = makeSelectSearchUris(query)(state); - if (urisForQuery && !!urisForQuery.length) { - return; - } - - dispatch({ - type: ACTIONS.SEARCH_START, - }); - - // If the user is on the file page with a pre-populated uri and they select - // the search option without typing anything, searchQuery will be empty - // We need to populate it so the input is filled on the search page - if (!state.search.searchQuery) { - dispatch({ - type: ACTIONS.UPDATE_SEARCH_QUERY, - data: { searchQuery: query }, - }); - } - - fetch(`https://lighthouse.lbry.io/search?s=${query}`) - .then(handleFetchResponse) - .then(data => { - const uris = []; - const actions = []; - - data.forEach(result => { - const uri = buildURI({ - claimName: result.name, - claimId: result.claimId, - }); - actions.push(doResolveUri(uri)); - uris.push(uri); - }); - - actions.push({ - type: ACTIONS.SEARCH_SUCCESS, - data: { - query, - uris, - }, - }); - dispatch(batchActions(...actions)); - }) - .catch(() => { - dispatch({ - type: ACTIONS.SEARCH_FAIL, - }); - }); -}; - -export const doUpdateSearchQuery = (query: string, shouldSkipSuggestions: ?boolean) => dispatch => { - dispatch({ - type: ACTIONS.UPDATE_SEARCH_QUERY, - data: { query }, - }); - - // Don't fetch new suggestions if the user just added a space - if (!query.endsWith(' ') || !shouldSkipSuggestions) { - dispatch(getSearchSuggestions(query)); - } -}; - -export const getSearchSuggestions = (value: string) => dispatch => { - const query = value.trim(); - - const isPrefix = () => { - return query === '@' || query === 'lbry:' || query === 'lbry:/' || query === 'lbry://'; - }; - - if (!query || isPrefix()) { - dispatch({ - type: ACTIONS.UPDATE_SEARCH_SUGGESTIONS, - data: { suggestions: [] }, - }); - return; - } - - let suggestions = []; - try { - // If the user is about to manually add the claim id ignore it until they - // actually add one. This would hardly ever happen, but then the search - // suggestions won't change just from adding a '#' after a uri - let uriQuery = query; - if (uriQuery.endsWith('#')) { - uriQuery = uriQuery.slice(0, -1); - } - - const uri = normalizeURI(uriQuery); - const { claimName, isChannel } = parseURI(uri); - - suggestions.push( - { - value: uri, - shorthand: isChannel ? claimName.slice(1) : claimName, - type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE, - }, - { - value: claimName, - type: SEARCH_TYPES.SEARCH, - } - ); - - // If it's a valid url, don't fetch any extra search results - return dispatch({ - type: ACTIONS.UPDATE_SEARCH_SUGGESTIONS, - data: { suggestions }, - }); - } catch (e) { - suggestions.push({ - value: query, - type: SEARCH_TYPES.SEARCH, - }); - } - - // Populate the current search query suggestion before fetching results - dispatch({ - type: ACTIONS.UPDATE_SEARCH_SUGGESTIONS, - data: { suggestions }, - }); - - // strip out any basic stuff for more accurate search results - let searchValue = value.replace(/lbry:\/\//g, '').replace(/-/g, ' '); - if (searchValue.includes('#')) { - // This should probably be more robust, but I think it's fine for now - // Remove everything after # to get rid of the claim id - searchValue = searchValue.substring(0, searchValue.indexOf('#')); - } - - return fetch(`https://lighthouse.lbry.io/autocomplete?s=${searchValue}`) - .then(handleFetchResponse) - .then(apiSuggestions => { - const formattedSuggestions = apiSuggestions.slice(0, 6).map(suggestion => { - // This will need to be more robust when the api starts returning lbry uris - const isChannel = suggestion.startsWith('@'); - const suggestionObj = { - value: isChannel ? `lbry://${suggestion}` : suggestion, - shorthand: isChannel ? suggestion.slice(1) : '', - type: isChannel ? 'channel' : 'search', - }; - - return suggestionObj; - }); - - suggestions = suggestions.concat(formattedSuggestions); - dispatch({ - type: ACTIONS.UPDATE_SEARCH_SUGGESTIONS, - data: { suggestions }, - }); - }) - .catch(() => { - // If the fetch fails, do nothing - // Basic search suggestions are already populated at this point - }); -}; diff --git a/src/renderer/redux/actions/settings.js b/src/renderer/redux/actions/settings.js index e0fe6b1c5..08a4626ae 100644 --- a/src/renderer/redux/actions/settings.js +++ b/src/renderer/redux/actions/settings.js @@ -1,8 +1,6 @@ -import * as ACTIONS from 'constants/action_types'; -import * as SETTINGS from 'constants/settings'; import Fs from 'fs'; import Http from 'http'; -import Lbry from 'lbry'; +import { Lbry, ACTIONS, SETTINGS } from 'lbry-redux'; import moment from 'moment'; import analytics from 'analytics'; diff --git a/src/renderer/redux/actions/subscriptions.js b/src/renderer/redux/actions/subscriptions.js index 53160ef8c..6f0dba49f 100644 --- a/src/renderer/redux/actions/subscriptions.js +++ b/src/renderer/redux/actions/subscriptions.js @@ -8,10 +8,9 @@ import type { SubscriptionNotifications, } from 'redux/reducers/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions'; -import Lbry from 'lbry'; +import { Lbry, buildURI } from 'lbry-redux'; import { doPurchaseUri } from 'redux/actions/content'; import { doNavigate } from 'redux/actions/navigation'; -import { buildURI } from 'lbryURI'; import analytics from 'analytics'; const CHECK_SUBSCRIPTIONS_INTERVAL = 60 * 60 * 1000; diff --git a/src/renderer/redux/actions/user.js b/src/renderer/redux/actions/user.js index 2c2e1a09e..eb3bdecc4 100644 --- a/src/renderer/redux/actions/user.js +++ b/src/renderer/redux/actions/user.js @@ -1,7 +1,7 @@ import * as ACTIONS from 'constants/action_types'; import * as MODALS from 'constants/modal_types'; import Lbryio from 'lbryio'; -import { doOpenModal, doShowSnackBar } from 'redux/actions/app'; +import { doOpenModal, doShowSnackBar } from 'lbry-redux'; import { doClaimRewardType, doRewardList } from 'redux/actions/rewards'; import { selectEmailToVerify, diff --git a/src/renderer/redux/actions/wallet.js b/src/renderer/redux/actions/wallet.js deleted file mode 100644 index 419107695..000000000 --- a/src/renderer/redux/actions/wallet.js +++ /dev/null @@ -1,190 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; -import * as MODALS from 'constants/modal_types'; -import Lbry from 'lbry'; -import { doOpenModal, doShowSnackBar } from 'redux/actions/app'; -import { doNavigate } from 'redux/actions/navigation'; -import { selectBalance } from 'redux/selectors/wallet'; - -export function doUpdateBalance() { - return (dispatch, getState) => { - const { wallet: { balance: balanceInStore } } = getState(); - Lbry.wallet_balance().then(balance => { - if (balanceInStore !== balance) { - return dispatch({ - type: ACTIONS.UPDATE_BALANCE, - data: { - balance, - }, - }); - } - }); - }; -} - -export function doBalanceSubscribe() { - return dispatch => { - dispatch(doUpdateBalance()); - setInterval(() => dispatch(doUpdateBalance()), 5000); - }; -} - -export function doFetchTransactions() { - return dispatch => { - dispatch({ - type: ACTIONS.FETCH_TRANSACTIONS_STARTED, - }); - - Lbry.transaction_list().then(results => { - dispatch({ - type: ACTIONS.FETCH_TRANSACTIONS_COMPLETED, - data: { - transactions: results, - }, - }); - }); - }; -} - -export function doFetchBlock(height) { - return dispatch => { - Lbry.block_show({ height }).then(block => { - dispatch({ - type: ACTIONS.FETCH_BLOCK_SUCCESS, - data: { block }, - }); - }); - }; -} - -export function doGetNewAddress() { - return dispatch => { - dispatch({ - type: ACTIONS.GET_NEW_ADDRESS_STARTED, - }); - - Lbry.wallet_new_address().then(address => { - localStorage.setItem('wallet_address', address); - dispatch({ - type: ACTIONS.GET_NEW_ADDRESS_COMPLETED, - data: { address }, - }); - }); - }; -} - -export function doCheckAddressIsMine(address) { - return dispatch => { - dispatch({ - type: ACTIONS.CHECK_ADDRESS_IS_MINE_STARTED, - }); - - Lbry.wallet_is_address_mine({ address }).then(isMine => { - if (!isMine) dispatch(doGetNewAddress()); - - dispatch({ - type: ACTIONS.CHECK_ADDRESS_IS_MINE_COMPLETED, - }); - }); - }; -} - -export function doSendDraftTransaction({ amount, address }) { - return (dispatch, getState) => { - const state = getState(); - const balance = selectBalance(state); - - if (balance - amount <= 0) { - dispatch(doOpenModal(MODALS.INSUFFICIENT_CREDITS)); - return; - } - - dispatch({ - type: ACTIONS.SEND_TRANSACTION_STARTED, - }); - - const successCallback = results => { - if (results === true) { - dispatch({ - type: ACTIONS.SEND_TRANSACTION_COMPLETED, - }); - dispatch( - doShowSnackBar({ - message: __(`You sent ${amount} LBC`), - linkText: __('History'), - linkTarget: __('/wallet'), - }) - ); - } else { - dispatch({ - type: ACTIONS.SEND_TRANSACTION_FAILED, - data: { error: results }, - }); - dispatch(doOpenModal(MODALS.TRANSACTION_FAILED)); - } - }; - - const errorCallback = error => { - dispatch({ - type: ACTIONS.SEND_TRANSACTION_FAILED, - data: { error: error.message }, - }); - dispatch(doOpenModal(MODALS.TRANSACTION_FAILED)); - }; - - Lbry.wallet_send({ - amount, - address, - }).then(successCallback, errorCallback); - }; -} - -export function doSendSupport(amount, claimId, uri) { - return (dispatch, getState) => { - const state = getState(); - const balance = selectBalance(state); - - if (balance - amount <= 0) { - dispatch(doOpenModal(MODALS.INSUFFICIENT_CREDITS)); - return; - } - - dispatch({ - type: ACTIONS.SUPPORT_TRANSACTION_STARTED, - }); - - const successCallback = results => { - if (results.txid) { - dispatch({ - type: ACTIONS.SUPPORT_TRANSACTION_COMPLETED, - }); - dispatch( - doShowSnackBar({ - message: __(`You sent ${amount} LBC as a tip, Mahalo!`), - linkText: __('History'), - linkTarget: __('/wallet'), - }) - ); - dispatch(doNavigate('/show', { uri })); - } else { - dispatch({ - type: ACTIONS.SUPPORT_TRANSACTION_FAILED, - data: { error: results.code }, - }); - dispatch(doOpenModal(MODALS.TRANSACTION_FAILED)); - } - }; - - const errorCallback = error => { - dispatch({ - type: ACTIONS.SUPPORT_TRANSACTION_FAILED, - data: { error: error.code }, - }); - dispatch(doOpenModal(MODALS.TRANSACTION_FAILED)); - }; - - Lbry.wallet_send({ - claim_id: claimId, - amount, - }).then(successCallback, errorCallback); - }; -} diff --git a/src/renderer/redux/reducers/app.js b/src/renderer/redux/reducers/app.js index ac8b8f5fb..188fd06e2 100644 --- a/src/renderer/redux/reducers/app.js +++ b/src/renderer/redux/reducers/app.js @@ -89,11 +89,10 @@ reducers[ACTIONS.AUTO_UPDATE_DOWNLOADED] = state => autoUpdateDownloaded: true, }); -reducers[ACTIONS.AUTO_UPDATE_DECLINED] = state => { - return Object.assign({}, state, { +reducers[ACTIONS.AUTO_UPDATE_DECLINED] = state => + Object.assign({}, state, { autoUpdateDeclined: true, }); -}; reducers[ACTIONS.UPGRADE_DOWNLOAD_COMPLETED] = (state, action) => Object.assign({}, state, { @@ -121,17 +120,15 @@ reducers[ACTIONS.SKIP_UPGRADE] = state => { }); }; -reducers[ACTIONS.MEDIA_PLAY] = state => { - return Object.assign({}, state, { +reducers[ACTIONS.MEDIA_PLAY] = state => + Object.assign({}, state, { modalsAllowed: false, }); -}; -reducers[ACTIONS.MEDIA_PAUSE] = state => { - return Object.assign({}, state, { +reducers[ACTIONS.MEDIA_PAUSE] = state => + Object.assign({}, state, { modalsAllowed: true, }); -}; reducers[ACTIONS.SET_PLAYING_URI] = (state, action) => { if (action.data.uri === null) { diff --git a/src/renderer/redux/reducers/claims.js b/src/renderer/redux/reducers/claims.js deleted file mode 100644 index f7c06f293..000000000 --- a/src/renderer/redux/reducers/claims.js +++ /dev/null @@ -1,187 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; - -const reducers = {}; - -const defaultState = {}; - -reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state, action) => { - const { resolveInfo } = action.data; - const byUri = Object.assign({}, state.claimsByUri); - const byId = Object.assign({}, state.byId); - - Object.entries(resolveInfo).forEach(([uri, { certificate, claim }]) => { - if (claim) { - byId[claim.claim_id] = claim; - byUri[uri] = claim.claim_id; - } else if (claim === undefined && certificate !== undefined) { - byId[certificate.claim_id] = certificate; - // Don't point URI at the channel certificate unless it actually is - // a channel URI. This is brittle. - if (!uri.split(certificate.name)[1].match(/\//)) { - byUri[uri] = certificate.claim_id; - } else { - byUri[uri] = null; - } - } else { - byUri[uri] = null; - } - }); - - return Object.assign({}, state, { - byId, - claimsByUri: byUri, - }); -}; - -reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = state => - Object.assign({}, state, { - isFetchingClaimListMine: true, - }); - -reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state, action) => { - const { claims } = action.data; - const byId = Object.assign({}, state.byId); - const pendingById = Object.assign({}, state.pendingById); - - claims - .filter( - claim => claim.category && (claim.category.match(/claim/) || claim.category.match(/update/)) - ) - .forEach(claim => { - byId[claim.claim_id] = claim; - - const pending = Object.values(pendingById).find( - pendingClaim => - pendingClaim.name === claim.name && pendingClaim.channel_name === claim.channel_name - ); - - if (pending) { - delete pendingById[pending.claim_id]; - } - }); - - // Remove old timed out pending publishes - Object.values(pendingById) - .filter(pendingClaim => Date.now() - pendingClaim.time >= 20 * 60 * 1000) - .forEach(pendingClaim => { - delete pendingById[pendingClaim.claim_id]; - }); - - return Object.assign({}, state, { - isFetchingClaimListMine: false, - myClaims: claims, - byId, - pendingById, - }); -}; - -reducers[ACTIONS.FETCH_CHANNEL_LIST_STARTED] = state => - Object.assign({}, state, { fetchingMyChannels: true }); - -reducers[ACTIONS.FETCH_CHANNEL_LIST_COMPLETED] = (state, action) => { - const { claims } = action.data; - const myChannelClaims = new Set(state.myChannelClaims); - const byId = Object.assign({}, state.byId); - - claims.forEach(claim => { - myChannelClaims.add(claim.claim_id); - byId[claims.claim_id] = claim; - }); - - return Object.assign({}, state, { - byId, - fetchingMyChannels: false, - myChannelClaims, - }); -}; - -reducers[ACTIONS.FETCH_CHANNEL_CLAIMS_STARTED] = (state, action) => { - const { uri, page } = action.data; - const fetchingChannelClaims = Object.assign({}, state.fetchingChannelClaims); - - fetchingChannelClaims[uri] = page; - - return Object.assign({}, state, { - fetchingChannelClaims, - }); -}; - -reducers[ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED] = (state, action) => { - const { uri, claims, page } = action.data; - - const claimsByChannel = Object.assign({}, state.claimsByChannel); - const byChannel = Object.assign({}, claimsByChannel[uri]); - const allClaimIds = new Set(byChannel.all); - const currentPageClaimIds = []; - const byId = Object.assign({}, state.byId); - const fetchingChannelClaims = Object.assign({}, state.fetchingChannelClaims); - - if (claims !== undefined) { - claims.forEach(claim => { - allClaimIds.add(claim.claim_id); - currentPageClaimIds.push(claim.claim_id); - byId[claim.claim_id] = claim; - }); - } - - byChannel.all = allClaimIds; - byChannel[page] = currentPageClaimIds; - claimsByChannel[uri] = byChannel; - delete fetchingChannelClaims[uri]; - - return Object.assign({}, state, { - claimsByChannel, - byId, - fetchingChannelClaims, - }); -}; - -reducers[ACTIONS.ABANDON_CLAIM_STARTED] = (state, action) => { - const { claimId } = action.data; - const abandoningById = Object.assign({}, state.abandoningById); - - abandoningById[claimId] = true; - - return Object.assign({}, state, { - abandoningById, - }); -}; - -reducers[ACTIONS.ABANDON_CLAIM_SUCCEEDED] = (state, action) => { - const { claimId } = action.data; - const byId = Object.assign({}, state.byId); - const claimsByUri = Object.assign({}, state.claimsByUri); - - Object.keys(claimsByUri).forEach(uri => { - if (claimsByUri[uri] === claimId) { - delete claimsByUri[uri]; - } - }); - - delete byId[claimId]; - - return Object.assign({}, state, { - byId, - claimsByUri, - }); -}; - -reducers[ACTIONS.CREATE_CHANNEL_COMPLETED] = (state, action) => { - const { channelClaim } = action.data; - const byId = Object.assign({}, state.byId); - const myChannelClaims = new Set(state.myChannelClaims); - - byId[channelClaim.claim_id] = channelClaim; - myChannelClaims.add(channelClaim.claim_id); - - return Object.assign({}, state, { - byId, - myChannelClaims, - }); -}; - -export default function reducer(state = defaultState, action) { - const handler = reducers[action.type]; - if (handler) return handler(state, action); - return state; -} diff --git a/src/renderer/redux/reducers/cost_info.js b/src/renderer/redux/reducers/cost_info.js deleted file mode 100644 index 4137bb83f..000000000 --- a/src/renderer/redux/reducers/cost_info.js +++ /dev/null @@ -1,34 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; - -const reducers = {}; -const defaultState = {}; - -reducers[ACTIONS.FETCH_COST_INFO_STARTED] = (state, action) => { - const { uri } = action.data; - const newFetching = Object.assign({}, state.fetching); - newFetching[uri] = true; - - return Object.assign({}, state, { - fetching: newFetching, - }); -}; - -reducers[ACTIONS.FETCH_COST_INFO_COMPLETED] = (state, action) => { - const { uri, costInfo } = action.data; - const newByUri = Object.assign({}, state.byUri); - const newFetching = Object.assign({}, state.fetching); - - newByUri[uri] = costInfo; - delete newFetching[uri]; - - return Object.assign({}, state, { - byUri: newByUri, - fetching: newFetching, - }); -}; - -export default function reducer(state = defaultState, action) { - const handler = reducers[action.type]; - if (handler) return handler(state, action); - return state; -} diff --git a/src/renderer/redux/reducers/file_info.js b/src/renderer/redux/reducers/file_info.js deleted file mode 100644 index 0d9ed2431..000000000 --- a/src/renderer/redux/reducers/file_info.js +++ /dev/null @@ -1,156 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; - -const reducers = {}; -const defaultState = {}; - -reducers[ACTIONS.FILE_LIST_STARTED] = state => - Object.assign({}, state, { - isFetchingFileList: true, - }); - -reducers[ACTIONS.FILE_LIST_SUCCEEDED] = (state, action) => { - const { fileInfos } = action.data; - const newByOutpoint = Object.assign({}, state.byOutpoint); - const pendingByOutpoint = Object.assign({}, state.pendingByOutpoint); - - fileInfos.forEach(fileInfo => { - const { outpoint } = fileInfo; - - if (outpoint) newByOutpoint[fileInfo.outpoint] = fileInfo; - }); - - return Object.assign({}, state, { - isFetchingFileList: false, - byOutpoint: newByOutpoint, - pendingByOutpoint, - }); -}; - -reducers[ACTIONS.FETCH_FILE_INFO_STARTED] = (state, action) => { - const { outpoint } = action.data; - const newFetching = Object.assign({}, state.fetching); - - newFetching[outpoint] = true; - - return Object.assign({}, state, { - fetching: newFetching, - }); -}; - -reducers[ACTIONS.FETCH_FILE_INFO_COMPLETED] = (state, action) => { - const { fileInfo, outpoint } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const newFetching = Object.assign({}, state.fetching); - - newByOutpoint[outpoint] = fileInfo; - delete newFetching[outpoint]; - - return Object.assign({}, state, { - byOutpoint: newByOutpoint, - fetching: newFetching, - }); -}; - -reducers[ACTIONS.DOWNLOADING_STARTED] = (state, action) => { - const { uri, outpoint, fileInfo } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const newDownloading = Object.assign({}, state.downloadingByOutpoint); - const newLoading = Object.assign({}, state.urisLoading); - - newDownloading[outpoint] = true; - newByOutpoint[outpoint] = fileInfo; - delete newLoading[uri]; - - return Object.assign({}, state, { - downloadingByOutpoint: newDownloading, - urisLoading: newLoading, - byOutpoint: newByOutpoint, - }); -}; - -reducers[ACTIONS.DOWNLOADING_PROGRESSED] = (state, action) => { - const { outpoint, fileInfo } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const newDownloading = Object.assign({}, state.downloadingByOutpoint); - - newByOutpoint[outpoint] = fileInfo; - newDownloading[outpoint] = true; - - return Object.assign({}, state, { - byOutpoint: newByOutpoint, - downloadingByOutpoint: newDownloading, - }); -}; - -reducers[ACTIONS.DOWNLOADING_COMPLETED] = (state, action) => { - const { outpoint, fileInfo } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const newDownloading = Object.assign({}, state.downloadingByOutpoint); - - newByOutpoint[outpoint] = fileInfo; - delete newDownloading[outpoint]; - - return Object.assign({}, state, { - byOutpoint: newByOutpoint, - downloadingByOutpoint: newDownloading, - }); -}; - -reducers[ACTIONS.FILE_DELETE] = (state, action) => { - const { outpoint } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const downloadingByOutpoint = Object.assign({}, state.downloadingByOutpoint); - - delete newByOutpoint[outpoint]; - delete downloadingByOutpoint[outpoint]; - - return Object.assign({}, state, { - byOutpoint: newByOutpoint, - downloadingByOutpoint, - }); -}; - -reducers[ACTIONS.LOADING_VIDEO_STARTED] = (state, action) => { - const { uri } = action.data; - - const newLoading = Object.assign({}, state.urisLoading); - - newLoading[uri] = true; - - return Object.assign({}, state, { - urisLoading: newLoading, - }); -}; - -reducers[ACTIONS.LOADING_VIDEO_FAILED] = (state, action) => { - const { uri } = action.data; - - const newLoading = Object.assign({}, state.urisLoading); - - delete newLoading[uri]; - - return Object.assign({}, state, { - urisLoading: newLoading, - }); -}; - -reducers[ACTIONS.FETCH_DATE] = (state, action) => { - const { time } = action.data; - if (time) { - return Object.assign({}, state, { - publishedDate: time, - }); - } - return null; -}; - -export default function reducer(state = defaultState, action) { - const handler = reducers[action.type]; - if (handler) return handler(state, action); - return state; -} diff --git a/src/renderer/redux/reducers/publish.js b/src/renderer/redux/reducers/publish.js index 8bc91918b..d314d7443 100644 --- a/src/renderer/redux/reducers/publish.js +++ b/src/renderer/redux/reducers/publish.js @@ -1,6 +1,6 @@ // @flow import { handleActions } from 'util/redux-utils'; -import { buildURI } from 'lbryURI'; +import { buildURI } from 'lbry-redux'; import * as ACTIONS from 'constants/action_types'; import { CHANNEL_ANONYMOUS } from 'constants/claim'; diff --git a/src/renderer/redux/reducers/search.js b/src/renderer/redux/reducers/search.js deleted file mode 100644 index 7a2a92ca1..000000000 --- a/src/renderer/redux/reducers/search.js +++ /dev/null @@ -1,103 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; -import { handleActions } from 'util/redux-utils'; - -type SearchSuccess = { - type: ACTIONS.SEARCH_SUCCESS, - data: { - query: string, - uris: Array, - }, -}; - -type UpdateSearchQuery = { - type: ACTIONS.UPDATE_SEARCH_QUERY, - data: { - query: string, - }, -}; - -type SearchSuggestion = { - value: string, - shorthand: string, - type: string, -}; - -type UpdateSearchSuggestions = { - type: ACTIONS.UPDATE_SEARCH_SUGGESTIONS, - data: { - suggestions: Array, - }, -}; - -type SearchState = { - isActive: boolean, - searchQuery: string, - suggestions: Array, - urisByQuery: {}, -}; - -const defaultState = { - isActive: false, - searchQuery: '', // needs to be an empty string for input focusing - suggestions: [], - urisByQuery: {}, -}; - -export default handleActions( - { - [ACTIONS.SEARCH_START]: (state: SearchState): SearchState => ({ - ...state, - searching: true, - }), - [ACTIONS.SEARCH_SUCCESS]: (state: SearchState, action: SearchSuccess): SearchState => { - const { query, uris } = action.data; - - return { - ...state, - searching: false, - urisByQuery: Object.assign({}, state.urisByQuery, { [query]: uris }), - }; - }, - - [ACTIONS.SEARCH_FAIL]: (state: SearchState): SearchState => ({ - ...state, - searching: false, - }), - - [ACTIONS.UPDATE_SEARCH_QUERY]: ( - state: SearchState, - action: UpdateSearchQuery - ): SearchState => ({ - ...state, - searchQuery: action.data.query, - isActive: true, - }), - - [ACTIONS.UPDATE_SEARCH_SUGGESTIONS]: ( - state: SearchState, - action: UpdateSearchSuggestions - ): SearchState => ({ - ...state, - suggestions: action.data.suggestions, - }), - - // clear the searchQuery on back/forward - // it may be populated by the page title for search/file pages - // if going home, it should be blank - [ACTIONS.HISTORY_NAVIGATE]: (state: SearchState): SearchState => ({ - ...state, - searchQuery: '', - suggestions: [], - isActive: false, - }), - // sets isActive to false so the uri will be populated correctly if the - // user is on a file page. The search query will still be present on any - // other page - [ACTIONS.CLOSE_MODAL]: (state: SearchState): SearchState => ({ - ...state, - isActive: false, - }), - }, - defaultState -); diff --git a/src/renderer/redux/reducers/wallet.js b/src/renderer/redux/reducers/wallet.js deleted file mode 100644 index 590404ce8..000000000 --- a/src/renderer/redux/reducers/wallet.js +++ /dev/null @@ -1,114 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; - -const reducers = {}; -const receiveAddress = localStorage.getItem('receiveAddress'); - -const defaultState = { - balance: undefined, - blocks: {}, - transactions: {}, - fetchingTransactions: false, - receiveAddress, - gettingNewAddress: false, - sendingSupport: false, - sendingTx: false, -}; - -reducers[ACTIONS.FETCH_TRANSACTIONS_STARTED] = state => - Object.assign({}, state, { - fetchingTransactions: true, - }); - -reducers[ACTIONS.FETCH_TRANSACTIONS_COMPLETED] = (state, action) => { - const byId = Object.assign({}, state.transactions); - - const { transactions } = action.data; - - transactions.forEach(transaction => { - byId[transaction.txid] = transaction; - }); - - return Object.assign({}, state, { - transactions: byId, - fetchingTransactions: false, - }); -}; - -reducers[ACTIONS.GET_NEW_ADDRESS_STARTED] = state => - Object.assign({}, state, { - gettingNewAddress: true, - }); - -reducers[ACTIONS.GET_NEW_ADDRESS_COMPLETED] = (state, action) => { - const { address } = action.data; - - localStorage.setItem('receiveAddress', address); - return Object.assign({}, state, { - gettingNewAddress: false, - receiveAddress: address, - }); -}; - -reducers[ACTIONS.UPDATE_BALANCE] = (state, action) => - Object.assign({}, state, { - balance: action.data.balance, - }); - -reducers[ACTIONS.CHECK_ADDRESS_IS_MINE_STARTED] = state => - Object.assign({}, state, { - checkingAddressOwnership: true, - }); - -reducers[ACTIONS.CHECK_ADDRESS_IS_MINE_COMPLETED] = state => - Object.assign({}, state, { - checkingAddressOwnership: false, - }); - -reducers[ACTIONS.SEND_TRANSACTION_STARTED] = state => { - return Object.assign({}, state, { - sendingTx: true, - }); -}; - -reducers[ACTIONS.SEND_TRANSACTION_COMPLETED] = state => - Object.assign({}, state, { - sendingTx: false, - }); - -reducers[ACTIONS.SEND_TRANSACTION_FAILED] = (state, action) => { - return Object.assign({}, state, { - sendingTx: false, - error: action.data.error, - }); -}; - -reducers[ACTIONS.SUPPORT_TRANSACTION_STARTED] = state => - Object.assign({}, state, { - sendingSupport: true, - }); - -reducers[ACTIONS.SUPPORT_TRANSACTION_COMPLETED] = state => - Object.assign({}, state, { - sendingSupport: false, - }); - -reducers[ACTIONS.SUPPORT_TRANSACTION_FAILED] = (state, action) => - Object.assign({}, state, { - error: action.data.error, - sendingSupport: false, - }); - -reducers[ACTIONS.FETCH_BLOCK_SUCCESS] = (state, action) => { - const { block, block: { height } } = action.data; - const blocks = Object.assign({}, state.blocks); - - blocks[height] = block; - - return Object.assign({}, state, { blocks }); -}; - -export default function reducer(state = defaultState, action) { - const handler = reducers[action.type]; - if (handler) return handler(state, action); - return state; -} diff --git a/src/renderer/redux/selectors/claims.js b/src/renderer/redux/selectors/claims.js deleted file mode 100644 index bb3c7ae04..000000000 --- a/src/renderer/redux/selectors/claims.js +++ /dev/null @@ -1,179 +0,0 @@ -import { normalizeURI } from 'lbryURI'; -import { makeSelectCurrentParam } from 'redux/selectors/navigation'; -import { createSelector } from 'reselect'; - -const selectState = state => state.claims || {}; - -export const selectClaimsById = createSelector(selectState, state => state.byId || {}); - -export const selectClaimById = id => - createSelector(selectClaimsById, claims => { - const claimById = claims[id]; - return claimById; - }); - -export const selectClaimsByUri = createSelector(selectState, selectClaimsById, (state, byId) => { - const byUri = state.claimsByUri || {}; - const claims = {}; - - Object.keys(byUri).forEach(uri => { - const claimId = byUri[uri]; - - // NOTE returning a null claim allows us to differentiate between an - // undefined (never fetched claim) and one which just doesn't exist. Not - // the cleanest solution but couldn't think of anything better right now - if (claimId === null) { - claims[uri] = null; - } else { - claims[uri] = byId[claimId]; - } - }); - - return claims; -}); - -export const selectAllClaimsByChannel = createSelector( - selectState, - state => state.claimsByChannel || {} -); - -export const makeSelectClaimForUri = uri => - createSelector(selectClaimsByUri, claims => claims && claims[normalizeURI(uri)]); - -export const selectMyClaimsRaw = createSelector(selectState, state => state.myClaims); - -export const selectAbandoningIds = createSelector(selectState, state => - Object.keys(state.abandoningById || {}) -); - -export const selectMyActiveClaims = createSelector( - selectMyClaimsRaw, - selectAbandoningIds, - (claims, abandoningIds) => - new Set( - claims && - claims - .map(claim => claim.claim_id) - .filter(claimId => Object.keys(abandoningIds).indexOf(claimId) === -1) - ) -); - -export const makeSelectClaimIsMine = rawUri => { - const uri = normalizeURI(rawUri); - return createSelector( - selectClaimsByUri, - selectMyActiveClaims, - (claims, myClaims) => - claims && claims[uri] && claims[uri].claim_id && myClaims.has(claims[uri].claim_id) - ); -}; - -export const selectAllFetchingChannelClaims = createSelector( - selectState, - state => state.fetchingChannelClaims || {} -); - -export const makeSelectFetchingChannelClaims = uri => - createSelector(selectAllFetchingChannelClaims, fetching => fetching && fetching[uri]); - -export const makeSelectClaimsInChannelForCurrentPage = uri => { - const pageSelector = makeSelectCurrentParam('page'); - - return createSelector( - selectClaimsById, - selectAllClaimsByChannel, - pageSelector, - (byId, allClaims, page) => { - const byChannel = allClaims[uri] || {}; - const claimIds = byChannel[page || 1]; - - if (!claimIds) return claimIds; - - return claimIds.map(claimId => byId[claimId]); - } - ); -}; - -export const makeSelectMetadataForUri = uri => - createSelector(makeSelectClaimForUri(uri), claim => { - const metadata = claim && claim.value && claim.value.stream && claim.value.stream.metadata; - - return metadata || (claim === undefined ? undefined : null); - }); - -export const makeSelectTitleForUri = uri => - createSelector(makeSelectMetadataForUri(uri), metadata => metadata && metadata.title); - -export const makeSelectContentTypeForUri = uri => - createSelector(makeSelectClaimForUri(uri), claim => { - const source = claim && claim.value && claim.value.stream && claim.value.stream.source; - return source ? source.contentType : undefined; - }); - -export const selectIsFetchingClaimListMine = createSelector( - selectState, - state => state.isFetchingClaimListMine -); - -export const selectPendingClaims = createSelector(selectState, state => - Object.values(state.pendingById || {}) -); - -export const selectMyClaims = createSelector( - selectMyActiveClaims, - selectClaimsById, - selectAbandoningIds, - selectPendingClaims, - (myClaimIds, byId, abandoningIds, pendingClaims) => { - const claims = []; - - myClaimIds.forEach(id => { - const claim = byId[id]; - - if (claim && abandoningIds.indexOf(id) === -1) claims.push(claim); - }); - - return [...claims, ...pendingClaims]; - } -); - -export const selectMyClaimsWithoutChannels = createSelector(selectMyClaims, myClaims => - myClaims.filter(claim => !claim.name.match(/^@/)) -); - -export const selectAllMyClaimsByOutpoint = createSelector( - selectMyClaimsRaw, - claims => - new Set(claims && claims.length ? claims.map(claim => `${claim.txid}:${claim.nout}`) : null) -); - -export const selectMyClaimsOutpoints = createSelector(selectMyClaims, myClaims => { - const outpoints = []; - - myClaims.forEach(claim => outpoints.push(`${claim.txid}:${claim.nout}`)); - - return outpoints; -}); - -export const selectFetchingMyChannels = createSelector( - selectState, - state => state.fetchingMyChannels -); - -export const selectMyChannelClaims = createSelector( - selectState, - selectClaimsById, - (state, byId) => { - const ids = state.myChannelClaims || []; - const claims = []; - - ids.forEach(id => { - if (byId[id]) { - // I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-app/issues/544 - claims.push(byId[id]); - } - }); - - return claims; - } -); diff --git a/src/renderer/redux/selectors/content.js b/src/renderer/redux/selectors/content.js index 371c59764..346f044c1 100644 --- a/src/renderer/redux/selectors/content.js +++ b/src/renderer/redux/selectors/content.js @@ -9,16 +9,8 @@ export const selectFetchingFeaturedUris = createSelector( state => state.fetchingFeaturedContent ); -export const selectResolvingUris = createSelector(selectState, state => state.resolvingUris || []); - export const selectPlayingUri = createSelector(selectState, state => state.playingUri); -export const makeSelectIsUriResolving = uri => - createSelector( - selectResolvingUris, - resolvingUris => resolvingUris && resolvingUris.indexOf(uri) !== -1 - ); - export const selectChannelClaimCounts = createSelector( selectState, state => state.channelClaimCounts || {} diff --git a/src/renderer/redux/selectors/cost_info.js b/src/renderer/redux/selectors/cost_info.js deleted file mode 100644 index 04d5b09e5..000000000 --- a/src/renderer/redux/selectors/cost_info.js +++ /dev/null @@ -1,20 +0,0 @@ -import { createSelector } from 'reselect'; -import { selectCurrentParams } from 'redux/selectors/navigation'; - -export const selectState = state => state.costInfo || {}; - -export const selectAllCostInfoByUri = createSelector(selectState, state => state.byUri || {}); - -export const makeSelectCostInfoForUri = uri => - createSelector(selectAllCostInfoByUri, costInfos => costInfos && costInfos[uri]); - -export const selectCostForCurrentPageUri = createSelector( - selectAllCostInfoByUri, - selectCurrentParams, - (costInfo, params) => (params.uri && costInfo[params.uri] ? costInfo[params.uri].cost : undefined) -); - -export const selectFetchingCostInfo = createSelector(selectState, state => state.fetching || {}); - -export const makeSelectFetchingCostInfoForUri = uri => - createSelector(selectFetchingCostInfo, fetchingByUri => fetchingByUri && fetchingByUri[uri]); diff --git a/src/renderer/redux/selectors/media.js b/src/renderer/redux/selectors/media.js index 804b1190b..40a6725e1 100644 --- a/src/renderer/redux/selectors/media.js +++ b/src/renderer/redux/selectors/media.js @@ -1,13 +1,12 @@ -import * as settings from 'constants/settings'; import { createSelector } from 'reselect'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { makeSelectClaimForUri } from 'lbry-redux'; -const _selectState = state => state.media || {}; +const selectState = state => state.media || {}; -export const selectMediaPaused = createSelector(_selectState, state => state.paused); +export const selectMediaPaused = createSelector(selectState, state => state.paused); export const makeSelectMediaPositionForUri = uri => - createSelector(_selectState, makeSelectClaimForUri(uri), (state, claim) => { + createSelector(selectState, makeSelectClaimForUri(uri), (state, claim) => { const outpoint = `${claim.txid}:${claim.nout}`; return state.positions[outpoint] || null; }); diff --git a/src/renderer/redux/selectors/navigation.js b/src/renderer/redux/selectors/navigation.js deleted file mode 100644 index f4acc3034..000000000 --- a/src/renderer/redux/selectors/navigation.js +++ /dev/null @@ -1,202 +0,0 @@ -import { createSelector } from 'reselect'; -import { parseQueryParams } from 'util/query_params'; - -export const selectState = state => state.navigation || {}; - -export const selectCurrentPath = createSelector(selectState, state => state.currentPath); - -export const computePageFromPath = path => path.replace(/^\//, '').split('?')[0]; - -export const selectCurrentPage = createSelector(selectCurrentPath, path => - computePageFromPath(path) -); - -export const selectCurrentParams = createSelector(selectCurrentPath, path => { - if (path === undefined) return {}; - if (!path.match(/\?/)) return {}; - - return parseQueryParams(path.split('?')[1]); -}); - -export const makeSelectCurrentParam = param => - createSelector(selectCurrentParams, params => (params ? params[param] : undefined)); - -export const selectPathAfterAuth = createSelector(selectState, state => state.pathAfterAuth); - -export const selectIsBackDisabled = createSelector(selectState, state => state.index === 0); - -export const selectIsForwardDisabled = createSelector( - selectState, - state => state.index === state.stack.length - 1 -); - -export const selectIsHome = createSelector(selectCurrentPage, page => page === 'discover'); - -export const selectHistoryIndex = createSelector(selectState, state => state.index); - -export const selectHistoryStack = createSelector(selectState, state => state.stack); - -// returns current page attributes (scrollY, path) -export const selectActiveHistoryEntry = createSelector( - selectState, - state => state.stack[state.index] -); - -export const selectPageTitle = createSelector(selectCurrentPage, page => { - switch (page) { - default: - return ''; - } -}); - -export const selectNavLinks = createSelector( - selectCurrentPage, - selectHistoryStack, - (currentPage, historyStack) => { - const isWalletPage = page => - page === 'wallet' || - page === 'send' || - page === 'getcredits' || - page === 'rewards' || - page === 'history' || - page === 'invite'; - - const isMyLbryPage = page => - page === 'downloaded' || page === 'published' || page === 'settings'; - - const previousStack = historyStack.slice().reverse(); - - const getPreviousSubLinkPath = checkIfValidPage => { - for (let i = 0; i < previousStack.length; i += 1) { - const currentStackItem = previousStack[i]; - - // Trim off the "/" from the path - const pageInStack = currentStackItem.path.slice(1); - if (checkIfValidPage(pageInStack)) { - return currentStackItem.path; - } - } - - return undefined; - }; - - // Gets the last active sublink in a section - const getActiveSublink = category => { - if (category === 'wallet') { - const previousPath = getPreviousSubLinkPath(isWalletPage); - return previousPath || '/wallet'; - } else if (category === 'myLbry') { - const previousPath = getPreviousSubLinkPath(isMyLbryPage); - return previousPath || '/downloaded'; - } - - return undefined; - }; - - const isCurrentlyWalletPage = isWalletPage(currentPage); - const isCurrentlyMyLbryPage = isMyLbryPage(currentPage); - - const walletSubLinks = [ - { - label: 'Overview', - path: '/wallet', - active: currentPage === 'wallet', - }, - { - label: 'Send & Recieve', - path: '/send', - active: currentPage === 'send', - }, - { - label: 'Get Credits', - path: '/getcredits', - active: currentPage === 'getcredits', - }, - { - label: 'Rewards', - path: '/rewards', - active: currentPage === 'rewards', - }, - { - label: 'Invites', - path: '/invite', - active: currentPage === 'invite', - }, - { - label: 'Transactions', - path: '/history', - active: currentPage === 'history', - }, - ]; - - const myLbrySubLinks = [ - { - label: 'Downloads', - path: '/downloaded', - active: currentPage === 'downloaded', - }, - { - label: 'Publishes', - path: '/published', - active: currentPage === 'published', - }, - { - label: 'Settings', - path: '/settings', - active: currentPage === 'settings', - }, - { - label: 'Backup', - path: '/backup', - active: currentPage === 'backup', - }, - ]; - - const navLinks = { - primary: [ - { - label: 'Explore', - path: '/discover', - active: currentPage === 'discover', - icon: 'Compass', - }, - { - label: 'Subscriptions', - path: '/subscriptions', - active: currentPage === 'subscriptions', - icon: 'AtSign', - }, - ], - secondary: [ - { - label: 'Wallet', - icon: 'CreditCard', - subLinks: walletSubLinks, - path: isCurrentlyWalletPage ? '/wallet' : getActiveSublink('wallet'), - active: isWalletPage(currentPage), - }, - { - label: 'My LBRY', - icon: 'Settings', - subLinks: myLbrySubLinks, - path: isCurrentlyMyLbryPage ? '/downloaded' : getActiveSublink('myLbry'), - active: isMyLbryPage(currentPage), - }, - { - label: 'Publish', - icon: 'UploadCloud', - path: '/publish', - active: currentPage === 'publish', - }, - { - label: 'Help', - path: '/help', - active: currentPage === 'help', - icon: 'HelpCircle', - }, - ], - }; - - return navLinks; - } -); diff --git a/src/renderer/redux/selectors/publish.js b/src/renderer/redux/selectors/publish.js index f292ea51e..e0d1468ab 100644 --- a/src/renderer/redux/selectors/publish.js +++ b/src/renderer/redux/selectors/publish.js @@ -1,5 +1,5 @@ import { createSelector } from 'reselect'; -import { parseURI } from 'lbryURI'; +import { parseURI } from 'lbry-redux'; const selectState = state => state.publish || {}; diff --git a/src/renderer/redux/selectors/search.js b/src/renderer/redux/selectors/search.js deleted file mode 100644 index c7e983ced..000000000 --- a/src/renderer/redux/selectors/search.js +++ /dev/null @@ -1,39 +0,0 @@ -import { selectCurrentPage, selectCurrentParams } from 'redux/selectors/navigation'; -import { createSelector } from 'reselect'; - -export const selectState = state => state.search || {}; - -export const selectSearchValue = createSelector(selectState, state => { - return state.searchQuery; -}); - -export const selectSearchQuery = createSelector( - selectCurrentPage, - selectCurrentParams, - (page, params) => (page === 'search' ? params && params.query : null) -); - -export const selectIsSearching = createSelector(selectState, state => state.searching); - -export const selectSearchUrisByQuery = createSelector(selectState, state => state.urisByQuery); - -export const makeSelectSearchUris = query => - // replace statement below is kind of ugly, and repeated in doSearch action - createSelector( - selectSearchUrisByQuery, - byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '') : query] - ); - -export const selectWunderBarAddress = createSelector( - selectCurrentPage, - selectSearchQuery, - selectCurrentParams, - (page, query, params) => { - // only populate the wunderbar address if we are on the file/channel pages - // or show the search query - if (page === 'show') { - return params.uri; - } - return query; - } -); diff --git a/src/renderer/redux/selectors/subscriptions.js b/src/renderer/redux/selectors/subscriptions.js index 30efb5dc4..8f5f9d6ba 100644 --- a/src/renderer/redux/selectors/subscriptions.js +++ b/src/renderer/redux/selectors/subscriptions.js @@ -1,5 +1,5 @@ import { createSelector } from 'reselect'; -import { selectAllClaimsByChannel, selectClaimsById } from './claims'; +import { selectAllClaimsByChannel, selectClaimsById } from 'lbry-redux'; // get the entire subscriptions state const selectState = state => state.subscriptions || {}; diff --git a/src/renderer/redux/selectors/wallet.js b/src/renderer/redux/selectors/wallet.js deleted file mode 100644 index d5fd9326d..000000000 --- a/src/renderer/redux/selectors/wallet.js +++ /dev/null @@ -1,105 +0,0 @@ -import { createSelector } from 'reselect'; - -export const selectState = state => state.wallet || {}; - -export const selectBalance = createSelector(selectState, state => state.balance); - -export const selectTransactionsById = createSelector(selectState, state => state.transactions); - -export const selectTransactionItems = createSelector(selectTransactionsById, byId => { - const items = []; - - Object.keys(byId).forEach(txid => { - const tx = byId[txid]; - - // ignore dust/fees - // it is fee only txn if all infos are also empty - if ( - Math.abs(tx.value) === Math.abs(tx.fee) && - tx.claim_info.length === 0 && - tx.support_info.length === 0 && - tx.update_info.length === 0 - ) { - return; - } - - const append = []; - - append.push( - ...tx.claim_info.map(item => - Object.assign({}, tx, item, { - type: item.claim_name[0] === '@' ? 'channel' : 'publish', - }) - ) - ); - append.push( - ...tx.support_info.map(item => - Object.assign({}, tx, item, { - type: !item.is_tip ? 'support' : 'tip', - }) - ) - ); - append.push(...tx.update_info.map(item => Object.assign({}, tx, item, { type: 'update' }))); - - if (!append.length) { - append.push( - Object.assign({}, tx, { - type: tx.value < 0 ? 'spend' : 'receive', - }) - ); - } - - items.push( - ...append.map(item => { - // value on transaction, amount on outpoint - // amount is always positive, but should match sign of value - const amount = parseFloat(item.balance_delta ? item.balance_delta : item.value); - - return { - txid, - date: tx.timestamp ? new Date(Number(tx.timestamp) * 1000) : null, - amount, - fee: amount < 0 ? -1 * tx.fee / append.length : 0, - claim_id: item.claim_id, - claim_name: item.claim_name, - type: item.type || 'send', - nout: item.nout, - }; - }) - ); - }); - return items.reverse(); -}); - -export const selectRecentTransactions = createSelector(selectTransactionItems, transactions => { - const threshold = new Date(); - threshold.setDate(threshold.getDate() - 7); - return transactions.filter(transaction => transaction.date > threshold); -}); - -export const selectHasTransactions = createSelector( - selectTransactionItems, - transactions => transactions && transactions.length > 0 -); - -export const selectIsFetchingTransactions = createSelector( - selectState, - state => state.fetchingTransactions -); - -export const selectIsSendingSupport = createSelector(selectState, state => state.sendingSupport); - -export const selectReceiveAddress = createSelector(selectState, state => state.receiveAddress); - -export const selectGettingNewAddress = createSelector( - selectState, - state => state.gettingNewAddress -); - -export const selectBlocks = createSelector(selectState, state => state.blocks); - -export const makeSelectBlockDate = block => - createSelector( - selectBlocks, - blocks => (blocks && blocks[block] ? new Date(blocks[block].time * 1000) : undefined) - ); diff --git a/src/renderer/rewards.js b/src/renderer/rewards.js index 8d218c471..f55e26b45 100644 --- a/src/renderer/rewards.js +++ b/src/renderer/rewards.js @@ -1,6 +1,5 @@ -import Lbry from 'lbry'; +import { Lbry, doShowSnackBar } from 'lbry-redux'; import Lbryio from 'lbryio'; -import { doShowSnackBar } from 'redux/actions/app'; function rewardMessage(type, amount) { return { diff --git a/src/renderer/store.js b/src/renderer/store.js index 7e4ef6835..425b3acd4 100644 --- a/src/renderer/store.js +++ b/src/renderer/store.js @@ -1,16 +1,18 @@ import { createLogger } from 'redux-logger'; import appReducer from 'redux/reducers/app'; import availabilityReducer from 'redux/reducers/availability'; -import claimsReducer from 'redux/reducers/claims'; import contentReducer from 'redux/reducers/content'; -import costInfoReducer from 'redux/reducers/cost_info'; -import fileInfoReducer from 'redux/reducers/file_info'; +import { + claimsReducer, + costInfoReducer, + fileInfoReducer, + searchReducer, + walletReducer, +} from 'lbry-redux'; import navigationReducer from 'redux/reducers/navigation'; import rewardsReducer from 'redux/reducers/rewards'; -import searchReducer from 'redux/reducers/search'; import settingsReducer from 'redux/reducers/settings'; import userReducer from 'redux/reducers/user'; -import walletReducer from 'redux/reducers/wallet'; import shapeShiftReducer from 'redux/reducers/shape_shift'; import subscriptionsReducer from 'redux/reducers/subscriptions'; import mediaReducer from 'redux/reducers/media'; @@ -96,12 +98,14 @@ const store = createStore( const compressor = createCompressor(); const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']); const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']); +// We only need to persist the receiveAddress for the wallet +const walletFilter = createFilter('wallet', ['receiveAddress']); const persistOptions = { - whitelist: ['claims', 'subscriptions', 'publish'], + whitelist: ['claims', 'subscriptions', 'publish', 'wallet'], // Order is important. Needs to be compressed last or other transforms can't // read the data - transforms: [saveClaimsFilter, subscriptionsFilter, compressor], + transforms: [saveClaimsFilter, subscriptionsFilter, walletFilter, compressor], debounce: 10000, storage: localForage, }; diff --git a/src/renderer/util/batchActions.js b/src/renderer/util/batchActions.js deleted file mode 100644 index 4bc4eee7f..000000000 --- a/src/renderer/util/batchActions.js +++ /dev/null @@ -1,9 +0,0 @@ -// https://github.com/reactjs/redux/issues/911 -function batchActions(...actions) { - return { - type: 'BATCH_ACTIONS', - actions, - }; -} - -export default batchActions; diff --git a/src/renderer/util/form-validation.js b/src/renderer/util/form-validation.js index 161e628d6..167e6c0b2 100644 --- a/src/renderer/util/form-validation.js +++ b/src/renderer/util/form-validation.js @@ -1,6 +1,6 @@ // @flow /* eslint-disable prefer-default-export */ -import { regexAddress } from 'lbryURI'; +import { regexAddress } from 'lbry-redux'; type DraftTxValues = { address: string, diff --git a/yarn.lock b/yarn.lock index 2119fff2c..18fdbeced 100644 --- a/yarn.lock +++ b/yarn.lock @@ -117,6 +117,13 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" +"@segment/top-domain@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@segment/top-domain/-/top-domain-3.0.0.tgz#02e5a5a4fd42a9f6cf886b05e82f104012a3c3a7" + dependencies: + component-cookie "^1.1.2" + component-url "^0.2.1" + "@types/node@^8.0.24": version "8.10.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.1.tgz#aac98b810c50568054486f2bb8c486d824713be8" @@ -125,6 +132,13 @@ version "1.13.5" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.5.tgz#ca854e9fbdbcdf45d7376882875f28e2c60593f8" +JSONStream@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + abab@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" @@ -222,6 +236,16 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" +amplitude-js@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/amplitude-js/-/amplitude-js-4.1.1.tgz#f9aa4dbbab431df3ec132e07b7e1d5ca773e4068" + dependencies: + "@segment/top-domain" "^3.0.0" + blueimp-md5 "^2.10.0" + json3 "^3.3.2" + lodash "^4.17.4" + ua-parser-js "github:amplitude/ua-parser-js#ed538f1" + ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -1341,6 +1365,10 @@ bluebird@~3.4.1: version "3.4.7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" +blueimp-md5@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.10.0.tgz#02f0843921f90dca14f5b8920a38593201d6964d" + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -2045,7 +2073,7 @@ combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@2.15.x, commander@^2.11.0, commander@^2.14.1, commander@^2.5.0, commander@^2.9.0, commander@~2.15.0: +commander@2.15.x, commander@^2.11.0, commander@^2.12.2, commander@^2.14.1, commander@^2.5.0, commander@^2.9.0, commander@~2.15.0: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" @@ -2098,10 +2126,20 @@ compare-version@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080" +component-cookie@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/component-cookie/-/component-cookie-1.1.3.tgz#053e14a3bd7748154f55724fd39a60c01994ebed" + dependencies: + debug "*" + component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" +component-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/component-url/-/component-url-0.2.1.tgz#4e4f4799c43ead9fd3ce91b5a305d220208fee47" + compressible@~2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9" @@ -2483,15 +2521,15 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" +debug@*, debug@^3.0.0, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" -debug@^3.0.0, debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" +debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" @@ -2940,7 +2978,7 @@ electron-devtools-installer@^2.2.3: rimraf "^2.5.2" semver "^5.3.0" -electron-dl@^1.11.0: +electron-dl@^1.11.0, electron-dl@^1.6.0: version "1.11.0" resolved "https://registry.yarnpkg.com/electron-dl/-/electron-dl-1.11.0.tgz#112851f3857bb1a556b5c736af06040bd40df850" dependencies: @@ -3235,10 +3273,16 @@ es6-map@^0.1.3: es6-symbol "~3.1.1" event-emitter "~0.3.5" -es6-promise@^4.0.5: +es6-promise@^4.0.3, es6-promise@^4.0.5: version "4.2.4" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + dependencies: + es6-promise "^4.0.3" + es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" @@ -3731,6 +3775,10 @@ extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" @@ -4039,7 +4087,7 @@ fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" -from2@^2.1.0: +from2@^2.1.0, from2@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" dependencies: @@ -4791,6 +4839,10 @@ inquirer@^3.0.6: strip-ansi "^4.0.0" through "^2.3.6" +install@^0.10.2: + version "0.10.4" + resolved "https://registry.yarnpkg.com/install/-/install-0.10.4.tgz#9cb09115768b93a582d1450a6ba3f275975b49aa" + internal-ip@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" @@ -5201,6 +5253,17 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" +jayson@^2.0.2: + version "2.0.5" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-2.0.5.tgz#46df3f0bceb0b5b708bf7c8806c34c81938d3f21" + dependencies: + JSONStream "^1.3.1" + commander "^2.12.2" + es6-promisify "^5.0.0" + eyes "^0.1.8" + json-stringify-safe "^5.0.1" + lodash "^4.17.4" + jest-config@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.4.3.tgz#0e9d57db267839ea31309119b41dc2fa31b76403" @@ -5404,6 +5467,10 @@ jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" +jshashes@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/jshashes/-/jshashes-1.0.7.tgz#bed8c97a0e9632fd0513916f55f76dd5486be59f" + json-loader@^0.5.4: version "0.5.7" resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" @@ -5458,6 +5525,10 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" @@ -5538,6 +5609,33 @@ lazy-val@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc" +lbry-redux@lbryio/lbry-redux: + version "0.0.1" + resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/800083dc244191e5f2385ba8df11b85ca5fec8eb" + dependencies: + amplitude-js "^4.0.0" + bluebird "^3.5.1" + classnames "^2.2.5" + electron-dl "^1.6.0" + from2 "^2.3.0" + install "^0.10.2" + jayson "^2.0.2" + jshashes "^1.0.7" + proxy-polyfill "0.1.6" + rc-progress "^2.0.6" + react "^16.2.0" + react-redux "^5.0.3" + redux "^3.6.0" + redux-action-buffer "^1.1.0" + redux-logger "^3.0.1" + redux-persist "^4.8.0" + redux-persist-transform-compress "^4.2.0" + redux-persist-transform-filter "0.0.10" + reselect "^3.0.0" + semver "^5.3.0" + tree-kill "^1.1.0" + y18n "^4.0.0" + lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" @@ -5817,8 +5915,8 @@ lower-case@^1.1.1: resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" lowercase-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" lru-cache@^4.0.1, lru-cache@^4.1.1: version "4.1.2" @@ -7200,6 +7298,10 @@ proxy-addr@~2.0.3: forwarded "~0.1.2" ipaddr.js "1.6.0" +proxy-polyfill@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/proxy-polyfill/-/proxy-polyfill-0.1.6.tgz#ef41ec6c66f534db15db36c54493a62d184b364e" + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -7408,7 +7510,7 @@ react-redux@^5.0.3: loose-envify "^1.1.0" prop-types "^15.6.0" -react-simplemde-editor@^3.6.11: +react-simplemde-editor@3.6.11: version "3.6.11" resolved "https://registry.yarnpkg.com/react-simplemde-editor/-/react-simplemde-editor-3.6.11.tgz#4b9e136f6d4d00218e8ece3d87949e23b14e21dc" dependencies: @@ -7432,6 +7534,15 @@ react@^0.14.2: envify "^3.0.0" fbjs "^0.6.1" +react@^16.2.0: + version "16.3.2" + resolved "https://registry.yarnpkg.com/react/-/react-16.3.2.tgz#fdc8420398533a1e58872f59091b272ce2f91ea9" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + react@^16.3.0: version "16.3.0" resolved "https://registry.yarnpkg.com/react/-/react-16.3.0.tgz#fc5a01c68f91e9b38e92cf83f7b795ebdca8ddff" @@ -7566,6 +7677,10 @@ reduce-function-call@^1.0.1: dependencies: balanced-match "^0.4.2" +redux-action-buffer@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redux-action-buffer/-/redux-action-buffer-1.2.0.tgz#2ec0a1d899cc9f6f44ccdeb431ee52ad41dd9755" + redux-logger@^3.0.1: version "3.0.6" resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf" @@ -7579,6 +7694,17 @@ redux-persist-transform-compress@^4.2.0: json-stringify-safe "^5.0.1" lz-string "^1.4.4" +redux-persist-transform-filter@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/redux-persist-transform-filter/-/redux-persist-transform-filter-0.0.10.tgz#9a3b106ce8939d2cbbf5212c747ed177fff14280" + dependencies: + lodash.forin "^4.4.0" + lodash.get "^4.4.2" + lodash.isempty "^4.4.0" + lodash.pickby "^4.6.0" + lodash.set "^4.3.2" + lodash.unset "^4.5.2" + redux-persist-transform-filter@0.0.16: version "0.0.16" resolved "https://registry.yarnpkg.com/redux-persist-transform-filter/-/redux-persist-transform-filter-0.0.16.tgz#0c21dc166774c12fb3f090f7a2f5ea90f7ba0cea" @@ -8740,7 +8866,7 @@ through2@~0.2.3: readable-stream "~1.1.9" xtend "~2.1.1" -through@^2.3.6, through@^2.3.8, through@~2.3.4, through@~2.3.6: +"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8, through@~2.3.4, through@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -8893,6 +9019,10 @@ ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" +"ua-parser-js@github:amplitude/ua-parser-js#ed538f1": + version "0.7.10" + resolved "https://codeload.github.com/amplitude/ua-parser-js/tar.gz/ed538f16f5c6ecd8357da989b617d4f156dcf35d" + uglify-es@^3.3.4: version "3.3.9" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"