Skip to content

Commit

Permalink
Notify story creator for replies
Browse files Browse the repository at this point in the history
  • Loading branch information
jamiebuilds-signal committed Oct 11, 2022
1 parent 512d655 commit 25bc163
Show file tree
Hide file tree
Showing 16 changed files with 250 additions and 135 deletions.
14 changes: 12 additions & 2 deletions ts/background.ts
Expand Up @@ -154,6 +154,7 @@ import { SeenStatus } from './MessageSeenStatus';
import MessageSender from './textsecure/SendMessage';
import type AccountManager from './textsecure/AccountManager';
import { onStoryRecipientUpdate } from './util/onStoryRecipientUpdate';
import { StoryViewModeType, StoryViewTargetType } from './types/Stories';

const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;

Expand Down Expand Up @@ -1879,10 +1880,19 @@ export async function startApp(): Promise<void> {
activeWindowService.registerForActive(() => notificationService.clear());
window.addEventListener('unload', () => notificationService.fastClear());

notificationService.on('click', (id, messageId) => {
notificationService.on('click', (id, messageId, storyId) => {
window.showWindow();

if (id) {
window.Whisper.events.trigger('showConversation', id, messageId);
if (storyId) {
window.reduxActions.stories.viewStory({
storyId,
storyViewMode: StoryViewModeType.Single,
viewTarget: StoryViewTargetType.Replies,
});
} else {
window.Whisper.events.trigger('showConversation', id, messageId);
}
} else {
window.reduxActions.app.openInbox();
}
Expand Down
5 changes: 3 additions & 2 deletions ts/components/MyStories.tsx
Expand Up @@ -3,11 +3,12 @@

import React, { useState } from 'react';
import type { MyStoryType, StoryViewType } from '../types/Stories';
import { StoryViewTargetType, StoryViewModeType } from '../types/Stories';
import type { LocalizerType } from '../types/Util';
import type { ViewStoryActionCreatorType } from '../state/ducks/stories';
import { ConfirmationDialog } from './ConfirmationDialog';
import { ContextMenu } from './ContextMenu';
import { StoryViewModeType } from '../types/Stories';

import { MessageTimestamp } from './conversation/MessageTimestamp';
import { StoryDistributionListName } from './StoryDistributionListName';
import { StoryImage } from './StoryImage';
Expand Down Expand Up @@ -151,7 +152,7 @@ export const MyStories = ({
viewStory({
storyId: story.messageId,
storyViewMode: StoryViewModeType.User,
shouldShowDetailsModal: true,
viewTarget: StoryViewTargetType.Details,
});
},
},
Expand Down
8 changes: 6 additions & 2 deletions ts/components/StoryListItem.tsx
Expand Up @@ -5,13 +5,14 @@ import React, { useState } from 'react';
import classNames from 'classnames';
import type { ConversationType } from '../state/ducks/conversations';
import type { ConversationStoryType, StoryViewType } from '../types/Stories';
import { StoryViewTargetType, HasStories } from '../types/Stories';
import type { LocalizerType } from '../types/Util';
import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
import type { ViewUserStoriesActionCreatorType } from '../state/ducks/stories';
import { Avatar, AvatarSize } from './Avatar';
import { ConfirmationDialog } from './ConfirmationDialog';
import { ContextMenu } from './ContextMenu';
import { HasStories } from '../types/Stories';

import { MessageTimestamp } from './conversation/MessageTimestamp';
import { StoryImage } from './StoryImage';
import { ThemeType } from '../types/Util';
Expand Down Expand Up @@ -134,7 +135,10 @@ export const StoryListItem = ({
icon: 'StoryListItem__icon--info',
label: i18n('StoryListItem__info'),
onClick: () =>
viewUserStories({ conversationId, shouldShowDetailsModal: true }),
viewUserStories({
conversationId,
viewTarget: StoryViewTargetType.Details,
}),
},
{
icon: 'StoryListItem__icon--chat',
Expand Down
56 changes: 33 additions & 23 deletions ts/components/StoryViewer.tsx
Expand Up @@ -31,7 +31,11 @@ import { SendStatus } from '../messages/MessageSendState';
import { StoryDetailsModal } from './StoryDetailsModal';
import { StoryDistributionListName } from './StoryDistributionListName';
import { StoryImage } from './StoryImage';
import { StoryViewDirectionType, StoryViewModeType } from '../types/Stories';
import {
StoryViewDirectionType,
StoryViewModeType,
StoryViewTargetType,
} from '../types/Stories';
import { StoryViewsNRepliesModal } from './StoryViewsNRepliesModal';
import { Theme } from '../util/theme';
import { ToastType } from '../state/ducks/toast';
Expand Down Expand Up @@ -83,7 +87,7 @@ export type PropsType = {
recentEmojis?: Array<string>;
renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element;
replyState?: ReplyStateType;
shouldShowDetailsModal?: boolean;
viewTarget?: StoryViewTargetType;
showToast: ShowToastActionCreatorType;
skinTone?: number;
story: StoryViewType;
Expand Down Expand Up @@ -128,7 +132,7 @@ export const StoryViewer = ({
recentEmojis,
renderEmojiPicker,
replyState,
shouldShowDetailsModal,
viewTarget,
showToast,
skinTone,
story,
Expand Down Expand Up @@ -167,25 +171,27 @@ export const StoryViewer = ({

const conversationId = group?.id || story.sender.id;

const [hasStoryViewsNRepliesModal, setHasStoryViewsNRepliesModal] =
useState(false);
const [hasStoryDetailsModal, setHasStoryDetailsModal] = useState(
Boolean(shouldShowDetailsModal)
const [currentViewTarget, setCurrentViewTarget] = useState(
viewTarget ?? null
);

useEffect(() => {
setCurrentViewTarget(viewTarget ?? null);
}, [viewTarget]);

const onClose = useCallback(() => {
viewStory({
closeViewer: true,
});
}, [viewStory]);

const onEscape = useCallback(() => {
if (hasStoryViewsNRepliesModal) {
setHasStoryViewsNRepliesModal(false);
if (currentViewTarget != null) {
setCurrentViewTarget(null);
} else {
onClose();
}
}, [hasStoryViewsNRepliesModal, onClose]);
}, [currentViewTarget, onClose]);

useEscapeHandling(onEscape);

Expand Down Expand Up @@ -314,8 +320,7 @@ export const StoryViewer = ({
hasActiveCall ||
hasConfirmHideStory ||
hasExpandedCaption ||
hasStoryDetailsModal ||
hasStoryViewsNRepliesModal ||
currentViewTarget != null ||
isShowingContextMenu ||
pauseStory ||
Boolean(reactionEmoji);
Expand Down Expand Up @@ -351,7 +356,7 @@ export const StoryViewer = ({
(ev: KeyboardEvent) => {
// the replies modal can consume arrow keys
// we don't want to navigate while someone is typing a reply
if (hasStoryViewsNRepliesModal) {
if (currentViewTarget != null) {
return;
}

Expand All @@ -374,7 +379,7 @@ export const StoryViewer = ({
}
},
[
hasStoryViewsNRepliesModal,
currentViewTarget,
canNavigateLeft,
canNavigateRight,
story.messageId,
Expand Down Expand Up @@ -466,7 +471,7 @@ export const StoryViewer = ({
{
icon: 'StoryListItem__icon--info',
label: i18n('StoryListItem__info'),
onClick: () => setHasStoryDetailsModal(true),
onClick: () => setCurrentViewTarget(StoryViewTargetType.Details),
},
{
icon: 'StoryListItem__icon--delete',
Expand All @@ -478,7 +483,7 @@ export const StoryViewer = ({
{
icon: 'StoryListItem__icon--info',
label: i18n('StoryListItem__info'),
onClick: () => setHasStoryDetailsModal(true),
onClick: () => setCurrentViewTarget(StoryViewTargetType.Details),
},
{
icon: 'StoryListItem__icon--hide',
Expand Down Expand Up @@ -726,7 +731,9 @@ export const StoryViewer = ({
{(canReply || isSent) && (
<button
className="StoryViewer__reply"
onClick={() => setHasStoryViewsNRepliesModal(true)}
onClick={() =>
setCurrentViewTarget(StoryViewTargetType.Replies)
}
tabIndex={0}
type="button"
>
Expand Down Expand Up @@ -788,19 +795,20 @@ export const StoryViewer = ({
type="button"
/>
</div>
{hasStoryDetailsModal && (
{currentViewTarget === StoryViewTargetType.Details && (
<StoryDetailsModal
getPreferredBadge={getPreferredBadge}
i18n={i18n}
onClose={() => setHasStoryDetailsModal(false)}
onClose={() => setCurrentViewTarget(null)}
sender={story.sender}
sendState={sendState}
size={attachment?.size}
timestamp={timestamp}
expirationTimestamp={story.expirationTimestamp}
/>
)}
{hasStoryViewsNRepliesModal && (
{(currentViewTarget === StoryViewTargetType.Replies ||
currentViewTarget === StoryViewTargetType.Views) && (
<StoryViewsNRepliesModal
authorTitle={firstName || title}
canReply={Boolean(canReply)}
Expand All @@ -809,18 +817,18 @@ export const StoryViewer = ({
hasViewsCapability={isSent}
i18n={i18n}
isGroupStory={isGroupStory}
onClose={() => setHasStoryViewsNRepliesModal(false)}
onClose={() => setCurrentViewTarget(null)}
onReact={emoji => {
onReactToStory(emoji, story);
if (!isGroupStory) {
setHasStoryViewsNRepliesModal(false);
setCurrentViewTarget(null);
showToast(ToastType.StoryReact);
}
setReactionEmoji(emoji);
}}
onReply={(message, mentions, replyTimestamp) => {
if (!isGroupStory) {
setHasStoryViewsNRepliesModal(false);
setCurrentViewTarget(null);
showToast(ToastType.StoryReply);
}
onReplyToStory(message, mentions, replyTimestamp, story);
Expand All @@ -836,6 +844,8 @@ export const StoryViewer = ({
sortedGroupMembers={group?.sortedGroupMembers}
storyPreviewAttachment={attachment}
views={views}
viewTarget={currentViewTarget}
onChangeViewTarget={setCurrentViewTarget}
/>
)}
{hasConfirmHideStory && (
Expand Down
26 changes: 23 additions & 3 deletions ts/components/StoryViewsNRepliesModal.stories.tsx
Expand Up @@ -4,6 +4,7 @@
import type { Meta, Story } from '@storybook/react';
import React from 'react';

import { useArgs } from '@storybook/addons';
import type { PropsType } from './StoryViewsNRepliesModal';
import * as durations from '../util/durations';
import enMessages from '../../_locales/en/messages.json';
Expand All @@ -14,6 +15,7 @@ import { UUID } from '../types/UUID';
import { fakeAttachment } from '../test-both/helpers/fakeAttachment';
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
import { setupI18n } from '../util/setupI18n';
import { StoryViewTargetType } from '../types/Stories';

const i18n = setupI18n('en', enMessages);

Expand Down Expand Up @@ -64,6 +66,12 @@ export default {
views: {
defaultValue: [],
},
viewTarget: {
defaultValue: StoryViewTargetType.Views,
},
onChangeViewTarget: {
action: true,
},
},
} as Meta;

Expand Down Expand Up @@ -161,9 +169,21 @@ function getViewsAndReplies() {
};
}

const Template: Story<PropsType> = args => (
<StoryViewsNRepliesModal {...args} />
);
const Template: Story<PropsType> = args => {
const [, updateArgs] = useArgs();

function onChangeViewTarget(viewTarget: StoryViewTargetType) {
args.onChangeViewTarget(viewTarget);
updateArgs({ viewTarget });
}

return (
<StoryViewsNRepliesModal
{...args}
onChangeViewTarget={onChangeViewTarget}
/>
);
};

export const CanReply = Template.bind({});
CanReply.args = {};
Expand Down

0 comments on commit 25bc163

Please sign in to comment.