much progress towards a working merge

This commit is contained in:
Jeremy Kauffman 2017-05-03 23:44:08 -04:00
parent d94ef70f60
commit 36a992343f
42 changed files with 713 additions and 932 deletions

View file

@ -12,7 +12,6 @@ Web UI version numbers should always match the corresponding version of LBRY App
* The app is much more responsive switching pages. It no longer reloads the entire page and all assets on each page change.
* lbry.js now offers a subscription model for wallet balance similar to file info.
* Fixed file info subscribes not being unsubscribed in unmount.
* Fixed drawer not highlighting selected page.
* You can now make API calls directly on the lbry module, e.g. lbry.peer_list()
* New-style API calls return promises instead of using callbacks
* Wherever possible, use outpoints for unique IDs instead of names or SD hashes

View file

@ -32,18 +32,6 @@ export function doNavigate(path) {
export function doLogoClick() {
}
export function doOpenDrawer() {
return {
type: types.OPEN_DRAWER
}
}
export function doCloseDrawer() {
return {
type: types.CLOSE_DRAWER
}
}
export function doOpenModal(modal) {
return {
type: types.OPEN_MODAL,
@ -59,6 +47,12 @@ export function doCloseModal() {
}
}
export function doHistoryBack() {
return {
type: types.HISTORY_BACK
}
}
export function doUpdateDownloadProgress(percent) {
return {
type: types.UPGRADE_DOWNLOAD_PROGRESSED,
@ -153,12 +147,8 @@ export function doCheckUpgradeAvailable() {
return function(dispatch, getState) {
const state = getState()
lbry.checkNewVersionAvailable(({isAvailable}) => {
if (!isAvailable) {
return;
}
lbry.getVersionInfo((versionInfo) => {
lbry.getVersionInfo().then(({remoteVersion, upgradeAvailable}) => {
if (upgradeAvailable) {
dispatch({
type: types.UPDATE_VERSION,
data: {
@ -171,7 +161,7 @@ export function doCheckUpgradeAvailable() {
modal: 'upgrade'
}
})
});
}
});
}
}

View file

@ -121,7 +121,7 @@ export function doFetchPublishedContent() {
}
}
export function doFetchFeaturedContent() {
export function doFetchFeaturedUris() {
return function(dispatch, getState) {
const state = getState()
@ -130,11 +130,20 @@ export function doFetchFeaturedContent() {
})
const success = ({ Categories, Uris }) => {
let featuredUris = {}
Categories.forEach((category) => {
if (Uris[category] && Uris[category].length) {
featuredUris[category] = Uris[category]
}
})
dispatch({
type: types.FETCH_FEATURED_CONTENT_COMPLETED,
data: {
categories: Categories,
uris: Uris,
uris: featuredUris,
}
})
@ -146,6 +155,13 @@ export function doFetchFeaturedContent() {
}
const failure = () => {
dispatch({
type: types.FETCH_FEATURED_CONTENT_COMPLETED,
data: {
categories: [],
uris: {}
}
})
}
lbryio.call('discover', 'list', { version: "early-access" } )

View file

@ -41,6 +41,7 @@ export function doGetNewAddress() {
type: types.GET_NEW_ADDRESS_STARTED
})
console.log('do get new address');
lbry.wallet_new_address().then(function(address) {
localStorage.setItem('wallet_address', address);
dispatch({

View file

@ -14,322 +14,4 @@ const app = {
}
}
global.app = app;
module.exports = app;
//
// import React from 'react';
// import {Line} from 'rc-progress';
//
// import lbry from './lbry.js';
// import SettingsPage from './page/settings.js';
// import HelpPage from './page/help.js';
// import WatchPage from './page/watch.js';
// import ReportPage from './page/report.js';
// import StartPage from './page/start.js';
// import RewardsPage from './page/rewards.js';
// import RewardPage from './page/reward.js';
// import WalletPage from './page/wallet.js';
// import ShowPage from './page/show.js';
// import PublishPage from './page/publish.js';
// import SearchPage from './page/search.js';
// import DiscoverPage from './page/discover.js';
// import DeveloperPage from './page/developer.js';
// import lbryuri from './lbryuri.js';
// import {FileListDownloaded, FileListPublished} from './page/file-list.js';
// import Header from './component/header.js';
// import {Modal, ExpandableModal} from './component/modal.js';
// import {Link} from './component/link';
//
//
// const {remote, ipcRenderer, shell} = require('electron');
// const {download} = remote.require('electron-dl');
// const path = require('path');
// const app = require('electron').remote.app;
// const fs = remote.require('fs');
//
//
// var App = React.createClass({
// _error_key_labels: {
// connectionString: 'API connection string',
// method: 'Method',
// params: 'Parameters',
// code: 'Error code',
// message: 'Error message',
// data: 'Error data',
// },
// _fullScreenPages: ['watch'],
// _storeHistoryOfNextRender: false,
//
// _upgradeDownloadItem: null,
// _isMounted: false,
// _version: null,
// getUpdateUrl: function() {
// switch (process.platform) {
// case 'darwin':
// return 'https://lbry.io/get/lbry.dmg';
// case 'linux':
// return 'https://lbry.io/get/lbry.deb';
// case 'win32':
// return 'https://lbry.io/get/lbry.exe';
// default:
// throw 'Unknown platform';
// }
// },
// // Hard code the filenames as a temporary workaround, because
// // electron-dl throws errors when you try to get the filename
// getUpgradeFilename: function() {
// switch (process.platform) {
// case 'darwin':
// return `LBRY-${this._version}.dmg`;
// case 'linux':
// return `LBRY_${this._version}_amd64.deb`;
// case 'windows':
// return `LBRY.Setup.${this._version}.exe`;
// default:
// throw 'Unknown platform';
// }
// },
// getViewingPageAndArgs: function(address) {
// // For now, routes are in format ?page or ?page=args
// let [isMatch, viewingPage, pageArgs] = address.match(/\??([^=]*)(?:=(.*))?/);
// return {
// viewingPage: viewingPage,
// pageArgs: pageArgs === undefined ? null : decodeURIComponent(pageArgs)
// };
// },
// getInitialState: function() {
// return Object.assign(this.getViewingPageAndArgs(window.location.search), {
// viewingPage: 'discover',
// appUrl: null,
// errorInfo: null,
// modal: null,
// downloadProgress: null,
// downloadComplete: false,
// });
// },
// componentWillMount: function() {
// window.addEventListener("popstate", this.onHistoryPop);
//
// document.addEventListener('unhandledError', (event) => {
// this.alertError(event.detail);
// });
//
// //open links in external browser and skip full redraw on changing page
// document.addEventListener('click', (event) => {
// var target = event.target;
// while (target && target !== document) {
// if (target.matches('a[href^="http"]')) {
// event.preventDefault();
// shell.openExternal(target.href);
// return;
// }
// if (target.matches('a[href^="?"]')) {
// event.preventDefault();
// if (this._isMounted) {
// let appUrl = target.getAttribute('href');
// this._storeHistoryOfNextRender = true;
// this.setState(Object.assign({}, this.getViewingPageAndArgs(appUrl), { appUrl: appUrl }));
// document.body.scrollTop = 0;
// }
// }
// target = target.parentNode;
// }
// });
//
// if (!sessionStorage.getItem('upgradeSkipped')) {
// lbry.getVersionInfo().then(({remoteVersion, upgradeAvailable}) => {
// if (upgradeAvailable) {
// this._version = remoteVersion;
// this.setState({
// modal: 'upgrade',
// });
// }
// });
// }
// },
// closeModal: function() {
// this.setState({
// modal: null,
// });
// },
// componentDidMount: function() {
// this._isMounted = true;
// },
// componentWillUnmount: function() {
// this._isMounted = false;
// window.removeEventListener("popstate", this.onHistoryPop);
// },
// onHistoryPop: function() {
// this.setState(this.getViewingPageAndArgs(location.search));
// },
// onSearch: function(term) {
// this._storeHistoryOfNextRender = true;
// const isShow = term.startsWith('lbry://');
// this.setState({
// viewingPage: isShow ? "show" : "search",
// appUrl: (isShow ? "?show=" : "?search=") + encodeURIComponent(term),
// pageArgs: term
// });
// },
// onSubmit: function(uri) {
// this._storeHistoryOfNextRender = true;
// this.setState({
// address: uri,
// appUrl: "?show=" + encodeURIComponent(uri),
// viewingPage: "show",
// pageArgs: uri
// })
// },
// handleUpgradeClicked: function() {
// // Make a new directory within temp directory so the filename is guaranteed to be available
// const dir = fs.mkdtempSync(app.getPath('temp') + require('path').sep);
//
// let options = {
// onProgress: (p) => this.setState({downloadProgress: Math.round(p * 100)}),
// directory: dir,
// };
// download(remote.getCurrentWindow(), this.getUpdateUrl(), options)
// .then(downloadItem => {
// /**
// * TODO: get the download path directly from the download object. It should just be
// * downloadItem.getSavePath(), but the copy on the main process is being garbage collected
// * too soon.
// */
//
// this._upgradeDownloadItem = downloadItem;
// this._upgradeDownloadPath = path.join(dir, this.getUpgradeFilename());
// this.setState({
// downloadComplete: true
// });
// });
// this.setState({modal: 'downloading'});
// },
// handleStartUpgradeClicked: function() {
// ipcRenderer.send('upgrade', this._upgradeDownloadPath);
// },
// cancelUpgrade: function() {
// if (this._upgradeDownloadItem) {
// /*
// * Right now the remote reference to the download item gets garbage collected as soon as the
// * the download is over (maybe even earlier), so trying to cancel a finished download may
// * throw an error.
// */
// try {
// this._upgradeDownloadItem.cancel();
// } catch (err) {
// // Do nothing
// }
// }
// this.setState({
// downloadProgress: null,
// downloadComplete: false,
// modal: null,
// });
// },
// handleSkipClicked: function() {
// sessionStorage.setItem('upgradeSkipped', true);
// this.setState({
// modal: null,
// });
// },
// alertError: function(error) {
// var errorInfoList = [];
// for (let key of Object.keys(error)) {
// let val = typeof error[key] == 'string' ? error[key] : JSON.stringify(error[key]);
// let label = this._error_key_labels[key];
// errorInfoList.push(<li key={key}><strong>{label}</strong>: <code>{val}</code></li>);
// }
//
// this.setState({
// modal: 'error',
// errorInfo: <ul className="error-modal__error-list">{errorInfoList}</ul>,
// });
// },
// getContentAndAddress: function()
// {
// switch(this.state.viewingPage)
// {
// case 'search':
// return [this.state.pageArgs ? this.state.pageArgs : "Search", 'icon-search', <SearchPage query={this.state.pageArgs} />];
// case 'settings':
// return ["Settings", "icon-gear", <SettingsPage />];
// case 'help':
// return ["Help", "icon-question", <HelpPage />];
// case 'report':
// return ['Report an Issue', 'icon-file', <ReportPage />];
// case 'downloaded':
// return ["Downloads & Purchases", "icon-folder", <FileListDownloaded />];
// case 'published':
// return ["Publishes", "icon-folder", <FileListPublished />];
// case 'start':
// return ["Start", "icon-file", <StartPage />];
// case 'rewards':
// return ["Rewards", "icon-bank", <RewardsPage />];
// case 'wallet':
// case 'send':
// case 'receive':
// return [this.state.viewingPage.charAt(0).toUpperCase() + this.state.viewingPage.slice(1), "icon-bank", <WalletPage viewingPage={this.state.viewingPage} />]
// case 'show':
// return [lbryuri.normalize(this.state.pageArgs), "icon-file", <ShowPage uri={this.state.pageArgs} />];
// case 'publish':
// return ["Publish", "icon-upload", <PublishPage />];
// case 'developer':
// return ["Developer", "icon-file", <DeveloperPage />];
// case 'discover':
// default:
// return ["Home", "icon-home", <DiscoverPage />];
// }
// },
// render: function() {
// let [address, wunderBarIcon, mainContent] = this.getContentAndAddress();
//
// lbry.setTitle(address);
//
// if (this._storeHistoryOfNextRender) {
// this._storeHistoryOfNextRender = false;
// history.pushState({}, document.title, this.state.appUrl);
// }
//
// return (
// this._fullScreenPages.includes(this.state.viewingPage) ?
// mainContent :
// <div id="window">
// <Header onSearch={this.onSearch} onSubmit={this.onSubmit} address={address} wunderBarIcon={wunderBarIcon} viewingPage={this.state.viewingPage} />
// <div id="main-content">
// {mainContent}
// </div>
// <Modal isOpen={this.state.modal == 'upgrade'} contentLabel="Update available"
// type="confirm" confirmButtonLabel="Upgrade" abortButtonLabel="Skip"
// onConfirmed={this.handleUpgradeClicked} onAborted={this.handleSkipClicked}>
// Your version of LBRY is out of date and may be unreliable or insecure.
// </Modal>
// <Modal isOpen={this.state.modal == 'downloading'} contentLabel="Downloading Update" type="custom">
// Downloading Update{this.state.downloadProgress ? `: ${this.state.downloadProgress}%` : null}
// <Line percent={this.state.downloadProgress} strokeWidth="4"/>
// {this.state.downloadComplete ? (
// <div>
// <br />
// <p>Click "Begin Upgrade" to start the upgrade process.</p>
// <p>The app will close, and you will be prompted to install the latest version of LBRY.</p>
// <p>After the install is complete, please reopen the app.</p>
// </div>
// ) : null }
// <div className="modal__buttons">
// {this.state.downloadComplete
// ? <Link button="primary" label="Begin Upgrade" className="modal__button" onClick={this.handleStartUpgradeClicked} />
// : null}
// <Link button="alt" label="Cancel" className="modal__button" onClick={this.cancelUpgrade} />
// </div>
// </Modal>
// <ExpandableModal isOpen={this.state.modal == 'error'} contentLabel="Error" className="error-modal"
// overlayClassName="error-modal-overlay" onConfirmed={this.closeModal}
// extraContent={this.state.errorInfo}>
// <h3 className="modal__header">Error</h3>
//
// <div className="error-modal__content">
// <div><img className="error-modal__warning-symbol" src={lbry.imagePath('warning.png')} /></div>
// <p>We're sorry that LBRY has encountered an error. This has been reported and we will investigate the problem.</p>
// </div>
// </ExpandableModal>
// </div>
// );
module.exports = app;

View file

@ -10,8 +10,6 @@ import {
} from 'selectors/app'
import {
doCheckUpgradeAvailable,
doOpenDrawer,
doCloseDrawer,
doOpenModal,
doCloseModal,
doSearch,
@ -21,15 +19,12 @@ import App from './view'
const select = (state) => ({
currentPage: selectCurrentPage(state),
modal: selectCurrentModal(state),
drawerOpen: selectDrawerOpen(state),
headerLinks: selectHeaderLinks(state),
searchTerm: selectSearchTerm(state)
})
const perform = (dispatch) => ({
checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()),
openDrawer: () => dispatch(doOpenDrawer()),
closeDrawer: () => dispatch(doCloseDrawer()),
openModal: () => dispatch(doOpenModal()),
closeModal: () => dispatch(doCloseModal()),
})

View file

@ -1,26 +1,13 @@
import React from 'react'
import lbry from 'lbry.js';
import Router from 'component/router'
import Header from 'component/header';
import {Modal, ExpandableModal} from 'component/modal.js';
import ErrorModal from 'component/errorModal'
import DownloadingModal from 'component/downloadingModal'
import UpgradeModal from 'component/upgradeModal'
import Link from 'component/link';
import {Line} from 'rc-progress';
const App = React.createClass({
// Temporary workaround since electron-dl throws errors when you try to get the filename
getViewingPageAndArgs: function(address) {
// For now, routes are in format ?page or ?page=args
let [isMatch, viewingPage, pageArgs] = address.match(/\??([^=]*)(?:=(.*))?/);
return {
viewingPage: viewingPage,
pageArgs: pageArgs === undefined ? null : pageArgs
};
},
componentWillMount: function() {
class App extends React.Component {
componentWillMount() {
document.addEventListener('unhandledError', (event) => {
this.props.alertError(event.detail);
});
@ -28,24 +15,20 @@ const App = React.createClass({
if (!this.props.upgradeSkipped) {
this.props.checkUpgradeAvailable()
}
},
render: function() {
}
render() {
const {
currentPage,
openDrawer,
closeDrawer,
openModal,
closeModal,
modal,
drawerOpen,
headerLinks,
search,
searchTerm,
} = this.props
const searchQuery = (currentPage == 'discover' && searchTerm ? searchTerm : '')
return <div id="window" className={ drawerOpen ? 'drawer-open' : 'drawer-closed' }>
<Header onOpenDrawer={openDrawer} initialQuery={searchQuery} onSearch={search} links={headerLinks} />
return <div id="window">
<Header initialQuery={searchQuery} onSearch={() => { alert('header search'); }}
onSubmit={() => { alert('header submit'); }} links={headerLinks} />
<div id="main-content">
<Router />
</div>
@ -54,6 +37,6 @@ const App = React.createClass({
{modal == 'error' && <ErrorModal />}
</div>
}
});
}
export default App

View file

@ -2,7 +2,8 @@ import React from "react";
import lbryio from "../lbryio.js";
import Modal from "./modal.js";
import ModalPage from "./modal-page.js";
import {Link, RewardLink} from "../component/link";
import Link from "component/link"
import {RewardLink} from 'component/reward-link';
import {FormRow} from "../component/form.js";
import {CreditAmount, Address} from "../component/common.js";
import {getLocal, getSession, setSession, setLocal} from '../utils.js';

View file

@ -1,33 +0,0 @@
import React from 'react'
import {
connect
} from 'react-redux'
import Drawer from './view'
import {
doNavigate,
doCloseDrawer,
doLogoClick,
} from 'actions/app'
import {
doUpdateBalance,
} from 'actions/wallet'
import {
selectCurrentPage,
} from 'selectors/app'
import {
selectBalance,
} from 'selectors/wallet'
const select = (state) => ({
currentPage: selectCurrentPage(state),
balance: selectBalance(state),
})
const perform = {
linkClick: doNavigate,
logoClick: doLogoClick,
closeDrawerClick: doCloseDrawer,
updateBalance: doUpdateBalance,
}
export default connect(select, perform)(Drawer)

View file

@ -1,68 +0,0 @@
import lbry from 'lbry.js';
import React from 'react';
import Link from 'component/link';
const DrawerItem = (props) => {
const {
currentPage,
href,
subPages,
badge,
label,
linkClick,
icon,
} = props
const isSelected = (
currentPage == href.substr(0) ||
(subPages && subPages.indexOf(currentPage) != -1)
)
return <Link icon={icon} badge={badge} label={label} onClick={() => linkClick(href)} className={ 'drawer-item ' + (isSelected ? 'drawer-item-selected' : '') } />
}
var drawerImageStyle = { //@TODO: remove this, img should be properly scaled once size is settled
height: '36px'
};
class Drawer extends React.Component {
constructor(props) {
super(props)
this._balanceSubscribeId = null
}
componentDidMount() {
const { updateBalance } = this.props
this._balanceSubscribeId = lbry.balanceSubscribe((balance) => {
updateBalance(balance)
});
}
componentWillUnmount() {
if (this._balanceSubscribeId) {
lbry.balanceUnsubscribe(this._balanceSubscribeId)
}
}
render() {
const {
closeDrawerClick,
logoClick,
balance,
} = this.props
return(<nav id="drawer">
<div id="drawer-handle">
<Link title="Close" onClick={closeDrawerClick} icon="icon-bars" className="close-drawer-link"/>
<a href="discover" onMouseUp={logoClick}><img src={lbry.imagePath("lbry-dark-1600x528.png")} style={drawerImageStyle}/></a>
</div>
<DrawerItem {...this.props} href='discover' label="Discover" icon="icon-search" />
<DrawerItem {...this.props} href='publish' label="Publish" icon="icon-upload" />
<DrawerItem {...this.props} href='downloaded' subPages={['published']} label="My Files" icon='icon-cloud-download' />
<DrawerItem {...this.props} href="wallet" subPages={['send', 'receive', 'claim']} label="My Wallet" badge={lbry.formatCredits(balance) } icon="icon-bank" />
<DrawerItem {...this.props} href='settings' label="Settings" icon='icon-gear' />
<DrawerItem {...this.props} href='help' label="Help" icon='icon-question-circle' />
</nav>)
}
}
export default Drawer;

View file

@ -3,31 +3,21 @@ import {
connect
} from 'react-redux'
import {
selectCurrentPage,
selectHeaderLinks,
selectPageTitle,
} from 'selectors/app'
selectBalance
} from 'selectors/wallet'
import {
doNavigate,
doHistoryBack,
} from 'actions/app'
import {
doSearchContent,
doActivateSearch,
doDeactivateSearch,
} from 'actions/search'
import Header from './view'
const select = (state) => ({
currentPage: selectCurrentPage(state),
subLinks: selectHeaderLinks(state),
pageTitle: selectPageTitle(state),
balance: lbry.formatCredits(selectBalance(state), 1)
})
const perform = (dispatch) => ({
navigate: (path) => dispatch(doNavigate(path)),
search: (query) => dispatch(doSearchContent(query)),
activateSearch: () => dispatch(doActivateSearch()),
deactivateSearch: () => setTimeout(() => { dispatch(doDeactivateSearch()) }, 50),
back: () => dispatch(doHistoryBack()),
})
export default connect(select, perform)(Header)

View file

@ -1,193 +1,37 @@
import React from 'react';
import lbryuri from 'lbryuri.js';
import {Icon, CreditAmount} from 'component/common.js';
import Link from 'component/link';
import WunderBar from 'component/wunderbar';
let Header = React.createClass({
_balanceSubscribeId: null,
_isMounted: false,
propTypes: {
onSearch: React.PropTypes.func.isRequired,
onSubmit: React.PropTypes.func.isRequired
},
getInitialState: function() {
return {
balance: 0
};
},
componentDidMount: function() {
this._isMounted = true;
this._balanceSubscribeId = lbry.balanceSubscribe((balance) => {
if (this._isMounted) {
this.setState({balance: balance});
}
});
},
componentWillUnmount: function() {
this._isMounted = false;
if (this._balanceSubscribeId) {
lbry.balanceUnsubscribe(this._balanceSubscribeId)
}
},
render: function() {
return <header id="header">
<div className="header__item">
<Link onClick={() => { lbry.back() }} button="alt button--flat" icon="icon-arrow-left" />
</div>
<div className="header__item">
<Link href="?discover" button="alt button--flat" icon="icon-home" />
</div>
<div className="header__item header__item--wunderbar">
<WunderBar address={this.props.address} icon={this.props.wunderBarIcon}
onSearch={this.props.onSearch} onSubmit={this.props.onSubmit} viewingPage={this.props.viewingPage} />
</div>
<div className="header__item">
<Link href="?wallet" button="text" icon="icon-bank" label={lbry.formatCredits(this.state.balance, 1)} ></Link>
</div>
<div className="header__item">
<Link button="primary button--flat" href="?publish" icon="icon-upload" label="Publish" />
</div>
<div className="header__item">
<Link button="alt button--flat" href="?downloaded" icon="icon-folder" />
</div>
<div className="header__item">
<Link button="alt button--flat" href="?settings" icon="icon-gear" />
</div>
</header>
}
});
class WunderBar extends React.PureComponent {
static propTypes = {
onSearch: React.PropTypes.func.isRequired,
onSubmit: React.PropTypes.func.isRequired
}
constructor(props) {
super(props);
this._userTypingTimer = null;
this._input = null;
this._stateBeforeSearch = null;
this._resetOnNextBlur = true;
this.onChange = this.onChange.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
this.onKeyPress = this.onKeyPress.bind(this);
this.onReceiveRef = this.onReceiveRef.bind(this);
this.state = {
address: this.props.address,
icon: this.props.icon
};
}
componentWillUnmount() {
if (this.userTypingTimer) {
clearTimeout(this._userTypingTimer);
}
}
onChange(event) {
if (this._userTypingTimer)
{
clearTimeout(this._userTypingTimer);
}
this.setState({ address: event.target.value })
let searchTerm = event.target.value;
this._userTypingTimer = setTimeout(() => {
this._resetOnNextBlur = false;
this.props.onSearch(searchTerm);
}, 800); // 800ms delay, tweak for faster/slower
}
export const Header = (props) => {
const {
balance,
back,
navigate
} = props
componentWillReceiveProps(nextProps) {
if (nextProps.viewingPage !== this.props.viewingPage || nextProps.address != this.props.address) {
this.setState({ address: nextProps.address, icon: nextProps.icon });
}
}
onFocus() {
this._stateBeforeSearch = this.state;
let newState = {
icon: "icon-search",
isActive: true
}
this._focusPending = true;
//below is hacking, improved when we have proper routing
if (!this.state.address.startsWith('lbry://') && this.state.icon !== "icon-search") //onFocus, if they are not on an exact URL or a search page, clear the bar
{
newState.address = '';
}
this.setState(newState);
}
onBlur() {
let commonState = {isActive: false};
if (this._resetOnNextBlur) {
this.setState(Object.assign({}, this._stateBeforeSearch, commonState));
this._input.value = this.state.address;
} else {
this._resetOnNextBlur = true;
this._stateBeforeSearch = this.state;
this.setState(commonState);
}
}
componentDidUpdate() {
this._input.value = this.state.address;
if (this._input && this._focusPending) {
this._input.select();
this._focusPending = false;
}
}
onKeyPress(event) {
if (event.charCode == 13 && this._input.value) {
let uri = null,
method = "onSubmit";
this._resetOnNextBlur = false;
clearTimeout(this._userTypingTimer);
try {
uri = lbryuri.normalize(this._input.value);
this.setState({ value: uri });
} catch (error) { //then it's not a valid URL, so let's search
uri = this._input.value;
method = "onSearch";
}
this.props[method](uri);
this._input.blur();
}
}
onReceiveRef(ref) {
this._input = ref;
}
render() {
return (
<div className={'wunderbar' + (this.state.isActive ? ' wunderbar--active' : '')}>
{this.state.icon ? <Icon fixed icon={this.state.icon} /> : '' }
<input className="wunderbar__input" type="search" placeholder="Type a LBRY address or search term"
ref={this.onReceiveRef}
onFocus={this.onFocus}
onBlur={this.onBlur}
onChange={this.onChange}
onKeyPress={this.onKeyPress}
value={this.state.address}
placeholder="Find movies, music, games, and more" />
</div>
);
}
return <header id="header">
<div className="header__item">
<Link onClick={back} button="alt button--flat" icon="icon-arrow-left" />
</div>
<div className="header__item">
<Link onClick={() => navigate('discover')} button="alt button--flat" icon="icon-home" />
</div>
<div className="header__item header__item--wunderbar">
<WunderBar/>
</div>
<div className="header__item">
<Link onClick={() => navigate('wallet')} button="text" icon="icon-bank" label={balance} ></Link>
</div>
<div className="header__item">
<Link onClick={() => navigate('publish')} button="primary button--flat" icon="icon-upload" label="Publish" />
</div>
<div className="header__item">
<Link onClick={() => navigate('downloaded')} button="alt button--flat" icon="icon-folder" />
</div>
<div className="header__item">
<Link onClick={() => navigate('settings')} button="alt button--flat" icon="icon-gear" />
</div>
</header>
}
export default Header;

View file

@ -0,0 +1,21 @@
import React from 'react'
import {
connect,
} from 'react-redux'
import {
selectCurrentPage,
} from 'selectors/app'
import {
doNavigate,
} from 'actions/app'
import NavMain from './view'
const select = (state) => ({
currentPage: selectCurrentPage(state)
})
const perform = (dispatch) => ({
navigate: (path) => dispatch(doNavigate(path))
})
export default connect(select, perform)(NavMain)

View file

@ -0,0 +1,22 @@
import React from 'react';
export const NavMain = (props) => {
const {
links,
currentPage,
navigate,
} = props
return (
<nav className="sub-header">{
Object.keys(links).map((link) => {
console.log(link + " vs " + currentPage);
return <a href="#" onClick={() => navigate(link)} key={link} className={link == currentPage ? 'sub-header-selected' : 'sub-header-unselected' }>
{links[link]}
</a>
})
}</nav>
)
}
export default NavMain

View file

@ -0,0 +1,7 @@
import React from 'react'
import {
connect,
} from 'react-redux'
import NavSettings from './view'
export default connect(null, null)(NavSettings)

View file

@ -0,0 +1,11 @@
import React from 'react';
import NavMain from 'component/navMain'
export const NavSettings = () => {
return <NavMain links={{
'settings': 'Settings',
'help' : 'Help'
}} />;
}
export default NavSettings

View file

@ -0,0 +1,7 @@
import React from 'react'
import {
connect,
} from 'react-redux'
import NavWallet from './view'
export default connect(null, null)(NavWallet)

View file

@ -0,0 +1,13 @@
import React from 'react';
import NavMain from 'component/navMain'
export const NavWallet = () => {
return <NavMain links={{
'wallet': 'Overview',
'send': 'Send',
'receive': 'Receive',
'rewards': 'Rewards'
}} />
}
export default NavWallet

View file

@ -4,13 +4,15 @@ import HelpPage from 'page/help';
import ReportPage from 'page/report.js';
import StartPage from 'page/start.js';
import WalletPage from 'page/wallet';
import ShowPage from 'page/showPage';
import FilePage from 'page/filePage';
import PublishPage from 'page/publish';
import DiscoverPage from 'page/discover';
import SplashScreen from 'component/splash.js';
import DeveloperPage from 'page/developer.js';
import RewardsPage from 'page/rewards.js';
import FileListDownloaded from 'page/fileListDownloaded'
import FileListPublished from 'page/fileListPublished'
import ChannelPage from 'page/channel'
const route = (page, routesMap) => {
const component = routesMap[page]
@ -34,10 +36,12 @@ const Router = (props) => {
'wallet': <WalletPage {...props} />,
'send': <WalletPage {...props} />,
'receive': <WalletPage {...props} />,
'show': <ShowPage {...props} />,
'show': <FilePage {...props} />,
'channel': <ChannelPage {...props} />,
'publish': <PublishPage {...props} />,
'developer': <DeveloperPage {...props} />,
'discover': <DiscoverPage {...props} />,
'rewards': <RewardsPage {...props} />,
})
}

View file

@ -1,22 +0,0 @@
const SubHeader = (props) => {
const {
subLinks,
currentPage,
navigate,
} = props
const links = [],
viewingUrl = '?' + this.props.viewingPage;
for(let link of Object.keys(subLinks)) {
links.push(
<a href="#" onClick={() => navigate(link)} key={link} className={link == currentPage ? 'sub-header-selected' : 'sub-header-unselected' }>
{subLinks[link]}
</a>
);
}
return (
<nav className={"sub-header" + (this.props.modifier ? ' sub-header--' + this.props.modifier : '')}>{links}</nav>
)
}

View file

@ -1,12 +0,0 @@
import {SubHeader} from '../component/sub-header.js';
export let WalletNav = React.createClass({
render: function () {
return <SubHeader modifier="constrained" viewingPage={this.props.viewingPage} links={{
'?wallet': 'Overview',
'?send': 'Send',
'?receive': 'Receive',
'?rewards': 'Rewards'
}} />;
}
});

View file

@ -0,0 +1,32 @@
import React from 'react'
import {
connect
} from 'react-redux'
import {
selectWunderBarAddress,
selectWunderBarIcon
} from 'selectors/app'
import {
doNavigate,
} from 'actions/app'
import {
doSearchContent,
doActivateSearch,
doDeactivateSearch,
} from 'actions/search'
import Wunderbar from './view'
const select = (state) => ({
address: selectWunderBarAddress(state),
icon: selectWunderBarIcon(state)
})
const perform = (dispatch) => ({
// navigate: (path) => dispatch(doNavigate(path)),
onSearch: (query) => dispatch(doSearchContent(query)),
onSubmit: (query) => dispatch(doSearchContent(query)),
// activateSearch: () => dispatch(doActivateSearch()),
// deactivateSearch: () => setTimeout(() => { dispatch(doDeactivateSearch()) }, 50),
})
export default connect(select, perform)(Wunderbar)

View file

@ -0,0 +1,136 @@
import React from 'react';
import lbryuri from 'lbryuri.js';
import {Icon} from 'component/common.js';
class WunderBar extends React.PureComponent {
static propTypes = {
onSearch: React.PropTypes.func.isRequired,
onSubmit: React.PropTypes.func.isRequired
}
constructor(props) {
super(props);
this._userTypingTimer = null;
this._input = null;
this._stateBeforeSearch = null;
this._resetOnNextBlur = true;
this.onChange = this.onChange.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
this.onKeyPress = this.onKeyPress.bind(this);
this.onReceiveRef = this.onReceiveRef.bind(this);
this.state = {
address: this.props.address,
icon: this.props.icon
};
}
componentWillUnmount() {
if (this.userTypingTimer) {
clearTimeout(this._userTypingTimer);
}
}
onChange(event) {
if (this._userTypingTimer)
{
clearTimeout(this._userTypingTimer);
}
this.setState({ address: event.target.value })
let searchTerm = event.target.value;
this._userTypingTimer = setTimeout(() => {
this._resetOnNextBlur = false;
this.props.onSearch(searchTerm);
}, 800); // 800ms delay, tweak for faster/slower
}
componentWillReceiveProps(nextProps) {
if (nextProps.viewingPage !== this.props.viewingPage || nextProps.address != this.props.address) {
this.setState({ address: nextProps.address, icon: nextProps.icon });
}
}
onFocus() {
this._stateBeforeSearch = this.state;
let newState = {
icon: "icon-search",
isActive: true
}
this._focusPending = true;
//below is hacking, improved when we have proper routing
if (!this.state.address.startsWith('lbry://') && this.state.icon !== "icon-search") //onFocus, if they are not on an exact URL or a search page, clear the bar
{
newState.address = '';
}
this.setState(newState);
}
onBlur() {
let commonState = {isActive: false};
if (this._resetOnNextBlur) {
this.setState(Object.assign({}, this._stateBeforeSearch, commonState));
this._input.value = this.state.address;
} else {
this._resetOnNextBlur = true;
this._stateBeforeSearch = this.state;
this.setState(commonState);
}
}
componentDidUpdate() {
this._input.value = this.state.address;
if (this._input && this._focusPending) {
this._input.select();
this._focusPending = false;
}
}
onKeyPress(event) {
if (event.charCode == 13 && this._input.value) {
let uri = null,
method = "onSubmit";
this._resetOnNextBlur = false;
clearTimeout(this._userTypingTimer);
try {
uri = lbryuri.normalize(this._input.value);
this.setState({ value: uri });
} catch (error) { //then it's not a valid URL, so let's search
uri = this._input.value;
method = "onSearch";
}
this.props[method](uri);
this._input.blur();
}
}
onReceiveRef(ref) {
this._input = ref;
}
render() {
return (
<div className={'wunderbar' + (this.state.isActive ? ' wunderbar--active' : '')}>
{this.state.icon ? <Icon fixed icon={this.state.icon} /> : '' }
<input className="wunderbar__input" type="search" placeholder="Type a LBRY address or search term"
ref={this.onReceiveRef}
onFocus={this.onFocus}
onBlur={this.onBlur}
onChange={this.onChange}
onKeyPress={this.onKeyPress}
value={this.state.address}
placeholder="Find movies, music, games, and more" />
</div>
);
}
}
export default WunderBar;

View file

@ -1,9 +1,7 @@
export const NAVIGATE = 'NAVIGATE'
export const OPEN_MODAL = 'OPEN_MODAL'
export const CLOSE_MODAL = 'CLOSE_MODAL'
export const OPEN_DRAWER = 'OPEN_DRAWER'
export const CLOSE_DRAWER = 'CLOSE_DRAWER'
export const HISTORY_BACK = 'HISTORY_BACK'
export const DAEMON_READY = 'DAEMON_READY'

View file

@ -155,10 +155,6 @@ lbry.checkFirstRun = function(callback) {
lbry.call('is_first_run', {}, callback);
}
lbry.getNewAddress = function(callback) {
lbry.call('wallet_new_address', {}, callback);
}
lbry.getUnusedAddress = function(callback) {
lbry.call('wallet_unused_address', {}, callback);
}
@ -174,7 +170,7 @@ lbry.getDaemonSettings = function(callback) {
lbry.setDaemonSettings = function(settings, callback) {
lbry.call('set_settings', settings, callback);
}
lbry.setDaemonSetting = function(setting, value, callback) {
var setSettingsArgs = {};
setSettingsArgs[setting] = value;
@ -640,19 +636,19 @@ lbry.claim_list_mine = function(params={}) {
});
}
const claimCacheKey = 'resolve_claim_cache';
lbry._claimCache = getLocal(claimCacheKey, {});
lbry.resolve = function(params={}) {
const claimCacheKey = 'resolve_claim_cache',
claimCache = getSession(claimCacheKey, {})
return new Promise((resolve, reject) => {
if (!params.uri) {
throw "Resolve has hacked cache on top of it that requires a URI"
}
if (params.uri && claimCache[params.uri] !== undefined) {
resolve(claimCache[params.uri]);
if (params.uri && lbry._claimCache[params.uri] !== undefined) {
resolve(lbry._claimCache[params.uri]);
} else {
lbry.call('resolve', params, function(data) {
claimCache[params.uri] = data;
setSession(claimCacheKey, claimCache)
lbry._claimCache[params.uri] = data;
setLocal(claimCacheKey, lbry._claimCache)
resolve(data)
}, reject)
}
@ -660,20 +656,18 @@ lbry.resolve = function(params={}) {
}
// Adds caching.
lbry._settingsPromise = null;
lbry.settings_get = function(params={}) {
return new Promise((resolve, reject) => {
if (params.allow_cached) {
const cached = getSession('settings');
if (cached) {
return resolve(cached);
}
}
if (params.allow_cached && lbry._settingsPromise) {
return lbry._settingsPromise;
}
lbry._settingsPromise = new Promise((resolve, reject) => {
lbry.call('settings_get', {}, (settings) => {
setSession('settings', settings);
resolve(settings);
});
}, reject);
});
return lbry._settingsPromise;
}
// lbry.get = function(params={}) {

View file

@ -0,0 +1,17 @@
import React from 'react'
import {
connect
} from 'react-redux'
import {
selectCurrentUriTitle,
} from 'selectors/app'
import ChannelPage from './view'
const select = (state) => ({
title: selectCurrentUriTitle(state)
})
const perform = (dispatch) => ({
})
export default connect(select, perform)(ChannelPage)

View file

@ -0,0 +1,22 @@
import React from 'react';
const ChannelPage = (props) => {
const {
title
} = props
return <main className="main--single-column">
<section className="card">
<div className="card__inner">
<div className="card__title-identity"><h1>{title}</h1></div>
</div>
<div className="card__content">
<p>
This channel page is a stub.
</p>
</div>
</section>
</main>
}
export default ChannelPage;

View file

@ -3,7 +3,7 @@ import {
connect
} from 'react-redux'
import {
selectFeaturedContentByCategory
selectFeaturedUris
} from 'selectors/content'
import {
doSearchContent,
@ -17,11 +17,7 @@ import {
import DiscoverPage from './view'
const select = (state) => ({
featuredContentByCategory: selectFeaturedContentByCategory(state),
isSearching: selectIsSearching(state),
query: selectSearchQuery(state),
results: selectCurrentSearchResults(state),
searchActive: selectSearchActivated(state),
featuredUris: selectFeaturedUris(state),
})
const perform = (dispatch) => ({

View file

@ -22,44 +22,65 @@ const FeaturedCategory = (props) => {
</div>
}
let DiscoverPage = React.createClass({
getInitialState: function() {
return {
featuredUris: {},
failed: false
};
},
componentWillMount: function() {
lbryio.call('discover', 'list', { version: "early-access" } ).then(({Categories, Uris}) => {
let featuredUris = {}
Categories.forEach((category) => {
if (Uris[category] && Uris[category].length) {
featuredUris[category] = Uris[category]
}
})
this.setState({ featuredUris: featuredUris });
}, () => {
this.setState({
failed: true
})
});
},
render: function() {
return <main>{
this.state.failed ?
<div className="empty">Failed to load landing content.</div> :
<div>
{
Object.keys(this.state.featuredUris).map((category) => {
return this.state.featuredUris[category].length ?
<FeaturedCategory key={category} category={category} names={this.state.featuredUris[category]} /> :
'';
})
}
</div>
}</main>;
}
})
const DiscoverPage = (props) => {
const {
featuredUris
} = props
return <main>{
Object.keys(featuredUris).length === 0 ?
<div className="empty">Failed to load landing content.</div> :
<div>
{
Object.keys(featuredUris).map((category) => {
return featuredUris[category].length ?
<FeaturedCategory key={category} category={category} names={featuredUris[category]} /> :
'';
})
}
</div>
}</main>
}
//
// let DiscoverPage = React.createClass({
// getInitialState: function() {
// return {
// featuredUris: {},
// failed: false
// };
// },
// componentWillMount: function() {
// lbryio.call('discover', 'list', { version: "early-access" } ).then(({Categories, Uris}) => {
// let featuredUris = {}
// Categories.forEach((category) => {
// if (Uris[category] && Uris[category].length) {
// featuredUris[category] = Uris[category]
// }
// })
// this.setState({ featuredUris: featuredUris });
// }, () => {
// this.setState({
// failed: true
// })
// });
// },
// render: function() {
// return <main>{
// this.state.failed ?
// <div className="empty">Failed to load landing content.</div> :
// <div>
// {
// Object.keys(this.state.featuredUris).map((category) => {
// return this.state.featuredUris[category].length ?
// <FeaturedCategory key={category} category={category} names={this.state.featuredUris[category]} /> :
// '';
// })
// }
// </div>
// }</main>;
// }
// })
// const DiscoverPage = (props) => {
// const {

View file

@ -17,7 +17,7 @@ import {
import {
selectCurrentUriCostInfo,
} from 'selectors/cost_info'
import ShowPage from './view'
import FilePage from './view'
const select = (state) => ({
claim: selectCurrentUriClaim(state),
@ -30,4 +30,4 @@ const select = (state) => ({
const perform = (dispatch) => ({
})
export default connect(select, perform)(ShowPage)
export default connect(select, perform)(FilePage)

View file

@ -16,27 +16,20 @@ import UriIndicator from 'component/uriIndicator';
const FormatItem = (props) => {
const {
contentType,
metadata,
metadata: {
thumbnail,
author,
title,
description,
language,
license,
},
cost,
uri,
outpoint,
costIncludesData,
}
} = props
const mediaType = lbry.getMediaType(contentType);
return (
<table className="table-standard">
<tbody>
<tr>
<td>Content-Type</td><td>{contentType}</td>
<td>Content-Type</td><td>{mediaType}</td>
</tr>
<tr>
<td>Author</td><td>{author}</td>
@ -52,23 +45,6 @@ const FormatItem = (props) => {
)
}
let ChannelPage = React.createClass({
render: function() {
return <main className="main--single-column">
<section className="card">
<div className="card__inner">
<div className="card__title-identity"><h1>{this.props.title}</h1></div>
</div>
<div className="card__content">
<p>
This channel page is a stub.
</p>
</div>
</section>
</main>
}
});
let FilePage = React.createClass({
_isMounted: false,
@ -267,8 +243,6 @@ let ShowPage = React.createClass({
}
</div>
</section>;
} else if (this.state.claimType == "channel") {
innerContent = <ChannelPage title={this._uri} />
} else {
let channelUriObj = lbryuri.parse(this._uri)
delete channelUriObj.path;
@ -289,4 +263,105 @@ let ShowPage = React.createClass({
}
});
export default ShowPage;
export default FilePage;
//
// const ShowPage = (props) => {
// const {
// claim,
// navigate,
// claim: {
// txid,
// nout,
// has_signature: hasSignature,
// signature_is_valid: signatureIsValid,
// value,
// value: {
// stream,
// stream: {
// metadata,
// source,
// metadata: {
// title,
// } = {},
// source: {
// contentType,
// } = {},
// } = {},
// } = {},
// },
// uri,
// isDownloaded,
// fileInfo,
// costInfo,
// costInfo: {
// cost,
// includesData: costIncludesData,
// } = {},
// } = props
//
// const outpoint = txid + ':' + nout;
// const uriLookupComplete = !!claim && Object.keys(claim).length
//
// if (props.isFailed) {
// return (
// <main className="main--single-column">
// <section className="card">
// <div className="card__inner">
// <div className="card__title-identity"><h1>{uri}</h1></div>
// </div>
// <div className="card__content">
// <p>
// This location is not yet in use.
// { ' ' }
// <Link href="#" onClick={() => navigate('publish')} label="Put something here" />.
// </p>
// </div>
// </section>
// </main>
// )
// }
//
// return (
// <main className="main--single-column">
// <section className="show-page-media">
// { contentType && contentType.startsWith('video/') ?
// <Video className="video-embedded" uri={uri} metadata={metadata} outpoint={outpoint} /> :
// (metadata ? <Thumbnail src={metadata.thumbnail} /> : <Thumbnail />) }
// </section>
// <section className="card">
// <div className="card__inner">
// <div className="card__title-identity">
// {isDownloaded === false
// ? <span style={{float: "right"}}><FilePrice uri={lbryuri.normalize(uri)} /></span>
// : null}
// <h1>{title}</h1>
// { uriLookupComplete ?
// <div>
// <div className="card__subtitle">
// <UriIndicator uri={uri} />
// </div>
// <div className="card__actions">
// <FileActions uri={uri} outpoint={outpoint} metadata={metadata} contentType={contentType} />
// </div>
// </div> : '' }
// </div>
// { uriLookupComplete ?
// <div>
// <div className="card__content card__subtext card__subtext card__subtext--allow-newlines">
// {metadata.description}
// </div>
// </div>
// : <div className="card__content"><BusyMessage message="Loading magic decentralized data..." /></div> }
// </div>
// { metadata ?
// <div className="card__content">
// <FormatItem metadata={metadata} contentType={contentType} cost={cost} uri={uri} outpoint={outpoint} costIncludesData={costIncludesData} />
// </div> : '' }
// <div className="card__content">
// <Link href="https://lbry.io/dmca" label="report" className="button-text-help" />
// </div>
// </section>
// </main>
// )
// }

View file

@ -2,6 +2,7 @@
import React from 'react';
import lbry from 'lbry.js';
import Link from 'component/link';
import NavSettings from 'component/navSettings';
import {version as uiVersion} from 'json!../../../package.json';
var HelpPage = React.createClass({
@ -49,58 +50,71 @@ var HelpPage = React.createClass({
return (
<main className="main--single-column">
<NavSettings />
<section className="card">
<h3>Read the FAQ</h3>
<p>Our FAQ answers many common questions.</p>
<p><Link href="https://lbry.io/faq" label="Read the FAQ" icon="icon-question" button="alt"/></p>
<div className="card__title-primary">
<h3>Read the FAQ</h3>
</div>
<div className="card__content">
<p>Our FAQ answers many common questions.</p>
<p><Link href="https://lbry.io/faq" label="Read the FAQ" icon="icon-question" button="alt"/></p>
</div>
</section>
<section className="card">
<h3>Get Live Help</h3>
<p>
Live help is available most hours in the <strong>#help</strong> channel of our Slack chat room.
</p>
<p>
<Link button="alt" label="Join Our Slack" icon="icon-slack" href="https://slack.lbry.io" />
</p>
<div className="card__title-primary">
<h3>Get Live Help</h3>
</div>
<div className="card__content">
<p>
Live help is available most hours in the <strong>#help</strong> channel of our Slack chat room.
</p>
<p>
<Link button="alt" label="Join Our Slack" icon="icon-slack" href="https://slack.lbry.io" />
</p>
</div>
</section>
<section className="card">
<h3>Report a Bug</h3>
<p>Did you find something wrong?</p>
<p><Link href="?report" label="Submit a Bug Report" icon="icon-bug" button="alt" /></p>
<div className="meta">Thanks! LBRY is made by its users.</div>
<div className="card__title-primary"><h3>Report a Bug</h3></div>
<div className="card__content">
<p>Did you find something wrong?</p>
<p><Link href="?report" label="Submit a Bug Report" icon="icon-bug" button="alt" /></p>
<div className="meta">Thanks! LBRY is made by its users.</div>
</div>
</section>
{!ver ? null :
<section className="card">
<h3>About</h3>
{ver.lbrynet_update_available || ver.lbryum_update_available ?
<section className="card">
<div className="card__title-primary"><h3>About</h3></div>
<div className="card__content">
{ver.lbrynet_update_available || ver.lbryum_update_available ?
<p>A newer version of LBRY is available. <Link href={newVerLink} label={`Download LBRY ${ver.remote_lbrynet} now!`} /></p>
: <p>Your copy of LBRY is up to date.</p>
}
<table className="table-standard">
<tbody>
<tr>
<th>daemon (lbrynet)</th>
<td>{ver.lbrynet_version}</td>
</tr>
<tr>
<th>wallet (lbryum)</th>
<td>{ver.lbryum_version}</td>
</tr>
<tr>
<th>interface</th>
<td>{uiVersion}</td>
</tr>
<tr>
<th>Platform</th>
<td>{platform}</td>
</tr>
<tr>
<th>Installation ID</th>
<td>{this.state.lbryId}</td>
</tr>
</tbody>
</table>
</section>
: <p>Your copy of LBRY is up to date.</p>
}
<table className="table-standard">
<tbody>
<tr>
<th>daemon (lbrynet)</th>
<td>{ver.lbrynet_version}</td>
</tr>
<tr>
<th>wallet (lbryum)</th>
<td>{ver.lbryum_version}</td>
</tr>
<tr>
<th>interface</th>
<td>{uiVersion}</td>
</tr>
<tr>
<th>Platform</th>
<td>{platform}</td>
</tr>
<tr>
<th>Installation ID</th>
<td>{this.state.lbryId}</td>
</tr>
</tbody>
</table>
</div>
</section>
}
</main>
);

View file

@ -1,10 +1,7 @@
import React from 'react';
import lbry from 'lbry';
import lbryio from 'lbryio';
import {CreditAmount, Icon} from 'component/common.js';
import rewards from 'rewards';
import Modal from 'component/modal';
import {WalletNav} from 'component/wallet-nav ewar';
import NavWallet from 'component/navWallet';
import {RewardLink} from 'component/reward-link';
const RewardTile = React.createClass({
@ -36,7 +33,7 @@ const RewardTile = React.createClass({
}
});
var RewardsPage = React.createClass({
export let RewardsPage = React.createClass({
componentWillMount: function() {
this.loadRewards()
},
@ -58,7 +55,7 @@ var RewardsPage = React.createClass({
render: function() {
return (
<main className="main--single-column">
<WalletNav viewingPage="rewards"/>
<NavWallet />
<div>
{!this.state.userRewards
? (this.state.failed ? <div className="empty">Failed to load rewards.</div> : '')

View file

@ -1,17 +1,8 @@
import React from 'react';
import {FormField, FormRow} from '../component/form.js';
import {SubHeader} from '../component/sub-header.js';
import NavSettings from 'component/navSettings';
import lbry from '../lbry.js';
export let SettingsNav = React.createClass({
render: function() {
return <SubHeader modifier="constrained" viewingPage={this.props.viewingPage} links={{
'?settings': 'Settings',
'?help' : 'Help'
}} />;
}
});
var SettingsPage = React.createClass({
_onSettingSaveSuccess: function() {
// This is bad.
@ -100,7 +91,7 @@ var SettingsPage = React.createClass({
*/
return (
<main className="main--single-column">
<SettingsNav viewingPage="settings" />
<NavSettings />
<section className="card">
<div className="card__content">
<h3>Download Directory</h3>

View file

@ -2,6 +2,7 @@ import React from 'react';
import lbry from 'lbry.js';
import Link from 'component/link';
import Modal from 'component/modal';
import NavWallet from 'component/navWallet';
import {
FormField,
FormRow
@ -247,6 +248,7 @@ const WalletPage = (props) => {
return (
<main className="main--single-column">
<NavWallet />
<section className="card">
<div className="card__title-primary">
<h3>Balance</h3>

View file

@ -6,7 +6,6 @@ const defaultState = {
isLoaded: false,
currentPath: 'discover',
platform: process.platform,
drawerOpen: sessionStorage.getItem('drawerOpen') || true,
upgradeSkipped: sessionStorage.getItem('upgradeSkipped'),
daemonReady: false,
platform: window.navigator.platform,
@ -84,20 +83,6 @@ reducers[types.CLOSE_MODAL] = function(state, action) {
})
}
reducers[types.OPEN_DRAWER] = function(state, action) {
sessionStorage.setItem('drawerOpen', false)
return Object.assign({}, state, {
drawerOpen: true
})
}
reducers[types.CLOSE_DRAWER] = function(state, action) {
sessionStorage.setItem('drawerOpen', false)
return Object.assign({}, state, {
drawerOpen: false
})
}
reducers[types.UPGRADE_DOWNLOAD_PROGRESSED] = function(state, action) {
return Object.assign({}, state, {
downloadProgress: action.data.percent

View file

@ -12,15 +12,15 @@ reducers[types.FETCH_FEATURED_CONTENT_STARTED] = function(state, action) {
reducers[types.FETCH_FEATURED_CONTENT_COMPLETED] = function(state, action) {
const {
uris
uris,
success
} = action.data
const newFeaturedContent = Object.assign({}, state.featuredContent, {
byCategory: uris,
})
return Object.assign({}, state, {
fetchingFeaturedContent: false,
featuredContent: newFeaturedContent
fetchingFeaturedContentFailed: !success,
featuredUris: uris
})
}

View file

@ -56,7 +56,7 @@ rewards.claimReward = function (type) {
}
return new Promise((resolve, reject) => {
lbry.wallet_new_address().then((address) => {
lbry.wallet_unused_address().then((address) => {
const params = {
reward_type: type,
wallet_address: address,

View file

@ -1,4 +1,4 @@
import { createSelector } from 'reselect'
import {createSelector} from 'reselect'
export const _selectState = state => state.app || {}
@ -22,35 +22,98 @@ export const selectCurrentUri = createSelector(
(path) => {
if (path.match(/=/)) {
return path.split('=')[1]
} else {
}
else {
return undefined
}
}
)
export const selectCurrentUriTitle = createSelector(
_selectState,
(state) => "fix me"
)
export const selectPageTitle = createSelector(
selectCurrentPage,
selectCurrentUri,
(page, uri) => {
switch(page)
{
case 'discover':
return 'Discover'
switch (page) {
case 'search':
return 'Search'
case 'settings':
return 'Settings'
case 'help':
return 'Help'
case 'report':
return 'Report'
case 'wallet':
case 'send':
case 'receive':
case 'rewards':
return 'Wallet'
return page.charAt(0).toUpperCase() + page.slice(1)
case 'show':
return lbryuri.normalize(page)
case 'downloaded':
return 'My Files'
return 'Downloads & Purchases'
case 'published':
return 'My Files'
return 'Publishes'
case 'start':
return 'Start'
case 'publish':
return 'Publish'
case 'help':
return 'Help'
case 'developer':
return 'Developer'
case 'discover':
return 'Home'
default:
return 'LBRY';
return '';
}
}
)
export const selectWunderBarAddress = createSelector(
selectPageTitle,
(title) => title
)
export const selectWunderBarIcon = createSelector(
selectCurrentPage,
selectCurrentUri,
(page, uri) => {
switch (page) {
case 'search':
return 'icon-search'
case 'settings':
return 'icon-gear'
case 'help':
return 'icon-question'
case 'report':
return 'icon-file'
case 'downloaded':
return 'icon-folder'
case 'published':
return 'icon-folder'
case 'start':
return 'icon-file'
case 'rewards':
return 'icon-bank'
case 'wallet':
case 'send':
case 'receive':
return 'icon-bank'
case 'show':
return 'icon-file'
case 'publish':
return 'icon-upload'
case 'developer':
return 'icon-file'
case 'developer':
return 'icon-code'
case 'discover':
return 'icon-home'
}
}
)
@ -115,24 +178,18 @@ export const selectDownloadComplete = createSelector(
(state) => state.upgradeDownloadCompleted
)
export const selectDrawerOpen = createSelector(
_selectState,
(state) => state.drawerOpen
)
export const selectHeaderLinks = createSelector(
selectCurrentPage,
(page) => {
switch(page)
{
switch (page) {
case 'wallet':
case 'send':
case 'receive':
case 'rewards':
return {
'wallet' : 'Overview',
'send' : 'Send',
'receive' : 'Receive',
'wallet': 'Overview',
'send': 'Send',
'receive': 'Receive',
'rewards': 'Rewards',
};
case 'downloaded':

View file

@ -7,26 +7,21 @@ import {
export const _selectState = state => state.content || {}
export const selectFeaturedContent = createSelector(
export const selectFeaturedUris = createSelector(
_selectState,
(state) => state.featuredContent || {}
(state) => state.featuredUris || {}
)
export const selectFeaturedContentByCategory = createSelector(
selectFeaturedContent,
(featuredContent) => featuredContent.byCategory || {}
)
export const selectFetchingFeaturedContent = createSelector(
export const selectFetchingFeaturedUris = createSelector(
_selectState,
(state) => !!state.fetchingFeaturedContent
)
export const shouldFetchFeaturedContent = createSelector(
export const shouldFetchFeaturedUris = createSelector(
selectDaemonReady,
selectCurrentPage,
selectFetchingFeaturedContent,
selectFeaturedContentByCategory,
selectFetchingFeaturedUris,
selectFeaturedUris,
(daemonReady, page, fetching, byCategory) => {
if (!daemonReady) return false
if (page != 'discover') return false

View file

@ -3,7 +3,7 @@ import {
shouldGetReceiveAddress,
} from 'selectors/wallet'
import {
shouldFetchFeaturedContent,
shouldFetchFeaturedUris,
shouldFetchDownloadedContent,
shouldFetchPublishedContent,
} from 'selectors/content'
@ -21,7 +21,7 @@ import {
doGetNewAddress,
} from 'actions/wallet'
import {
doFetchFeaturedContent,
doFetchFeaturedUris,
doFetchDownloadedContent,
doFetchPublishedContent,
} from 'actions/content'
@ -48,8 +48,8 @@ triggers.push({
})
triggers.push({
selector: shouldFetchFeaturedContent,
action: doFetchFeaturedContent,
selector: shouldFetchFeaturedUris,
action: doFetchFeaturedUris,
})
triggers.push({

View file

@ -60,11 +60,9 @@ nav.sub-header
{
text-transform: uppercase;
padding: 0 0 $spacing-vertical;
&.sub-header--constrained {
max-width: $width-page-constrained;
margin-left: auto;
margin-right: auto;
}
max-width: $width-page-constrained;
margin-left: auto;
margin-right: auto;
> a
{
$sub-header-selected-underline-height: 2px;