Skip to content

Commit 9c419c1

Browse files
committed
Merge branch 'dev' into new-navigation
2 parents 3f4f755 + 49b620e commit 9c419c1

File tree

13 files changed

+167
-153
lines changed

13 files changed

+167
-153
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"@wireapp/avs": "9.7.15",
1010
"@wireapp/commons": "5.2.8",
1111
"@wireapp/core": "46.0.14",
12-
"@wireapp/react-ui-kit": "9.17.7",
12+
"@wireapp/react-ui-kit": "9.18.0",
1313
"@wireapp/store-engine-dexie": "2.1.10",
1414
"@wireapp/webapp-events": "0.22.0",
1515
"amplify": "https://github.com/wireapp/amplify#head=master",

src/i18n/de-DE.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,7 @@
11821182
"participantDevicesHeader": "Geräte",
11831183
"participantDevicesHeadline": "{{brandName}} gibt jedem Gerät einen einzigartigen Fingerabdruck. Vergleichen Sie diese mit {{user}} und überprüfen Sie Ihre Unterhaltung.",
11841184
"participantDevicesLearnMore": "Mehr erfahren",
1185-
"participantDevicesNoClients": "{{user}} has no devices attached to their account and won’t get your messages or calls at the moment.",
1185+
"participantDevicesNoClients": "{{user}} hat keine Geräte, die mit dem Benutzerkonto verbunden sind, und wird Ihre Nachrichten oder Anrufe im Moment nicht erhalten.",
11861186
"participantDevicesProteusDeviceVerification": "Proteus-Geräteüberprüfung",
11871187
"participantDevicesProteusKeyFingerprint": "Proteus-Schlüssel-Fingerabdruck",
11881188
"participantDevicesSelfAllDevices": "Alle meine Geräte anzeigen",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Wire
3+
* Copyright (C) 2024 Wire Swiss GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see http://www.gnu.org/licenses/.
17+
*
18+
*/
19+
20+
import {CSSObject} from '@emotion/react';
21+
22+
export const messageBodyWrapper: CSSObject = {
23+
display: 'grid',
24+
gridTemplateColumns: 'calc(100% - var(--delivered-state-width)) var(--delivered-state-width)',
25+
paddingLeft: 'var(--conversation-message-sender-width)',
26+
};
27+
28+
export const deliveredMessageIndicator: CSSObject = {
29+
display: 'flex',
30+
justifyContent: 'center',
31+
paddingTop: '2px',
32+
width: 'var(--delivered-state-width)',
33+
};

src/script/components/MessagesList/Message/ContentMessage/ContentMessage.tsx

Lines changed: 76 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {QualifiedId} from '@wireapp/api-client/lib/user';
2323
import cx from 'classnames';
2424
import ko from 'knockout';
2525

26+
import {Icon} from 'Components/Icon';
2627
import {ReadIndicator} from 'Components/MessagesList/Message/ReadIndicator';
2728
import {Conversation} from 'src/script/entity/Conversation';
2829
import {CompositeMessage} from 'src/script/entity/message/CompositeMessage';
@@ -31,8 +32,11 @@ import {useRelativeTimestamp} from 'src/script/hooks/useRelativeTimestamp';
3132
import {StatusType} from 'src/script/message/StatusType';
3233
import {useKoSubscribableChildren} from 'Util/ComponentUtil';
3334
import {getMessageAriaLabel} from 'Util/conversationMessages';
35+
import {t} from 'Util/LocalizerUtil';
36+
import {checkIsMessageDelivered} from 'Util/util';
3437

3538
import {ContentAsset} from './asset';
39+
import {deliveredMessageIndicator, messageBodyWrapper} from './ContentMessage.styles';
3640
import {MessageActionsMenu} from './MessageActions/MessageActions';
3741
import {useMessageActionsState} from './MessageActions/MessageActions.state';
3842
import {MessageReactionsList} from './MessageActions/MessageReactions/MessageReactionsList';
@@ -48,6 +52,7 @@ import {ContextMenuEntry} from '../../../../ui/ContextMenu';
4852
import {EphemeralTimer} from '../EphemeralTimer';
4953
import {MessageTime} from '../MessageTime';
5054
import {useMessageFocusedTabIndex} from '../util';
55+
5156
export interface ContentMessageProps extends Omit<MessageActions, 'onClickResetSession'> {
5257
contextMenu: {entries: ko.Subscribable<ContextMenuEntry[]>};
5358
conversation: Conversation;
@@ -104,6 +109,7 @@ export const ContentMessageComponent = ({
104109
status,
105110
quote,
106111
isObfuscated,
112+
readReceipts,
107113
} = useKoSubscribableChildren(message, [
108114
'senderName',
109115
'timestamp',
@@ -116,6 +122,7 @@ export const ContentMessageComponent = ({
116122
'status',
117123
'quote',
118124
'isObfuscated',
125+
'readReceipts',
119126
]);
120127

121128
const timeAgo = useRelativeTimestamp(message.timestamp());
@@ -159,6 +166,8 @@ export const ContentMessageComponent = ({
159166
}
160167
};
161168

169+
const showDeliveredMessageIcon = checkIsMessageDelivered(isLastDeliveredMessage, readReceipts);
170+
162171
// Closing another ActionMenu on outside click
163172
useClickOutside(messageRef, hideActionMenuVisibility);
164173

@@ -194,73 +203,77 @@ export const ContentMessageComponent = ({
194203
</MessageHeader>
195204
)}
196205

197-
<div
198-
className={cx('message-body', {
199-
'message-asset': isAssetMessage,
200-
'message-quoted': !!quote,
201-
'ephemeral-asset-expired': isObfuscated && isAssetMessage,
202-
'icon-file': isObfuscated && isFileMessage,
203-
'icon-movie': isObfuscated && isVideoMessage,
204-
})}
205-
{...(ephemeralCaption && {title: ephemeralCaption})}
206-
>
207-
{ephemeral_status === EphemeralStatusType.ACTIVE && (
208-
<div className="message-ephemeral-timer">
209-
<EphemeralTimer message={message} />
210-
</div>
211-
)}
206+
<div css={messageBodyWrapper}>
207+
<div
208+
className={cx('message-body', {
209+
'message-asset': isAssetMessage,
210+
'message-quoted': !!quote,
211+
'ephemeral-asset-expired': isObfuscated && isAssetMessage,
212+
'icon-file': isObfuscated && isFileMessage,
213+
'icon-movie': isObfuscated && isVideoMessage,
214+
})}
215+
{...(ephemeralCaption && {title: ephemeralCaption})}
216+
>
217+
{ephemeral_status === EphemeralStatusType.ACTIVE && (
218+
<div className="message-ephemeral-timer">
219+
<EphemeralTimer message={message} />
220+
</div>
221+
)}
222+
223+
{quote && (
224+
<Quote
225+
conversation={conversation}
226+
quote={quote}
227+
selfId={selfId}
228+
findMessage={findMessage}
229+
showDetail={onClickImage}
230+
focusMessage={onClickTimestamp}
231+
handleClickOnMessage={onClickMessage}
232+
showUserDetails={onClickAvatar}
233+
isMessageFocused={msgFocusState}
234+
/>
235+
)}
212236

213-
{quote && (
214-
<Quote
215-
conversation={conversation}
216-
quote={quote}
217-
selfId={selfId}
218-
findMessage={findMessage}
219-
showDetail={onClickImage}
220-
focusMessage={onClickTimestamp}
221-
handleClickOnMessage={onClickMessage}
222-
showUserDetails={onClickAvatar}
223-
isMessageFocused={msgFocusState}
224-
/>
225-
)}
237+
{assets.map(asset => (
238+
<ContentAsset
239+
key={asset.type}
240+
asset={asset}
241+
message={message}
242+
selfId={selfId}
243+
onClickButton={onClickButton}
244+
onClickImage={onClickImage}
245+
onClickMessage={onClickMessage}
246+
isMessageFocused={msgFocusState}
247+
is1to1Conversation={conversation.is1to1()}
248+
onClickDetails={() => onClickDetails(message)}
249+
/>
250+
))}
226251

227-
{assets.map(asset => (
228-
<ContentAsset
229-
key={asset.type}
230-
asset={asset}
231-
message={message}
232-
selfId={selfId}
233-
onClickButton={onClickButton}
234-
onClickImage={onClickImage}
235-
onClickMessage={onClickMessage}
236-
isMessageFocused={msgFocusState}
237-
is1to1Conversation={conversation.is1to1()}
238-
isLastDeliveredMessage={isLastDeliveredMessage}
239-
onClickDetails={() => onClickDetails(message)}
240-
/>
241-
))}
252+
{isAssetMessage && (
253+
<ReadIndicator message={message} is1to1Conversation={conversation.is1to1()} onClick={onClickDetails} />
254+
)}
242255

243-
{isAssetMessage && (
244-
<ReadIndicator
245-
message={message}
246-
is1to1Conversation={conversation.is1to1()}
247-
isLastDeliveredMessage={isLastDeliveredMessage}
248-
onClick={onClickDetails}
249-
/>
250-
)}
256+
{!isConversationReadonly && isActionMenuVisible && (
257+
<MessageActionsMenu
258+
isMsgWithHeader={!hideHeader}
259+
message={message}
260+
handleActionMenuVisibility={setActionMenuVisibility}
261+
contextMenu={contextMenu}
262+
isMessageFocused={msgFocusState}
263+
handleReactionClick={onClickReaction}
264+
reactionsTotalCount={reactions.length}
265+
isRemovedFromConversation={conversation.removed_from_conversation()}
266+
/>
267+
)}
268+
</div>
251269

252-
{!isConversationReadonly && isActionMenuVisible && (
253-
<MessageActionsMenu
254-
isMsgWithHeader={!hideHeader}
255-
message={message}
256-
handleActionMenuVisibility={setActionMenuVisibility}
257-
contextMenu={contextMenu}
258-
isMessageFocused={msgFocusState}
259-
handleReactionClick={onClickReaction}
260-
reactionsTotalCount={reactions.length}
261-
isRemovedFromConversation={conversation.removed_from_conversation()}
262-
/>
263-
)}
270+
<div css={deliveredMessageIndicator}>
271+
{showDeliveredMessageIcon && (
272+
<div data-uie-name="status-message-read-receipt-delivered" title={t('conversationMessageDelivered')}>
273+
<Icon.OutlineCheck />
274+
</div>
275+
)}
276+
</div>
264277
</div>
265278

266279
{[StatusType.FAILED, StatusType.FEDERATION_ERROR].includes(status) && (

src/script/components/MessagesList/Message/ContentMessage/asset/index.tsx

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ interface ContentAssetProps {
5454
selfId: QualifiedId;
5555
isMessageFocused: boolean;
5656
is1to1Conversation: boolean;
57-
isLastDeliveredMessage: boolean;
5857
onClickDetails: () => void;
5958
}
6059

@@ -67,7 +66,6 @@ const ContentAsset = ({
6766
onClickButton,
6867
isMessageFocused,
6968
is1to1Conversation,
70-
isLastDeliveredMessage,
7169
onClickDetails,
7270
}: ContentAssetProps) => {
7371
const {isObfuscated, status} = useKoSubscribableChildren(message, ['isObfuscated', 'status']);
@@ -96,25 +94,15 @@ const ContentAsset = ({
9694
)}
9795

9896
{shouldRenderText && (
99-
<ReadIndicator
100-
message={message}
101-
is1to1Conversation={is1to1Conversation}
102-
isLastDeliveredMessage={isLastDeliveredMessage}
103-
onClick={onClickDetails}
104-
/>
97+
<ReadIndicator message={message} is1to1Conversation={is1to1Conversation} onClick={onClickDetails} />
10598
)}
10699

107100
{previews.map(() => (
108101
<div key={asset.id} className="message-asset">
109102
<LinkPreviewAsset message={message} isFocusable={isMessageFocused} />
110103

111104
{!shouldRenderText && (
112-
<ReadIndicator
113-
message={message}
114-
is1to1Conversation={is1to1Conversation}
115-
isLastDeliveredMessage={isLastDeliveredMessage}
116-
onClick={onClickDetails}
117-
/>
105+
<ReadIndicator message={message} is1to1Conversation={is1to1Conversation} onClick={onClickDetails} />
118106
)}
119107
</div>
120108
))}

src/script/components/MessagesList/Message/PingMessage.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919

2020
import cx from 'classnames';
2121

22+
import {Icon} from 'Components/Icon';
2223
import {useKoSubscribableChildren} from 'Util/ComponentUtil';
24+
import {t} from 'Util/LocalizerUtil';
25+
import {checkIsMessageDelivered} from 'Util/util';
2326

2427
import {ReadReceiptStatus} from './ReadReceiptStatus';
2528

@@ -32,10 +35,17 @@ export interface PingMessageProps {
3235
}
3336

3437
const PingMessage = ({message, is1to1Conversation, isLastDeliveredMessage}: PingMessageProps) => {
35-
const {unsafeSenderName, caption, ephemeral_caption, isObfuscated, get_icon_classes} = useKoSubscribableChildren(
36-
message,
37-
['unsafeSenderName', 'caption', 'ephemeral_caption', 'isObfuscated', 'get_icon_classes'],
38-
);
38+
const {unsafeSenderName, caption, ephemeral_caption, isObfuscated, get_icon_classes, readReceipts} =
39+
useKoSubscribableChildren(message, [
40+
'unsafeSenderName',
41+
'caption',
42+
'ephemeral_caption',
43+
'isObfuscated',
44+
'get_icon_classes',
45+
'readReceipts',
46+
]);
47+
48+
const showDeliveredMessageIcon = checkIsMessageDelivered(isLastDeliveredMessage, readReceipts);
3949

4050
return (
4151
<div className="message-header" data-uie-name="element-message-ping">
@@ -45,6 +55,7 @@ const PingMessage = ({message, is1to1Conversation, isLastDeliveredMessage}: Ping
4555
<div
4656
className={cx('message-header-label', {
4757
'ephemeral-message-obfuscated': isObfuscated,
58+
'message-header-ping-delivered': showDeliveredMessageIcon,
4859
})}
4960
title={ephemeral_caption}
5061
data-uie-name="element-message-ping-text"
@@ -54,11 +65,13 @@ const PingMessage = ({message, is1to1Conversation, isLastDeliveredMessage}: Ping
5465
<span className="ellipsis">{caption}</span>
5566
</p>
5667

57-
<ReadReceiptStatus
58-
message={message}
59-
is1to1Conversation={is1to1Conversation}
60-
isLastDeliveredMessage={isLastDeliveredMessage}
61-
/>
68+
{showDeliveredMessageIcon ? (
69+
<div className="message-ping-delivered-icon" title={t('conversationMessageDelivered')}>
70+
<Icon.OutlineCheck />
71+
</div>
72+
) : (
73+
<ReadReceiptStatus message={message} is1to1Conversation={is1to1Conversation} />
74+
)}
6275
</div>
6376
</div>
6477
);

src/script/components/MessagesList/Message/ReadIndicator/ReadIndicator.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import {Icon} from 'Components/Icon';
2121
import {useKoSubscribableChildren} from 'Util/ComponentUtil';
22-
import {t} from 'Util/LocalizerUtil';
2322
import {formatTimeShort} from 'Util/TimeUtil';
2423

2524
import {ReadIndicatorContainer, ReadIndicatorStyles, ReadReceiptText} from './ReadIndicator.styles';
@@ -29,31 +28,24 @@ import {Message} from '../../../../entity/message/Message';
2928
interface ReadIndicatorProps {
3029
message: Message;
3130
is1to1Conversation?: boolean;
32-
isLastDeliveredMessage?: boolean;
3331
showIconOnly?: boolean;
3432
onClick?: (message: Message) => void;
3533
}
3634

3735
export const ReadIndicator = ({
3836
message,
3937
is1to1Conversation = false,
40-
isLastDeliveredMessage = false,
4138
showIconOnly = false,
4239
onClick,
4340
}: ReadIndicatorProps) => {
4441
const {readReceipts} = useKoSubscribableChildren(message, ['readReceipts']);
4542

4643
if (is1to1Conversation) {
4744
const readReceiptText = readReceipts.length ? formatTimeShort(readReceipts[0].time) : '';
48-
const showDeliveredMessage = isLastDeliveredMessage && readReceiptText === '';
4945

5046
return (
5147
<div css={ReadIndicatorContainer} className="read-indicator-wrapper">
5248
<span css={ReadIndicatorStyles(showIconOnly)} data-uie-name="status-message-read-receipts">
53-
{showDeliveredMessage && (
54-
<span data-uie-name="status-message-read-receipt-delivered">{t('conversationMessageDelivered')}</span>
55-
)}
56-
5749
{showIconOnly && readReceiptText && <Icon.Read />}
5850

5951
{!showIconOnly && !!readReceiptText && (

0 commit comments

Comments
 (0)