diff --git a/.bumpversion.cfg b/.bumpversion.cfg index b24d9073c..a5f60a198 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,23 +1,5 @@ [bumpversion] -current_version = 0.9.0rc6 +current_version = 0.1.1 commit = True tag = True -parse = (?P\d+)\.(?P\d+)\.(?P\d+)((?P[a-z]+)(?P\d+))? -serialize = - {major}.{minor}.{patch}{release}{candidate} - {major}.{minor}.{patch} - -[bumpversion:file:package.json] - -[bumpversion:part:release] -optional_value = production -values = - rc - production - -[bumpversion:file:CHANGELOG.md] -search = [Unreleased] -replace = [Unreleased] - - \#\# [{new_version}] - {now:%Y-%m-%d} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b0776f00..79341d400 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). -The LBRY Web UI comes bundled as part of [LBRY App](https://github.com/lbryio/lbry-app). Web UI version numbers track corresponding version of LBRY App. +The LBRY Web UI comes bundled as part of [LBRY App](https://github.com/lbryio/lbry-app). Web UI version numbers should always match the corresponding version of LBRY App. ## [Unreleased] -### Changed - * Use local file for publishing - * Use local file and html5 for video playback - * Misc changes needed to make UI compatible with electron diff --git a/dist/quit.html b/dist/quit.html deleted file mode 100644 index 5bed1d4a9..000000000 --- a/dist/quit.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - LBRY - - - - - - - - - - - - - - - - -
-
- LBRY -
-

- Shutting Down - -

-
-
-
- diff --git a/dist/warning.html b/dist/warning.html deleted file mode 100644 index d82276d94..000000000 --- a/dist/warning.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - LBRY - - - - - - - - - - - - - - - - -
-
- LBRY -
-

- The daemon has unexpectedly shutdown. Goodbye. - -

-
-
-
- diff --git a/js/app.js b/js/app.js index fdf8b1028..68c03a648 100644 --- a/js/app.js +++ b/js/app.js @@ -1,6 +1,4 @@ import React from 'react'; -import {Line} from 'rc-progress'; - import lbry from './lbry.js'; import SettingsPage from './page/settings.js'; import HelpPage from './page/help.js'; @@ -21,11 +19,6 @@ import Header from './component/header.js'; import Modal from './component/modal.js'; import {Link} from './component/link.js'; - -const {remote, ipcRenderer} = require('electron'); -const {download} = remote.require('electron-dl'); - - var App = React.createClass({ _error_key_labels: { connectionString: 'API connection string', @@ -52,7 +45,6 @@ var App = React.createClass({ modal: null, updateUrl: null, isOldOSX: null, - downloadProgress: null, }; }, componentWillMount: function() { @@ -78,9 +70,6 @@ var App = React.createClass({ } else if (versionInfo.os_system == 'Linux') { var updateUrl = 'https://lbry.io/get/lbry.deb'; } else if (versionInfo.os_system == 'Windows') { - // A little weird, but for electron, the installer is - // actually an exe. Maybe a better url would - // be something like /get/windows ? var updateUrl = 'https://lbry.io/get/lbry.msi'; } else { var updateUrl = 'https://lbry.io/get'; @@ -108,18 +97,8 @@ var App = React.createClass({ }); }, handleUpgradeClicked: function() { - // TODO: create a callback for onProgress and have the UI - // show download progress - // TODO: remove the saveAs popup. Thats just me being lazy and having - // some indication that the download is happening - // TODO: calling lbry.stop() ends up displaying the "daemon - // unexpectedly stopped" page. Have a better way of shutting down - let options = { - onProgress: (p) => this.setState({downloadProgress: Math.round(p * 100)}), - } - download(remote.getCurrentWindow(), this.state.updateUrl, options) - .then(dl => ipcRenderer.send('shutdown')); - this.setState({modal: 'downloading'}); + lbry.stop(); + window.location = this.state.updateUrl; }, handleSkipClicked: function() { sessionStorage.setItem('upgradeSkipped', true); @@ -232,11 +211,6 @@ var App = React.createClass({ : null} - // TODO: have color refence css color-primary - - Downloading Update: {this.state.downloadProgress}% Complete - -

Error

diff --git a/js/component/common.js b/js/component/common.js index 9e163476c..afb110871 100644 --- a/js/component/common.js +++ b/js/component/common.js @@ -98,7 +98,7 @@ export let Address = React.createClass({ }); export let Thumbnail = React.createClass({ - _defaultImageUri: lbry.imagePath('default-thumb.svg'), + _defaultImageUri: '/img/default-thumb.svg', _maxLoadTime: 10000, _isMounted: false, diff --git a/js/component/drawer.js b/js/component/drawer.js index 01b7d0ffc..c43239345 100644 --- a/js/component/drawer.js +++ b/js/component/drawer.js @@ -38,15 +38,15 @@ var Drawer = React.createClass({ ); } diff --git a/js/component/file-tile.js b/js/component/file-tile.js index d6e79b860..6cc2afddc 100644 --- a/js/component/file-tile.js +++ b/js/component/file-tile.js @@ -121,15 +121,15 @@ export let FileTileStream = React.createClass({
- +
{ !this.props.hidePrice ? : null} - +

- + {title} @@ -196,4 +196,4 @@ export let FileTile = React.createClass({ return ; } -}); +}); \ No newline at end of file diff --git a/js/component/form.js b/js/component/form.js index 1d2b63bf6..ae4135a29 100644 --- a/js/component/form.js +++ b/js/component/form.js @@ -56,9 +56,6 @@ var FormField = React.createClass({ getValue: function() { if (this.props.type == 'checkbox') { return this.refs.field.checked; - } - else if (this.props.type == 'file') { - return this.refs.field.files[0].path; } else { return this.refs.field.value; } diff --git a/js/component/splash.js b/js/component/splash.js index bba92e288..29cb65234 100644 --- a/js/component/splash.js +++ b/js/component/splash.js @@ -28,7 +28,6 @@ var SplashScreen = React.createClass({ }); lbry.resolveName('one', () => { - window.sessionStorage.setItem('loaded', 'y') this.props.onLoadDone(); }); return; diff --git a/js/main.js b/js/main.js index e03313718..d5cb1ab57 100644 --- a/js/main.js +++ b/js/main.js @@ -13,27 +13,24 @@ var init = function() { } var canvas = document.getElementById('canvas'); - if (window.sessionStorage.getItem('loaded') == 'y') { - ReactDOM.render(, canvas) - } else { - ReactDOM.render( - { - if (balance <= 0) { - window.location.href = '?claim'; - } else { - ReactDOM.render(, canvas); - } - }); - } else { + + ReactDOM.render( + { + if (balance <= 0) { + window.location.href = '?claim'; + } else { ReactDOM.render(, canvas); - } - }}/>, - canvas - ); - } + } + }); + } else { + ReactDOM.render(, canvas); + } + }}/>, + canvas + ); }; init(); diff --git a/js/page/publish.js b/js/page/publish.js index cf2d6f45d..d1d48bc3a 100644 --- a/js/page/publish.js +++ b/js/page/publish.js @@ -45,7 +45,14 @@ var PublishPage = React.createClass({ } } - if (missingFieldFound) { + let fileProcessing = false; + if (this.state.fileInfo && !this.state.tempFileReady) { + this.refs.file.showAdvice('Your file is still processing.'); + this.refs.file.focus(); + fileProcessing = true; + } + + if (missingFieldFound || fileProcessing) { this.setState({ submitting: false, }); @@ -82,7 +89,7 @@ var PublishPage = React.createClass({ }; if (this.refs.file.getValue() !== '') { - publishArgs.file_path = this.refs.file.getValue(); + publishArgs.file_path = this._tempFilePath; } lbry.publish(publishArgs, (message) => { @@ -107,6 +114,8 @@ var PublishPage = React.createClass({ } }, getInitialState: function() { + this._tempFilePath = null; + return { rawName: '', name: '', @@ -118,12 +127,14 @@ var PublishPage = React.createClass({ myClaimValue: 0.0, myClaimMetadata: null, myClaimExists: null, + fileInfo: null, copyrightNotice: '', otherLicenseDescription: '', otherLicenseUrl: '', uploadProgress: 0.0, uploaded: false, errorMessage: null, + tempFileReady: false, submitting: false, modal: null, }; @@ -225,6 +236,56 @@ var PublishPage = React.createClass({ feeCurrency: event.target.value, }); }, + handleFileChange: function(event) { + event.preventDefault(); + + var fileInput = event.target; + + this._tempFilePath = null; + if (fileInput.files.length == 0) { + // File was removed + this.setState({ + fileInfo: null, + uploadProgress: 0.0, + uploaded: false, + tempFileReady: false, + }); + } else { + var file = fileInput.files[0]; + this.setState({ + fileInfo: { + name: file.name, + size: file.size, + }, + uploadProgress: 0.0, + uploaded: false, + tempFileReady: false, + }); + + var xhr = new XMLHttpRequest(); + xhr.upload.addEventListener('progress', (event) => { + this.setState({ + uploadProgress: (event.loaded / event.total), + }); + }); + xhr.upload.addEventListener('load', (event) => { + this.setState({ + uploaded: true, + }); + }); + xhr.addEventListener('load', (event) => { + this._tempFilePath = JSON.parse(xhr.responseText); + this.setState({ + tempFileReady: true, + }); + }) + + var formData = new FormData(fileInput.form); + formData.append('file', fileInput.files[0]); + xhr.open('POST', lbry.webUiUri + '/upload', true); + xhr.send(formData); + } + }, handleFeePrefChange: function(feeEnabled) { this.setState({ isFee: feeEnabled @@ -272,6 +333,21 @@ var PublishPage = React.createClass({ document.title = "Publish"; }, componentDidUpdate: function() { + if (this.state.fileInfo && !this.state.tempFileReady) { + // A file was chosen but the daemon hasn't finished processing it yet, i.e. it's loading, so + // we're displaying a progress bar and need a value for it. + + // React can't unset the "value" prop (to show an "indeterminate" bar) after it's already + // been set, so we have to manage it manually. + + if (!this.state.uploaded) { + // Still uploading + this.refs.progress.setAttribute('value', this.state.uploadProgress); + } else { + // Fully uploaded and waiting for server to finish processing, so set progress bar to "indeterminite" + this.refs.progress.removeAttribute('value'); + } + } }, // Also getting a type warning here too render: function() { @@ -294,7 +370,13 @@ var PublishPage = React.createClass({

Choose File

- + + { !this.state.fileInfo ? '' : + (!this.state.tempFileReady ?
+ + {!this.state.uploaded ? Importing file into LBRY... : Processing file...} +
+ :
File ready for publishing!
) } { this.state.myClaimExists ?
If you don't choose a file, the file from your existing claim will be used.
: null }
diff --git a/js/page/watch.js b/js/page/watch.js index 640d43ac2..e9b3a9185 100644 --- a/js/page/watch.js +++ b/js/page/watch.js @@ -1,18 +1,8 @@ import React from 'react'; -import {Icon} from '../component/common.js'; -import {Link} from '../component/link.js'; import lbry from '../lbry.js'; import LoadScreen from '../component/load_screen.js' -const fs = require('fs'); -const VideoStream = require('videostream'); - - var WatchPage = React.createClass({ - _isMounted: false, - _controlsHideDelay: 3000, // Note: this needs to be shorter than the built-in delay in Electron, or Electron will hide the controls before us - _controlsHideTimeout: null, - propTypes: { name: React.PropTypes.string, }, @@ -22,55 +12,19 @@ var WatchPage = React.createClass({ readyToPlay: false, loadStatusMessage: "Requesting stream", mimeType: null, - controlsShown: false, }; }, componentDidMount: function() { lbry.getStream(this.props.name); this.updateLoadStatus(); }, - handleBackClicked: function() { - history.back(); - }, - handleMouseMove: function() { - if (this._controlsTimeout) { - clearTimeout(this._controlsTimeout); - } - - if (!this.state.controlsShown) { - this.setState({ - controlsShown: true, - }); - } - this._controlsTimeout = setTimeout(() => { - if (!this.isMounted) { - return; - } - - this.setState({ - controlsShown: false, - }); - }, this._controlsHideDelay); - }, - handleMouseOut: function() { - if (this._controlsTimeout) { - clearTimeout(this._controlsTimeout); - } - - if (this.state.controlsShown) { - this.setState({ - controlsShown: false, - }); - } - }, updateLoadStatus: function() { lbry.getFileStatus(this.props.name, (status) => { if (!status || !['running', 'stopped'].includes(status.code) || status.written_bytes == 0) { // Download hasn't started yet, so update status message (if available) then try again - // TODO: Would be nice to check if we have the MOOV before starting playing if (status) { this.setState({ - loadStatusMessage: status.message, + loadStatusMessage: status.message }); } setTimeout(() => { this.updateLoadStatus() }, 250); @@ -79,17 +33,11 @@ var WatchPage = React.createClass({ readyToPlay: true, mimeType: status.mime_type, }) - const mediaFile = { - createReadStream: function (opts) { - // Return a readable stream that provides the bytes - // between offsets "start" and "end" inclusive - console.log('Stream between ' + opts.start + ' and ' + opts.end + '.'); - return fs.createReadStream(status.download_path, opts) - } - } - var elem = this.refs.video; - var videostream = VideoStream(mediaFile, elem); - elem.play(); + var player = new MediaElementPlayer(this.refs.player, { + mode: 'shim', + plugins: ['flash'], + setDimensions: false, + }); } }); }, @@ -97,22 +45,10 @@ var WatchPage = React.createClass({ return ( !this.state.readyToPlay ? - :
-