Skip to content

How is "Three dot menu" different from "Chat list item context menu"? #5325

@WofWca

Description

@WofWca
  • Operating System (Linux/Mac/Windows/iOS/Android): All
  • Delta Chat Version: 1.60.1

ThreeDotMenu and ChatListContextMenu are almost identical.

menu = [
{
label: tx('search_in_chat'),
action: () => {
// Same as in with `KeybindAction.ChatList_SearchInChat`
//
// TODO improvement a11y: maybe we can add `aria-keyshortcuts=`
// to this menu item?
window.__chatlistSetSearch?.('', selectedChat.id)
setTimeout(
() =>
ActionEmitter.emitAction(KeybindAction.ChatList_FocusSearchInput),
0
)
},
},
canSend &&
selectedChat.chatType !== C.DC_CHAT_TYPE_IN_BROADCAST &&
selectedChat.chatType !== C.DC_CHAT_TYPE_MAILINGLIST && {
label: tx('ephemeral_messages'),
action: onDisappearingMessages,
},
!(isSelfTalk || isDeviceChat) &&
settingsStore !== null &&
settingsStore.desktopSettings.enableChatAuditLog && {
label: tx('menu_chat_audit_log'),
action: onChatAudit,
},
{ type: 'separator' },
!selectedChat.isMuted
? {
label: tx('menu_mute'),
subitems: [
{
label: tx('mute_for_one_hour'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
selectedChat.id,
{
kind: 'Until',
duration: Timespans.ONE_HOUR_IN_SECONDS,
}
)
},
},
{
label: tx('mute_for_eight_hours'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
selectedChat.id,
{
kind: 'Until',
duration: Timespans.ONE_HOUR_IN_SECONDS * 8,
}
)
},
},
{
label: tx('mute_for_one_day'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
selectedChat.id,
{
kind: 'Until',
duration: Timespans.ONE_DAY_IN_SECONDS,
}
)
},
},
{
label: tx('mute_for_seven_days'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
selectedChat.id,
{
kind: 'Until',
duration: Timespans.ONE_WEEK_IN_SECONDS,
}
)
},
},
{
label: tx('mute_forever'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
selectedChat.id,
{ kind: 'Forever' }
)
},
},
],
}
: {
label: tx('menu_unmute'),
action: onUnmuteChat,
},
selectedChat.archived
? {
label: tx('menu_unarchive_chat'),
action: () => {
BackendRemote.rpc.setChatVisibility(accountId, chatId, 'Normal')
unselectChat()
},
}
: {
label: tx('menu_archive_chat'),
action: () => {
BackendRemote.rpc.setChatVisibility(accountId, chatId, 'Archived')
unselectChat()
},
},
{ type: 'separator' },
!isGroup &&
!(isSelfTalk || isDeviceChat) && {
label: tx('menu_block_contact'),
action: onBlockContact,
},
isGroup &&
selfInGroup && {
label: tx('menu_leave_group'),
action: onLeaveGroup,
},
{
label: tx('clear_chat'),
action: onClearChat,
},
{
label: tx('menu_delete_chat'),
action: onDeleteChat,
},
]

const menu: (ContextMenuItem | false)[] = chatListItem
? [
// Pin
pin,
// Mute
!chatListItem.isMuted
? {
label: tx('menu_mute'),
subitems: [
{
label: tx('mute_for_one_hour'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
chatListItem.id,
{
kind: 'Until',
duration: Timespans.ONE_HOUR_IN_SECONDS,
}
)
},
},
{
label: tx('mute_for_eight_hours'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
chatListItem.id,
{
kind: 'Until',
duration: Timespans.ONE_HOUR_IN_SECONDS * 8,
}
)
},
},
{
label: tx('mute_for_one_day'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
chatListItem.id,
{
kind: 'Until',
duration: Timespans.ONE_DAY_IN_SECONDS,
}
)
},
},
{
label: tx('mute_for_seven_days'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
chatListItem.id,
{
kind: 'Until',
duration: Timespans.ONE_WEEK_IN_SECONDS,
}
)
},
},
{
label: tx('mute_forever'),
action: () => {
BackendRemote.rpc.setChatMuteDuration(
accountId,
chatListItem.id,
{ kind: 'Forever' }
)
},
},
],
}
: {
label: tx('menu_unmute'),
action: onUnmuteChat,
},
// Archive
archive,
{ type: 'separator' },
// View Profile
!isGroup && {
label: tx('menu_view_profile'),
action: onViewProfile,
},
// View Group Profile (for non encrypted groups)
isGroup &&
!chatListItem.isEncrypted &&
chatListItem.isSelfInGroup && {
label: tx('menu_view_profile'),
action: onViewGroup,
},
// Edit Group
isGroup &&
chatListItem.isEncrypted &&
chatListItem.isSelfInGroup && {
label: tx('menu_edit_group'),
dataTestid: 'edit-group',
action: onViewGroup,
},
// Edit Channel
isOutBroadcast && {
label: tx('edit_channel'),
action: onViewGroup,
},
// Clone Group
isGroup && {
label: tx('clone_chat'),
action: () => {
openDialog(CloneChat, {
setViewMode: 'createGroup',
chatTemplateId: chatListItem.id,
})
},
},
// Encryption Info
!chatListItem.isDeviceTalk &&
!chatListItem.isSelfTalk && {
label: tx('encryption_info_title_desktop'),
action: onEncrInfo,
},
{ type: 'separator' },
// Leave channel
chatListItem.chatType === C.DC_CHAT_TYPE_IN_BROADCAST &&
!chatListItem.isContactRequest && {
label: tx('menu_leave_channel'),
action: onLeaveGroupOrChannel,
},
// Leave group
isGroup &&
chatListItem.isEncrypted &&
chatListItem.isSelfInGroup && {
label: tx('menu_leave_group'),
action: onLeaveGroupOrChannel,
},
// Block contact
!isGroup &&
!(
chatListItem.isSelfTalk ||
chatListItem.isDeviceTalk ||
isOutBroadcast
) && {
label: tx('menu_block_contact'),
action: onBlockContact,
},
// Delete
{
label: tx('menu_delete_chat'),
action: onDeleteChat,
},
]

But not completely. Some options that are present in one are missing in another. For example, "Search in chat" and "Ephemeral messages" are only available in ThreeDotMenu, "Clone chat", "View chat", "Clear chat", "Encryption info" are only available in ChatListContextMenu.
What this results in:

  • You have to figure out which menu you need to open to get to the option you need
  • Behavior inconsistency. We, as part of the core v2 migration, recently updated the ChatListContextMenu, but did not update ThreeDotMenu.

Can we just keep ChatListContextMenu and remove ThreeDotMenu? Or remove the duplicate items? This would not be good on small screens though, where the chat list is not always visible, as on Android.
At the very least we should them reuse the same code, to avoid inconsistencies.

Just in case, keep in mind that chat list item multiselect is coming: #5297.

WDYT?

Metadata

Metadata

Assignees

Labels

refactorThis PR or issue is about refactoringui/uxUI/UX related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions