Universal Disappearing Messages
This commit is contained in:
parent
c63871d71b
commit
19f8042cd3
50 changed files with 1224 additions and 191 deletions
|
@ -13,6 +13,7 @@ import {
|
|||
} from 'react-contextmenu';
|
||||
|
||||
import { Emojify } from './Emojify';
|
||||
import { DisappearingTimeDialog } from './DisappearingTimeDialog';
|
||||
import { Avatar, AvatarSize } from '../Avatar';
|
||||
import { InContactsIcon } from '../InContactsIcon';
|
||||
|
||||
|
@ -92,10 +93,18 @@ export type PropsType = PropsDataType &
|
|||
PropsActionsType &
|
||||
PropsHousekeepingType;
|
||||
|
||||
enum ModalState {
|
||||
NothingOpen,
|
||||
CustomDisappearingTimeout,
|
||||
}
|
||||
|
||||
type StateType = {
|
||||
isNarrow: boolean;
|
||||
modalState: ModalState;
|
||||
};
|
||||
|
||||
const TIMER_ITEM_CLASS = 'module-ConversationHeader__disappearing-timer__item';
|
||||
|
||||
export class ConversationHeader extends React.Component<PropsType, StateType> {
|
||||
private showMenuBound: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
|
||||
|
@ -106,7 +115,7 @@ export class ConversationHeader extends React.Component<PropsType, StateType> {
|
|||
public constructor(props: PropsType) {
|
||||
super(props);
|
||||
|
||||
this.state = { isNarrow: false };
|
||||
this.state = { isNarrow: false, modalState: ModalState.NothingOpen };
|
||||
|
||||
this.menuTriggerRef = React.createRef();
|
||||
this.showMenuBound = this.showMenu.bind(this);
|
||||
|
@ -355,6 +364,7 @@ export class ConversationHeader extends React.Component<PropsType, StateType> {
|
|||
i18n,
|
||||
acceptedMessageRequest,
|
||||
canChangeTimer,
|
||||
expireTimer,
|
||||
isArchived,
|
||||
isMe,
|
||||
isPinned,
|
||||
|
@ -427,23 +437,60 @@ export class ConversationHeader extends React.Component<PropsType, StateType> {
|
|||
|
||||
const hasGV2AdminEnabled = isGroup && groupVersion === 2;
|
||||
|
||||
const isActiveExpireTimer = (value: number): boolean => {
|
||||
if (!expireTimer) {
|
||||
return value === 0;
|
||||
}
|
||||
|
||||
// Custom time...
|
||||
if (value === -1) {
|
||||
return !expirationTimer.DEFAULT_DURATIONS_SET.has(expireTimer);
|
||||
}
|
||||
return value === expireTimer;
|
||||
};
|
||||
|
||||
const expireDurations: ReadonlyArray<ReactNode> = [
|
||||
...expirationTimer.DEFAULT_DURATIONS_IN_SECONDS,
|
||||
-1,
|
||||
].map((seconds: number) => {
|
||||
let text: string;
|
||||
|
||||
if (seconds === -1) {
|
||||
text = i18n('customDisappearingTimeOption');
|
||||
} else {
|
||||
text = expirationTimer.format(i18n, seconds, {
|
||||
capitalizeOff: true,
|
||||
});
|
||||
}
|
||||
|
||||
const onDurationClick = () => {
|
||||
if (seconds === -1) {
|
||||
this.setState({
|
||||
modalState: ModalState.CustomDisappearingTimeout,
|
||||
});
|
||||
} else {
|
||||
onSetDisappearingMessages(seconds);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<MenuItem key={seconds} onClick={onDurationClick}>
|
||||
<div
|
||||
className={classNames(
|
||||
TIMER_ITEM_CLASS,
|
||||
isActiveExpireTimer(seconds) && `${TIMER_ITEM_CLASS}--active`
|
||||
)}
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
</MenuItem>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<ContextMenu id={triggerId}>
|
||||
{disableTimerChanges ? null : (
|
||||
<SubMenu title={disappearingTitle}>
|
||||
{expirationTimer.DEFAULT_DURATIONS_IN_SECONDS.map(
|
||||
(seconds: number) => (
|
||||
<MenuItem
|
||||
key={seconds}
|
||||
onClick={() => {
|
||||
onSetDisappearingMessages(seconds);
|
||||
}}
|
||||
>
|
||||
{expirationTimer.format(i18n, seconds)}
|
||||
</MenuItem>
|
||||
)
|
||||
)}
|
||||
</SubMenu>
|
||||
<SubMenu title={disappearingTitle}>{expireDurations}</SubMenu>
|
||||
)}
|
||||
<SubMenu title={muteTitle}>
|
||||
{muteOptions.map(item => (
|
||||
|
@ -578,36 +625,64 @@ export class ConversationHeader extends React.Component<PropsType, StateType> {
|
|||
}
|
||||
|
||||
public render(): ReactNode {
|
||||
const { id, isSMSOnly } = this.props;
|
||||
const { isNarrow } = this.state;
|
||||
const {
|
||||
id,
|
||||
isSMSOnly,
|
||||
i18n,
|
||||
onSetDisappearingMessages,
|
||||
expireTimer,
|
||||
} = this.props;
|
||||
const { isNarrow, modalState } = this.state;
|
||||
const triggerId = `conversation-${id}`;
|
||||
|
||||
let modalNode: ReactNode;
|
||||
if (modalState === ModalState.NothingOpen) {
|
||||
modalNode = undefined;
|
||||
} else if (modalState === ModalState.CustomDisappearingTimeout) {
|
||||
modalNode = (
|
||||
<DisappearingTimeDialog
|
||||
i18n={i18n}
|
||||
initialValue={expireTimer}
|
||||
onSubmit={value => {
|
||||
this.setState({ modalState: ModalState.NothingOpen });
|
||||
onSetDisappearingMessages(value);
|
||||
}}
|
||||
onClose={() => this.setState({ modalState: ModalState.NothingOpen })}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
throw missingCaseError(modalState);
|
||||
}
|
||||
|
||||
return (
|
||||
<Measure
|
||||
bounds
|
||||
onResize={({ bounds }) => {
|
||||
if (!bounds || !bounds.width) {
|
||||
return;
|
||||
}
|
||||
this.setState({ isNarrow: bounds.width < 500 });
|
||||
}}
|
||||
>
|
||||
{({ measureRef }) => (
|
||||
<div
|
||||
className={classNames('module-ConversationHeader', {
|
||||
'module-ConversationHeader--narrow': isNarrow,
|
||||
})}
|
||||
ref={measureRef}
|
||||
>
|
||||
{this.renderBackButton()}
|
||||
{this.renderHeader()}
|
||||
{!isSMSOnly && this.renderOutgoingCallButtons()}
|
||||
{this.renderSearchButton()}
|
||||
{this.renderMoreButton(triggerId)}
|
||||
{this.renderMenu(triggerId)}
|
||||
</div>
|
||||
)}
|
||||
</Measure>
|
||||
<>
|
||||
{modalNode}
|
||||
<Measure
|
||||
bounds
|
||||
onResize={({ bounds }) => {
|
||||
if (!bounds || !bounds.width) {
|
||||
return;
|
||||
}
|
||||
this.setState({ isNarrow: bounds.width < 500 });
|
||||
}}
|
||||
>
|
||||
{({ measureRef }) => (
|
||||
<div
|
||||
className={classNames('module-ConversationHeader', {
|
||||
'module-ConversationHeader--narrow': isNarrow,
|
||||
})}
|
||||
ref={measureRef}
|
||||
>
|
||||
{this.renderBackButton()}
|
||||
{this.renderHeader()}
|
||||
{!isSMSOnly && this.renderOutgoingCallButtons()}
|
||||
{this.renderSearchButton()}
|
||||
{this.renderMoreButton(triggerId)}
|
||||
{this.renderMenu(triggerId)}
|
||||
</div>
|
||||
)}
|
||||
</Measure>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue