@amityco/react-native-social-uikit 4.0.0-b295c41.0 → 4.0.0-c2327e7.0

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 (204) hide show
  1. package/lib/commonjs/components/CreatePostChooseTargetModal/CreatePostChooseTargetModal.js +1 -1
  2. package/lib/commonjs/components/CreatePostChooseTargetModal/CreatePostChooseTargetModal.js.map +1 -1
  3. package/lib/commonjs/components/MediaSection/index.js +3 -3
  4. package/lib/commonjs/components/MediaSection/index.js.map +1 -1
  5. package/lib/commonjs/components/PostTypeChoiceModal/PostTypeChoiceModal.js +14 -5
  6. package/lib/commonjs/components/PostTypeChoiceModal/PostTypeChoiceModal.js.map +1 -1
  7. package/lib/commonjs/components/PostTypeChoiceModal/style.js +1 -2
  8. package/lib/commonjs/components/PostTypeChoiceModal/style.js.map +1 -1
  9. package/lib/commonjs/components/Social/PostList/index.js +1 -3
  10. package/lib/commonjs/components/Social/PostList/index.js.map +1 -1
  11. package/lib/commonjs/index.js +6 -0
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/commonjs/screens/CreateLivestream/CreateLivestream.js +16 -16
  14. package/lib/commonjs/screens/CreateLivestream/CreateLivestream.js.map +1 -1
  15. package/lib/commonjs/screens/LivestreamPlayer/index.js +3 -6
  16. package/lib/commonjs/screens/LivestreamPlayer/index.js.map +1 -1
  17. package/lib/commonjs/svg/svg-xml-list.js +1 -1
  18. package/lib/commonjs/util/postTypeChecker.js.map +1 -1
  19. package/lib/commonjs/v4/PublicApi/Components/AmityCreatePostMenuComponent/AmityCreatePostMenuComponent.js +11 -9
  20. package/lib/commonjs/v4/PublicApi/Components/AmityCreatePostMenuComponent/AmityCreatePostMenuComponent.js.map +1 -1
  21. package/lib/commonjs/v4/PublicApi/Elements/ButtonWithIconElement/styles.js +3 -2
  22. package/lib/commonjs/v4/PublicApi/Elements/ButtonWithIconElement/styles.js.map +1 -1
  23. package/lib/commonjs/v4/PublicApi/Pages/AmityCommunityProfilePage/AmityCommunityProfilePage.js +28 -25
  24. package/lib/commonjs/v4/PublicApi/Pages/AmityCommunityProfilePage/AmityCommunityProfilePage.js.map +1 -1
  25. package/lib/commonjs/v4/PublicApi/Pages/AmityCommunityProfilePage/styles.js +2 -2
  26. package/lib/commonjs/v4/PublicApi/Pages/AmityCommunityProfilePage/styles.js.map +1 -1
  27. package/lib/commonjs/v4/PublicApi/Pages/AmityCreateLivestreamPage/AmityCreateLivestreamPage.js +206 -68
  28. package/lib/commonjs/v4/PublicApi/Pages/AmityCreateLivestreamPage/AmityCreateLivestreamPage.js.map +1 -1
  29. package/lib/commonjs/v4/PublicApi/Pages/AmityCreateLivestreamPage/RoomView.js +50 -0
  30. package/lib/commonjs/v4/PublicApi/Pages/AmityCreateLivestreamPage/RoomView.js.map +1 -0
  31. package/lib/commonjs/v4/PublicApi/Pages/AmityCreateLivestreamPage/styles.js +71 -3
  32. package/lib/commonjs/v4/PublicApi/Pages/AmityCreateLivestreamPage/styles.js.map +1 -1
  33. package/lib/commonjs/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.js +120 -117
  34. package/lib/commonjs/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.js.map +1 -1
  35. package/lib/commonjs/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.js.map +1 -1
  36. package/lib/commonjs/v4/component/LivestreamContent/index.js +12 -12
  37. package/lib/commonjs/v4/component/LivestreamContent/index.js.map +1 -1
  38. package/lib/commonjs/v4/component/PostContent/index.js +4 -4
  39. package/lib/commonjs/v4/component/PostContent/index.js.map +1 -1
  40. package/lib/commonjs/v4/component/PostMenu/index.js +2 -2
  41. package/lib/commonjs/v4/component/PostMenu/index.js.map +1 -1
  42. package/lib/commonjs/v4/component/Toast/index.js +4 -4
  43. package/lib/commonjs/v4/component/Toast/index.js.map +1 -1
  44. package/lib/commonjs/v4/component/Toast/styles.js +2 -2
  45. package/lib/commonjs/v4/component/Toast/styles.js.map +1 -1
  46. package/lib/commonjs/v4/enum/roomStatus.js +14 -0
  47. package/lib/commonjs/v4/enum/roomStatus.js.map +1 -0
  48. package/lib/commonjs/v4/hook/index.js +22 -0
  49. package/lib/commonjs/v4/hook/index.js.map +1 -1
  50. package/lib/commonjs/v4/hook/useCustomRankingGlobalFeed.js +1 -3
  51. package/lib/commonjs/v4/hook/useCustomRankingGlobalFeed.js.map +1 -1
  52. package/lib/commonjs/v4/hook/usePostSubscription.js +38 -0
  53. package/lib/commonjs/v4/hook/usePostSubscription.js.map +1 -0
  54. package/lib/commonjs/v4/hook/useRoomSubscription.js +22 -0
  55. package/lib/commonjs/v4/hook/useRoomSubscription.js.map +1 -0
  56. package/lib/commonjs/v4/index.js +7 -0
  57. package/lib/commonjs/v4/index.js.map +1 -1
  58. package/lib/commonjs/v4/stores/slices/toast.js +4 -1
  59. package/lib/commonjs/v4/stores/slices/toast.js.map +1 -1
  60. package/lib/module/components/CreatePostChooseTargetModal/CreatePostChooseTargetModal.js +1 -1
  61. package/lib/module/components/CreatePostChooseTargetModal/CreatePostChooseTargetModal.js.map +1 -1
  62. package/lib/module/components/MediaSection/index.js +3 -3
  63. package/lib/module/components/MediaSection/index.js.map +1 -1
  64. package/lib/module/components/PostTypeChoiceModal/PostTypeChoiceModal.js +15 -8
  65. package/lib/module/components/PostTypeChoiceModal/PostTypeChoiceModal.js.map +1 -1
  66. package/lib/module/components/PostTypeChoiceModal/style.js +1 -2
  67. package/lib/module/components/PostTypeChoiceModal/style.js.map +1 -1
  68. package/lib/module/components/Social/PostList/index.js +1 -3
  69. package/lib/module/components/Social/PostList/index.js.map +1 -1
  70. package/lib/module/index.js +2 -6
  71. package/lib/module/index.js.map +1 -1
  72. package/lib/module/screens/CreateLivestream/CreateLivestream.js +17 -17
  73. package/lib/module/screens/CreateLivestream/CreateLivestream.js.map +1 -1
  74. package/lib/module/screens/LivestreamPlayer/index.js +4 -8
  75. package/lib/module/screens/LivestreamPlayer/index.js.map +1 -1
  76. package/lib/module/svg/svg-xml-list.js +1 -1
  77. package/lib/module/util/postTypeChecker.js.map +1 -1
  78. package/lib/module/v4/PublicApi/Components/AmityCreatePostMenuComponent/AmityCreatePostMenuComponent.js +11 -9
  79. package/lib/module/v4/PublicApi/Components/AmityCreatePostMenuComponent/AmityCreatePostMenuComponent.js.map +1 -1
  80. package/lib/module/v4/PublicApi/Elements/ButtonWithIconElement/styles.js +3 -2
  81. package/lib/module/v4/PublicApi/Elements/ButtonWithIconElement/styles.js.map +1 -1
  82. package/lib/module/v4/PublicApi/Pages/AmityCommunityProfilePage/AmityCommunityProfilePage.js +29 -26
  83. package/lib/module/v4/PublicApi/Pages/AmityCommunityProfilePage/AmityCommunityProfilePage.js.map +1 -1
  84. package/lib/module/v4/PublicApi/Pages/AmityCommunityProfilePage/styles.js +2 -2
  85. package/lib/module/v4/PublicApi/Pages/AmityCommunityProfilePage/styles.js.map +1 -1
  86. package/lib/module/v4/PublicApi/Pages/AmityCreateLivestreamPage/AmityCreateLivestreamPage.js +211 -72
  87. package/lib/module/v4/PublicApi/Pages/AmityCreateLivestreamPage/AmityCreateLivestreamPage.js.map +1 -1
  88. package/lib/module/v4/PublicApi/Pages/AmityCreateLivestreamPage/RoomView.js +42 -0
  89. package/lib/module/v4/PublicApi/Pages/AmityCreateLivestreamPage/RoomView.js.map +1 -0
  90. package/lib/module/v4/PublicApi/Pages/AmityCreateLivestreamPage/styles.js +71 -3
  91. package/lib/module/v4/PublicApi/Pages/AmityCreateLivestreamPage/styles.js.map +1 -1
  92. package/lib/module/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.js +123 -120
  93. package/lib/module/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.js.map +1 -1
  94. package/lib/module/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.js.map +1 -1
  95. package/lib/module/v4/component/LivestreamContent/index.js +13 -13
  96. package/lib/module/v4/component/LivestreamContent/index.js.map +1 -1
  97. package/lib/module/v4/component/PostContent/index.js +4 -4
  98. package/lib/module/v4/component/PostContent/index.js.map +1 -1
  99. package/lib/module/v4/component/PostMenu/index.js +2 -2
  100. package/lib/module/v4/component/PostMenu/index.js.map +1 -1
  101. package/lib/module/v4/component/Toast/index.js +4 -4
  102. package/lib/module/v4/component/Toast/index.js.map +1 -1
  103. package/lib/module/v4/component/Toast/styles.js +2 -2
  104. package/lib/module/v4/component/Toast/styles.js.map +1 -1
  105. package/lib/module/v4/enum/roomStatus.js +8 -0
  106. package/lib/module/v4/enum/roomStatus.js.map +1 -0
  107. package/lib/module/v4/hook/index.js +2 -0
  108. package/lib/module/v4/hook/index.js.map +1 -1
  109. package/lib/module/v4/hook/useCustomRankingGlobalFeed.js +1 -3
  110. package/lib/module/v4/hook/useCustomRankingGlobalFeed.js.map +1 -1
  111. package/lib/module/v4/hook/usePostSubscription.js +31 -0
  112. package/lib/module/v4/hook/usePostSubscription.js.map +1 -0
  113. package/lib/module/v4/hook/useRoomSubscription.js +15 -0
  114. package/lib/module/v4/hook/useRoomSubscription.js.map +1 -0
  115. package/lib/module/v4/index.js +1 -1
  116. package/lib/module/v4/index.js.map +1 -1
  117. package/lib/module/v4/stores/slices/toast.js +4 -1
  118. package/lib/module/v4/stores/slices/toast.js.map +1 -1
  119. package/lib/typescript/src/components/MediaSection/index.d.ts.map +1 -1
  120. package/lib/typescript/src/components/PostTypeChoiceModal/style.d.ts +1 -2
  121. package/lib/typescript/src/components/PostTypeChoiceModal/style.d.ts.map +1 -1
  122. package/lib/typescript/src/components/Social/PostList/index.d.ts +1 -3
  123. package/lib/typescript/src/components/Social/PostList/index.d.ts.map +1 -1
  124. package/lib/typescript/src/index.d.ts +2 -2
  125. package/lib/typescript/src/index.d.ts.map +1 -1
  126. package/lib/typescript/src/screens/LivestreamPlayer/index.d.ts.map +1 -1
  127. package/lib/typescript/src/util/postTypeChecker.d.ts +1 -1
  128. package/lib/typescript/src/util/postTypeChecker.d.ts.map +1 -1
  129. package/lib/typescript/src/v4/PublicApi/Components/AmityPostContentComponent/AmityPostContentComponent.d.ts +1 -3
  130. package/lib/typescript/src/v4/PublicApi/Components/AmityPostContentComponent/AmityPostContentComponent.d.ts.map +1 -1
  131. package/lib/typescript/src/v4/PublicApi/Elements/ButtonWithIconElement/styles.d.ts +1 -0
  132. package/lib/typescript/src/v4/PublicApi/Elements/ButtonWithIconElement/styles.d.ts.map +1 -1
  133. package/lib/typescript/src/v4/PublicApi/Pages/AmityCommunityProfilePage/AmityCommunityProfilePage.d.ts.map +1 -1
  134. package/lib/typescript/src/v4/PublicApi/Pages/AmityCommunityProfilePage/styles.d.ts +1 -1
  135. package/lib/typescript/src/v4/PublicApi/Pages/AmityCreateLivestreamPage/AmityCreateLivestreamPage.d.ts.map +1 -1
  136. package/lib/typescript/src/v4/PublicApi/Pages/AmityCreateLivestreamPage/RoomView.d.ts +8 -0
  137. package/lib/typescript/src/v4/PublicApi/Pages/AmityCreateLivestreamPage/RoomView.d.ts.map +1 -0
  138. package/lib/typescript/src/v4/PublicApi/Pages/AmityCreateLivestreamPage/styles.d.ts +70 -2
  139. package/lib/typescript/src/v4/PublicApi/Pages/AmityCreateLivestreamPage/styles.d.ts.map +1 -1
  140. package/lib/typescript/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.d.ts.map +1 -1
  141. package/lib/typescript/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.d.ts.map +1 -1
  142. package/lib/typescript/src/v4/component/LivestreamContent/index.d.ts +1 -1
  143. package/lib/typescript/src/v4/component/LivestreamContent/index.d.ts.map +1 -1
  144. package/lib/typescript/src/v4/component/PostContent/index.d.ts.map +1 -1
  145. package/lib/typescript/src/v4/component/Toast/styles.d.ts +1 -1
  146. package/lib/typescript/src/v4/component/Toast/styles.d.ts.map +1 -1
  147. package/lib/typescript/src/v4/enum/roomStatus.d.ts +8 -0
  148. package/lib/typescript/src/v4/enum/roomStatus.d.ts.map +1 -0
  149. package/lib/typescript/src/v4/hook/index.d.ts +2 -0
  150. package/lib/typescript/src/v4/hook/index.d.ts.map +1 -1
  151. package/lib/typescript/src/v4/hook/usePendingPostQuery.d.ts +3 -0
  152. package/lib/typescript/src/v4/hook/usePendingPostQuery.d.ts.map +1 -1
  153. package/lib/typescript/src/v4/hook/usePostSubscription.d.ts +4 -0
  154. package/lib/typescript/src/v4/hook/usePostSubscription.d.ts.map +1 -0
  155. package/lib/typescript/src/v4/hook/useRoomSubscription.d.ts +4 -0
  156. package/lib/typescript/src/v4/hook/useRoomSubscription.d.ts.map +1 -0
  157. package/lib/typescript/src/v4/index.d.ts +1 -0
  158. package/lib/typescript/src/v4/index.d.ts.map +1 -1
  159. package/lib/typescript/src/v4/routes/RouteParamList.d.ts +1 -1
  160. package/lib/typescript/src/v4/routes/RouteParamList.d.ts.map +1 -1
  161. package/lib/typescript/src/v4/stores/slices/toast.d.ts +1 -0
  162. package/lib/typescript/src/v4/stores/slices/toast.d.ts.map +1 -1
  163. package/package.json +6 -3
  164. package/src/components/CreatePostChooseTargetModal/CreatePostChooseTargetModal.tsx +1 -1
  165. package/src/components/MediaSection/index.tsx +4 -6
  166. package/src/components/PostTypeChoiceModal/PostTypeChoiceModal.tsx +15 -15
  167. package/src/components/PostTypeChoiceModal/style.ts +1 -2
  168. package/src/components/Social/PostList/index.tsx +1 -4
  169. package/src/index.tsx +2 -2
  170. package/src/screens/CreateLivestream/CreateLivestream.tsx +17 -17
  171. package/src/screens/LivestreamPlayer/index.tsx +9 -15
  172. package/src/svg/svg-xml-list.ts +1 -1
  173. package/src/util/postTypeChecker.ts +1 -1
  174. package/src/v4/PublicApi/Components/AmityCreatePostMenuComponent/AmityCreatePostMenuComponent.tsx +10 -10
  175. package/src/v4/PublicApi/Components/AmityPostContentComponent/AmityPostContentComponent.tsx +1 -1
  176. package/src/v4/PublicApi/Elements/ButtonWithIconElement/styles.ts +3 -2
  177. package/src/v4/PublicApi/Pages/AmityCommunityProfilePage/AmityCommunityProfilePage.tsx +24 -25
  178. package/src/v4/PublicApi/Pages/AmityCommunityProfilePage/styles.ts +2 -2
  179. package/src/v4/PublicApi/Pages/AmityCreateLivestreamPage/AmityCreateLivestreamPage.tsx +241 -89
  180. package/src/v4/PublicApi/Pages/AmityCreateLivestreamPage/RoomView.tsx +48 -0
  181. package/src/v4/PublicApi/Pages/AmityCreateLivestreamPage/styles.ts +72 -3
  182. package/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.tsx +135 -148
  183. package/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.ts +1 -0
  184. package/src/v4/component/LivestreamContent/index.tsx +21 -22
  185. package/src/v4/component/PostContent/index.tsx +6 -8
  186. package/src/v4/component/PostMenu/index.tsx +2 -2
  187. package/src/v4/component/Toast/index.tsx +1 -1
  188. package/src/v4/component/Toast/styles.ts +2 -2
  189. package/src/v4/enum/roomStatus.ts +7 -0
  190. package/src/v4/hook/index.ts +2 -0
  191. package/src/v4/hook/useCustomRankingGlobalFeed.ts +1 -1
  192. package/src/v4/hook/usePostSubscription.ts +34 -0
  193. package/src/v4/hook/useRoomSubscription.ts +19 -0
  194. package/src/v4/index.tsx +1 -1
  195. package/src/v4/routes/RouteParamList.tsx +1 -1
  196. package/src/v4/stores/slices/toast.ts +5 -0
  197. package/uikit.config.json +1 -1
  198. package/lib/commonjs/v4/enum/livestreamStatus.js +0 -13
  199. package/lib/commonjs/v4/enum/livestreamStatus.js.map +0 -1
  200. package/lib/module/v4/enum/livestreamStatus.js +0 -7
  201. package/lib/module/v4/enum/livestreamStatus.js.map +0 -1
  202. package/lib/typescript/src/v4/enum/livestreamStatus.d.ts +0 -7
  203. package/lib/typescript/src/v4/enum/livestreamStatus.d.ts.map +0 -1
  204. package/src/v4/enum/livestreamStatus.ts +0 -6
@@ -1,10 +1,4 @@
1
- import React, {
2
- useCallback,
3
- useEffect,
4
- useLayoutEffect,
5
- useRef,
6
- useState,
7
- } from 'react';
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
8
2
  import {
9
3
  Alert,
10
4
  Image,
@@ -12,20 +6,15 @@ import {
12
6
  Platform,
13
7
  TextInput,
14
8
  TouchableOpacity,
15
- // Linking,
16
9
  View,
17
10
  ImageStyle,
11
+ Linking,
18
12
  } from 'react-native';
19
13
  import { useStyles } from './styles';
20
14
  import { SafeAreaView } from 'react-native-safe-area-context';
21
- // import {
22
- // AmityStreamBroadcasterState,
23
- // AmityVideoBroadcaster,
24
- // // @ts-ignore
25
- // } from '@amityco/video-broadcaster-react-native';
26
15
  import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
27
16
  import useImagePicker from '../../../../v4/hook/useImagePicker';
28
- import { arrowDown } from '../../../../v4/assets/icons';
17
+ import { arrowDown, close } from '../../../../v4/assets/icons';
29
18
  import { SvgXml } from 'react-native-svg';
30
19
  import { Typography } from '../../../component/Typography/Typography';
31
20
  import { useTheme } from 'react-native-paper';
@@ -33,12 +22,12 @@ import { MyMD3Theme } from '../../../../providers/amity-ui-kit-provider';
33
22
  import { useBottomSheet } from '../../../../redux/slices/bottomSheetSlice';
34
23
  import { CircularProgressIndicator } from '../../../component/CircularProgressIndicator';
35
24
  import { RootStackParamList } from '../../../../v4/routes/RouteParamList';
36
- import { PostRepository, StreamRepository } from '@amityco/ts-sdk-react-native';
25
+ import { PostRepository, RoomRepository } from '@amityco/ts-sdk-react-native';
37
26
  import { NativeStackNavigationProp } from '@react-navigation/native-stack';
38
- // import Button from '../../../component/Button/Button';
27
+ import Button from '../../../component/Button/Button';
39
28
  import { useRequestPermission } from '../../../../v4/hook/useCamera';
40
29
  import NetInfo from '@react-native-community/netinfo';
41
- import { LivestreamStatus } from '../../../enum/livestreamStatus';
30
+ import { RoomStatus } from '../../../enum/roomStatus';
42
31
  import { AmityThumbnailActionComponent } from '../../Components/AmityThumbnailActionComponent';
43
32
  import { StartLivestreamButton } from '../../../elements/StartLivestreamButton';
44
33
  import { PageID } from '../../../enum';
@@ -48,6 +37,18 @@ import { EndLiveStreamButton } from '../../../elements/EndLiveStreamButton';
48
37
  import { AddThumbnailButton } from '../../../elements/AddThumbnailButton';
49
38
  import { SwitchCameraButton } from '../../../elements/SwitchCameraButton';
50
39
 
40
+ import { Track, LocalVideoTrack } from 'livekit-client';
41
+ import { LiveKitRoom, registerGlobals } from '@livekit/react-native';
42
+ import { RoomView } from './RoomView';
43
+ import { Camera, useCameraDevice } from 'react-native-vision-camera';
44
+ import { useRoomSubscription } from '../../../../v4/hook/useRoomSubscription';
45
+ import { useToast } from '../../../../v4/stores/slices/toast';
46
+
47
+ // Register WebRTC globals required for LiveKit
48
+ registerGlobals();
49
+
50
+ const serverUrl = 'wss://sp-live-3tr59jrk.livekit.cloud';
51
+
51
52
  const calculateTime = (time: number) => {
52
53
  const hours = Math.floor(time / 3600000);
53
54
  const minutes = Math.floor(time / 60000);
@@ -64,7 +65,6 @@ const calculateTime = (time: number) => {
64
65
 
65
66
  function AmityCreateLivestreamPage() {
66
67
  const styles = useStyles();
67
- const streamRef = useRef<any>(null);
68
68
  const navigation =
69
69
  useNavigation<NativeStackNavigationProp<RootStackParamList>>();
70
70
  const theme = useTheme<MyMD3Theme>();
@@ -75,15 +75,28 @@ function AmityCreateLivestreamPage() {
75
75
  const [isLive, setIsLive] = useState<boolean>(false);
76
76
  const [description, setDescription] = useState<string>('');
77
77
  const [isEnding, setIsEnding] = useState<boolean>(false);
78
+ const [countdown, setCountdown] = useState<number | null>(null);
78
79
  const [post, setPost] = useState<Amity.Post | null>(null);
79
- const [stream, setStream] = useState<Amity.Stream | null>(null);
80
- const [timer] = useState<number | null>(null);
80
+ const [room, setRoom] = useState<Amity.Room | null>(null);
81
+ const timerRef = useRef<number | null>(null);
81
82
  const [isConnecting, setIsConnecting] = useState<boolean>(false);
82
83
  const [androidPermission, setAndroidPermission] = useState<boolean>(false);
83
84
  const [iOSPermission, setIOSPermission] = useState<boolean>(true);
84
85
  const [reconnecting, setReconnecting] = useState<boolean>(false);
86
+ const [livekitParticipant, setLivekitParticipant] = useState<any>(null);
87
+ const [isFrontCamera, setIsFrontCamera] = useState<boolean>(true);
88
+ const [roomToken, setRoomToken] = useState<Amity.BroadcasterData | null>(
89
+ null
90
+ );
85
91
  const unsubscribeRef = useRef<Amity.Unsubscriber>(null);
86
92
 
93
+ useRoomSubscription({ room });
94
+ const { showToast } = useToast();
95
+
96
+ const frontCamera = useCameraDevice('front');
97
+ const backCamera = useCameraDevice('back');
98
+ const cameraDevice = isFrontCamera ? frontCamera : backCamera;
99
+
87
100
  const {
88
101
  imageUri,
89
102
  isLoading,
@@ -100,6 +113,43 @@ function AmityCreateLivestreamPage() {
100
113
  (Platform.OS === 'android' && androidPermission) ||
101
114
  (Platform.OS === 'ios' && iOSPermission);
102
115
 
116
+ const fourHours = 4 * 60 * 60 * 1000; // 4 hours
117
+ const countdownStart = fourHours - 10 * 1000; // Start countdown 10 seconds before end
118
+ const toastTriggerTime = fourHours - 3 * 60 * 1000; // Show toast 3 minutes before end
119
+
120
+ const switchCamera = useCallback(async () => {
121
+ if (isLive && livekitParticipant) {
122
+ try {
123
+ const cameraPublication = livekitParticipant.getTrackPublication(
124
+ Track.Source.Camera
125
+ );
126
+
127
+ if (cameraPublication?.track) {
128
+ const videoTrack = cameraPublication.track as LocalVideoTrack;
129
+
130
+ // Stop current camera
131
+ await videoTrack.stop();
132
+
133
+ // Get new facing mode
134
+ const newFacingMode = isFrontCamera ? 'environment' : 'user';
135
+
136
+ // Restart camera with new facing mode
137
+ await videoTrack.restartTrack({
138
+ facingMode: newFacingMode,
139
+ });
140
+
141
+ // Toggle the camera state
142
+ setIsFrontCamera((prev) => !prev);
143
+ }
144
+ } catch (error) {
145
+ console.error('Failed to switch camera:', error);
146
+ }
147
+ } else {
148
+ // Just toggle the camera state for preview
149
+ setIsFrontCamera((prev) => !prev);
150
+ }
151
+ }, [livekitParticipant, isFrontCamera, isLive]);
152
+
103
153
  useRequestPermission({
104
154
  shouldCall: Platform.OS === 'ios',
105
155
  onRequestPermissionFailed: (callback?: () => void) => {
@@ -156,37 +206,54 @@ function AmityCreateLivestreamPage() {
156
206
  setIsLive(true);
157
207
  setIsConnecting(true);
158
208
 
159
- const { data: newStream } = await StreamRepository.createStream({
209
+ const { data: newStream } = await RoomRepository.createRoom({
160
210
  title,
161
211
  description: description || undefined,
162
212
  thumbnailFileId: uploadedImage?.fileId,
213
+ type: 'coHosts',
163
214
  });
164
215
 
216
+ setRoom(newStream);
217
+
165
218
  if (newStream) {
219
+ const roomTokenResponse = await RoomRepository.getBroadcasterData(
220
+ newStream.roomId
221
+ );
222
+
223
+ setRoomToken(roomTokenResponse);
224
+
166
225
  const params = {
167
226
  targetId,
168
227
  targetType,
169
- dataType: 'liveStream' as Amity.PostContentType,
228
+ dataType: 'room' as Amity.PostContentType,
170
229
  data: {
171
230
  text: `${newStream.title}${
172
231
  newStream.description ? `\n\n${newStream.description}` : ''
173
232
  }`,
174
- streamId: newStream.streamId,
233
+ roomId: newStream.roomId,
175
234
  },
176
235
  };
177
236
 
178
237
  const newPost = await PostRepository.createPost(params);
179
238
 
180
- streamRef.current = StreamRepository.getStreamById(
181
- newStream.streamId,
182
- ({ data }) => {
183
- setStream(data);
184
- setPost(newPost.data);
185
- streamRef?.current?.startPublish(newStream.streamId);
186
- }
187
- );
239
+ setPost(newPost.data);
240
+
241
+ // Set isConnecting to false since LiveKit room is already connected
242
+ setIsConnecting(false);
243
+
244
+ // Start the timer when live stream actually starts
245
+ if (timerRef.current) {
246
+ clearInterval(timerRef.current);
247
+ }
248
+
249
+ const intervalId = setInterval(() => {
250
+ setTime((prev) => prev + 1000);
251
+ }, 1000);
252
+
253
+ timerRef.current = intervalId;
188
254
  }
189
255
  } catch (error) {
256
+ console.log('startLiveStream error', error);
190
257
  setIsLive(false);
191
258
  setIsConnecting(false);
192
259
  Alert.alert(
@@ -201,17 +268,6 @@ function AmityCreateLivestreamPage() {
201
268
  }
202
269
  };
203
270
 
204
- // const onBroadcastStateChange = (state: AmityStreamBroadcasterState) => {
205
- // if (state === AmityStreamBroadcasterState.CONNECTED) {
206
- // setIsConnecting(false);
207
- // setReconnecting(false);
208
- // const intervalId = setInterval(() => {
209
- // setTime((prev) => prev + 1000);
210
- // }, 1000);
211
- // setTimer(intervalId);
212
- // }
213
- // };
214
-
215
271
  const confirmEndStreamAlert = () => {
216
272
  Alert.alert(
217
273
  'End live stream?',
@@ -234,21 +290,22 @@ function AmityCreateLivestreamPage() {
234
290
 
235
291
  const endLiveStream = useCallback(
236
292
  async (showEndPopup = false) => {
237
- if (stream) {
293
+ if (room) {
238
294
  setIsEnding(true);
239
295
  try {
240
- await StreamRepository.disposeStream(stream.streamId);
296
+ await RoomRepository.stopRoom(room.roomId);
241
297
  } catch (e) {
242
298
  console.log('disposeStream error', e);
243
299
  } finally {
244
- streamRef?.current.stopPublish();
245
-
246
300
  setIsLive(false);
247
- setStream(null);
301
+ setRoom(null);
248
302
  setTitle('');
249
303
  setDescription('');
250
304
  setTime(0);
251
- clearInterval(timer);
305
+ if (timerRef.current) {
306
+ clearInterval(timerRef.current);
307
+ timerRef.current = null;
308
+ }
252
309
  setIsEnding(false);
253
310
  setReconnecting(false);
254
311
 
@@ -259,15 +316,40 @@ function AmityCreateLivestreamPage() {
259
316
  }
260
317
  }
261
318
  },
262
- [post, stream, timer, navigation]
319
+ [post, room, navigation]
263
320
  );
264
321
 
265
322
  useEffect(() => {
266
- const fourHours = 4 * 60 * 60 * 1000;
267
- if (streamRef.current && stream && time >= fourHours) {
323
+ // Show toast when 3 minutes left
324
+ if (room && time >= toastTriggerTime && time < toastTriggerTime + 1000) {
325
+ showToast({
326
+ type: 'informative',
327
+ message:
328
+ 'Your live will automatically end once it reaches 4-hour limit.',
329
+ duration: 3000,
330
+ bottomPosition: 96,
331
+ });
332
+ }
333
+
334
+ if (room && time >= fourHours) {
268
335
  endLiveStream(true);
336
+ setCountdown(null);
337
+ } else if (room && time >= countdownStart && time < fourHours) {
338
+ // Calculate countdown from 10 to 0
339
+ const remaining = Math.ceil((fourHours - time) / 1000);
340
+ setCountdown(remaining);
341
+ } else {
342
+ setCountdown(null);
269
343
  }
270
- }, [endLiveStream, stream, time]);
344
+ }, [
345
+ endLiveStream,
346
+ room,
347
+ time,
348
+ showToast,
349
+ toastTriggerTime,
350
+ fourHours,
351
+ countdownStart,
352
+ ]);
271
353
 
272
354
  useEffect(() => {
273
355
  if (Platform.OS === 'android') checkPermissionAndroid();
@@ -284,48 +366,34 @@ function AmityCreateLivestreamPage() {
284
366
  return () => unsubscribe();
285
367
  }, []);
286
368
 
287
- useLayoutEffect(() => {
288
- setTimeout(() => {
289
- streamRef.current && streamRef.current.switchCamera();
290
- }, 300);
291
- }, [streamRef]);
292
-
293
369
  useEffect(() => {
294
370
  let threeMinutesTimeout: number;
295
371
 
296
- if (reconnecting && stream && stream?.status === 'live') {
372
+ if (reconnecting && room && room?.status === RoomStatus.live) {
297
373
  threeMinutesTimeout = setTimeout(() => {
298
374
  endLiveStream();
299
375
  }, 1000 * 60 * 3);
300
376
  }
301
377
 
302
- if (
303
- !reconnecting &&
304
- stream &&
305
- stream?.status === 'live' &&
306
- streamRef?.current
307
- ) {
308
- streamRef?.current?.startPublish(stream?.streamId);
309
-
378
+ if (!reconnecting && room && room?.status === RoomStatus.live) {
310
379
  if (threeMinutesTimeout) {
311
380
  clearTimeout(threeMinutesTimeout);
312
381
  threeMinutesTimeout = null;
313
382
  }
314
383
  }
315
- }, [reconnecting, endLiveStream, stream]);
384
+ }, [reconnecting, endLiveStream, room]);
316
385
 
317
386
  useEffect(() => {
318
387
  const isTerminated =
319
- stream?.moderation?.terminateLabels &&
320
- stream?.moderation?.terminateLabels?.length > 0;
388
+ room?.moderation?.terminateLabels &&
389
+ room?.moderation?.terminateLabels?.length > 0;
321
390
  const isLiveOrEnded =
322
- stream?.status === LivestreamStatus.live ||
323
- stream?.status === LivestreamStatus.ended;
391
+ room?.status === RoomStatus.live || room?.status === RoomStatus.ended;
324
392
 
325
393
  if (isLiveOrEnded && isTerminated) {
326
394
  navigation.replace('LivestreamTerminated', { type: 'streamer' });
327
395
  }
328
- }, [stream?.moderation?.terminateLabels, stream?.status, navigation]);
396
+ }, [room?.moderation?.terminateLabels, room?.status, navigation]);
329
397
 
330
398
  useEffect(() => {
331
399
  const unsubscribe = unsubscribeRef.current;
@@ -345,17 +413,53 @@ function AmityCreateLivestreamPage() {
345
413
  style={[styles.overlay, !hasPermission && styles.noPermissionOverlay]}
346
414
  />
347
415
  )}
348
- {/* {hasPermission ? (
349
- <View style={styles.cameraContainer}>
350
- <View style={styles.camera}>
351
- <AmityVideoBroadcaster
352
- ref={streamRef}
353
- bitrate={2 * 1024 * 1024}
354
- onBroadcastStateChange={onBroadcastStateChange}
355
- resolution={{ width: 1280, height: 720 }}
356
- />
416
+
417
+ {/* Preview camera part */}
418
+
419
+ {hasPermission ? (
420
+ roomToken ? (
421
+ <LiveKitRoom
422
+ serverUrl={serverUrl}
423
+ token={roomToken.coHostToken}
424
+ connect={true}
425
+ options={{
426
+ adaptiveStream: { pixelDensity: 'screen' },
427
+ }}
428
+ audio={{
429
+ echoCancellation: true,
430
+ noiseSuppression: true,
431
+ autoGainControl: true,
432
+ }}
433
+ video={{
434
+ facingMode: isFrontCamera ? 'user' : 'environment',
435
+ }}
436
+ onConnected={() => {
437
+ setIsConnecting(false);
438
+ setReconnecting(false);
439
+ }}
440
+ >
441
+ <View style={styles.cameraContainer}>
442
+ <View style={styles.camera}>
443
+ <RoomView
444
+ onLocalParticipantReady={setLivekitParticipant}
445
+ isFrontCamera={isFrontCamera}
446
+ />
447
+ </View>
448
+ </View>
449
+ </LiveKitRoom>
450
+ ) : (
451
+ <View style={styles.cameraContainer}>
452
+ <View style={styles.camera}>
453
+ {cameraDevice && (
454
+ <Camera
455
+ style={{ flex: 1 }}
456
+ device={cameraDevice}
457
+ isActive={true}
458
+ />
459
+ )}
460
+ </View>
357
461
  </View>
358
- </View>
462
+ )
359
463
  ) : (
360
464
  <View style={styles.permission}>
361
465
  <Typography.TitleBold style={styles.permissionTitle}>
@@ -374,7 +478,8 @@ function AmityCreateLivestreamPage() {
374
478
  </Typography.BodyBold>
375
479
  </Button>
376
480
  </View>
377
- )} */}
481
+ )}
482
+
378
483
  {isEnding && (
379
484
  <View style={styles.connecting}>
380
485
  <CircularProgressIndicator size={40} strokeWidth={2} />
@@ -406,12 +511,46 @@ function AmityCreateLivestreamPage() {
406
511
  </Typography.Caption>
407
512
  </View>
408
513
  )}
514
+
515
+ <TouchableOpacity
516
+ style={styles.closeButton}
517
+ onPress={() => confirmEndStreamAlert()}
518
+ >
519
+ <SvgXml
520
+ xml={close()}
521
+ width="28"
522
+ height="28"
523
+ color={theme.colors.background}
524
+ />
525
+ </TouchableOpacity>
526
+
409
527
  <View style={styles.timer}>
410
528
  <LiveTimerStatus
411
529
  time={calculateTime(time)}
412
530
  pageId={PageID.create_livestream_page}
413
531
  />
414
532
  </View>
533
+ {countdown !== null && (
534
+ <View style={styles.countdownOverlay}>
535
+ <View style={styles.countdownContainer}>
536
+ <Typography.TitleBold style={styles.countdownText}>
537
+ Live stream ends in
538
+ </Typography.TitleBold>
539
+ <View style={styles.countdownCircle}>
540
+ <CircularProgressIndicator
541
+ size={64}
542
+ strokeWidth={2}
543
+ progress={((10 - countdown) / 10) * 100}
544
+ />
545
+ <View style={styles.countdownNumberContainer}>
546
+ <Typography.Title style={styles.countdownNumber}>
547
+ {countdown}
548
+ </Typography.Title>
549
+ </View>
550
+ </View>
551
+ </View>
552
+ </View>
553
+ )}
415
554
  </>
416
555
  )
417
556
  ) : (
@@ -443,7 +582,18 @@ function AmityCreateLivestreamPage() {
443
582
  />
444
583
  <TouchableOpacity
445
584
  style={styles.communityButton}
446
- onPress={() => navigation.goBack()}
585
+ onPress={() => {
586
+ const state = navigation.getState();
587
+ const routes = state.routes;
588
+ const currentIndex = state.index;
589
+ const previousRoute = routes[currentIndex - 1];
590
+
591
+ if (previousRoute?.name === 'LivestreamPostTargetSelection') {
592
+ navigation.goBack();
593
+ } else {
594
+ return;
595
+ }
596
+ }}
447
597
  activeOpacity={0.7}
448
598
  >
449
599
  <Typography.Body
@@ -452,7 +602,11 @@ function AmityCreateLivestreamPage() {
452
602
  ellipsizeMode="tail"
453
603
  >
454
604
  Live on{' '}
455
- <Typography.BodyBold numberOfLines={1} ellipsizeMode="tail">
605
+ <Typography.BodyBold
606
+ numberOfLines={1}
607
+ ellipsizeMode="tail"
608
+ style={styles.communityName}
609
+ >
456
610
  {targetName}
457
611
  </Typography.BodyBold>
458
612
  </Typography.Body>
@@ -567,9 +721,7 @@ function AmityCreateLivestreamPage() {
567
721
  )}
568
722
  <SwitchCameraButton
569
723
  pageId={PageID.create_livestream_page}
570
- onPress={() => {
571
- streamRef.current && streamRef.current.switchCamera();
572
- }}
724
+ onPress={switchCamera}
573
725
  />
574
726
  </View>
575
727
  </SafeAreaView>
@@ -0,0 +1,48 @@
1
+ import React, { useEffect } from 'react';
2
+ import { View } from 'react-native';
3
+ import { Track } from 'livekit-client';
4
+ import { VideoTrack, useLocalParticipant } from '@livekit/react-native';
5
+ import { useStyles } from './styles';
6
+
7
+ interface RoomViewProps {
8
+ onLocalParticipantReady?: (participant: any) => void;
9
+ isFrontCamera: boolean;
10
+ }
11
+
12
+ export const RoomView: React.FC<RoomViewProps> = ({
13
+ onLocalParticipantReady,
14
+ isFrontCamera,
15
+ }) => {
16
+ const { localParticipant } = useLocalParticipant();
17
+ const styles = useStyles();
18
+
19
+ useEffect(() => {
20
+ if (localParticipant && onLocalParticipantReady) {
21
+ onLocalParticipantReady(localParticipant);
22
+ }
23
+ }, [localParticipant, onLocalParticipantReady]);
24
+
25
+ if (!localParticipant?.isCameraEnabled) {
26
+ return <View style={styles.roomContainer} />;
27
+ }
28
+
29
+ const cameraTrack = localParticipant.getTrackPublication(Track.Source.Camera);
30
+
31
+ if (!cameraTrack?.track) {
32
+ return <View style={styles.roomContainer} />;
33
+ }
34
+
35
+ return (
36
+ <View style={styles.roomContainer}>
37
+ <VideoTrack
38
+ trackRef={{
39
+ participant: localParticipant,
40
+ publication: cameraTrack,
41
+ source: Track.Source.Camera,
42
+ }}
43
+ style={styles.videoTrack}
44
+ mirror={isFrontCamera}
45
+ />
46
+ </View>
47
+ );
48
+ };
@@ -8,7 +8,7 @@ export const useStyles = () => {
8
8
  const { height: screenHeight } = Dimensions.get('window');
9
9
  const insets = useSafeAreaInsets();
10
10
 
11
- const availableHeight = screenHeight - 80 - 60 - 40 - 40 - 120;
11
+ const availableHeight = screenHeight - 80 - 60 - 40 - 40 - 120 - 50;
12
12
  const styles = StyleSheet.create({
13
13
  container: {
14
14
  flex: 1,
@@ -26,7 +26,6 @@ export const useStyles = () => {
26
26
  },
27
27
  overlay: {
28
28
  flex: 1,
29
- height: '100%',
30
29
  top: 0,
31
30
  bottom: 0,
32
31
  left: 0,
@@ -158,12 +157,19 @@ export const useStyles = () => {
158
157
  text: {
159
158
  color: theme.colors.background,
160
159
  },
161
- timer: {
160
+
161
+ closeButton: {
162
162
  left: 16,
163
163
  zIndex: 100,
164
164
  position: 'absolute',
165
165
  top: 20 + insets.top,
166
166
  },
167
+ timer: {
168
+ right: 16,
169
+ zIndex: 100,
170
+ position: 'absolute',
171
+ top: 20 + insets.top,
172
+ },
167
173
  permission: {
168
174
  flex: 1,
169
175
  top: 80 + insets.top,
@@ -191,6 +197,69 @@ export const useStyles = () => {
191
197
  color: theme.colors.background,
192
198
  textAlign: 'center',
193
199
  },
200
+ containerRoom: {
201
+ flex: 1,
202
+ alignItems: 'stretch',
203
+ justifyContent: 'center',
204
+ padding: 10,
205
+ },
206
+ participantView: {
207
+ flex: 1,
208
+ margin: 5,
209
+ height: 200,
210
+ backgroundColor: '#ccc',
211
+ },
212
+ roomContainer: {
213
+ flex: 1,
214
+ width: '100%',
215
+ height: '100%',
216
+ },
217
+ videoTrack: {
218
+ width: '100%',
219
+ height: '100%',
220
+ },
221
+ countdownOverlay: {
222
+ position: 'absolute',
223
+ top: 0,
224
+ left: 0,
225
+ right: 0,
226
+ bottom: 80,
227
+ justifyContent: 'center',
228
+ alignItems: 'center',
229
+ backgroundColor: 'rgba(0, 0, 0, 0.7)',
230
+ zIndex: 150,
231
+ },
232
+ countdownContainer: {
233
+ alignItems: 'center',
234
+ gap: 24,
235
+ },
236
+ countdownCircle: {
237
+ position: 'relative',
238
+ alignItems: 'center',
239
+ justifyContent: 'center',
240
+ width: 72,
241
+ height: 72,
242
+ },
243
+ countdownNumberContainer: {
244
+ position: 'absolute',
245
+ top: 0,
246
+ left: 0,
247
+ right: 0,
248
+ bottom: 0,
249
+ alignItems: 'center',
250
+ justifyContent: 'center',
251
+ },
252
+ countdownNumber: {
253
+ fontSize: 32,
254
+ fontWeight: '700',
255
+ color: theme.colors.background,
256
+ },
257
+ countdownText: {
258
+ fontSize: 24,
259
+ fontWeight: '500',
260
+ color: theme.colors.background,
261
+ textAlign: 'center',
262
+ },
194
263
  });
195
264
 
196
265
  return styles;