mirror of
https://github.com/LBRYFoundation/lbry-desktop.git
synced 2025-08-23 17:47:24 +00:00
Merged with master to resolve conflicts
This commit is contained in:
commit
ee002597fc
25 changed files with 309 additions and 87 deletions
|
@ -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
1
ui/dist/index.html
vendored
|
@ -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">
|
||||||
|
|
|
@ -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());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
27
ui/js/component/modalRemoveFile/index.js
Normal file
27
ui/js/component/modalRemoveFile/index.js
Normal 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);
|
72
ui/js/component/modalRemoveFile/view.jsx
Normal file
72
ui/js/component/modalRemoveFile/view.jsx
Normal 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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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"}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
export const WELCOME = "welcome";
|
export const WELCOME = "welcome";
|
||||||
|
export const CONFIRM_FILE_REMOVE = "confirmFileRemove";
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue