mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2025-12-19 17:58:48 +00:00
Add pinned message notifications
This commit is contained in:
@@ -3408,6 +3408,14 @@
|
||||
"messageformat": "You donated for {recipient}",
|
||||
"description": "Shown to label a donation badge you've sent in notifications and the left pane"
|
||||
},
|
||||
"icu:message--pinned--preview--received": {
|
||||
"messageformat": "{sender} pinned a message",
|
||||
"description": "Shown to label pinned message notification in notifications and the left pane."
|
||||
},
|
||||
"icu:message--pinned--preview--sent": {
|
||||
"messageformat": "You pinned a message",
|
||||
"description": "Shown to label pinned message notification in notifications and the left pane."
|
||||
},
|
||||
"icu:message--donation": {
|
||||
"messageformat": "Donation",
|
||||
"description": "Shown to label the donation badge you've redeemed on another device."
|
||||
|
||||
@@ -232,26 +232,27 @@ function TabTrigger(props: {
|
||||
);
|
||||
}
|
||||
|
||||
type ContentProps = Readonly<{
|
||||
i18n: LocalizerType;
|
||||
pin: Pin;
|
||||
onPinGoTo: (messageId: string) => void;
|
||||
onPinRemove: (messageId: string) => void;
|
||||
onPinsShowAll: () => void;
|
||||
canPinMessages: boolean;
|
||||
}>;
|
||||
|
||||
const Content = forwardRef(function Content(
|
||||
props: {
|
||||
i18n: LocalizerType;
|
||||
pin: Pin;
|
||||
onPinGoTo: (messageId: string) => void;
|
||||
onPinRemove: (messageId: string) => void;
|
||||
onPinsShowAll: () => void;
|
||||
canPinMessages: boolean;
|
||||
},
|
||||
ref: ForwardedRef<HTMLDivElement>
|
||||
): JSX.Element {
|
||||
const {
|
||||
{
|
||||
i18n,
|
||||
pin,
|
||||
onPinGoTo,
|
||||
onPinRemove,
|
||||
onPinsShowAll,
|
||||
canPinMessages,
|
||||
...forwardedProps
|
||||
} = props;
|
||||
|
||||
}: ContentProps,
|
||||
ref: ForwardedRef<HTMLDivElement>
|
||||
): JSX.Element {
|
||||
const handlePinGoTo = useCallback(() => {
|
||||
onPinGoTo(pin.message.id);
|
||||
}, [onPinGoTo, pin.message.id]);
|
||||
@@ -277,10 +278,10 @@ const Content = forwardRef(function Content(
|
||||
{thumbnailUrl != null && <ImageThumbnail url={thumbnailUrl} />}
|
||||
<div className={tw('min-w-0 flex-1')}>
|
||||
<h1 className={tw('type-body-small font-semibold text-label-primary')}>
|
||||
<UserText text={props.pin.sender.title} />
|
||||
<UserText text={pin.sender.title} />
|
||||
</h1>
|
||||
<p className={tw('me-2 truncate type-body-medium text-label-primary')}>
|
||||
<MessagePreview i18n={i18n} message={props.pin.message} />
|
||||
<MessagePreview i18n={i18n} message={pin.message} />
|
||||
</p>
|
||||
<AriaClickable.HiddenTrigger
|
||||
aria-label={i18n(
|
||||
@@ -302,7 +303,7 @@ const Content = forwardRef(function Content(
|
||||
/>
|
||||
</AxoDropdownMenu.Trigger>
|
||||
<AxoDropdownMenu.Content>
|
||||
{props.canPinMessages && (
|
||||
{canPinMessages && (
|
||||
<AxoDropdownMenu.Item
|
||||
symbol="pin-slash"
|
||||
onSelect={handlePinRemove}
|
||||
|
||||
@@ -93,6 +93,13 @@ export async function onPinnedMessageAdd(
|
||||
}
|
||||
}
|
||||
|
||||
if (result.change?.inserted) {
|
||||
await targetConversation.addNotification('pinned-message-notification', {
|
||||
pinnedMessageId: targetMessage.id,
|
||||
sourceServiceId: props.pinnedByAci,
|
||||
});
|
||||
}
|
||||
|
||||
window.reduxActions.pinnedMessages.onPinnedMessagesChanged(
|
||||
targetConversation.id
|
||||
);
|
||||
|
||||
@@ -1933,7 +1933,8 @@ export class BackupExportStream extends Readable {
|
||||
}
|
||||
|
||||
if (isPinnedMessageNotification(message)) {
|
||||
throw new Error('unimplemented');
|
||||
// TODO(jamie): Implement backups for pinned messages
|
||||
return { kind: NonBubbleResultKind.Drop };
|
||||
}
|
||||
|
||||
if (isProfileChange(message)) {
|
||||
|
||||
@@ -134,6 +134,11 @@ function onPinnedMessageAdd(
|
||||
): StateThunk {
|
||||
return async dispatch => {
|
||||
const target = await getPinnedMessageTarget(targetMessageId);
|
||||
const targetConversation = window.ConversationController.get(
|
||||
target.conversationId
|
||||
);
|
||||
strictAssert(targetConversation != null, 'Missing target conversation');
|
||||
|
||||
await conversationJobQueue.add({
|
||||
type: conversationQueueJobEnum.enum.PinMessage,
|
||||
...target,
|
||||
@@ -152,6 +157,11 @@ function onPinnedMessageAdd(
|
||||
pinnedAt,
|
||||
});
|
||||
|
||||
await targetConversation.addNotification('pinned-message-notification', {
|
||||
pinnedMessageId: targetMessageId,
|
||||
sourceServiceId: itemStorage.user.getCheckedAci(),
|
||||
});
|
||||
|
||||
dispatch(onPinnedMessagesChanged(target.conversationId));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -512,7 +512,21 @@ export function getNotificationDataForMessage(
|
||||
}
|
||||
|
||||
if (isPinnedMessageNotification(attributes)) {
|
||||
throw new Error('unimplemented');
|
||||
const fromContact = getAuthor(attributes);
|
||||
const ourAci = itemStorage.user.getCheckedAci();
|
||||
|
||||
let text: string;
|
||||
if (fromContact?.getAci() === ourAci) {
|
||||
text = i18n('icu:message--pinned--preview--sent');
|
||||
} else {
|
||||
const sender = fromContact?.getTitle() ?? i18n('icu:unknownContact');
|
||||
text = i18n('icu:message--pinned--preview--received', { sender });
|
||||
}
|
||||
|
||||
return {
|
||||
emoji: '📌',
|
||||
text,
|
||||
};
|
||||
}
|
||||
|
||||
const { poll } = attributes;
|
||||
|
||||
Reference in New Issue
Block a user