make standardized menu, use them in ConversationHeader

and ConversationListItem
This commit is contained in:
Audric Ackermann 2020-07-24 16:38:03 +10:00
parent 8910be2ceb
commit 401c37c39e
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4
5 changed files with 471 additions and 229 deletions

View File

@ -608,6 +608,7 @@
},
isOnline: this.isOnline(),
hasNickname: !!this.getNickname(),
isKickedFromGroup: !!this.get('isKickedFromGroup'),
selectedMessages: this.selectedMessages,
@ -620,6 +621,9 @@
onDeleteContact: () => this.deleteContact(),
onDeleteMessages: () => this.deleteMessages(),
onCloseOverlay: () => this.resetMessageSelection(),
onInviteContacts: () => {
window.Whisper.events.trigger('inviteContacts', this);
},
};
return result;

View File

@ -12,10 +12,12 @@ import { TypingAnimation } from './conversation/TypingAnimation';
import { Colors, LocalizerType } from '../types/Util';
import {
showClearNickname,
showBlock,
showCopyId,
showDeleteContact,
getBlockMenuItem,
getClearNicknameMenuItem,
getCopyIdMenuItem,
getDeleteContactMenuItem,
getInviteContactMenuItem,
getLeaveGroupMenuItem,
} from '../session/utils/Menu';
export type PropsData = {
@ -49,6 +51,7 @@ export type PropsData = {
hasNickname?: boolean;
isSecondary?: boolean;
isGroupInvitation?: boolean;
isKickedFromGroup?: boolean;
};
type PropsHousekeeping = {
@ -62,6 +65,7 @@ type PropsHousekeeping = {
onClearNickname?: () => void;
onCopyPublicKey?: () => void;
onUnblockContact?: () => void;
onInviteContacts?: () => void;
};
type Props = PropsData & PropsHousekeeping;
@ -170,53 +174,72 @@ export class ConversationListItem extends React.PureComponent<Props> {
isPublic,
hasNickname,
type,
isKickedFromGroup,
onDeleteContact,
onDeleteMessages,
onBlockContact,
onChangeNickname,
onClearNickname,
onCopyPublicKey,
onUnblockContact,
onInviteContacts,
} = this.props;
const blockTitle = isBlocked ? i18n('unblockUser') : i18n('blockUser');
const blockHandler = isBlocked ? onUnblockContact : onBlockContact;
const isPrivate = type === 'direct';
return (
<ContextMenu id={triggerId}>
{showBlock(isMe, isPrivate) ? (
<MenuItem onClick={blockHandler}>{blockTitle}</MenuItem>
) : null}
{getBlockMenuItem(
isMe,
isPrivate,
isBlocked,
onBlockContact,
onUnblockContact,
i18n
)}
{/* {!isPublic && !isRss && !isMe ? (
<MenuItem onClick={onChangeNickname}>
{i18n('changeNickname')}
</MenuItem>
) : null} */}
{showClearNickname(isPublic, isRss, isMe, hasNickname) ? (
<MenuItem onClick={onClearNickname}>{i18n('clearNickname')}</MenuItem>
) : null}
{showCopyId(isPublic, isRss) ? (
<MenuItem onClick={onCopyPublicKey}>{i18n('copyPublicKey')}</MenuItem>
) : null}
{getClearNicknameMenuItem(
isPublic,
isRss,
isMe,
hasNickname,
onClearNickname,
i18n
)}
{getCopyIdMenuItem(
isPublic,
isRss,
type === 'group',
onCopyPublicKey,
i18n
)}
<MenuItem onClick={onDeleteMessages}>{i18n('deleteMessages')}</MenuItem>
{showDeleteContact(
{getInviteContactMenuItem(
type === 'group',
isPublic,
onInviteContacts,
i18n
)}
{getDeleteContactMenuItem(
isMe,
isClosable,
type === 'group',
isPublic,
isRss
) ? (
!isPublic ? (
<MenuItem onClick={onDeleteContact}>
{i18n('deleteContact')}
</MenuItem>
) : (
<MenuItem onClick={onDeleteContact}>
{i18n('deletePublicChannel')}
</MenuItem>
)
) : null}
isRss,
onDeleteContact,
i18n
)}
{getLeaveGroupMenuItem(
isKickedFromGroup,
type === 'group',
isPublic,
isRss,
onDeleteContact,
i18n
)}
</ContextMenu>
);
}

View File

@ -20,20 +20,7 @@ import {
SessionButtonColor,
SessionButtonType,
} from '../session/SessionButton';
import {
showAddModerators,
showBlock,
showCopyId,
showDeleteContact,
showInviteContact,
showLeaveGroup,
showMemberMenu,
showRemoveModerators,
showResetSession,
showSafetyNumber,
showTimerOptions,
showUpdateGroupName,
} from '../../session/utils/Menu';
import * as Menu from '../../session/utils/Menu';
export interface TimerOption {
name: string;
@ -319,48 +306,59 @@ export class ConversationHeader extends React.Component<Props> {
onUpdateGroupName,
} = this.props;
const copyIdLabel = isGroup ? i18n('copyChatId') : i18n('copyPublicKey');
return (
<ContextMenu id={triggerId}>
{this.renderPublicMenuItems()}
{showCopyId(isPublic, isRss) ? (
<MenuItem onClick={onCopyPublicKey}>{copyIdLabel}</MenuItem>
) : null}
{Menu.getCopyIdMenuItem(
isPublic,
isRss,
isGroup,
onCopyPublicKey,
i18n
)}
<MenuItem onClick={onDeleteMessages}>{i18n('deleteMessages')}</MenuItem>
{showAddModerators(amMod, isKickedFromGroup) ? (
<MenuItem onClick={onAddModerators}>{i18n('addModerators')}</MenuItem>
) : null}
{showRemoveModerators(amMod, isKickedFromGroup) ? (
<MenuItem onClick={onRemoveModerators}>
{i18n('removeModerators')}
</MenuItem>
) : null}
{showUpdateGroupName(amMod, isKickedFromGroup) ? (
<MenuItem onClick={onUpdateGroupName}>
{i18n('editGroupNameOrPicture')}
</MenuItem>
) : null}
{showLeaveGroup(isKickedFromGroup, isGroup, isPublic, isRss) ? (
<MenuItem onClick={onLeaveGroup}>{i18n('leaveGroup')}</MenuItem>
) : null}
{Menu.getAddModeratorsMenuItem(
amMod,
isKickedFromGroup,
onAddModerators,
i18n
)}
{Menu.getRemoveModeratorsMenuItem(
amMod,
isKickedFromGroup,
onRemoveModerators,
i18n
)}
{Menu.getUpdateGroupNameMenuItem(
amMod,
isKickedFromGroup,
onUpdateGroupName,
i18n
)}
{Menu.getLeaveGroupMenuItem(
isKickedFromGroup,
isGroup,
isPublic,
isRss,
onLeaveGroup,
i18n
)}
{/* TODO: add delete group */}
{showInviteContact(isGroup, isPublic) ? (
<MenuItem onClick={onInviteContacts}>
{i18n('inviteContacts')}
</MenuItem>
) : null}
{showDeleteContact(isMe, isClosable, isGroup, isPublic, isRss) ? (
!isPublic ? (
<MenuItem onClick={onDeleteContact}>
{i18n('deleteContact')}
</MenuItem>
) : (
<MenuItem onClick={onDeleteContact}>
{i18n('deletePublicChannel')}
</MenuItem>
)
) : null}
{Menu.getInviteContactMenuItem(
isGroup,
isPublic,
onInviteContacts,
i18n
)}
{Menu.getDeleteContactMenuItem(
isMe,
isClosable,
isGroup,
isPublic,
isRss,
onDeleteContact,
i18n
)}
</ContextMenu>
);
}
@ -459,53 +457,45 @@ export class ConversationHeader extends React.Component<Props> {
onUnblockUser,
} = this.props;
if (isPublic || isRss) {
return null;
}
const disappearingTitle = i18n('disappearingMessages') as any;
const blockTitle = isBlocked ? i18n('unblockUser') : i18n('blockUser');
const blockHandler = isBlocked ? onUnblockUser : onBlockUser;
const disappearingMessagesMenuItem = showTimerOptions(
const disappearingMessagesMenuItem = Menu.getDisappearingMenuItem(
isPublic,
isRss,
isKickedFromGroup,
isBlocked
) && (
<SubMenu title={disappearingTitle}>
{(timerOptions || []).map(item => (
<MenuItem
key={item.value}
onClick={() => {
onSetDisappearingMessages(item.value);
}}
>
{item.name}
</MenuItem>
))}
</SubMenu>
isBlocked,
timerOptions,
onSetDisappearingMessages,
i18n
);
const showMembersMenuItem = showMemberMenu(isPublic, isRss, isGroup) && (
<MenuItem onClick={onShowGroupMembers}>{i18n('showMembers')}</MenuItem>
);
const showSafetyNumberMenuItem = showSafetyNumber(
const showMembersMenuItem = Menu.getShowMemberMenuItem(
isPublic,
isRss,
isGroup,
isMe
) && (
<MenuItem onClick={onShowSafetyNumber}>
{i18n('showSafetyNumber')}
</MenuItem>
onShowGroupMembers,
i18n
);
const resetSessionMenuItem = showResetSession(isPublic, isRss, isGroup) && (
<MenuItem onClick={onResetSession}>{i18n('resetSession')}</MenuItem>
const showSafetyNumberMenuItem = Menu.getShowSafetyNumberMenuItem(
isPublic,
isRss,
isGroup,
isMe,
onShowSafetyNumber,
i18n
);
const blockHandlerMenuItem = showBlock(isMe, isPrivate) && (
<MenuItem onClick={blockHandler}>{blockTitle}</MenuItem>
const resetSessionMenuItem = Menu.getResetSessionMenuItem(
isPublic,
isRss,
isGroup,
onResetSession,
i18n
);
const blockHandlerMenuItem = Menu.getBlockMenuItem(
isMe,
isPrivate,
isBlocked,
onBlockUser,
onUnblockUser,
i18n
);
return (

View File

@ -1,111 +0,0 @@
export function showTimerOptions(
isPublic: boolean,
isRss: boolean,
isKickedFromGroup: boolean,
isBlocked: boolean
): boolean {
return (
Boolean(!isPublic) && Boolean(!isRss) && !isKickedFromGroup && !isBlocked
);
}
export function showMemberMenu(
isPublic: boolean,
isRss: boolean,
isGroup: boolean
): boolean {
return Boolean(!isPublic) && Boolean(!isRss) && isGroup;
}
export function showSafetyNumber(
isPublic: boolean,
isRss: boolean,
isGroup: boolean,
isMe: boolean
): boolean {
return Boolean(!isPublic) && Boolean(!isRss) && !isGroup && !isMe;
}
export function showResetSession(
isPublic: boolean,
isRss: boolean,
isGroup: boolean
): boolean {
return Boolean(!isPublic) && Boolean(!isRss) && Boolean(!isGroup);
}
export function showBlock(
isMe: boolean | undefined,
isPrivate: boolean | undefined
): boolean {
return Boolean(!isMe) && Boolean(isPrivate);
}
export function showClearNickname(
isPublic: boolean | undefined,
isRss: boolean | undefined,
isMe: boolean | undefined,
hasNickname: boolean | undefined
): boolean {
return (
Boolean(!isPublic) &&
Boolean(!isRss) &&
Boolean(!isMe) &&
Boolean(hasNickname)
);
}
export function showCopyId(
isPublic: boolean | undefined,
isRss: boolean | undefined
): boolean {
return Boolean(!isPublic) && Boolean(!isRss);
}
export function showDeleteContact(
isMe: boolean | undefined,
isClosable: boolean | undefined,
isGroup: boolean | undefined,
isPublic: boolean | undefined,
isRss: boolean | undefined
): boolean {
return (
Boolean(!isMe) && Boolean(isClosable) && !!(!isGroup || isPublic || isRss)
);
}
export function showAddModerators(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined
): boolean {
return Boolean(!isKickedFromGroup) && Boolean(amMod);
}
export function showRemoveModerators(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined
): boolean {
return Boolean(!isKickedFromGroup) && Boolean(amMod);
}
export function showUpdateGroupName(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined
): boolean {
return Boolean(!isKickedFromGroup) && Boolean(amMod);
}
export function showLeaveGroup(
isKickedFromGroup: boolean | undefined,
isGroup: boolean | undefined,
isPublic: boolean | undefined,
isRss: boolean | undefined
): boolean {
return Boolean(!isKickedFromGroup) && !!(!isGroup || isPublic || isRss);
}
export function showInviteContact(
isGroup: boolean | undefined,
isPublic: boolean | undefined
): boolean {
return Boolean(isGroup) && Boolean(isPublic);
}

336
ts/session/utils/Menu.tsx Normal file
View File

@ -0,0 +1,336 @@
import React from 'react';
import { MenuItem, SubMenu } from 'react-contextmenu';
import { LocalizerType } from '../../types/Util';
import { TimerOption } from '../../components/conversation/ConversationHeader';
function showTimerOptions(
isPublic: boolean,
isRss: boolean,
isKickedFromGroup: boolean,
isBlocked: boolean
): boolean {
return (
Boolean(!isPublic) && Boolean(!isRss) && !isKickedFromGroup && !isBlocked
);
}
function showMemberMenu(
isPublic: boolean,
isRss: boolean,
isGroup: boolean
): boolean {
return Boolean(!isPublic) && Boolean(!isRss) && isGroup;
}
function showSafetyNumber(
isPublic: boolean,
isRss: boolean,
isGroup: boolean,
isMe: boolean
): boolean {
return Boolean(!isPublic) && Boolean(!isRss) && !isGroup && !isMe;
}
function showResetSession(
isPublic: boolean,
isRss: boolean,
isGroup: boolean
): boolean {
return Boolean(!isPublic) && Boolean(!isRss) && Boolean(!isGroup);
}
function showBlock(
isMe: boolean | undefined,
isPrivate: boolean | undefined
): boolean {
return Boolean(!isMe) && Boolean(isPrivate);
}
function showClearNickname(
isPublic: boolean | undefined,
isRss: boolean | undefined,
isMe: boolean | undefined,
hasNickname: boolean | undefined
): boolean {
return (
Boolean(!isPublic) &&
Boolean(!isRss) &&
Boolean(!isMe) &&
Boolean(hasNickname)
);
}
function showCopyId(
isPublic: boolean | undefined,
isRss: boolean | undefined
): boolean {
return Boolean(!isPublic) && Boolean(!isRss);
}
function showDeleteContact(
isMe: boolean | undefined,
isClosable: boolean | undefined,
isGroup: boolean | undefined,
isPublic: boolean | undefined,
isRss: boolean | undefined
): boolean {
return (
Boolean(!isMe) && Boolean(isClosable) && !!(!isGroup || isPublic || isRss)
);
}
function showAddModerators(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined
): boolean {
return Boolean(!isKickedFromGroup) && Boolean(amMod);
}
function showRemoveModerators(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined
): boolean {
return Boolean(!isKickedFromGroup) && Boolean(amMod);
}
function showUpdateGroupName(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined
): boolean {
return Boolean(!isKickedFromGroup) && Boolean(amMod);
}
function showLeaveGroup(
isKickedFromGroup: boolean | undefined,
isGroup: boolean | undefined,
isPublic: boolean | undefined,
isRss: boolean | undefined
): boolean {
return Boolean(!isKickedFromGroup) && Boolean(isGroup) && !isPublic && !isRss;
}
function showInviteContact(
isGroup: boolean | undefined,
isPublic: boolean | undefined
): boolean {
return Boolean(isGroup) && Boolean(isPublic);
}
/** Menu items standardized */
export function getInviteContactMenuItem(
isGroup: boolean | undefined,
isPublic: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showInviteContact(isGroup, isPublic)) {
return <MenuItem onClick={action}>{i18n('inviteContacts')}</MenuItem>;
}
return null;
}
export function getDeleteContactMenuItem(
isMe: boolean | undefined,
isClosable: boolean | undefined,
isGroup: boolean | undefined,
isPublic: boolean | undefined,
isRss: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showDeleteContact(isMe, isClosable, isGroup, isPublic, isRss)) {
if (isPublic) {
return (
<MenuItem onClick={action}>{i18n('deletePublicChannel')}</MenuItem>
);
}
return <MenuItem onClick={action}>{i18n('deleteContact')}</MenuItem>;
}
return null;
}
export function getLeaveGroupMenuItem(
isKickedFromGroup: boolean | undefined,
isGroup: boolean | undefined,
isPublic: boolean | undefined,
isRss: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showLeaveGroup(isKickedFromGroup, isGroup, isPublic, isRss)) {
return <MenuItem onClick={action}>{i18n('leaveGroup')}</MenuItem>;
}
return null;
}
export function getUpdateGroupNameMenuItem(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showUpdateGroupName(amMod, isKickedFromGroup)) {
return (
<MenuItem onClick={action}>{i18n('editGroupNameOrPicture')}</MenuItem>
);
}
return null;
}
export function getRemoveModeratorsMenuItem(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showRemoveModerators(amMod, isKickedFromGroup)) {
return <MenuItem onClick={action}>{i18n('removeModerators')}</MenuItem>;
}
return null;
}
export function getAddModeratorsMenuItem(
amMod: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showAddModerators(amMod, isKickedFromGroup)) {
return <MenuItem onClick={action}>{i18n('addModerators')}</MenuItem>;
}
return null;
}
export function getCopyIdMenuItem(
isPublic: boolean | undefined,
isRss: boolean | undefined,
isGroup: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showCopyId(isPublic, isRss)) {
const copyIdLabel = isGroup ? i18n('copyChatId') : i18n('copyPublicKey');
return <MenuItem onClick={action}>{copyIdLabel}</MenuItem>;
}
return null;
}
export function getDisappearingMenuItem(
isPublic: boolean | undefined,
isRss: boolean | undefined,
isKickedFromGroup: boolean | undefined,
isBlocked: boolean | undefined,
timerOptions: Array<TimerOption>,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (
showTimerOptions(
Boolean(isPublic),
Boolean(isRss),
Boolean(isKickedFromGroup),
Boolean(isBlocked)
)
) {
return (
<SubMenu title={i18n('disappearingMessages') as any}>
{(timerOptions || []).map(item => (
<MenuItem
key={item.value}
onClick={() => {
action(item.value);
}}
>
{item.name}
</MenuItem>
))}
</SubMenu>
);
}
return null;
}
export function getShowMemberMenuItem(
isPublic: boolean | undefined,
isRss: boolean | undefined,
isGroup: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showMemberMenu(Boolean(isPublic), Boolean(isRss), Boolean(isGroup))) {
return <MenuItem onClick={action}>{i18n('showMembers')}</MenuItem>;
}
return null;
}
export function getShowSafetyNumberMenuItem(
isPublic: boolean | undefined,
isRss: boolean | undefined,
isGroup: boolean | undefined,
isMe: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (
showSafetyNumber(
Boolean(isPublic),
Boolean(isRss),
Boolean(isGroup),
Boolean(isMe)
)
) {
return <MenuItem onClick={action}>{i18n('showSafetyNumber')}</MenuItem>;
}
return null;
}
export function getResetSessionMenuItem(
isPublic: boolean | undefined,
isRss: boolean | undefined,
isGroup: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showResetSession(Boolean(isPublic), Boolean(isRss), Boolean(isGroup))) {
return <MenuItem onClick={action}>{i18n('resetSession')}</MenuItem>;
}
return null;
}
export function getBlockMenuItem(
isMe: boolean | undefined,
isPrivate: boolean | undefined,
isBlocked: boolean | undefined,
actionBlock: any,
actionUnblock: any,
i18n: LocalizerType
): JSX.Element | null {
if (showBlock(Boolean(isMe), Boolean(isPrivate))) {
const blockTitle = isBlocked ? i18n('unblockUser') : i18n('blockUser');
const blockHandler = isBlocked ? actionUnblock : actionBlock;
return <MenuItem onClick={blockHandler}>{blockTitle}</MenuItem>;
}
return null;
}
export function getClearNicknameMenuItem(
isPublic: boolean | undefined,
isRss: boolean | undefined,
isMe: boolean | undefined,
hasNickname: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (
showClearNickname(
Boolean(isPublic),
Boolean(isRss),
Boolean(isMe),
Boolean(hasNickname)
)
) {
return <MenuItem onClick={action}>{i18n('clearNickname')}</MenuItem>;
}
return null;
}