Merge pull request #2 from lbryio/help-page
Help page and video loading
This commit is contained in:
commit
5870f42ab3
13 changed files with 287 additions and 15 deletions
BIN
dist.zip
BIN
dist.zip
Binary file not shown.
4
dist/index.html
vendored
4
dist/index.html
vendored
|
@ -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
BIN
js/.DS_Store
vendored
Normal file
Binary file not shown.
44
js/app.js
44
js/app.js
|
@ -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}>
|
||||
|
|
|
@ -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 : '' }
|
||||
|
|
25
js/lbry.js
25
js/lbry.js
|
@ -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
33
js/page/help.js
Normal 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>
|
||||
);
|
||||
}
|
||||
});
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -253,4 +280,4 @@ var HomePage = React.createClass({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
39
js/page/report.js
Normal file
39
js/page/report.js
Normal 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>
|
||||
);
|
||||
}
|
||||
});
|
|
@ -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
13
js/page/start.js
Normal 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
76
js/page/watch.js
Normal 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>
|
||||
);
|
||||
}
|
||||
});
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue