UI for when read receipts are turned off
This commit is contained in:
parent
7632f31cf2
commit
39143015c5
8 changed files with 135 additions and 33 deletions
|
@ -7487,6 +7487,10 @@
|
||||||
"message": "Unmute",
|
"message": "Unmute",
|
||||||
"description": "Aria label for unmuting stories"
|
"description": "Aria label for unmuting stories"
|
||||||
},
|
},
|
||||||
|
"StoryViewer__views-off": {
|
||||||
|
"message": "Views off",
|
||||||
|
"description": "When the user has read receipts turned off"
|
||||||
|
},
|
||||||
"StoryDetailsModal__sent-time": {
|
"StoryDetailsModal__sent-time": {
|
||||||
"message": "Sent $time$",
|
"message": "Sent $time$",
|
||||||
"description": "Sent timestamp",
|
"description": "Sent timestamp",
|
||||||
|
@ -7511,6 +7515,10 @@
|
||||||
"message": "Copy timestamp",
|
"message": "Copy timestamp",
|
||||||
"description": "Context menu item to help debugging"
|
"description": "Context menu item to help debugging"
|
||||||
},
|
},
|
||||||
|
"StoryViewsNRepliesModal__read-receipts-off": {
|
||||||
|
"message": "Enable read receipts to see who's viewed your stories. Open the Signal app on your mobile device and navigate to Settings > Privacy.",
|
||||||
|
"description": "Instructions on how to enable read receipts"
|
||||||
|
},
|
||||||
"StoryViewsNRepliesModal__no-replies": {
|
"StoryViewsNRepliesModal__no-replies": {
|
||||||
"message": "No replies yet",
|
"message": "No replies yet",
|
||||||
"description": "Placeholder text for when there are no replies"
|
"description": "Placeholder text for when there are no replies"
|
||||||
|
|
|
@ -208,6 +208,11 @@
|
||||||
&__copy-icon {
|
&__copy-icon {
|
||||||
@include color-svg('../images/icons/v2/copy-outline-24.svg', $color-white);
|
@include color-svg('../images/icons/v2/copy-outline-24.svg', $color-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__read-receipts-off {
|
||||||
|
color: $color-gray-25;
|
||||||
|
margin: 160px 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.Tabs.StoryViewsNRepliesModal__tabs {
|
.Tabs.StoryViewsNRepliesModal__tabs {
|
||||||
|
|
|
@ -31,6 +31,9 @@ export default {
|
||||||
hasAllStoriesMuted: {
|
hasAllStoriesMuted: {
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
},
|
},
|
||||||
|
hasReadReceiptSetting: {
|
||||||
|
defaultValue: true,
|
||||||
|
},
|
||||||
i18n: {
|
i18n: {
|
||||||
defaultValue: i18n,
|
defaultValue: i18n,
|
||||||
},
|
},
|
||||||
|
@ -168,3 +171,35 @@ export const YourStory = Template.bind({});
|
||||||
};
|
};
|
||||||
YourStory.storyName = 'Your story';
|
YourStory.storyName = 'Your story';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ReadReceiptsOff = Template.bind({});
|
||||||
|
{
|
||||||
|
const storyView = getFakeStoryView(
|
||||||
|
'/fixtures/nathan-anderson-316188-unsplash.jpg'
|
||||||
|
);
|
||||||
|
ReadReceiptsOff.args = {
|
||||||
|
hasReadReceiptSetting: false,
|
||||||
|
story: {
|
||||||
|
...storyView,
|
||||||
|
sender: {
|
||||||
|
...storyView.sender,
|
||||||
|
isMe: true,
|
||||||
|
},
|
||||||
|
sendState: [
|
||||||
|
{
|
||||||
|
recipient: getDefaultConversation(),
|
||||||
|
status: SendStatus.Viewed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
recipient: getDefaultConversation(),
|
||||||
|
status: SendStatus.Delivered,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
recipient: getDefaultConversation(),
|
||||||
|
status: SendStatus.Pending,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ReadReceiptsOff.storyName = 'Read receipts turned off';
|
||||||
|
|
|
@ -59,6 +59,7 @@ export type PropsType = {
|
||||||
>;
|
>;
|
||||||
hasActiveCall?: boolean;
|
hasActiveCall?: boolean;
|
||||||
hasAllStoriesMuted: boolean;
|
hasAllStoriesMuted: boolean;
|
||||||
|
hasReadReceiptSetting: boolean;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
loadStoryReplies: (conversationId: string, messageId: string) => unknown;
|
loadStoryReplies: (conversationId: string, messageId: string) => unknown;
|
||||||
markStoryRead: (mId: string) => unknown;
|
markStoryRead: (mId: string) => unknown;
|
||||||
|
@ -107,6 +108,7 @@ export const StoryViewer = ({
|
||||||
group,
|
group,
|
||||||
hasActiveCall,
|
hasActiveCall,
|
||||||
hasAllStoriesMuted,
|
hasAllStoriesMuted,
|
||||||
|
hasReadReceiptSetting,
|
||||||
i18n,
|
i18n,
|
||||||
loadStoryReplies,
|
loadStoryReplies,
|
||||||
markStoryRead,
|
markStoryRead,
|
||||||
|
@ -661,7 +663,11 @@ export const StoryViewer = ({
|
||||||
<>
|
<>
|
||||||
{sendState || replyCount > 0 ? (
|
{sendState || replyCount > 0 ? (
|
||||||
<span className="StoryViewer__reply__chevron">
|
<span className="StoryViewer__reply__chevron">
|
||||||
|
{sendState && !hasReadReceiptSetting && !replyCount && (
|
||||||
|
<>{i18n('StoryViewer__views-off')}</>
|
||||||
|
)}
|
||||||
{sendState &&
|
{sendState &&
|
||||||
|
hasReadReceiptSetting &&
|
||||||
(viewCount === 1 ? (
|
(viewCount === 1 ? (
|
||||||
<Intl
|
<Intl
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
@ -749,6 +755,7 @@ export const StoryViewer = ({
|
||||||
authorTitle={firstName || title}
|
authorTitle={firstName || title}
|
||||||
canReply={Boolean(canReply)}
|
canReply={Boolean(canReply)}
|
||||||
getPreferredBadge={getPreferredBadge}
|
getPreferredBadge={getPreferredBadge}
|
||||||
|
hasReadReceiptSetting={hasReadReceiptSetting}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
isGroupStory={isGroupStory}
|
isGroupStory={isGroupStory}
|
||||||
onClose={() => setHasStoryViewsNRepliesModal(false)}
|
onClose={() => setHasStoryViewsNRepliesModal(false)}
|
||||||
|
|
|
@ -28,6 +28,9 @@ export default {
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
},
|
},
|
||||||
getPreferredBadge: { action: true },
|
getPreferredBadge: { action: true },
|
||||||
|
hasReadReceiptSetting: {
|
||||||
|
defaultValue: true,
|
||||||
|
},
|
||||||
i18n: {
|
i18n: {
|
||||||
defaultValue: i18n,
|
defaultValue: i18n,
|
||||||
},
|
},
|
||||||
|
@ -202,3 +205,23 @@ export const InAGroupCantReply = Template.bind({});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
InAGroupCantReply.storyName = "In a group (can't reply)";
|
InAGroupCantReply.storyName = "In a group (can't reply)";
|
||||||
|
|
||||||
|
export const ReadReceiptsTurnedOff = Template.bind({});
|
||||||
|
ReadReceiptsTurnedOff.args = {
|
||||||
|
canReply: false,
|
||||||
|
hasReadReceiptSetting: false,
|
||||||
|
views: getViewsAndReplies().views,
|
||||||
|
};
|
||||||
|
ReadReceiptsTurnedOff.storyName = 'Read receipts turned off';
|
||||||
|
|
||||||
|
export const GroupReadReceiptsOff = Template.bind({});
|
||||||
|
{
|
||||||
|
const { views, replies } = getViewsAndReplies();
|
||||||
|
GroupReadReceiptsOff.args = {
|
||||||
|
hasReadReceiptSetting: false,
|
||||||
|
isGroupStory: true,
|
||||||
|
replies,
|
||||||
|
views,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
GroupReadReceiptsOff.storyName = 'Read receipts turned off (group)';
|
||||||
|
|
|
@ -87,6 +87,7 @@ export type PropsType = {
|
||||||
authorTitle: string;
|
authorTitle: string;
|
||||||
canReply: boolean;
|
canReply: boolean;
|
||||||
getPreferredBadge: PreferredBadgeSelectorType;
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
|
hasReadReceiptSetting: boolean;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
isGroupStory?: boolean;
|
isGroupStory?: boolean;
|
||||||
onClose: () => unknown;
|
onClose: () => unknown;
|
||||||
|
@ -113,6 +114,7 @@ export const StoryViewsNRepliesModal = ({
|
||||||
authorTitle,
|
authorTitle,
|
||||||
canReply,
|
canReply,
|
||||||
getPreferredBadge,
|
getPreferredBadge,
|
||||||
|
hasReadReceiptSetting,
|
||||||
i18n,
|
i18n,
|
||||||
isGroupStory,
|
isGroupStory,
|
||||||
onClose,
|
onClose,
|
||||||
|
@ -353,40 +355,52 @@ export const StoryViewsNRepliesModal = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewsElement = views.length ? (
|
let viewsElement: JSX.Element | undefined;
|
||||||
<div className="StoryViewsNRepliesModal__views">
|
if (!hasReadReceiptSetting) {
|
||||||
{views.map(view => (
|
viewsElement = (
|
||||||
<div className="StoryViewsNRepliesModal__view" key={view.recipient.id}>
|
<div className="StoryViewsNRepliesModal__read-receipts-off">
|
||||||
<div>
|
{i18n('StoryViewsNRepliesModal__read-receipts-off')}
|
||||||
<Avatar
|
</div>
|
||||||
acceptedMessageRequest={view.recipient.acceptedMessageRequest}
|
);
|
||||||
avatarPath={view.recipient.avatarPath}
|
} else if (views.length) {
|
||||||
badge={undefined}
|
viewsElement = (
|
||||||
color={getAvatarColor(view.recipient.color)}
|
<div className="StoryViewsNRepliesModal__views">
|
||||||
conversationType="direct"
|
{views.map(view => (
|
||||||
i18n={i18n}
|
<div
|
||||||
isMe={Boolean(view.recipient.isMe)}
|
className="StoryViewsNRepliesModal__view"
|
||||||
name={view.recipient.name}
|
key={view.recipient.id}
|
||||||
profileName={view.recipient.profileName}
|
>
|
||||||
sharedGroupNames={view.recipient.sharedGroupNames || []}
|
<div>
|
||||||
size={AvatarSize.TWENTY_EIGHT}
|
<Avatar
|
||||||
title={view.recipient.title}
|
acceptedMessageRequest={view.recipient.acceptedMessageRequest}
|
||||||
/>
|
avatarPath={view.recipient.avatarPath}
|
||||||
<span className="StoryViewsNRepliesModal__view--name">
|
badge={undefined}
|
||||||
<ContactName title={view.recipient.title} />
|
color={getAvatarColor(view.recipient.color)}
|
||||||
</span>
|
conversationType="direct"
|
||||||
|
i18n={i18n}
|
||||||
|
isMe={Boolean(view.recipient.isMe)}
|
||||||
|
name={view.recipient.name}
|
||||||
|
profileName={view.recipient.profileName}
|
||||||
|
sharedGroupNames={view.recipient.sharedGroupNames || []}
|
||||||
|
size={AvatarSize.TWENTY_EIGHT}
|
||||||
|
title={view.recipient.title}
|
||||||
|
/>
|
||||||
|
<span className="StoryViewsNRepliesModal__view--name">
|
||||||
|
<ContactName title={view.recipient.title} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{view.updatedAt && (
|
||||||
|
<MessageTimestamp
|
||||||
|
i18n={i18n}
|
||||||
|
module="StoryViewsNRepliesModal__view--timestamp"
|
||||||
|
timestamp={view.updatedAt}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{view.updatedAt && (
|
))}
|
||||||
<MessageTimestamp
|
</div>
|
||||||
i18n={i18n}
|
);
|
||||||
module="StoryViewsNRepliesModal__view--timestamp"
|
}
|
||||||
timestamp={view.updatedAt}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : undefined;
|
|
||||||
|
|
||||||
const tabsElement =
|
const tabsElement =
|
||||||
views.length && replies.length ? (
|
views.length && replies.length ? (
|
||||||
|
|
|
@ -130,3 +130,8 @@ export const getHasSetMyStoriesPrivacy = createSelector(
|
||||||
getItems,
|
getItems,
|
||||||
(state: ItemsStateType): boolean => Boolean(state.hasSetMyStoriesPrivacy)
|
(state: ItemsStateType): boolean => Boolean(state.hasSetMyStoriesPrivacy)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getHasReadReceiptSetting = createSelector(
|
||||||
|
getItems,
|
||||||
|
(state: ItemsStateType): boolean => Boolean(state['read-receipt-setting'])
|
||||||
|
);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { getConversationSelector } from '../selectors/conversations';
|
||||||
import {
|
import {
|
||||||
getEmojiSkinTone,
|
getEmojiSkinTone,
|
||||||
getHasAllStoriesMuted,
|
getHasAllStoriesMuted,
|
||||||
|
getHasReadReceiptSetting,
|
||||||
getPreferredReactionEmoji,
|
getPreferredReactionEmoji,
|
||||||
} from '../selectors/items';
|
} from '../selectors/items';
|
||||||
import { getIntl } from '../selectors/user';
|
import { getIntl } from '../selectors/user';
|
||||||
|
@ -76,6 +77,9 @@ export function SmartStoryViewer(): JSX.Element | null {
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasActiveCall = useSelector(isInFullScreenCall);
|
const hasActiveCall = useSelector(isInFullScreenCall);
|
||||||
|
const hasReadReceiptSetting = useSelector<StateType, boolean>(
|
||||||
|
getHasReadReceiptSetting
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StoryViewer
|
<StoryViewer
|
||||||
|
@ -84,6 +88,7 @@ export function SmartStoryViewer(): JSX.Element | null {
|
||||||
group={conversationStory.group}
|
group={conversationStory.group}
|
||||||
hasActiveCall={hasActiveCall}
|
hasActiveCall={hasActiveCall}
|
||||||
hasAllStoriesMuted={hasAllStoriesMuted}
|
hasAllStoriesMuted={hasAllStoriesMuted}
|
||||||
|
hasReadReceiptSetting={hasReadReceiptSetting}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
numStories={selectedStoryData.numStories}
|
numStories={selectedStoryData.numStories}
|
||||||
onHideStory={toggleHideStories}
|
onHideStory={toggleHideStories}
|
||||||
|
|
Loading…
Reference in a new issue