Merge branch 'master' into restructuring

This commit is contained in:
Igor Gassmann 2017-12-07 12:23:43 -03:00
commit eaa5c212d2
23 changed files with 284 additions and 72 deletions

2
.gitignore vendored
View file

@ -24,3 +24,5 @@ build/daemon.zip
.vimrc
package-lock.json
.DS_Store

View file

@ -21,6 +21,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
* Fixed scriolling restore/reset/set (#729)
* Fixed sorting by title for published files (#614)
* App now uses the new balance_delta field in the txn list.
* Abandoning from the claim page now works.
*
### Deprecated

17
src/renderer/.flowconfig Normal file
View file

@ -0,0 +1,17 @@
[ignore]
.*/node_modules/**
[include]
[libs]
flow-typed
[lints]
[options]
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue
module.name_mapper='^constants\(.*\)$' -> '<PROJECT_ROOT>/js/constants\1'
module.name_mapper='^redux\(.*\)$' -> '<PROJECT_ROOT>/js/redux\1'
[strict]

View file

@ -1,13 +1,14 @@
import React from "react";
import PropTypes from "prop-types";
import { formatCredits, formatFullPrice } from "util/formatCredits";
import lbry from "../lbry.js";
//component/icon.js
export class Icon extends React.PureComponent {
static propTypes = {
icon: React.PropTypes.string.isRequired,
className: React.PropTypes.string,
fixed: React.PropTypes.bool,
icon: PropTypes.string.isRequired,
className: PropTypes.string,
fixed: PropTypes.bool,
};
render() {
@ -24,7 +25,7 @@ export class Icon extends React.PureComponent {
export class TruncatedText extends React.PureComponent {
static propTypes = {
lines: React.PropTypes.number,
lines: PropTypes.number,
};
static defaultProps = {
@ -45,7 +46,7 @@ export class TruncatedText extends React.PureComponent {
export class BusyMessage extends React.PureComponent {
static propTypes = {
message: React.PropTypes.string,
message: PropTypes.string,
};
render() {
@ -65,14 +66,14 @@ export class CurrencySymbol extends React.PureComponent {
export class CreditAmount extends React.PureComponent {
static propTypes = {
amount: React.PropTypes.number.isRequired,
precision: React.PropTypes.number,
isEstimate: React.PropTypes.bool,
label: React.PropTypes.bool,
showFree: React.PropTypes.bool,
showFullPrice: React.PropTypes.bool,
showPlus: React.PropTypes.bool,
look: React.PropTypes.oneOf(["indicator", "plain", "fee"]),
amount: PropTypes.number.isRequired,
precision: PropTypes.number,
isEstimate: PropTypes.bool,
label: PropTypes.bool,
showFree: PropTypes.bool,
showFullPrice: PropTypes.bool,
showPlus: PropTypes.bool,
look: PropTypes.oneOf(["indicator", "plain", "fee"]),
};
static defaultProps = {
@ -142,7 +143,7 @@ let addressStyle = {
};
export class Address extends React.PureComponent {
static propTypes = {
address: React.PropTypes.string,
address: PropTypes.string,
};
constructor(props) {
@ -174,7 +175,7 @@ export class Address extends React.PureComponent {
export class Thumbnail extends React.PureComponent {
static propTypes = {
src: React.PropTypes.string,
src: PropTypes.string,
};
handleError() {

View file

@ -1,11 +1,12 @@
import React from "react";
import PropTypes from "prop-types";
const { remote } = require("electron");
class FileSelector extends React.PureComponent {
static propTypes = {
type: React.PropTypes.oneOf(["file", "directory"]),
initPath: React.PropTypes.string,
onFileChosen: React.PropTypes.func,
type: PropTypes.oneOf(["file", "directory"]),
initPath: PropTypes.string,
onFileChosen: PropTypes.func,
};
static defaultProps = {

View file

@ -1,4 +1,5 @@
import React from "react";
import PropTypes from "prop-types";
import FormField from "component/formField";
import { Icon } from "component/common.js";
@ -12,7 +13,7 @@ export function formFieldId() {
export class Form extends React.PureComponent {
static propTypes = {
onSubmit: React.PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
};
constructor(props) {
@ -35,15 +36,9 @@ export class Form extends React.PureComponent {
export class FormRow extends React.PureComponent {
static propTypes = {
label: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.element,
]),
errorMessage: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.object,
]),
// helper: React.PropTypes.html,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
errorMessage: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
// helper: PropTypes.html,
};
static defaultProps = {

View file

@ -1,4 +1,5 @@
import React from "react";
import PropTypes from "prop-types";
import FileSelector from "component/file-selector.js";
import SimpleMDE from "react-simplemde-editor";
import { formFieldNestedLabelTypes, formFieldId } from "../form";
@ -8,14 +9,14 @@ const formFieldFileSelectorTypes = ["file", "directory"];
class FormField extends React.PureComponent {
static propTypes = {
type: React.PropTypes.string.isRequired,
prefix: React.PropTypes.string,
postfix: React.PropTypes.string,
hasError: React.PropTypes.bool,
trim: React.PropTypes.bool,
regexp: React.PropTypes.oneOfType([
React.PropTypes.instanceOf(RegExp),
React.PropTypes.string,
type: PropTypes.string.isRequired,
prefix: PropTypes.string,
postfix: PropTypes.string,
hasError: PropTypes.bool,
trim: PropTypes.bool,
regexp: PropTypes.oneOfType([
PropTypes.instanceOf(RegExp),
PropTypes.string,
]),
};

View file

@ -1,10 +1,11 @@
import React from "react";
import PropTypes from "prop-types";
import * as icons from "constants/icons";
export default class Icon extends React.PureComponent {
static propTypes = {
icon: React.PropTypes.string.isRequired,
fixed: React.PropTypes.bool,
icon: PropTypes.string.isRequired,
fixed: PropTypes.bool,
};
static defaultProps = {

View file

@ -1,13 +1,14 @@
import React from "react";
import PropTypes from "prop-types";
import lbry from "../lbry.js";
import { BusyMessage, Icon } from "./common.js";
import Link from "component/link";
class LoadScreen extends React.PureComponent {
static propTypes = {
message: React.PropTypes.string.isRequired,
details: React.PropTypes.string,
isWarning: React.PropTypes.bool,
message: PropTypes.string.isRequired,
details: PropTypes.string,
isWarning: PropTypes.bool,
};
constructor(props) {

View file

@ -1,13 +1,14 @@
import React from "react";
import PropTypes from "prop-types";
import { Icon } from "./common.js";
import Link from "component/link";
export class DropDownMenuItem extends React.PureComponent {
static propTypes = {
href: React.PropTypes.string,
label: React.PropTypes.string,
icon: React.PropTypes.string,
onClick: React.PropTypes.func,
href: PropTypes.string,
label: PropTypes.string,
icon: PropTypes.string,
onClick: PropTypes.func,
};
static defaultProps = {

View file

@ -1,5 +1,10 @@
import React from "react";
import { connect } from "react-redux";
import PublishForm from "./view";
import { selectBalance } from "redux/selectors/wallet";
export default connect(null, null)(PublishForm);
const select = state => ({
balance: selectBalance(state),
});
export default connect(select, null)(PublishForm);

View file

@ -48,11 +48,22 @@ class ChannelSection extends React.PureComponent {
handleNewChannelBidChange(event) {
this.setState({
newChannelBid: event.target.value,
newChannelBid: parseFloat(event.target.value),
});
}
handleCreateChannelClick(event) {
const { balance } = this.props;
const { newChannelBid } = this.state;
if (newChannelBid > balance) {
this.refs.newChannelName.showError(
__("Unable to create channel due to insufficient funds.")
);
return;
}
this.setState({
creatingChannel: true,
});

View file

@ -61,6 +61,15 @@ class PublishForm extends React.PureComponent {
}
handleSubmit() {
const { balance } = this.props;
const { bid } = this.state;
if (bid > balance) {
this.handlePublishError({ message: "insufficient funds" });
return;
}
this.setState({
submitting: true,
});

View file

@ -1,4 +1,5 @@
import React from "react";
import PropTypes from "prop-types";
import lbry from "lbry.js";
import LoadScreen from "../load_screen.js";
import ModalIncompatibleDaemon from "modal/modalIncompatibleDaemon";
@ -8,8 +9,8 @@ import * as modals from "constants/modal_types";
export class SplashScreen extends React.PureComponent {
static propTypes = {
message: React.PropTypes.string,
onLoadDone: React.PropTypes.func,
message: PropTypes.string,
onLoadDone: PropTypes.func,
};
constructor(props) {

View file

@ -1,9 +1,10 @@
import React from "react";
import PropTypes from "prop-types";
export class ToolTip extends React.PureComponent {
static propTypes = {
body: React.PropTypes.string.isRequired,
label: React.PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
};
constructor(props) {

View file

@ -1,10 +1,11 @@
import React from "react";
import PropTypes from "prop-types";
import ReactMarkdown from "react-markdown";
import ReactDOMServer from "react-dom/server";
class TruncatedMarkdown extends React.PureComponent {
static propTypes = {
lines: React.PropTypes.number,
lines: PropTypes.number,
};
static defaultProps = {

View file

@ -1,4 +1,5 @@
import React from "react";
import PropTypes from "prop-types";
import lbryuri from "lbryuri.js";
import { Icon } from "component/common.js";
import { parseQueryParams } from "util/query_params";
@ -7,8 +8,8 @@ class WunderBar extends React.PureComponent {
static TYPING_TIMEOUT = 800;
static propTypes = {
onSearch: React.PropTypes.func.isRequired,
onSubmit: React.PropTypes.func.isRequired,
onSearch: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
};
constructor(props) {

3
src/renderer/flow-typed/electron.js vendored Normal file
View file

@ -0,0 +1,3 @@
declare module 'electron' {
declare module.exports: any;
}

View file

@ -0,0 +1,116 @@
var spawnSync = require('child_process').spawnSync;
var flow = require('flow-bin');
var merge = require('lodash.merge');
var store = {
error: null,
flowOptions: [
'status',
'--color=always',
],
options: {
warn: false,
formatter: function (errorCode, errorDetails) {
return 'Flow: ' + errorCode + '\n\n' + errorDetails;
},
},
};
function flowErrorCode(status) {
var error;
switch (status) {
/*
case 0:
error = null;
break;
*/
case 1:
error = 'Server Initializing';
break;
case 2:
error = 'Type Error';
break;
case 3:
error = 'Out of Time';
break;
case 4:
error = 'Kill Error';
break;
case 6:
error = 'No Server Running';
break;
case 7:
error = 'Out of Retries';
break;
case 8:
error = 'Invalid Flowconfig';
break;
case 9:
error = 'Build Id Mismatch';
break;
case 10:
error = 'Input Error';
break;
case 11:
error = 'Lock Stolen';
break;
case 12:
error = 'Could Not Find Flowconfig';
break;
case 13:
error = 'Server Out of Date';
break;
case 14:
error = 'Server Client Directory Mismatch';
break;
case 15:
error = 'Out of Shared Memory';
break;
}
return error;
}
function checkFlowStatus(compiler, next) {
var res = spawnSync(flow, store.flowOptions);
var status = res.status;
if (status !== 0) {
var errorCode = flowErrorCode(status);
var errorDetails = res.stdout.toString() + res.stderr.toString();
store.error = new Error(store.options.formatter(errorCode, errorDetails));
}
next();
}
function pushError(compilation) {
if (store.error) {
if (store.options.warn) {
compilation.warnings.push(store.error);
} else {
compilation.errors.push(store.error);
}
store.error = null;
}
}
function FlowFlowPlugin(options) {
store.options = merge(store.options, options);
}
FlowFlowPlugin.prototype.apply = function(compiler) {
compiler.plugin('run', checkFlowStatus);
compiler.plugin('watch-run', checkFlowStatus);
compiler.plugin('compilation', pushError);
};
module.exports = FlowFlowPlugin;

View file

@ -1,18 +1,19 @@
import React from "react";
import PropTypes from "prop-types";
import ReactModal from "react-modal";
import Link from "component/link/index";
import app from "app.js";
export class Modal extends React.PureComponent {
static propTypes = {
type: React.PropTypes.oneOf(["alert", "confirm", "custom"]),
overlay: React.PropTypes.bool,
onConfirmed: React.PropTypes.func,
onAborted: React.PropTypes.func,
confirmButtonLabel: React.PropTypes.string,
abortButtonLabel: React.PropTypes.string,
confirmButtonDisabled: React.PropTypes.bool,
abortButtonDisabled: React.PropTypes.bool,
type: PropTypes.oneOf(["alert", "confirm", "custom"]),
overlay: PropTypes.bool,
onConfirmed: PropTypes.func,
onAborted: PropTypes.func,
confirmButtonLabel: PropTypes.string,
abortButtonLabel: PropTypes.string,
confirmButtonDisabled: PropTypes.bool,
abortButtonDisabled: PropTypes.bool,
};
static defaultProps = {
@ -64,8 +65,8 @@ export class Modal extends React.PureComponent {
export class ExpandableModal extends React.PureComponent {
static propTypes = {
expandButtonLabel: React.PropTypes.string,
extraContent: React.PropTypes.element,
expandButtonLabel: PropTypes.string,
extraContent: PropTypes.element,
};
static defaultProps = {

View file

@ -102,8 +102,8 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
const fileInfo = byOutpoint[outpoint];
if (fileInfo) {
txid = fileInfo.outpoint.slice(0, -2);
nout = fileInfo.outpoint.slice(-1);
const txid = fileInfo.outpoint.slice(0, -2);
const nout = fileInfo.outpoint.slice(-1);
dispatch(doAbandonClaim(txid, nout));
}

View file

@ -1,22 +1,60 @@
// @flow
import * as types from "constants/action_types";
import * as modalTypes from "constants/modal_types";
const { remote } = require("electron");
const application = remote.app;
const win = remote.BrowserWindow.getFocusedWindow();
const reducers = {};
const defaultState = {
export type SnackBar = {
message: string,
linkText: string,
linkTarget: string,
isError: boolean,
};
export type AppState = {
isLoaded: boolean,
modal: ?string,
modalProps: mixed,
platform: string,
upgradeSkipped: boolean,
daemonVersionMatched: ?boolean,
daemonReady: boolean,
hasSignature: boolean,
badgeNumber: number,
volume: number,
downloadProgress: ?number,
upgradeDownloading: ?boolean,
upgradeDownloadComplete: ?boolean,
checkUpgradeTimer: ?number,
isUpgradeAvailable: ?boolean,
isUpgradeSkipped: ?boolean,
snackBar: ?SnackBar,
};
const defaultState: AppState = {
isLoaded: false,
modal: null,
modalProps: {},
platform: process.platform,
upgradeSkipped: sessionStorage.getItem("upgradeSkipped"),
upgradeSkipped: sessionStorage.getItem("upgradeSkipped") === "true",
daemonVersionMatched: null,
daemonReady: false,
hasSignature: false,
badgeNumber: 0,
volume: sessionStorage.getItem("volume") || 1,
volume: Number(sessionStorage.getItem("volume")) || 1,
downloadProgress: undefined,
upgradeDownloading: undefined,
upgradeDownloadComplete: undefined,
checkUpgradeTimer: undefined,
isUpgradeAvailable: undefined,
isUpgradeSkipped: undefined,
snackBar: undefined,
};
reducers[types.DAEMON_READY] = function(state, action) {
@ -61,7 +99,7 @@ reducers[types.UPGRADE_DOWNLOAD_STARTED] = function(state, action) {
};
reducers[types.SKIP_UPGRADE] = function(state, action) {
sessionStorage.setItem("upgradeSkipped", true);
sessionStorage.setItem("upgradeSkipped", "true");
return Object.assign({}, state, {
isUpgradeSkipped: true,
@ -164,7 +202,7 @@ reducers[types.VOLUME_CHANGED] = function(state, action) {
});
};
export default function reducer(state = defaultState, action) {
export default function reducer(state: AppState = defaultState, action: any) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
return state;

View file

@ -22,7 +22,7 @@ function rewardMessage(type, amount) {
amount
),
many_downloads: __(
"You earned %s LBC for downloading some of the things.",
"You earned %s LBC for downloading a bunch of things.",
amount
),
first_publish: __(
@ -33,6 +33,10 @@ function rewardMessage(type, amount) {
"You earned %s LBC for watching a featured download.",
amount
),
referral: __(
"You earned %s LBC for referring someone.",
amount
),
}[type];
}