fixed merge conflicts with latest master

This commit is contained in:
Akinwale Ariwodola 2017-08-19 09:01:31 +01:00
commit 970539ffae
106 changed files with 614 additions and 22894 deletions

View file

@ -17,6 +17,10 @@ values =
production
[bumpversion:file:app/package.json]
search = "version": "{current_version}"
replace = "version": "{new_version}"
[bumpversion:file:ui/package.json]
search = "version": "{current_version}"
replace = "version": "{new_version}"

View file

@ -31,7 +31,7 @@ Tell us what happens instead
You can include a screenshot instead of typing it out -->
<!-- For the daemon, run:
curl 'http://localhost:5279/lbryapi' --data '{"method":"version"}'
curl 'http://localhost:5279' --data '{"method":"version"}'
and include the full output -->
- LBRY Daemon version:

View file

@ -8,20 +8,28 @@ Web UI version numbers should always match the corresponding version of LBRY App
## [Unreleased]
### Added
* Added a new component, `FormFieldPrice` which is now used in Publish and Settings
*
* 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
* Some form field refactoring as we progress towards form sanity.
* 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.
* 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.
*
* 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)
* Support claims no longer show up on Published page (#384)
### Deprecated
*

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

@ -32,7 +32,7 @@ const DAEMON_PATH = process.env.LBRY_DAEMON || path.join(__dirname, 'dist', 'lbr
let client = jayson.client.http({
host: 'localhost',
port: 5279,
path: '/lbryapi',
path: '/',
timeout: 1000
});

View file

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

View file

@ -1 +0,0 @@
https://github.com/lbryio/lbry/releases/download/v0.14.2/lbrynet-daemon-v0.14.2-OSNAME.zip

View file

@ -29,7 +29,10 @@ cd ..
# get daemon and cli executable
$daemon_url = (Get-Content build\DAEMON_URL -Raw).replace("OSNAME", "windows")
$package_settings = (Get-Content app\package.json -Raw | ConvertFrom-Json).lbrySettings
$daemon_ver = $package_settings.lbrynetDaemonVersion
$daemon_url_template = $package_settings.lbrynetDaemonUrlTemplate
$daemon_url = $daemon_url_template.Replace('OSNAME', 'windows').Replace('DAEMONVER', $daemon_ver)
Invoke-WebRequest -Uri $daemon_url -OutFile daemon.zip
Expand-Archive daemon.zip -DestinationPath app\dist\
dir app\dist\ # verify that daemon binary is there

View file

@ -80,7 +80,8 @@ else
OSNAME="linux"
fi
DAEMON_VER=$(node -e "console.log(require(\"$ROOT/app/package.json\").lbrySettings.lbrynetDaemonVersion)")
DAEMON_URL="https://github.com/lbryio/lbry/releases/download/v${DAEMON_VER}/lbrynet-daemon-v${DAEMON_VER}-${OSNAME}.zip"
DAEMON_URL_TEMPLATE=$(node -e "console.log(require(\"$ROOT/app/package.json\").lbrySettings.lbrynetDaemonUrlTemplate)")
DAEMON_URL=$(echo ${DAEMON_URL_TEMPLATE//DAEMONVER/$DAEMON_VER} | sed "s/OSNAME/$OSNAME/g")
wget --quiet "$DAEMON_URL" -O "$BUILD_DIR/daemon.zip"
unzip "$BUILD_DIR/daemon.zip" -d "$ROOT/app/dist/"
rm "$BUILD_DIR/daemon.zip"

View file

@ -5,6 +5,7 @@ This script should be run locally, not on a build server.
import argparse
import contextlib
import os
import json
import re
import requests
import subprocess
@ -16,7 +17,7 @@ import github
import changelog
ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
DAEMON_URL_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'DAEMON_URL')
APP_PACKAGE_JSON_FILE = os.path.join(ROOT, 'app', 'package.json')
def main():
@ -38,11 +39,11 @@ def main():
print 'Current version: {}'.format(repo.current_version)
print 'New version: {}'.format(repo.new_version)
with open(DAEMON_URL_FILE, 'r') as f:
daemon_url_template = f.read().strip()
daemon_version = re.search('/(?P<version>v[^/]+)', daemon_url_template)
print 'Daemon version: {} ({})'.format(
daemon_version.group('version'), daemon_url_template)
with open(APP_PACKAGE_JSON_FILE, 'r') as f:
package_settings = json.load(f)['lbrySettings']
daemon_url_template = package_settings['lbrynetDaemonUrlTemplate']
daemon_version = package_settings['lbrynetDaemonVersion']
print 'Daemon version: {} ({})'.format(daemon_version, daemon_url_template.replace('DAEMONVER', daemon_version))
if not args.confirm and not confirm():
print "Aborting"
@ -190,18 +191,25 @@ def run_sanity_checks(repo, branch):
def check_daemon_urls():
success = True
with open(DAEMON_URL_FILE, 'r') as f:
daemon_url_template = f.read().strip()
if "OSNAME" not in daemon_url_template:
print "Daemon URL must include the string 'OSNAME'"
return False
for osname in ('linux', 'macos', 'windows'):
if not check_url(daemon_url_template.replace('OSNAME', osname)):
success = False
print "Daemon URL for " + osname + " does not work"
return success
with open(APP_PACKAGE_JSON_FILE, 'r') as f:
package_settings = json.load(f)['lbrySettings']
daemon_url_template = package_settings['lbrynetDaemonUrlTemplate']
daemon_version = package_settings['lbrynetDaemonVersion']
if "OSNAME" not in daemon_url_template:
print "Daemon URL must include the string \"OSNAME\""
return False
elif "DAEMONVER" not in daemon_url_template:
print "Daemon URL must include the string \"DAEMONVER\""
return False
for osname in ('linux', 'macos', 'windows'):
if not check_url(daemon_url_template.replace('DAEMONVER', daemon_version).replace('OSNAME', osname)):
print "Daemon URL for", osname, " does not work"
return False
return True
def check_url(url):
url = url.strip()

View file

@ -60,5 +60,6 @@
"electron": "^1.7.5",
"electron-builder": "^11.7.0",
"electron-debug": "^1.4.0"
}
},
"license": "MIT"
}

3
ui/dist/index.html vendored
View file

@ -4,7 +4,6 @@
<meta name="viewport" content="width=device-width">
<title>LBRY</title>
<link href='https://fonts.googleapis.com/css?family=Raleway:600,300' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400italic,600italic,600' rel='stylesheet' type='text/css'>
<link href="./css/all.css" rel="stylesheet" type="text/css" media="screen,print" />
<link rel="icon" type="image/png" href="./img/fav/favicon-32x32.png" sizes="32x32">
@ -19,8 +18,6 @@
</head>
<body>
<div id="canvas"></div>
<script src="./js/mediaelement/jquery.js"></script>
<script src="./js/mediaelement/mediaelement-and-player.js"></script>
<script src="./js/bundle.js"></script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -1,14 +0,0 @@
<?xml version="1.0" standalone="no"?>
<svg id="bigplay" viewBox="0 0 100 200" style="background-color:#ffffff00" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
x="0px" y="0px" width="100px" height="200px"
>
<g id="dark">
<path id="Polygon" d="M 72.5 49.5 L 38.75 68.9856 L 38.75 30.0144 L 72.5 49.5 Z" fill="#ffffff" opacity="0.75" />
<path id="Ellipse" d="M 13 50.5 C 13 29.7891 29.7891 13 50.5 13 C 71.2109 13 88 29.7891 88 50.5 C 88 71.2109 71.2109 88 50.5 88 C 29.7891 88 13 71.2109 13 50.5 Z" stroke="#ffffff" stroke-width="5" fill="none" opacity="0.75"/>
</g>
<g id="light">
<path id="Polygon2" d="M 72.5 149.5 L 38.75 168.9856 L 38.75 130.0144 L 72.5 149.5 Z" fill="#ffffff" opacity="1.0" />
<path id="Ellipse2" d="M 13 150.5 C 13 129.7891 29.7891 113 50.5 113 C 71.2109 113 88 129.7891 88 150.5 C 88 171.211 71.2109 188 50.5 188 C 29.7891 188 13 171.211 13 150.5 Z" stroke="#ffffff" stroke-width="5" fill="none" opacity="1.0"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,289 +0,0 @@
/* TED player */
.mejs-container.mejs-ted {
}
.mejs-ted .mejs-controls {
background: #eee;
height: 65px;
}
.mejs-ted .mejs-button,
.mejs-ted .mejs-time {
position: absolute;
background: #ddd;
}
.mejs-ted .mejs-controls .mejs-time-rail .mejs-time-total {
background-color: none;
background: url(controls-ted.png) repeat-x 0 -52px;
height: 6px;
}
.mejs-ted .mejs-controls .mejs-time-rail .mejs-time-buffering {
height: 6px;
}
.mejs-ted .mejs-controls .mejs-time-rail .mejs-time-loaded {
background-color: none;
background: url(controls-ted.png) repeat-x 0 -52px;
width: 0;
height: 6px;
}
.mejs-ted .mejs-controls .mejs-time-rail .mejs-time-current {
width: 0;
height: 6px;
background-color: none;
background: url(controls-ted.png) repeat-x 0 -59px;
}
.mejs-ted .mejs-controls .mejs-time-rail .mejs-time-handle {
display: block;
margin: 0;
width: 14px;
height: 21px;
top: -7px;
border: 0;
background: url(controls-ted.png) no-repeat 0 0;
}
.mejs-ted .mejs-controls .mejs-time-rail .mejs-time-float {
display: none;
}
.mejs-ted .mejs-controls .mejs-playpause-button {
top: 29px;
left: 9px;
width: 49px;
height: 28px;
}
.mejs-ted .mejs-controls .mejs-playpause-button button {
width: 49px;
height: 28px;
background: url(controls-ted.png) no-repeat -50px -23px;
margin: 0;
padding: 0;
}
.mejs-ted .mejs-controls .mejs-pause button {
background-position: 0 -23px;
}
.mejs-ted .mejs-controls .mejs-fullscreen-button {
top: 34px;
right: 9px;
width: 17px;
height: 15px;
background : none;
}
.mejs-ted .mejs-controls .mejs-fullscreen-button button {
width: 19px;
height: 17px;
background: transparent url(controls-ted.png) no-repeat 0 -66px;
margin: 0;
padding: 0;
}
.mejs-ted .mejs-controls .mejs-unfullscreen button {
background: transparent url(controls-ted.png) no-repeat -21px -66px;
margin: 0;
padding: 0;
}
.mejs-ted .mejs-controls .mejs-volume-button {
top: 30px;
right: 35px;
width: 24px;
height: 22px;
}
.mejs-ted .mejs-controls .mejs-mute button {
background: url(controls-ted.png) no-repeat -15px 0;
width: 24px;
height: 22px;
margin: 0;
padding: 0;
}
.mejs-ted .mejs-controls .mejs-unmute button {
background: url(controls-ted.png) no-repeat -40px 0;
width: 24px;
height: 22px;
margin: 0;
padding: 0;
}
.mejs-ted .mejs-controls .mejs-volume-button .mejs-volume-slider {
background: #fff;
border: solid 1px #aaa;
border-width: 1px 1px 0 1px;
width: 22px;
height: 65px;
top: -65px;
}
.mejs-ted .mejs-controls .mejs-volume-button .mejs-volume-total {
background: url(controls-ted.png) repeat-y -41px -66px;
left: 8px;
width: 6px;
height: 50px;
}
.mejs-ted .mejs-controls .mejs-volume-button .mejs-volume-current {
left: 8px;
width: 6px;
background: url(controls-ted.png) repeat-y -48px -66px;
height: 50px;
}
.mejs-ted .mejs-controls .mejs-volume-button .mejs-volume-handle {
display: none;
}
.mejs-ted .mejs-controls .mejs-time span {
color: #333;
}
.mejs-ted .mejs-controls .mejs-currenttime-container {
position: absolute;
top: 32px;
right: 100px;
border: solid 1px #999;
background: #fff;
color: #333;
padding-top: 2px;
border-radius: 3px;
color: #333;
}
.mejs-ted .mejs-controls .mejs-duration-container {
position: absolute;
top: 32px;
right: 65px;
border: solid 1px #999;
background: #fff;
color: #333;
padding-top: 2px;
border-radius: 3px;
color: #333;
}
.mejs-ted .mejs-controls .mejs-time button{
color: #333;
}
.mejs-ted .mejs-controls .mejs-captions-button {
display: none;
}
/* END: TED player */
/* WMP player */
.mejs-container.mejs-wmp {
}
.mejs-wmp .mejs-controls {
background: transparent url(controls-wmp-bg.png) center 16px no-repeat;
height: 65px;
}
.mejs-wmp .mejs-button,
.mejs-wmp .mejs-time {
position: absolute;
background: transparent;
}
.mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-total {
background-color: transparent;
border: solid 1px #ccc;
height: 3px;
}
.mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-buffering {
height: 3px;
}
.mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-loaded {
background-color: rgba(255,255,255,0.3);
width: 0;
height: 3px;
}
.mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-current {
width: 0;
height: 1px;
background-color: #014CB6;
border: solid 1px #7FC9FA;
border-width: 1px 0;
border-color: #7FC9FA #fff #619FF2 #fff;
}
.mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-handle {
display: block;
margin: 0;
width: 16px;
height: 9px;
top: -3px;
border: 0;
background: url(controls-wmp.png) no-repeat 0 -80px;
}
.mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-float {
display: none;
}
.mejs-wmp .mejs-controls .mejs-playpause-button {
top: 10px;
left: 50%;
margin: 10px 0 0 -20px;
width: 40px;
height: 40px;
}
.mejs-wmp .mejs-controls .mejs-playpause-button button {
width: 40px;
height: 40px;
background: url(controls-wmp.png) no-repeat 0 0;
margin: 0;
padding: 0;
}
.mejs-wmp .mejs-controls .mejs-pause button {
background-position: 0 -40px;
}
.mejs-wmp .mejs-controls .mejs-currenttime-container {
position: absolute;
top: 25px;
left: 50%;
margin-left: -93px;
}
.mejs-wmp .mejs-controls .mejs-duration-container {
position: absolute;
top: 25px;
left: 50%;
margin-left: -58px;
}
.mejs-wmp .mejs-controls .mejs-volume-button {
top: 32px;
right: 50%;
margin-right: -55px;
width: 20px;
height: 15px;
}
.mejs-wmp .mejs-controls .mejs-volume-button button {
margin: 0;
padding: 0;
background: url(controls-wmp.png) no-repeat -42px -17px;
width: 20px;
height: 15px;
}
.mejs-wmp .mejs-controls .mejs-unmute button {
margin: 0;
padding: 0;
background: url(controls-wmp.png) no-repeat -42px 0;
width: 20px;
height: 15px;
}
.mejs-wmp .mejs-controls .mejs-volume-button .mejs-volume-slider {
background: rgba(102,102,102,0.6);
}
.mejs-wmp .mejs-controls .mejs-fullscreen-button {
top: 32px;
right: 50%;
margin-right: -82px;
width: 15px;
height: 14px;
}
.mejs-wmp .mejs-controls .mejs-fullscreen-button button {
margin: 0;
padding: 0;
background: url(controls-wmp.png) no-repeat -63px 0;
width: 15px;
height: 14px;
}
.mejs-wmp .mejs-controls .mejs-captions-button {
display: none;
}
/* END: WMP player */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

3
ui/dist/quit.html vendored
View file

@ -3,8 +3,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>LBRY</title>
<link href='https://fonts.googleapis.com/css?family=Raleway:600,300' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400italic,600italic,600' rel='stylesheet' type='text/css'>
<link href="./css/all.css" rel="stylesheet" type="text/css" media="screen,print" />
<link href="./js/mediaelement/mediaelementplayer.css" rel="stylesheet" type="text/css" />

View file

@ -3,11 +3,9 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>LBRY</title>
<link href='https://fonts.googleapis.com/css?family=Raleway:600,300' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400italic,600italic,600' rel='stylesheet' type='text/css'>
<link href="./css/all.css" rel="stylesheet" type="text/css" media="screen,print" />
<link href="./js/mediaelement/mediaelementplayer.css" rel="stylesheet" type="text/css" />
<link rel="icon" type="image/png" href="./img/fav/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="./img/fav/favicon-194x194.png" sizes="194x194">
<link rel="icon" type="image/png" href="./img/fav/favicon-96x96.png" sizes="96x96">

View file

@ -3,11 +3,9 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>LBRY</title>
<link href='https://fonts.googleapis.com/css?family=Raleway:600,300' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400italic,600italic,600' rel='stylesheet' type='text/css'>
<link href="./css/all.css" rel="stylesheet" type="text/css" media="screen,print" />
<link href="./js/mediaelement/mediaelementplayer.css" rel="stylesheet" type="text/css" />
<link rel="icon" type="image/png" href="./img/fav/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="./img/fav/favicon-194x194.png" sizes="194x194">
<link rel="icon" type="image/png" href="./img/fav/favicon-96x96.png" sizes="96x96">

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

@ -104,7 +104,7 @@ export function doSendDraftTransaction() {
};
lbry
.send_amount_to_address({
.wallet_send({
amount: draftTx.amount,
address: draftTx.address,
})

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

@ -72,25 +72,28 @@ export class CreditAmount extends React.PureComponent {
};
static defaultProps = {
precision: 1,
precision: 2,
label: true,
showFree: false,
look: "indicator",
};
render() {
const formattedAmount = formatCredits(
this.props.amount,
this.props.precision
);
const minimumRenderableAmount = Math.pow(10, -1 * this.props.precision);
const { amount, precision } = this.props;
let formattedAmount = amount > 0 && amount < minimumRenderableAmount
? "<" + minimumRenderableAmount
: formatCredits(amount, precision);
let amountText;
if (this.props.showFree && parseFloat(formattedAmount) == 0) {
if (this.props.showFree && parseFloat(this.props.amount) === 0) {
amountText = __("free");
} else if (this.props.label) {
amountText =
formattedAmount +
" " +
(parseFloat(formattedAmount) == 1 ? __("credit") : __("credits"));
(parseFloat(amount) == 1 ? __("credit") : __("credits"));
} else {
amountText = formattedAmount;
}

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,18 +3,35 @@ 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}
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
onClick={() => navigate("/discover")}

View file

@ -17,11 +17,9 @@ const Link = props => {
const className =
(props.className || "") +
(!props.className && !props.button ? "button-text" : "") + // Non-button links get the same look as text buttons
(props.button
? " button-block button-" + props.button + " button-set-item"
: "") +
(props.disabled ? " disabled" : "");
(!props.className && !button ? "button-text" : "") + // Non-button links get the same look as text buttons
(button ? " button-block button-" + button + " button-set-item" : "") +
(disabled ? " disabled" : "");
let content;
if (children) {

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

@ -55,7 +55,7 @@ class ChannelSection extends React.PureComponent {
handleCreateChannelClick(event) {
if (this.state.newChannelName.length < 5) {
this.refs.newChannelName.showError(
__("LBRY channel names must be at least 4 characters in length.")
__("LBRY channel names must be at least 5 characters in length.")
);
return;
}

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";
@ -377,46 +377,6 @@ class PublishForm extends React.PureComponent {
});
}
handleCreateChannelClick(event) {
if (this.state.newChannelName.length < 5) {
this.refs.newChannelName.showError(
__("LBRY channel names must be at least 4 characters in length.")
);
return;
}
this.setState({
creatingChannel: true,
});
const newChannelName = this.state.newChannelName;
lbry
.channel_new({
channel_name: newChannelName,
amount: parseFloat(this.state.newChannelBid),
})
.then(
() => {
setTimeout(() => {
this.setState({
creatingChannel: false,
});
this._updateChannelList(newChannelName);
}, 10000);
},
error => {
// TODO: better error handling
this.refs.newChannelName.showError(
__("Unable to create channel due to an internal error.")
);
this.setState({
creatingChannel: false,
});
}
);
}
getLicense() {
switch (this.state.licenseType) {
case "copyright":
@ -564,6 +524,7 @@ class PublishForm extends React.PureComponent {
: <div>
<div className="card__content">
<FormRow
ref="meta_title"
label={__("Title")}
type="text"
name="title"
@ -825,6 +786,7 @@ class PublishForm extends React.PureComponent {
ref="bid"
type="number"
step="0.01"
min="0"
label={__("Deposit")}
postfix="LBC"
onChange={event => {
@ -833,6 +795,7 @@ class PublishForm extends React.PureComponent {
value={this.state.bid}
placeholder={this.claim() ? this.topClaimValue() + 10 : 100}
helper={lbcInputHelp}
min="0"
/>
</div>
: ""}
@ -844,6 +807,7 @@ class PublishForm extends React.PureComponent {
</div>
<div className="card__content">
<FormRow
ref="tosAgree"
label={
<span>
{__("I agree to the")}

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

@ -14,6 +14,7 @@ import FileListPublished from "page/fileListPublished";
import ChannelPage from "page/channel";
import SearchPage from "page/search";
import AuthPage from "page/auth";
import BackupPage from "page/backup";
const route = (page, routesMap) => {
const component = routesMap[page];
@ -26,6 +27,7 @@ const Router = props => {
return route(currentPage, {
auth: <AuthPage params={params} />,
backup: <BackupPage params={params} />,
channel: <ChannelPage params={params} />,
developer: <DeveloperPage params={params} />,
discover: <DiscoverPage params={params} />,

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

@ -34,7 +34,7 @@ class UserEmailNew extends React.PureComponent {
<FormRow
type="text"
label="Email"
placeholder="scrwvwls@lbry.io"
placeholder="youremail@example.org"
name="email"
value={this.state.email}
errorMessage={errorMessage}

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 => {
@ -25,6 +25,7 @@ const WalletSend = props => {
label={__("Amount")}
postfix={__("LBC")}
step="0.01"
min="0"
type="number"
placeholder="1.23"
size="10"

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

@ -7,3 +7,4 @@ export const UPGRADE = "upgrade";
export const WELCOME = "welcome";
export const FIRST_REWARD = "first_reward";
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

@ -9,7 +9,7 @@ const menu = remote.require("./menu/main-menu");
let lbry = {
isConnected: false,
daemonConnectionString: "http://localhost:5279/lbryapi",
daemonConnectionString: "http://localhost:5279",
pendingPublishTimeout: 20 * 60 * 1000,
defaultClientSettings: {
showNsfw: false,

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() {

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

@ -0,0 +1,10 @@
import React from "react";
import { connect } from "react-redux";
import { selectDaemonSettings } from "selectors/settings";
import BackupPage from "./view";
const select = state => ({
daemonSettings: selectDaemonSettings(state),
});
export default connect(select, null)(BackupPage);

View file

@ -0,0 +1,55 @@
import React from "react";
import SubHeader from "component/subHeader";
import Link from "component/link";
class BackupPage extends React.PureComponent {
render() {
const { daemonSettings } = this.props;
if (!daemonSettings || Object.keys(daemonSettings).length === 0) {
return (
<main className="main--single-column">
<SubHeader />
<span className="empty">{__("Failed to load settings.")}</span>
</main>
);
}
return (
<main className="main--single-column">
<SubHeader />
<section className="card">
<div className="card__title-primary">
<h3>{__("Backup Wallet")}</h3>
</div>
<div className="card__content">
<p>
{__(
"Currently, there is no automatic wallet backup, but it is fairly easy to back up manually."
)}
</p>
<p>
{__(
"To backup your wallet, make a copy of the folder listed below:"
)}
</p>
<p>
<code>
{__(`${daemonSettings.lbryum_wallet_dir}`)}
</code>
</p>
<p>
<strong>
{__(
"Access to these files are equivalent to having access to your credits. Keep any copies you make of your wallet in a secure place."
)}
</strong>
</p>
</div>
</section>
</main>
);
}
}
export default BackupPage;

View file

@ -83,6 +83,7 @@ class ChannelPage extends React.PureComponent {
pageClassName="pagination__item"
previousClassName="pagination__item pagination__item--previous"
nextClassName="pagination__item pagination__item--next"
breakClassName="pagination__item pagination__item--break"
marginPagesDisplayed={2}
onPageChange={e => this.changePage(e.selected + 1)}
initialPage={parseInt(page - 1)}

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,
};
}
@ -99,7 +100,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(e) {

View file

@ -1,5 +1,6 @@
import React from "react";
import { connect } from "react-redux";
import { doNavigate } from "actions/app";
import { selectCurrentPage } from "selectors/app";
import { selectBalance } from "selectors/wallet";
import WalletPage from "./view";
@ -9,4 +10,8 @@ const select = state => ({
balance: selectBalance(state),
});
export default connect(select, null)(WalletPage);
const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
});
export default connect(select, perform)(WalletPage);

View file

@ -3,11 +3,11 @@ import SubHeader from "component/subHeader";
import TransactionList from "component/transactionList";
import WalletAddress from "component/walletAddress";
import WalletSend from "component/walletSend";
import Link from "component/link";
import { CreditAmount } from "component/common";
const WalletPage = props => {
const { balance, currentPage } = props;
const { balance, currentPage, navigate } = props;
return (
<main className="main--single-column">
@ -19,6 +19,14 @@ const WalletPage = props => {
<div className="card__content">
<CreditAmount amount={balance} precision={8} />
</div>
<div className="card__content">
<div className="help">
<Link
onClick={() => navigate("/backup")}
label={__("Backup Your Wallet")}
/>
</div>
</div>
</section>
{currentPage === "wallet" ? <TransactionList {...props} /> : ""}
{currentPage === "send" ? <WalletSend {...props} /> : ""}

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

@ -50,7 +50,7 @@ reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) {
.filter(claimId => Object.keys(abandoningById).indexOf(claimId) === -1)
);
claims.forEach(claim => {
claims.filter(claim => claim.category.match(/claim/)).forEach(claim => {
byId[claim.claim_id] = claim;
const pending = Object.values(pendingById).find(pendingClaim => {

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";
@ -41,6 +42,8 @@ export const selectPageTitle = createSelector(
return __("Send");
case "receive":
return __("Receive");
case "backup":
return __("Backup");
case "rewards":
return __("Rewards");
case "start":
@ -130,11 +133,13 @@ export const selectDownloadComplete = createSelector(
);
export const selectHeaderLinks = createSelector(selectCurrentPage, page => {
// This contains intentional fall throughs
switch (page) {
case "wallet":
case "send":
case "receive":
case "rewards":
case "backup":
return {
wallet: __("Overview"),
send: __("Send"),
@ -198,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(
@ -217,3 +227,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

@ -57,6 +57,7 @@ export const selectWunderBarIcon = createSelector(selectCurrentPage, page => {
case "wallet":
case "send":
case "receive":
case "backup":
return "icon-bank";
case "show":
return "icon-file";

View file

@ -23,7 +23,7 @@
"homepage": "https://github.com/lbryio/lbry-app",
"dependencies": {
"from2": "^2.3.0",
"jshashes": "^1.0.6",
"jshashes": "^1.0.7",
"localforage": "^1.5.0",
"node-sass": "^4.5.3",
"rc-progress": "^2.0.6",
@ -49,7 +49,7 @@
"babel": "^6.5.2",
"babel-cli": "^6.24.1",
"babel-core": "^6.18.2",
"babel-loader": "^6.4.1",
"babel-loader": "^7.1.1",
"babel-plugin-react-require": "^3.0.0",
"babel-polyfill": "^6.20.0",
"babel-preset-es2015": "^6.24.1",

Some files were not shown because too many files have changed in this diff Show more