Additional pop up menu options

This commit is contained in:
saltrafael 2021-06-11 17:49:18 -03:00 committed by jessopb
parent 524370711c
commit 2aaa9f358b
16 changed files with 336 additions and 150 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);
}
}

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,
empty?: string,
};
@ -130,7 +129,6 @@ function ClaimListDiscover(props: Props) {
livestreamMap,
hasSource,
isChannel = false,
channelIsMine = false,
empty,
} = props;
const didNavigateForward = history.action === 'PUSH';
@ -514,7 +512,6 @@ function ClaimListDiscover(props: Props) {
liveLivestreamsFirst={liveLivestreamsFirst}
livestreamMap={livestreamMap}
searchOptions={options}
channelIsMine={channelIsMine}
/>
{loading && (
<div className="claim-grid">

View file

@ -2,35 +2,38 @@ import { connect } from 'react-redux';
import {
doCollectionEdit,
makeSelectClaimForUri,
makeSelectClaimIsMine,
makeSelectFileInfoForUri,
doPrepareEdit,
makeSelectCollectionForIdHasClaimUrl,
makeSelectNameForCollectionId,
makeSelectCollectionIsMine,
COLLECTIONS_CONSTS,
} 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 ClaimPreview from './view';
import * as USER from 'constants/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 fs from 'fs';
const select = (state, props) => {
const claim = makeSelectClaimForUri(props.uri)(state);
const permanentUri = claim && claim.permanent_url;
return {
claim,
claimIsMine: props.channelIsMine
? props.isRepost
? makeSelectClaimIsMine(props.uri)(state)
: true
: makeSelectClaimIsMine(props.uri)(state),
claimIsMine: makeSelectSigningIsMine(props.uri)(state),
hasClaimInWatchLater: makeSelectCollectionForIdHasClaimUrl(COLLECTIONS_CONSTS.WATCH_LATER_ID, permanentUri)(state),
channelIsMuted: makeSelectChannelIsMuted(props.uri)(state),
channelIsBlocked: makeSelectChannelIsBlocked(props.uri)(state),
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
isSubscribed: makeSelectIsSubscribed(props.channelUri, true)(state),
claimInCollection: makeSelectCollectionForIdHasClaimUrl(props.collectionId, permanentUri)(state),
collectionName: makeSelectNameForCollectionId(props.collectionId)(state),
isMyCollection: makeSelectCollectionIsMine(props.collectionId)(state),
@ -38,11 +41,26 @@ const select = (state, props) => {
};
};
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));
},
doToast: (props) => dispatch(doToast(props)),
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: (collection, props) => dispatch(doCollectionEdit(collection, props)),
});
export default connect(select, perform)(ClaimPreview);

View file

@ -9,63 +9,84 @@ import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button';
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, COLLECTIONS_CONSTS } 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();
if (!claim) {
return null;
}
const channelUri = claim
? claim.value_type === 'channel'
? claim.permanent_url
: (claim.signing_channel && claim.signing_channel.permanent_url) || ''
: '';
const shareUrl: string = generateShareUrl(SHARE_DOMAIN, uri);
const isCollectionClaim = claim && claim.value_type === 'collection';
@ -78,8 +99,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 +131,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);
}
@ -110,6 +185,29 @@ function ClaimMenuList(props: Props) {
<Icon size={20} icon={ICONS.MORE_VERTICAL} />
</MenuButton>
<MenuList className="menu__list">
{!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>
{hasExperimentalUi && (
<>
{/* WATCH LATER */}
@ -148,7 +246,7 @@ function ClaimMenuList(props: Props) {
</MenuItem>
<MenuItem
className="comment__menu-option"
onSelect={() => doOpenModal(MODALS.COLLECTION_DELETE, { collectionId })}
onSelect={() => openModal(MODALS.COLLECTION_DELETE, { collectionId })}
>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.DELETE} />
@ -161,7 +259,7 @@ function ClaimMenuList(props: Props) {
{isPlayable && (
<MenuItem
className="comment__menu-option"
onSelect={() => doOpenModal(MODALS.COLLECTION_ADD, { uri, type: 'playlist' })}
onSelect={() => openModal(MODALS.COLLECTION_ADD, { uri, type: 'playlist' })}
>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.STACK} />
@ -169,10 +267,11 @@ function ClaimMenuList(props: Props) {
</div>
</MenuItem>
)}
<hr className="menu__separator" />
</>
)}
<hr className="menu__separator" />
{channelUri && !claimIsMine && !isMyCollection && (
{channelUri && !claimIsMine && !isMyCollection ? !incognito && (
<>
<MenuItem className="comment__menu-option" onSelect={handleToggleBlock}>
<div className="menu__link">
@ -187,10 +286,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

@ -161,6 +161,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId);
navigateUrl = navigateUrl + `?` + collectionParams.toString();
}
const channelUri = claim && (signingChannel ? signingChannel.permanent_url : claim.permanent_url);
const navLinkProps = {
to: navigateUrl,
onClick: (e) => e.stopPropagation(),
@ -421,7 +422,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

@ -191,8 +191,7 @@ function ChannelPage(props: Props) {
{!channelIsBlackListed && <ShareButton uri={uri} />}
{!(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,8 +2,10 @@
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) => {
export function doToggleMuteChannel(uri: string, showLink: boolean, unmute: boolean = false) {
return async (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const ready = selectPrefsReady(state);
@ -17,4 +19,23 @@ export const doToggleMuteChannel = (uri: string) => (dispatch: Dispatch, getStat
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,11 @@ 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 +584,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,11 +1,20 @@
// @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) => {
type SubscriptionArgs = {
channelName: string,
uri: string,
notificationsDisabled?: boolean,
};
export function doToggleSubscription(subscription: SubscriptionArgs, isSubscribed: boolean = false) {
return async (dispatch: Dispatch, getState: GetState) => {
const {
settings: { daemonSettings },
sync: { prefsReady: ready },
@ -18,19 +27,23 @@ export const doChannelSubscribe = subscription => (dispatch, getState) => {
const { share_usage_data: shareSetting } = daemonSettings;
const isSharingData = shareSetting || IS_WEB;
if (!isSubscribed) {
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,
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,
@ -39,31 +52,27 @@ export const doChannelSubscribe = subscription => (dispatch, getState) => {
});
dispatch(doClaimRewardType(REWARDS.TYPE_SUBSCRIPTION, { failSilently: true }));
}
};
export const doChannelUnsubscribe = 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;
dispatch({
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
data: subscription,
});
if (isSharingData) {
const { channelClaimId } = parseURI(subscription.uri);
} 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);
});
};