Merge pull request #2 from lbryio/help-page

Help page and video loading
This commit is contained in:
Jack Robison 2016-05-06 03:15:13 -04:00
commit 5870f42ab3
13 changed files with 287 additions and 15 deletions

BIN
dist.zip

Binary file not shown.

4
dist/index.html vendored
View file

@ -26,6 +26,10 @@
<script src="./js/component/splash.js"></script>
<script src="./js/page/home.js"></script>
<script src="./js/page/settings.js"></script>
<script src="./js/page/help.js"></script>
<script src="./js/page/watch.js"></script>
<script src="./js/page/report.js"></script>
<script src="./js/page/start.js"></script>
<script src="./js/app.js"></script>
<script src="./js/main.js"></script>
</body>

BIN
js/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -5,16 +5,42 @@ var appStyles = {
};
var App = React.createClass({
getInitialState: function() {
return {
viewingPage: window.location.search === '?settings' ? 'settings' : 'home'
// For now, routes are in format ?page or ?page=args
var match, param, val;
[match, param, val] = window.location.search.match(/\??([^=]*)(?:=(.*))?/);
if (['settings', 'help', 'start', 'watch', 'report'].indexOf(param) != -1) {
var viewingPage = param;
} else {
var viewingPage = 'home';
}
return {
viewingPage: viewingPage,
pageArgs: val,
};
},
componentWillMount: function() {
lbry.checkNewVersionAvailable(function(isAvailable) {
if (isAvailable) {
alert("The version of LBRY you're using is not up to date.\n\n" +
"You'll now be taken to lbry.io, where you can download the latest version.");
window.location = "http://www.lbry.io/" + (navigator.userAgent.indexOf('Mac OS X') != -1 ? 'osx' : 'linux');
var message = "The version of LBRY you're using is not up to date.\n\n" +
"You'll now be taken to lbry.io, where you can download the latest version.";
lbry.getVersionInfo(function(versionInfo) {
var maj, min, patch;
[maj, min, patch] = versionInfo.lbrynet_version.split('.');
if (versionInfo.os_system == 'Darwin' && maj == 0 && min <= 2 && patch <= 2) {
// On OS X with version <= 0.2.2, we need to notify user to close manually close LBRY
message += "\n\nBefore installing the new version, make sure to exit LBRY, if you started the app " +
"click that LBRY icon in your status bar and choose \"Quit.\"";
} else {
lbry.stop();
}
alert(message);
window.location = "http://www.lbry.io/" + (versionInfo.os_system == 'Darwin' ? 'osx' : 'linux');
});
}
});
},
@ -30,6 +56,14 @@ var App = React.createClass({
var content = <HomePage />;
} else if (this.state.viewingPage == 'settings') {
var content = <SettingsPage />;
} else if (this.state.viewingPage == 'help') {
var content = <HelpPage />;
} else if (this.state.viewingPage == 'watch') {
var content = <WatchPage name={this.state.pageArgs}/>;
} else if (this.state.viewingPage == 'report') {
var content = <ReportPage />;
} else if (this.state.viewingPage == 'start') {
var content = <StartPage />;
}
return (
<div style={appStyles}>

View file

@ -15,7 +15,8 @@ var Link = React.createClass({
console.log(this.props);
var href = this.props.href ? this.props.href : 'javascript:;',
icon = this.props.icon ? <Icon icon={this.props.icon} /> : '',
className = (this.props.button ? 'button-block button-' + this.props.button : 'button-text');
className = (this.props.button ? 'button-block button-' + this.props.button : 'button-text') +
(this.props.hidden ? ' hidden' : '') + (this.props.disabled ? ' disabled' : '');
return (
<a className={className} href={href} style={this.props.style ? this.props.style : {}} onClick={this.props.onClick}>
{this.props.icon ? icon : '' }

View file

@ -95,6 +95,18 @@ lbry.search = function(query, callback)
lbry.call("search_nametrie", { "search": query }, callback);
}
lbry.getStream = function(name, callback) {
lbry.call('get', { 'name': name }, callback);
};
lbry.getFileStatus = function(name, callback) {
lbry.call('get_lbry_file', { 'name': name }, callback);
}
lbry.getVersionInfo = function(callback) {
lbry.call('version', {}, callback);
};
lbry.checkNewVersionAvailable = function(callback) {
lbry.call('version', {}, function() {
// If the "version" method is available, we have a daemon new enough to do version checking
@ -107,6 +119,15 @@ lbry.checkNewVersionAvailable = function(callback) {
});
}
lbry.reportBug = function(message, callback) {
lbry.call('upload_log', {
name_prefix: 'report',
exclude_previous: false,
force: true,
message: message
}, callback);
}
//utilities
lbry.formatCredits = function(amount, precision)
{
@ -132,3 +153,7 @@ lbry.imagePath = function(file)
{
return lbry.rootPath + '/img/' + file;
}
lbry.stop = function(callback) {
lbry.call('stop', {}, callback);
};

33
js/page/help.js Normal file
View file

@ -0,0 +1,33 @@
//@TODO: Customize advice based on OS
var HelpPage = React.createClass({
render: function() {
return (
<main>
<h1>Troubleshooting</h1>
<p>Here are the most commonly encountered problems and what to try doing about them</p>
<h3>Nothing seems to start downloading</h3>
<p>Not all content that you find in the search window is necessarily hosted; LBRY is still young. However, 'wonderfullife' should assuredly be accessible. If you can't download it, and you're not experiencing the below problem, try forwarding ports 4444 and 3333 on your firewall or router.</p>
<h3>Videos have trouble playing</h3>
<p>This is caused by your video player trying to start the file while it's still empty. Try reloading the page after a few seconds, it should work. You should also see the file appear in the downloads folder configured in your LBRY settings, which is the gear icon at the top of the main menu.</p>
<p>A real fix for this is underway!</p>
<h3>How do I turn LBRY off?</h3>
<p>If you're on OS X you can find the app running in the notification area at the top right of your screen; simply click the LBRY icon and choose "Quit."</p>
<p>On Linux, you'll find a Close button in the menu at the top right of LBRY.</p>
<p>If you're running LBRY from the command line, you may also close the app with the command "stop-lbrynet-daemon."</p>
<h3>None of this applies to me, or it didn't work</h3>
<p>Please <Link href="/?report" label="send us a bug report" />. Thanks!</p>
<section>
<Link href="/" label="<< Return" />
</section>
</main>
);
}
});

View file

@ -87,12 +87,27 @@ var searchRowImgStyle = {
var SearchResultRow = React.createClass({
getInitialState: function() {
return {
downloading: false
}
},
startDownload: function() {
if (!this.state.downloading) {
this.setState({
downloading: true
});
lbry.getStream(this.props.name, (streamInfo) => {
alert('Downloading ' + this.props.title + ' to ' + streamInfo.path);
});
}
},
render: function() {
var displayURI = 'lbry://' + this.props.name;
// No support for lbry:// URLs in Windows or on Chrome yet
if (/windows|win32/i.test(navigator.userAgent) || (window.chrome && window.navigator.vendor == "Google Inc.")) {
var linkURI = window.location.host + "/view?name=" + this.props.name;
var linkURI = "/?watch=" + this.props.name;
} else {
var linkURI = displayURI;
}
@ -100,7 +115,7 @@ var SearchResultRow = React.createClass({
return (
<div className="row-fluid">
<div className="span3">
<img src={this.props.imgUrl} alt="Photo for {this.props.title}" style={searchRowImgStyle} />
<img src={this.props.imgUrl} alt={'Photo for ' + (this.props.title || this.props.name)} style={searchRowImgStyle} />
</div>
<div className="span9">
<span style={searchRowCostStyle}>
@ -111,7 +126,8 @@ var SearchResultRow = React.createClass({
<p style={searchRowDescriptionStyle}>{this.props.description}</p>
<div>
<Link href={linkURI} label="Watch" icon="icon-play" button="primary" />
<Link href={linkURI} label="Download" icon="icon-download" button="alt" />
<Link onClick={this.startDownload} label={this.state.downloading ? "Downloading" : "Download"}
disabled={this.state.downloading} icon="icon-download" button="alt" />
</div>
</div>
</div>
@ -202,7 +218,7 @@ var Header = React.createClass({
render: function() {
return (
<header>
<TopBar onPageChosen={this.handlePageChosen}/>
<TopBar />
<div style={logoStyle}>
<img src="./img/lbry-dark-1600x528.png" style={imgStyle}/>
</div>
@ -216,12 +232,19 @@ var topBarStyle = {
},
balanceStyle = {
'marginRight': '5px'
},
closeIconStyle = {
'color': '#ff5155'
};
var TopBar = React.createClass({
onClose: function() {
window.location.href = "?start";
},
getInitialState: function() {
return {
balance: 0
balance: 0,
showClose: /linux/i.test(navigator.userAgent) // @TODO: find a way to use getVersionInfo() here without messy state management
};
},
componentDidMount: function() {
@ -238,7 +261,11 @@ var TopBar = React.createClass({
<span style={balanceStyle}>
<CreditAmount amount={this.state.balance}/>
</span>
<Link href='/?settings' icon="icon-gear" />
<Link href='/?settings' icon='icon-gear' />
{ ' ' }
<Link href='/?help' icon='icon-question-circle' />
{ ' ' }
<Link href="/?start" onClick={this.onClose} icon="icon-close" style={closeIconStyle} hidden={!this.state.showClose} />
</span>
);
}

39
js/page/report.js Normal file
View file

@ -0,0 +1,39 @@
var ReportPage = React.createClass({
submitMessage: function() {
if (this._messageArea.value) {
this.setState({
submitting: true
});
lbry.reportBug(this._messageArea.value, () => {
this.setState({
submitting: false
});
alert("Your bug report has been submitted! Thank you for your feedback.");
});
this._messageArea.value = '';
}
},
getInitialState: function() {
return {
submitting: false,
}
},
render: function() {
return (
<main>
<h1>Report a bug</h1>
<section>
<p>Please describe the problem you experienced and any information you think might be useful to us. Links to screenshots are great!</p>
<textarea ref={(t) => this._messageArea = t} cols="50" rows="10" name="message" type="text"/>
<div><button onClick={this.submitMessage} className={this.state.submitting ? 'disabled' : ''}>{this.state.submitting ? 'Submitting...' : 'Submit bug report'}</button></div>
</section>
<section>
Developers, feel free to instead <Link href="https://github.com/lbryio/lbry/issues" label="submit an issue on GitHub"/>.
</section>
<section>
<Link href="/?help" label="<< Return to Help"/>
</section>
</main>
);
}
});

View file

@ -29,7 +29,7 @@ var SettingsPage = React.createClass({
this.storeSetting('upload_log', event.target.checked);
},
onDownloadDirChange: function(event) {
this.storeSetting('default_download_directory', event.target.value);
this.storeSetting('download_directory', event.target.value);
},
onMaxUploadPrefChange: function(isLimited) {
if (!isLimited) {
@ -84,7 +84,7 @@ var SettingsPage = React.createClass({
<section>
<h4>Download directory</h4>
<div className="help">Where would you like the files you download from LBRY to be saved?</div>
<input style={downloadDirectoryFieldStyles} type="text" name="default_download_directory" defaultValue={this.state.settings.default_download_directory} onChange={this.onDownloadDirChange}/>
<input style={downloadDirectoryFieldStyles} type="text" name="download_directory" defaultValue={this.state.settings.download_directory} onChange={this.onDownloadDirChange}/>
</section>
<section>
<h4>Max Upload</h4>

13
js/page/start.js Normal file
View file

@ -0,0 +1,13 @@
var StartPage = React.createClass({
componentWillMount: function() {
lbry.stop();
},
render: function() {
return (
<main>
<h1>LBRY has closed</h1>
<Link href="lbry://lbry" label="Click here to start LBRY" />
</main>
);
}
});

76
js/page/watch.js Normal file
View file

@ -0,0 +1,76 @@
var videoStyle = {
width: '100%',
height: '100%',
backgroundColor: '#000'
};
var WatchPage = React.createClass({
propTypes: {
name: React.PropTypes.string,
},
getInitialState: function() {
return {
downloadStarted: false,
readyToPlay: false,
loadStatusMessage: "Requesting stream",
};
},
componentDidMount: function() {
lbry.getStream(this.props.name);
this.updateLoadStatus();
setTimeout(() => { this.reloadIfNeeded() }, 15000);
},
reloadIfNeeded: function() {
// Fallback option for loading problems: every 15 seconds, if the video hasn't reported being
// playable yet, ask it to reload.
if (!this.state.readyToPlay) {
console.log("Trying again");
this._video.load()
}
},
onCanPlay: function() {
this.setState({
readyToPlay: true
});
},
updateLoadStatus: function() {
lbry.getFileStatus(this.props.name, (status) => {
if (!status || status.code != 'running' || status.written_bytes == 0) {
// Download hasn't started yet, so update status message (if available) then try again
if (status) {
this.setState({
loadStatusMessage: status.message
});
}
setTimeout(() => { this.updateLoadStatus() }, 250);
} else {
this.setState({
loadStatusMessage: "Buffering",
downloadStarted: true,
});
setTimeout(() => { this.reloadIfNeeded() }, 15000);
}
});
},
render: function() {
if (!this.state.downloadStarted) {
var video = null;
} else {
// If the download has started, render the <video> behind the scenes so it can start loading.
// When the video is actually ready to play, the loading text is hidden and the video shown.
var video = <video src={"/view?name=" + this.props.name} style={videoStyle}
className={this.state.readyToPlay ? '' : 'hidden'} controls
onCanPlay={this.onCanPlay} ref={(video) => {this._video = video}}/>;
}
return (
<main>
<div className={this.state.readyToPlay ? 'hidden' : ''}>
<h3>Loading lbry://{this.props.name}</h3>
{this.state.loadStatusMessage}...
</div>
{video}
</main>
);
}
});

View file

@ -40,10 +40,21 @@ header
line-height: $spacing-vertical;
}
p
{
margin-bottom: 0.8em;
}
.hidden {
display: none;
}
.disabled {
pointer-events: none;
opacity: 0.7;
}
input[type="search"]
{
border: 0 none;
@ -86,6 +97,10 @@ input[type="search"]
{
margin-left: 20px;
}
.icon
{
top: 0em;
}
.icon:first-child
{
padding-right: 5px;
@ -120,6 +135,11 @@ input[type="search"]
}
}
.icon {
position: relative;
top: 0.16em;
}
.fade-in-link {
&:hover {