Merge branch 'master' into master

This commit is contained in:
Baltazar Gomez 2017-08-18 15:54:18 -06:00 committed by GitHub
commit d2c735717c
46 changed files with 426 additions and 182 deletions

View file

@ -10,22 +10,25 @@ Web UI version numbers should always match the corresponding version of LBRY App
### Added
* Added a new component, `FormFieldPrice` which is now used in Publish and Settings
* Added a theme system to select different themes in Settings.
* New Dark theme.
* Added wallet backup guide reference
*
* Added a new dark theme.
* 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
* 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.
* Removed confusing placeholder text from email input
* 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)
* Some form field refactoring as we take baby steps towards form sanity.
* 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
* 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)
* 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
* Fixed pagination styling for pages > 5 (#416)
* Fixed sizing on squat videos (#419)

View file

@ -22,10 +22,12 @@ To install from source or make changes to the application, continue reading belo
### One-time Setup
1. Install node and npm.
2. Check out this repo.
3. Set up a Python virtual environment, or live on the wild side.
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).
1. Install npm and node (v6 and above required, use [nvm](https://github.com/creationix/nvm/blob/master/README.md) if having trouble)
2. Install keytar and libsecret (see [keytar repository](https://github.com/atom/node-keytar) )
3. Install yarn by running: npm install -g yarn (may require elevated permissions)
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
@ -51,4 +53,4 @@ checkout out the build steps in [appveyor.yml](https://github.com/lbryio/lbry-ap
## 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.

View file

@ -8,6 +8,8 @@ import {
selectPageTitle,
selectCurrentPage,
selectCurrentParams,
selectHistoryBack,
selectHistoryForward,
} from "selectors/app";
import { doSearch } from "actions/search";
import { doFetchDaemonSettings } from "actions/settings";
@ -31,7 +33,11 @@ export function doNavigate(path, params = {}, options = {}) {
const state = getState();
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() {
return function(dispatch, getState) {
if (!history.state) return;
if (history.state.index === 0) return;
// Get back history from stack
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) {
title += " - LBRY";
history.pushState(currentState, title, `#${relativeUrl}`);
dispatch({
type: types.HISTORY_NAVIGATE,
data: {
location: relativeUrl,
},
});
};
}
@ -266,10 +303,22 @@ export function doDaemonReady() {
return function(dispatch, getState) {
const path = window.location.hash || "#/discover";
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({
type: types.DAEMON_READY,
data: { page },
});
dispatch(doFetchDaemonSettings());
dispatch(doFileList());

View file

@ -1,12 +1,13 @@
import store from "store.js";
import lbry from "./lbry.js";
import * as settings from "constants/settings";
const env = ENV;
const config = {
...require(`./config/${env}`),
};
const language = lbry.getClientSetting("language")
? lbry.getClientSetting("language")
const language = lbry.getClientSetting(settings.LANGUAGE)
? lbry.getClientSetting(settings.LANGUAGE)
: "en";
const i18n = require("y18n")({
directory: "app/locales",

View file

@ -1,15 +1,8 @@
import React from "react";
import Router from "component/router";
import Router from "component/router/index";
import Header from "component/header";
import ModalError from "component/modalError";
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 ModalRouter from "modal/modalRouter";
import lbry from "lbry";
import * as modals from "constants/modal_types";
class App extends React.PureComponent {
componentWillMount() {
@ -34,50 +27,23 @@ class App extends React.PureComponent {
fetchRewardedContent();
this.showWelcome(this.props);
this.scrollListener = () => this.props.recordScroll(window.scrollY);
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() {
window.removeEventListener("scroll", this.scrollListener);
}
render() {
const { modal } = this.props;
return (
<div id="window">
<Header />
<div id="main-content">
<Router />
</div>
{modal == modals.UPGRADE && <ModalUpgrade />}
{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 />}
<ModalRouter />
</div>
);
}

View file

@ -1,11 +1,11 @@
import React from "react";
import { Icon, BusyMessage } from "component/common";
import FilePrice from "component/filePrice";
import { Modal } from "component/modal";
import { Modal } from "modal/modal";
import Link from "component/link";
import { ToolTip } from "component/tooltip";
import { DropDownMenu, DropDownMenuItem } from "component/menu";
import ModalRemoveFile from "component/modalRemoveFile";
import ModalRemoveFile from "modal/modalRemoveFile";
import * as modals from "constants/modal_types";
class FileActions extends React.PureComponent {

View file

@ -1,11 +1,14 @@
import React from "react";
import { formatCredits } from "utils";
import { connect } from "react-redux";
import { selectIsBackDisabled, selectIsForwardDisabled } from "selectors/app";
import { selectBalance } from "selectors/wallet";
import { doNavigate, doHistoryBack } from "actions/app";
import { doNavigate, doHistoryBack, doHistoryForward } from "actions/app";
import Header from "./view";
const select = state => ({
isBackDisabled: selectIsBackDisabled(state),
isForwardDisabled: selectIsForwardDisabled(state),
balance: formatCredits(selectBalance(state), 1),
publish: __("Publish"),
});
@ -13,6 +16,7 @@ const select = state => ({
const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
back: () => dispatch(doHistoryBack()),
forward: () => dispatch(doHistoryForward()),
});
export default connect(select, perform)(Header);

View file

@ -3,12 +3,34 @@ import Link from "component/link";
import WunderBar from "component/wunderbar";
export const Header = props => {
const { balance, back, navigate, publish } = props;
const {
balance,
back,
forward,
isBackDisabled,
isForwardDisabled,
navigate,
publish,
} = props;
return (
<header id="header">
<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 className="header__item">
<Link

View file

@ -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;

View file

@ -5,7 +5,7 @@ import FormField from "component/formField";
import { FormRow } from "component/form.js";
import Link from "component/link";
import FormFieldPrice from "component/formFieldPrice";
import Modal from "component/modal";
import Modal from "modal/modal";
import { BusyMessage } from "component/common";
import ChannelSection from "./internal/channelSection";

View file

@ -1,5 +1,5 @@
import React from "react";
import Modal from "component/modal";
import Modal from "modal/modal";
import Link from "component/link";
const RewardLink = props => {

View file

@ -1,9 +1,9 @@
import React from "react";
import lbry from "../../lbry.js";
import lbry from "lbry.js";
import LoadScreen from "../load_screen.js";
import ModalIncompatibleDaemon from "../modalIncompatibleDaemon";
import ModalUpgrade from "component/modalUpgrade";
import ModalDownloading from "component/modalDownloading";
import ModalIncompatibleDaemon from "modal/modalIncompatibleDaemon";
import ModalUpgrade from "modal/modalUpgrade";
import ModalDownloading from "modal/modalDownloading";
export class SplashScreen extends React.PureComponent {
static propTypes = {

View file

@ -1,7 +1,7 @@
import React from "react";
import FilePrice from "component/filePrice";
import Link from "component/link";
import Modal from "component/modal";
import Modal from "modal/modal";
class VideoPlayButton extends React.PureComponent {
componentDidMount() {

View file

@ -1,6 +1,6 @@
import React from "react";
import Link from "component/link";
import Modal from "component/modal";
import Modal from "modal/modal";
import { FormRow } from "component/form";
const WalletSend = props => {

View file

@ -1,7 +1,7 @@
export const CHANGE_PATH = "CHANGE_PATH";
export const OPEN_MODAL = "OPEN_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 REMOVE_SNACKBAR_SNACK = "REMOVE_SNACKBAR_SNACK";
export const WINDOW_FOCUSED = "WINDOW_FOCUSED";

View file

@ -6,4 +6,5 @@ export const INSUFFICIENT_CREDITS = "insufficient_credits";
export const UPGRADE = "upgrade";
export const WELCOME = "welcome";
export const FIRST_REWARD = "first_reward";
export const AUTHENTICATION_FAILURE = "auth_failure";
export const AUTHENTICATION_FAILURE = "auth_failure";
export const CREDIT_INTRO = "credit_intro";

View 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";

View file

@ -1,7 +1,7 @@
import React from "react";
import ReactModal from "react-modal";
import Link from "component/link";
import app from "../app.js";
import Link from "component/link/index";
import app from "app.js";
export class Modal extends React.PureComponent {
static propTypes = {

View file

@ -1,5 +1,5 @@
import React from "react";
import { Modal } from "component/modal";
import { Modal } from "modal/modal";
class ModalAuthFailure extends React.PureComponent {
render() {
@ -12,11 +12,17 @@ class ModalAuthFailure extends React.PureComponent {
type="confirm"
confirmButtonLabel={__("Reload")}
abortButtonLabel={__("Continue")}
onConfirmed={() => { window.location.reload() }}
onConfirmed={() => {
window.location.reload();
}}
onAborted={close}
>
<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>
);
}

View file

@ -9,7 +9,8 @@ import {
makeSelectRewardByType,
selectTotalRewardValue,
} from "selectors/rewards";
import ModalWelcome from "./view";
import * as settings from "constants/settings";
import ModalCreditIntro from "./view";
const select = (state, props) => {
const selectHasClaimed = makeSelectHasClaimedReward(),
@ -24,7 +25,7 @@ const select = (state, props) => {
const perform = dispatch => () => {
const closeModal = () => {
dispatch(doSetClientSetting("welcome_acknowledged", true));
dispatch(doSetClientSetting(settings.CREDIT_INTRO_ACKNOWLEDGED, true));
dispatch(doCloseModal());
};
@ -37,4 +38,4 @@ const perform = dispatch => () => {
};
};
export default connect(select, perform)(ModalWelcome);
export default connect(select, perform)(ModalCreditIntro);

View 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;

View file

@ -1,7 +1,7 @@
import React from "react";
import { Modal } from "component/modal";
import { Modal } from "modal/modal";
import { Line } from "rc-progress";
import Link from "component/link";
import Link from "component/link/index";
class ModalDownloading extends React.PureComponent {
render() {

View file

@ -1,6 +1,6 @@
import React from "react";
import lbry from "lbry";
import { ExpandableModal } from "component/modal";
import { ExpandableModal } from "modal/modal";
class ModalError extends React.PureComponent {
render() {

View file

@ -1,5 +1,5 @@
import React from "react";
import { Modal } from "component/modal";
import { Modal } from "modal/modal";
import { CreditAmount } from "component/common";
class ModalFirstReward extends React.PureComponent {

View file

@ -1,6 +1,6 @@
import React from "react";
import { Modal } from "component/modal";
import Link from "component/link";
import { Modal } from "modal/modal";
import Link from "component/link/index";
class ModalIncompatibleDaemon extends React.PureComponent {
render() {

View file

@ -1,5 +1,5 @@
import React from "react";
import { Modal } from "component/modal";
import { Modal } from "modal/modal";
class ModalInsufficientCredits extends React.PureComponent {
render() {

View file

@ -1,6 +1,6 @@
import React from "react";
import { Modal } from "component/modal";
import FormField from "component/formField";
import { Modal } from "modal/modal";
import FormField from "component/formField/index";
class ModalRemoveFile extends React.PureComponent {
constructor(props) {

View 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);

View 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;

View file

@ -1,5 +1,5 @@
import React from "react";
import { Modal } from "component/modal";
import { Modal } from "modal/modal";
class ModalUpgrade extends React.PureComponent {
render() {

View 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);

View 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;

View file

@ -2,6 +2,7 @@ import React from "react";
import FormField from "component/formField";
import { FormRow } from "component/form.js";
import SubHeader from "component/subHeader";
import * as settings from "constants/settings";
import lbry from "lbry.js";
import Link from "component/link";
import FormFieldPrice from "component/formFieldPrice";
@ -17,8 +18,8 @@ class SettingsPage extends React.PureComponent {
this.state = {
// isMaxUpload: daemonSettings && daemonSettings.max_upload != 0,
// isMaxDownload: daemonSettings && daemonSettings.max_download != 0,
showUnavailable: lbry.getClientSetting("showUnavailable"),
language: lbry.getClientSetting("language"),
showUnavailable: lbry.getClientSetting(settings.SHOW_UNAVAILABLE),
language: lbry.getClientSetting(settings.LANGUAGE),
clearingCache: false,
theme: lbry.getClientSetting("theme"),
themes: [],
@ -109,7 +110,7 @@ class SettingsPage extends React.PureComponent {
// }
onShowNsfwChange(event) {
this.props.setClientSetting("showNsfw", event.target.checked);
this.props.setClientSetting(settings.SHOW_NSFW, event.target.checked);
}
// onLanguageChange(language) {

View file

@ -1,6 +1,5 @@
import * as types from "constants/action_types";
import * as modalTypes from "constants/modal_types";
import lbry from "lbry";
const currentPath = () => {
const hash = document.location.hash;
@ -15,6 +14,8 @@ const win = remote.BrowserWindow.getFocusedWindow();
const reducers = {};
const defaultState = {
isLoaded: false,
isBackDisabled: true,
isForwardDisabled: true,
currentPath: currentPath(),
pathAfterAuth: "/discover",
platform: process.platform,
@ -23,11 +24,17 @@ const defaultState = {
daemonReady: false,
hasSignature: false,
badgeNumber: 0,
history: { index: 0, stack: [] },
};
reducers[types.DAEMON_READY] = function(state, action) {
const { history } = state;
const { page } = action.data;
history.stack.push(page);
return Object.assign({}, state, {
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) {
const handler = reducers[action.type];
if (handler) return handler(state, action);

View file

@ -1,5 +1,6 @@
import { createSelector } from "reselect";
import { parseQueryParams, toQueryString } from "util/query_params";
import * as settings from "constants/settings.js";
import lbry from "lbry";
import lbryuri from "lbryuri";
@ -202,9 +203,14 @@ export const selectSnackBarSnacks = createSelector(
snackBar => snackBar.snacks || []
);
export const selectCreditsIntroAcknowledged = createSelector(
_selectState,
state => lbry.getClientSetting(settings.CREDIT_INTRO_ACKNOWLEDGED)
);
export const selectWelcomeModalAcknowledged = createSelector(
_selectState,
state => lbry.getClientSetting("welcome_acknowledged")
state => lbry.getClientSetting(settings.FIRST_RUN_ACKNOWLEDGED)
);
export const selectBadgeNumber = createSelector(
@ -216,3 +222,35 @@ export const selectPathAfterAuth = createSelector(
_selectState,
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];
}
});

View file

@ -105,7 +105,7 @@ p
.disabled {
pointer-events: none;
opacity: 0.7;
opacity: 0.5;
}
.truncated-text {

View file

@ -73,7 +73,7 @@
max-width: none;
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;
padding: 8px;
list-style: none;