Merge branch 'master' into css_patch
This commit is contained in:
commit
2e28582277
33 changed files with 288 additions and 199 deletions
|
@ -8,15 +8,24 @@ Web UI version numbers should always match the corresponding version of LBRY App
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### 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)
|
* New custom styled scrollbar [#574](https://github.com/lbryio/lbry-app/pull/574)
|
||||||
*
|
*
|
||||||
|
|
||||||
### Changed
|
### 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)
|
* 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.
|
* Display search bar on discover page instead of title and remove duplicated icon.
|
||||||
* Minor update for themes.
|
* Minor update for themes.
|
||||||
|
*
|
||||||
|
|
||||||
### Fixed
|
### 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 unresponsive header [#613](https://github.com/lbryio/lbry-app/issues/613)
|
||||||
* Fixed dark theme issues with text content.
|
* Fixed dark theme issues with text content.
|
||||||
* Minor css fixes.
|
* Minor css fixes.
|
||||||
|
|
3
CONTRIBUTING.md
Normal file
3
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## Contributing to LBRY
|
||||||
|
|
||||||
|
https://lbry.io/faq/contributing
|
28
README.md
28
README.md
|
@ -49,43 +49,49 @@ to create distributable packages, which is run by calling:
|
||||||
## Development on Windows
|
## Development on Windows
|
||||||
|
|
||||||
### Windows Dependency
|
### Windows Dependency
|
||||||
|
1. Download and install `git` from <a href="https://git-for-windows.github.io/">github.io<a> (configure to use command prompt integration)
|
||||||
1. Download and install `npm` and `node` from <a href="https://nodejs.org/en/download/current/">nodejs.org<a>
|
2. 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 `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 `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>
|
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
|
### 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 -m pip install -r build\requirements.txt
|
||||||
python build\set_version.py
|
python build\set_version.py
|
||||||
npm install -g yarn
|
npm install -g yarn
|
||||||
yarn install
|
yarn install
|
||||||
```
|
```
|
||||||
2. Change directory to `app` and run the following;
|
3. Change directory to `app` and run the following;
|
||||||
```
|
```
|
||||||
yarn install
|
yarn install
|
||||||
node_modules\.bin\electron-rebuild
|
node_modules\.bin\electron-rebuild
|
||||||
node_modules\.bin\electron-rebuild
|
node_modules\.bin\electron-rebuild
|
||||||
cd ..
|
cd ..
|
||||||
```
|
```
|
||||||
3. Change directory to `ui` and run the following
|
4. Change directory to `ui` and run the following:
|
||||||
```
|
```
|
||||||
yarn install
|
yarn install
|
||||||
npm rebuild node-sass
|
npm rebuild node-sass
|
||||||
node node_modules\node-sass\bin\node-sass --output dist\css --sourcemap=none scss\
|
node node_modules\node-sass\bin\node-sass --output dist\css --sourcemap=none scss\
|
||||||
node_modules\.bin\webpack --config webpack.dev.config.js
|
node_modules\.bin\webpack --config webpack.dev.config.js
|
||||||
xcopy dist ..\app\dist
|
xcopy /E dist ..\app\dist
|
||||||
cd ..
|
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
|
### Building lbry-app
|
||||||
1. run `node_modules\.bin\build -p never` from the root of the project.
|
1. run `node_modules\.bin\build -p never` from the root of the project.
|
||||||
|
|
||||||
### Running the electron app
|
### Running the electron app
|
||||||
1. Run `./node_modules/.bin/electron app`
|
1. Run `node_modules\.bin\electron app`
|
||||||
|
|
||||||
### Ongoing Development
|
### Ongoing Development
|
||||||
1. `cd ui`
|
1. `cd ui`
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"electron-rebuild": "^1.5.11"
|
"electron-rebuild": "^1.5.11"
|
||||||
},
|
},
|
||||||
"lbrySettings": {
|
"lbrySettings": {
|
||||||
"lbrynetDaemonVersion": "0.16.1",
|
"lbrynetDaemonVersion": "0.16.3",
|
||||||
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-daemon-vDAEMONVER-OSNAME.zip"
|
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-daemon-vDAEMONVER-OSNAME.zip"
|
||||||
},
|
},
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as types from "constants/action_types";
|
import * as types from "constants/action_types";
|
||||||
import * as settings from "constants/settings";
|
|
||||||
import lbry from "lbry";
|
import lbry from "lbry";
|
||||||
import {
|
import {
|
||||||
selectUpdateUrl,
|
selectUpdateUrl,
|
||||||
|
@ -8,6 +7,7 @@ import {
|
||||||
selectUpgradeFilename,
|
selectUpgradeFilename,
|
||||||
} from "selectors/app";
|
} from "selectors/app";
|
||||||
import { doFetchDaemonSettings } from "actions/settings";
|
import { doFetchDaemonSettings } from "actions/settings";
|
||||||
|
import { doBalanceSubscribe } from "actions/wallet";
|
||||||
import { doAuthenticate } from "actions/user";
|
import { doAuthenticate } from "actions/user";
|
||||||
import { doFetchFileInfosAndPublishedClaims } from "actions/file_info";
|
import { doFetchFileInfosAndPublishedClaims } from "actions/file_info";
|
||||||
|
|
||||||
|
@ -178,6 +178,7 @@ export function doDaemonReady() {
|
||||||
dispatch(doAuthenticate());
|
dispatch(doAuthenticate());
|
||||||
dispatch({ type: types.DAEMON_READY });
|
dispatch({ type: types.DAEMON_READY });
|
||||||
dispatch(doFetchDaemonSettings());
|
dispatch(doFetchDaemonSettings());
|
||||||
|
dispatch(doBalanceSubscribe());
|
||||||
dispatch(doFetchFileInfosAndPublishedClaims());
|
dispatch(doFetchFileInfosAndPublishedClaims());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as types from "constants/action_types";
|
import * as types from "constants/action_types";
|
||||||
|
import * as settings from "constants/settings";
|
||||||
import lbry from "lbry";
|
import lbry from "lbry";
|
||||||
import lbryio from "lbryio";
|
import lbryio from "lbryio";
|
||||||
import lbryuri from "lbryuri";
|
import lbryuri from "lbryuri";
|
||||||
|
@ -322,29 +323,56 @@ export function doPurchaseUri(uri) {
|
||||||
const downloadingByOutpoint = selectDownloadingByOutpoint(state);
|
const downloadingByOutpoint = selectDownloadingByOutpoint(state);
|
||||||
const alreadyDownloading =
|
const alreadyDownloading =
|
||||||
fileInfo && !!downloadingByOutpoint[fileInfo.outpoint];
|
fileInfo && !!downloadingByOutpoint[fileInfo.outpoint];
|
||||||
const costInfo = makeSelectCostInfoForUri(uri)(state);
|
|
||||||
const { cost } = costInfo;
|
|
||||||
|
|
||||||
if (
|
function attemptPlay(cost, instantPurchaseMax = null) {
|
||||||
alreadyDownloading ||
|
if (cost > 0 && (!instantPurchaseMax || cost > instantPurchaseMax)) {
|
||||||
(fileInfo && fileInfo.completed && fileInfo.written_bytes > 0)
|
dispatch(doOpenModal(modals.AFFIRM_PURCHASE, { uri }));
|
||||||
) {
|
} else {
|
||||||
return;
|
dispatch(doLoadVideo(uri));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we already fully downloaded the file.
|
// we already fully downloaded the file.
|
||||||
if (
|
if (fileInfo && fileInfo.completed) {
|
||||||
cost === 0 ||
|
// If written_bytes is false that means the user has deleted/moved the
|
||||||
(fileInfo && (fileInfo.completed || fileInfo.download_directory))
|
// file manually on their file system, so we need to dispatch a
|
||||||
) {
|
// doLoadVideo action to reconstruct the file from the blobs
|
||||||
return dispatch(doLoadVideo(uri));
|
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) {
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,23 @@ import { doOpenModal, doShowSnackBar } from "actions/app";
|
||||||
import { doNavigate } from "actions/navigation";
|
import { doNavigate } from "actions/navigation";
|
||||||
import * as modals from "constants/modal_types";
|
import * as modals from "constants/modal_types";
|
||||||
|
|
||||||
export function doUpdateBalance(balance) {
|
export function doUpdateBalance() {
|
||||||
return {
|
return function(dispatch, getState) {
|
||||||
type: types.UPDATE_BALANCE,
|
lbry.wallet_balance().then(balance => {
|
||||||
data: {
|
return dispatch({
|
||||||
balance: balance,
|
type: types.UPDATE_BALANCE,
|
||||||
},
|
data: {
|
||||||
|
balance: balance,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doBalanceSubscribe() {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
dispatch(doUpdateBalance());
|
||||||
|
setInterval(() => dispatch(doUpdateBalance()), 5000);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { selectUser } from "selectors/user";
|
||||||
import { doCheckUpgradeAvailable, doAlertError } from "actions/app";
|
import { doCheckUpgradeAvailable, doAlertError } from "actions/app";
|
||||||
import { doRecordScroll } from "actions/navigation";
|
import { doRecordScroll } from "actions/navigation";
|
||||||
import { doFetchRewardedContent } from "actions/content";
|
import { doFetchRewardedContent } from "actions/content";
|
||||||
import { doUpdateBalance } from "actions/wallet";
|
|
||||||
import App from "./view";
|
import App from "./view";
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
|
@ -16,7 +15,6 @@ const select = (state, props) => ({
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
alertError: errorList => dispatch(doAlertError(errorList)),
|
alertError: errorList => dispatch(doAlertError(errorList)),
|
||||||
checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()),
|
checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()),
|
||||||
updateBalance: balance => dispatch(doUpdateBalance(balance)),
|
|
||||||
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
|
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
|
||||||
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
|
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,6 @@ class App extends React.PureComponent {
|
||||||
const {
|
const {
|
||||||
alertError,
|
alertError,
|
||||||
checkUpgradeAvailable,
|
checkUpgradeAvailable,
|
||||||
updateBalance,
|
|
||||||
fetchRewardedContent,
|
fetchRewardedContent,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -22,10 +21,6 @@ class App extends React.PureComponent {
|
||||||
checkUpgradeAvailable();
|
checkUpgradeAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
lbry.balanceSubscribe(balance => {
|
|
||||||
updateBalance(balance);
|
|
||||||
});
|
|
||||||
|
|
||||||
fetchRewardedContent();
|
fetchRewardedContent();
|
||||||
|
|
||||||
this.scrollListener = () => this.props.recordScroll(window.scrollY);
|
this.scrollListener = () => this.props.recordScroll(window.scrollY);
|
||||||
|
|
|
@ -2,12 +2,13 @@ import React from "react";
|
||||||
import lbryuri from "lbryuri.js";
|
import lbryuri from "lbryuri.js";
|
||||||
import CardMedia from "component/cardMedia";
|
import CardMedia from "component/cardMedia";
|
||||||
import Link from "component/link";
|
import Link from "component/link";
|
||||||
import { TruncatedText, Icon } from "component/common";
|
import { TruncatedText } from "component/common";
|
||||||
import IconFeatured from "component/iconFeatured";
|
import Icon from "component/icon";
|
||||||
import FilePrice from "component/filePrice";
|
import FilePrice from "component/filePrice";
|
||||||
import UriIndicator from "component/uriIndicator";
|
import UriIndicator from "component/uriIndicator";
|
||||||
import NsfwOverlay from "component/nsfwOverlay";
|
import NsfwOverlay from "component/nsfwOverlay";
|
||||||
import TruncatedMarkdown from "component/truncatedMarkdown";
|
import TruncatedMarkdown from "component/truncatedMarkdown";
|
||||||
|
import * as icons from "constants/icons";
|
||||||
|
|
||||||
class FileCard extends React.PureComponent {
|
class FileCard extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -94,11 +95,12 @@ class FileCard extends React.PureComponent {
|
||||||
<TruncatedText lines={1}>{title}</TruncatedText>
|
<TruncatedText lines={1}>{title}</TruncatedText>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__subtitle">
|
<div className="card__subtitle">
|
||||||
<span style={{ float: "right" }}>
|
<span className="card__indicators">
|
||||||
<FilePrice uri={uri} />
|
<FilePrice uri={uri} />
|
||||||
{isRewardContent && <span>{" "}<IconFeatured /></span>}
|
{" "}
|
||||||
{fileInfo &&
|
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
||||||
<span>{" "}<Icon fixed icon="icon-folder" /></span>}
|
{" "}
|
||||||
|
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||||
</span>
|
</span>
|
||||||
<UriIndicator uri={uri} />
|
<UriIndicator uri={uri} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -29,8 +29,9 @@ class FileDetails extends React.PureComponent {
|
||||||
const { description, language, license } = metadata;
|
const { description, language, license } = metadata;
|
||||||
const { height } = claim;
|
const { height } = claim;
|
||||||
const mediaType = lbry.getMediaType(contentType);
|
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;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -59,12 +60,12 @@ class FileDetails extends React.PureComponent {
|
||||||
<tr>
|
<tr>
|
||||||
<td>{__("License")}</td><td>{license}</td>
|
<td>{__("License")}</td><td>{license}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{directory &&
|
{downloadPath &&
|
||||||
<tr>
|
<tr>
|
||||||
<td>{__("Downloaded to")}</td>
|
<td>{__("Downloaded to")}</td>
|
||||||
<td>
|
<td>
|
||||||
<Link onClick={() => openFolder(directory)}>
|
<Link onClick={() => openFolder(downloadPath)}>
|
||||||
{directory}
|
{downloadPath}
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
</tr>}
|
</tr>}
|
||||||
|
|
|
@ -87,7 +87,8 @@ class FileList extends React.PureComponent {
|
||||||
<FileTile
|
<FileTile
|
||||||
key={fileInfo.outpoint || fileInfo.claim_id}
|
key={fileInfo.outpoint || fileInfo.claim_id}
|
||||||
uri={uri}
|
uri={uri}
|
||||||
hidePrice={true}
|
showPrice={false}
|
||||||
|
showLocal={false}
|
||||||
showActions={true}
|
showActions={true}
|
||||||
showEmpty={this.props.fileTileShowEmpty}
|
showEmpty={this.props.fileTileShowEmpty}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import * as icons from "constants/icons";
|
||||||
import lbryuri from "lbryuri.js";
|
import lbryuri from "lbryuri.js";
|
||||||
import CardMedia from "component/cardMedia";
|
import CardMedia from "component/cardMedia";
|
||||||
import FileActions from "component/fileActions";
|
import FileActions from "component/fileActions";
|
||||||
|
@ -6,12 +7,17 @@ import Link from "component/link";
|
||||||
import { TruncatedText } from "component/common.js";
|
import { TruncatedText } from "component/common.js";
|
||||||
import FilePrice from "component/filePrice";
|
import FilePrice from "component/filePrice";
|
||||||
import NsfwOverlay from "component/nsfwOverlay";
|
import NsfwOverlay from "component/nsfwOverlay";
|
||||||
import IconFeatured from "component/iconFeatured";
|
import Icon from "component/icon";
|
||||||
|
|
||||||
class FileTile extends React.PureComponent {
|
class FileTile extends React.PureComponent {
|
||||||
static SHOW_EMPTY_PUBLISH = "publish";
|
static SHOW_EMPTY_PUBLISH = "publish";
|
||||||
static SHOW_EMPTY_PENDING = "pending";
|
static SHOW_EMPTY_PENDING = "pending";
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
showPrice: true,
|
||||||
|
showLocal: true,
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -59,8 +65,10 @@ class FileTile extends React.PureComponent {
|
||||||
isResolvingUri,
|
isResolvingUri,
|
||||||
showEmpty,
|
showEmpty,
|
||||||
navigate,
|
navigate,
|
||||||
hidePrice,
|
showPrice,
|
||||||
|
showLocal,
|
||||||
rewardedContentClaimIds,
|
rewardedContentClaimIds,
|
||||||
|
fileInfo,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const uri = lbryuri.normalize(this.props.uri);
|
const uri = lbryuri.normalize(this.props.uri);
|
||||||
|
@ -111,8 +119,13 @@ class FileTile extends React.PureComponent {
|
||||||
<CardMedia title={title} thumbnail={thumbnail} />
|
<CardMedia title={title} thumbnail={thumbnail} />
|
||||||
<div className="file-tile__content">
|
<div className="file-tile__content">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
{!hidePrice ? <FilePrice uri={this.props.uri} /> : null}
|
<span className="card__indicators">
|
||||||
{isRewardContent && <IconFeatured />}
|
{showPrice && <FilePrice uri={this.props.uri} />}
|
||||||
|
{" "}
|
||||||
|
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
||||||
|
{" "}
|
||||||
|
{showLocal && fileInfo && <Icon icon={icons.LOCAL} />}
|
||||||
|
</span>
|
||||||
<div className="meta">{uri}</div>
|
<div className="meta">{uri}</div>
|
||||||
<h3>
|
<h3>
|
||||||
<TruncatedText lines={1}>{title}</TruncatedText>
|
<TruncatedText lines={1}>{title}</TruncatedText>
|
||||||
|
|
5
ui/js/component/icon/index.js
Normal file
5
ui/js/component/icon/index.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import Icon from "./view";
|
||||||
|
|
||||||
|
export default connect(null, null)(Icon);
|
40
ui/js/component/icon/view.jsx
Normal file
40
ui/js/component/icon/view.jsx
Normal 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} />;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import IconFeatured from "./view";
|
|
||||||
|
|
||||||
export default connect(null, null)(IconFeatured);
|
|
|
@ -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;
|
|
|
@ -20,6 +20,7 @@ class PublishForm extends React.PureComponent {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
id: null,
|
id: null,
|
||||||
|
uri: null,
|
||||||
rawName: "",
|
rawName: "",
|
||||||
name: "",
|
name: "",
|
||||||
bid: 10,
|
bid: 10,
|
||||||
|
@ -166,7 +167,6 @@ class PublishForm extends React.PureComponent {
|
||||||
claim() {
|
claim() {
|
||||||
const { claimsByUri } = this.props;
|
const { claimsByUri } = this.props;
|
||||||
const { uri } = this.state;
|
const { uri } = this.state;
|
||||||
|
|
||||||
return claimsByUri[uri];
|
return claimsByUri[uri];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,9 +437,10 @@ class PublishForm extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileChange() {
|
onFileChange() {
|
||||||
|
const { mode } = this.state;
|
||||||
if (this.refs.file.getValue()) {
|
if (this.refs.file.getValue()) {
|
||||||
this.setState({ hasFile: true });
|
this.setState({ hasFile: true });
|
||||||
if (!this.state.customUrl) {
|
if (!this.state.customUrl && mode !== "edit") {
|
||||||
let fileName = this._getFileName(this.refs.file.getValue());
|
let fileName = this._getFileName(this.refs.file.getValue());
|
||||||
this.nameChanged(fileName);
|
this.nameChanged(fileName);
|
||||||
}
|
}
|
||||||
|
@ -822,7 +823,7 @@ class PublishForm extends React.PureComponent {
|
||||||
<FormRow
|
<FormRow
|
||||||
ref="bid"
|
ref="bid"
|
||||||
type="number"
|
type="number"
|
||||||
step="0.01"
|
step="0.1"
|
||||||
label={__("Deposit")}
|
label={__("Deposit")}
|
||||||
postfix="LBC"
|
postfix="LBC"
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
|
|
|
@ -33,7 +33,7 @@ class WalletSend extends React.PureComponent {
|
||||||
<FormRow
|
<FormRow
|
||||||
label={__("Amount")}
|
label={__("Amount")}
|
||||||
postfix={__("LBC")}
|
postfix={__("LBC")}
|
||||||
step="0.01"
|
step="0.1"
|
||||||
min="0"
|
min="0"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="1.23"
|
placeholder="1.23"
|
||||||
|
|
2
ui/js/constants/icons.js
Normal file
2
ui/js/constants/icons.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export const FEATURED = "rocket";
|
||||||
|
export const LOCAL = "folder";
|
|
@ -6,5 +6,7 @@ export const NEW_USER_ACKNOWLEDGED = "welcome_acknowledged";
|
||||||
export const LANGUAGE = "language";
|
export const LANGUAGE = "language";
|
||||||
export const SHOW_NSFW = "showNsfw";
|
export const SHOW_NSFW = "showNsfw";
|
||||||
export const SHOW_UNAVAILABLE = "showUnavailable";
|
export const SHOW_UNAVAILABLE = "showUnavailable";
|
||||||
|
export const INSTANT_PURCHASE_ENABLED = "instantPurchaseEnabled";
|
||||||
|
export const INSTANT_PURCHASE_MAX = "instantPurchaseMax";
|
||||||
export const THEME = "theme";
|
export const THEME = "theme";
|
||||||
export const THEMES = "themes";
|
export const THEMES = "themes";
|
||||||
|
|
|
@ -37,10 +37,12 @@ let lbry = {
|
||||||
debug: false,
|
debug: false,
|
||||||
useCustomLighthouseServers: false,
|
useCustomLighthouseServers: false,
|
||||||
customLighthouseServers: [],
|
customLighthouseServers: [],
|
||||||
showDeveloperMenu: false,
|
|
||||||
language: "en",
|
language: "en",
|
||||||
theme: "light",
|
theme: "light",
|
||||||
themes: [],
|
themes: [],
|
||||||
|
instantPurchaseMax: null,
|
||||||
|
instantPurchaseEnabled: false,
|
||||||
|
instantPurchaseMax: { currency: "LBC", amount: 0.1 },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,9 +229,6 @@ lbry.publishDeprecated = function(
|
||||||
|
|
||||||
lbry.getClientSetting = function(setting) {
|
lbry.getClientSetting = function(setting) {
|
||||||
var localStorageVal = localStorage.getItem("setting_" + setting);
|
var localStorageVal = localStorage.getItem("setting_" + setting);
|
||||||
if (setting == "showDeveloperMenu") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return localStorageVal === null
|
return localStorageVal === null
|
||||||
? lbry.defaultClientSettings[setting]
|
? lbry.defaultClientSettings[setting]
|
||||||
: JSON.parse(localStorageVal);
|
: JSON.parse(localStorageVal);
|
||||||
|
@ -239,13 +238,6 @@ lbry.setClientSetting = function(setting, value) {
|
||||||
return localStorage.setItem("setting_" + setting, JSON.stringify(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) {
|
lbry.imagePath = function(file) {
|
||||||
return "img/" + 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() {
|
lbry.getAppVersionInfo = function() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
ipcRenderer.once("version-info-received", (event, versionInfo) => {
|
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._resolveXhrs = {};
|
||||||
lbry.resolve = function(params = {}) {
|
lbry.resolve = function(params = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
|
@ -16,14 +16,12 @@ const { remote, ipcRenderer, shell } = require("electron");
|
||||||
const contextMenu = remote.require("./menu/context-menu");
|
const contextMenu = remote.require("./menu/context-menu");
|
||||||
const app = require("./app");
|
const app = require("./app");
|
||||||
|
|
||||||
lbry.showMenuIfNeeded();
|
|
||||||
|
|
||||||
window.addEventListener("contextmenu", event => {
|
window.addEventListener("contextmenu", event => {
|
||||||
contextMenu.showContextMenu(
|
contextMenu.showContextMenu(
|
||||||
remote.getCurrentWindow(),
|
remote.getCurrentWindow(),
|
||||||
event.x,
|
event.x,
|
||||||
event.y,
|
event.y,
|
||||||
lbry.getClientSetting("showDeveloperMenu")
|
env === "development"
|
||||||
);
|
);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
|
@ -52,6 +52,7 @@ class ChannelPage extends React.PureComponent {
|
||||||
name: claim.name,
|
name: claim.name,
|
||||||
claimId: claim.claim_id,
|
claimId: claim.claim_id,
|
||||||
})}
|
})}
|
||||||
|
showLocal={true}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: <span className="empty">{__("No content found.")}</span>;
|
: <span className="empty">{__("No content found.")}</span>;
|
||||||
|
|
|
@ -11,7 +11,6 @@ class DeveloperPage extends React.PureComponent {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
showDeveloperMenu: lbry.getClientSetting("showDeveloperMenu"),
|
|
||||||
useCustomLighthouseServers: lbry.getClientSetting(
|
useCustomLighthouseServers: lbry.getClientSetting(
|
||||||
"useCustomLighthouseServers"
|
"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) {
|
handleUseCustomLighthouseServersChange(event) {
|
||||||
lbry.setClientSetting("useCustomLighthouseServers", event.target.checked);
|
lbry.setClientSetting("useCustomLighthouseServers", event.target.checked);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -71,19 +62,6 @@ class DeveloperPage extends React.PureComponent {
|
||||||
<main>
|
<main>
|
||||||
<section className="card">
|
<section className="card">
|
||||||
<h3>{__("Developer Settings")}</h3>
|
<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">
|
<div className="form-row">
|
||||||
<label>
|
<label>
|
||||||
<FormField
|
<FormField
|
||||||
|
|
|
@ -6,8 +6,10 @@ import { Thumbnail } from "component/common";
|
||||||
import FilePrice from "component/filePrice";
|
import FilePrice from "component/filePrice";
|
||||||
import FileDetails from "component/fileDetails";
|
import FileDetails from "component/fileDetails";
|
||||||
import UriIndicator from "component/uriIndicator";
|
import UriIndicator from "component/uriIndicator";
|
||||||
import IconFeatured from "component/iconFeatured";
|
import Icon from "component/icon";
|
||||||
import WalletSendTip from "component/walletSendTip";
|
import WalletSendTip from "component/walletSendTip";
|
||||||
|
import DateTime from "component/dateTime";
|
||||||
|
import * as icons from "constants/icons";
|
||||||
|
|
||||||
class FilePage extends React.PureComponent {
|
class FilePage extends React.PureComponent {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -77,7 +79,8 @@ class FilePage extends React.PureComponent {
|
||||||
{!fileInfo || fileInfo.written_bytes <= 0
|
{!fileInfo || fileInfo.written_bytes <= 0
|
||||||
? <span style={{ float: "right" }}>
|
? <span style={{ float: "right" }}>
|
||||||
<FilePrice uri={lbryuri.normalize(uri)} />
|
<FilePrice uri={lbryuri.normalize(uri)} />
|
||||||
{isRewardContent && <span>{" "}<IconFeatured /></span>}
|
{isRewardContent &&
|
||||||
|
<span>{" "}<Icon icon={icons.FEATURED} /></span>}
|
||||||
</span>
|
</span>
|
||||||
: null}
|
: null}
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
|
|
|
@ -21,6 +21,13 @@ const select = state => ({
|
||||||
daemonSettings: selectDaemonSettings(state),
|
daemonSettings: selectDaemonSettings(state),
|
||||||
showNsfw: makeSelectClientSetting(settings.SHOW_NSFW)(state),
|
showNsfw: makeSelectClientSetting(settings.SHOW_NSFW)(state),
|
||||||
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(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),
|
theme: makeSelectClientSetting(settings.THEME)(state),
|
||||||
themes: makeSelectClientSetting(settings.THEMES)(state),
|
themes: makeSelectClientSetting(settings.THEMES)(state),
|
||||||
language: selectCurrentLanguage(state),
|
language: selectCurrentLanguage(state),
|
||||||
|
|
|
@ -13,6 +13,8 @@ class SettingsPage extends React.PureComponent {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
instantPurchaseEnabled: props.instantPurchaseEnabled,
|
||||||
|
instantPurchaseMax: props.instantPurchaseMax,
|
||||||
clearingCache: false,
|
clearingCache: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -59,6 +61,22 @@ class SettingsPage extends React.PureComponent {
|
||||||
this.props.setClientSetting(settings.THEME, value);
|
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) {
|
// onMaxUploadPrefChange(isLimited) {
|
||||||
// if (!isLimited) {
|
// if (!isLimited) {
|
||||||
// this.setDaemonSetting("max_upload", 0.0);
|
// this.setDaemonSetting("max_upload", 0.0);
|
||||||
|
@ -113,6 +131,8 @@ class SettingsPage extends React.PureComponent {
|
||||||
language,
|
language,
|
||||||
languages,
|
languages,
|
||||||
showNsfw,
|
showNsfw,
|
||||||
|
instantPurchaseEnabled,
|
||||||
|
instantPurchaseMax,
|
||||||
showUnavailable,
|
showUnavailable,
|
||||||
theme,
|
theme,
|
||||||
themes,
|
themes,
|
||||||
|
@ -167,9 +187,14 @@ class SettingsPage extends React.PureComponent {
|
||||||
</section>
|
</section>
|
||||||
<section className="card">
|
<section className="card">
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<h3>{__("Max Purchase Price")}</h3>
|
<h3>{__("Purchase Settings")}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
|
<div className="form-row__label-row">
|
||||||
|
<label className="form-row__label">
|
||||||
|
{__("Max Purchase Price")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<FormRow
|
<FormRow
|
||||||
type="radio"
|
type="radio"
|
||||||
name="max_key_fee"
|
name="max_key_fee"
|
||||||
|
@ -211,6 +236,47 @@ class SettingsPage extends React.PureComponent {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
|
|
||||||
<section className="card">
|
<section className="card">
|
||||||
|
|
|
@ -6,6 +6,10 @@ import lbry from "lbry";
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
clientSettings: {
|
clientSettings: {
|
||||||
|
instantPurchaseEnabled: lbry.getClientSetting(
|
||||||
|
settings.INSTANT_PURCHASE_ENABLED
|
||||||
|
),
|
||||||
|
instantPurchaseMax: lbry.getClientSetting(settings.INSTANT_PURCHASE_MAX),
|
||||||
showNsfw: lbry.getClientSetting(settings.SHOW_NSFW),
|
showNsfw: lbry.getClientSetting(settings.SHOW_NSFW),
|
||||||
showUnavailable: lbry.getClientSetting(settings.SHOW_UNAVAILABLE),
|
showUnavailable: lbry.getClientSetting(settings.SHOW_UNAVAILABLE),
|
||||||
welcome_acknowledged: lbry.getClientSetting(settings.NEW_USER_ACKNOWLEDGED),
|
welcome_acknowledged: lbry.getClientSetting(settings.NEW_USER_ACKNOWLEDGED),
|
||||||
|
|
|
@ -180,7 +180,12 @@ export const selectMyChannelClaims = createSelector(
|
||||||
const ids = state.myChannelClaims || [];
|
const ids = state.myChannelClaims || [];
|
||||||
const claims = [];
|
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;
|
return claims;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,17 @@
|
||||||
transform: translate(0, 0);
|
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
|
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
|
||||||
readers do not read off random characters that represent icons */
|
readers do not read off random characters that represent icons */
|
||||||
.icon-glass:before {
|
.icon-glass:before {
|
||||||
|
|
|
@ -167,6 +167,11 @@ $font-size-subtext-multiple: 0.82;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 36%
|
top: 36%
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card__indicators {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
.card--small {
|
.card--small {
|
||||||
width: var(--card-small-width);
|
width: var(--card-small-width);
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
@ -269,10 +274,6 @@ $padding-right-card-hover-hack: 30px;
|
||||||
right: 0;
|
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
|
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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,12 +3,6 @@ $height-file-tile: $spacing-vertical * 6;
|
||||||
.file-tile__row {
|
.file-tile__row {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: $height-file-tile;
|
height: $height-file-tile;
|
||||||
.credit-amount {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
.icon-featured {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
//also a hack
|
//also a hack
|
||||||
.card__media {
|
.card__media {
|
||||||
height: $height-file-tile;
|
height: $height-file-tile;
|
||||||
|
|
Loading…
Reference in a new issue