2016-11-22 21:19:08 +01:00
|
|
|
import React from 'react';
|
2017-02-20 19:56:15 +01:00
|
|
|
import {Line} from 'rc-progress';
|
|
|
|
|
2016-11-22 21:19:08 +01:00
|
|
|
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';
|
2017-03-28 11:07:52 +02:00
|
|
|
import RewardsPage from './page/rewards.js';
|
|
|
|
import RewardPage from './page/reward.js';
|
2016-11-22 21:19:08 +01:00
|
|
|
import WalletPage from './page/wallet.js';
|
2017-04-11 03:29:07 +02:00
|
|
|
import ShowPage from './page/show.js';
|
2016-11-22 21:19:08 +01:00
|
|
|
import PublishPage from './page/publish.js';
|
2017-05-01 02:15:21 +02:00
|
|
|
import SearchPage from './page/search.js';
|
2016-11-22 21:19:08 +01:00
|
|
|
import DiscoverPage from './page/discover.js';
|
2016-12-29 10:23:28 +01:00
|
|
|
import DeveloperPage from './page/developer.js';
|
2017-05-02 00:31:13 +02:00
|
|
|
import lbryuri from './lbryuri.js';
|
2017-01-13 23:18:37 +01:00
|
|
|
import {FileListDownloaded, FileListPublished} from './page/file-list.js';
|
2016-11-22 21:19:08 +01:00
|
|
|
import Header from './component/header.js';
|
2017-02-25 08:57:29 +01:00
|
|
|
import {Modal, ExpandableModal} from './component/modal.js';
|
2016-11-22 21:19:08 +01:00
|
|
|
import {Link} from './component/link.js';
|
|
|
|
|
2017-02-20 19:56:15 +01:00
|
|
|
|
2017-03-16 00:12:52 +01:00
|
|
|
const {remote, ipcRenderer, shell} = require('electron');
|
2017-02-20 19:56:15 +01:00
|
|
|
const {download} = remote.require('electron-dl');
|
2017-03-17 10:06:02 +01:00
|
|
|
const path = require('path');
|
|
|
|
const app = require('electron').remote.app;
|
2017-03-22 11:47:44 +01:00
|
|
|
const fs = remote.require('fs');
|
2017-02-20 19:56:15 +01:00
|
|
|
|
|
|
|
|
2016-04-10 02:00:56 +02:00
|
|
|
var App = React.createClass({
|
2016-10-21 11:21:07 +02:00
|
|
|
_error_key_labels: {
|
2016-10-22 10:40:46 +02:00
|
|
|
connectionString: 'API connection string',
|
2016-10-21 11:21:07 +02:00
|
|
|
method: 'Method',
|
|
|
|
params: 'Parameters',
|
|
|
|
code: 'Error code',
|
|
|
|
message: 'Error message',
|
|
|
|
data: 'Error data',
|
|
|
|
},
|
2017-04-01 08:30:32 +02:00
|
|
|
_fullScreenPages: ['watch'],
|
2017-05-01 02:15:21 +02:00
|
|
|
_storeHistoryOfNextRender: false,
|
2016-10-21 11:21:07 +02:00
|
|
|
|
2017-03-17 10:06:02 +01:00
|
|
|
_upgradeDownloadItem: null,
|
2017-03-26 20:30:18 +02:00
|
|
|
_isMounted: false,
|
2017-03-17 10:06:02 +01:00
|
|
|
_version: null,
|
2017-03-22 11:55:16 +01:00
|
|
|
getUpdateUrl: function() {
|
2017-03-23 19:08:14 +01:00
|
|
|
switch (process.platform) {
|
2017-03-22 11:55:16 +01:00
|
|
|
case 'darwin':
|
|
|
|
return 'https://lbry.io/get/lbry.dmg';
|
|
|
|
case 'linux':
|
|
|
|
return 'https://lbry.io/get/lbry.deb';
|
|
|
|
case 'win32':
|
2017-03-23 19:08:14 +01:00
|
|
|
return 'https://lbry.io/get/lbry.exe';
|
|
|
|
default:
|
|
|
|
throw 'Unknown platform';
|
2017-03-22 11:55:16 +01:00
|
|
|
}
|
|
|
|
},
|
2017-03-23 19:08:14 +01:00
|
|
|
// Hard code the filenames as a temporary workaround, because
|
|
|
|
// electron-dl throws errors when you try to get the filename
|
2017-03-17 10:06:02 +01:00
|
|
|
getUpgradeFilename: function() {
|
2017-03-23 19:08:14 +01:00
|
|
|
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';
|
2017-03-17 10:06:02 +01:00
|
|
|
}
|
|
|
|
},
|
2017-03-26 20:30:18 +02:00
|
|
|
getViewingPageAndArgs: function(address) {
|
2016-04-21 11:51:27 +02:00
|
|
|
// For now, routes are in format ?page or ?page=args
|
2017-03-27 07:44:13 +02:00
|
|
|
let [isMatch, viewingPage, pageArgs] = address.match(/\??([^=]*)(?:=(.*))?/);
|
2016-04-20 12:28:13 +02:00
|
|
|
return {
|
2016-08-27 16:12:56 +02:00
|
|
|
viewingPage: viewingPage,
|
2017-05-01 02:15:21 +02:00
|
|
|
pageArgs: pageArgs === undefined ? null : decodeURIComponent(pageArgs)
|
2017-03-26 20:30:18 +02:00
|
|
|
};
|
|
|
|
},
|
|
|
|
getInitialState: function() {
|
2017-04-09 17:06:23 +02:00
|
|
|
return Object.assign(this.getViewingPageAndArgs(window.location.search), {
|
2017-05-01 05:33:53 +02:00
|
|
|
viewingPage: 'discover',
|
2017-05-01 02:15:21 +02:00
|
|
|
appUrl: null,
|
2016-10-21 11:21:07 +02:00
|
|
|
errorInfo: null,
|
2016-10-21 09:47:06 +02:00
|
|
|
modal: null,
|
2017-02-20 19:56:15 +01:00
|
|
|
downloadProgress: null,
|
2017-03-17 10:06:02 +01:00
|
|
|
downloadComplete: false,
|
2017-03-26 20:30:18 +02:00
|
|
|
});
|
2016-04-10 02:00:56 +02:00
|
|
|
},
|
2016-04-12 12:30:25 +02:00
|
|
|
componentWillMount: function() {
|
2017-05-01 02:15:21 +02:00
|
|
|
window.addEventListener("popstate", this.onHistoryPop);
|
|
|
|
|
2016-10-22 11:22:44 +02:00
|
|
|
document.addEventListener('unhandledError', (event) => {
|
2016-10-21 11:21:07 +02:00
|
|
|
this.alertError(event.detail);
|
|
|
|
});
|
|
|
|
|
2017-03-26 20:30:18 +02:00
|
|
|
//open links in external browser and skip full redraw on changing page
|
2017-03-27 07:44:13 +02:00
|
|
|
document.addEventListener('click', (event) => {
|
2017-03-16 00:12:52 +01:00
|
|
|
var target = event.target;
|
|
|
|
while (target && target !== document) {
|
|
|
|
if (target.matches('a[href^="http"]')) {
|
|
|
|
event.preventDefault();
|
|
|
|
shell.openExternal(target.href);
|
|
|
|
return;
|
|
|
|
}
|
2017-03-26 20:30:18 +02:00
|
|
|
if (target.matches('a[href^="?"]')) {
|
|
|
|
event.preventDefault();
|
|
|
|
if (this._isMounted) {
|
2017-05-01 02:15:21 +02:00
|
|
|
let appUrl = target.getAttribute('href');
|
|
|
|
this._storeHistoryOfNextRender = true;
|
|
|
|
this.setState(Object.assign({}, this.getViewingPageAndArgs(appUrl), { appUrl: appUrl }));
|
2017-05-01 22:50:07 +02:00
|
|
|
document.body.scrollTop = 0;
|
2017-03-26 20:30:18 +02:00
|
|
|
}
|
|
|
|
}
|
2017-03-16 00:12:52 +01:00
|
|
|
target = target.parentNode;
|
|
|
|
}
|
2017-03-27 07:44:13 +02:00
|
|
|
});
|
2017-03-16 00:12:52 +01:00
|
|
|
|
2017-03-22 11:55:16 +01:00
|
|
|
if (!sessionStorage.getItem('upgradeSkipped')) {
|
2017-04-27 08:52:14 +02:00
|
|
|
lbry.getVersionInfo().then(({remoteVersion, upgradeAvailable}) => {
|
|
|
|
if (upgradeAvailable) {
|
|
|
|
this._version = remoteVersion;
|
2017-03-22 11:55:16 +01:00
|
|
|
this.setState({
|
|
|
|
modal: 'upgrade',
|
|
|
|
});
|
2017-04-27 08:52:14 +02:00
|
|
|
}
|
2016-05-30 15:43:34 +02:00
|
|
|
});
|
2017-03-22 11:55:16 +01:00
|
|
|
}
|
2016-04-12 12:30:25 +02:00
|
|
|
},
|
2016-10-21 09:47:06 +02:00
|
|
|
closeModal: function() {
|
|
|
|
this.setState({
|
|
|
|
modal: null,
|
|
|
|
});
|
|
|
|
},
|
2017-03-26 20:30:18 +02:00
|
|
|
componentDidMount: function() {
|
|
|
|
this._isMounted = true;
|
|
|
|
},
|
|
|
|
componentWillUnmount: function() {
|
|
|
|
this._isMounted = false;
|
2017-05-01 02:15:21 +02:00
|
|
|
window.removeEventListener("popstate", this.onHistoryPop);
|
|
|
|
},
|
|
|
|
onHistoryPop: function() {
|
|
|
|
this.setState(this.getViewingPageAndArgs(location.search));
|
2017-03-26 20:30:18 +02:00
|
|
|
},
|
2017-05-01 02:15:21 +02:00
|
|
|
onSearch: function(term) {
|
|
|
|
this._storeHistoryOfNextRender = true;
|
2017-05-01 05:38:14 +02:00
|
|
|
const isShow = term.startsWith('lbry://');
|
2017-05-01 02:15:21 +02:00
|
|
|
this.setState({
|
2017-05-01 05:38:14 +02:00
|
|
|
viewingPage: isShow ? "show" : "search",
|
|
|
|
appUrl: (isShow ? "?show=" : "?search=") + encodeURIComponent(term),
|
2017-05-01 02:15:21 +02:00
|
|
|
pageArgs: term
|
2017-04-30 03:56:55 +02:00
|
|
|
});
|
2017-04-12 04:01:45 +02:00
|
|
|
},
|
2017-05-01 05:38:14 +02:00
|
|
|
onSubmit: function(uri) {
|
|
|
|
this._storeHistoryOfNextRender = true;
|
|
|
|
this.setState({
|
|
|
|
address: uri,
|
|
|
|
appUrl: "?show=" + encodeURIComponent(uri),
|
|
|
|
viewingPage: "show",
|
|
|
|
pageArgs: uri
|
|
|
|
})
|
|
|
|
},
|
2016-10-21 09:47:06 +02:00
|
|
|
handleUpgradeClicked: function() {
|
2017-03-22 11:47:44 +01:00
|
|
|
// 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);
|
|
|
|
|
2017-02-20 19:56:15 +01:00
|
|
|
let options = {
|
|
|
|
onProgress: (p) => this.setState({downloadProgress: Math.round(p * 100)}),
|
2017-03-17 10:06:02 +01:00
|
|
|
directory: dir,
|
|
|
|
};
|
2017-03-22 11:47:44 +01:00
|
|
|
download(remote.getCurrentWindow(), this.getUpdateUrl(), options)
|
2017-03-17 10:06:02 +01:00
|
|
|
.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
|
|
|
|
});
|
|
|
|
});
|
2017-02-20 19:56:15 +01:00
|
|
|
this.setState({modal: 'downloading'});
|
2016-10-21 09:47:06 +02:00
|
|
|
},
|
2017-03-17 10:06:02 +01:00
|
|
|
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,
|
|
|
|
});
|
|
|
|
},
|
2016-10-21 09:47:06 +02:00
|
|
|
handleSkipClicked: function() {
|
|
|
|
sessionStorage.setItem('upgradeSkipped', true);
|
|
|
|
this.setState({
|
|
|
|
modal: null,
|
|
|
|
});
|
|
|
|
},
|
2016-10-21 11:21:07 +02:00
|
|
|
alertError: function(error) {
|
|
|
|
var errorInfoList = [];
|
|
|
|
for (let key of Object.keys(error)) {
|
2016-10-22 10:35:47 +02:00
|
|
|
let val = typeof error[key] == 'string' ? error[key] : JSON.stringify(error[key]);
|
2016-10-21 11:21:07 +02:00
|
|
|
let label = this._error_key_labels[key];
|
2016-10-22 11:50:55 +02:00
|
|
|
errorInfoList.push(<li key={key}><strong>{label}</strong>: <code>{val}</code></li>);
|
2016-10-21 11:21:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
modal: 'error',
|
2016-10-26 08:57:20 +02:00
|
|
|
errorInfo: <ul className="error-modal__error-list">{errorInfoList}</ul>,
|
2016-10-21 11:21:07 +02:00
|
|
|
});
|
|
|
|
},
|
2017-04-27 05:54:53 +02:00
|
|
|
getContentAndAddress: function()
|
2016-08-08 00:13:17 +02:00
|
|
|
{
|
|
|
|
switch(this.state.viewingPage)
|
|
|
|
{
|
2017-05-01 02:15:21 +02:00
|
|
|
case 'search':
|
|
|
|
return [this.state.pageArgs ? this.state.pageArgs : "Search", 'icon-search', <SearchPage query={this.state.pageArgs} />];
|
2016-08-08 00:13:17 +02:00
|
|
|
case 'settings':
|
2017-04-27 05:54:53 +02:00
|
|
|
return ["Settings", "icon-gear", <SettingsPage />];
|
2016-08-08 00:13:17 +02:00
|
|
|
case 'help':
|
2017-04-27 05:54:53 +02:00
|
|
|
return ["Help", "icon-question", <HelpPage />];
|
2016-08-08 00:13:17 +02:00
|
|
|
case 'report':
|
2017-05-01 02:15:21 +02:00
|
|
|
return ['Report an Issue', 'icon-file', <ReportPage />];
|
2016-09-23 11:19:39 +02:00
|
|
|
case 'downloaded':
|
2017-04-27 05:54:53 +02:00
|
|
|
return ["Downloads & Purchases", "icon-folder", <FileListDownloaded />];
|
2016-09-23 11:19:39 +02:00
|
|
|
case 'published':
|
2017-04-27 05:54:53 +02:00
|
|
|
return ["Publishes", "icon-folder", <FileListPublished />];
|
2016-08-08 00:13:17 +02:00
|
|
|
case 'start':
|
2017-04-27 05:54:53 +02:00
|
|
|
return ["Start", "icon-file", <StartPage />];
|
2017-03-28 11:07:52 +02:00
|
|
|
case 'rewards':
|
2017-04-27 05:54:53 +02:00
|
|
|
return ["Rewards", "icon-bank", <RewardsPage />];
|
2016-08-08 00:13:17 +02:00
|
|
|
case 'wallet':
|
2016-08-27 16:12:56 +02:00
|
|
|
case 'send':
|
|
|
|
case 'receive':
|
2017-04-27 05:54:53 +02:00
|
|
|
return [this.state.viewingPage.charAt(0).toUpperCase() + this.state.viewingPage.slice(1), "icon-bank", <WalletPage viewingPage={this.state.viewingPage} />]
|
2016-08-08 00:13:17 +02:00
|
|
|
case 'show':
|
2017-05-02 00:31:13 +02:00
|
|
|
return [lbryuri.normalize(this.state.pageArgs), "icon-file", <ShowPage uri={this.state.pageArgs} />];
|
2016-08-08 00:13:17 +02:00
|
|
|
case 'publish':
|
2017-04-27 05:54:53 +02:00
|
|
|
return ["Publish", "icon-upload", <PublishPage />];
|
2016-12-29 10:23:28 +01:00
|
|
|
case 'developer':
|
2017-04-27 05:54:53 +02:00
|
|
|
return ["Developer", "icon-file", <DeveloperPage />];
|
2016-08-27 16:12:56 +02:00
|
|
|
case 'discover':
|
2017-05-01 02:15:21 +02:00
|
|
|
default:
|
|
|
|
return ["Home", "icon-home", <DiscoverPage />];
|
2016-08-08 00:13:17 +02:00
|
|
|
}
|
|
|
|
},
|
2016-04-10 02:00:56 +02:00
|
|
|
render: function() {
|
2017-04-27 15:17:18 +02:00
|
|
|
let [address, wunderBarIcon, mainContent] = this.getContentAndAddress();
|
2017-04-27 05:54:53 +02:00
|
|
|
|
2017-05-01 02:15:21 +02:00
|
|
|
lbry.setTitle(address);
|
|
|
|
|
|
|
|
if (this._storeHistoryOfNextRender) {
|
|
|
|
this._storeHistoryOfNextRender = false;
|
|
|
|
history.pushState({}, document.title, this.state.appUrl);
|
|
|
|
}
|
|
|
|
|
2016-08-07 22:10:44 +02:00
|
|
|
return (
|
2017-03-31 01:00:33 +02:00
|
|
|
this._fullScreenPages.includes(this.state.viewingPage) ?
|
2016-08-08 05:39:44 +02:00
|
|
|
mainContent :
|
2017-04-27 05:54:53 +02:00
|
|
|
<div id="window">
|
2017-05-01 05:38:14 +02:00
|
|
|
<Header onSearch={this.onSearch} onSubmit={this.onSubmit} address={address} wunderBarIcon={wunderBarIcon} viewingPage={this.state.viewingPage} />
|
2017-04-27 15:17:18 +02:00
|
|
|
<div id="main-content">
|
2016-08-08 05:39:44 +02:00
|
|
|
{mainContent}
|
|
|
|
</div>
|
2017-01-13 23:05:09 +01:00
|
|
|
<Modal isOpen={this.state.modal == 'upgrade'} contentLabel="Update available"
|
|
|
|
type="confirm" confirmButtonLabel="Upgrade" abortButtonLabel="Skip"
|
|
|
|
onConfirmed={this.handleUpgradeClicked} onAborted={this.handleSkipClicked}>
|
2017-03-22 11:55:16 +01:00
|
|
|
Your version of LBRY is out of date and may be unreliable or insecure.
|
2016-10-21 09:47:06 +02:00
|
|
|
</Modal>
|
2017-02-20 19:56:15 +01:00
|
|
|
<Modal isOpen={this.state.modal == 'downloading'} contentLabel="Downloading Update" type="custom">
|
2017-03-17 23:05:25 +01:00
|
|
|
Downloading Update{this.state.downloadProgress ? `: ${this.state.downloadProgress}%` : null}
|
2017-02-20 19:56:15 +01:00
|
|
|
<Line percent={this.state.downloadProgress} strokeWidth="4"/>
|
2017-03-17 23:05:25 +01:00
|
|
|
{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 }
|
2017-03-17 10:06:02 +01:00
|
|
|
<div className="modal__buttons">
|
2017-03-17 23:05:25 +01:00
|
|
|
{this.state.downloadComplete
|
2017-03-17 10:06:02 +01:00
|
|
|
? <Link button="primary" label="Begin Upgrade" className="modal__button" onClick={this.handleStartUpgradeClicked} />
|
|
|
|
: null}
|
2017-03-17 23:05:25 +01:00
|
|
|
<Link button="alt" label="Cancel" className="modal__button" onClick={this.cancelUpgrade} />
|
2017-03-17 10:06:02 +01:00
|
|
|
</div>
|
2017-02-20 19:56:15 +01:00
|
|
|
</Modal>
|
2017-02-25 08:57:29 +01:00
|
|
|
<ExpandableModal isOpen={this.state.modal == 'error'} contentLabel="Error" className="error-modal"
|
|
|
|
overlayClassName="error-modal-overlay" onConfirmed={this.closeModal}
|
|
|
|
extraContent={this.state.errorInfo}>
|
2016-10-26 08:57:20 +02:00
|
|
|
<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>
|
2016-10-25 05:52:36 +02:00
|
|
|
</div>
|
2017-02-25 08:57:29 +01:00
|
|
|
</ExpandableModal>
|
2016-08-07 22:10:44 +02:00
|
|
|
</div>
|
|
|
|
);
|
2016-04-10 02:00:56 +02:00
|
|
|
}
|
2016-08-23 16:53:45 +02:00
|
|
|
});
|
2016-11-22 21:19:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
export default App;
|