Merged with master to resolve conflicts

This commit is contained in:
Akinwale Ariwodola 2017-07-06 18:39:35 +01:00
commit ee002597fc
25 changed files with 309 additions and 87 deletions

View file

@ -8,7 +8,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
## [Unreleased] ## [Unreleased]
### Added ### Added
* * Added option to release claim when deleting a file
* *
### Changed ### Changed
@ -16,7 +16,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
* *
### Fixed ### Fixed
* * Fixed bug with download notice when switching window focus
* *
### Deprecated ### Deprecated

1
ui/dist/index.html vendored
View file

@ -7,7 +7,6 @@
<link href='https://fonts.googleapis.com/css?family=Raleway:600,300' rel='stylesheet' type='text/css'> <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='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="./css/all.css" rel="stylesheet" type="text/css" media="screen,print" />
<link rel="stylesheet" href="https://cdn.plyr.io/2.0.12/plyr.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-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-194x194.png" sizes="194x194">
<link rel="icon" type="image/png" href="./img/fav/favicon-96x96.png" sizes="96x96"> <link rel="icon" type="image/png" href="./img/fav/favicon-96x96.png" sizes="96x96">

View file

@ -4,10 +4,11 @@ import { doFetchClaimListMine } from "actions/content";
import { import {
selectClaimsByUri, selectClaimsByUri,
selectClaimListMineIsPending, selectClaimListMineIsPending,
selectMyClaimsOutpoints,
} from "selectors/claims"; } from "selectors/claims";
import { import {
selectFileListIsPending, selectFileListIsPending,
selectAllFileInfos, selectFileInfosByOutpoint,
selectUrisLoading, selectUrisLoading,
} from "selectors/file_info"; } from "selectors/file_info";
import { doCloseModal } from "actions/app"; import { doCloseModal } from "actions/app";
@ -78,8 +79,41 @@ export function doOpenFileInFolder(fileInfo) {
}; };
} }
export function doDeleteFile(outpoint, deleteFromComputer) { export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
return function(dispatch, getState) { return function(dispatch, getState) {
const state = getState();
lbry.file_delete({
outpoint: outpoint,
delete_from_download_dir: deleteFromComputer,
});
// If the file is for a claim we published then also abandom the claim
const myClaimsOutpoints = selectMyClaimsOutpoints(state);
if (abandonClaim && myClaimsOutpoints.indexOf(outpoint) !== -1) {
const byOutpoint = selectFileInfosByOutpoint(state);
const fileInfo = byOutpoint[outpoint];
if (fileInfo) {
dispatch({
type: types.ABANDON_CLAIM_STARTED,
data: {
claimId: fileInfo.claim_id,
},
});
const success = () => {
dispatch({
type: types.ABANDON_CLAIM_COMPLETED,
data: {
claimId: fileInfo.claim_id,
},
});
};
lbry.claim_abandon({ claim_id: fileInfo.claim_id }).then(success);
}
}
dispatch({ dispatch({
type: types.FILE_DELETE, type: types.FILE_DELETE,
data: { data: {
@ -87,11 +121,6 @@ export function doDeleteFile(outpoint, deleteFromComputer) {
}, },
}); });
lbry.file_delete({
outpoint: outpoint,
delete_from_download_dir: deleteFromComputer,
});
dispatch(doCloseModal()); dispatch(doCloseModal());
}; };
} }

View file

@ -1,10 +1,10 @@
import React from "react"; import React from "react";
import Router from "component/router"; import Router from "component/router";
import Header from "component/header"; import Header from "component/header";
import ErrorModal from "component/errorModal"; import ModalError from "component/modalError";
import DownloadingModal from "component/downloadingModal"; import ModalDownloading from "component/modalDownloading";
import UpgradeModal from "component/upgradeModal"; import UpgradeModal from "component/modalUpgrade";
import WelcomeModal from "component/welcomeModal"; import WelcomeModal from "component/modalWelcome";
import lbry from "lbry"; import lbry from "lbry";
import { Line } from "rc-progress"; import { Line } from "rc-progress";
@ -33,8 +33,8 @@ class App extends React.PureComponent {
<Router /> <Router />
</div> </div>
{modal == "upgrade" && <UpgradeModal />} {modal == "upgrade" && <UpgradeModal />}
{modal == "downloading" && <DownloadingModal />} {modal == "downloading" && <ModalDownloading />}
{modal == "error" && <ErrorModal />} {modal == "error" && <ModalError />}
{modal == "welcome" && <WelcomeModal />} {modal == "welcome" && <WelcomeModal />}
</div> </div>
); );

View file

@ -9,13 +9,10 @@ import {
import { makeSelectIsAvailableForUri } from "selectors/availability"; import { makeSelectIsAvailableForUri } from "selectors/availability";
import { selectCurrentModal } from "selectors/app"; import { selectCurrentModal } from "selectors/app";
import { makeSelectCostInfoForUri } from "selectors/cost_info"; import { makeSelectCostInfoForUri } from "selectors/cost_info";
import { doCloseModal, doOpenModal, doHistoryBack } from "actions/app"; import { doCloseModal, doOpenModal } from "actions/app";
import { doFetchAvailability } from "actions/availability"; import { doFetchAvailability } from "actions/availability";
import { import { doOpenFileInShell, doOpenFileInFolder } from "actions/file_info";
doOpenFileInShell, import { makeSelectClaimForUriIsMine } from "selectors/claims";
doOpenFileInFolder,
doDeleteFile,
} from "actions/file_info";
import { doPurchaseUri, doLoadVideo } from "actions/content"; import { doPurchaseUri, doLoadVideo } from "actions/content";
import FileActions from "./view"; import FileActions from "./view";
@ -25,6 +22,7 @@ const makeSelect = () => {
const selectDownloadingForUri = makeSelectDownloadingForUri(); const selectDownloadingForUri = makeSelectDownloadingForUri();
const selectCostInfoForUri = makeSelectCostInfoForUri(); const selectCostInfoForUri = makeSelectCostInfoForUri();
const selectLoadingForUri = makeSelectLoadingForUri(); const selectLoadingForUri = makeSelectLoadingForUri();
const selectClaimForUriIsMine = makeSelectClaimForUriIsMine();
const select = (state, props) => ({ const select = (state, props) => ({
fileInfo: selectFileInfoForUri(state, props), fileInfo: selectFileInfoForUri(state, props),
@ -35,6 +33,7 @@ const makeSelect = () => {
downloading: selectDownloadingForUri(state, props), downloading: selectDownloadingForUri(state, props),
costInfo: selectCostInfoForUri(state, props), costInfo: selectCostInfoForUri(state, props),
loading: selectLoadingForUri(state, props), loading: selectLoadingForUri(state, props),
claimIsMine: selectClaimForUriIsMine(state, props),
}); });
return select; return select;
@ -45,10 +44,6 @@ const perform = dispatch => ({
closeModal: () => dispatch(doCloseModal()), closeModal: () => dispatch(doCloseModal()),
openInFolder: fileInfo => dispatch(doOpenFileInFolder(fileInfo)), openInFolder: fileInfo => dispatch(doOpenFileInFolder(fileInfo)),
openInShell: fileInfo => dispatch(doOpenFileInShell(fileInfo)), openInShell: fileInfo => dispatch(doOpenFileInShell(fileInfo)),
deleteFile: (fileInfo, deleteFromComputer) => {
dispatch(doHistoryBack());
dispatch(doDeleteFile(fileInfo, deleteFromComputer));
},
openModal: modal => dispatch(doOpenModal(modal)), openModal: modal => dispatch(doOpenModal(modal)),
startDownload: uri => dispatch(doPurchaseUri(uri, "affirmPurchase")), startDownload: uri => dispatch(doPurchaseUri(uri, "affirmPurchase")),
loadVideo: uri => dispatch(doLoadVideo(uri)), loadVideo: uri => dispatch(doLoadVideo(uri)),

View file

@ -2,17 +2,17 @@ import React from "react";
import { Icon, BusyMessage } from "component/common"; import { Icon, BusyMessage } from "component/common";
import FilePrice from "component/filePrice"; import FilePrice from "component/filePrice";
import { Modal } from "component/modal"; import { Modal } from "component/modal";
import { FormField } from "component/form";
import Link from "component/link"; import Link from "component/link";
import { ToolTip } from "component/tooltip"; import { ToolTip } from "component/tooltip";
import { DropDownMenu, DropDownMenuItem } from "component/menu"; import { DropDownMenu, DropDownMenuItem } from "component/menu";
import ModalRemoveFile from "component/modalRemoveFile";
import * as modals from "constants/modal_types";
class FileActions extends React.PureComponent { class FileActions extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
forceShowActions: false, forceShowActions: false,
deleteChecked: false,
}; };
} }
@ -37,12 +37,6 @@ class FileActions extends React.PureComponent {
}); });
} }
handleDeleteCheckboxClicked(event) {
this.setState({
deleteChecked: event.target.checked,
});
}
onAffirmPurchase() { onAffirmPurchase() {
this.props.closeModal(); this.props.closeModal();
this.props.loadVideo(this.props.uri); this.props.loadVideo(this.props.uri);
@ -55,7 +49,6 @@ class FileActions extends React.PureComponent {
platform, platform,
downloading, downloading,
uri, uri,
deleteFile,
openInFolder, openInFolder,
openInShell, openInShell,
modal, modal,
@ -64,10 +57,10 @@ class FileActions extends React.PureComponent {
startDownload, startDownload,
costInfo, costInfo,
loading, loading,
claimIsMine,
} = this.props; } = this.props;
const deleteChecked = this.state.deleteChecked, const metadata = fileInfo ? fileInfo.metadata : null,
metadata = fileInfo ? fileInfo.metadata : null,
openInFolderMessage = platform.startsWith("Mac") openInFolderMessage = platform.startsWith("Mac")
? __("Open in Finder") ? __("Open in Finder")
: __("Open in Folder"), : __("Open in Folder"),
@ -85,7 +78,10 @@ class FileActions extends React.PureComponent {
: __("Connecting..."), : __("Connecting..."),
labelWithIcon = ( labelWithIcon = (
<span className="button__content"> <span className="button__content">
<Icon icon="icon-download" /><span>{label}</span> <Icon icon="icon-download" />
<span>
{label}
</span>
</span> </span>
); );
@ -162,7 +158,7 @@ class FileActions extends React.PureComponent {
/> />
<DropDownMenuItem <DropDownMenuItem
key={1} key={1}
onClick={() => openModal("confirmRemove")} onClick={() => openModal(modals.CONFIRM_FILE_REMOVE)}
label={__("Remove...")} label={__("Remove...")}
/> />
</DropDownMenu> </DropDownMenu>
@ -174,9 +170,11 @@ class FileActions extends React.PureComponent {
onConfirmed={this.onAffirmPurchase.bind(this)} onConfirmed={this.onAffirmPurchase.bind(this)}
onAborted={closeModal} onAborted={closeModal}
> >
{__("This will purchase")} <strong>{title}</strong> {__("for")} {__("This will purchase")} <strong>{title}</strong> {__("for")}{" "}
{" "}<strong><FilePrice uri={uri} look="plain" /></strong> <strong>
{" "}{__("credits")}. <FilePrice uri={uri} look="plain" />
</strong>{" "}
{__("credits")}.
</Modal> </Modal>
<Modal <Modal
isOpen={modal == "notEnoughCredits"} isOpen={modal == "notEnoughCredits"}
@ -192,28 +190,12 @@ class FileActions extends React.PureComponent {
> >
{__("LBRY was unable to download the stream")} <strong>{uri}</strong>. {__("LBRY was unable to download the stream")} <strong>{uri}</strong>.
</Modal> </Modal>
<Modal {modal == modals.CONFIRM_FILE_REMOVE &&
isOpen={modal == "confirmRemove"} <ModalRemoveFile
contentLabel={__("Not enough credits")} uri={uri}
type="confirm" outpoint={fileInfo.outpoint}
confirmButtonLabel={__("Remove")} title={title}
onConfirmed={() => deleteFile(fileInfo.outpoint, deleteChecked)} />}
onAborted={closeModal}
>
<p>
{__("Are you sure you'd like to remove")} <cite>{title}</cite>
{" "}{__("from LBRY?")}
</p>
<label>
<FormField
type="checkbox"
checked={deleteChecked}
onClick={this.handleDeleteCheckboxClicked.bind(this)}
/>
{" "}{__("Delete this file from my computer")}
</label>
</Modal>
</section> </section>
); );
} }

View file

@ -2,7 +2,7 @@ import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { doStartUpgrade, doCancelUpgrade } from "actions/app"; import { doStartUpgrade, doCancelUpgrade } from "actions/app";
import { selectDownloadProgress, selectDownloadComplete } from "selectors/app"; import { selectDownloadProgress, selectDownloadComplete } from "selectors/app";
import DownloadingModal from "./view"; import ModalDownloading from "./view";
const select = state => ({ const select = state => ({
downloadProgress: selectDownloadProgress(state), downloadProgress: selectDownloadProgress(state),
@ -14,4 +14,4 @@ const perform = dispatch => ({
cancelUpgrade: () => dispatch(doCancelUpgrade()), cancelUpgrade: () => dispatch(doCancelUpgrade()),
}); });
export default connect(select, perform)(DownloadingModal); export default connect(select, perform)(ModalDownloading);

View file

@ -3,7 +3,7 @@ import { Modal } from "component/modal";
import { Line } from "rc-progress"; import { Line } from "rc-progress";
import Link from "component/link"; import Link from "component/link";
class DownloadingModal extends React.PureComponent { class ModalDownloading extends React.PureComponent {
render() { render() {
const { const {
downloadProgress, downloadProgress,
@ -59,4 +59,4 @@ class DownloadingModal extends React.PureComponent {
} }
} }
export default DownloadingModal; export default ModalDownloading;

View file

@ -2,7 +2,7 @@ import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { selectCurrentModal, selectModalExtraContent } from "selectors/app"; import { selectCurrentModal, selectModalExtraContent } from "selectors/app";
import { doCloseModal } from "actions/app"; import { doCloseModal } from "actions/app";
import ErrorModal from "./view"; import ModalError from "./view";
const select = state => ({ const select = state => ({
modal: selectCurrentModal(state), modal: selectCurrentModal(state),
@ -13,4 +13,4 @@ const perform = dispatch => ({
closeModal: () => dispatch(doCloseModal()), closeModal: () => dispatch(doCloseModal()),
}); });
export default connect(select, perform)(ErrorModal); export default connect(select, perform)(ModalError);

View file

@ -2,7 +2,7 @@ import React from "react";
import lbry from "lbry"; import lbry from "lbry";
import { ExpandableModal } from "component/modal"; import { ExpandableModal } from "component/modal";
class ErrorModal extends React.PureComponent { class ModalError extends React.PureComponent {
render() { render() {
const { modal, closeModal, error } = this.props; const { modal, closeModal, error } = this.props;
@ -60,4 +60,4 @@ class ErrorModal extends React.PureComponent {
} }
} }
export default ErrorModal; export default ModalError;

View file

@ -0,0 +1,27 @@
import React from "react";
import { connect } from "react-redux";
import { doCloseModal, doHistoryBack } from "actions/app";
import { doDeleteFile } from "actions/file_info";
import { makeSelectClaimForUriIsMine } from "selectors/claims";
import ModalRemoveFile from "./view";
const makeSelect = () => {
const selectClaimForUriIsMine = makeSelectClaimForUriIsMine();
const select = (state, props) => ({
claimIsMine: selectClaimForUriIsMine(state, props),
});
return select;
};
const perform = dispatch => ({
closeModal: () => dispatch(doCloseModal()),
deleteFile: (fileInfo, deleteFromComputer, abandonClaim) => {
dispatch(doHistoryBack());
dispatch(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim));
},
});
export default connect(makeSelect, perform)(ModalRemoveFile);

View file

@ -0,0 +1,72 @@
import React from "react";
import { Modal } from "component/modal";
import { FormField } from "component/form.js";
class ModalRemoveFile extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
deleteChecked: false,
abandonClaimChecked: false,
};
}
handleDeleteCheckboxClicked(event) {
this.setState({
deleteChecked: event.target.checked,
});
}
handleAbandonClaimCheckboxClicked(event) {
this.setState({
abandonClaimChecked: event.target.checked,
});
}
render() {
const { claimIsMine, closeModal, deleteFile, outpoint, title } = this.props;
const { deleteChecked, abandonClaimChecked } = this.state;
return (
<Modal
isOpen={true}
contentLabel={__("Confirm File Remove")}
type="confirm"
confirmButtonLabel={__("Remove")}
onConfirmed={() =>
deleteFile(outpoint, deleteChecked, abandonClaimChecked)}
onAborted={closeModal}
>
<p>
{__("Are you sure you'd like to remove")} <cite>{title}</cite>{" "}
{__("from LBRY?")}
</p>
<section>
<label>
<FormField
type="checkbox"
checked={deleteChecked}
onClick={this.handleDeleteCheckboxClicked.bind(this)}
/>{" "}
{__("Delete this file from my computer")}
</label>
</section>
{claimIsMine &&
<section>
<label>
<FormField
type="checkbox"
checked={abandonClaimChecked}
onClick={this.handleAbandonClaimCheckboxClicked.bind(this)}
/>{" "}
{__("Abandon the claim for this URI")}
</label>
</section>}
</Modal>
);
}
}
export default ModalRemoveFile;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { doDownloadUpgrade, doSkipUpgrade } from "actions/app"; import { doDownloadUpgrade, doSkipUpgrade } from "actions/app";
import UpgradeModal from "./view"; import ModalUpgrade from "./view";
const select = state => ({}); const select = state => ({});
@ -10,4 +10,4 @@ const perform = dispatch => ({
skipUpgrade: () => dispatch(doSkipUpgrade()), skipUpgrade: () => dispatch(doSkipUpgrade()),
}); });
export default connect(select, perform)(UpgradeModal); export default connect(select, perform)(ModalUpgrade);

View file

@ -2,7 +2,7 @@ import React from "react";
import { Modal } from "component/modal"; import { Modal } from "component/modal";
import { downloadUpgrade, skipUpgrade } from "actions/app"; import { downloadUpgrade, skipUpgrade } from "actions/app";
class UpgradeModal extends React.PureComponent { class ModalUpgrade extends React.PureComponent {
render() { render() {
const { downloadUpgrade, skipUpgrade } = this.props; const { downloadUpgrade, skipUpgrade } = this.props;
@ -24,4 +24,4 @@ class UpgradeModal extends React.PureComponent {
} }
} }
export default UpgradeModal; export default ModalUpgrade;

View file

@ -4,12 +4,31 @@ import Link from "component/link";
import Modal from "component/modal"; import Modal from "component/modal";
class VideoPlayButton extends React.PureComponent { class VideoPlayButton extends React.PureComponent {
componentDidMount() {
this.keyDownListener = this.onKeyDown.bind(this);
document.addEventListener("keydown", this.keyDownListener);
}
componentWillUnmount() {
document.removeEventListener("keydown", this.keyDownListener);
}
onPurchaseConfirmed() { onPurchaseConfirmed() {
this.props.closeModal(); this.props.closeModal();
this.props.startPlaying(); this.props.startPlaying();
this.props.loadVideo(this.props.uri); this.props.loadVideo(this.props.uri);
} }
onKeyDown(event) {
if (
"input" !== event.target.tagName.toLowerCase() &&
"Space" === event.code
) {
event.preventDefault();
this.onWatchClick();
}
}
onWatchClick() { onWatchClick() {
this.props.purchaseUri(this.props.uri).then(() => { this.props.purchaseUri(this.props.uri).then(() => {
if (!this.props.modal) { if (!this.props.modal) {
@ -73,9 +92,11 @@ class VideoPlayButton extends React.PureComponent {
onConfirmed={this.onPurchaseConfirmed.bind(this)} onConfirmed={this.onPurchaseConfirmed.bind(this)}
onAborted={closeModal} onAborted={closeModal}
> >
{__("This will purchase")} <strong>{title}</strong> {__("for")} {__("This will purchase")} <strong>{title}</strong> {__("for")}{" "}
{" "}<strong><FilePrice uri={uri} look="plain" /></strong> <strong>
{" "}{__("credits")}. <FilePrice uri={uri} look="plain" />
</strong>{" "}
{__("credits")}.
</Modal> </Modal>
<Modal <Modal
isOpen={modal == "timedOut"} isOpen={modal == "timedOut"}

View file

@ -1,7 +1,9 @@
const { remote } = require("electron");
import React from "react"; import React from "react";
import { Thumbnail } from "component/common"; import { Thumbnail } from "component/common";
import player from "render-media"; import player from "render-media";
import fs from "fs"; import fs from "fs";
import { setSession, getSession } from "utils";
import LoadingScreen from "./loading-screen"; import LoadingScreen from "./loading-screen";
class VideoPlayer extends React.PureComponent { class VideoPlayer extends React.PureComponent {
@ -15,6 +17,8 @@ class VideoPlayer extends React.PureComponent {
startedPlaying: false, startedPlaying: false,
unplayable: false, unplayable: false,
}; };
this.togglePlayListener = this.togglePlay.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -28,6 +32,15 @@ class VideoPlayer extends React.PureComponent {
const renderMediaCallback = err => { const renderMediaCallback = err => {
if (err) this.setState({ unplayable: true }); if (err) this.setState({ unplayable: true });
}; };
// Handle fullscreen change for the Windows platform
const win32FullScreenChange = e => {
const win = remote.BrowserWindow.getFocusedWindow();
if ("win32" === process.platform) {
win.setMenu(
document.webkitIsFullScreen ? null : remote.Menu.getApplicationMenu()
);
}
};
// use renderAudio override for mp3 // use renderAudio override for mp3
if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) { if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
@ -41,8 +54,10 @@ class VideoPlayer extends React.PureComponent {
); );
} }
document.addEventListener("keydown", this.togglePlayListener);
const mediaElement = this.refs.media.children[0]; const mediaElement = this.refs.media.children[0];
if (mediaElement) { if (mediaElement) {
mediaElement.addEventListener("click", this.togglePlayListener);
mediaElement.addEventListener( mediaElement.addEventListener(
"loadedmetadata", "loadedmetadata",
loadedMetadata.bind(this), loadedMetadata.bind(this),
@ -50,6 +65,22 @@ class VideoPlayer extends React.PureComponent {
once: true, once: true,
} }
); );
mediaElement.addEventListener(
"webkitfullscreenchange",
win32FullScreenChange.bind(this)
);
mediaElement.addEventListener("volumechange", () => {
setSession("prefs_volume", mediaElement.volume);
});
mediaElement.volume = this.getPreferredVolume();
}
}
componentWillUnmount() {
document.removeEventListener("keydown", this.togglePlayListener);
const mediaElement = this.refs.media.children[0];
if (mediaElement) {
mediaElement.removeEventListener("click", this.togglePlayListener);
} }
} }
@ -62,6 +93,30 @@ class VideoPlayer extends React.PureComponent {
container.appendChild(audio); container.appendChild(audio);
} }
togglePlay(event) {
// ignore all events except click and spacebar keydown, or input events in a form control
if (
"keydown" === event.type &&
("Space" !== event.code || "input" === event.target.tagName.toLowerCase())
) {
return;
}
event.preventDefault();
const mediaElement = this.refs.media.children[0];
if (mediaElement) {
if (!mediaElement.paused) {
mediaElement.pause();
} else {
mediaElement.play();
}
}
}
getPreferredVolume() {
const volumePreference = parseFloat(getSession("prefs_volume"));
return isNaN(volumePreference) ? 1 : volumePreference;
}
componentDidUpdate() { componentDidUpdate() {
const { contentType, downloadCompleted } = this.props; const { contentType, downloadCompleted } = this.props;
const { startedPlaying } = this.state; const { startedPlaying } = this.state;

View file

@ -62,6 +62,8 @@ export const PLAY_VIDEO_STARTED = "PLAY_VIDEO_STARTED";
export const FETCH_AVAILABILITY_STARTED = "FETCH_AVAILABILITY_STARTED"; export const FETCH_AVAILABILITY_STARTED = "FETCH_AVAILABILITY_STARTED";
export const FETCH_AVAILABILITY_COMPLETED = "FETCH_AVAILABILITY_COMPLETED"; export const FETCH_AVAILABILITY_COMPLETED = "FETCH_AVAILABILITY_COMPLETED";
export const FILE_DELETE = "FILE_DELETE"; export const FILE_DELETE = "FILE_DELETE";
export const ABANDON_CLAIM_STARTED = "ABANDON_CLAIM_STARTED";
export const ABANDON_CLAIM_COMPLETED = "ABANDON_CLAIM_COMPLETED";
// Search // Search
export const SEARCH_STARTED = "SEARCH_STARTED"; export const SEARCH_STARTED = "SEARCH_STARTED";

View file

@ -1 +1,2 @@
export const WELCOME = "welcome"; export const WELCOME = "welcome";
export const CONFIRM_FILE_REMOVE = "confirmFileRemove";

View file

@ -462,6 +462,12 @@ lbry.claim_list_mine = function(params = {}) {
}); });
}; };
lbry.claim_abandon = function(params = {}) {
return new Promise((resolve, reject) => {
apiCall("claim_abandon", params, resolve, reject);
});
};
lbry._resolveXhrs = {}; lbry._resolveXhrs = {};
lbry.resolve = function(params = {}) { lbry.resolve = function(params = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View file

@ -80,6 +80,29 @@ reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) {
}); });
}; };
reducers[types.ABANDON_CLAIM_COMPLETED] = function(state, action) {
const { claimId } = action.data;
const myClaims = new Set(state.myClaims);
const byId = Object.assign({}, state.byId);
const claimsByUri = Object.assign({}, state.claimsByUri);
const uris = [];
Object.keys(claimsByUri).forEach(uri => {
if (claimsByUri[uri] === claimId) {
delete claimsByUri[uri];
}
});
delete byId[claimId];
myClaims.delete(claimId);
return Object.assign({}, state, {
myClaims,
byId,
claimsByUri,
});
};
export default function reducer(state = defaultState, action) { export default function reducer(state = defaultState, action) {
const handler = reducers[action.type]; const handler = reducers[action.type];
if (handler) return handler(state, action); if (handler) return handler(state, action);

View file

@ -48,6 +48,18 @@ export const makeSelectClaimForUri = () => {
return createSelector(selectClaimForUri, claim => claim); return createSelector(selectClaimForUri, claim => claim);
}; };
const selectClaimForUriIsMine = (state, props) => {
const uri = lbryuri.normalize(props.uri);
const claim = selectClaimsByUri(state)[uri];
const myClaims = selectMyClaims(state);
return myClaims.has(claim.claim_id);
};
export const makeSelectClaimForUriIsMine = () => {
return createSelector(selectClaimForUriIsMine, isMine => isMine);
};
export const selectClaimsInChannelForUri = (state, props) => { export const selectClaimsInChannelForUri = (state, props) => {
return selectAllClaimsByChannel(state)[props.uri]; return selectAllClaimsByChannel(state)[props.uri];
}; };
@ -95,7 +107,7 @@ export const selectClaimListMineIsPending = createSelector(
export const selectMyClaims = createSelector( export const selectMyClaims = createSelector(
_selectState, _selectState,
state => state.myClaims || new Set() state => new Set(state.myClaims)
); );
export const selectMyClaimsOutpoints = createSelector( export const selectMyClaimsOutpoints = createSelector(

View file

@ -1,6 +1,6 @@
const { remote } = require("electron"); const { remote } = require("electron");
const application = remote.app; const application = remote.app;
const win = remote.BrowserWindow.getFocusedWindow(); const win = remote.getCurrentWindow();
const setProgressBar = progress => { const setProgressBar = progress => {
win.setProgressBar(progress); win.setProgressBar(progress);

View file

@ -17,9 +17,12 @@ video {
max-width: $width-page-constrained; max-width: $width-page-constrained;
max-height: $height-video-embedded; max-height: $height-video-embedded;
height: $height-video-embedded; height: $height-video-embedded;
position: relative; /*for .plyr below*/ position: relative;
video { video {
height: 100%; height: 100%;
position: absolute;
left: 0;
top: 0;
} }
&.video--hidden { &.video--hidden {
height: $height-video-embedded; height: $height-video-embedded;
@ -27,11 +30,6 @@ video {
&.video--active { &.video--active {
/*background: none;*/ /*background: none;*/
} }
.plyr {
top: 50%;
transform: translateY(-50%);
}
} }
.video--obscured .video__cover .video--obscured .video__cover
{ {