improve pop up not identifying your own content in some cases

edit option

delete option

analytics for channel claim

support option

follow option

fix

revert

subscription actions

block actions

mute actions

block and mute buttons

mute menu option

lint

handle edit channel

fix comment mute

logic

analytics

handle delete channel

fix claimismine

fix rebase
This commit is contained in:
Thomas Zarebczan 2021-06-08 15:36:58 -04:00 committed by zeppi
parent 8f423c5ffb
commit 7d3f35b0c5
16 changed files with 331 additions and 129 deletions

View file

@ -6,8 +6,8 @@ type Props = {
uri: string,
isBlocked: boolean,
isBlockingOrUnBlocking: boolean,
doCommentModUnBlock: (string) => void,
doCommentModBlock: (string) => void,
doCommentModUnBlock: (string, boolean) => void,
doCommentModBlock: (string, boolean) => void,
};
function ChannelBlockButton(props: Props) {
@ -15,9 +15,9 @@ function ChannelBlockButton(props: Props) {
function handleClick() {
if (isBlocked) {
doCommentModUnBlock(uri);
doCommentModUnBlock(uri, false);
} else {
doCommentModBlock(uri);
doCommentModBlock(uri, false);
}
}
@ -30,8 +30,8 @@ function ChannelBlockButton(props: Props) {
? __('Unblocking...')
: __('Unblock')
: isBlockingOrUnBlocking
? __('Blocking...')
: __('Block')
? __('Blocking...')
: __('Block')
}
onClick={handleClick}
/>

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { doToggleMuteChannel } from 'redux/actions/blocked';
import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked';
import { makeSelectChannelIsMuted } from 'redux/selectors/blocked';
import ChannelMuteButton from './view';
@ -8,5 +8,6 @@ const select = (state, props) => ({
});
export default connect(select, {
doToggleMuteChannel,
doChannelMute,
doChannelUnmute,
})(ChannelMuteButton);

View file

@ -6,17 +6,26 @@ type Props = {
uri: string,
isMuted: boolean,
channelClaim: ?ChannelClaim,
doToggleMuteChannel: (string) => void,
doChannelMute: (string, boolean) => void,
doChannelUnmute: (string, boolean) => void,
};
function ChannelBlockButton(props: Props) {
const { uri, doToggleMuteChannel, isMuted } = props;
const { uri, doChannelMute, doChannelUnmute, isMuted } = props;
function handleClick() {
if (isMuted) {
doChannelUnmute(uri, false);
} else {
doChannelMute(uri, false);
}
}
return (
<Button
button={isMuted ? 'alt' : 'secondary'}
label={isMuted ? __('Unmute') : __('Mute')}
onClick={() => doToggleMuteChannel(uri)}
onClick={handleClick}
/>
);
}

View file

@ -44,7 +44,6 @@ type Props = {
liveLivestreamsFirst?: boolean,
livestreamMap?: { [string]: any },
searchOptions?: any,
channelIsMine: boolean,
collectionId?: string,
};
@ -76,7 +75,6 @@ export default function ClaimList(props: Props) {
liveLivestreamsFirst,
livestreamMap,
searchOptions,
channelIsMine,
collectionId,
} = props;
@ -136,7 +134,6 @@ export default function ClaimList(props: Props) {
showHiddenByUser={showHiddenByUser}
properties={renderProperties}
live={resolveLive(index)}
channelIsMine={channelIsMine}
collectionId={collectionId}
/>
))}

View file

@ -73,7 +73,6 @@ type Props = {
livestreamMap?: { [string]: any },
hasSource?: boolean,
isChannel?: boolean,
channelIsMine?: boolean,
};
function ClaimListDiscover(props: Props) {
@ -129,7 +128,6 @@ function ClaimListDiscover(props: Props) {
livestreamMap,
hasSource,
isChannel = false,
channelIsMine = false,
} = props;
const didNavigateForward = history.action === 'PUSH';
const { search } = location;
@ -512,7 +510,6 @@ function ClaimListDiscover(props: Props) {
liveLivestreamsFirst={liveLivestreamsFirst}
livestreamMap={livestreamMap}
searchOptions={options}
channelIsMine={channelIsMine}
/>
{loading && (
<div className="claim-grid">

View file

@ -7,16 +7,23 @@ import {
makeSelectNameForCollectionId,
makeSelectCollectionIsMine,
COLLECTIONS_CONSTS,
makeSelectFileInfoForUri,
doPrepareEdit,
} from 'lbry-redux';
import { makeSelectChannelIsMuted } from 'redux/selectors/blocked';
import { doToggleMuteChannel } from 'redux/actions/blocked';
import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked';
import { doSetActiveChannel, doSetIncognito, doOpenModal } from 'redux/actions/app';
import { doCommentModBlock, doCommentModUnBlock } from 'redux/actions/comments';
import { makeSelectChannelIsBlocked } from 'redux/selectors/comments';
import { doOpenModal } from 'redux/actions/app';
import { doToast } from 'redux/actions/notifications';
import { makeSelectUserPropForProp } from 'redux/selectors/user';
import { makeSelectSigningIsMine } from 'redux/selectors/content';
import { doChannelSubscribe, doChannelUnsubscribe } from 'redux/actions/subscriptions';
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
import ClaimPreview from './view';
import * as USER from 'constants/user';
import fs from 'fs';
const select = (state, props) => {
const claim = makeSelectClaimForUri(props.uri)(state);
@ -35,14 +42,31 @@ const select = (state, props) => {
collectionName: makeSelectNameForCollectionId(props.collectionId)(state),
isMyCollection: makeSelectCollectionIsMine(props.collectionId)(state),
hasExperimentalUi: makeSelectUserPropForProp(USER.EXPERIMENTAL_UI)(state),
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
isSubscribed: makeSelectIsSubscribed(props.channelUri, true)(state),
};
};
export default connect(select, {
doToggleMuteChannel,
doCommentModBlock,
doCommentModUnBlock,
doCollectionEdit,
doOpenModal,
doToast,
})(ClaimPreview);
const perform = (dispatch) => ({
prepareEdit: (publishData, uri, fileInfo) => {
if (publishData.signing_channel) {
dispatch(doSetIncognito(false));
dispatch(doSetActiveChannel(publishData.signing_channel.claim_id));
} else {
dispatch(doSetIncognito(true));
}
dispatch(doPrepareEdit(publishData, uri, fileInfo, fs));
},
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
doChannelMute: (channelUri) => dispatch(doChannelMute(channelUri)),
doChannelUnmute: (channelUri) => dispatch(doChannelUnmute(channelUri)),
doCommentModBlock: (channelUri) => dispatch(doCommentModBlock(channelUri)),
doCommentModUnBlock: (channelUri) => dispatch(doCommentModUnBlock(channelUri)),
doChannelSubscribe: (subscription) => dispatch(doChannelSubscribe(subscription)),
doChannelUnsubscribe: (subscription) => dispatch(doChannelUnsubscribe(subscription)),
doCollectionEdit: (id, params) => dispatch(doCollectionEdit(id, params)),
doToast: (params) => dispatch(doToast(params)),
});
export default connect(select, perform)(ClaimPreview);

View file

@ -10,54 +10,81 @@ import Icon from 'component/common/icon';
import { generateShareUrl } from 'util/url';
import { useHistory } from 'react-router';
import { COLLECTIONS_CONSTS } from 'lbry-redux';
import { buildURI, parseURI } from 'lbry-redux';
const SHARE_DOMAIN = SHARE_DOMAIN_URL || URL;
const PAGE_VIEW_QUERY = `view`;
const EDIT_PAGE = 'edit';
type SubscriptionArgs = {
channelName: string,
uri: string,
notificationsDisabled?: boolean,
};
type Props = {
uri: string,
channelUri: string,
claim: ?Claim,
openModal: (id: string, {}) => void,
inline?: boolean,
claimIsMine: boolean,
channelIsMuted: boolean,
channelIsBlocked: boolean,
doToggleMuteChannel: (string) => void,
doChannelMute: (string) => void,
doChannelUnmute: (string) => void,
doCommentModBlock: (string) => void,
doCommentModUnBlock: (string) => void,
channelIsMine: boolean,
isRepost: boolean,
doCollectionEdit: (string, any) => void,
hasClaimInWatchLater: boolean,
doOpenModal: (string, {}) => void,
claimInCollection: boolean,
collectionName?: string,
collectionId: string,
isMyCollection: boolean,
doToast: ({ message: string }) => void,
hasExperimentalUi: boolean,
claimIsMine: boolean,
fileInfo: FileListItem,
prepareEdit: ({}, string, {}) => void,
isSubscribed: boolean,
doChannelSubscribe: (SubscriptionArgs) => void,
doChannelUnsubscribe: (SubscriptionArgs) => void,
};
function ClaimMenuList(props: Props) {
const {
uri,
channelUri,
claim,
openModal,
inline = false,
claimIsMine,
doToggleMuteChannel,
doChannelMute,
doChannelUnmute,
channelIsMuted,
channelIsBlocked,
doCommentModBlock,
doCommentModUnBlock,
doCollectionEdit,
hasClaimInWatchLater,
doOpenModal,
collectionId,
collectionName,
isMyCollection,
doToast,
hasExperimentalUi,
claimIsMine,
fileInfo,
prepareEdit,
isSubscribed,
doChannelSubscribe,
doChannelUnsubscribe,
} = props;
const incognito = channelUri && !(channelUri.includes('@'));
const signingChannel = claim && (claim.signing_channel || claim);
const isChannel = !incognito && signingChannel === claim;
const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0));
const subscriptionLabel = isSubscribed ? __('Unfollow') : __('Follow');
const { push } = useHistory();
const { push, replace } = useHistory();
if (!claim) {
return null;
}
@ -78,8 +105,28 @@ function ClaimMenuList(props: Props) {
// $FlowFixMe
(claim.value.stream_type === 'audio' || claim.value.stream_type === 'video');
function handleFollow() {
const permanentUrl = signingChannel && signingChannel.permanent_url;
const { channelName } = parseURI(permanentUrl);
const subscriptionHandler = isSubscribed ? doChannelUnsubscribe : doChannelSubscribe;
subscriptionHandler({
channelName: '@' + channelName,
uri: permanentUrl,
notificationsDisabled: true,
});
}
function handleAnalytics() {
push(`/$/${PAGES.CREATOR_DASHBOARD}?channel=${encodeURIComponent(signingChannel.canonical_url)}`);
}
function handleToggleMute() {
doToggleMuteChannel(channelUri);
if (channelIsMuted) {
doChannelUnmute(channelUri);
} else {
doChannelMute(channelUri);
}
}
function handleToggleBlock() {
@ -90,6 +137,40 @@ function ClaimMenuList(props: Props) {
}
}
function handleEdit() {
if (!isChannel) {
const signingChannelName = signingChannel && signingChannel.name;
let editUri;
const uriObject: { streamName: string, streamClaimId: string, channelName?: string } = {
streamName: claim.name,
streamClaimId: claim.claim_id,
};
if (signingChannelName) {
uriObject.channelName = signingChannelName;
}
editUri = buildURI(uriObject);
push(`/$/${PAGES.UPLOAD}`);
prepareEdit(claim, editUri, fileInfo);
} else {
const channelUrl = claim.name + ':' + claim.claim_id;
push(`/${channelUrl}?${PAGE_VIEW_QUERY}=${EDIT_PAGE}`);
}
}
function handleDelete() {
if (!isChannel) {
openModal(MODALS.CONFIRM_FILE_REMOVE, { uri });
} else {
openModal(MODALS.CONFIRM_CLAIM_REVOKE, { claim: claim, cb: () => replace(`/$/${PAGES.CHANNELS}`) });
}
}
function handleSupport() {
openModal(MODALS.SEND_TIP, { uri, isSupport: true });
}
function handleCopyLink() {
navigator.clipboard.writeText(shareUrl);
}
@ -172,7 +253,29 @@ function ClaimMenuList(props: Props) {
</>
)}
<hr className="menu__separator" />
{channelUri && !claimIsMine && !isMyCollection && (
{!incognito && (!claimIsMine ? (
<MenuItem className="comment__menu-option" onSelect={handleFollow}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.SUBSCRIBE} />
{subscriptionLabel}
</div>
</MenuItem>
) : (
<MenuItem className="comment__menu-option" onSelect={handleAnalytics}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.ANALYTICS} />
{__('Channel Analytics')}
</div>
</MenuItem>
))}
<MenuItem className="comment__menu-option" onSelect={handleSupport}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.LBC} />
{__('Support')}
</div>
</MenuItem>
{channelUri && !claimIsMine && !isMyCollection && !incognito ? (
<>
<MenuItem className="comment__menu-option" onSelect={handleToggleBlock}>
<div className="menu__link">
@ -187,10 +290,27 @@ function ClaimMenuList(props: Props) {
{channelIsMuted ? __('Unmute Channel') : __('Mute Channel')}
</div>
</MenuItem>
</>
) : (
<>
<MenuItem className="comment__menu-option" onSelect={handleEdit}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.EDIT} />
{__('Edit')}
</div>
</MenuItem>
<hr className="menu__separator" />
{showDelete && (
<MenuItem className="comment__menu-option" onSelect={handleDelete}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.DELETE} />
{__('Delete')}
</div>
</MenuItem>
)}
</>
)}
<hr className="menu__separator" />
<MenuItem className="comment__menu-option" onSelect={handleCopyLink}>
<div className="menu__link">

View file

@ -30,7 +30,7 @@ import * as ICONS from 'constants/icons';
type Props = {
uri: string,
claim: ?Claim, // maybe?
claim: ?Claim,
obscureNsfw: boolean,
showUserBlocked: boolean,
claimIsMine: boolean,
@ -155,6 +155,8 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
const isCollection = claim && claim.value_type === 'collection';
const isChannelUri = isValid ? parseURI(uri).isChannel : false;
const signingChannel = claim && claim.signing_channel;
const channelUri = claim && (signingChannel ? signingChannel.permanent_url : claim.permanent_url);
let navigateUrl = formatLbryUrlForWeb((claim && claim.canonical_url) || uri || '/');
if (collectionId) {
const collectionParams = new URLSearchParams();
@ -421,7 +423,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
)}
</div>
</div>
{!hideMenu && <ClaimMenuList uri={uri} collectionId={collectionId} />}
{!hideMenu && <ClaimMenuList uri={uri} collectionId={collectionId} channelUri={channelUri} />}
</>
</WrapperElement>
);

View file

@ -43,7 +43,6 @@ type Props = {
showHiddenByUser?: boolean,
properties?: (Claim) => void,
live?: boolean,
channelIsMine?: boolean,
collectionId?: string,
};
@ -67,7 +66,6 @@ function ClaimPreviewTile(props: Props) {
showHiddenByUser,
properties,
live,
channelIsMine,
collectionId,
} = props;
const isRepost = claim && claim.repost_channel_url;
@ -100,11 +98,8 @@ function ClaimPreviewTile(props: Props) {
}
}
let channelUri;
const signingChannel = claim && claim.signing_channel;
if (signingChannel) {
channelUri = signingChannel.permanent_url;
}
const channelUri = signingChannel && signingChannel.permanent_url;
function handleClick(e) {
if (navigateUrl) {
@ -219,7 +214,7 @@ function ClaimPreviewTile(props: Props) {
</div>
)}
{/* CHECK CLAIM MENU LIST PARAMS (IS REPOST?) */}
<ClaimMenuList uri={uri} collectionId={listId} channelIsMine={channelIsMine} isRepost={isRepost} />
<ClaimMenuList uri={uri} collectionId={listId} channelUri={channelUri} isRepost={isRepost} />
</h2>
</NavLink>
<div>

View file

@ -1,7 +1,7 @@
import { connect } from 'react-redux';
import { makeSelectChannelPermUrlForClaimUri, makeSelectClaimIsMine, makeSelectClaimForUri } from 'lbry-redux';
import { doCommentAbandon, doCommentPin, doCommentList, doCommentModBlock } from 'redux/actions/comments';
import { doToggleMuteChannel } from 'redux/actions/blocked';
import { doChannelMute } from 'redux/actions/blocked';
// import { doSetActiveChannel } from 'redux/actions/app';
import { doSetPlayingUri } from 'redux/actions/content';
import { selectActiveChannelClaim } from 'redux/selectors/app';
@ -19,7 +19,7 @@ const select = (state, props) => ({
const perform = (dispatch) => ({
clearPlayingUri: () => dispatch(doSetPlayingUri({ uri: null })),
deleteComment: (commentId, creatorChannelUrl) => dispatch(doCommentAbandon(commentId, creatorChannelUrl)),
blockChannel: (channelUri) => dispatch(doToggleMuteChannel(channelUri)),
muteChannel: (channelUri) => dispatch(doChannelMute(channelUri)),
pinComment: (commentId, remove) => dispatch(doCommentPin(commentId, remove)),
fetchComments: (uri) => dispatch(doCommentList(uri)),
// setActiveChannel: channelId => dispatch(doSetActiveChannel(channelId)),

View file

@ -15,7 +15,7 @@ type Props = {
linkedComment?: any,
isPinned: boolean,
pinComment: (string, boolean) => Promise<any>,
blockChannel: (string) => void,
muteChannel: (string) => void,
fetchComments: (string) => void,
handleEditComment: () => void,
contentChannelPermanentUrl: any,
@ -34,7 +34,7 @@ function CommentMenuList(props: Props) {
commentIsMine,
commentId,
deleteComment,
blockChannel,
muteChannel,
pinComment,
clearPlayingUri,
activeChannelClaim,
@ -66,7 +66,7 @@ function CommentMenuList(props: Props) {
}
function handleCommentMute() {
blockChannel(authorUri);
muteChannel(authorUri);
}
return (

View file

@ -186,7 +186,7 @@ function ChannelPage(props: Props) {
{!(isBlocked || isMuted) && <ClaimSupportButton uri={uri} />}
{!(isBlocked || isMuted) && (!channelIsBlackListed || isSubscribed) && <SubscribeButton uri={permanentUrl} />}
{/* TODO: add channel collections <ClaimCollectionAddButton uri={uri} fileAction /> */}
<ClaimMenuList uri={claim.permanent_url} inline />
<ClaimMenuList uri={claim.permanent_url} channelUri={claim.permanent_url} inline />
</div>
{cover && <img className={classnames('channel-cover__custom')} src={cover} />}
<div className="channel__primary-info">

View file

@ -2,19 +2,40 @@
import * as ACTIONS from 'constants/action_types';
import { selectPrefsReady } from 'redux/selectors/sync';
import { doAlertWaitingForSync } from 'redux/actions/app';
import { doToast } from 'redux/actions/notifications';
export const doToggleMuteChannel = (uri: string) => (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const ready = selectPrefsReady(state);
export function doToggleMuteChannel(uri: string, showLink: boolean, unmute: boolean = false) {
return async (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const ready = selectPrefsReady(state);
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
dispatch({
type: ACTIONS.TOGGLE_BLOCK_CHANNEL,
data: {
uri,
},
});
};
dispatch({
type: ACTIONS.TOGGLE_BLOCK_CHANNEL,
data: {
uri,
},
});
dispatch(doToast({
message: __(!unmute ? 'Channel muted. You will not see them again.' : 'Channel unmuted!'),
linkText: __(showLink ? 'See All' : ''),
linkTarget: '/settings/block_and_mute',
}));
};
}
export function doChannelMute(uri: string, showLink: boolean = true) {
return (dispatch: Dispatch) => {
return dispatch(doToggleMuteChannel(uri, showLink));
};
}
export function doChannelUnmute(uri: string, showLink: boolean = true) {
return (dispatch: Dispatch) => {
return dispatch(doToggleMuteChannel(uri, showLink, true));
};
}

View file

@ -506,7 +506,7 @@ async function channelSignName(channelClaimId: string, channelName: string) {
}
// Hides a users comments from all creator's claims and prevent them from commenting in the future
export function doCommentModToggleBlock(channelUri: string, unblock: boolean = false) {
export function doCommentModToggleBlock(channelUri: string, showLink: boolean, unblock: boolean = false) {
return async (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const myChannels = selectMyChannelClaims(state);
@ -564,9 +564,15 @@ export function doCommentModToggleBlock(channelUri: string, unblock: boolean = f
data: { channelUri },
});
if (!unblock) {
dispatch(doToast({ message: __('Channel blocked. You will not see them again.') }));
}
dispatch(
doToast({
message: __(
!unblock ? 'Channel blocked. They will not interact with you again.' : 'Channel unblocked!'
),
linkText: __(showLink ? 'See All' : ''),
linkTarget: '/settings/block_and_mute',
})
);
})
.catch(() => {
dispatch({
@ -582,15 +588,15 @@ export function doCommentModToggleBlock(channelUri: string, unblock: boolean = f
};
}
export function doCommentModBlock(commentAuthor: string) {
export function doCommentModBlock(commentAuthor: string, showLink: boolean = true) {
return (dispatch: Dispatch) => {
return dispatch(doCommentModToggleBlock(commentAuthor));
return dispatch(doCommentModToggleBlock(commentAuthor, showLink));
};
}
export function doCommentModUnBlock(commentAuthor: string) {
export function doCommentModUnBlock(commentAuthor: string, showLink: boolean = true) {
return (dispatch: Dispatch) => {
return dispatch(doCommentModToggleBlock(commentAuthor, true));
return dispatch(doCommentModToggleBlock(commentAuthor, showLink, true));
};
}

View file

@ -1,69 +1,78 @@
// @flow
import * as ACTIONS from 'constants/action_types';
import REWARDS from 'rewards';
import { Lbryio } from 'lbryinc';
import { doClaimRewardType } from 'redux/actions/rewards';
import { parseURI } from 'lbry-redux';
import { doAlertWaitingForSync } from 'redux/actions/app';
import { doToast } from 'redux/actions/notifications';
export const doChannelSubscribe = subscription => (dispatch, getState) => {
const {
settings: { daemonSettings },
sync: { prefsReady: ready },
} = getState();
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
const { share_usage_data: shareSetting } = daemonSettings;
const isSharingData = shareSetting || IS_WEB;
const subscriptionUri = subscription.uri;
if (!subscriptionUri.startsWith('lbry://')) {
throw Error(`Subscription uris must include the "lbry://" prefix.\nTried to subscribe to ${subscriptionUri}`);
}
dispatch({
type: ACTIONS.CHANNEL_SUBSCRIBE,
data: subscription,
});
// if the user isn't sharing data, keep the subscriptions entirely in the app
if (isSharingData || IS_WEB) {
const { channelClaimId } = parseURI(subscription.uri);
// They are sharing data, we can store their subscriptions in our internal database
Lbryio.call('subscription', 'new', {
channel_name: subscription.channelName,
claim_id: channelClaimId,
notifications_disabled: subscription.notificationsDisabled,
});
dispatch(doClaimRewardType(REWARDS.TYPE_SUBSCRIPTION, { failSilently: true }));
}
type SubscriptionArgs = {
channelName: string,
uri: string,
notificationsDisabled?: boolean,
};
export const doChannelUnsubscribe = subscription => (dispatch, getState) => {
const {
settings: { daemonSettings },
sync: { prefsReady: ready },
} = getState();
export function doToggleSubscription(subscription: SubscriptionArgs, isSubscribed: boolean = false) {
return async (dispatch: Dispatch, getState: GetState) => {
const {
settings: { daemonSettings },
sync: { prefsReady: ready },
} = getState();
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
if (!ready) {
return dispatch(doAlertWaitingForSync());
}
const { share_usage_data: shareSetting } = daemonSettings;
const isSharingData = shareSetting || IS_WEB;
const { share_usage_data: shareSetting } = daemonSettings;
const isSharingData = shareSetting || IS_WEB;
dispatch({
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
data: subscription,
});
if (!isSubscribed) {
const subscriptionUri = subscription.uri;
if (!subscriptionUri.startsWith('lbry://')) {
throw Error(`Subscription uris must include the "lbry://" prefix.\nTried to subscribe to ${subscriptionUri}`);
}
}
if (isSharingData) {
const { channelClaimId } = parseURI(subscription.uri);
Lbryio.call('subscription', 'delete', {
claim_id: channelClaimId,
dispatch({
type: !isSubscribed ? ACTIONS.CHANNEL_SUBSCRIBE : ACTIONS.CHANNEL_UNSUBSCRIBE,
data: subscription,
});
}
};
// if the user isn't sharing data, keep the subscriptions entirely in the app
if (isSharingData || IS_WEB) {
const { channelClaimId } = parseURI(subscription.uri);
if (!isSubscribed) {
// They are sharing data, we can store their subscriptions in our internal database
Lbryio.call('subscription', 'new', {
channel_name: subscription.channelName,
claim_id: channelClaimId,
notifications_disabled: subscription.notificationsDisabled,
});
dispatch(doClaimRewardType(REWARDS.TYPE_SUBSCRIPTION, { failSilently: true }));
} else {
Lbryio.call('subscription', 'delete', {
claim_id: channelClaimId,
});
}
}
dispatch(doToast({
message: __(!isSubscribed ? 'You followed %CHANNEL_NAME%!' : 'Unfollowed %CHANNEL_NAME%.', { CHANNEL_NAME: subscription.channelName }),
}));
};
}
export function doChannelSubscribe(subscription: SubscriptionArgs) {
return (dispatch: Dispatch) => {
return dispatch(doToggleSubscription(subscription));
};
}
export function doChannelUnsubscribe(subscription: SubscriptionArgs) {
return (dispatch: Dispatch) => {
return dispatch(doToggleSubscription(subscription, true));
};
}

View file

@ -11,6 +11,8 @@ import {
parseURI,
makeSelectContentTypeForUri,
makeSelectFileNameForUri,
normalizeURI,
selectMyActiveClaims,
} from 'lbry-redux';
import { makeSelectRecommendedContentForUri } from 'redux/selectors/search';
import { selectMutedChannels } from 'redux/selectors/blocked';
@ -243,3 +245,22 @@ export const makeSelectInsufficientCreditsForUri = (uri: string) =>
return !isMine && costInfo && costInfo.cost > 0 && costInfo.cost > balance;
}
);
export const makeSelectSigningIsMine = (rawUri: string) => {
let uri;
try {
uri = normalizeURI(rawUri);
} catch (e) { }
return createSelector(selectClaimsByUri, selectMyActiveClaims, (claims, myClaims) => {
try {
parseURI(uri);
} catch (e) {
return false;
}
const repostedChannel = claims && claims[uri] && claims[uri].reposted_claim && (claims[uri].reposted_claim.signing_channel || claims[uri].reposted_claim);
const signingChannel = claims && claims[uri] && (repostedChannel || claims[uri].signing_channel || claims[uri]);
return signingChannel && myClaims.has(signingChannel.claim_id);
});
};