Add option to abandon claim when deleting published file
This commit is contained in:
parent
1dea560cdf
commit
91359c2966
7 changed files with 136 additions and 31 deletions
|
@ -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());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
doOpenFileInFolder,
|
doOpenFileInFolder,
|
||||||
doDeleteFile,
|
doDeleteFile,
|
||||||
} from "actions/file_info";
|
} from "actions/file_info";
|
||||||
|
import { makeSelectClaimForUriIsMine } from "selectors/claims";
|
||||||
import { doPurchaseUri, doLoadVideo } from "actions/content";
|
import { doPurchaseUri, doLoadVideo } from "actions/content";
|
||||||
import FileActions from "./view";
|
import FileActions from "./view";
|
||||||
|
|
||||||
|
@ -25,6 +26,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 +37,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,9 +48,9 @@ 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) => {
|
deleteFile: (fileInfo, deleteFromComputer, abandonClaim) => {
|
||||||
dispatch(doHistoryBack());
|
dispatch(doHistoryBack());
|
||||||
dispatch(doDeleteFile(fileInfo, deleteFromComputer));
|
dispatch(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim));
|
||||||
},
|
},
|
||||||
openModal: modal => dispatch(doOpenModal(modal)),
|
openModal: modal => dispatch(doOpenModal(modal)),
|
||||||
startDownload: uri => dispatch(doPurchaseUri(uri, "affirmPurchase")),
|
startDownload: uri => dispatch(doPurchaseUri(uri, "affirmPurchase")),
|
||||||
|
|
|
@ -13,6 +13,7 @@ class FileActions extends React.PureComponent {
|
||||||
this.state = {
|
this.state = {
|
||||||
forceShowActions: false,
|
forceShowActions: false,
|
||||||
deleteChecked: false,
|
deleteChecked: false,
|
||||||
|
abandonClaimChecked: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +44,12 @@ class FileActions extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleAbandonClaimCheckboxClicked(event) {
|
||||||
|
this.setState({
|
||||||
|
abandonClaimChecked: event.target.checked,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onAffirmPurchase() {
|
onAffirmPurchase() {
|
||||||
this.props.closeModal();
|
this.props.closeModal();
|
||||||
this.props.loadVideo(this.props.uri);
|
this.props.loadVideo(this.props.uri);
|
||||||
|
@ -64,9 +71,11 @@ class FileActions extends React.PureComponent {
|
||||||
startDownload,
|
startDownload,
|
||||||
costInfo,
|
costInfo,
|
||||||
loading,
|
loading,
|
||||||
|
claimIsMine,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const deleteChecked = this.state.deleteChecked,
|
const deleteChecked = this.state.deleteChecked,
|
||||||
|
abandonClaimChecked = this.state.abandonClaimChecked,
|
||||||
metadata = fileInfo ? fileInfo.metadata : null,
|
metadata = fileInfo ? fileInfo.metadata : null,
|
||||||
openInFolderMessage = platform.startsWith("Mac")
|
openInFolderMessage = platform.startsWith("Mac")
|
||||||
? __("Open in Finder")
|
? __("Open in Finder")
|
||||||
|
@ -77,15 +86,19 @@ class FileActions extends React.PureComponent {
|
||||||
let content;
|
let content;
|
||||||
|
|
||||||
if (loading || downloading) {
|
if (loading || downloading) {
|
||||||
const progress = fileInfo && fileInfo.written_bytes
|
const progress =
|
||||||
? fileInfo.written_bytes / fileInfo.total_bytes * 100
|
fileInfo && fileInfo.written_bytes
|
||||||
: 0,
|
? fileInfo.written_bytes / fileInfo.total_bytes * 100
|
||||||
|
: 0,
|
||||||
label = fileInfo
|
label = fileInfo
|
||||||
? progress.toFixed(0) + __("% complete")
|
? progress.toFixed(0) + __("% complete")
|
||||||
: __("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>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -174,9 +187,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"}
|
||||||
|
@ -197,22 +212,36 @@ class FileActions extends React.PureComponent {
|
||||||
contentLabel={__("Not enough credits")}
|
contentLabel={__("Not enough credits")}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__("Remove")}
|
confirmButtonLabel={__("Remove")}
|
||||||
onConfirmed={() => deleteFile(fileInfo.outpoint, deleteChecked)}
|
onConfirmed={() =>
|
||||||
|
deleteFile(fileInfo.outpoint, deleteChecked, abandonClaimChecked)}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
{__("Are you sure you'd like to remove")} <cite>{title}</cite>
|
{__("Are you sure you'd like to remove")} <cite>{title}</cite>{" "}
|
||||||
{" "}{__("from LBRY?")}
|
{__("from LBRY?")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<label>
|
<section>
|
||||||
<FormField
|
<label>
|
||||||
type="checkbox"
|
<FormField
|
||||||
checked={deleteChecked}
|
type="checkbox"
|
||||||
onClick={this.handleDeleteCheckboxClicked.bind(this)}
|
checked={deleteChecked}
|
||||||
/>
|
onClick={this.handleDeleteCheckboxClicked.bind(this)}
|
||||||
{" "}{__("Delete this file from my computer")}
|
/>{" "}
|
||||||
</label>
|
{__("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>
|
</Modal>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -268,9 +268,10 @@ lbry.getClientSettings = function() {
|
||||||
var outSettings = {};
|
var outSettings = {};
|
||||||
for (let setting of Object.keys(lbry.defaultClientSettings)) {
|
for (let setting of Object.keys(lbry.defaultClientSettings)) {
|
||||||
var localStorageVal = localStorage.getItem("setting_" + setting);
|
var localStorageVal = localStorage.getItem("setting_" + setting);
|
||||||
outSettings[setting] = localStorageVal === null
|
outSettings[setting] =
|
||||||
? lbry.defaultClientSettings[setting]
|
localStorageVal === null
|
||||||
: JSON.parse(localStorageVal);
|
? lbry.defaultClientSettings[setting]
|
||||||
|
: JSON.parse(localStorageVal);
|
||||||
}
|
}
|
||||||
return outSettings;
|
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._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(
|
||||||
|
|
Loading…
Reference in a new issue