agora-appbuilder-core 4.1.8-beta.1 → 4.1.8-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/package.json +2 -2
  2. package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +1 -1
  3. package/template/agora-rn-uikit/src/Rtc/Join.tsx +18 -9
  4. package/template/bridge/rtc/webNg/RtcEngine.ts +2 -2
  5. package/template/defaultConfig.js +4 -3
  6. package/template/global.d.ts +1 -0
  7. package/template/package.json +1 -1
  8. package/template/src/atoms/TextInput.tsx +3 -0
  9. package/template/src/components/Controls.tsx +17 -15
  10. package/template/src/components/common/GenericPopup.tsx +0 -1
  11. package/template/src/components/common/data-table.tsx +42 -15
  12. package/template/src/components/controls/useControlPermissionMatrix.tsx +7 -4
  13. package/template/src/components/recordings/RecordingItemRow.tsx +289 -0
  14. package/template/src/components/recordings/RecordingsDateTable.tsx +99 -25
  15. package/template/src/components/recordings/TextTrackItemRow.tsx +120 -0
  16. package/template/src/components/room-info/useRoomInfo.tsx +1 -0
  17. package/template/src/components/{stt-transcript/STTTranscriptTable.tsx → text-tracks/TextTracksTable.tsx} +61 -50
  18. package/template/src/components/{stt-transcript/ViewSTTTranscriptModal.tsx → text-tracks/ViewTextTracksModal.tsx} +7 -7
  19. package/template/src/components/text-tracks/useFetchSTTTranscript.tsx +262 -0
  20. package/template/src/language/default-labels/videoCallScreenLabels.ts +7 -7
  21. package/template/src/pages/VideoCall.tsx +1 -1
  22. package/template/src/subComponents/ChatInput.tsx +72 -1
  23. package/template/src/subComponents/recording/useRecording.tsx +19 -4
  24. package/template/src/utils/useCreateRoom.ts +1 -1
  25. package/template/src/utils/useJoinRoom.ts +5 -1
  26. package/template/src/components/stt-transcript/useFetchSTTTranscript.tsx +0 -193
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agora-appbuilder-core",
3
- "version": "4.1.8-beta.1",
3
+ "version": "4.1.8-beta.11",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -9,7 +9,7 @@
9
9
  ],
10
10
  "scripts": {
11
11
  "vercel-build": "npm run dev-setup && cd template && npm run web:build && cd .. && npm run copy-vercel",
12
- "uikit": "rm -rf template/agora-rn-uikit && git clone https://github.com/AgoraIO-Community/appbuilder-ui-kit.git template/agora-rn-uikit && cd template/agora-rn-uikit && git checkout appbuilder-uikit-3.1.4",
12
+ "uikit": "rm -rf template/agora-rn-uikit && git clone https://github.com/AgoraIO-Community/appbuilder-ui-kit.git template/agora-rn-uikit && cd template/agora-rn-uikit && git checkout appbuilder-uikit-3.1.8",
13
13
  "deps": "cd template && npm i --force",
14
14
  "dev-setup": "npm run uikit && npm run deps && node devSetup.js",
15
15
  "web-build": "cd template && npm run web:build && cd .. && npm run copy-vercel",
@@ -142,7 +142,7 @@ export interface RtcPropsInterface {
142
142
  callActive?: boolean;
143
143
  encryption?: {
144
144
  key: string;
145
- mode: EncryptionMode.Aes128Gcm2 | EncryptionMode.Aes256Gcm2;
145
+ mode: EncryptionMode.Aes128Xts | EncryptionMode.Aes256Gcm2;
146
146
  salt: number[];
147
147
  };
148
148
  // commented for v1 release
@@ -51,18 +51,27 @@ const Join: React.FC<{
51
51
  const videoState = defaultContent[maxUid]?.video;
52
52
  async function join() {
53
53
  if (
54
- rtcProps?.encryption &&
55
- rtcProps?.encryption.key &&
56
- rtcProps.encryption.mode &&
57
- rtcProps.encryption.salt
54
+ // rtcProps?.encryption &&
55
+ // rtcProps?.encryption.key &&
56
+ rtcProps?.encryption?.mode
57
+ // rtcProps.encryption.salt
58
58
  ) {
59
59
  try {
60
- await engine.enableEncryption(true, {
61
- encryptionKey: rtcProps?.encryption.key,
62
- encryptionMode: rtcProps?.encryption.mode,
63
- encryptionKdfSalt: rtcProps?.encryption.salt,
60
+ console.log(
61
+ 'ui kit setting encryption mode to ',
62
+ rtcProps?.encryption?.mode,
63
+ );
64
+ const encryptionConfig = {
65
+ encryptionKey: rtcProps?.encryption?.key,
66
+ encryptionMode: rtcProps?.encryption?.mode,
64
67
  datastreamEncryptionEnabled: true,
65
- });
68
+ ...(rtcProps?.encryption?.mode == 1
69
+ ? {}
70
+ : {
71
+ encryptionKdfSalt: rtcProps?.encryption?.salt,
72
+ }),
73
+ };
74
+ await engine.enableEncryption(true, encryptionConfig);
66
75
  } catch (error) {
67
76
  console.warn('encryption error', error);
68
77
  }
@@ -1466,13 +1466,13 @@ export default class RtcEngine {
1466
1466
  this.client.setEncryptionConfig(
1467
1467
  mode,
1468
1468
  config.encryptionKey,
1469
- config.encryptionKdfSalt,
1469
+ config.encryptionMode === 1? null:config.encryptionKdfSalt,
1470
1470
  true, // encryptDataStream
1471
1471
  ),
1472
1472
  this.screenClient.setEncryptionConfig(
1473
1473
  mode,
1474
1474
  config.encryptionKey,
1475
- config.encryptionKdfSalt,
1475
+ config.encryptionMode === 1? null:config.encryptionKdfSalt,
1476
1476
  true, // encryptDataStream
1477
1477
  ),
1478
1478
  ]);
@@ -77,8 +77,8 @@ const DefaultConfig = {
77
77
  CHAT_ORG_NAME: '',
78
78
  CHAT_APP_NAME: '',
79
79
  CHAT_URL: '',
80
- CLI_VERSION: '3.1.8-beta.1',
81
- CORE_VERSION: '4.1.8-beta.1',
80
+ CLI_VERSION: '3.1.8-beta.11',
81
+ CORE_VERSION: '4.1.8-beta.11',
82
82
  DISABLE_LANDSCAPE_MODE: false,
83
83
  STT_AUTO_START: false,
84
84
  CLOUD_RECORDING_AUTO_START: false,
@@ -89,7 +89,8 @@ const DefaultConfig = {
89
89
  AI_LAYOUT: 'LAYOUT_TYPE_1',
90
90
  SDK_CODEC: 'vp8',
91
91
  ENABLE_WAITING_ROOM_AUTO_APPROVAL: false,
92
- ENABLE_WAITING_ROOM_AUTO_REQUEST: false
92
+ ENABLE_WAITING_ROOM_AUTO_REQUEST: false,
93
+ ENABLE_TEXT_TRACKS: false,
93
94
  };
94
95
 
95
96
  module.exports = DefaultConfig;
@@ -177,6 +177,7 @@ interface ConfigInterface {
177
177
  SDK_CODEC: string;
178
178
  ENABLE_WAITING_ROOM_AUTO_APPROVAL: boolean;
179
179
  ENABLE_WAITING_ROOM_AUTO_REQUEST: boolean;
180
+ ENABLE_TEXT_TRACKS: boolean;
180
181
  }
181
182
  declare var $config: ConfigInterface;
182
183
  declare module 'customization' {
@@ -64,7 +64,7 @@
64
64
  "agora-extension-beauty-effect": "^1.0.2-beta",
65
65
  "agora-extension-virtual-background": "^1.1.3",
66
66
  "agora-react-native-rtm": "1.5.1",
67
- "agora-rtc-sdk-ng": "4.23.3",
67
+ "agora-rtc-sdk-ng": "4.23.4",
68
68
  "agora-rtm-sdk": "1.5.1",
69
69
  "buffer": "^6.0.3",
70
70
  "electron-log": "4.3.5",
@@ -17,6 +17,9 @@ import hexadecimalTransparency from '../utils/hexadecimalTransparency';
17
17
 
18
18
  interface TextInputCustomProps extends TextInputProps {
19
19
  setRef?: (ref: any) => void;
20
+ onCompositionStart?: () => void;
21
+ onCompositionEnd?: () => void;
22
+ onInput?: (event: any) => void;
20
23
  }
21
24
 
22
25
  const TextInputCustom = (props: TextInputCustomProps) => {
@@ -103,7 +103,7 @@ import {
103
103
  toolbarItemTranscriptText,
104
104
  toolbarItemVirtualBackgroundText,
105
105
  toolbarItemWhiteboardText,
106
- toolbarItemManageTranscriptText,
106
+ toolbarItemManageTextTracksText,
107
107
  } from '../language/default-labels/videoCallScreenLabels';
108
108
  import {LogSource, logger} from '../logger/AppBuilderLogger';
109
109
  import {useModal} from '../utils/useModal';
@@ -116,7 +116,7 @@ import {
116
116
  InviteToolbarItem,
117
117
  ScreenshareToolbarItem,
118
118
  } from './controls/toolbar-items';
119
- import ViewSTTTranscriptModal from './stt-transcript/ViewSTTTranscriptModal';
119
+ import ViewTextTracksModal from './text-tracks/ViewTextTracksModal';
120
120
 
121
121
  export const useToggleWhiteboard = () => {
122
122
  const {
@@ -278,7 +278,9 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
278
278
  const viewRecordingsLabel = useString<boolean>(
279
279
  toolbarItemViewRecordingText,
280
280
  )();
281
- const viewSTTLabel = useString<boolean>(toolbarItemManageTranscriptText)();
281
+ const viewTextTracksLabel = useString<boolean>(
282
+ toolbarItemManageTextTracksText,
283
+ )();
282
284
  const moreButtonLabel = useString(toolbarItemMoreText)();
283
285
  const virtualBackgroundLabel = useString(toolbarItemVirtualBackgroundText)();
284
286
  const chatLabel = useString(toolbarItemChatText)();
@@ -297,9 +299,9 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
297
299
  toggle: toggleVRModal,
298
300
  } = useModal();
299
301
  const {
300
- modalOpen: isSTTTranscriptModalOpen,
301
- setModalOpen: setSTTTranscriptModalOpen,
302
- toggle: toggleSTTTranscriptModal,
302
+ modalOpen: isTextTrackModalOpen,
303
+ setModalOpen: setTextTrackModalOpen,
304
+ toggle: toggleTextTrackModal,
303
305
  } = useModal();
304
306
  const moreBtnRef = useRef(null);
305
307
  const {width: globalWidth, height: globalHeight} = useWindowDimensions();
@@ -814,20 +816,20 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
814
816
  });
815
817
  }
816
818
 
817
- // 13. Transcripts to download
818
- const canAccessAllTranscripts =
819
- useControlPermissionMatrix('viewAllTranscripts');
819
+ // 13. Text-tracks to download
820
+ const canAccessAllTextTracks =
821
+ useControlPermissionMatrix('viewAllTextTracks');
820
822
 
821
- if (canAccessAllTranscripts) {
823
+ if (canAccessAllTextTracks) {
822
824
  actionMenuitems.push({
823
- componentName: 'view-all-transcripts',
825
+ componentName: 'view-all-text-tracks',
824
826
  order: 13,
825
827
  icon: 'transcript',
826
828
  iconColor: $config.SECONDARY_ACTION_COLOR,
827
829
  textColor: $config.FONT_COLOR,
828
- title: viewSTTLabel,
830
+ title: viewTextTracksLabel,
829
831
  onPress: () => {
830
- toggleSTTTranscriptModal();
832
+ toggleTextTrackModal();
831
833
  },
832
834
  });
833
835
  }
@@ -978,8 +980,8 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
978
980
  )}
979
981
  </>
980
982
  )}
981
- {canAccessAllTranscripts && isSTTTranscriptModalOpen ? (
982
- <ViewSTTTranscriptModal setModalOpen={setSTTTranscriptModalOpen} />
983
+ {canAccessAllTextTracks && isTextTrackModalOpen ? (
984
+ <ViewTextTracksModal setModalOpen={setTextTrackModalOpen} />
983
985
  ) : (
984
986
  <></>
985
987
  )}
@@ -51,7 +51,6 @@ const GenericPopup: React.FC<ConfirmationModalProps> = ({
51
51
  onCancel && onCancel();
52
52
  };
53
53
  const handleConfirm = () => {
54
- setVisible(false);
55
54
  onConfirm();
56
55
  };
57
56
 
@@ -19,6 +19,7 @@ interface TableHeaderProps {
19
19
  rowStyle?: ViewStyle;
20
20
  cellStyle?: ViewStyle;
21
21
  firstCellStyle?: ViewStyle;
22
+ lastCellStyle?: ViewStyle;
22
23
  textStyle?: TextStyle;
23
24
  }
24
25
 
@@ -28,22 +29,27 @@ const TableHeader: React.FC<TableHeaderProps> = ({
28
29
  rowStyle,
29
30
  cellStyle,
30
31
  firstCellStyle,
32
+ lastCellStyle,
31
33
  textStyle,
32
34
  }) => (
33
35
  <View style={[style.thead, containerStyle]}>
34
36
  <View style={[style.throw, rowStyle]}>
35
- {columns.map((col, index) => (
36
- <View
37
- key={col}
38
- style={[
39
- style.th,
40
- index === 0 && style.plzero,
41
- cellStyle,
42
- index === 0 && firstCellStyle,
43
- ]}>
44
- <Text style={[style.thText, textStyle]}>{col}</Text>
45
- </View>
46
- ))}
37
+ {columns.map((col, index) => {
38
+ const isFirst = index === 0;
39
+ const isLast = index === (columns.length > 1 ? columns.length - 1 : 0);
40
+ return (
41
+ <View
42
+ key={col}
43
+ style={[
44
+ style.th,
45
+ cellStyle,
46
+ isFirst && firstCellStyle,
47
+ isLast && lastCellStyle,
48
+ ]}>
49
+ <Text style={[style.thText, textStyle]}>{col}</Text>
50
+ </View>
51
+ );
52
+ })}
47
53
  </View>
48
54
  </View>
49
55
  );
@@ -151,7 +157,7 @@ const TableFooter: React.FC<TableFooterProps> = ({
151
157
 
152
158
  export {TableHeader, TableFooter, TableBody};
153
159
 
154
- const style = StyleSheet.create({
160
+ export const style = StyleSheet.create({
155
161
  scrollgrow: {
156
162
  flexGrow: 1,
157
163
  },
@@ -222,7 +228,7 @@ const style = StyleSheet.create({
222
228
  flex: 1,
223
229
  alignSelf: 'stretch',
224
230
  justifyContent: 'center',
225
- paddingHorizontal: 12,
231
+ // paddingHorizontal: 12,
226
232
  },
227
233
  thText: {
228
234
  color: $config.FONT_COLOR + ThemeConfig.EmphasisPlus.medium,
@@ -249,7 +255,6 @@ const style = StyleSheet.create({
249
255
  flex: 1,
250
256
  alignSelf: 'center',
251
257
  justifyContent: 'center',
252
- // height: 100,
253
258
  gap: 10,
254
259
  },
255
260
  tpreview: {
@@ -275,6 +280,8 @@ const style = StyleSheet.create({
275
280
  tactions: {
276
281
  display: 'flex',
277
282
  flexDirection: 'row',
283
+ alignItems: 'center',
284
+ justifyContent: 'flex-end',
278
285
  },
279
286
  tlink: {
280
287
  color: $config.PRIMARY_ACTION_BRAND_COLOR,
@@ -382,4 +389,24 @@ const style = StyleSheet.create({
382
389
  pl15: {
383
390
  paddingLeft: 15,
384
391
  },
392
+ // icon celles
393
+ tdIconCell: {
394
+ flex: 0,
395
+ flexShrink: 0,
396
+ alignItems: 'flex-start',
397
+ justifyContent: 'center',
398
+ minWidth: 52,
399
+ // paddingRight: 50 + 12,
400
+ },
401
+ thIconCell: {
402
+ flex: 0,
403
+ flexShrink: 0,
404
+ alignSelf: 'stretch',
405
+ justifyContent: 'center',
406
+ minWidth: 50,
407
+ paddingHorizontal: 12,
408
+ },
409
+ alignCellToRight: {
410
+ alignItems: 'flex-end',
411
+ },
385
412
  });
@@ -15,7 +15,7 @@ export type ControlPermissionKey =
15
15
  | 'participantControl'
16
16
  | 'screenshareControl'
17
17
  | 'settingsControl'
18
- | 'viewAllTranscripts';
18
+ | 'viewAllTextTracks';
19
19
 
20
20
  /**
21
21
  * ControlPermissionRule defines the properties used to evaluate permission rules.
@@ -36,9 +36,12 @@ export const controlPermissionMatrix: Record<
36
36
  settingsControl: ({preference}) => !preference.disableSettings,
37
37
  screenshareControl: ({preference}) =>
38
38
  $config.SCREEN_SHARING && !preference.disableScreenShare,
39
- viewAllTranscripts: ({isHost}) =>
40
- $config.ENABLE_STT && $config.ENABLE_MEETING_TRANSCRIPT && isWeb(),
41
- // isHost,
39
+ viewAllTextTracks: ({isHost}) =>
40
+ isHost &&
41
+ $config.ENABLE_STT &&
42
+ $config.ENABLE_MEETING_TRANSCRIPT &&
43
+ $config.ENABLE_TEXT_TRACKS &&
44
+ isWeb(),
42
45
  };
43
46
 
44
47
  export const useControlPermissionMatrix = (
@@ -0,0 +1,289 @@
1
+ import React, {useEffect, useState} from 'react';
2
+ import {View, Text, Linking, TouchableOpacity, StyleSheet} from 'react-native';
3
+ import {downloadRecording, getDuration, getRecordedDateTime} from './utils';
4
+ import IconButtonWithToolTip from '../../atoms/IconButton';
5
+ import Tooltip from '../../atoms/Tooltip';
6
+ import Clipboard from '../../subComponents/Clipboard';
7
+ import Spacer from '../../atoms/Spacer';
8
+ import PlatformWrapper from '../../utils/PlatformWrapper';
9
+ import {useFetchSTTTranscript} from '../text-tracks/useFetchSTTTranscript';
10
+ import {style} from '../common/data-table';
11
+ import {FetchRecordingData} from '../../subComponents/recording/useRecording';
12
+ import ImageIcon from '../../atoms/ImageIcon';
13
+ import TextTrackItemRow from './TextTrackItemRow';
14
+
15
+ interface RecordingItemRowProps {
16
+ item: FetchRecordingData['recordings'][0];
17
+ onDeleteAction: (id: string) => void;
18
+ onTextTrackDownload: (textTrackLink: string) => void;
19
+ showTextTracks: boolean;
20
+ }
21
+ export default function RecordingItemRow({
22
+ item,
23
+ onDeleteAction,
24
+ onTextTrackDownload,
25
+ showTextTracks = false,
26
+ }: RecordingItemRowProps) {
27
+ const [expanded, setIsExpanded] = useState(false);
28
+
29
+ const [date, time] = getRecordedDateTime(item.created_at);
30
+ const recordingStatus = item.status;
31
+
32
+ const {sttRecState, getSTTsForRecording} = useFetchSTTTranscript();
33
+ const {
34
+ status,
35
+ error,
36
+ data: {stts = []},
37
+ } = sttRecState;
38
+
39
+ useEffect(() => {
40
+ if (expanded) {
41
+ if (item.id) {
42
+ getSTTsForRecording(item.id);
43
+ }
44
+ }
45
+ }, [expanded, item.id, getSTTsForRecording]);
46
+
47
+ if (
48
+ recordingStatus === 'STOPPING' ||
49
+ recordingStatus === 'STARTED' ||
50
+ (recordingStatus === 'INPROGRESS' && !item?.download_url)
51
+ ) {
52
+ return (
53
+ <View key={item.id} style={style.pt12}>
54
+ <View style={[style.infotextContainer, style.captionContainer]}>
55
+ <ImageIcon
56
+ iconSize={20}
57
+ iconType="plain"
58
+ name="info"
59
+ tintColor={$config.SEMANTIC_NEUTRAL}
60
+ />
61
+ <Text style={[style.captionText]}>
62
+ Current recording is ongoing. Once it concludes, we'll generate the
63
+ link
64
+ </Text>
65
+ </View>
66
+ </View>
67
+ );
68
+ }
69
+
70
+ // Collapsible Row
71
+ return (
72
+ <View>
73
+ {/* ========== PARENT ROW ========== */}
74
+ <View style={style.tbrow} key={item.id}>
75
+ {showTextTracks && (
76
+ <View style={style.tdIconCell}>
77
+ <IconButtonWithToolTip
78
+ hoverEffect={true}
79
+ hoverEffectStyle={style.iconButtonHoverEffect}
80
+ containerStyle={style.iconButton}
81
+ iconProps={{
82
+ name: expanded ? 'arrow-up' : 'arrow-down',
83
+ iconType: 'plain',
84
+ iconSize: 20,
85
+ tintColor: `${$config.FONT_COLOR}`,
86
+ }}
87
+ onPress={() => setIsExpanded(prev => !prev)}
88
+ />
89
+ </View>
90
+ )}
91
+ <View style={[style.td, style.plzero]}>
92
+ <Text style={style.ttime}>
93
+ {date}
94
+ <br />
95
+ <Text style={style.ttime}>{time}</Text>
96
+ </Text>
97
+ </View>
98
+ <View style={[style.td]}>
99
+ <Text style={style.ttime}>
100
+ {getDuration(item.created_at, item.ended_at)}
101
+ </Text>
102
+ </View>
103
+ <View style={style.td}>
104
+ {!item.download_url ? (
105
+ <View style={(style.tactions, {marginTop: 0})}>
106
+ <Text style={style.placeHolder}>{'No recording found'}</Text>
107
+ </View>
108
+ ) : item?.download_url?.length > 0 ? (
109
+ <View style={style.tactions}>
110
+ <View>
111
+ {item?.download_url?.map((link: string, i: number) => (
112
+ <View
113
+ style={[
114
+ style.tactions,
115
+ //if recording contains multiple parts then we need to add some space each row
116
+ i >= 1 ? {marginTop: 8} : {},
117
+ ]}>
118
+ <View>
119
+ <IconButtonWithToolTip
120
+ hoverEffect={true}
121
+ hoverEffectStyle={style.iconButtonHoverEffect}
122
+ containerStyle={style.iconButton}
123
+ iconProps={{
124
+ name: 'download',
125
+ iconType: 'plain',
126
+ iconSize: 20,
127
+ tintColor: `${$config.SECONDARY_ACTION_COLOR}`,
128
+ }}
129
+ onPress={() => {
130
+ downloadRecording(link);
131
+ }}
132
+ />
133
+ </View>
134
+ <View style={style.pl10}>
135
+ <IconButtonWithToolTip
136
+ hoverEffect={true}
137
+ hoverEffectStyle={style.iconButtonHoverEffect}
138
+ containerStyle={style.iconButton}
139
+ iconProps={{
140
+ name: 'link-share',
141
+ iconType: 'plain',
142
+ iconSize: 20,
143
+ tintColor: `${$config.SECONDARY_ACTION_COLOR}`,
144
+ }}
145
+ onPress={async () => {
146
+ if (await Linking.canOpenURL(link)) {
147
+ await Linking.openURL(link);
148
+ }
149
+ }}
150
+ />
151
+ </View>
152
+ <View style={[style.pl10]}>
153
+ <Tooltip
154
+ isClickable
155
+ placement="left"
156
+ toolTipMessage="Link Copied"
157
+ onPress={() => {
158
+ Clipboard.setString(link);
159
+ }}
160
+ toolTipIcon={
161
+ <>
162
+ <ImageIcon
163
+ iconType="plain"
164
+ name="tick-fill"
165
+ tintColor={$config.SEMANTIC_SUCCESS}
166
+ iconSize={20}
167
+ />
168
+ <Spacer size={8} horizontal={true} />
169
+ </>
170
+ }
171
+ fontSize={12}
172
+ renderContent={() => {
173
+ return (
174
+ <PlatformWrapper>
175
+ {(isHovered: boolean) => (
176
+ <TouchableOpacity
177
+ style={[
178
+ isHovered
179
+ ? style.iconButtonHoverEffect
180
+ : {},
181
+ style.iconShareLink,
182
+ ]}
183
+ onPress={() => {
184
+ Clipboard.setString(link);
185
+ }}>
186
+ <ImageIcon
187
+ iconType="plain"
188
+ name="copy-link"
189
+ iconSize={20}
190
+ tintColor={$config.SECONDARY_ACTION_COLOR}
191
+ />
192
+ </TouchableOpacity>
193
+ )}
194
+ </PlatformWrapper>
195
+ );
196
+ }}
197
+ />
198
+ </View>
199
+ </View>
200
+ ))}
201
+ </View>
202
+ <View style={[style.pl10]}>
203
+ <IconButtonWithToolTip
204
+ hoverEffect={true}
205
+ hoverEffectStyle={style.iconButtonHoverEffect}
206
+ containerStyle={style.iconButton}
207
+ iconProps={{
208
+ name: 'delete',
209
+ iconType: 'plain',
210
+ iconSize: 20,
211
+ tintColor: `${$config.SEMANTIC_ERROR}`,
212
+ }}
213
+ onPress={() => {
214
+ onDeleteAction && onDeleteAction(item.id);
215
+ }}
216
+ />
217
+ </View>
218
+ </View>
219
+ ) : (
220
+ <View style={(style.tactions, {marginTop: 0})}>
221
+ <Text style={style.placeHolder}>No recordings found</Text>
222
+ </View>
223
+ )}
224
+ </View>
225
+ </View>
226
+ {/* ========== CHILDREN ROW ========== */}
227
+ {expanded && (
228
+ <View style={expanedStyles.expandedContainer}>
229
+ <View>
230
+ <Text style={expanedStyles.expandedHeaderText}>Text-tracks</Text>
231
+ </View>
232
+ <View style={expanedStyles.expandedHeaderBody}>
233
+ {status === 'idle' || status === 'pending' ? (
234
+ <Text style={style.ttime}>Fetching text-tracks....</Text>
235
+ ) : status === 'rejected' ? (
236
+ <Text style={style.ttime}>
237
+ {error?.message ||
238
+ 'There was an error while fetching the text-tracks'}
239
+ </Text>
240
+ ) : status === 'resolved' && stts?.length === 0 ? (
241
+ <Text style={style.ttime}>
242
+ There are no text-tracks's for this recording
243
+ </Text>
244
+ ) : (
245
+ <>
246
+ <Text style={style.ttime}>Found {stts.length} text tracks</Text>
247
+ <View>
248
+ {stts.map(item => (
249
+ <TextTrackItemRow
250
+ key={item.id}
251
+ item={item}
252
+ onTextTrackDownload={onTextTrackDownload}
253
+ />
254
+ ))}
255
+ </View>
256
+ </>
257
+ )}
258
+ </View>
259
+ </View>
260
+ )}
261
+ </View>
262
+ );
263
+ }
264
+
265
+ const expanedStyles = StyleSheet.create({
266
+ expandedContainer: {
267
+ display: 'flex',
268
+ flexDirection: 'column',
269
+ gap: 5,
270
+ color: $config.FONT_COLOR,
271
+ borderColor: $config.CARD_LAYER_3_COLOR,
272
+ backgroundColor: $config.CARD_LAYER_2_COLOR,
273
+ paddingHorizontal: 12,
274
+ paddingVertical: 15,
275
+ borderRadius: 5,
276
+ },
277
+ expandedHeaderText: {
278
+ fontSize: 15,
279
+ lineHeight: 32,
280
+ fontWeight: '500',
281
+ color: $config.FONT_COLOR,
282
+ },
283
+ expandedHeaderBody: {
284
+ display: 'flex',
285
+ flexDirection: 'row',
286
+ justifyContent: 'space-between',
287
+ alignItems: 'flex-start',
288
+ },
289
+ });