mirror of
https://github.com/LBRYFoundation/lbry-desktop.git
synced 2025-09-01 01:35:11 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
d2c735717c
46 changed files with 426 additions and 182 deletions
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -10,22 +10,25 @@ Web UI version numbers should always match the corresponding version of LBRY App
|
||||||
### Added
|
### Added
|
||||||
* Added a new component, `FormFieldPrice` which is now used in Publish and Settings
|
* Added a new component, `FormFieldPrice` which is now used in Publish and Settings
|
||||||
* Added a theme system to select different themes in Settings.
|
* Added a theme system to select different themes in Settings.
|
||||||
* New Dark theme.
|
* Added a new dark theme.
|
||||||
* Added wallet backup guide reference
|
* Added a forward button and improved history behavior. Back/forward disable when unusable.
|
||||||
*
|
* Added a new component, `FormFieldPrice` which is now used in Publish and Settings.
|
||||||
|
* Added wallet backup guide reference.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Updated to daemon [0.15](https://github.com/lbryio/lbry/releases). Most relevant changes for app are improved announcing of content and a fix for the daemon getting stuck running.
|
* Updated to daemon [0.15](https://github.com/lbryio/lbry/releases). Most relevant changes for app are improved announcing of content and a fix for the daemon getting stuck running.
|
||||||
* Some form field refactoring as we progress towards form sanity.
|
* Continued to refine first-run process, process for new users, and introducing people to LBRY and LBRY credits.
|
||||||
|
* Changed the default price settings.
|
||||||
* When an "Open" button is clicked on a show page, if the file fails to open, the app will try to open the file's folder.
|
* When an "Open" button is clicked on a show page, if the file fails to open, the app will try to open the file's folder.
|
||||||
* Removed confusing placeholder text from email input
|
* Some form field refactoring as we take baby steps towards form sanity.
|
||||||
* Updated several packages and fixed warnings in build process (all but the [fsevents warning](https://github.com/yarnpkg/yarn/issues/3738), which is rather dramatic)
|
* Replaced confusing placeholder text from email input.
|
||||||
|
* Refactored modal and settings logic.
|
||||||
|
* Updated several packages and fixed warnings in build process (all but the [fsevents warning](https://github.com/yarnpkg/yarn/issues/3738), which is a rather dramatic debate)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* Tiles will no longer be blurry on hover (Windows only bug)
|
* Tiles will no longer be blurry on hover (Windows only bug)
|
||||||
* Removed placeholder values from price selection form fields, which was causing confusion that these were real values (#426)
|
* Removed placeholder values from price selection form fields, which was causing confusion that these were real values (#426)
|
||||||
* Fixed showing "other currency" help tip in publish form, which was caused due to not "setting" state for price
|
* Fixed showing "other currency" help tip in publish form, which was caused due to not "setting" state for price
|
||||||
* Now using setState in formFieldPrice
|
|
||||||
* Public page now properly checks for all required fields are filled
|
* Public page now properly checks for all required fields are filled
|
||||||
* Fixed pagination styling for pages > 5 (#416)
|
* Fixed pagination styling for pages > 5 (#416)
|
||||||
* Fixed sizing on squat videos (#419)
|
* Fixed sizing on squat videos (#419)
|
||||||
|
|
12
README.md
12
README.md
|
@ -22,10 +22,12 @@ To install from source or make changes to the application, continue reading belo
|
||||||
|
|
||||||
### One-time Setup
|
### One-time Setup
|
||||||
|
|
||||||
1. Install node and npm.
|
1. Install npm and node (v6 and above required, use [nvm](https://github.com/creationix/nvm/blob/master/README.md) if having trouble)
|
||||||
2. Check out this repo.
|
2. Install keytar and libsecret (see [keytar repository](https://github.com/atom/node-keytar) )
|
||||||
3. Set up a Python virtual environment, or live on the wild side.
|
3. Install yarn by running: npm install -g yarn (may require elevated permissions)
|
||||||
4. Run `./build.sh`. This builds the UI assets and puts them into `app/dist`. It also downloads [lbry daemon](https://github.com/lbryio/lbry/releases).
|
4. Check out this repo.
|
||||||
|
5. Set up a Python virtual environment, or live on the wild side.
|
||||||
|
6. Run `./build.sh`. This builds the UI assets and puts them into `app/dist`. It also downloads [lbry daemon](https://github.com/lbryio/lbry/releases).
|
||||||
|
|
||||||
### Running
|
### Running
|
||||||
|
|
||||||
|
@ -51,4 +53,4 @@ checkout out the build steps in [appveyor.yml](https://github.com/lbryio/lbry-ap
|
||||||
|
|
||||||
## Internationalization
|
## Internationalization
|
||||||
|
|
||||||
If you want to help translating the lbry-app, you can copy the en.json file in /app/locales and modify the values while leaving the keys as their original English strings. An example for this would be: `"Skip": "Überspringen",` Translations should automatically show up in options.
|
If you want to help translating the lbry-app, you can copy the en.json file in /app/locales and modify the values while leaving the keys as their original English strings. An example for this would be: `"Skip": "Überspringen",` Translations should automatically show up in options.
|
||||||
|
|
|
@ -8,6 +8,8 @@ import {
|
||||||
selectPageTitle,
|
selectPageTitle,
|
||||||
selectCurrentPage,
|
selectCurrentPage,
|
||||||
selectCurrentParams,
|
selectCurrentParams,
|
||||||
|
selectHistoryBack,
|
||||||
|
selectHistoryForward,
|
||||||
} from "selectors/app";
|
} from "selectors/app";
|
||||||
import { doSearch } from "actions/search";
|
import { doSearch } from "actions/search";
|
||||||
import { doFetchDaemonSettings } from "actions/settings";
|
import { doFetchDaemonSettings } from "actions/settings";
|
||||||
|
@ -31,7 +33,11 @@ export function doNavigate(path, params = {}, options = {}) {
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const pageTitle = selectPageTitle(state);
|
const pageTitle = selectPageTitle(state);
|
||||||
dispatch(doHistoryPush({ params }, pageTitle, url));
|
const historyState = history.state;
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
doHistoryPush({ params, page: historyState.page + 1 }, pageTitle, url)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,10 +83,35 @@ export function doChangePath(path, options = {}) {
|
||||||
|
|
||||||
export function doHistoryBack() {
|
export function doHistoryBack() {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
if (!history.state) return;
|
// Get back history from stack
|
||||||
if (history.state.index === 0) return;
|
const back = selectHistoryBack(getState());
|
||||||
|
|
||||||
history.back();
|
if (back) {
|
||||||
|
// Set location
|
||||||
|
dispatch(doChangePath(back.location));
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: types.HISTORY_NAVIGATE,
|
||||||
|
data: { page: back },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doHistoryForward() {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
// Get forward history from stack
|
||||||
|
const forward = selectHistoryForward(getState());
|
||||||
|
|
||||||
|
if (forward) {
|
||||||
|
// Set location
|
||||||
|
dispatch(doChangePath(forward.location));
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: types.HISTORY_NAVIGATE,
|
||||||
|
data: { page: forward },
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +119,12 @@ export function doHistoryPush(currentState, title, relativeUrl) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
title += " - LBRY";
|
title += " - LBRY";
|
||||||
history.pushState(currentState, title, `#${relativeUrl}`);
|
history.pushState(currentState, title, `#${relativeUrl}`);
|
||||||
|
dispatch({
|
||||||
|
type: types.HISTORY_NAVIGATE,
|
||||||
|
data: {
|
||||||
|
location: relativeUrl,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,10 +303,22 @@ export function doDaemonReady() {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
const path = window.location.hash || "#/discover";
|
const path = window.location.hash || "#/discover";
|
||||||
const params = parseQueryParams(path.split("?")[1] || "");
|
const params = parseQueryParams(path.split("?")[1] || "");
|
||||||
history.replaceState({ params, index: 0 }, document.title, `${path}`);
|
|
||||||
|
// Get first page
|
||||||
|
const page = {
|
||||||
|
index: 0,
|
||||||
|
location: path.replace(/^#/, ""),
|
||||||
|
};
|
||||||
|
|
||||||
|
history.replaceState(
|
||||||
|
{ params, is_first_page: true, page: 1 },
|
||||||
|
document.title,
|
||||||
|
`${path}`
|
||||||
|
);
|
||||||
dispatch(doAuthenticate());
|
dispatch(doAuthenticate());
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.DAEMON_READY,
|
type: types.DAEMON_READY,
|
||||||
|
data: { page },
|
||||||
});
|
});
|
||||||
dispatch(doFetchDaemonSettings());
|
dispatch(doFetchDaemonSettings());
|
||||||
dispatch(doFileList());
|
dispatch(doFileList());
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import store from "store.js";
|
import store from "store.js";
|
||||||
import lbry from "./lbry.js";
|
import lbry from "./lbry.js";
|
||||||
|
import * as settings from "constants/settings";
|
||||||
|
|
||||||
const env = ENV;
|
const env = ENV;
|
||||||
const config = {
|
const config = {
|
||||||
...require(`./config/${env}`),
|
...require(`./config/${env}`),
|
||||||
};
|
};
|
||||||
const language = lbry.getClientSetting("language")
|
const language = lbry.getClientSetting(settings.LANGUAGE)
|
||||||
? lbry.getClientSetting("language")
|
? lbry.getClientSetting(settings.LANGUAGE)
|
||||||
: "en";
|
: "en";
|
||||||
const i18n = require("y18n")({
|
const i18n = require("y18n")({
|
||||||
directory: "app/locales",
|
directory: "app/locales",
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Router from "component/router";
|
import Router from "component/router/index";
|
||||||
import Header from "component/header";
|
import Header from "component/header";
|
||||||
import ModalError from "component/modalError";
|
import ModalRouter from "modal/modalRouter";
|
||||||
import ModalAuthFailure from "component/modalAuthFailure";
|
|
||||||
import ModalDownloading from "component/modalDownloading";
|
|
||||||
import ModalInsufficientCredits from "component/modalInsufficientCredits";
|
|
||||||
import ModalUpgrade from "component/modalUpgrade";
|
|
||||||
import ModalWelcome from "component/modalWelcome";
|
|
||||||
import ModalFirstReward from "component/modalFirstReward";
|
|
||||||
import lbry from "lbry";
|
import lbry from "lbry";
|
||||||
import * as modals from "constants/modal_types";
|
|
||||||
|
|
||||||
class App extends React.PureComponent {
|
class App extends React.PureComponent {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
@ -34,50 +27,23 @@ class App extends React.PureComponent {
|
||||||
|
|
||||||
fetchRewardedContent();
|
fetchRewardedContent();
|
||||||
|
|
||||||
this.showWelcome(this.props);
|
|
||||||
|
|
||||||
this.scrollListener = () => this.props.recordScroll(window.scrollY);
|
this.scrollListener = () => this.props.recordScroll(window.scrollY);
|
||||||
|
|
||||||
window.addEventListener("scroll", this.scrollListener);
|
window.addEventListener("scroll", this.scrollListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
this.showWelcome(nextProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
showWelcome(props) {
|
|
||||||
const { isWelcomeAcknowledged, openWelcomeModal, user } = props;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isWelcomeAcknowledged &&
|
|
||||||
user &&
|
|
||||||
!user.is_reward_approved &&
|
|
||||||
!user.is_identity_verified
|
|
||||||
) {
|
|
||||||
openWelcomeModal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
window.removeEventListener("scroll", this.scrollListener);
|
window.removeEventListener("scroll", this.scrollListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { modal } = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="window">
|
<div id="window">
|
||||||
<Header />
|
<Header />
|
||||||
<div id="main-content">
|
<div id="main-content">
|
||||||
<Router />
|
<Router />
|
||||||
</div>
|
</div>
|
||||||
{modal == modals.UPGRADE && <ModalUpgrade />}
|
<ModalRouter />
|
||||||
{modal == modals.DOWNLOADING && <ModalDownloading />}
|
|
||||||
{modal == modals.ERROR && <ModalError />}
|
|
||||||
{modal == modals.INSUFFICIENT_CREDITS && <ModalInsufficientCredits />}
|
|
||||||
{modal == modals.WELCOME && <ModalWelcome />}
|
|
||||||
{modal == modals.FIRST_REWARD && <ModalFirstReward />}
|
|
||||||
{modal == modals.AUTHENTICATION_FAILURE && <ModalAuthFailure />}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Icon, BusyMessage } from "component/common";
|
import { Icon, BusyMessage } from "component/common";
|
||||||
import FilePrice from "component/filePrice";
|
import FilePrice from "component/filePrice";
|
||||||
import { Modal } from "component/modal";
|
import { Modal } from "modal/modal";
|
||||||
import Link from "component/link";
|
import Link from "component/link";
|
||||||
import { ToolTip } from "component/tooltip";
|
import { ToolTip } from "component/tooltip";
|
||||||
import { DropDownMenu, DropDownMenuItem } from "component/menu";
|
import { DropDownMenu, DropDownMenuItem } from "component/menu";
|
||||||
import ModalRemoveFile from "component/modalRemoveFile";
|
import ModalRemoveFile from "modal/modalRemoveFile";
|
||||||
import * as modals from "constants/modal_types";
|
import * as modals from "constants/modal_types";
|
||||||
|
|
||||||
class FileActions extends React.PureComponent {
|
class FileActions extends React.PureComponent {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { formatCredits } from "utils";
|
import { formatCredits } from "utils";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
import { selectIsBackDisabled, selectIsForwardDisabled } from "selectors/app";
|
||||||
import { selectBalance } from "selectors/wallet";
|
import { selectBalance } from "selectors/wallet";
|
||||||
import { doNavigate, doHistoryBack } from "actions/app";
|
import { doNavigate, doHistoryBack, doHistoryForward } from "actions/app";
|
||||||
import Header from "./view";
|
import Header from "./view";
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
isBackDisabled: selectIsBackDisabled(state),
|
||||||
|
isForwardDisabled: selectIsForwardDisabled(state),
|
||||||
balance: formatCredits(selectBalance(state), 1),
|
balance: formatCredits(selectBalance(state), 1),
|
||||||
publish: __("Publish"),
|
publish: __("Publish"),
|
||||||
});
|
});
|
||||||
|
@ -13,6 +16,7 @@ const select = state => ({
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: path => dispatch(doNavigate(path)),
|
navigate: path => dispatch(doNavigate(path)),
|
||||||
back: () => dispatch(doHistoryBack()),
|
back: () => dispatch(doHistoryBack()),
|
||||||
|
forward: () => dispatch(doHistoryForward()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(Header);
|
export default connect(select, perform)(Header);
|
||||||
|
|
|
@ -3,12 +3,34 @@ import Link from "component/link";
|
||||||
import WunderBar from "component/wunderbar";
|
import WunderBar from "component/wunderbar";
|
||||||
|
|
||||||
export const Header = props => {
|
export const Header = props => {
|
||||||
const { balance, back, navigate, publish } = props;
|
const {
|
||||||
|
balance,
|
||||||
|
back,
|
||||||
|
forward,
|
||||||
|
isBackDisabled,
|
||||||
|
isForwardDisabled,
|
||||||
|
navigate,
|
||||||
|
publish,
|
||||||
|
} = props;
|
||||||
return (
|
return (
|
||||||
<header id="header">
|
<header id="header">
|
||||||
<div className="header__item">
|
<div className="header__item">
|
||||||
<Link onClick={back} button="alt button--flat" icon="icon-arrow-left" title={__("Back")} />
|
<Link
|
||||||
|
onClick={back}
|
||||||
|
disabled={isBackDisabled}
|
||||||
|
button="alt button--flat"
|
||||||
|
icon="icon-arrow-left"
|
||||||
|
title={__("Back")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="header__item">
|
||||||
|
<Link
|
||||||
|
onClick={forward}
|
||||||
|
disabled={isForwardDisabled}
|
||||||
|
button="alt button--flat"
|
||||||
|
icon="icon-arrow-right"
|
||||||
|
title={__("Forward")}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="header__item">
|
<div className="header__item">
|
||||||
<Link
|
<Link
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { Modal } from "component/modal";
|
|
||||||
import { CreditAmount } from "component/common";
|
|
||||||
import Link from "component/link";
|
|
||||||
import RewardLink from "component/rewardLink";
|
|
||||||
|
|
||||||
class ModalWelcome extends React.PureComponent {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isFirstScreen: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { closeModal, totalRewardValue, verifyAccount } = this.props;
|
|
||||||
|
|
||||||
const totalRewardRounded = Math.round(totalRewardValue / 10) * 10;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY">
|
|
||||||
{this.state.isFirstScreen &&
|
|
||||||
<section>
|
|
||||||
<h3 className="modal__header">{__("Welcome to LBRY")}</h3>
|
|
||||||
<p>
|
|
||||||
{__(
|
|
||||||
"Using LBRY is like dating a centaur. Totally normal up top, and"
|
|
||||||
)}
|
|
||||||
{" "}<em>{__("way different")}</em> {__("underneath.")}
|
|
||||||
</p>
|
|
||||||
<p>{__("Up top, LBRY is similar to popular media sites.")}</p>
|
|
||||||
<p>
|
|
||||||
{__(
|
|
||||||
"Below, LBRY is controlled by users -- you -- via blockchain and decentralization."
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<div className="modal__buttons">
|
|
||||||
<Link
|
|
||||||
button="primary"
|
|
||||||
onClick={() => {
|
|
||||||
this.setState({ isFirstScreen: false });
|
|
||||||
}}
|
|
||||||
label={__("Continue")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</section>}
|
|
||||||
{!this.state.isFirstScreen &&
|
|
||||||
<section>
|
|
||||||
<h3 className="modal__header">{__("Claim Your Credits")}</h3>
|
|
||||||
<p>
|
|
||||||
The LBRY network is controlled and powered by credits called{" "}
|
|
||||||
<em>LBC</em>, a blockchain asset.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{__("New patrons receive ")} {" "}
|
|
||||||
{totalRewardValue
|
|
||||||
? <CreditAmount amount={totalRewardRounded} />
|
|
||||||
: <span className="credit-amount">{__("credits")}</span>}
|
|
||||||
{" "} {__("in rewards for usage and influence of the network.")}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{__(
|
|
||||||
"You'll also earn weekly bonuses for checking out the greatest new stuff."
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<div className="modal__buttons">
|
|
||||||
<Link
|
|
||||||
button="primary"
|
|
||||||
onClick={verifyAccount}
|
|
||||||
label={__("You Had Me At Free LBC")}
|
|
||||||
/>
|
|
||||||
<Link
|
|
||||||
button="alt"
|
|
||||||
onClick={closeModal}
|
|
||||||
label={__("I Burn Money")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</section>}
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ModalWelcome;
|
|
|
@ -5,7 +5,7 @@ import FormField from "component/formField";
|
||||||
import { FormRow } from "component/form.js";
|
import { FormRow } from "component/form.js";
|
||||||
import Link from "component/link";
|
import Link from "component/link";
|
||||||
import FormFieldPrice from "component/formFieldPrice";
|
import FormFieldPrice from "component/formFieldPrice";
|
||||||
import Modal from "component/modal";
|
import Modal from "modal/modal";
|
||||||
import { BusyMessage } from "component/common";
|
import { BusyMessage } from "component/common";
|
||||||
import ChannelSection from "./internal/channelSection";
|
import ChannelSection from "./internal/channelSection";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Modal from "component/modal";
|
import Modal from "modal/modal";
|
||||||
import Link from "component/link";
|
import Link from "component/link";
|
||||||
|
|
||||||
const RewardLink = props => {
|
const RewardLink = props => {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import lbry from "../../lbry.js";
|
import lbry from "lbry.js";
|
||||||
import LoadScreen from "../load_screen.js";
|
import LoadScreen from "../load_screen.js";
|
||||||
import ModalIncompatibleDaemon from "../modalIncompatibleDaemon";
|
import ModalIncompatibleDaemon from "modal/modalIncompatibleDaemon";
|
||||||
import ModalUpgrade from "component/modalUpgrade";
|
import ModalUpgrade from "modal/modalUpgrade";
|
||||||
import ModalDownloading from "component/modalDownloading";
|
import ModalDownloading from "modal/modalDownloading";
|
||||||
|
|
||||||
export class SplashScreen extends React.PureComponent {
|
export class SplashScreen extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import FilePrice from "component/filePrice";
|
import FilePrice from "component/filePrice";
|
||||||
import Link from "component/link";
|
import Link from "component/link";
|
||||||
import Modal from "component/modal";
|
import Modal from "modal/modal";
|
||||||
|
|
||||||
class VideoPlayButton extends React.PureComponent {
|
class VideoPlayButton extends React.PureComponent {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Link from "component/link";
|
import Link from "component/link";
|
||||||
import Modal from "component/modal";
|
import Modal from "modal/modal";
|
||||||
import { FormRow } from "component/form";
|
import { FormRow } from "component/form";
|
||||||
|
|
||||||
const WalletSend = props => {
|
const WalletSend = props => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export const CHANGE_PATH = "CHANGE_PATH";
|
export const CHANGE_PATH = "CHANGE_PATH";
|
||||||
export const OPEN_MODAL = "OPEN_MODAL";
|
export const OPEN_MODAL = "OPEN_MODAL";
|
||||||
export const CLOSE_MODAL = "CLOSE_MODAL";
|
export const CLOSE_MODAL = "CLOSE_MODAL";
|
||||||
export const HISTORY_BACK = "HISTORY_BACK";
|
export const HISTORY_NAVIGATE = "HISTORY_NAVIGATE";
|
||||||
export const SHOW_SNACKBAR = "SHOW_SNACKBAR";
|
export const SHOW_SNACKBAR = "SHOW_SNACKBAR";
|
||||||
export const REMOVE_SNACKBAR_SNACK = "REMOVE_SNACKBAR_SNACK";
|
export const REMOVE_SNACKBAR_SNACK = "REMOVE_SNACKBAR_SNACK";
|
||||||
export const WINDOW_FOCUSED = "WINDOW_FOCUSED";
|
export const WINDOW_FOCUSED = "WINDOW_FOCUSED";
|
||||||
|
|
|
@ -6,4 +6,5 @@ export const INSUFFICIENT_CREDITS = "insufficient_credits";
|
||||||
export const UPGRADE = "upgrade";
|
export const UPGRADE = "upgrade";
|
||||||
export const WELCOME = "welcome";
|
export const WELCOME = "welcome";
|
||||||
export const FIRST_REWARD = "first_reward";
|
export const FIRST_REWARD = "first_reward";
|
||||||
export const AUTHENTICATION_FAILURE = "auth_failure";
|
export const AUTHENTICATION_FAILURE = "auth_failure";
|
||||||
|
export const CREDIT_INTRO = "credit_intro";
|
||||||
|
|
5
ui/js/constants/settings.js
Normal file
5
ui/js/constants/settings.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export const CREDIT_INTRO_ACKNOWLEDGED = "credit_intro_acknowledged";
|
||||||
|
export const FIRST_RUN_ACKNOWLEDGED = "welcome_acknowledged";
|
||||||
|
export const LANGUAGE = "language";
|
||||||
|
export const SHOW_NSFW = "showNsfw";
|
||||||
|
export const SHOW_UNAVAILABLE = "showUnavailable";
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactModal from "react-modal";
|
import ReactModal from "react-modal";
|
||||||
import Link from "component/link";
|
import Link from "component/link/index";
|
||||||
import app from "../app.js";
|
import app from "app.js";
|
||||||
|
|
||||||
export class Modal extends React.PureComponent {
|
export class Modal extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Modal } from "component/modal";
|
import { Modal } from "modal/modal";
|
||||||
|
|
||||||
class ModalAuthFailure extends React.PureComponent {
|
class ModalAuthFailure extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
|
@ -12,11 +12,17 @@ class ModalAuthFailure extends React.PureComponent {
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__("Reload")}
|
confirmButtonLabel={__("Reload")}
|
||||||
abortButtonLabel={__("Continue")}
|
abortButtonLabel={__("Continue")}
|
||||||
onConfirmed={() => { window.location.reload() }}
|
onConfirmed={() => {
|
||||||
|
window.location.reload();
|
||||||
|
}}
|
||||||
onAborted={close}
|
onAborted={close}
|
||||||
>
|
>
|
||||||
<h3>{__("Authentication Failure")}</h3>
|
<h3>{__("Authentication Failure")}</h3>
|
||||||
<p>{__("If reloading does not fix this, or you see this at every start up, please email help@lbry.io.")}</p>
|
<p>
|
||||||
|
{__(
|
||||||
|
"If reloading does not fix this, or you see this at every start up, please email help@lbry.io."
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -9,7 +9,8 @@ import {
|
||||||
makeSelectRewardByType,
|
makeSelectRewardByType,
|
||||||
selectTotalRewardValue,
|
selectTotalRewardValue,
|
||||||
} from "selectors/rewards";
|
} from "selectors/rewards";
|
||||||
import ModalWelcome from "./view";
|
import * as settings from "constants/settings";
|
||||||
|
import ModalCreditIntro from "./view";
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const selectHasClaimed = makeSelectHasClaimedReward(),
|
const selectHasClaimed = makeSelectHasClaimedReward(),
|
||||||
|
@ -24,7 +25,7 @@ const select = (state, props) => {
|
||||||
|
|
||||||
const perform = dispatch => () => {
|
const perform = dispatch => () => {
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
dispatch(doSetClientSetting("welcome_acknowledged", true));
|
dispatch(doSetClientSetting(settings.CREDIT_INTRO_ACKNOWLEDGED, true));
|
||||||
dispatch(doCloseModal());
|
dispatch(doCloseModal());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,4 +38,4 @@ const perform = dispatch => () => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(select, perform)(ModalWelcome);
|
export default connect(select, perform)(ModalCreditIntro);
|
44
ui/js/modal/modalCreditIntro/view.jsx
Normal file
44
ui/js/modal/modalCreditIntro/view.jsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Modal } from "modal/modal";
|
||||||
|
import { CreditAmount } from "component/common";
|
||||||
|
import Link from "component/link/index";
|
||||||
|
|
||||||
|
const ModalCreditIntro = props => {
|
||||||
|
const { closeModal, totalRewardValue, verifyAccount } = props;
|
||||||
|
|
||||||
|
const totalRewardRounded = Math.round(totalRewardValue / 10) * 10;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY">
|
||||||
|
<section>
|
||||||
|
<h3 className="modal__header">{__("Claim Your Credits")}</h3>
|
||||||
|
<p>
|
||||||
|
The LBRY network is controlled and powered by credits called{" "}
|
||||||
|
<em>LBC</em>, a blockchain asset.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{__("New patrons receive ")} {" "}
|
||||||
|
{totalRewardValue
|
||||||
|
? <CreditAmount amount={totalRewardRounded} />
|
||||||
|
: <span className="credit-amount">{__("credits")}</span>}
|
||||||
|
{" "} {__("in rewards for usage and influence of the network.")}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
"You'll also earn weekly bonuses for checking out the greatest new stuff."
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<div className="modal__buttons">
|
||||||
|
<Link
|
||||||
|
button="primary"
|
||||||
|
onClick={verifyAccount}
|
||||||
|
label={__("You Had Me At Free LBC")}
|
||||||
|
/>
|
||||||
|
<Link button="alt" onClick={closeModal} label={__("I Burn Money")} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalCreditIntro;
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Modal } from "component/modal";
|
import { Modal } from "modal/modal";
|
||||||
import { Line } from "rc-progress";
|
import { Line } from "rc-progress";
|
||||||
import Link from "component/link";
|
import Link from "component/link/index";
|
||||||
|
|
||||||
class ModalDownloading extends React.PureComponent {
|
class ModalDownloading extends React.PureComponent {
|
||||||
render() {
|
render() {
|
|
@ -1,6 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import lbry from "lbry";
|
import lbry from "lbry";
|
||||||
import { ExpandableModal } from "component/modal";
|
import { ExpandableModal } from "modal/modal";
|
||||||
|
|
||||||
class ModalError extends React.PureComponent {
|
class ModalError extends React.PureComponent {
|
||||||
render() {
|
render() {
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Modal } from "component/modal";
|
import { Modal } from "modal/modal";
|
||||||
import { CreditAmount } from "component/common";
|
import { CreditAmount } from "component/common";
|
||||||
|
|
||||||
class ModalFirstReward extends React.PureComponent {
|
class ModalFirstReward extends React.PureComponent {
|
|
@ -1,6 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Modal } from "component/modal";
|
import { Modal } from "modal/modal";
|
||||||
import Link from "component/link";
|
import Link from "component/link/index";
|
||||||
|
|
||||||
class ModalIncompatibleDaemon extends React.PureComponent {
|
class ModalIncompatibleDaemon extends React.PureComponent {
|
||||||
render() {
|
render() {
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Modal } from "component/modal";
|
import { Modal } from "modal/modal";
|
||||||
|
|
||||||
class ModalInsufficientCredits extends React.PureComponent {
|
class ModalInsufficientCredits extends React.PureComponent {
|
||||||
render() {
|
render() {
|
|
@ -1,6 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Modal } from "component/modal";
|
import { Modal } from "modal/modal";
|
||||||
import FormField from "component/formField";
|
import FormField from "component/formField/index";
|
||||||
|
|
||||||
class ModalRemoveFile extends React.PureComponent {
|
class ModalRemoveFile extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
20
ui/js/modal/modalRouter/index.js
Normal file
20
ui/js/modal/modalRouter/index.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { selectCurrentModal } from "selectors/app";
|
||||||
|
import { doOpenModal } from "actions/app";
|
||||||
|
import { selectWelcomeModalAcknowledged } from "selectors/app";
|
||||||
|
import { selectUser } from "selectors/user";
|
||||||
|
import ModalRouter from "./view";
|
||||||
|
import * as modals from "constants/modal_types";
|
||||||
|
|
||||||
|
const select = (state, props) => ({
|
||||||
|
modal: selectCurrentModal(state),
|
||||||
|
isWelcomeAcknowledged: selectWelcomeModalAcknowledged(state),
|
||||||
|
user: selectUser(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
openWelcomeModal: () => dispatch(doOpenModal(modals.WELCOME)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(ModalRouter);
|
60
ui/js/modal/modalRouter/view.jsx
Normal file
60
ui/js/modal/modalRouter/view.jsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import React from "react";
|
||||||
|
import ModalError from "modal/modalError";
|
||||||
|
import ModalAuthFailure from "modal/modalAuthFailure";
|
||||||
|
import ModalDownloading from "modal/modalDownloading";
|
||||||
|
import ModalInsufficientCredits from "modal/modalInsufficientCredits";
|
||||||
|
import ModalUpgrade from "modal/modalUpgrade";
|
||||||
|
import ModalWelcome from "modal/modalWelcome";
|
||||||
|
import ModalFirstReward from "modal/modalFirstReward";
|
||||||
|
import * as modals from "constants/modal_types";
|
||||||
|
import ModalCreditIntro from "modal/modalCreditIntro";
|
||||||
|
|
||||||
|
class ModalRouter extends React.PureComponent {
|
||||||
|
componentWillMount() {
|
||||||
|
this.showWelcome(this.props);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
this.showWelcome(nextProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
showWelcome(props) {
|
||||||
|
const { isWelcomeAcknowledged, openWelcomeModal, user } = props;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isWelcomeAcknowledged &&
|
||||||
|
user &&
|
||||||
|
!user.is_reward_approved &&
|
||||||
|
!user.is_identity_verified
|
||||||
|
) {
|
||||||
|
openWelcomeModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { modal } = this.props;
|
||||||
|
|
||||||
|
switch (modal) {
|
||||||
|
case modals.UPGRADE:
|
||||||
|
return <ModalUpgrade />;
|
||||||
|
case modals.DOWNLOADING:
|
||||||
|
return <ModalDownloading />;
|
||||||
|
case modals.ERROR:
|
||||||
|
return <ModalError />;
|
||||||
|
case modals.INSUFFICIENT_CREDITS:
|
||||||
|
return <ModalInsufficientCredits />;
|
||||||
|
case modals.WELCOME:
|
||||||
|
return <ModalWelcome />;
|
||||||
|
case modals.FIRST_REWARD:
|
||||||
|
return <ModalFirstReward />;
|
||||||
|
case modals.AUTHENTICATION_FAILURE:
|
||||||
|
return <ModalAuthFailure />;
|
||||||
|
case modals.CREDIT_INTRO:
|
||||||
|
return <ModalCreditIntro />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalRouter;
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Modal } from "component/modal";
|
import { Modal } from "modal/modal";
|
||||||
|
|
||||||
class ModalUpgrade extends React.PureComponent {
|
class ModalUpgrade extends React.PureComponent {
|
||||||
render() {
|
render() {
|
17
ui/js/modal/modalWelcome/index.js
Normal file
17
ui/js/modal/modalWelcome/index.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import React from "react";
|
||||||
|
import * as settings from "constants/settings";
|
||||||
|
import * as modals from "constants/modal_types";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { doCloseModal, doOpenModal } from "actions/app";
|
||||||
|
import { doSetClientSetting } from "actions/settings";
|
||||||
|
import ModalWelcome from "./view";
|
||||||
|
|
||||||
|
const perform = dispatch => () => ({
|
||||||
|
closeModal: () => {
|
||||||
|
dispatch(doSetClientSetting(settings.FIRST_RUN_ACKNOWLEDGED, true));
|
||||||
|
dispatch(doCloseModal());
|
||||||
|
dispatch(doOpenModal(modals.CREDIT_INTRO));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(null, perform)(ModalWelcome);
|
32
ui/js/modal/modalWelcome/view.jsx
Normal file
32
ui/js/modal/modalWelcome/view.jsx
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Modal } from "modal/modal";
|
||||||
|
import Link from "component/link/index";
|
||||||
|
|
||||||
|
const ModalWelcome = props => {
|
||||||
|
const { closeModal } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY">
|
||||||
|
<section>
|
||||||
|
<h3 className="modal__header">{__("Welcome to LBRY")}</h3>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
"Using LBRY is like dating a centaur. Totally normal up top, and"
|
||||||
|
)}
|
||||||
|
{" "}<em>{__("way different")}</em> {__("underneath.")}
|
||||||
|
</p>
|
||||||
|
<p>{__("Up top, LBRY is similar to popular media sites.")}</p>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
"Below, LBRY is controlled by users -- you -- via blockchain and decentralization."
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<div className="modal__buttons">
|
||||||
|
<Link button="primary" onClick={closeModal} label={__("Continue")} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalWelcome;
|
|
@ -2,6 +2,7 @@ import React from "react";
|
||||||
import FormField from "component/formField";
|
import FormField from "component/formField";
|
||||||
import { FormRow } from "component/form.js";
|
import { FormRow } from "component/form.js";
|
||||||
import SubHeader from "component/subHeader";
|
import SubHeader from "component/subHeader";
|
||||||
|
import * as settings from "constants/settings";
|
||||||
import lbry from "lbry.js";
|
import lbry from "lbry.js";
|
||||||
import Link from "component/link";
|
import Link from "component/link";
|
||||||
import FormFieldPrice from "component/formFieldPrice";
|
import FormFieldPrice from "component/formFieldPrice";
|
||||||
|
@ -17,8 +18,8 @@ class SettingsPage extends React.PureComponent {
|
||||||
this.state = {
|
this.state = {
|
||||||
// isMaxUpload: daemonSettings && daemonSettings.max_upload != 0,
|
// isMaxUpload: daemonSettings && daemonSettings.max_upload != 0,
|
||||||
// isMaxDownload: daemonSettings && daemonSettings.max_download != 0,
|
// isMaxDownload: daemonSettings && daemonSettings.max_download != 0,
|
||||||
showUnavailable: lbry.getClientSetting("showUnavailable"),
|
showUnavailable: lbry.getClientSetting(settings.SHOW_UNAVAILABLE),
|
||||||
language: lbry.getClientSetting("language"),
|
language: lbry.getClientSetting(settings.LANGUAGE),
|
||||||
clearingCache: false,
|
clearingCache: false,
|
||||||
theme: lbry.getClientSetting("theme"),
|
theme: lbry.getClientSetting("theme"),
|
||||||
themes: [],
|
themes: [],
|
||||||
|
@ -109,7 +110,7 @@ class SettingsPage extends React.PureComponent {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
onShowNsfwChange(event) {
|
onShowNsfwChange(event) {
|
||||||
this.props.setClientSetting("showNsfw", event.target.checked);
|
this.props.setClientSetting(settings.SHOW_NSFW, event.target.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
// onLanguageChange(language) {
|
// onLanguageChange(language) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import * as types from "constants/action_types";
|
import * as types from "constants/action_types";
|
||||||
import * as modalTypes from "constants/modal_types";
|
import * as modalTypes from "constants/modal_types";
|
||||||
import lbry from "lbry";
|
|
||||||
|
|
||||||
const currentPath = () => {
|
const currentPath = () => {
|
||||||
const hash = document.location.hash;
|
const hash = document.location.hash;
|
||||||
|
@ -15,6 +14,8 @@ const win = remote.BrowserWindow.getFocusedWindow();
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
isLoaded: false,
|
isLoaded: false,
|
||||||
|
isBackDisabled: true,
|
||||||
|
isForwardDisabled: true,
|
||||||
currentPath: currentPath(),
|
currentPath: currentPath(),
|
||||||
pathAfterAuth: "/discover",
|
pathAfterAuth: "/discover",
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
|
@ -23,11 +24,17 @@ const defaultState = {
|
||||||
daemonReady: false,
|
daemonReady: false,
|
||||||
hasSignature: false,
|
hasSignature: false,
|
||||||
badgeNumber: 0,
|
badgeNumber: 0,
|
||||||
|
history: { index: 0, stack: [] },
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[types.DAEMON_READY] = function(state, action) {
|
reducers[types.DAEMON_READY] = function(state, action) {
|
||||||
|
const { history } = state;
|
||||||
|
const { page } = action.data;
|
||||||
|
history.stack.push(page);
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
daemonReady: true,
|
daemonReady: true,
|
||||||
|
history,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -163,6 +170,55 @@ reducers[types.WINDOW_FOCUSED] = function(state, action) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
reducers[types.HISTORY_NAVIGATE] = (state, action) => {
|
||||||
|
let page = false;
|
||||||
|
let location = false;
|
||||||
|
|
||||||
|
// Get history from state
|
||||||
|
const { history } = state;
|
||||||
|
|
||||||
|
if (action.data.page) {
|
||||||
|
// Get page
|
||||||
|
page = action.data.page;
|
||||||
|
} else if (action.data.location) {
|
||||||
|
// Get new location
|
||||||
|
location = action.data.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new location to stack
|
||||||
|
if (location) {
|
||||||
|
const lastItem = history.stack.length - 1;
|
||||||
|
|
||||||
|
// Check for duplicated
|
||||||
|
let is_duplicate = lastItem > -1
|
||||||
|
? history.stack[lastItem].location === location
|
||||||
|
: false;
|
||||||
|
|
||||||
|
if (!is_duplicate) {
|
||||||
|
// Create new page
|
||||||
|
page = {
|
||||||
|
index: history.stack.length,
|
||||||
|
location,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update index
|
||||||
|
history.index = history.stack.length;
|
||||||
|
|
||||||
|
// Add to stack
|
||||||
|
history.stack.push(page);
|
||||||
|
}
|
||||||
|
} else if (page) {
|
||||||
|
// Update index
|
||||||
|
history.index = page.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
history,
|
||||||
|
isBackDisabled: history.index === 0, // First page
|
||||||
|
isForwardDisabled: history.index === history.stack.length - 1, // Last page
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export default function reducer(state = defaultState, action) {
|
export default function reducer(state = defaultState, action) {
|
||||||
const handler = reducers[action.type];
|
const handler = reducers[action.type];
|
||||||
if (handler) return handler(state, action);
|
if (handler) return handler(state, action);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { createSelector } from "reselect";
|
import { createSelector } from "reselect";
|
||||||
import { parseQueryParams, toQueryString } from "util/query_params";
|
import { parseQueryParams, toQueryString } from "util/query_params";
|
||||||
|
import * as settings from "constants/settings.js";
|
||||||
import lbry from "lbry";
|
import lbry from "lbry";
|
||||||
import lbryuri from "lbryuri";
|
import lbryuri from "lbryuri";
|
||||||
|
|
||||||
|
@ -202,9 +203,14 @@ export const selectSnackBarSnacks = createSelector(
|
||||||
snackBar => snackBar.snacks || []
|
snackBar => snackBar.snacks || []
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectCreditsIntroAcknowledged = createSelector(
|
||||||
|
_selectState,
|
||||||
|
state => lbry.getClientSetting(settings.CREDIT_INTRO_ACKNOWLEDGED)
|
||||||
|
);
|
||||||
|
|
||||||
export const selectWelcomeModalAcknowledged = createSelector(
|
export const selectWelcomeModalAcknowledged = createSelector(
|
||||||
_selectState,
|
_selectState,
|
||||||
state => lbry.getClientSetting("welcome_acknowledged")
|
state => lbry.getClientSetting(settings.FIRST_RUN_ACKNOWLEDGED)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectBadgeNumber = createSelector(
|
export const selectBadgeNumber = createSelector(
|
||||||
|
@ -216,3 +222,35 @@ export const selectPathAfterAuth = createSelector(
|
||||||
_selectState,
|
_selectState,
|
||||||
state => state.pathAfterAuth
|
state => state.pathAfterAuth
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectIsBackDisabled = createSelector(
|
||||||
|
_selectState,
|
||||||
|
state => state.isBackDisabled
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectIsForwardDisabled = createSelector(
|
||||||
|
_selectState,
|
||||||
|
state => state.isForwardDisabled
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectHistoryBack = createSelector(_selectState, state => {
|
||||||
|
const { history } = state;
|
||||||
|
const index = history.index - 1;
|
||||||
|
|
||||||
|
// Check if page exists
|
||||||
|
if (index > -1) {
|
||||||
|
// Get back history
|
||||||
|
return history.stack[index];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const selectHistoryForward = createSelector(_selectState, state => {
|
||||||
|
const { history } = state;
|
||||||
|
const index = history.index + 1;
|
||||||
|
|
||||||
|
// Check if page exists
|
||||||
|
if (index <= history.stack.length) {
|
||||||
|
// Get forward history
|
||||||
|
return history.stack[index];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -105,7 +105,7 @@ p
|
||||||
|
|
||||||
.disabled {
|
.disabled {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.7;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.truncated-text {
|
.truncated-text {
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
max-width: none;
|
max-width: none;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
.error-modal__error-list { /*shitty hack/temp fix for long errors making modals unusable*/
|
.error-modal__error-list { /*shitty hack/temp fix for long errors making modal unusable*/
|
||||||
border: 1px solid #eee;
|
border: 1px solid #eee;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
|
Loading…
Add table
Reference in a new issue