From b43ed0b64f6b89d0d2fd289d1d929439e3f72645 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sat, 1 Jul 2017 21:33:23 +0100 Subject: [PATCH 01/11] Issue #311 playback input improvements --- ui/js/component/video/internal/player.jsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ui/js/component/video/internal/player.jsx b/ui/js/component/video/internal/player.jsx index 1a86c3b20..4385278c0 100644 --- a/ui/js/component/video/internal/player.jsx +++ b/ui/js/component/video/internal/player.jsx @@ -33,6 +33,7 @@ class VideoPlayer extends React.PureComponent { renderMediaCallback.bind(this) ); + document.addEventListener("keydown", this.togglePlay.bind(this)); const mediaElement = this.refs.media.children[0]; if (mediaElement) { mediaElement.addEventListener( @@ -42,6 +43,23 @@ class VideoPlayer extends React.PureComponent { once: true, } ); + mediaElement.addEventListener("click", this.togglePlay.bind(this)); + } + } + + togglePlay(event) { + // ignore all events except click and spacebar keydown + if ("keydown" === event.type && event.keyCode !== 32) { + return; + } + event.preventDefault(); + const mediaElement = this.refs.media.children[0]; + if (mediaElement) { + if (!mediaElement.paused) { + mediaElement.pause(); + } else { + mediaElement.play(); + } } } From fb3785feed9552c271442007ba43073676b1b0ec Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sat, 1 Jul 2017 21:48:12 +0100 Subject: [PATCH 02/11] Implemented the ability for the spacebar to initiate video playback --- .../component/video/internal/play-button.jsx | 26 ++++++++++++++----- ui/js/component/video/internal/player.jsx | 2 +- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/ui/js/component/video/internal/play-button.jsx b/ui/js/component/video/internal/play-button.jsx index fb297904a..f696ab539 100644 --- a/ui/js/component/video/internal/play-button.jsx +++ b/ui/js/component/video/internal/play-button.jsx @@ -4,12 +4,23 @@ import Link from "component/link"; import Modal from "component/modal"; class VideoPlayButton extends React.PureComponent { + componentDidMount() { + document.addEventListener("keydown", this.onKeyDown.bind(this)); + } + onPurchaseConfirmed() { this.props.closeModal(); this.props.startPlaying(); this.props.loadVideo(this.props.uri); } + onKeyDown(event) { + if (event.keyCode === 32) { + event.preventDefault(); + this.onWatchClick(); + } + } + onWatchClick() { this.props.purchaseUri(this.props.uri).then(() => { if (!this.props.modal) { @@ -45,9 +56,10 @@ class VideoPlayButton extends React.PureComponent { isLoading || fileInfo === undefined || (fileInfo === null && (!costInfo || costInfo.cost === undefined)); - const icon = ["audio", "video"].indexOf(mediaType) !== -1 - ? "icon-play" - : "icon-folder-o"; + const icon = + ["audio", "video"].indexOf(mediaType) !== -1 + ? "icon-play" + : "icon-folder-o"; return (
@@ -73,9 +85,11 @@ class VideoPlayButton extends React.PureComponent { onConfirmed={this.onPurchaseConfirmed.bind(this)} onAborted={closeModal} > - {__("This will purchase")} {title} {__("for")} - {" "} - {" "}{__("credits")}. + {__("This will purchase")} {title} {__("for")}{" "} + + + {" "} + {__("credits")}. Date: Sat, 1 Jul 2017 22:57:14 +0100 Subject: [PATCH 03/11] Added requested event handling changes --- ui/js/component/video/internal/play-button.jsx | 16 ++++++++++------ ui/js/component/video/internal/player.jsx | 16 +++++++++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ui/js/component/video/internal/play-button.jsx b/ui/js/component/video/internal/play-button.jsx index f696ab539..aa352ddf7 100644 --- a/ui/js/component/video/internal/play-button.jsx +++ b/ui/js/component/video/internal/play-button.jsx @@ -5,7 +5,12 @@ import Modal from "component/modal"; class VideoPlayButton extends React.PureComponent { componentDidMount() { - document.addEventListener("keydown", this.onKeyDown.bind(this)); + this.keyDownListener = this.onKeyDown.bind(this); + document.addEventListener("keydown", this.keyDownListener); + } + + componentWillUnmount() { + document.removeEventListener("keydown", this.keyDownListener); } onPurchaseConfirmed() { @@ -15,7 +20,7 @@ class VideoPlayButton extends React.PureComponent { } onKeyDown(event) { - if (event.keyCode === 32) { + if ("Space" === event.code) { event.preventDefault(); this.onWatchClick(); } @@ -56,10 +61,9 @@ class VideoPlayButton extends React.PureComponent { isLoading || fileInfo === undefined || (fileInfo === null && (!costInfo || costInfo.cost === undefined)); - const icon = - ["audio", "video"].indexOf(mediaType) !== -1 - ? "icon-play" - : "icon-folder-o"; + const icon = ["audio", "video"].indexOf(mediaType) !== -1 + ? "icon-play" + : "icon-folder-o"; return (
diff --git a/ui/js/component/video/internal/player.jsx b/ui/js/component/video/internal/player.jsx index 6b7c04eed..bf2a6dcc3 100644 --- a/ui/js/component/video/internal/player.jsx +++ b/ui/js/component/video/internal/player.jsx @@ -13,6 +13,8 @@ class VideoPlayer extends React.PureComponent { startedPlaying: false, unplayable: false, }; + + this.togglePlayListener = this.togglePlay.bind(this); } componentDidMount() { @@ -33,7 +35,7 @@ class VideoPlayer extends React.PureComponent { renderMediaCallback.bind(this) ); - document.addEventListener("keydown", this.togglePlay.bind(this)); + document.addEventListener("keydown", this.togglePlayListener); const mediaElement = this.refs.media.children[0]; if (mediaElement) { mediaElement.addEventListener( @@ -43,13 +45,21 @@ class VideoPlayer extends React.PureComponent { once: true, } ); - mediaElement.addEventListener("click", this.togglePlay.bind(this)); + mediaElement.addEventListener("click", this.togglePlayListener); + } + } + + componentWillUnmount() { + document.removeEventListener("keydown", this.togglePlayListener); + const mediaElement = this.refs.media.children[0]; + if (mediaElement) { + mediaElement.removeEventListener("click", this.togglePlayListener); } } togglePlay(event) { // ignore all events except click and spacebar keydown - if ("keydown" === event.type && event.keyCode !== 32) { + if ("keydown" === event.type && "Space" !== event.code) { return; } event.preventDefault(); From 98e25bee45780ec7d79c2981f9cf75766a0d4b8b Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sun, 2 Jul 2017 09:00:22 +0100 Subject: [PATCH 04/11] Issue #308 hide menu in fullscreen mode on Windows --- ui/js/component/video/internal/player.jsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ui/js/component/video/internal/player.jsx b/ui/js/component/video/internal/player.jsx index 1a86c3b20..608d67842 100644 --- a/ui/js/component/video/internal/player.jsx +++ b/ui/js/component/video/internal/player.jsx @@ -1,3 +1,4 @@ +const { remote } = require("electron"); import React from "react"; import { Thumbnail } from "component/common"; import player from "render-media"; @@ -25,6 +26,15 @@ class VideoPlayer extends React.PureComponent { const renderMediaCallback = err => { 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() + ); + } + }; player.append( this.file(), @@ -42,6 +52,10 @@ class VideoPlayer extends React.PureComponent { once: true, } ); + mediaElement.addEventListener( + "webkitfullscreenchange", + win32FullScreenChange.bind(this) + ); } } From 99cb1a0a6502a2157fcd46b0c61017f75688a8b1 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Sun, 2 Jul 2017 10:48:18 -0400 Subject: [PATCH 05/11] fix video sizing, remove unused CSS --- ui/dist/index.html | 1 - ui/scss/component/_video.scss | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ui/dist/index.html b/ui/dist/index.html index 8fbf0b5b6..d951dddd1 100644 --- a/ui/dist/index.html +++ b/ui/dist/index.html @@ -7,7 +7,6 @@ - diff --git a/ui/scss/component/_video.scss b/ui/scss/component/_video.scss index 745b2d494..aff720a7b 100644 --- a/ui/scss/component/_video.scss +++ b/ui/scss/component/_video.scss @@ -17,9 +17,12 @@ video { max-width: $width-page-constrained; max-height: $height-video-embedded; height: $height-video-embedded; - position: relative; /*for .plyr below*/ + position: relative; video { height: 100%; + position: absolute; + left: 0; + top: 0; } &.video--hidden { height: $height-video-embedded; @@ -27,11 +30,6 @@ video { &.video--active { /*background: none;*/ } - - .plyr { - top: 50%; - transform: translateY(-50%); - } } .video--obscured .video__cover { From 444f2308772f49b5209b21caa6a393e19c5c4958 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sat, 1 Jul 2017 22:38:09 +0100 Subject: [PATCH 06/11] Issue #310 video volume reset fix --- ui/js/component/video/internal/player.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ui/js/component/video/internal/player.jsx b/ui/js/component/video/internal/player.jsx index 608d67842..b7a305472 100644 --- a/ui/js/component/video/internal/player.jsx +++ b/ui/js/component/video/internal/player.jsx @@ -52,13 +52,23 @@ class VideoPlayer extends React.PureComponent { once: true, } ); + mediaElement.addEventListener( "webkitfullscreenchange", win32FullScreenChange.bind(this) ); + mediaElement.addEventListener("volumechange", () => { + localStorage.setItem("prefs_volume", mediaElement.volume); + }); + mediaElement.volume = this.getPreferredVolume(); } } + getPreferredVolume() { + const volumePreference = parseFloat(localStorage.getItem("prefs_volume")); + return isNaN(volumePreference) ? 1 : volumePreference; + } + componentDidUpdate() { const { mediaType, downloadCompleted } = this.props; const { startedPlaying } = this.state; From 1dea560cdf9ba4da33cfe69abf9cc5c9fd1e9772 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Sun, 2 Jul 2017 11:35:30 -0400 Subject: [PATCH 07/11] switch volume to session --- ui/js/component/video/internal/player.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/js/component/video/internal/player.jsx b/ui/js/component/video/internal/player.jsx index b7a305472..56375ce6b 100644 --- a/ui/js/component/video/internal/player.jsx +++ b/ui/js/component/video/internal/player.jsx @@ -3,6 +3,7 @@ import React from "react"; import { Thumbnail } from "component/common"; import player from "render-media"; import fs from "fs"; +import { setSession, getSession } from "utils"; import LoadingScreen from "./loading-screen"; class VideoPlayer extends React.PureComponent { @@ -58,14 +59,14 @@ class VideoPlayer extends React.PureComponent { win32FullScreenChange.bind(this) ); mediaElement.addEventListener("volumechange", () => { - localStorage.setItem("prefs_volume", mediaElement.volume); + setSession("prefs_volume", mediaElement.volume); }); mediaElement.volume = this.getPreferredVolume(); } } getPreferredVolume() { - const volumePreference = parseFloat(localStorage.getItem("prefs_volume")); + const volumePreference = parseFloat(getSession("prefs_volume")); return isNaN(volumePreference) ? 1 : volumePreference; } From 91359c29668e1cc6e9ebe3434d5e299ad516552d Mon Sep 17 00:00:00 2001 From: 6ea86b96 <6ea86b96@gmail.com> Date: Thu, 29 Jun 2017 14:44:34 +0700 Subject: [PATCH 08/11] Add option to abandon claim when deleting published file --- ui/js/actions/file_info.js | 43 +++++++++++++++--- ui/js/component/fileActions/index.js | 7 ++- ui/js/component/fileActions/view.jsx | 65 ++++++++++++++++++++-------- ui/js/constants/action_types.js | 2 + ui/js/lbry.js | 13 ++++-- ui/js/reducers/claims.js | 23 ++++++++++ ui/js/selectors/claims.js | 14 +++++- 7 files changed, 136 insertions(+), 31 deletions(-) diff --git a/ui/js/actions/file_info.js b/ui/js/actions/file_info.js index ba4c606db..9d3861fb7 100644 --- a/ui/js/actions/file_info.js +++ b/ui/js/actions/file_info.js @@ -4,10 +4,11 @@ import { doFetchClaimListMine } from "actions/content"; import { selectClaimsByUri, selectClaimListMineIsPending, + selectMyClaimsOutpoints, } from "selectors/claims"; import { selectFileListIsPending, - selectAllFileInfos, + selectFileInfosByOutpoint, selectUrisLoading, } from "selectors/file_info"; 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) { + 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({ type: types.FILE_DELETE, data: { @@ -87,11 +121,6 @@ export function doDeleteFile(outpoint, deleteFromComputer) { }, }); - lbry.file_delete({ - outpoint: outpoint, - delete_from_download_dir: deleteFromComputer, - }); - dispatch(doCloseModal()); }; } diff --git a/ui/js/component/fileActions/index.js b/ui/js/component/fileActions/index.js index 572783ee5..eb5fc7422 100644 --- a/ui/js/component/fileActions/index.js +++ b/ui/js/component/fileActions/index.js @@ -16,6 +16,7 @@ import { doOpenFileInFolder, doDeleteFile, } from "actions/file_info"; +import { makeSelectClaimForUriIsMine } from "selectors/claims"; import { doPurchaseUri, doLoadVideo } from "actions/content"; import FileActions from "./view"; @@ -25,6 +26,7 @@ const makeSelect = () => { const selectDownloadingForUri = makeSelectDownloadingForUri(); const selectCostInfoForUri = makeSelectCostInfoForUri(); const selectLoadingForUri = makeSelectLoadingForUri(); + const selectClaimForUriIsMine = makeSelectClaimForUriIsMine(); const select = (state, props) => ({ fileInfo: selectFileInfoForUri(state, props), @@ -35,6 +37,7 @@ const makeSelect = () => { downloading: selectDownloadingForUri(state, props), costInfo: selectCostInfoForUri(state, props), loading: selectLoadingForUri(state, props), + claimIsMine: selectClaimForUriIsMine(state, props), }); return select; @@ -45,9 +48,9 @@ const perform = dispatch => ({ closeModal: () => dispatch(doCloseModal()), openInFolder: fileInfo => dispatch(doOpenFileInFolder(fileInfo)), openInShell: fileInfo => dispatch(doOpenFileInShell(fileInfo)), - deleteFile: (fileInfo, deleteFromComputer) => { + deleteFile: (fileInfo, deleteFromComputer, abandonClaim) => { dispatch(doHistoryBack()); - dispatch(doDeleteFile(fileInfo, deleteFromComputer)); + dispatch(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim)); }, openModal: modal => dispatch(doOpenModal(modal)), startDownload: uri => dispatch(doPurchaseUri(uri, "affirmPurchase")), diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx index b78512be9..530987806 100644 --- a/ui/js/component/fileActions/view.jsx +++ b/ui/js/component/fileActions/view.jsx @@ -13,6 +13,7 @@ class FileActions extends React.PureComponent { this.state = { forceShowActions: false, deleteChecked: false, + abandonClaimChecked: false, }; } @@ -43,6 +44,12 @@ class FileActions extends React.PureComponent { }); } + handleAbandonClaimCheckboxClicked(event) { + this.setState({ + abandonClaimChecked: event.target.checked, + }); + } + onAffirmPurchase() { this.props.closeModal(); this.props.loadVideo(this.props.uri); @@ -64,9 +71,11 @@ class FileActions extends React.PureComponent { startDownload, costInfo, loading, + claimIsMine, } = this.props; const deleteChecked = this.state.deleteChecked, + abandonClaimChecked = this.state.abandonClaimChecked, metadata = fileInfo ? fileInfo.metadata : null, openInFolderMessage = platform.startsWith("Mac") ? __("Open in Finder") @@ -77,15 +86,19 @@ class FileActions extends React.PureComponent { let content; if (loading || downloading) { - const progress = fileInfo && fileInfo.written_bytes - ? fileInfo.written_bytes / fileInfo.total_bytes * 100 - : 0, + const progress = + fileInfo && fileInfo.written_bytes + ? fileInfo.written_bytes / fileInfo.total_bytes * 100 + : 0, label = fileInfo ? progress.toFixed(0) + __("% complete") : __("Connecting..."), labelWithIcon = ( - {label} + + + {label} + ); @@ -174,9 +187,11 @@ class FileActions extends React.PureComponent { onConfirmed={this.onAffirmPurchase.bind(this)} onAborted={closeModal} > - {__("This will purchase")} {title} {__("for")} - {" "} - {" "}{__("credits")}. + {__("This will purchase")} {title} {__("for")}{" "} + + + {" "} + {__("credits")}. deleteFile(fileInfo.outpoint, deleteChecked)} + onConfirmed={() => + deleteFile(fileInfo.outpoint, deleteChecked, abandonClaimChecked)} onAborted={closeModal} >

- {__("Are you sure you'd like to remove")} {title} - {" "}{__("from LBRY?")} + {__("Are you sure you'd like to remove")} {title}{" "} + {__("from LBRY?")}

- +
+ +
+ {claimIsMine && +
+ +
}
); diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js index a66ae5874..216c84762 100644 --- a/ui/js/constants/action_types.js +++ b/ui/js/constants/action_types.js @@ -62,6 +62,8 @@ export const PLAY_VIDEO_STARTED = "PLAY_VIDEO_STARTED"; export const FETCH_AVAILABILITY_STARTED = "FETCH_AVAILABILITY_STARTED"; export const FETCH_AVAILABILITY_COMPLETED = "FETCH_AVAILABILITY_COMPLETED"; export const FILE_DELETE = "FILE_DELETE"; +export const ABANDON_CLAIM_STARTED = "ABANDON_CLAIM_STARTED"; +export const ABANDON_CLAIM_COMPLETED = "ABANDON_CLAIM_COMPLETED"; // Search export const SEARCH_STARTED = "SEARCH_STARTED"; diff --git a/ui/js/lbry.js b/ui/js/lbry.js index 262e957bf..accc5152c 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -268,9 +268,10 @@ lbry.getClientSettings = function() { var outSettings = {}; for (let setting of Object.keys(lbry.defaultClientSettings)) { var localStorageVal = localStorage.getItem("setting_" + setting); - outSettings[setting] = localStorageVal === null - ? lbry.defaultClientSettings[setting] - : JSON.parse(localStorageVal); + outSettings[setting] = + localStorageVal === null + ? lbry.defaultClientSettings[setting] + : JSON.parse(localStorageVal); } return outSettings; }; @@ -462,6 +463,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.resolve = function(params = {}) { return new Promise((resolve, reject) => { diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index a237947b6..7417bc2fb 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -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) { const handler = reducers[action.type]; if (handler) return handler(state, action); diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index 7508c6ce1..b966375e9 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -48,6 +48,18 @@ export const makeSelectClaimForUri = () => { 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) => { return selectAllClaimsByChannel(state)[props.uri]; }; @@ -95,7 +107,7 @@ export const selectClaimListMineIsPending = createSelector( export const selectMyClaims = createSelector( _selectState, - state => state.myClaims || new Set() + state => new Set(state.myClaims) ); export const selectMyClaimsOutpoints = createSelector( From 8ea972200a5f22e5f870255506f81e2f92a76ae7 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Sun, 2 Jul 2017 14:23:38 -0400 Subject: [PATCH 09/11] refactor remove file modal --- ui/js/component/app/view.jsx | 12 +-- ui/js/component/fileActions/index.js | 12 +-- ui/js/component/fileActions/view.jsx | 73 ++++--------------- .../index.jsx => modalDownloading/index.js} | 4 +- .../view.jsx | 4 +- .../index.jsx => modalError/index.js} | 4 +- .../{errorModal => modalError}/view.jsx | 4 +- ui/js/component/modalRemoveFile/index.js | 27 +++++++ ui/js/component/modalRemoveFile/view.jsx | 72 ++++++++++++++++++ .../index.jsx => modalUpgrade/index.js} | 4 +- .../{upgradeModal => modalUpgrade}/view.jsx | 4 +- .../index.jsx => modalWelcome/index.js} | 0 .../{welcomeModal => modalWelcome}/view.jsx | 0 ui/js/constants/modal_types.js | 1 + 14 files changed, 133 insertions(+), 88 deletions(-) rename ui/js/component/{downloadingModal/index.jsx => modalDownloading/index.js} (83%) rename ui/js/component/{downloadingModal => modalDownloading}/view.jsx (94%) rename ui/js/component/{errorModal/index.jsx => modalError/index.js} (81%) rename ui/js/component/{errorModal => modalError}/view.jsx (95%) create mode 100644 ui/js/component/modalRemoveFile/index.js create mode 100644 ui/js/component/modalRemoveFile/view.jsx rename ui/js/component/{upgradeModal/index.jsx => modalUpgrade/index.js} (77%) rename ui/js/component/{upgradeModal => modalUpgrade}/view.jsx (88%) rename ui/js/component/{welcomeModal/index.jsx => modalWelcome/index.js} (100%) rename ui/js/component/{welcomeModal => modalWelcome}/view.jsx (100%) diff --git a/ui/js/component/app/view.jsx b/ui/js/component/app/view.jsx index f117c5f2e..727f4e39a 100644 --- a/ui/js/component/app/view.jsx +++ b/ui/js/component/app/view.jsx @@ -1,10 +1,10 @@ import React from "react"; import Router from "component/router"; import Header from "component/header"; -import ErrorModal from "component/errorModal"; -import DownloadingModal from "component/downloadingModal"; -import UpgradeModal from "component/upgradeModal"; -import WelcomeModal from "component/welcomeModal"; +import ModalError from "component/modalError"; +import ModalDownloading from "component/modalDownloading"; +import UpgradeModal from "component/modalUpgrade"; +import WelcomeModal from "component/modalWelcome"; import lbry from "lbry"; import { Line } from "rc-progress"; @@ -33,8 +33,8 @@ class App extends React.PureComponent {
{modal == "upgrade" && } - {modal == "downloading" && } - {modal == "error" && } + {modal == "downloading" && } + {modal == "error" && } {modal == "welcome" && }
); diff --git a/ui/js/component/fileActions/index.js b/ui/js/component/fileActions/index.js index eb5fc7422..769a1390d 100644 --- a/ui/js/component/fileActions/index.js +++ b/ui/js/component/fileActions/index.js @@ -9,13 +9,9 @@ import { import { makeSelectIsAvailableForUri } from "selectors/availability"; import { selectCurrentModal } from "selectors/app"; 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 { - doOpenFileInShell, - doOpenFileInFolder, - doDeleteFile, -} from "actions/file_info"; +import { doOpenFileInShell, doOpenFileInFolder } from "actions/file_info"; import { makeSelectClaimForUriIsMine } from "selectors/claims"; import { doPurchaseUri, doLoadVideo } from "actions/content"; import FileActions from "./view"; @@ -48,10 +44,6 @@ const perform = dispatch => ({ closeModal: () => dispatch(doCloseModal()), openInFolder: fileInfo => dispatch(doOpenFileInFolder(fileInfo)), openInShell: fileInfo => dispatch(doOpenFileInShell(fileInfo)), - deleteFile: (fileInfo, deleteFromComputer, abandonClaim) => { - dispatch(doHistoryBack()); - dispatch(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim)); - }, openModal: modal => dispatch(doOpenModal(modal)), startDownload: uri => dispatch(doPurchaseUri(uri, "affirmPurchase")), loadVideo: uri => dispatch(doLoadVideo(uri)), diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx index 530987806..53188a1f5 100644 --- a/ui/js/component/fileActions/view.jsx +++ b/ui/js/component/fileActions/view.jsx @@ -2,18 +2,17 @@ import React from "react"; import { Icon, BusyMessage } from "component/common"; import FilePrice from "component/filePrice"; import { Modal } from "component/modal"; -import { FormField } from "component/form"; import Link from "component/link"; import { ToolTip } from "component/tooltip"; import { DropDownMenu, DropDownMenuItem } from "component/menu"; +import ModalRemoveFile from "component/modalRemoveFile"; +import * as modals from "constants/modal_types"; class FileActions extends React.PureComponent { constructor(props) { super(props); this.state = { forceShowActions: false, - deleteChecked: false, - abandonClaimChecked: false, }; } @@ -38,18 +37,6 @@ class FileActions extends React.PureComponent { }); } - handleDeleteCheckboxClicked(event) { - this.setState({ - deleteChecked: event.target.checked, - }); - } - - handleAbandonClaimCheckboxClicked(event) { - this.setState({ - abandonClaimChecked: event.target.checked, - }); - } - onAffirmPurchase() { this.props.closeModal(); this.props.loadVideo(this.props.uri); @@ -62,7 +49,6 @@ class FileActions extends React.PureComponent { platform, downloading, uri, - deleteFile, openInFolder, openInShell, modal, @@ -74,9 +60,7 @@ class FileActions extends React.PureComponent { claimIsMine, } = this.props; - const deleteChecked = this.state.deleteChecked, - abandonClaimChecked = this.state.abandonClaimChecked, - metadata = fileInfo ? fileInfo.metadata : null, + const metadata = fileInfo ? fileInfo.metadata : null, openInFolderMessage = platform.startsWith("Mac") ? __("Open in Finder") : __("Open in Folder"), @@ -86,10 +70,9 @@ class FileActions extends React.PureComponent { let content; if (loading || downloading) { - const progress = - fileInfo && fileInfo.written_bytes - ? fileInfo.written_bytes / fileInfo.total_bytes * 100 - : 0, + const progress = fileInfo && fileInfo.written_bytes + ? fileInfo.written_bytes / fileInfo.total_bytes * 100 + : 0, label = fileInfo ? progress.toFixed(0) + __("% complete") : __("Connecting..."), @@ -175,7 +158,7 @@ class FileActions extends React.PureComponent { /> openModal("confirmRemove")} + onClick={() => openModal(modals.CONFIRM_FILE_REMOVE)} label={__("Remove...")} /> @@ -207,42 +190,12 @@ class FileActions extends React.PureComponent { > {__("LBRY was unable to download the stream")} {uri}. - - deleteFile(fileInfo.outpoint, deleteChecked, abandonClaimChecked)} - onAborted={closeModal} - > -

- {__("Are you sure you'd like to remove")} {title}{" "} - {__("from LBRY?")} -

- -
- -
- {claimIsMine && -
- -
} -
+ {modal == modals.CONFIRM_FILE_REMOVE && + } ); } diff --git a/ui/js/component/downloadingModal/index.jsx b/ui/js/component/modalDownloading/index.js similarity index 83% rename from ui/js/component/downloadingModal/index.jsx rename to ui/js/component/modalDownloading/index.js index 1902cbd13..a8a316658 100644 --- a/ui/js/component/downloadingModal/index.jsx +++ b/ui/js/component/modalDownloading/index.js @@ -2,7 +2,7 @@ import React from "react"; import { connect } from "react-redux"; import { doStartUpgrade, doCancelUpgrade } from "actions/app"; import { selectDownloadProgress, selectDownloadComplete } from "selectors/app"; -import DownloadingModal from "./view"; +import ModalDownloading from "./view"; const select = state => ({ downloadProgress: selectDownloadProgress(state), @@ -14,4 +14,4 @@ const perform = dispatch => ({ cancelUpgrade: () => dispatch(doCancelUpgrade()), }); -export default connect(select, perform)(DownloadingModal); +export default connect(select, perform)(ModalDownloading); diff --git a/ui/js/component/downloadingModal/view.jsx b/ui/js/component/modalDownloading/view.jsx similarity index 94% rename from ui/js/component/downloadingModal/view.jsx rename to ui/js/component/modalDownloading/view.jsx index 0bf612d7f..9b5bed354 100644 --- a/ui/js/component/downloadingModal/view.jsx +++ b/ui/js/component/modalDownloading/view.jsx @@ -3,7 +3,7 @@ import { Modal } from "component/modal"; import { Line } from "rc-progress"; import Link from "component/link"; -class DownloadingModal extends React.PureComponent { +class ModalDownloading extends React.PureComponent { render() { const { downloadProgress, @@ -59,4 +59,4 @@ class DownloadingModal extends React.PureComponent { } } -export default DownloadingModal; +export default ModalDownloading; diff --git a/ui/js/component/errorModal/index.jsx b/ui/js/component/modalError/index.js similarity index 81% rename from ui/js/component/errorModal/index.jsx rename to ui/js/component/modalError/index.js index dadbe3eb5..47680ecc9 100644 --- a/ui/js/component/errorModal/index.jsx +++ b/ui/js/component/modalError/index.js @@ -2,7 +2,7 @@ import React from "react"; import { connect } from "react-redux"; import { selectCurrentModal, selectModalExtraContent } from "selectors/app"; import { doCloseModal } from "actions/app"; -import ErrorModal from "./view"; +import ModalError from "./view"; const select = state => ({ modal: selectCurrentModal(state), @@ -13,4 +13,4 @@ const perform = dispatch => ({ closeModal: () => dispatch(doCloseModal()), }); -export default connect(select, perform)(ErrorModal); +export default connect(select, perform)(ModalError); diff --git a/ui/js/component/errorModal/view.jsx b/ui/js/component/modalError/view.jsx similarity index 95% rename from ui/js/component/errorModal/view.jsx rename to ui/js/component/modalError/view.jsx index 57bfe19dc..8090c4282 100644 --- a/ui/js/component/errorModal/view.jsx +++ b/ui/js/component/modalError/view.jsx @@ -2,7 +2,7 @@ import React from "react"; import lbry from "lbry"; import { ExpandableModal } from "component/modal"; -class ErrorModal extends React.PureComponent { +class ModalError extends React.PureComponent { render() { const { modal, closeModal, error } = this.props; @@ -60,4 +60,4 @@ class ErrorModal extends React.PureComponent { } } -export default ErrorModal; +export default ModalError; diff --git a/ui/js/component/modalRemoveFile/index.js b/ui/js/component/modalRemoveFile/index.js new file mode 100644 index 000000000..de54514d5 --- /dev/null +++ b/ui/js/component/modalRemoveFile/index.js @@ -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); diff --git a/ui/js/component/modalRemoveFile/view.jsx b/ui/js/component/modalRemoveFile/view.jsx new file mode 100644 index 000000000..02a58d0c2 --- /dev/null +++ b/ui/js/component/modalRemoveFile/view.jsx @@ -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 ( + + deleteFile(outpoint, deleteChecked, abandonClaimChecked)} + onAborted={closeModal} + > +

+ {__("Are you sure you'd like to remove")} {title}{" "} + {__("from LBRY?")} +

+ +
+ +
+ {claimIsMine && +
+ +
} +
+ ); + } +} + +export default ModalRemoveFile; diff --git a/ui/js/component/upgradeModal/index.jsx b/ui/js/component/modalUpgrade/index.js similarity index 77% rename from ui/js/component/upgradeModal/index.jsx rename to ui/js/component/modalUpgrade/index.js index f30266554..ae4d815c7 100644 --- a/ui/js/component/upgradeModal/index.jsx +++ b/ui/js/component/modalUpgrade/index.js @@ -1,7 +1,7 @@ import React from "react"; import { connect } from "react-redux"; import { doDownloadUpgrade, doSkipUpgrade } from "actions/app"; -import UpgradeModal from "./view"; +import ModalUpgrade from "./view"; const select = state => ({}); @@ -10,4 +10,4 @@ const perform = dispatch => ({ skipUpgrade: () => dispatch(doSkipUpgrade()), }); -export default connect(select, perform)(UpgradeModal); +export default connect(select, perform)(ModalUpgrade); diff --git a/ui/js/component/upgradeModal/view.jsx b/ui/js/component/modalUpgrade/view.jsx similarity index 88% rename from ui/js/component/upgradeModal/view.jsx rename to ui/js/component/modalUpgrade/view.jsx index 37df28c4b..544fd96b7 100644 --- a/ui/js/component/upgradeModal/view.jsx +++ b/ui/js/component/modalUpgrade/view.jsx @@ -2,7 +2,7 @@ import React from "react"; import { Modal } from "component/modal"; import { downloadUpgrade, skipUpgrade } from "actions/app"; -class UpgradeModal extends React.PureComponent { +class ModalUpgrade extends React.PureComponent { render() { const { downloadUpgrade, skipUpgrade } = this.props; @@ -24,4 +24,4 @@ class UpgradeModal extends React.PureComponent { } } -export default UpgradeModal; +export default ModalUpgrade; diff --git a/ui/js/component/welcomeModal/index.jsx b/ui/js/component/modalWelcome/index.js similarity index 100% rename from ui/js/component/welcomeModal/index.jsx rename to ui/js/component/modalWelcome/index.js diff --git a/ui/js/component/welcomeModal/view.jsx b/ui/js/component/modalWelcome/view.jsx similarity index 100% rename from ui/js/component/welcomeModal/view.jsx rename to ui/js/component/modalWelcome/view.jsx diff --git a/ui/js/constants/modal_types.js b/ui/js/constants/modal_types.js index b34bb9afb..787dabaaf 100644 --- a/ui/js/constants/modal_types.js +++ b/ui/js/constants/modal_types.js @@ -1 +1,2 @@ export const WELCOME = "welcome"; +export const CONFIRM_FILE_REMOVE = "confirmFileRemove"; From 2cc24318c10512d665b66c67d5947f84ab7036f1 Mon Sep 17 00:00:00 2001 From: 6ea86b96 <6ea86b96@gmail.com> Date: Mon, 3 Jul 2017 13:54:03 +0700 Subject: [PATCH 10/11] Stop progress bar code blowing up if window is defocused before download starts --- ui/js/util/setProgressBar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/js/util/setProgressBar.js b/ui/js/util/setProgressBar.js index 304a54f17..b5d869f3d 100644 --- a/ui/js/util/setProgressBar.js +++ b/ui/js/util/setProgressBar.js @@ -1,6 +1,6 @@ const { remote } = require("electron"); const application = remote.app; -const win = remote.BrowserWindow.getFocusedWindow(); +const win = remote.getCurrentWindow(); const setProgressBar = progress => { win.setProgressBar(progress); From 48c10b6c53a937b2aa2a90708acf662efce9ed3d Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Tue, 4 Jul 2017 13:06:09 -0400 Subject: [PATCH 11/11] update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c6a2184e..9c1829aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Web UI version numbers should always match the corresponding version of LBRY App ## [Unreleased] ### Added - * + * Added option to release claim when deleting a file * ### Changed @@ -16,7 +16,7 @@ Web UI version numbers should always match the corresponding version of LBRY App * ### Fixed - * + * Fixed bug with download notice when switching window focus * ### Deprecated