diff --git a/CHANGELOG.md b/CHANGELOG.md index c3e07a4f9..aae0813e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/README.md b/README.md index e446b747a..5e94a8bf5 100644 --- a/README.md +++ b/README.md @@ -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. \ No newline at end of file +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. diff --git a/ui/js/actions/app.js b/ui/js/actions/app.js index 44964b0ba..e70e9767f 100644 --- a/ui/js/actions/app.js +++ b/ui/js/actions/app.js @@ -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()); diff --git a/ui/js/app.js b/ui/js/app.js index c5bfdcfbd..2504b72e8 100644 --- a/ui/js/app.js +++ b/ui/js/app.js @@ -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", diff --git a/ui/js/component/app/view.jsx b/ui/js/component/app/view.jsx index e8ebbcd09..32cb74247 100644 --- a/ui/js/component/app/view.jsx +++ b/ui/js/component/app/view.jsx @@ -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 (
- {__( - "Using LBRY is like dating a centaur. Totally normal up top, and" - )} - {" "}{__("way different")} {__("underneath.")} -
-{__("Up top, LBRY is similar to popular media sites.")}
-- {__( - "Below, LBRY is controlled by users -- you -- via blockchain and decentralization." - )} -
-- The LBRY network is controlled and powered by credits called{" "} - LBC, a blockchain asset. -
-
- {__("New patrons receive ")} {" "}
- {totalRewardValue
- ?
- {__( - "You'll also earn weekly bonuses for checking out the greatest new stuff." - )} -
-{__("If reloading does not fix this, or you see this at every start up, please email help@lbry.io.")}
++ {__( + "If reloading does not fix this, or you see this at every start up, please email help@lbry.io." + )} +
); } diff --git a/ui/js/component/modalWelcome/index.js b/ui/js/modal/modalCreditIntro/index.js similarity index 81% rename from ui/js/component/modalWelcome/index.js rename to ui/js/modal/modalCreditIntro/index.js index 3cb4a44d6..0626eee8f 100644 --- a/ui/js/component/modalWelcome/index.js +++ b/ui/js/modal/modalCreditIntro/index.js @@ -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); diff --git a/ui/js/modal/modalCreditIntro/view.jsx b/ui/js/modal/modalCreditIntro/view.jsx new file mode 100644 index 000000000..8a2b7b500 --- /dev/null +++ b/ui/js/modal/modalCreditIntro/view.jsx @@ -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 ( ++ The LBRY network is controlled and powered by credits called{" "} + LBC, a blockchain asset. +
+
+ {__("New patrons receive ")} {" "}
+ {totalRewardValue
+ ?
+ {__( + "You'll also earn weekly bonuses for checking out the greatest new stuff." + )} +
++ {__( + "Using LBRY is like dating a centaur. Totally normal up top, and" + )} + {" "}{__("way different")} {__("underneath.")} +
+{__("Up top, LBRY is similar to popular media sites.")}
++ {__( + "Below, LBRY is controlled by users -- you -- via blockchain and decentralization." + )} +
+