Merge remote-tracking branch 'origin/master' into rewards3

This commit is contained in:
Jeremy Kauffman 2017-07-24 18:09:37 -04:00
commit ac34faea80
15 changed files with 94 additions and 37 deletions

View file

@ -13,6 +13,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
* Support markdown makeup in claim description * Support markdown makeup in claim description
* Replaced free speech flag (used when image is missing) with labeled color tiles * Replaced free speech flag (used when image is missing) with labeled color tiles
* Added a loading message to file actions * Added a loading message to file actions
* URL is auto suggested in Publish Page
### Changed ### Changed
* Publishes now uses claims rather than files * Publishes now uses claims rather than files
@ -28,6 +29,11 @@ Web UI version numbers should always match the corresponding version of LBRY App
* Restored feedback on claim amounts * Restored feedback on claim amounts
* Fixed hiding price input when Free is checked on publish form * Fixed hiding price input when Free is checked on publish form
* Fixed hiding new identity fields on publish form * Fixed hiding new identity fields on publish form
* Fixed files on downloaded tab not showing download progress
* Fixed downloading files that are deleted not being removed from the downloading list
* Fixed download progress bar not being cleared when a downloading file is deleted
* Fixed refresh regression after adding scroll position to history state
* Fixed app thinking downloads with 0 progress were downloaded after restart
### Deprecated ### Deprecated
* *

View file

@ -46,8 +46,8 @@ dir dist # verify that binary was built/named correctly
# sign binary # sign binary
nuget install secure-file -ExcludeVersion nuget install secure-file -ExcludeVersion
secure-file\tools\secure-file -decrypt build\lbry2.pfx.enc -secret "$env:pfx_key" secure-file\tools\secure-file -decrypt build\lbry3.pfx.enc -secret "$env:pfx_key"
& ${env:SIGNTOOL_PATH} sign /f build\lbry2.pfx /p "$env:key_pass" /tr http://tsa.starfieldtech.com /td SHA256 /fd SHA256 dist\*.exe & ${env:SIGNTOOL_PATH} sign /f build\lbry3.pfx /p "$env:key_pass" /tr http://tsa.starfieldtech.com /td SHA256 /fd SHA256 dist\*.exe
python build\upload_assets.py python build\upload_assets.py

Binary file not shown.

BIN
build/lbry3.pfx.enc Normal file

Binary file not shown.

View file

@ -13,6 +13,7 @@ import { doFetchDaemonSettings } from "actions/settings";
import { doAuthenticate } from "actions/user"; import { doAuthenticate } from "actions/user";
import { doFileList } from "actions/file_info"; import { doFileList } from "actions/file_info";
import { toQueryString } from "util/query_params"; import { toQueryString } from "util/query_params";
import { parseQueryParams } from "util/query_params";
const { remote, ipcRenderer, shell } = require("electron"); const { remote, ipcRenderer, shell } = require("electron");
const path = require("path"); const path = require("path");
@ -76,6 +77,7 @@ export function doChangePath(path, options = {}) {
export function doHistoryBack() { export function doHistoryBack() {
return function(dispatch, getState) { return function(dispatch, getState) {
if (!history.state) return; if (!history.state) return;
if (history.state.index === 0) return;
history.back(); history.back();
}; };
@ -260,7 +262,9 @@ export function doAlertError(errorList) {
export function doDaemonReady() { export function doDaemonReady() {
return function(dispatch, getState) { return function(dispatch, getState) {
history.replaceState({}, document.title, `#/discover`); const path = window.location.hash || "#/discover";
const params = parseQueryParams(path.split("?")[1] || "");
history.replaceState({ params, index: 0 }, document.title, `${path}`);
dispatch(doAuthenticate()); dispatch(doAuthenticate());
dispatch({ dispatch({
type: types.DAEMON_READY, type: types.DAEMON_READY,

View file

@ -5,7 +5,7 @@ import lbryuri from "lbryuri";
import { selectBalance } from "selectors/wallet"; import { selectBalance } from "selectors/wallet";
import { import {
selectFileInfoForUri, selectFileInfoForUri,
selectUrisDownloading, selectDownloadingByOutpoint,
} from "selectors/file_info"; } from "selectors/file_info";
import { selectResolvingUris } from "selectors/content"; import { selectResolvingUris } from "selectors/content";
import { selectCostInfoForUri } from "selectors/cost_info"; import { selectCostInfoForUri } from "selectors/cost_info";
@ -265,8 +265,9 @@ export function doPurchaseUri(uri, purchaseModalName) {
const state = getState(); const state = getState();
const balance = selectBalance(state); const balance = selectBalance(state);
const fileInfo = selectFileInfoForUri(state, { uri }); const fileInfo = selectFileInfoForUri(state, { uri });
const downloadingByUri = selectUrisDownloading(state); const downloadingByOutpoint = selectDownloadingByOutpoint(state);
const alreadyDownloading = !!downloadingByUri[uri]; const alreadyDownloading =
fileInfo && !!downloadingByOutpoint[fileInfo.outpoint];
// we already fully downloaded the file. // we already fully downloaded the file.
if (fileInfo && fileInfo.completed) { if (fileInfo && fileInfo.completed) {

View file

@ -10,8 +10,11 @@ import {
selectIsFetchingFileList, selectIsFetchingFileList,
selectFileInfosByOutpoint, selectFileInfosByOutpoint,
selectUrisLoading, selectUrisLoading,
selectTotalDownloadProgress,
} from "selectors/file_info"; } from "selectors/file_info";
import { doCloseModal } from "actions/app"; import { doCloseModal, doHistoryBack } from "actions/app";
import setProgressBar from "util/setProgressBar";
import batchActions from "util/batchActions";
const { shell } = require("electron"); const { shell } = require("electron");
@ -119,7 +122,22 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
}, },
}); });
dispatch(doCloseModal()); const totalProgress = selectTotalDownloadProgress(getState());
setProgressBar(totalProgress);
};
}
export function doDeleteFileAndGoBack(
fileInfo,
deleteFromComputer,
abandonClaim
) {
return function(dispatch, getState) {
const actions = [];
actions.push(doCloseModal());
actions.push(doHistoryBack());
actions.push(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim));
dispatch(batchActions(...actions));
}; };
} }

View file

@ -118,7 +118,10 @@ class FileActions extends React.PureComponent {
/> />
</div> </div>
); );
} else if (fileInfo === null && !downloading) { } else if (
(fileInfo === null || (fileInfo && fileInfo.written_bytes === 0)) &&
!downloading
) {
if (!costInfo) { if (!costInfo) {
content = <BusyMessage message={__("Fetching cost info")} />; content = <BusyMessage message={__("Fetching cost info")} />;
} else { } else {

View file

@ -1,8 +1,9 @@
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { doCloseModal, doHistoryBack } from "actions/app"; import { doCloseModal, doHistoryBack } from "actions/app";
import { doDeleteFile } from "actions/file_info"; import { doDeleteFileAndGoBack } from "actions/file_info";
import { makeSelectClaimForUriIsMine } from "selectors/claims"; import { makeSelectClaimForUriIsMine } from "selectors/claims";
import batchActions from "util/batchActions";
import ModalRemoveFile from "./view"; import ModalRemoveFile from "./view";
@ -19,8 +20,7 @@ const makeSelect = () => {
const perform = dispatch => ({ const perform = dispatch => ({
closeModal: () => dispatch(doCloseModal()), closeModal: () => dispatch(doCloseModal()),
deleteFile: (fileInfo, deleteFromComputer, abandonClaim) => { deleteFile: (fileInfo, deleteFromComputer, abandonClaim) => {
dispatch(doHistoryBack()); dispatch(doDeleteFileAndGoBack(fileInfo, deleteFromComputer, abandonClaim));
dispatch(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim));
}, },
}); });

View file

@ -43,6 +43,7 @@ class PublishForm extends React.PureComponent {
creatingChannel: false, creatingChannel: false,
modal: null, modal: null,
isFee: false, isFee: false,
customUrl: false,
}; };
} }
@ -203,6 +204,9 @@ class PublishForm extends React.PureComponent {
handleNameChange(event) { handleNameChange(event) {
var rawName = event.target.value; var rawName = event.target.value;
this.setState({
customUrl: Boolean(rawName.length),
});
this.nameChanged(rawName); this.nameChanged(rawName);
} }
@ -445,11 +449,24 @@ class PublishForm extends React.PureComponent {
onFileChange() { onFileChange() {
if (this.refs.file.getValue()) { if (this.refs.file.getValue()) {
this.setState({ hasFile: true }); this.setState({ hasFile: true });
if (!this.state.customUrl) {
let fileName = this._getFileName(this.refs.file.getValue());
this.nameChanged(fileName);
}
} else { } else {
this.setState({ hasFile: false }); this.setState({ hasFile: false });
} }
} }
_getFileName(fileName) {
const path = require("path");
const extension = path.extname(fileName);
fileName = path.basename(fileName, extension);
fileName = fileName.replace(lbryuri.REGEXP_INVALID_URI, "");
return fileName;
}
getNameBidHelpText() { getNameBidHelpText() {
if (this.state.prefillDone) { if (this.state.prefillDone) {
return __("Existing claim data was prefilled"); return __("Existing claim data was prefilled");

View file

@ -34,7 +34,6 @@ class UserEmailVerify extends React.PureComponent {
<FormRow <FormRow
type="text" type="text"
label={__("Verification Code")} label={__("Verification Code")}
placeholder="a94bXXXXXXXXXXXXXX"
name="code" name="code"
value={this.state.code} value={this.state.code}
onChange={event => { onChange={event => {
@ -45,7 +44,7 @@ class UserEmailVerify extends React.PureComponent {
{/* render help separately so it always shows */} {/* render help separately so it always shows */}
<div className="form-field__helper"> <div className="form-field__helper">
<p> <p>
{__("Email")}{" "} {__("Check your email for a verification code. Email")}{" "}
<Link href="mailto:help@lbry.io" label="help@lbry.io" />{" "} <Link href="mailto:help@lbry.io" label="help@lbry.io" />{" "}
{__("if you did not receive or are having trouble with your code.")} {__("if you did not receive or are having trouble with your code.")}
</p> </p>

View file

@ -291,7 +291,7 @@ lbry.setClientSetting = function(setting, value) {
lbry.formatName = function(name) { lbry.formatName = function(name) {
// Converts LBRY name to standard format (all lower case, no special characters, spaces replaced by dashes) // Converts LBRY name to standard format (all lower case, no special characters, spaces replaced by dashes)
name = name.replace("/s+/g", "-"); name = name.replace("/s+/g", "-");
name = name.toLowerCase().replace(/[^a-z0-9\-]/g, ""); name = name.toLowerCase().replace(lbryuri.REGEXP_INVALID_URI, "");
return name; return name;
}; };

View file

@ -3,6 +3,8 @@ const CLAIM_ID_MAX_LEN = 40;
const lbryuri = {}; const lbryuri = {};
lbryuri.REGEXP_INVALID_URI = /[^A-Za-z0-9-]/g;
/** /**
* Parses a LBRY name into its component parts. Throws errors with user-friendly * Parses a LBRY name into its component parts. Throws errors with user-friendly
* messages for invalid names. * messages for invalid names.
@ -70,7 +72,7 @@ lbryuri.parse = function(uri, requireProto = false) {
contentName = path; contentName = path;
} }
const nameBadChars = (channelName || name).match(/[^A-Za-z0-9-]/g); const nameBadChars = (channelName || name).match(lbryuri.REGEXP_INVALID_URI);
if (nameBadChars) { if (nameBadChars) {
throw new Error( throw new Error(
__( __(
@ -119,7 +121,7 @@ lbryuri.parse = function(uri, requireProto = false) {
throw new Error(__("Only channel URIs may have a path.")); throw new Error(__("Only channel URIs may have a path."));
} }
const pathBadChars = path.match(/[^A-Za-z0-9-]/g); const pathBadChars = path.match(lbryuri.REGEXP_INVALID_URI);
if (pathBadChars) { if (pathBadChars) {
throw new Error( throw new Error(
__(`Invalid character in path: %s`, pathBadChars.join(", ")) __(`Invalid character in path: %s`, pathBadChars.join(", "))

View file

@ -58,15 +58,15 @@ reducers[types.DOWNLOADING_STARTED] = function(state, action) {
const { uri, outpoint, fileInfo } = action.data; const { uri, outpoint, fileInfo } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint); const newByOutpoint = Object.assign({}, state.byOutpoint);
const newDownloading = Object.assign({}, state.urisDownloading); const newDownloading = Object.assign({}, state.downloadingByOutpoin);
const newLoading = Object.assign({}, state.urisLoading); const newLoading = Object.assign({}, state.urisLoading);
newDownloading[uri] = true; newDownloading[outpoint] = true;
newByOutpoint[outpoint] = fileInfo; newByOutpoint[outpoint] = fileInfo;
delete newLoading[uri]; delete newLoading[uri];
return Object.assign({}, state, { return Object.assign({}, state, {
urisDownloading: newDownloading, downloadingByOutpoint: newDownloading,
urisLoading: newLoading, urisLoading: newLoading,
byOutpoint: newByOutpoint, byOutpoint: newByOutpoint,
}); });
@ -76,14 +76,14 @@ reducers[types.DOWNLOADING_PROGRESSED] = function(state, action) {
const { uri, outpoint, fileInfo } = action.data; const { uri, outpoint, fileInfo } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint); const newByOutpoint = Object.assign({}, state.byOutpoint);
const newDownloading = Object.assign({}, state.urisDownloading); const newDownloading = Object.assign({}, state.downloadingByOutpoint);
newByOutpoint[outpoint] = fileInfo; newByOutpoint[outpoint] = fileInfo;
newDownloading[uri] = true; newDownloading[outpoint] = true;
return Object.assign({}, state, { return Object.assign({}, state, {
byOutpoint: newByOutpoint, byOutpoint: newByOutpoint,
urisDownloading: newDownloading, downloadingByOutpoint: newDownloading,
}); });
}; };
@ -91,14 +91,14 @@ reducers[types.DOWNLOADING_COMPLETED] = function(state, action) {
const { uri, outpoint, fileInfo } = action.data; const { uri, outpoint, fileInfo } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint); const newByOutpoint = Object.assign({}, state.byOutpoint);
const newDownloading = Object.assign({}, state.urisDownloading); const newDownloading = Object.assign({}, state.downloadingByOutpoint);
newByOutpoint[outpoint] = fileInfo; newByOutpoint[outpoint] = fileInfo;
delete newDownloading[uri]; delete newDownloading[outpoint];
return Object.assign({}, state, { return Object.assign({}, state, {
byOutpoint: newByOutpoint, byOutpoint: newByOutpoint,
urisDownloading: newDownloading, downloadingByOutpoint: newDownloading,
}); });
}; };
@ -106,11 +106,14 @@ reducers[types.FILE_DELETE] = function(state, action) {
const { outpoint } = action.data; const { outpoint } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint); const newByOutpoint = Object.assign({}, state.byOutpoint);
const downloadingByOutpoint = Object.assign({}, state.downloadingByOutpoint);
delete newByOutpoint[outpoint]; delete newByOutpoint[outpoint];
delete downloadingByOutpoint[outpoint];
return Object.assign({}, state, { return Object.assign({}, state, {
byOutpoint: newByOutpoint, byOutpoint: newByOutpoint,
downloadingByOutpoint,
}); });
}; };

View file

@ -39,14 +39,18 @@ export const makeSelectFileInfoForUri = () => {
return createSelector(selectFileInfoForUri, fileInfo => fileInfo); return createSelector(selectFileInfoForUri, fileInfo => fileInfo);
}; };
export const selectUrisDownloading = createSelector( export const selectDownloadingByOutpoint = createSelector(
_selectState, _selectState,
state => state.urisDownloading || {} state => state.downloadingByOutpoint || {}
); );
const selectDownloadingForUri = (state, props) => { const selectDownloadingForUri = (state, props) => {
const byUri = selectUrisDownloading(state); const byOutpoint = selectDownloadingByOutpoint(state);
return byUri[props.uri]; const fileInfo = selectFileInfoForUri(state, props);
if (!fileInfo) return false;
return byOutpoint[fileInfo.outpoint];
}; };
export const makeSelectDownloadingForUri = () => { export const makeSelectDownloadingForUri = () => {
@ -135,14 +139,14 @@ export const selectFileInfosByUri = createSelector(
); );
export const selectDownloadingFileInfos = createSelector( export const selectDownloadingFileInfos = createSelector(
selectUrisDownloading, selectDownloadingByOutpoint,
selectFileInfosByUri, selectFileInfosByOutpoint,
(urisDownloading, byUri) => { (downloadingByOutpoint, fileInfosByOutpoint) => {
const uris = Object.keys(urisDownloading); const outpoints = Object.keys(downloadingByOutpoint);
const fileInfos = []; const fileInfos = [];
uris.forEach(uri => { outpoints.forEach(outpoint => {
const fileInfo = byUri[uri]; const fileInfo = fileInfosByOutpoint[outpoint];
if (fileInfo) fileInfos.push(fileInfo); if (fileInfo) fileInfos.push(fileInfo);
}); });