Merge remote-tracking branch 'yougotwill/feature/ses-379/composition-rtl-support' into feature/ses-379/composition-rtl-support
This commit is contained in:
commit
bee00157ef
|
@ -5,12 +5,14 @@ import { getFocusedSettingsSection } from '../state/selectors/section';
|
||||||
|
|
||||||
import { SmartSessionConversation } from '../state/smart/SessionConversation';
|
import { SmartSessionConversation } from '../state/smart/SessionConversation';
|
||||||
import { SessionSettingsView } from './settings/SessionSettings';
|
import { SessionSettingsView } from './settings/SessionSettings';
|
||||||
|
import { useHTMLDirection } from '../util/i18n';
|
||||||
|
|
||||||
const FilteredSettingsView = SessionSettingsView as any;
|
const FilteredSettingsView = SessionSettingsView as any;
|
||||||
|
|
||||||
export const SessionMainPanel = () => {
|
export const SessionMainPanel = () => {
|
||||||
const focusedSettingsSection = useSelector(getFocusedSettingsSection);
|
const focusedSettingsSection = useSelector(getFocusedSettingsSection);
|
||||||
const isSettingsView = focusedSettingsSection !== undefined;
|
const isSettingsView = focusedSettingsSection !== undefined;
|
||||||
|
const htmlDirection = useHTMLDirection();
|
||||||
|
|
||||||
// even if it looks like this does nothing, this does update the redux store.
|
// even if it looks like this does nothing, this does update the redux store.
|
||||||
useAppIsFocused();
|
useAppIsFocused();
|
||||||
|
@ -20,7 +22,7 @@ export const SessionMainPanel = () => {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="session-conversation">
|
<div className="session-conversation">
|
||||||
<SmartSessionConversation />
|
<SmartSessionConversation htmlDirection={htmlDirection} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { HTMLDirection } from '../../util/i18n';
|
||||||
|
|
||||||
export interface FlexProps {
|
export interface FlexProps {
|
||||||
children?: any;
|
children?: any;
|
||||||
|
@ -6,7 +7,7 @@ export interface FlexProps {
|
||||||
container?: boolean;
|
container?: boolean;
|
||||||
dataTestId?: string;
|
dataTestId?: string;
|
||||||
// Container Props
|
// Container Props
|
||||||
flexDirection?: 'row' | 'column';
|
flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
|
||||||
justifyContent?:
|
justifyContent?:
|
||||||
| 'flex-start'
|
| 'flex-start'
|
||||||
| 'flex-end'
|
| 'flex-end'
|
||||||
|
@ -36,6 +37,8 @@ export interface FlexProps {
|
||||||
maxWidth?: string;
|
maxWidth?: string;
|
||||||
minWidth?: string;
|
minWidth?: string;
|
||||||
maxHeight?: string;
|
maxHeight?: string;
|
||||||
|
// RTL support
|
||||||
|
dir?: HTMLDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Flex = styled.div<FlexProps>`
|
export const Flex = styled.div<FlexProps>`
|
||||||
|
@ -53,4 +56,5 @@ export const Flex = styled.div<FlexProps>`
|
||||||
height: ${props => props.height || 'auto'};
|
height: ${props => props.height || 'auto'};
|
||||||
max-width: ${props => props.maxWidth || 'none'};
|
max-width: ${props => props.maxWidth || 'none'};
|
||||||
min-width: ${props => props.minWidth || 'none'};
|
min-width: ${props => props.minWidth || 'none'};
|
||||||
|
direction: ${props => props.dir || undefined};
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -53,6 +53,7 @@ import { SessionRightPanelWithDetails } from './SessionRightPanel';
|
||||||
import { NoMessageInConversation } from './SubtleNotification';
|
import { NoMessageInConversation } from './SubtleNotification';
|
||||||
import { MessageDetail } from './message/message-item/MessageDetail';
|
import { MessageDetail } from './message/message-item/MessageDetail';
|
||||||
|
|
||||||
|
import { HTMLDirection } from '../../util/i18n';
|
||||||
import { SessionSpinner } from '../basic/SessionSpinner';
|
import { SessionSpinner } from '../basic/SessionSpinner';
|
||||||
|
|
||||||
const DEFAULT_JPEG_QUALITY = 0.85;
|
const DEFAULT_JPEG_QUALITY = 0.85;
|
||||||
|
@ -74,6 +75,7 @@ interface Props {
|
||||||
showMessageDetails: boolean;
|
showMessageDetails: boolean;
|
||||||
isRightPanelShowing: boolean;
|
isRightPanelShowing: boolean;
|
||||||
hasOngoingCallWithFocusedConvo: boolean;
|
hasOngoingCallWithFocusedConvo: boolean;
|
||||||
|
htmlDirection: HTMLDirection;
|
||||||
|
|
||||||
// lightbox options
|
// lightbox options
|
||||||
lightBoxOptions?: LightBoxOptions;
|
lightBoxOptions?: LightBoxOptions;
|
||||||
|
@ -289,6 +291,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
||||||
stagedAttachments={this.props.stagedAttachments}
|
stagedAttachments={this.props.stagedAttachments}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
onChoseAttachments={this.onChoseAttachments}
|
onChoseAttachments={this.onChoseAttachments}
|
||||||
|
htmlDirection={this.props.htmlDirection}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -69,7 +69,7 @@ export const StyledEmojiPanel = styled.div<{
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(100% - 40px);
|
top: calc(100% - 40px);
|
||||||
left: calc(100% - 79px);
|
left: calc(100% - 106px);
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
|
@ -78,6 +78,10 @@ export const StyledEmojiPanel = styled.div<{
|
||||||
border: 0.7px solid var(--border-color);
|
border: 0.7px solid var(--border-color);
|
||||||
clip-path: polygon(100% 100%, 7.2px 100%, 100% 7.2px);
|
clip-path: polygon(100% 100%, 7.2px 100%, 100% 7.2px);
|
||||||
${props.panelBackgroundRGB && `background-color: rgb(${props.panelBackgroundRGB})`};
|
${props.panelBackgroundRGB && `background-color: rgb(${props.panelBackgroundRGB})`};
|
||||||
|
|
||||||
|
[dir='rtl'] & {
|
||||||
|
left: 75px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`};
|
`};
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,16 +36,17 @@ import {
|
||||||
StagedAttachmentImportedType,
|
StagedAttachmentImportedType,
|
||||||
StagedPreviewImportedType,
|
StagedPreviewImportedType,
|
||||||
} from '../../../util/attachmentsUtil';
|
} from '../../../util/attachmentsUtil';
|
||||||
|
import { HTMLDirection } from '../../../util/i18n';
|
||||||
import { LinkPreviews } from '../../../util/linkPreviews';
|
import { LinkPreviews } from '../../../util/linkPreviews';
|
||||||
import { Flex } from '../../basic/Flex';
|
|
||||||
import { CaptionEditor } from '../../CaptionEditor';
|
import { CaptionEditor } from '../../CaptionEditor';
|
||||||
|
import { Flex } from '../../basic/Flex';
|
||||||
import { getMediaPermissionsSettings } from '../../settings/SessionSettings';
|
import { getMediaPermissionsSettings } from '../../settings/SessionSettings';
|
||||||
import { getDraftForConversation, updateDraftForConversation } from '../SessionConversationDrafts';
|
import { getDraftForConversation, updateDraftForConversation } from '../SessionConversationDrafts';
|
||||||
import { SessionQuotedMessageComposition } from '../SessionQuotedMessageComposition';
|
import { SessionQuotedMessageComposition } from '../SessionQuotedMessageComposition';
|
||||||
import {
|
import {
|
||||||
getPreview,
|
|
||||||
LINK_PREVIEW_TIMEOUT,
|
LINK_PREVIEW_TIMEOUT,
|
||||||
SessionStagedLinkPreview,
|
SessionStagedLinkPreview,
|
||||||
|
getPreview,
|
||||||
} from '../SessionStagedLinkPreview';
|
} from '../SessionStagedLinkPreview';
|
||||||
import { StagedAttachmentList } from '../StagedAttachmentList';
|
import { StagedAttachmentList } from '../StagedAttachmentList';
|
||||||
import {
|
import {
|
||||||
|
@ -108,6 +109,7 @@ interface Props {
|
||||||
quotedMessageProps?: ReplyingToMessageProps;
|
quotedMessageProps?: ReplyingToMessageProps;
|
||||||
stagedAttachments: Array<StagedAttachmentType>;
|
stagedAttachments: Array<StagedAttachmentType>;
|
||||||
onChoseAttachments: (newAttachments: Array<File>) => void;
|
onChoseAttachments: (newAttachments: Array<File>) => void;
|
||||||
|
htmlDirection: HTMLDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
@ -119,26 +121,28 @@ interface State {
|
||||||
showCaptionEditor?: AttachmentType;
|
showCaptionEditor?: AttachmentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendMessageStyle = {
|
const sendMessageStyle = (dir?: HTMLDirection) => {
|
||||||
control: {
|
return {
|
||||||
wordBreak: 'break-all',
|
control: {
|
||||||
},
|
wordBreak: 'break-all',
|
||||||
input: {
|
},
|
||||||
overflow: 'auto',
|
input: {
|
||||||
maxHeight: '50vh',
|
overflow: 'auto',
|
||||||
wordBreak: 'break-word',
|
maxHeight: '50vh',
|
||||||
padding: '0px',
|
wordBreak: 'break-word',
|
||||||
margin: '0px',
|
padding: '0px',
|
||||||
},
|
margin: '0px',
|
||||||
highlighter: {
|
},
|
||||||
boxSizing: 'border-box',
|
highlighter: {
|
||||||
overflow: 'hidden',
|
boxSizing: 'border-box',
|
||||||
maxHeight: '50vh',
|
overflow: 'hidden',
|
||||||
},
|
maxHeight: '50vh',
|
||||||
flexGrow: 1,
|
},
|
||||||
minHeight: '24px',
|
flexGrow: 1,
|
||||||
width: '100%',
|
minHeight: '24px',
|
||||||
...styleForCompositionBoxSuggestions,
|
width: '100%',
|
||||||
|
...styleForCompositionBoxSuggestions(dir),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDefaultState = (newConvoId?: string) => {
|
const getDefaultState = (newConvoId?: string) => {
|
||||||
|
@ -209,21 +213,23 @@ const getSelectionBasedOnMentions = (draft: string, index: number) => {
|
||||||
return Number.MAX_SAFE_INTEGER;
|
return Number.MAX_SAFE_INTEGER;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledEmojiPanelContainer = styled.div`
|
const StyledEmojiPanelContainer = styled.div<{ dir?: HTMLDirection }>`
|
||||||
${StyledEmojiPanel} {
|
${StyledEmojiPanel} {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 68px;
|
bottom: 68px;
|
||||||
right: 0px;
|
${props => (props.dir === 'rtl' ? 'left: 0px' : 'right: 0px;')}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledSendMessageInput = styled.div`
|
const StyledSendMessageInput = styled.div<{ dir?: HTMLDirection }>`
|
||||||
|
position: relative;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-height: var(--composition-container-height);
|
min-height: var(--composition-container-height);
|
||||||
padding: var(--margins-xs) 0;
|
padding: var(--margins-xs) 0;
|
||||||
|
${props => props.dir === 'rtl' && 'margin-inline-start: var(--margins-sm);'}
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
|
|
||||||
|
@ -235,7 +241,7 @@ const StyledSendMessageInput = styled.div`
|
||||||
textarea {
|
textarea {
|
||||||
font-family: var(--font-default);
|
font-family: var(--font-default);
|
||||||
min-height: calc(var(--composition-container-height) / 3);
|
min-height: calc(var(--composition-container-height) / 3);
|
||||||
max-height: 3 * var(--composition-container-height);
|
max-height: calc(3 * var(--composition-container-height));
|
||||||
margin-right: var(--margins-md);
|
margin-right: var(--margins-md);
|
||||||
color: var(--text-color-primary);
|
color: var(--text-color-primary);
|
||||||
|
|
||||||
|
@ -417,7 +423,13 @@ class CompositionBoxInner extends React.Component<Props, State> {
|
||||||
/* eslint-disable @typescript-eslint/no-misused-promises */
|
/* eslint-disable @typescript-eslint/no-misused-promises */
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Flex
|
||||||
|
dir={this.props.htmlDirection}
|
||||||
|
container={true}
|
||||||
|
flexDirection={'row'}
|
||||||
|
alignItems={'center'}
|
||||||
|
width={'100%'}
|
||||||
|
>
|
||||||
{typingEnabled && <AddStagedAttachmentButton onClick={this.onChooseAttachment} />}
|
{typingEnabled && <AddStagedAttachmentButton onClick={this.onChooseAttachment} />}
|
||||||
<input
|
<input
|
||||||
className="hidden"
|
className="hidden"
|
||||||
|
@ -430,6 +442,7 @@ class CompositionBoxInner extends React.Component<Props, State> {
|
||||||
{typingEnabled && <StartRecordingButton onClick={this.onLoadVoiceNoteView} />}
|
{typingEnabled && <StartRecordingButton onClick={this.onLoadVoiceNoteView} />}
|
||||||
<StyledSendMessageInput
|
<StyledSendMessageInput
|
||||||
role="main"
|
role="main"
|
||||||
|
dir={this.props.htmlDirection}
|
||||||
onClick={this.focusCompositionBox} // used to focus on the textarea when clicking in its container
|
onClick={this.focusCompositionBox} // used to focus on the textarea when clicking in its container
|
||||||
ref={el => {
|
ref={el => {
|
||||||
this.container = el;
|
this.container = el;
|
||||||
|
@ -443,7 +456,7 @@ class CompositionBoxInner extends React.Component<Props, State> {
|
||||||
)}
|
)}
|
||||||
{typingEnabled && <SendMessageButton onClick={this.onSendMessage} />}
|
{typingEnabled && <SendMessageButton onClick={this.onSendMessage} />}
|
||||||
{typingEnabled && showEmojiPanel && (
|
{typingEnabled && showEmojiPanel && (
|
||||||
<StyledEmojiPanelContainer role="button">
|
<StyledEmojiPanelContainer role="button" dir={this.props.htmlDirection}>
|
||||||
<SessionEmojiPanel
|
<SessionEmojiPanel
|
||||||
ref={this.emojiPanel}
|
ref={this.emojiPanel}
|
||||||
show={showEmojiPanel}
|
show={showEmojiPanel}
|
||||||
|
@ -452,7 +465,7 @@ class CompositionBoxInner extends React.Component<Props, State> {
|
||||||
/>
|
/>
|
||||||
</StyledEmojiPanelContainer>
|
</StyledEmojiPanelContainer>
|
||||||
)}
|
)}
|
||||||
</>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/* eslint-enable @typescript-eslint/no-misused-promises */
|
/* eslint-enable @typescript-eslint/no-misused-promises */
|
||||||
|
@ -460,6 +473,7 @@ class CompositionBoxInner extends React.Component<Props, State> {
|
||||||
private renderTextArea() {
|
private renderTextArea() {
|
||||||
const { i18n } = window;
|
const { i18n } = window;
|
||||||
const { draft } = this.state;
|
const { draft } = this.state;
|
||||||
|
const { htmlDirection } = this.props;
|
||||||
|
|
||||||
if (!this.props.selectedConversation) {
|
if (!this.props.selectedConversation) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -483,6 +497,8 @@ class CompositionBoxInner extends React.Component<Props, State> {
|
||||||
const { typingEnabled } = this.props;
|
const { typingEnabled } = this.props;
|
||||||
const neverMatchingRegex = /($a)/;
|
const neverMatchingRegex = /($a)/;
|
||||||
|
|
||||||
|
const style = sendMessageStyle(htmlDirection);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MentionsInput
|
<MentionsInput
|
||||||
value={draft}
|
value={draft}
|
||||||
|
@ -493,11 +509,12 @@ class CompositionBoxInner extends React.Component<Props, State> {
|
||||||
onKeyUp={this.onKeyUp}
|
onKeyUp={this.onKeyUp}
|
||||||
placeholder={messagePlaceHolder}
|
placeholder={messagePlaceHolder}
|
||||||
spellCheck={true}
|
spellCheck={true}
|
||||||
|
dir={htmlDirection}
|
||||||
inputRef={this.textarea}
|
inputRef={this.textarea}
|
||||||
disabled={!typingEnabled}
|
disabled={!typingEnabled}
|
||||||
rows={1}
|
rows={1}
|
||||||
data-testid="message-input-text-area"
|
data-testid="message-input-text-area"
|
||||||
style={sendMessageStyle}
|
style={style}
|
||||||
suggestionsPortalHost={this.container as any}
|
suggestionsPortalHost={this.container as any}
|
||||||
forceSuggestionsAboveCursor={true} // force mentions to be rendered on top of the cursor, this is working with a fork of react-mentions for now
|
forceSuggestionsAboveCursor={true} // force mentions to be rendered on top of the cursor, this is working with a fork of react-mentions for now
|
||||||
>
|
>
|
||||||
|
@ -507,7 +524,9 @@ class CompositionBoxInner extends React.Component<Props, State> {
|
||||||
markup="@ᅭ__id__ᅲ__display__ᅭ" // ᅭ = \uFFD2 is one of the forbidden char for a display name (check displayNameRegex)
|
markup="@ᅭ__id__ᅲ__display__ᅭ" // ᅭ = \uFFD2 is one of the forbidden char for a display name (check displayNameRegex)
|
||||||
trigger="@"
|
trigger="@"
|
||||||
// this is only for the composition box visible content. The real stuff on the backend box is the @markup
|
// this is only for the composition box visible content. The real stuff on the backend box is the @markup
|
||||||
displayTransform={(_id, display) => `@${display}`}
|
displayTransform={(_id, display) =>
|
||||||
|
htmlDirection === 'rtl' ? `${display}@` : `@${display}`
|
||||||
|
}
|
||||||
data={this.fetchUsersForGroup}
|
data={this.fetchUsersForGroup}
|
||||||
renderSuggestion={renderUserMentionRow}
|
renderSuggestion={renderUserMentionRow}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { searchSync } from '../../../util/emoji.js';
|
||||||
const EmojiQuickResult = styled.span`
|
const EmojiQuickResult = styled.span`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
min-width: 250px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-inline-end: 20px;
|
padding-inline-end: 20px;
|
||||||
padding-inline-start: 10px;
|
padding-inline-start: 10px;
|
||||||
|
|
|
@ -1,28 +1,40 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SuggestionDataItem } from 'react-mentions';
|
import { SuggestionDataItem } from 'react-mentions';
|
||||||
import { MemberListItem } from '../../MemberListItem';
|
import { MemberListItem } from '../../MemberListItem';
|
||||||
|
import { HTMLDirection } from '../../../util/i18n';
|
||||||
|
|
||||||
export const styleForCompositionBoxSuggestions = {
|
const listRTLStyle = { position: 'absolute', bottom: '0px', right: '100%' };
|
||||||
suggestions: {
|
|
||||||
list: {
|
|
||||||
fontSize: 14,
|
|
||||||
boxShadow: 'var(--suggestions-shadow)',
|
|
||||||
backgroundColor: 'var(--suggestions-background-color)',
|
|
||||||
color: 'var(--suggestions-text-color)',
|
|
||||||
},
|
|
||||||
item: {
|
|
||||||
height: '100%',
|
|
||||||
paddingTop: '5px',
|
|
||||||
paddingBottom: '5px',
|
|
||||||
backgroundColor: 'var(--suggestions-background-color)',
|
|
||||||
color: 'var(--suggestions-text-color)',
|
|
||||||
transition: '0.25s',
|
|
||||||
|
|
||||||
'&focused': {
|
export const styleForCompositionBoxSuggestions = (dir: HTMLDirection = 'ltr') => {
|
||||||
backgroundColor: 'var(--suggestions-background-hover-color)',
|
const styles = {
|
||||||
|
suggestions: {
|
||||||
|
list: {
|
||||||
|
fontSize: 14,
|
||||||
|
boxShadow: 'var(--suggestions-shadow)',
|
||||||
|
backgroundColor: 'var(--suggestions-background-color)',
|
||||||
|
color: 'var(--suggestions-text-color)',
|
||||||
|
dir,
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
height: '100%',
|
||||||
|
paddingTop: '5px',
|
||||||
|
paddingBottom: '5px',
|
||||||
|
backgroundColor: 'var(--suggestions-background-color)',
|
||||||
|
color: 'var(--suggestions-text-color)',
|
||||||
|
transition: '0.25s',
|
||||||
|
|
||||||
|
'&focused': {
|
||||||
|
backgroundColor: 'var(--suggestions-background-hover-color)',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
|
|
||||||
|
if (dir === 'rtl') {
|
||||||
|
styles.suggestions.list = { ...styles.suggestions.list, ...listRTLStyle };
|
||||||
|
}
|
||||||
|
|
||||||
|
return styles;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const renderUserMentionRow = (suggestion: SuggestionDataItem) => {
|
export const renderUserMentionRow = (suggestion: SuggestionDataItem) => {
|
||||||
|
|
|
@ -366,12 +366,6 @@ export const MarkAllReadMenuItem = (): JSX.Element | null => {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function isRtlBody(): boolean {
|
|
||||||
const body = document.getElementsByTagName('body').item(0);
|
|
||||||
|
|
||||||
return body?.classList.contains('rtl') || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const BlockMenuItem = (): JSX.Element | null => {
|
export const BlockMenuItem = (): JSX.Element | null => {
|
||||||
const convoId = useConvoIdFromContext();
|
const convoId = useConvoIdFromContext();
|
||||||
const isMe = useIsMe(convoId);
|
const isMe = useIsMe(convoId);
|
||||||
|
@ -577,7 +571,7 @@ export const NotificationForConvoMenuItem = (): JSX.Element | null => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const isRtlMode = isRtlBody();'
|
// const isRtlMode = isRtlBody();
|
||||||
|
|
||||||
// exclude mentions_only settings for private chats as this does not make much sense
|
// exclude mentions_only settings for private chats as this does not make much sense
|
||||||
const notificationForConvoOptions = ConversationNotificationSetting.filter(n =>
|
const notificationForConvoOptions = ConversationNotificationSetting.filter(n =>
|
||||||
|
|
|
@ -751,8 +751,9 @@ app.on('ready', async () => {
|
||||||
assertLogger().info('app ready');
|
assertLogger().info('app ready');
|
||||||
assertLogger().info(`starting version ${packageJson.version}`);
|
assertLogger().info(`starting version ${packageJson.version}`);
|
||||||
if (!locale) {
|
if (!locale) {
|
||||||
const appLocale = app.getLocale() || 'en';
|
const appLocale = process.env.LANGUAGE || app.getLocale() || 'en';
|
||||||
locale = loadLocale({ appLocale, logger });
|
locale = loadLocale({ appLocale, logger });
|
||||||
|
assertLogger().info(`locale is ${appLocale}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = getDefaultSQLKey();
|
const key = getDefaultSQLKey();
|
||||||
|
|
|
@ -16,8 +16,13 @@ import { getSelectedConversationKey } from '../selectors/selectedConversation';
|
||||||
import { getStagedAttachmentsForCurrentConversation } from '../selectors/stagedAttachments';
|
import { getStagedAttachmentsForCurrentConversation } from '../selectors/stagedAttachments';
|
||||||
import { getTheme } from '../selectors/theme';
|
import { getTheme } from '../selectors/theme';
|
||||||
import { getOurNumber } from '../selectors/user';
|
import { getOurNumber } from '../selectors/user';
|
||||||
|
import { HTMLDirection } from '../../util/i18n';
|
||||||
|
|
||||||
const mapStateToProps = (state: StateType) => {
|
type SmartSessionConversationOwnProps = {
|
||||||
|
htmlDirection: HTMLDirection;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state: StateType, ownProps: SmartSessionConversationOwnProps) => {
|
||||||
return {
|
return {
|
||||||
selectedConversation: getSelectedConversation(state),
|
selectedConversation: getSelectedConversation(state),
|
||||||
selectedConversationKey: getSelectedConversationKey(state),
|
selectedConversationKey: getSelectedConversationKey(state),
|
||||||
|
@ -31,6 +36,7 @@ const mapStateToProps = (state: StateType) => {
|
||||||
stagedAttachments: getStagedAttachmentsForCurrentConversation(state),
|
stagedAttachments: getStagedAttachmentsForCurrentConversation(state),
|
||||||
hasOngoingCallWithFocusedConvo: getHasOngoingCallWithFocusedConvo(state),
|
hasOngoingCallWithFocusedConvo: getHasOngoingCallWithFocusedConvo(state),
|
||||||
isSelectedConvoInitialLoadingInProgress: getIsSelectedConvoInitialLoadingInProgress(state),
|
isSelectedConvoInitialLoadingInProgress: getIsSelectedConvoInitialLoadingInProgress(state),
|
||||||
|
htmlDirection: ownProps.htmlDirection,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -67,3 +67,15 @@ export const loadEmojiPanelI18n = async () => {
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// RTL Support
|
||||||
|
|
||||||
|
export type HTMLDirection = 'ltr' | 'rtl';
|
||||||
|
|
||||||
|
export function isRtlBody(): boolean {
|
||||||
|
const body = document.getElementsByTagName('body').item(0);
|
||||||
|
|
||||||
|
return body?.classList.contains('rtl') || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useHTMLDirection = (): HTMLDirection => (isRtlBody() ? 'rtl' : 'ltr');
|
||||||
|
|
Loading…
Reference in New Issue