agora-appbuilder-core 4.0.25 → 4.0.26-beta-2

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 (29) hide show
  1. package/package.json +1 -1
  2. package/template/android/app/src/main/assets/fonts/icomoon.ttf +0 -0
  3. package/template/customization-api/typeDefinition.ts +3 -8
  4. package/template/customization-api/utils.ts +1 -0
  5. package/template/defaultConfig.js +51 -51
  6. package/template/src/AppWrapper.tsx +1 -1
  7. package/template/src/assets/font-styles.css +4 -0
  8. package/template/src/assets/fonts/icomoon.ttf +0 -0
  9. package/template/src/assets/selection.json +1 -3452
  10. package/template/src/atoms/ActionMenu.tsx +88 -23
  11. package/template/src/atoms/Carousel.tsx +30 -24
  12. package/template/src/atoms/CustomIcon.tsx +1 -0
  13. package/template/src/atoms/ParticipantsCount.tsx +3 -10
  14. package/template/src/atoms/RecordingInfo.tsx +25 -30
  15. package/template/src/atoms/Toolbar.tsx +0 -8
  16. package/template/src/atoms/ToolbarPreset.tsx +77 -45
  17. package/template/src/components/Controls.tsx +289 -218
  18. package/template/src/components/Leftbar.tsx +62 -43
  19. package/template/src/components/Navbar.tsx +80 -77
  20. package/template/src/components/NavbarMobile.tsx +51 -46
  21. package/template/src/components/Rightbar.tsx +60 -43
  22. package/template/src/components/room-info/useRoomInfo.tsx +1 -1
  23. package/template/src/language/default-labels/videoCallScreenLabels.ts +1 -2
  24. package/template/src/pages/video-call/ActionSheet.tsx +4 -4
  25. package/template/src/pages/video-call/ActionSheetContent.tsx +134 -211
  26. package/template/src/pages/video-call/VideoCallMobileView.tsx +21 -27
  27. package/template/src/pages/video-call/VideoCallScreen.tsx +30 -20
  28. package/template/src/pages/video-call/index.ts +2 -0
  29. package/template/src/utils/common.tsx +48 -0
@@ -8,6 +8,7 @@ import {
8
8
  Image,
9
9
  TouchableOpacity,
10
10
  ViewStyle,
11
+ useWindowDimensions,
11
12
  } from 'react-native';
12
13
  import React, {SetStateAction, useState} from 'react';
13
14
 
@@ -17,8 +18,12 @@ import ThemeConfig from '../theme';
17
18
  import {isWebInternal} from '../utils/common';
18
19
  import hexadecimalTransparency from '../utils/hexadecimalTransparency';
19
20
  import Toggle from './Toggle';
21
+ import {Either} from '../../agora-rn-uikit/src/Controls/types';
22
+ import {ToolbarItemHide, ToolbarMoreMenuCustomItem} from './ToolbarPreset';
20
23
 
21
24
  export interface ActionMenuItem {
25
+ componentName?: string;
26
+ order?: number;
22
27
  isExternalIcon?: boolean;
23
28
  externalIconString?: string;
24
29
  isBase64Icon?: boolean;
@@ -33,6 +38,7 @@ export interface ActionMenuItem {
33
38
  onHoverContent?: JSX.Element;
34
39
  disabled?: boolean;
35
40
  iconSize?: number;
41
+ hide?: ToolbarItemHide;
36
42
  }
37
43
  export interface ActionMenuProps {
38
44
  from: string;
@@ -44,7 +50,7 @@ export interface ActionMenuProps {
44
50
  left?: number;
45
51
  bottom?: number;
46
52
  };
47
- items: ActionMenuItem[];
53
+ items: Either<ActionMenuItem[], ToolbarMoreMenuCustomItem[]>;
48
54
  hoverMode?: boolean;
49
55
  onHover?: (hover: boolean) => void;
50
56
  containerStyle?: ViewStyle;
@@ -58,28 +64,87 @@ const ActionMenu = (props: ActionMenuProps) => {
58
64
  items,
59
65
  hoverMode = false,
60
66
  } = props;
67
+ const {width, height} = useWindowDimensions();
61
68
 
62
69
  const renderItems = () => {
63
- return items?.map(
64
- (
65
- {
66
- icon = '',
67
- onHoverIcon,
68
- isBase64Icon = false,
69
- isExternalIcon = false,
70
- externalIconString = '',
71
- title,
72
- toggleStatus,
73
- callback,
74
- iconColor,
75
- textColor,
76
- disabled = false,
77
- onHoverCallback = undefined,
78
- onHoverContent = undefined,
79
- iconSize = 20,
80
- },
81
- index,
82
- ) => (
70
+ return items?.map((item, index) => {
71
+ //rendering the custom item with default UI
72
+ const {title, onPress, iconBase64, componentName, hide = false} = item;
73
+
74
+ if (typeof hide === 'boolean' && hide) {
75
+ return null;
76
+ }
77
+
78
+ try {
79
+ if (typeof hide === 'function' && hide && hide(width, height)) {
80
+ return null;
81
+ }
82
+ } catch (error) {}
83
+
84
+ if (title && onPress) {
85
+ return (
86
+ <PlatformWrapper key={props.from + '_' + componentName + index}>
87
+ {(isHovered: boolean) => (
88
+ <>
89
+ <TouchableOpacity
90
+ disabled={false}
91
+ style={[
92
+ styles.row,
93
+ isHovered && !false
94
+ ? //first item should have border-radius on top left and top right
95
+ index === 0
96
+ ? styles.rowHoveredFirstChild
97
+ : //last item should have border-radius on bottom left and top right
98
+ items?.length - 1 === index
99
+ ? styles.rowHoveredLastChild
100
+ : //middle items don't need any border-radius
101
+ styles.rowHoveredMiddleItems
102
+ : {},
103
+ false ? {opacity: 0.4} : {},
104
+ items?.length - 1 === index
105
+ ? {borderBottomColor: 'transparent'}
106
+ : {},
107
+ ]}
108
+ onPress={onPress}
109
+ key={componentName + index}>
110
+ {iconBase64 ? (
111
+ <View style={styles.iconContainer}>
112
+ <ImageIcon
113
+ base64={false}
114
+ base64TintColor={$config.SECONDARY_ACTION_COLOR}
115
+ iconType="plain"
116
+ iconSize={24}
117
+ icon={iconBase64}
118
+ tintColor={$config.SECONDARY_ACTION_COLOR}
119
+ />
120
+ </View>
121
+ ) : (
122
+ <></>
123
+ )}
124
+ <Text style={[styles.text]}>{title}</Text>
125
+ </TouchableOpacity>
126
+ </>
127
+ )}
128
+ </PlatformWrapper>
129
+ );
130
+ }
131
+
132
+ const {
133
+ icon = '',
134
+ onHoverIcon,
135
+ isBase64Icon = false,
136
+ isExternalIcon = false,
137
+ externalIconString = '',
138
+ toggleStatus,
139
+ callback,
140
+ iconColor,
141
+ textColor,
142
+ disabled = false,
143
+ onHoverCallback = undefined,
144
+ onHoverContent = undefined,
145
+ iconSize = 20,
146
+ } = item;
147
+ return (
83
148
  <PlatformWrapper key={props.from + '_' + title + index}>
84
149
  {(isHovered: boolean) => (
85
150
  <>
@@ -150,8 +215,8 @@ const ActionMenu = (props: ActionMenuProps) => {
150
215
  </>
151
216
  )}
152
217
  </PlatformWrapper>
153
- ),
154
- );
218
+ );
219
+ });
155
220
  };
156
221
 
157
222
  return (
@@ -10,9 +10,10 @@ interface CarouselItem {
10
10
 
11
11
  interface CarouselProps {
12
12
  data: CarouselItem[];
13
+ isPaginationRequired?: boolean;
13
14
  }
14
15
 
15
- const Carousel: React.FC<CarouselProps> = ({data}) => {
16
+ const Carousel: React.FC<CarouselProps> = ({data, isPaginationRequired}) => {
16
17
  const [activeIndex, setActiveIndex] = useState(0);
17
18
 
18
19
  const flatListRef = React.useRef<FlatList | null>(null);
@@ -36,7 +37,8 @@ const Carousel: React.FC<CarouselProps> = ({data}) => {
36
37
  };
37
38
 
38
39
  return (
39
- <View style={styles.container}>
40
+ <View
41
+ style={[styles.container, !isPaginationRequired ? {paddingTop: 24} : {}]}>
40
42
  <FlatList
41
43
  ref={flatListRef}
42
44
  data={data}
@@ -47,28 +49,32 @@ const Carousel: React.FC<CarouselProps> = ({data}) => {
47
49
  keyExtractor={(_, index) => index.toString()}
48
50
  onScroll={handleScroll}
49
51
  />
50
- <View style={styles.indicatorContainer}>
51
- {data.map((_, index) => (
52
- <Pressable
53
- key={index}
54
- onPress={() => {
55
- scrollToIndex(index);
56
- setActiveIndex(index);
57
- }}
58
- hitSlop={5} // to increase clickable area
59
- >
60
- {({pressed}) => (
61
- <View
62
- style={[
63
- styles.dot,
64
- index === activeIndex && styles.activeDot,
65
- pressed && styles.pressedDot,
66
- ]}
67
- />
68
- )}
69
- </Pressable>
70
- ))}
71
- </View>
52
+ {isPaginationRequired ? (
53
+ <View style={styles.indicatorContainer}>
54
+ {data.map((_, index) => (
55
+ <Pressable
56
+ key={index}
57
+ onPress={() => {
58
+ scrollToIndex(index);
59
+ setActiveIndex(index);
60
+ }}
61
+ hitSlop={5} // to increase clickable area
62
+ >
63
+ {({pressed}) => (
64
+ <View
65
+ style={[
66
+ styles.dot,
67
+ index === activeIndex && styles.activeDot,
68
+ pressed && styles.pressedDot,
69
+ ]}
70
+ />
71
+ )}
72
+ </Pressable>
73
+ ))}
74
+ </View>
75
+ ) : (
76
+ <></>
77
+ )}
72
78
  </View>
73
79
  );
74
80
  };
@@ -148,4 +148,5 @@ export interface IconsInterface {
148
148
  block_user: string;
149
149
  'play-circle': string;
150
150
  'copy-link': string;
151
+ 'recording-status': string;
151
152
  }
@@ -71,15 +71,8 @@ export default ParticipantsCount;
71
71
  const styles = StyleSheet.create({
72
72
  participantCountView: {
73
73
  flexDirection: 'row',
74
- padding: 12,
75
- paddingVertical: isMobileUA() ? 5 : 8,
76
- backgroundColor: $config.ICON_BG_COLOR,
77
- borderRadius: 25,
78
- borderWidth: 1,
79
- borderColor: $config.CARD_LAYER_3_COLOR,
80
- shadowColor: $config.HARD_CODED_BLACK_COLOR,
81
- shadowOffset: {width: 0, height: 4},
82
- shadowOpacity: 0.1,
83
- shadowRadius: 20,
74
+ alignItems: 'center',
75
+ alignContent: 'center',
76
+ justifyContent: 'center',
84
77
  },
85
78
  });
@@ -2,16 +2,35 @@ import {StyleSheet, Text, View} from 'react-native';
2
2
  import hexadecimalTransparency from '../utils/hexadecimalTransparency';
3
3
  import React from 'react';
4
4
  import {isMobileUA} from '../utils/common';
5
+ import IconButton from '../atoms/IconButton';
5
6
 
6
7
  const RecordingInfo = ({recordingLabel = ''}) => {
7
8
  return (
8
9
  <View style={[styles.recordingView]}>
9
- <View style={[styles.recordingStatus]} />
10
- {recordingLabel ? (
11
- <Text style={styles.recordingText}>{recordingLabel}</Text>
12
- ) : (
13
- <></>
14
- )}
10
+ <IconButton
11
+ placement="right"
12
+ isClickable={false}
13
+ containerStyle={styles.recordingView}
14
+ disabled={true}
15
+ iconProps={{
16
+ name: 'recording-status',
17
+ iconType: 'plain',
18
+ iconSize: 20,
19
+ tintColor: $config.SEMANTIC_ERROR,
20
+ }}
21
+ btnTextProps={{
22
+ text: recordingLabel,
23
+ textColor: $config.SEMANTIC_ERROR,
24
+ textStyle: {
25
+ fontFamily: 'Source Sans Pro',
26
+ fontWeight: '600',
27
+ fontSize: 12,
28
+ lineHeight: 12,
29
+ marginTop: 0,
30
+ marginLeft: 4,
31
+ },
32
+ }}
33
+ />
15
34
  </View>
16
35
  );
17
36
  };
@@ -20,33 +39,9 @@ export default RecordingInfo;
20
39
 
21
40
  const styles = StyleSheet.create({
22
41
  recordingView: {
23
- padding: 12,
24
- paddingVertical: isMobileUA() ? 10 : 12,
25
42
  flexDirection: 'row',
26
43
  alignItems: 'center',
27
44
  alignContent: 'center',
28
45
  justifyContent: 'center',
29
- borderRadius: 24,
30
- backgroundColor: $config.ICON_BG_COLOR,
31
- borderWidth: 1,
32
- borderColor: $config.CARD_LAYER_3_COLOR,
33
- shadowColor: $config.HARD_CODED_BLACK_COLOR,
34
- shadowOffset: {width: 0, height: 4},
35
- shadowOpacity: 0.1,
36
- shadowRadius: 20,
37
- },
38
- recordingText: {
39
- fontSize: 12,
40
- lineHeight: 12,
41
- fontWeight: '600',
42
- fontFamily: 'Source Sans Pro',
43
- color: $config.FONT_COLOR + hexadecimalTransparency['50%'],
44
- marginLeft: 4,
45
- },
46
- recordingStatus: {
47
- width: 12,
48
- height: 12,
49
- borderRadius: 6,
50
- backgroundColor: $config.SEMANTIC_ERROR,
51
46
  },
52
47
  });
@@ -2,16 +2,8 @@ import React from 'react';
2
2
  import {View, StyleSheet} from 'react-native';
3
3
  import {useToolbar, ToolbarPosition} from '../utils/useToolbar';
4
4
  import {isMobileUA, isWebInternal, useIsDesktop} from '../utils/common';
5
- import hexadecimalTransparency from '../utils/hexadecimalTransparency';
6
- import {ToolbarCustomItem} from './ToolbarPreset';
7
5
  import ActionSheet from '../pages/video-call/ActionSheet';
8
6
 
9
- // export interface ToolbarProps {
10
- // children: React.ReactNode;
11
- // bottomSheetOnMobile?: boolean;
12
- // customItems?: ToolbarCustomItem[];
13
- // }
14
-
15
7
  export interface ToolbarPropsBase {
16
8
  children: React.ReactNode;
17
9
  }
@@ -7,9 +7,22 @@ import {isMobileUA} from '../utils/common';
7
7
  import NavbarMobile from '../components/NavbarMobile';
8
8
  import ActionSheet from '../pages/video-call/ActionSheet';
9
9
 
10
- export type ToolbarDefaultItemName =
11
- //bottom bar
10
+ export type MoreButtonDefaultKeys =
11
+ | 'virtual-background'
12
+ | 'noise-cancellation'
13
+ | 'caption'
14
+ | 'transcript'
15
+ | 'view-recordings'
16
+ | 'whiteboard'
17
+ | 'chat'
18
+ | 'participant'
19
+ | 'settings'
20
+ | 'layout'
21
+ | 'invite'
22
+ | 'screenshare'
23
+ | 'recording';
12
24
 
25
+ export type BottomToolbarDefaultKeys =
13
26
  //left
14
27
  | 'layout'
15
28
  | 'invite'
@@ -21,8 +34,9 @@ export type ToolbarDefaultItemName =
21
34
  | 'switch-camera'
22
35
  | 'end-call'
23
36
  | 'raise-hand'
24
- | 'more'
37
+ | 'more';
25
38
 
39
+ export type TopToolbarDefaultKeys =
26
40
  //topbar
27
41
  | 'meeting-title'
28
42
  | 'participant-count'
@@ -31,12 +45,16 @@ export type ToolbarDefaultItemName =
31
45
  | 'participant'
32
46
  | 'settings';
33
47
 
34
- export type ToolbarDefaultItemConfig = {
35
- [key in ToolbarDefaultItemName]?: ToolbarDefaultItem;
48
+ export type ToolbarMoreButtonFields = {
49
+ [key in MoreButtonDefaultKeys]?: {
50
+ hide?: ToolbarItemHide;
51
+ order?: number;
52
+ };
36
53
  };
37
54
 
38
55
  export type ToolbarItemAlign = 'start' | 'center' | 'end';
39
- export type ToolbarItemHide = 'yes' | 'no';
56
+ export type ToolbarHideCallback = (width: number, height: number) => boolean;
57
+ export type ToolbarItemHide = boolean | ToolbarHideCallback;
40
58
 
41
59
  export interface ToolbarDefaultItem {
42
60
  component?: () => JSX.Element;
@@ -44,31 +62,62 @@ export interface ToolbarDefaultItem {
44
62
  hide?: ToolbarItemHide;
45
63
  order?: number;
46
64
  }
47
-
48
- export interface ToolbarCustomItem {
49
- component: () => JSX.Element;
50
- align: ToolbarItemAlign;
51
- hide: ToolbarItemHide;
52
- order?: number;
65
+ export interface ToolbarMoreDefaultItem extends ToolbarDefaultItem {
66
+ fields?: ToolbarMoreButtonFields;
53
67
  }
68
+
54
69
  export type ToolbarPresetAlign = 'top' | 'bottom' | 'right' | 'left';
55
70
 
71
+ export interface ToolbarMoreMenuCustomItem {
72
+ componentName: string;
73
+ title: string;
74
+ onPress: () => void;
75
+ iconBase64?: string;
76
+ hide?: ToolbarItemHide;
77
+ order?: number;
78
+ }
56
79
  export interface ToolbarBottomPresetProps {
57
- align: ToolbarPresetAlign;
58
- customItems?: Array<ToolbarCustomItem>;
59
- defaultItemsConfig?: ToolbarDefaultItemConfig;
60
- snapPointsMinMax: [number, number];
80
+ align: 'bottom';
81
+ items?:
82
+ | {
83
+ [key: string]: ToolbarDefaultItem;
84
+ }
85
+ | {
86
+ ['more']?: ToolbarMoreDefaultItem;
87
+ }
88
+ | {
89
+ [key in BottomToolbarDefaultKeys]?: ToolbarDefaultItem;
90
+ };
91
+ snapPointsMinMax?: [number, number];
61
92
  }
62
- export interface ToolbarOtherPresetProps {
63
- align: ToolbarPresetAlign;
64
- customItems?: Array<ToolbarCustomItem>;
65
- defaultItemsConfig?: ToolbarDefaultItemConfig;
66
- snapPointsMinMax?: never;
93
+ export interface ToolbarTopPresetProps {
94
+ align: 'top';
95
+ items?:
96
+ | {
97
+ [key in TopToolbarDefaultKeys]?: ToolbarDefaultItem;
98
+ }
99
+ | {
100
+ [key: string]: ToolbarDefaultItem;
101
+ };
102
+ }
103
+ export interface ToolbarRightPresetProps {
104
+ align: 'right';
105
+ items?: {
106
+ [key in TopToolbarDefaultKeys]?: ToolbarDefaultItem;
107
+ };
108
+ }
109
+ export interface ToolbarLeftPresetProps {
110
+ align: 'left';
111
+ items?: {
112
+ [key in TopToolbarDefaultKeys]?: ToolbarDefaultItem;
113
+ };
67
114
  }
68
115
 
69
116
  export type ToolbarPresetProps =
70
117
  | ToolbarBottomPresetProps
71
- | ToolbarOtherPresetProps;
118
+ | ToolbarTopPresetProps
119
+ | ToolbarLeftPresetProps
120
+ | ToolbarRightPresetProps;
72
121
 
73
122
  const ToolbarPreset = (props: ToolbarPresetProps) => {
74
123
  const {align} = props;
@@ -79,41 +128,24 @@ const ToolbarPreset = (props: ToolbarPresetProps) => {
79
128
  return null;
80
129
  }
81
130
  if (align === 'left') {
82
- return (
83
- <Leftbar customItems={props?.customItems} includeDefaultItems={true} />
84
- );
131
+ return <Leftbar items={props?.items} includeDefaultItems={true} />;
85
132
  } else if (align === 'right') {
86
- return (
87
- <Rightbar customItems={props?.customItems} includeDefaultItems={true} />
88
- );
133
+ return <Rightbar items={props?.items} includeDefaultItems={true} />;
89
134
  } else if (align === 'top') {
90
135
  return isMobileUA() ? (
91
- <NavbarMobile
92
- customItems={props?.customItems}
93
- includeDefaultItems={true}
94
- defaultItemsConfig={props?.defaultItemsConfig}
95
- />
136
+ <NavbarMobile items={props?.items} includeDefaultItems={true} />
96
137
  ) : (
97
- <Navbar
98
- customItems={props?.customItems}
99
- includeDefaultItems={true}
100
- defaultItemsConfig={props?.defaultItemsConfig}
101
- />
138
+ <Navbar items={props?.items} includeDefaultItems={true} />
102
139
  );
103
140
  } else if (align === 'bottom') {
104
141
  return isMobileUA() ? (
105
142
  <ActionSheet
106
- customItems={props?.customItems}
143
+ items={props?.items}
107
144
  includeDefaultItems={true}
108
145
  snapPointsMinMax={props?.snapPointsMinMax}
109
- defaultItemsConfig={props?.defaultItemsConfig}
110
146
  />
111
147
  ) : (
112
- <Controls
113
- customItems={props?.customItems}
114
- includeDefaultItems={true}
115
- defaultItemsConfig={props?.defaultItemsConfig}
116
- />
148
+ <Controls items={props?.items} includeDefaultItems={true} />
117
149
  );
118
150
  } else {
119
151
  return null;