Clarify behavior of group deletion
This commit is contained in:
parent
98c237856d
commit
08e8a7c6e9
8 changed files with 62 additions and 9 deletions
|
@ -1338,6 +1338,22 @@
|
||||||
"messageformat": "All messages in this chat will be deleted from all your devices. You can still search for this chat after you delete messages.",
|
"messageformat": "All messages in this chat will be deleted from all your devices. You can still search for this chat after you delete messages.",
|
||||||
"description": "Description for confirmation modal to delete all messages in a conversation"
|
"description": "Description for confirmation modal to delete all messages in a conversation"
|
||||||
},
|
},
|
||||||
|
"icu:deleteConversation": {
|
||||||
|
"messageformat": "Delete",
|
||||||
|
"description": "Menu item for deleting a conversation (including messages), title case."
|
||||||
|
},
|
||||||
|
"icu:ConversationHeader__DeleteConversationConfirmation__title": {
|
||||||
|
"messageformat": "Delete chat?",
|
||||||
|
"description": "Conversation Header > Delete Action > Delete Messages Confirmation Modal > Title. Previously known as icu:ConversationHeader__DeleteMessagesConfirmation__title"
|
||||||
|
},
|
||||||
|
"icu:ConversationHeader__DeleteConversationConfirmation__description": {
|
||||||
|
"messageformat": "All messages in this chat will be deleted from this device.",
|
||||||
|
"description": "Description for confirmation modal to delete a conversation"
|
||||||
|
},
|
||||||
|
"icu:ConversationHeader__DeleteConversationConfirmation__description-with-sync": {
|
||||||
|
"messageformat": "All messages in this chat will be deleted from all your devices.",
|
||||||
|
"description": "Description for confirmation modal to delete a conversation"
|
||||||
|
},
|
||||||
"icu:ConversationHeader__ContextMenu__LeaveGroupAction__title": {
|
"icu:ConversationHeader__ContextMenu__LeaveGroupAction__title": {
|
||||||
"messageformat": "Leave group",
|
"messageformat": "Leave group",
|
||||||
"description": "This is a button to leave a group"
|
"description": "This is a button to leave a group"
|
||||||
|
|
|
@ -654,7 +654,7 @@ function HeaderMenu({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<MenuItem onClick={onConversationDeleteMessages}>
|
<MenuItem onClick={onConversationDeleteMessages}>
|
||||||
{i18n('icu:deleteMessagesInConversation')}
|
{i18n('icu:deleteConversation')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
);
|
);
|
||||||
|
@ -792,7 +792,7 @@ function HeaderMenu({
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
<MenuItem onClick={onConversationDeleteMessages}>
|
<MenuItem onClick={onConversationDeleteMessages}>
|
||||||
{i18n('icu:deleteMessagesInConversation')}
|
{i18n('icu:deleteConversation')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{isGroup && (
|
{isGroup && (
|
||||||
<MenuItem onClick={onConversationLeaveGroup}>
|
<MenuItem onClick={onConversationLeaveGroup}>
|
||||||
|
@ -1002,17 +1002,17 @@ function DeleteMessagesConfirmationDialog({
|
||||||
|
|
||||||
const dialogBody = isDeleteSyncSendEnabled
|
const dialogBody = isDeleteSyncSendEnabled
|
||||||
? i18n(
|
? i18n(
|
||||||
'icu:ConversationHeader__DeleteMessagesInConversationConfirmation__description-with-sync'
|
'icu:ConversationHeader__DeleteConversationConfirmation__description-with-sync'
|
||||||
)
|
)
|
||||||
: i18n(
|
: i18n(
|
||||||
'icu:ConversationHeader__DeleteMessagesInConversationConfirmation__description'
|
'icu:ConversationHeader__DeleteConversationConfirmation__description'
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationDialog
|
<ConfirmationDialog
|
||||||
dialogName="ConversationHeader.destroyMessages"
|
dialogName="ConversationHeader.destroyMessages"
|
||||||
title={i18n(
|
title={i18n(
|
||||||
'icu:ConversationHeader__DeleteMessagesInConversationConfirmation__title'
|
'icu:ConversationHeader__DeleteConversationConfirmation__title'
|
||||||
)}
|
)}
|
||||||
actions={[
|
actions={[
|
||||||
{
|
{
|
||||||
|
|
1
ts/model-types.d.ts
vendored
1
ts/model-types.d.ts
vendored
|
@ -354,6 +354,7 @@ export type ConversationAttributesType = {
|
||||||
draftAttachments?: ReadonlyArray<AttachmentDraftType>;
|
draftAttachments?: ReadonlyArray<AttachmentDraftType>;
|
||||||
draftBodyRanges?: DraftBodyRanges;
|
draftBodyRanges?: DraftBodyRanges;
|
||||||
draftTimestamp?: number | null;
|
draftTimestamp?: number | null;
|
||||||
|
hiddenFromConversationSearch?: boolean;
|
||||||
hideStory?: boolean;
|
hideStory?: boolean;
|
||||||
inbox_position?: number;
|
inbox_position?: number;
|
||||||
// When contact is removed - it is initially placed into `justNotification`
|
// When contact is removed - it is initially placed into `justNotification`
|
||||||
|
|
|
@ -407,6 +407,8 @@ export class ConversationModel extends window.Backbone
|
||||||
this.unset('tokens');
|
this.unset('tokens');
|
||||||
|
|
||||||
this.on('change:members change:membersV2', this.fetchContacts);
|
this.on('change:members change:membersV2', this.fetchContacts);
|
||||||
|
this.on('change:active_at', this.onActiveAtChange);
|
||||||
|
|
||||||
this.typingRefreshTimer = null;
|
this.typingRefreshTimer = null;
|
||||||
this.typingPauseTimer = null;
|
this.typingPauseTimer = null;
|
||||||
|
|
||||||
|
@ -4416,6 +4418,12 @@ export class ConversationModel extends window.Backbone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onActiveAtChange(): void {
|
||||||
|
if (this.get('active_at') && this.get('hiddenFromConversationSearch')) {
|
||||||
|
this.set('hiddenFromConversationSearch', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async refreshGroupLink(): Promise<void> {
|
async refreshGroupLink(): Promise<void> {
|
||||||
if (!isGroupV2(this.attributes)) {
|
if (!isGroupV2(this.attributes)) {
|
||||||
return;
|
return;
|
||||||
|
@ -4846,7 +4854,12 @@ export class ConversationModel extends window.Backbone
|
||||||
ourAci
|
ourAci
|
||||||
);
|
);
|
||||||
const sharedGroups = ourGroups
|
const sharedGroups = ourGroups
|
||||||
.filter(c => c.hasMember(ourAci) && c.hasMember(theirAci))
|
.filter(
|
||||||
|
c =>
|
||||||
|
c.hasMember(ourAci) &&
|
||||||
|
c.hasMember(theirAci) &&
|
||||||
|
!c.attributes.hiddenFromConversationSearch
|
||||||
|
)
|
||||||
.sort(
|
.sort(
|
||||||
(left, right) =>
|
(left, right) =>
|
||||||
(right.get('timestamp') || 0) - (left.get('timestamp') || 0)
|
(right.get('timestamp') || 0) - (left.get('timestamp') || 0)
|
||||||
|
@ -5209,6 +5222,9 @@ export class ConversationModel extends window.Backbone
|
||||||
active_at: null,
|
active_at: null,
|
||||||
pendingUniversalTimer: undefined,
|
pendingUniversalTimer: undefined,
|
||||||
});
|
});
|
||||||
|
if (isGroup(this.attributes)) {
|
||||||
|
this.set('hiddenFromConversationSearch', true);
|
||||||
|
}
|
||||||
await DataWriter.updateConversation(this.attributes);
|
await DataWriter.updateConversation(this.attributes);
|
||||||
|
|
||||||
const ourConversation =
|
const ourConversation =
|
||||||
|
|
|
@ -199,6 +199,7 @@ import {
|
||||||
import { MAX_MESSAGE_COUNT } from '../../util/deleteForMe.types';
|
import { MAX_MESSAGE_COUNT } from '../../util/deleteForMe.types';
|
||||||
import { markCallHistoryReadInConversation } from './callHistory';
|
import { markCallHistoryReadInConversation } from './callHistory';
|
||||||
import type { CapabilitiesType } from '../../textsecure/WebAPI';
|
import type { CapabilitiesType } from '../../textsecure/WebAPI';
|
||||||
|
import type { SearchActionType } from './search';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
|
@ -295,6 +296,7 @@ export type ConversationType = ReadonlyDeep<
|
||||||
customColor?: CustomColorType;
|
customColor?: CustomColorType;
|
||||||
customColorId?: string;
|
customColorId?: string;
|
||||||
discoveredUnregisteredAt?: number;
|
discoveredUnregisteredAt?: number;
|
||||||
|
hiddenFromConversationSearch?: boolean;
|
||||||
hideStory?: boolean;
|
hideStory?: boolean;
|
||||||
isArchived?: boolean;
|
isArchived?: boolean;
|
||||||
isBlocked?: boolean;
|
isBlocked?: boolean;
|
||||||
|
@ -1850,7 +1852,7 @@ function destroyMessages(
|
||||||
void,
|
void,
|
||||||
RootStateType,
|
RootStateType,
|
||||||
unknown,
|
unknown,
|
||||||
ConversationUnloadedActionType | NoopActionType
|
ConversationUnloadedActionType | NoopActionType | SearchActionType
|
||||||
> {
|
> {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const conversation = window.ConversationController.get(conversationId);
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
|
@ -1869,6 +1871,20 @@ function destroyMessages(
|
||||||
);
|
);
|
||||||
|
|
||||||
await conversation.destroyMessages({ source: 'local-delete' });
|
await conversation.destroyMessages({ source: 'local-delete' });
|
||||||
|
|
||||||
|
// Deselect the conversation
|
||||||
|
if (
|
||||||
|
getState().conversations.selectedConversationId === conversationId
|
||||||
|
) {
|
||||||
|
showConversation({ conversationId: undefined });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear search state, in case it's showing in search
|
||||||
|
dispatch({
|
||||||
|
type: 'CLEAR_CONVERSATION_SEARCH',
|
||||||
|
payload: null,
|
||||||
|
});
|
||||||
|
|
||||||
drop(conversation.updateLastMessage());
|
drop(conversation.updateLastMessage());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -589,7 +589,8 @@ export const getAllComposableConversations = createSelector(
|
||||||
// All conversation should have a title except in weird cases where
|
// All conversation should have a title except in weird cases where
|
||||||
// they don't, in that case we don't want to show these for Forwarding.
|
// they don't, in that case we don't want to show these for Forwarding.
|
||||||
conversation.titleNoDefault &&
|
conversation.titleNoDefault &&
|
||||||
hasDisplayInfo(conversation)
|
hasDisplayInfo(conversation) &&
|
||||||
|
!conversation.hiddenFromConversationSearch
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@ export function filterAndSortConversations(
|
||||||
const withoutUnknown = conversations.filter(item => item.titleNoDefault);
|
const withoutUnknown = conversations.filter(item => item.titleNoDefault);
|
||||||
|
|
||||||
return searchConversations(withoutUnknown, searchTerm, regionCode)
|
return searchConversations(withoutUnknown, searchTerm, regionCode)
|
||||||
.slice()
|
.filter(({ item }) => !item.hiddenFromConversationSearch)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const { activeAt: aActiveAt = 0, left: aLeft = false } = a.item;
|
const { activeAt: aActiveAt = 0, left: aLeft = false } = a.item;
|
||||||
const { activeAt: bActiveAt = 0, left: bLeft = false } = b.item;
|
const { activeAt: bActiveAt = 0, left: bLeft = false } = b.item;
|
||||||
|
|
|
@ -175,6 +175,9 @@ export function getConversation(model: ConversationModel): ConversationType {
|
||||||
groupVersion,
|
groupVersion,
|
||||||
groupId: attributes.groupId,
|
groupId: attributes.groupId,
|
||||||
groupLink: buildGroupLink(attributes),
|
groupLink: buildGroupLink(attributes),
|
||||||
|
hiddenFromConversationSearch: Boolean(
|
||||||
|
attributes.hiddenFromConversationSearch
|
||||||
|
),
|
||||||
hideStory: Boolean(attributes.hideStory),
|
hideStory: Boolean(attributes.hideStory),
|
||||||
inboxPosition,
|
inboxPosition,
|
||||||
isArchived: attributes.isArchived,
|
isArchived: attributes.isArchived,
|
||||||
|
|
Loading…
Reference in a new issue