Skip to content

Commit 2e9d8c1

Browse files
authored
chore: Merge 4.73.1 into master (#7370)
2 parents c351658 + df1e2be commit 2e9d8c1

34 files changed

Lines changed: 1313 additions & 362 deletions

File tree

CLAUDE.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ pnpm storybook:start # Start Metro with Storybook UI
4040
pnpm storybook-generate # Generate story snapshots
4141
```
4242

43-
## Worktree contract
44-
45-
When using worktrees (`wt`), the post-start hook runs `pnpm install` only. `wt step copy-ignored` is opt-in and only used when the worktree will perform a native build (iOS/Android/Pods/Gradle/Bundler caches).
46-
4743
## Code Style
4844

4945
- **Prettier**: tabs, single quotes, 130 char width, no trailing commas, arrow parens avoid, bracket same line

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Also check the [#react-native](https://open.rocket.chat/channel/react-native) co
2626
Are you a dev and would like to help? Found a bug that you would like to report or a missing feature that you would like to work on? Great! We have written down a [Contribution guide](https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/CONTRIBUTING.md) so you can start easily.
2727

2828
## Whitelabel
29-
Do you want to make the app run on your own server only? [Follow our whitelabel documentation.](https://developer.rocket.chat/mobile-app/mobile-app-white-labelling)
29+
Do you want to make the app run on your own server only? [Follow our whitelabel documentation.](https://developer.rocket.chat/mobile-app-white-labelling)
3030

3131
## Engage with us
3232
### Share your story

android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ android {
9090
minSdkVersion rootProject.ext.minSdkVersion
9191
targetSdkVersion rootProject.ext.targetSdkVersion
9292
versionCode VERSIONCODE as Integer
93-
versionName "4.73.0"
93+
versionName "4.73.1"
9494
vectorDrawables.useSupportLibrary = true
9595
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
9696
resValue "string", "rn_config_reader_custom_package", "chat.rocket.reactnative"

android/app/src/main/java/chat/rocket/reactnative/notification/NotificationIntentHandler.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,4 @@ class NotificationIntentHandler {
170170
}
171171
}
172172
}
173+

app/actions/actionsTypes.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ export const ROOM = createRequestTypes('ROOM', [
2222
'FORWARD',
2323
'USER_TYPING',
2424
'HISTORY_REQUEST',
25-
'HISTORY_FINISHED'
25+
'HISTORY_FINISHED',
26+
'HISTORY_UI_LOADER_PUSH',
27+
'HISTORY_UI_LOADER_POP'
2628
]);
2729
export const INQUIRY = createRequestTypes('INQUIRY', [
2830
...defaultTypes,

app/actions/room.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,24 @@ export interface IRoomHistoryFinished extends Action {
5959
loaderId: string;
6060
}
6161

62+
export interface IRoomHistoryUiLoaderPush extends Action {
63+
loaderId: string;
64+
}
65+
66+
export interface IRoomHistoryUiLoaderPop extends Action {
67+
loaderId: string;
68+
}
69+
6270
export type TActionsRoom = TSubscribeRoom &
6371
TUnsubscribeRoom &
6472
ILeaveRoom &
6573
IDeleteRoom &
6674
IForwardRoom &
6775
IUserTyping &
6876
IRoomHistoryRequest &
69-
IRoomHistoryFinished;
77+
IRoomHistoryFinished &
78+
IRoomHistoryUiLoaderPush &
79+
IRoomHistoryUiLoaderPop;
7080

7181
export function subscribeRoom(rid: string): TSubscribeRoom {
7282
return {
@@ -138,3 +148,17 @@ export function roomHistoryFinished({ loaderId }: { loaderId: string }): IRoomHi
138148
loaderId
139149
};
140150
}
151+
152+
export function roomHistoryUiLoaderPush({ loaderId }: { loaderId: string }): IRoomHistoryUiLoaderPush {
153+
return {
154+
type: ROOM.HISTORY_UI_LOADER_PUSH,
155+
loaderId
156+
};
157+
}
158+
159+
export function roomHistoryUiLoaderPop({ loaderId }: { loaderId: string }): IRoomHistoryUiLoaderPop {
160+
return {
161+
type: ROOM.HISTORY_UI_LOADER_POP,
162+
loaderId
163+
};
164+
}

app/containers/markdown/index.tsx

Lines changed: 95 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import Paragraph from './components/Paragraph';
1818
import { Code } from './components/code';
1919
import Heading from './components/Heading';
2020
import log from '../../lib/methods/helpers/log';
21+
import styles from './styles';
2122

2223
export { default as MarkdownPreview } from './components/Preview';
2324

@@ -35,6 +36,71 @@ interface IMarkdownProps {
3536
textStyle?: StyleProp<TextStyle>;
3637
}
3738

39+
type MarkdownBlock = Root[number];
40+
41+
const PARSE_CACHE_MAX = 200;
42+
const parseCache = new Map<string, Root>();
43+
44+
const parseMessage = (msg: string): Root => {
45+
const cached = parseCache.get(msg);
46+
if (cached) {
47+
return cached;
48+
}
49+
50+
const result = parse(msg);
51+
52+
if (parseCache.size >= PARSE_CACHE_MAX) {
53+
const oldestKey = parseCache.keys().next().value;
54+
if (oldestKey !== undefined) {
55+
parseCache.delete(oldestKey);
56+
}
57+
}
58+
59+
parseCache.set(msg, result);
60+
return result;
61+
};
62+
63+
const resolveTokens = (msg: string, md: Root | undefined, isTranslated?: boolean): Root => {
64+
if (!isTranslated && md) {
65+
return md;
66+
}
67+
68+
return parseMessage(typeof msg === 'string' ? msg : String(msg || ''));
69+
};
70+
71+
const MarkdownBlockView = ({ block }: { block: MarkdownBlock }) => {
72+
'use memo';
73+
74+
switch (block.type) {
75+
case 'BIG_EMOJI':
76+
return <BigEmoji value={block.value} />;
77+
case 'UNORDERED_LIST':
78+
return <UnorderedList value={block.value} />;
79+
case 'ORDERED_LIST':
80+
return <OrderedList value={block.value} />;
81+
case 'TASKS':
82+
return <TaskList value={block.value} />;
83+
case 'QUOTE':
84+
return <Quote value={block.value} />;
85+
case 'PARAGRAPH':
86+
return <Paragraph value={block.value} />;
87+
case 'CODE':
88+
return <Code value={block.value} />;
89+
case 'HEADING':
90+
return <Heading value={block.value} level={block.level} />;
91+
case 'LINE_BREAK':
92+
return <LineBreak />;
93+
// This prop exists, but not even on the web it is treated, so...
94+
// https://github.com/RocketChat/Rocket.Chat/blob/develop/packages/gazzodown/src/Markup.tsx
95+
// case 'LIST_ITEM':
96+
// return <View />;
97+
case 'KATEX':
98+
return <KaTeX value={block.value} />;
99+
default:
100+
return null;
101+
}
102+
};
103+
38104
const Markdown: React.FC<IMarkdownProps> = ({
39105
msg,
40106
md,
@@ -48,60 +114,40 @@ const Markdown: React.FC<IMarkdownProps> = ({
48114
isTranslated,
49115
textStyle
50116
}: IMarkdownProps) => {
51-
if (!msg) return null;
117+
'use memo';
118+
119+
let tokens: Root | null = null;
120+
121+
if (msg) {
122+
try {
123+
const result = resolveTokens(msg, md, isTranslated);
124+
tokens = isEmpty(result) ? null : result;
125+
} catch (e) {
126+
log(e);
127+
}
128+
}
129+
130+
const contextValue = {
131+
mentions,
132+
channels,
133+
useRealName,
134+
username,
135+
navToRoomInfo,
136+
getCustomEmoji,
137+
onLinkPress,
138+
textStyle
139+
};
52140

53-
let tokens;
54-
try {
55-
tokens = !isTranslated && md ? md : parse(typeof msg === 'string' ? msg : String(msg || ''));
56-
} catch (e) {
57-
log(e);
141+
if (!tokens) {
58142
return null;
59143
}
60144

61-
if (isEmpty(tokens)) return null;
62145
return (
63-
<View style={{ gap: 2 }}>
64-
<MarkdownContext.Provider
65-
value={{
66-
mentions,
67-
channels,
68-
useRealName,
69-
username,
70-
navToRoomInfo,
71-
getCustomEmoji,
72-
onLinkPress,
73-
textStyle
74-
}}>
75-
{tokens?.map(block => {
76-
switch (block.type) {
77-
case 'BIG_EMOJI':
78-
return <BigEmoji value={block.value} />;
79-
case 'UNORDERED_LIST':
80-
return <UnorderedList value={block.value} />;
81-
case 'ORDERED_LIST':
82-
return <OrderedList value={block.value} />;
83-
case 'TASKS':
84-
return <TaskList value={block.value} />;
85-
case 'QUOTE':
86-
return <Quote value={block.value} />;
87-
case 'PARAGRAPH':
88-
return <Paragraph value={block.value} />;
89-
case 'CODE':
90-
return <Code value={block.value} />;
91-
case 'HEADING':
92-
return <Heading value={block.value} level={block.level} />;
93-
case 'LINE_BREAK':
94-
return <LineBreak />;
95-
// This prop exists, but not even on the web it is treated, so...
96-
// https://github.com/RocketChat/Rocket.Chat/blob/develop/packages/gazzodown/src/Markup.tsx
97-
// case 'LIST_ITEM':
98-
// return <View />;
99-
case 'KATEX':
100-
return <KaTeX value={block.value} />;
101-
default:
102-
return null;
103-
}
104-
})}
146+
<View style={styles.blocks}>
147+
<MarkdownContext.Provider value={contextValue}>
148+
{tokens.map((block, index) => (
149+
<MarkdownBlockView key={`${block.type}-${index}`} block={block} />
150+
))}
105151
</MarkdownContext.Provider>
106152
</View>
107153
);

app/containers/markdown/styles.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const codeFontFamily = Platform.select({
88
});
99

1010
export default StyleSheet.create({
11+
blocks: {
12+
gap: 2
13+
},
1114
container: {
1215
alignItems: 'flex-start',
1316
flexDirection: 'row'

app/lib/hooks/useVideoConf/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCameraPermissions } from 'expo-camera';
1+
import { Camera } from 'expo-camera';
22
import React, { useMemo } from 'react';
33

44
import { useActionSheet } from '../../../containers/ActionSheet';
@@ -33,7 +33,6 @@ export const useVideoConf = (
3333
const serverVersion = useAppSelector(state => state.server.version);
3434
const { callEnabled, disabledTooltip, roomType } = useVideoConfCall(rid);
3535

36-
const [permission, requestPermission] = useCameraPermissions();
3736
const { showActionSheet } = useActionSheet();
3837

3938
const isServer5OrNewer = useMemo(() => compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '5.0.0'), [serverVersion]);
@@ -66,9 +65,10 @@ export const useVideoConf = (
6665
fullContainer: true
6766
});
6867

68+
const permission = await Camera.getCameraPermissionsAsync();
6969
if (!permission?.granted) {
7070
try {
71-
await requestPermission();
71+
await Camera.requestCameraPermissionsAsync();
7272
handleAndroidBltPermission();
7373
} catch (error) {
7474
log(error);

app/lib/hooks/useVideoConf/useVideoConfCall.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEffect, useState } from 'react';
2+
import { shallowEqual } from 'react-redux';
23

34
import { SubscriptionType } from '../../../definitions';
45
import { getUserSelector } from '../../../selectors/login';
@@ -8,7 +9,6 @@ import { compareServerVersion } from '../../methods/helpers/compareServerVersion
89
import { isReadOnly } from '../../methods/helpers/isReadOnly';
910
import { useAppSelector } from '../useAppSelector';
1011
import { usePermissions } from '../usePermissions';
11-
import { useSetting } from '../useSetting';
1212

1313
export const useVideoConfCall = (
1414
rid: string
@@ -17,18 +17,31 @@ export const useVideoConfCall = (
1717
const [disabledTooltip, setDisabledTooltip] = useState(false);
1818
const [roomType, setRoomType] = useState<SubscriptionType>();
1919

20+
// Read all call-related settings in a single subscription instead of one useSetting per key.
21+
const settings = useAppSelector(
22+
state => ({
23+
jitsiEnabled: state.settings.Jitsi_Enabled,
24+
jitsiEnableTeams: state.settings.Jitsi_Enable_Teams,
25+
jitsiEnableChannels: state.settings.Jitsi_Enable_Channels,
26+
videoConfEnableDMs: state.settings.VideoConf_Enable_DMs,
27+
videoConfEnableChannels: state.settings.VideoConf_Enable_Channels,
28+
videoConfEnableTeams: state.settings.VideoConf_Enable_Teams,
29+
videoConfEnableGroups: state.settings.VideoConf_Enable_Groups,
30+
omnichannelCallProvider: state.settings.Omnichannel_call_provider
31+
}),
32+
shallowEqual
33+
);
34+
2035
// OLD SETTINGS
21-
const jitsiEnabled = useSetting('Jitsi_Enabled');
22-
const jitsiEnableTeams = useSetting('Jitsi_Enable_Teams');
23-
const jitsiEnableChannels = useSetting('Jitsi_Enable_Channels');
36+
const { jitsiEnabled, jitsiEnableTeams, jitsiEnableChannels } = settings;
2437

2538
// NEW SETTINGS
2639
// Only disable video conf if the settings are explicitly FALSE - any falsy value counts as true
27-
const enabledDMs = useSetting('VideoConf_Enable_DMs') !== false;
28-
const enabledChannel = useSetting('VideoConf_Enable_Channels') !== false;
29-
const enabledTeams = useSetting('VideoConf_Enable_Teams') !== false;
30-
const enabledGroups = useSetting('VideoConf_Enable_Groups') !== false;
31-
const enabledLiveChat = useSetting('Omnichannel_call_provider') === 'default-provider';
40+
const enabledDMs = settings.videoConfEnableDMs !== false;
41+
const enabledChannel = settings.videoConfEnableChannels !== false;
42+
const enabledTeams = settings.videoConfEnableTeams !== false;
43+
const enabledGroups = settings.videoConfEnableGroups !== false;
44+
const enabledLiveChat = settings.omnichannelCallProvider === 'default-provider';
3245

3346
const serverVersion = useAppSelector(state => state.server.version);
3447
const isServer5OrNewer = compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '5.0.0');

0 commit comments

Comments
 (0)