Merge branch 'master' into css_patch

This commit is contained in:
Baltazar Gomez 2017-09-28 20:30:27 -06:00 committed by GitHub
commit 2e28582277
33 changed files with 288 additions and 199 deletions

View file

@ -8,15 +8,24 @@ Web UI version numbers should always match the corresponding version of LBRY App
## [Unreleased]
### Added
* Add setting to automatically purchase low-cost content without a confirmation dialog
* New custom styled scrollbar [#574](https://github.com/lbryio/lbry-app/pull/574)
*
### Changed
* Updated the daemon from 0.16.1 to [0.16.3](https://github.com/lbryio/lbry/releases/tag/v0.16.3) to improve download performance and download issue detection.
* Changed the File page to make it clearer how to to open the folder for a file.
* Improved tabs styles with a nice animation. [#547](https://github.com/lbryio/lbry-app/pull/576)
* Display search bar on discover page instead of title and remove duplicated icon.
* Minor update for themes.
*
### Fixed
* Improve layout (and implementation) of the icon panel in file tiles and cards
* The folder icon representing a local download now shows up properly on Channel pages (#587)
* While editing a publish, the URL will no longer change if you select a new file. (#601)
* Fixed issues with opening the folder for a file (#606)
* Be consistent with the step property on credit inputs (#604)
* Fixed unresponsive header [#613](https://github.com/lbryio/lbry-app/issues/613)
* Fixed dark theme issues with text content.
* Minor css fixes.

3
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,3 @@
## Contributing to LBRY
https://lbry.io/faq/contributing

View file

@ -49,43 +49,49 @@ to create distributable packages, which is run by calling:
## Development on Windows
### Windows Dependency
1. Download and install `npm` and `node` from <a href="https://nodejs.org/en/download/current/">nodejs.org<a>
2. Download and install `python 2.7` from <a href="https://www.python.org/downloads/windows/">python.org</a>
3. Download and Install `Microsoft Visual C++ Compiler for Python 2.7` from <a href="https://www.microsoft.com/en-us/download/confirmation.aspx?id=44266">Microsoft<a>
4. Download and install `.NET Framework 2.0 Software Development Kit (SDK) (x64)` from <a href="https://www.microsoft.com/en-gb/download/details.aspx?id=15354">Microsoft<a>
1. Download and install `git` from <a href="https://git-for-windows.github.io/">github.io<a> (configure to use command prompt integration)
2. Download and install `npm` and `node` from <a href="https://nodejs.org/en/download/current/">nodejs.org<a>
3. Download and install `python 2.7` from <a href="https://www.python.org/downloads/windows/">python.org</a>
4. Download and Install `Microsoft Visual C++ Compiler for Python 2.7` from <a href="https://www.microsoft.com/en-us/download/confirmation.aspx?id=44266">Microsoft<a>
5. Download and install `.NET Framework 2.0 Software Development Kit (SDK) (x64)` from <a href="https://www.microsoft.com/en-gb/download/details.aspx?id=15354">Microsoft<a> (may need to extract setup.exe and install manually by running install.exe as Administrator)
### One-time Setup
1. Open command prompt in the root of the project and run the following;
1. Open command prompt as adminstrator and run the following:
```
npm install --global --production windows-build-tools
exit
```
2. Open command prompt in the root of the project and run the following:
```
python -m pip install -r build\requirements.txt
python build\set_version.py
npm install -g yarn
yarn install
```
2. Change directory to `app` and run the following;
3. Change directory to `app` and run the following;
```
yarn install
node_modules\.bin\electron-rebuild
node_modules\.bin\electron-rebuild
cd ..
```
3. Change directory to `ui` and run the following
4. Change directory to `ui` and run the following:
```
yarn install
npm rebuild node-sass
node node_modules\node-sass\bin\node-sass --output dist\css --sourcemap=none scss\
node_modules\.bin\webpack --config webpack.dev.config.js
xcopy dist ..\app\dist
xcopy /E dist ..\app\dist
cd ..
```
4. Download the lbry daemon and cli binaries and place them in `app\dist\`
4. Download the lbry daemon and cli [binaries](https://github.com/lbryio/lbry/releases) and place them in `app\dist\`
### Building lbry-app
1. run `node_modules\.bin\build -p never` from the root of the project.
### Running the electron app
1. Run `./node_modules/.bin/electron app`
1. Run `node_modules\.bin\electron app`
### Ongoing Development
1. `cd ui`

View file

@ -20,7 +20,7 @@
"electron-rebuild": "^1.5.11"
},
"lbrySettings": {
"lbrynetDaemonVersion": "0.16.1",
"lbrynetDaemonVersion": "0.16.3",
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-daemon-vDAEMONVER-OSNAME.zip"
},
"license": "MIT"

View file

@ -1,5 +1,4 @@
import * as types from "constants/action_types";
import * as settings from "constants/settings";
import lbry from "lbry";
import {
selectUpdateUrl,
@ -8,6 +7,7 @@ import {
selectUpgradeFilename,
} from "selectors/app";
import { doFetchDaemonSettings } from "actions/settings";
import { doBalanceSubscribe } from "actions/wallet";
import { doAuthenticate } from "actions/user";
import { doFetchFileInfosAndPublishedClaims } from "actions/file_info";
@ -178,6 +178,7 @@ export function doDaemonReady() {
dispatch(doAuthenticate());
dispatch({ type: types.DAEMON_READY });
dispatch(doFetchDaemonSettings());
dispatch(doBalanceSubscribe());
dispatch(doFetchFileInfosAndPublishedClaims());
};
}

View file

@ -1,4 +1,5 @@
import * as types from "constants/action_types";
import * as settings from "constants/settings";
import lbry from "lbry";
import lbryio from "lbryio";
import lbryuri from "lbryuri";
@ -322,29 +323,56 @@ export function doPurchaseUri(uri) {
const downloadingByOutpoint = selectDownloadingByOutpoint(state);
const alreadyDownloading =
fileInfo && !!downloadingByOutpoint[fileInfo.outpoint];
const costInfo = makeSelectCostInfoForUri(uri)(state);
const { cost } = costInfo;
if (
alreadyDownloading ||
(fileInfo && fileInfo.completed && fileInfo.written_bytes > 0)
) {
return;
function attemptPlay(cost, instantPurchaseMax = null) {
if (cost > 0 && (!instantPurchaseMax || cost > instantPurchaseMax)) {
dispatch(doOpenModal(modals.AFFIRM_PURCHASE, { uri }));
} else {
dispatch(doLoadVideo(uri));
}
}
// we already fully downloaded the file.
if (
cost === 0 ||
(fileInfo && (fileInfo.completed || fileInfo.download_directory))
) {
return dispatch(doLoadVideo(uri));
if (fileInfo && fileInfo.completed) {
// If written_bytes is false that means the user has deleted/moved the
// file manually on their file system, so we need to dispatch a
// doLoadVideo action to reconstruct the file from the blobs
if (!fileInfo.written_bytes) dispatch(doLoadVideo(uri));
return Promise.resolve();
}
// we are already downloading the file
if (alreadyDownloading) {
return Promise.resolve();
}
const costInfo = makeSelectCostInfoForUri(uri)(state);
const { cost } = costInfo;
if (cost > balance) {
return dispatch(doOpenModal(modals.INSUFFICIENT_CREDITS));
dispatch(doOpenModal(modals.INSUFFICIENT_CREDITS));
return Promise.resolve();
}
return dispatch(doOpenModal(modals.AFFIRM_PURCHASE, { uri }));
if (
cost == 0 ||
!lbry.getClientSetting(settings.INSTANT_PURCHASE_ENABLED)
) {
attemptPlay(cost);
} else {
const instantPurchaseMax = lbry.getClientSetting(
settings.INSTANT_PURCHASE_MAX
);
if (instantPurchaseMax.currency == "LBC") {
attemptPlay(cost, instantPurchaseMax.amount);
} else {
// Need to convert currency of instant purchase maximum before trying to play
lbryio.getExchangeRates().then(({ lbc_usd }) => {
attemptPlay(cost, instantPurchaseMax.amount / lbc_usd);
});
}
}
};
}

View file

@ -9,12 +9,23 @@ import { doOpenModal, doShowSnackBar } from "actions/app";
import { doNavigate } from "actions/navigation";
import * as modals from "constants/modal_types";
export function doUpdateBalance(balance) {
return {
type: types.UPDATE_BALANCE,
data: {
balance: balance,
},
export function doUpdateBalance() {
return function(dispatch, getState) {
lbry.wallet_balance().then(balance => {
return dispatch({
type: types.UPDATE_BALANCE,
data: {
balance: balance,
},
});
});
};
}
export function doBalanceSubscribe() {
return function(dispatch, getState) {
dispatch(doUpdateBalance());
setInterval(() => dispatch(doUpdateBalance()), 5000);
};
}

View file

@ -5,7 +5,6 @@ import { selectUser } from "selectors/user";
import { doCheckUpgradeAvailable, doAlertError } from "actions/app";
import { doRecordScroll } from "actions/navigation";
import { doFetchRewardedContent } from "actions/content";
import { doUpdateBalance } from "actions/wallet";
import App from "./view";
const select = (state, props) => ({
@ -16,7 +15,6 @@ const select = (state, props) => ({
const perform = dispatch => ({
alertError: errorList => dispatch(doAlertError(errorList)),
checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()),
updateBalance: balance => dispatch(doUpdateBalance(balance)),
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
});

View file

@ -10,7 +10,6 @@ class App extends React.PureComponent {
const {
alertError,
checkUpgradeAvailable,
updateBalance,
fetchRewardedContent,
} = this.props;
@ -22,10 +21,6 @@ class App extends React.PureComponent {
checkUpgradeAvailable();
}
lbry.balanceSubscribe(balance => {
updateBalance(balance);
});
fetchRewardedContent();
this.scrollListener = () => this.props.recordScroll(window.scrollY);

View file

@ -2,12 +2,13 @@ import React from "react";
import lbryuri from "lbryuri.js";
import CardMedia from "component/cardMedia";
import Link from "component/link";
import { TruncatedText, Icon } from "component/common";
import IconFeatured from "component/iconFeatured";
import { TruncatedText } from "component/common";
import Icon from "component/icon";
import FilePrice from "component/filePrice";
import UriIndicator from "component/uriIndicator";
import NsfwOverlay from "component/nsfwOverlay";
import TruncatedMarkdown from "component/truncatedMarkdown";
import * as icons from "constants/icons";
class FileCard extends React.PureComponent {
constructor(props) {
@ -94,11 +95,12 @@ class FileCard extends React.PureComponent {
<TruncatedText lines={1}>{title}</TruncatedText>
</div>
<div className="card__subtitle">
<span style={{ float: "right" }}>
<span className="card__indicators">
<FilePrice uri={uri} />
{isRewardContent && <span>{" "}<IconFeatured /></span>}
{fileInfo &&
<span>{" "}<Icon fixed icon="icon-folder" /></span>}
{" "}
{isRewardContent && <Icon icon={icons.FEATURED} />}
{" "}
{fileInfo && <Icon icon={icons.LOCAL} />}
</span>
<UriIndicator uri={uri} />
</div>

View file

@ -29,8 +29,9 @@ class FileDetails extends React.PureComponent {
const { description, language, license } = metadata;
const { height } = claim;
const mediaType = lbry.getMediaType(contentType);
const directory = fileInfo && fileInfo.download_path
? path.dirname(fileInfo.download_path)
const downloadPath = fileInfo
? path.normalize(fileInfo.download_path)
: null;
return (
@ -59,12 +60,12 @@ class FileDetails extends React.PureComponent {
<tr>
<td>{__("License")}</td><td>{license}</td>
</tr>
{directory &&
{downloadPath &&
<tr>
<td>{__("Downloaded to")}</td>
<td>
<Link onClick={() => openFolder(directory)}>
{directory}
<Link onClick={() => openFolder(downloadPath)}>
{downloadPath}
</Link>
</td>
</tr>}

View file

@ -87,7 +87,8 @@ class FileList extends React.PureComponent {
<FileTile
key={fileInfo.outpoint || fileInfo.claim_id}
uri={uri}
hidePrice={true}
showPrice={false}
showLocal={false}
showActions={true}
showEmpty={this.props.fileTileShowEmpty}
/>

View file

@ -1,4 +1,5 @@
import React from "react";
import * as icons from "constants/icons";
import lbryuri from "lbryuri.js";
import CardMedia from "component/cardMedia";
import FileActions from "component/fileActions";
@ -6,12 +7,17 @@ import Link from "component/link";
import { TruncatedText } from "component/common.js";
import FilePrice from "component/filePrice";
import NsfwOverlay from "component/nsfwOverlay";
import IconFeatured from "component/iconFeatured";
import Icon from "component/icon";
class FileTile extends React.PureComponent {
static SHOW_EMPTY_PUBLISH = "publish";
static SHOW_EMPTY_PENDING = "pending";
static defaultProps = {
showPrice: true,
showLocal: true,
};
constructor(props) {
super(props);
this.state = {
@ -59,8 +65,10 @@ class FileTile extends React.PureComponent {
isResolvingUri,
showEmpty,
navigate,
hidePrice,
showPrice,
showLocal,
rewardedContentClaimIds,
fileInfo,
} = this.props;
const uri = lbryuri.normalize(this.props.uri);
@ -111,8 +119,13 @@ class FileTile extends React.PureComponent {
<CardMedia title={title} thumbnail={thumbnail} />
<div className="file-tile__content">
<div className="card__title-primary">
{!hidePrice ? <FilePrice uri={this.props.uri} /> : null}
{isRewardContent && <IconFeatured />}
<span className="card__indicators">
{showPrice && <FilePrice uri={this.props.uri} />}
{" "}
{isRewardContent && <Icon icon={icons.FEATURED} />}
{" "}
{showLocal && fileInfo && <Icon icon={icons.LOCAL} />}
</span>
<div className="meta">{uri}</div>
<h3>
<TruncatedText lines={1}>{title}</TruncatedText>

View file

@ -0,0 +1,5 @@
import React from "react";
import { connect } from "react-redux";
import Icon from "./view";
export default connect(null, null)(Icon);

View file

@ -0,0 +1,40 @@
import React from "react";
import * as icons from "constants/icons";
export default class Icon extends React.PureComponent {
static propTypes = {
icon: React.PropTypes.string.isRequired,
fixed: React.PropTypes.bool,
};
static defaultProps = {
fixed: false,
};
getIconClass() {
const { icon } = this.props;
return icon.startsWith("icon-") ? icon : "icon-" + icon;
}
getIconTitle() {
switch (this.props.icon) {
case icons.FEATURED:
return __("Watch this and earn rewards.");
case icons.LOCAL:
return __("You have a copy of this file.");
default:
return "";
}
}
render() {
const className = this.getIconClass(),
title = this.getIconTitle();
const spanClassName =
"icon " + className + (this.props.fixed ? " icon-fixed-width " : "");
return <span className={spanClassName} title={title} />;
}
}

View file

@ -1,5 +0,0 @@
import React from "react";
import { connect } from "react-redux";
import IconFeatured from "./view";
export default connect(null, null)(IconFeatured);

View file

@ -1,15 +0,0 @@
import React from "react";
import { Icon } from "component/common.js";
const IconFeatured = props => {
return (
<span
className="icon-featured"
title={__("Watch content with this icon to earn weekly rewards.")}
>
<Icon icon="icon-rocket" fixed className="card__icon-featured-content" />
</span>
);
};
export default IconFeatured;

View file

@ -20,6 +20,7 @@ class PublishForm extends React.PureComponent {
this.state = {
id: null,
uri: null,
rawName: "",
name: "",
bid: 10,
@ -166,7 +167,6 @@ class PublishForm extends React.PureComponent {
claim() {
const { claimsByUri } = this.props;
const { uri } = this.state;
return claimsByUri[uri];
}
@ -437,9 +437,10 @@ class PublishForm extends React.PureComponent {
}
onFileChange() {
const { mode } = this.state;
if (this.refs.file.getValue()) {
this.setState({ hasFile: true });
if (!this.state.customUrl) {
if (!this.state.customUrl && mode !== "edit") {
let fileName = this._getFileName(this.refs.file.getValue());
this.nameChanged(fileName);
}
@ -822,7 +823,7 @@ class PublishForm extends React.PureComponent {
<FormRow
ref="bid"
type="number"
step="0.01"
step="0.1"
label={__("Deposit")}
postfix="LBC"
onChange={event => {

View file

@ -33,7 +33,7 @@ class WalletSend extends React.PureComponent {
<FormRow
label={__("Amount")}
postfix={__("LBC")}
step="0.01"
step="0.1"
min="0"
type="number"
placeholder="1.23"

2
ui/js/constants/icons.js Normal file
View file

@ -0,0 +1,2 @@
export const FEATURED = "rocket";
export const LOCAL = "folder";

View file

@ -6,5 +6,7 @@ export const NEW_USER_ACKNOWLEDGED = "welcome_acknowledged";
export const LANGUAGE = "language";
export const SHOW_NSFW = "showNsfw";
export const SHOW_UNAVAILABLE = "showUnavailable";
export const INSTANT_PURCHASE_ENABLED = "instantPurchaseEnabled";
export const INSTANT_PURCHASE_MAX = "instantPurchaseMax";
export const THEME = "theme";
export const THEMES = "themes";

View file

@ -37,10 +37,12 @@ let lbry = {
debug: false,
useCustomLighthouseServers: false,
customLighthouseServers: [],
showDeveloperMenu: false,
language: "en",
theme: "light",
themes: [],
instantPurchaseMax: null,
instantPurchaseEnabled: false,
instantPurchaseMax: { currency: "LBC", amount: 0.1 },
},
};
@ -227,9 +229,6 @@ lbry.publishDeprecated = function(
lbry.getClientSetting = function(setting) {
var localStorageVal = localStorage.getItem("setting_" + setting);
if (setting == "showDeveloperMenu") {
return true;
}
return localStorageVal === null
? lbry.defaultClientSettings[setting]
: JSON.parse(localStorageVal);
@ -239,13 +238,6 @@ lbry.setClientSetting = function(setting, value) {
return localStorage.setItem("setting_" + setting, JSON.stringify(value));
};
lbry.formatName = function(name) {
// Converts LBRY name to standard format (all lower case, no special characters, spaces replaced by dashes)
name = name.replace("/s+/g", "-");
name = name.toLowerCase().replace(lbryuri.REGEXP_INVALID_URI, "");
return name;
};
lbry.imagePath = function(file) {
return "img/" + file;
};
@ -276,56 +268,6 @@ lbry.getMediaType = function(contentType, fileName) {
}
};
lbry._subscribeIdCount = 0;
lbry._balanceSubscribeCallbacks = {};
lbry._balanceSubscribeInterval = 5000;
lbry._balanceUpdateInterval = null;
lbry._updateBalanceSubscribers = function() {
lbry.wallet_balance().then(function(balance) {
for (let callback of Object.values(lbry._balanceSubscribeCallbacks)) {
callback(balance);
}
});
if (
!lbry._balanceUpdateInterval &&
Object.keys(lbry._balanceSubscribeCallbacks).length
) {
lbry._balanceUpdateInterval = setInterval(() => {
lbry._updateBalanceSubscribers();
}, lbry._balanceSubscribeInterval);
}
};
lbry.balanceSubscribe = function(callback) {
const subscribeId = ++lbry._subscribeIdCount;
lbry._balanceSubscribeCallbacks[subscribeId] = callback;
lbry._updateBalanceSubscribers();
return subscribeId;
};
lbry.balanceUnsubscribe = function(subscribeId) {
delete lbry._balanceSubscribeCallbacks[subscribeId];
if (
lbry._balanceUpdateInterval &&
!Object.keys(lbry._balanceSubscribeCallbacks).length
) {
clearInterval(lbry._balanceUpdateInterval);
}
};
lbry.showMenuIfNeeded = function() {
const showingMenu = sessionStorage.getItem("menuShown") || null;
const chosenMenu = lbry.getClientSetting("showDeveloperMenu")
? "developer"
: "normal";
if (chosenMenu != showingMenu) {
menu.showMenubar(chosenMenu == "developer");
}
sessionStorage.setItem("menuShown", chosenMenu);
};
lbry.getAppVersionInfo = function() {
return new Promise((resolve, reject) => {
ipcRenderer.once("version-info-received", (event, versionInfo) => {
@ -407,25 +349,6 @@ lbry.claim_list_mine = function(params = {}) {
});
};
lbry.claim_abandon = function(params = {}) {
return new Promise((resolve, reject) => {
apiCall("claim_abandon", params, resolve, reject);
});
};
lbry.block_show = function(params = {}) {
return new Promise((resolve, reject) => {
apiCall(
"block_show",
params,
block => {
resolve(block);
},
reject
);
});
};
lbry._resolveXhrs = {};
lbry.resolve = function(params = {}) {
return new Promise((resolve, reject) => {

View file

@ -16,14 +16,12 @@ const { remote, ipcRenderer, shell } = require("electron");
const contextMenu = remote.require("./menu/context-menu");
const app = require("./app");
lbry.showMenuIfNeeded();
window.addEventListener("contextmenu", event => {
contextMenu.showContextMenu(
remote.getCurrentWindow(),
event.x,
event.y,
lbry.getClientSetting("showDeveloperMenu")
env === "development"
);
event.preventDefault();
});

View file

@ -52,6 +52,7 @@ class ChannelPage extends React.PureComponent {
name: claim.name,
claimId: claim.claim_id,
})}
showLocal={true}
/>
)
: <span className="empty">{__("No content found.")}</span>;

View file

@ -11,7 +11,6 @@ class DeveloperPage extends React.PureComponent {
super(props);
this.state = {
showDeveloperMenu: lbry.getClientSetting("showDeveloperMenu"),
useCustomLighthouseServers: lbry.getClientSetting(
"useCustomLighthouseServers"
),
@ -22,14 +21,6 @@ class DeveloperPage extends React.PureComponent {
};
}
handleShowDeveloperMenuChange(event) {
lbry.setClientSetting("showDeveloperMenu", event.target.checked);
lbry.showMenuIfNeeded();
this.setState({
showDeveloperMenu: event.target.checked,
});
}
handleUseCustomLighthouseServersChange(event) {
lbry.setClientSetting("useCustomLighthouseServers", event.target.checked);
this.setState({
@ -71,19 +62,6 @@ class DeveloperPage extends React.PureComponent {
<main>
<section className="card">
<h3>{__("Developer Settings")}</h3>
<div className="form-row">
<label>
<FormField
type="checkbox"
onChange={event => {
this.handleShowDeveloperMenuChange();
}}
checked={this.state.showDeveloperMenu}
/>
{" "}
{__("Show developer menu")}
</label>
</div>
<div className="form-row">
<label>
<FormField

View file

@ -6,8 +6,10 @@ import { Thumbnail } from "component/common";
import FilePrice from "component/filePrice";
import FileDetails from "component/fileDetails";
import UriIndicator from "component/uriIndicator";
import IconFeatured from "component/iconFeatured";
import Icon from "component/icon";
import WalletSendTip from "component/walletSendTip";
import DateTime from "component/dateTime";
import * as icons from "constants/icons";
class FilePage extends React.PureComponent {
componentDidMount() {
@ -77,7 +79,8 @@ class FilePage extends React.PureComponent {
{!fileInfo || fileInfo.written_bytes <= 0
? <span style={{ float: "right" }}>
<FilePrice uri={lbryuri.normalize(uri)} />
{isRewardContent && <span>{" "}<IconFeatured /></span>}
{isRewardContent &&
<span>{" "}<Icon icon={icons.FEATURED} /></span>}
</span>
: null}
<h1>{title}</h1>

View file

@ -21,6 +21,13 @@ const select = state => ({
daemonSettings: selectDaemonSettings(state),
showNsfw: makeSelectClientSetting(settings.SHOW_NSFW)(state),
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(state),
instantPurchaseEnabled: makeSelectClientSetting(
settings.INSTANT_PURCHASE_ENABLED
)(state),
instantPurchaseMax: makeSelectClientSetting(settings.INSTANT_PURCHASE_MAX)(
state
),
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(state),
theme: makeSelectClientSetting(settings.THEME)(state),
themes: makeSelectClientSetting(settings.THEMES)(state),
language: selectCurrentLanguage(state),

View file

@ -13,6 +13,8 @@ class SettingsPage extends React.PureComponent {
super(props);
this.state = {
instantPurchaseEnabled: props.instantPurchaseEnabled,
instantPurchaseMax: props.instantPurchaseMax,
clearingCache: false,
};
}
@ -59,6 +61,22 @@ class SettingsPage extends React.PureComponent {
this.props.setClientSetting(settings.THEME, value);
}
oninstantPurchaseEnabledChange(enabled) {
this.props.setClientSetting(settings.INSTANT_PURCHASE_ENABLED, enabled);
this.setState({
instantPurchaseEnabled: enabled,
});
}
onInstantPurchaseMaxChange(newValue) {
this.props.setClientSetting(settings.INSTANT_PURCHASE_MAX, newValue);
this.setState({
instantPurchaseMax: newValue,
});
}
// onMaxUploadPrefChange(isLimited) {
// if (!isLimited) {
// this.setDaemonSetting("max_upload", 0.0);
@ -113,6 +131,8 @@ class SettingsPage extends React.PureComponent {
language,
languages,
showNsfw,
instantPurchaseEnabled,
instantPurchaseMax,
showUnavailable,
theme,
themes,
@ -167,9 +187,14 @@ class SettingsPage extends React.PureComponent {
</section>
<section className="card">
<div className="card__content">
<h3>{__("Max Purchase Price")}</h3>
<h3>{__("Purchase Settings")}</h3>
</div>
<div className="card__content">
<div className="form-row__label-row">
<label className="form-row__label">
{__("Max Purchase Price")}
</label>
</div>
<FormRow
type="radio"
name="max_key_fee"
@ -211,6 +236,47 @@ class SettingsPage extends React.PureComponent {
)}
</div>
</div>
<div className="card__content">
<div className="form-row__label-row">
<label className="form-row__label">
{__("Purchase Confirmations")}
</label>
</div>
<FormRow
type="radio"
name="instant_purchase_max"
checked={!this.state.instantPurchaseEnabled}
label={__("Ask for confirmation of all purchases")}
onClick={e => {
this.oninstantPurchaseEnabledChange(false);
}}
/>
<div className="form-row">
<FormField
type="radio"
name="instant_purchase_max"
checked={this.state.instantPurchaseEnabled}
label={
"Single-click purchasing of content less than" +
(this.state.instantPurchaseEnabled ? "" : "...")
}
onClick={e => {
this.oninstantPurchaseEnabledChange(true);
}}
/>
{this.state.instantPurchaseEnabled &&
<FormFieldPrice
min="0.1"
step="0.1"
onChange={val => this.onInstantPurchaseMaxChange(val)}
defaultValue={this.state.instantPurchaseMax}
/>}
</div>
<div className="form-field__helper">
When this option is chosen, LBRY won't ask you to confirm
downloads below the given price.
</div>
</div>
</section>
<section className="card">

View file

@ -6,6 +6,10 @@ import lbry from "lbry";
const reducers = {};
const defaultState = {
clientSettings: {
instantPurchaseEnabled: lbry.getClientSetting(
settings.INSTANT_PURCHASE_ENABLED
),
instantPurchaseMax: lbry.getClientSetting(settings.INSTANT_PURCHASE_MAX),
showNsfw: lbry.getClientSetting(settings.SHOW_NSFW),
showUnavailable: lbry.getClientSetting(settings.SHOW_UNAVAILABLE),
welcome_acknowledged: lbry.getClientSetting(settings.NEW_USER_ACKNOWLEDGED),

View file

@ -180,7 +180,12 @@ export const selectMyChannelClaims = createSelector(
const ids = state.myChannelClaims || [];
const claims = [];
ids.forEach(id => claims.push(byId[id]));
ids.forEach(id => {
if (byId[id]) {
//I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-app/issues/544
claims.push(byId[id]);
}
});
return claims;
}

View file

@ -23,6 +23,17 @@
transform: translate(0, 0);
}
/* Adjustments for icon size and alignment */
.icon-rocket {
color: orangered;
font-size: 0.95em;
position: relative;
top: -0.04em;
margin-left: 0.025em;
margin-right: 0.025em;
}
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
readers do not read off random characters that represent icons */
.icon-glass:before {

View file

@ -167,6 +167,11 @@ $font-size-subtext-multiple: 0.82;
position: absolute;
top: 36%
}
.card__indicators {
float: right;
}
.card--small {
width: var(--card-small-width);
overflow-x: hidden;
@ -269,10 +274,6 @@ $padding-right-card-hover-hack: 30px;
right: 0;
}
.card__icon-featured-content {
color: orangered;
}
/*
if we keep doing things like this, we should add a real grid system, but I'm going to be a selective dick about it - Jeremy
*/

View file

@ -3,12 +3,6 @@ $height-file-tile: $spacing-vertical * 6;
.file-tile__row {
overflow: hidden;
height: $height-file-tile;
.credit-amount {
float: right;
}
.icon-featured {
float: right;
}
//also a hack
.card__media {
height: $height-file-tile;