From b1b557581b9aa23cc7a11345434e39b3be6e7687 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 10 Dec 2024 16:32:34 +1100 Subject: [PATCH] feat: move back conversation request buttons to the bottom because we can --- .../conversation/MessageRequestButtons.tsx | 4 +--- .../conversation/SessionConversation.tsx | 7 +++++-- .../conversation/SubtleNotification.tsx | 10 ++++++++- .../conversations/unsendingInteractions.ts | 21 ++++++++++++------- ts/models/message.ts | 2 +- ts/receiver/groupv2/handleGroupV2Message.ts | 19 ++++++++--------- ts/session/types/with.ts | 2 ++ ts/state/selectors/messages.ts | 6 ++---- 8 files changed, 43 insertions(+), 28 deletions(-) diff --git a/ts/components/conversation/MessageRequestButtons.tsx b/ts/components/conversation/MessageRequestButtons.tsx index ea0afae94..32bc31767 100644 --- a/ts/components/conversation/MessageRequestButtons.tsx +++ b/ts/components/conversation/MessageRequestButtons.tsx @@ -15,13 +15,12 @@ import { SessionButton, SessionButtonColor } from '../basic/SessionButton'; import { ConversationIncomingRequestExplanation, ConversationOutgoingRequestExplanation, - InvitedToGroupControlMessage, } from './SubtleNotification'; import { NetworkTime } from '../../util/NetworkTime'; const MessageRequestContainer = styled.div` display: flex; - flex-direction: column; + flex-direction: column-reverse; justify-content: center; padding: var(--margins-lg); gap: var(--margins-lg); @@ -98,7 +97,6 @@ export const ConversationMessageRequestButtons = () => { return ( - { diff --git a/ts/components/conversation/SessionConversation.tsx b/ts/components/conversation/SessionConversation.tsx index 6ca1d35b6..3ad79d45c 100644 --- a/ts/components/conversation/SessionConversation.tsx +++ b/ts/components/conversation/SessionConversation.tsx @@ -58,7 +58,7 @@ import { ConversationMessageRequestButtons } from './MessageRequestButtons'; import { RightPanel, StyledRightPanelContainer } from './right-panel/RightPanel'; import { HTMLDirection } from '../../util/i18n/rtlSupport'; import { showLinkVisitWarningDialog } from '../dialog/OpenUrlModal'; -import { NoMessageInConversation } from './SubtleNotification'; +import { InvitedToGroup, NoMessageInConversation } from './SubtleNotification'; const DEFAULT_JPEG_QUALITY = 0.85; @@ -265,7 +265,8 @@ export class SessionConversation extends Component { >
- + + } bottom={ @@ -276,6 +277,8 @@ export class SessionConversation extends Component { } disableTop={!this.props.hasOngoingCallWithFocusedConvo} /> + + {isDraggingFile && }
diff --git a/ts/components/conversation/SubtleNotification.tsx b/ts/components/conversation/SubtleNotification.tsx index ab9657e37..f0838aff7 100644 --- a/ts/components/conversation/SubtleNotification.tsx +++ b/ts/components/conversation/SubtleNotification.tsx @@ -155,7 +155,7 @@ const GroupRequestExplanation = () => { ); }; -export const InvitedToGroupControlMessage = () => { +const InvitedToGroupControlMessage = () => { const selectedConversation = useSelectedConversationKey(); const isGroupV2 = useSelectedIsGroupV2(); const hasMessages = useSelectedHasMessages(); @@ -202,6 +202,14 @@ export const InvitedToGroupControlMessage = () => { ); }; +export const InvitedToGroup = () => { + return ( + + + + ); +}; + export const NoMessageInConversation = () => { const selectedConversation = useSelectedConversationKey(); const hasMessages = useSelectedHasMessages(); diff --git a/ts/interactions/conversations/unsendingInteractions.ts b/ts/interactions/conversations/unsendingInteractions.ts index d400bec5d..3e8df466c 100644 --- a/ts/interactions/conversations/unsendingInteractions.ts +++ b/ts/interactions/conversations/unsendingInteractions.ts @@ -21,6 +21,7 @@ import { ed25519Str } from '../../session/utils/String'; import { UserGroupsWrapperActions } from '../../webworker/workers/browser/libsession_worker_interface'; import { NetworkTime } from '../../util/NetworkTime'; import { MessageQueue } from '../../session/sending'; +import { WithLocalMessageDeletionType } from '../../session/types/with'; async function unsendMessagesForEveryone1o1AndLegacy( conversation: ConversationModel, @@ -103,7 +104,8 @@ export async function unsendMessagesForEveryoneGroupV2({ */ async function unsendMessagesForEveryone( conversation: ConversationModel, - msgsToDelete: Array + msgsToDelete: Array, + { deletionType }: WithLocalMessageDeletionType ) { window?.log?.info('Deleting messages for all users in this conversation'); const destinationId = conversation.id as string; @@ -134,7 +136,11 @@ async function unsendMessagesForEveryone( allMessagesFrom: [], // currently we cannot remove all the messages from a specific pubkey but we do already handle them on the receiving side }); } - await deleteMessagesFromSwarmAndCompletelyLocally(conversation, msgsToDelete); + if (deletionType === 'complete') { + await deleteMessagesFromSwarmAndCompletelyLocally(conversation, msgsToDelete); + } else { + await deleteMessagesFromSwarmAndMarkAsDeletedLocally(conversation, msgsToDelete); + } window.inboxStore?.dispatch(resetSelectedMessageIds()); ToastUtils.pushDeleted(msgsToDelete.length); @@ -311,10 +317,9 @@ export async function deleteMessageLocallyOnly({ conversation, message, deletionType, -}: { +}: WithLocalMessageDeletionType & { conversation: ConversationModel; message: MessageModel; - deletionType: 'complete' | 'markDeleted'; }) { if (deletionType === 'complete') { // remove the message from the database @@ -446,7 +451,9 @@ const doDeleteSelectedMessages = async ({ } } // if they are all ours, of not but we are an admin, we can move forward - await unsendMessagesForEveryone(conversation, selectedMessages); + await unsendMessagesForEveryone(conversation, selectedMessages, { + deletionType: 'markDeleted', // 03 groups: mark as deleted + }); return; } @@ -455,13 +462,13 @@ const doDeleteSelectedMessages = async ({ window.inboxStore?.dispatch(resetSelectedMessageIds()); return; } - await unsendMessagesForEveryone(conversation, selectedMessages); + await unsendMessagesForEveryone(conversation, selectedMessages, { deletionType: 'complete' }); // not 03 group: delete completely return; } // delete just for me in a legacy closed group only means delete locally if (conversation.isClosedGroup()) { - await deleteMessagesFromSwarmAndCompletelyLocally(conversation, selectedMessages); + await deleteMessagesFromSwarmAndMarkAsDeletedLocally(conversation, selectedMessages); // Update view and trigger update window.inboxStore?.dispatch(resetSelectedMessageIds()); diff --git a/ts/models/message.ts b/ts/models/message.ts index 24ab54df9..0beff6b15 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -752,7 +752,7 @@ export class MessageModel extends Backbone.Model { props.text = body; } if (this.get('isDeleted')) { - props.isDeleted = this.get('isDeleted'); + props.isDeleted = !!this.get('isDeleted'); } if (this.getMessageHash()) { diff --git a/ts/receiver/groupv2/handleGroupV2Message.ts b/ts/receiver/groupv2/handleGroupV2Message.ts index 80b12b3f7..552cd0a52 100644 --- a/ts/receiver/groupv2/handleGroupV2Message.ts +++ b/ts/receiver/groupv2/handleGroupV2Message.ts @@ -68,7 +68,7 @@ async function getInitializedGroupObject({ if (!found) { found = { authData: null, - joinedAtSeconds: Math.floor(Date.now()/ 1000), + joinedAtSeconds: Math.floor(Date.now() / 1000), name: groupName, priority: 0, pubkeyHex: groupPk, @@ -410,7 +410,7 @@ async function handleGroupUpdateMemberLeftNotificationMessage({ }); } -async function handleGroupDeleteMemberContentMessage({ +async function handleGroupUpdateDeleteMemberContentMessage({ groupPk, signatureTimestamp, change, @@ -420,7 +420,7 @@ async function handleGroupDeleteMemberContentMessage({ if (!convo) { return; } - window.log.info(`handleGroupDeleteMemberContentMessage for ${ed25519Str(groupPk)}`); + window.log.info(`handleGroupUpdateDeleteMemberContentMessage for ${ed25519Str(groupPk)}`); /** * When handling a GroupUpdateDeleteMemberContentMessage we need to do a few things. @@ -428,10 +428,8 @@ async function handleGroupDeleteMemberContentMessage({ * 1. we only delete the messageHashes which are in the change.messageHashes AND sent by that same author. * When `adminSignature` is not empty and valid, * 2. we delete all the messages in the group sent by any of change.memberSessionIds AND - * 3. we delete all the messageHashes in the conversation matching the change.messageHashes (even if not from the right sender) + * 3. we mark as deleted all the messageHashes in the conversation matching the change.messageHashes (even if not from the right sender) * - * Note: we never fully delete those messages locally, but only empty them and mark them as deleted with the - * "This message was deleted" placeholder. * Eventually, we will be able to delete those "deleted by kept locally" messages with placeholders. */ @@ -445,8 +443,8 @@ async function handleGroupDeleteMemberContentMessage({ signatureTimestamp, }); - // we don't want to hang while for too long here - // processing the handleGroupDeleteMemberContentMessage itself + // we don't want to hang for too long here + // processing the handleGroupUpdateDeleteMemberContentMessage itself // (we are running on the receiving pipeline here) // so network calls are not allowed. for (let index = 0; index < messageModels.length; index++) { @@ -456,7 +454,7 @@ async function handleGroupDeleteMemberContentMessage({ await messageModel.markAsDeleted(); } catch (e) { window.log.warn( - `handleGroupDeleteMemberContentMessage markAsDeleted non-admin of ${messageModel.getMessageHash()} failed with`, + `handleGroupUpdateDeleteMemberContentMessage markAsDeleted non-admin of ${messageModel.getMessageHash()} failed with`, e.message ); } @@ -488,6 +486,7 @@ async function handleGroupDeleteMemberContentMessage({ toRemove, signatureTimestamp, }); // this is step 2. + const modelsByHashes = await Data.findAllMessageHashesInConversation({ groupPk, messageHashes: change.messageHashes, @@ -731,7 +730,7 @@ async function handleGroupUpdateMessage( return; } if (details.updateMessage.deleteMemberContent) { - await handleGroupDeleteMemberContentMessage({ + await handleGroupUpdateDeleteMemberContentMessage({ change: details.updateMessage .deleteMemberContent as SignalService.GroupUpdateDeleteMemberContentMessage, ...detailsWithContext, diff --git a/ts/session/types/with.ts b/ts/session/types/with.ts index a3885b53a..401c15a38 100644 --- a/ts/session/types/with.ts +++ b/ts/session/types/with.ts @@ -20,3 +20,5 @@ export type WithBatchMethod = { method: T }; export type WithConvoId = { conversationId: string }; export type WithMessageId = { messageId: string }; + +export type WithLocalMessageDeletionType = { deletionType: 'complete' | 'markDeleted' }; diff --git a/ts/state/selectors/messages.ts b/ts/state/selectors/messages.ts index 6e7637d28..ed22b1875 100644 --- a/ts/state/selectors/messages.ts +++ b/ts/state/selectors/messages.ts @@ -41,9 +41,7 @@ export const useAuthorProfileName = (messageId: string): string | null => { const authorProfileName = senderIsUs ? window.i18n('you') - : senderProps.nickname || - senderProps.displayNameInProfile || - PubKey.shorten(sender); + : senderProps.nickname || senderProps.displayNameInProfile || PubKey.shorten(sender); return authorProfileName || window.i18n('unknown'); }; @@ -70,7 +68,7 @@ export const useAuthorAvatarPath = (messageId: string): string | null => { export const useMessageIsDeleted = (messageId: string): boolean => { const props = useMessagePropsByMessageId(messageId); - return props?.propsForMessage.isDeleted || false; + return !!props?.propsForMessage.isDeleted || false; }; export const useFirstMessageOfSeries = (messageId: string | undefined): boolean => {