@amityco/react-native-social-uikit 4.0.0-a9cb7bb.0 → 4.0.0-b511cc3d.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.
- package/lib/commonjs/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/DetailStyle.js +1 -1
- package/lib/commonjs/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/DetailStyle.js.map +1 -1
- package/lib/commonjs/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/FeedStyle.js +2 -1
- package/lib/commonjs/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/FeedStyle.js.map +1 -1
- package/lib/commonjs/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.js +93 -67
- package/lib/commonjs/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.js.map +1 -1
- package/lib/commonjs/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.js +2 -1
- package/lib/commonjs/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.js.map +1 -1
- package/lib/commonjs/v4/enum/roomStatus.js +1 -1
- package/lib/module/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/DetailStyle.js +1 -1
- package/lib/module/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/DetailStyle.js.map +1 -1
- package/lib/module/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/FeedStyle.js +2 -1
- package/lib/module/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/FeedStyle.js.map +1 -1
- package/lib/module/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.js +94 -68
- package/lib/module/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.js.map +1 -1
- package/lib/module/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.js +2 -1
- package/lib/module/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.js.map +1 -1
- package/lib/module/v4/enum/roomStatus.js +1 -1
- package/lib/typescript/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.d.ts.map +1 -1
- package/lib/typescript/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.d.ts +1 -0
- package/lib/typescript/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.d.ts.map +1 -1
- package/lib/typescript/src/v4/enum/roomStatus.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/DetailStyle.tsx +1 -1
- package/src/v4/PublicApi/Components/AmityPostEngagementActionsComponent/Components/FeedStyle.tsx +1 -1
- package/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/AmityLivestreamPlayerPage.tsx +150 -87
- package/src/v4/PublicApi/Pages/AmityLivestreamPlayerPage/styles.ts +1 -0
- package/src/v4/enum/roomStatus.ts +1 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import React, { useEffect, useState, useRef } from 'react';
|
|
2
|
-
import { View, TouchableOpacity } from 'react-native';
|
|
2
|
+
import { View, TouchableOpacity, Platform } from 'react-native';
|
|
3
3
|
import { useStyles } from './styles';
|
|
4
4
|
import LiveStreamEndThumbnail from '../../../component/LivestreamContent/LivestreamEndedThumbnail';
|
|
5
5
|
import { SvgXml } from 'react-native-svg';
|
|
6
|
-
import { RoomRepository } from '@amityco/ts-sdk-react-native';
|
|
7
6
|
import { close } from '../../../assets/icons';
|
|
8
7
|
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
|
|
9
8
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
|
@@ -20,6 +19,7 @@ import {
|
|
|
20
19
|
usePostSubscription,
|
|
21
20
|
useRoomSubscription,
|
|
22
21
|
} from '../../../../v4/hook/index';
|
|
22
|
+
import { RoomRepository } from '@amityco/ts-sdk-react-native';
|
|
23
23
|
|
|
24
24
|
function AmityLiveStreamPlayerPage() {
|
|
25
25
|
const { styles, theme } = useStyles();
|
|
@@ -29,18 +29,21 @@ function AmityLiveStreamPlayerPage() {
|
|
|
29
29
|
|
|
30
30
|
const [reconnecting, setReconnecting] = useState(false);
|
|
31
31
|
const [room, setRoom] = useState<Amity.Room | null>(null);
|
|
32
|
+
const [videoError, setVideoError] = useState(false);
|
|
32
33
|
const [error, setError] = useState<Error | null>(null);
|
|
34
|
+
const [, setPlayerInitialized] = useState(false);
|
|
35
|
+
const [videoKey, setVideoKey] = useState(0);
|
|
36
|
+
const [isPaused, setIsPaused] = useState(false);
|
|
33
37
|
const [wasLive, setWasLive] = useState(false);
|
|
34
|
-
const [showEndThumbnail, setShowEndThumbnail] = useState(false);
|
|
35
|
-
const { roomId, post } = route.params;
|
|
36
|
-
const { client } = useAuth();
|
|
37
|
-
const videoRef = useRef<any>(null);
|
|
38
|
-
const isProgrammaticDismiss = useRef(false);
|
|
39
38
|
|
|
39
|
+
const { roomId, post } = route.params;
|
|
40
40
|
const { subscribedPost } = usePostSubscription(post?.postId);
|
|
41
|
-
|
|
42
41
|
useRoomSubscription({ room });
|
|
43
42
|
|
|
43
|
+
const { client } = useAuth();
|
|
44
|
+
const videoRef = useRef<any>(null);
|
|
45
|
+
const isStreamEnding = useRef(false);
|
|
46
|
+
|
|
44
47
|
useEffect(() => {
|
|
45
48
|
const unsubscribe = RoomRepository.getRoom(
|
|
46
49
|
roomId,
|
|
@@ -54,22 +57,16 @@ function AmityLiveStreamPlayerPage() {
|
|
|
54
57
|
}, [roomId]);
|
|
55
58
|
|
|
56
59
|
useEffect(() => {
|
|
57
|
-
if (room?.
|
|
58
|
-
|
|
60
|
+
if (room?.status === RoomStatus.live) {
|
|
61
|
+
setWasLive(true);
|
|
59
62
|
}
|
|
60
|
-
}, [room?.
|
|
63
|
+
}, [room?.status]);
|
|
61
64
|
|
|
62
65
|
useEffect(() => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
room?.moderation?.terminateLabels?.length > 0;
|
|
66
|
-
const isLiveOrEnded =
|
|
67
|
-
room?.status === RoomStatus.live || room?.status === RoomStatus.ended;
|
|
68
|
-
|
|
69
|
-
if (isLiveOrEnded && isTerminated) {
|
|
70
|
-
navigation.replace('LivestreamTerminated', { type: 'viewer' });
|
|
66
|
+
if (room?.isDeleted || subscribedPost?.isDeleted) {
|
|
67
|
+
navigation.replace('PostDetail', { postId: subscribedPost?.postId });
|
|
71
68
|
}
|
|
72
|
-
}, [room?.
|
|
69
|
+
}, [room?.isDeleted, subscribedPost, navigation]);
|
|
73
70
|
|
|
74
71
|
useEffect(() => {
|
|
75
72
|
const unsubscribe = NetInfo.addEventListener((state) => {
|
|
@@ -78,44 +75,94 @@ function AmityLiveStreamPlayerPage() {
|
|
|
78
75
|
return () => unsubscribe();
|
|
79
76
|
}, []);
|
|
80
77
|
|
|
81
|
-
// Track if user was watching live
|
|
82
78
|
useEffect(() => {
|
|
83
|
-
if (room?.status
|
|
84
|
-
setWasLive(true);
|
|
85
|
-
}
|
|
86
|
-
}, [room?.status]);
|
|
79
|
+
if (!room?.status) return;
|
|
87
80
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
81
|
+
const shouldEnd =
|
|
82
|
+
room.status === RoomStatus.ended ||
|
|
83
|
+
(room.status === RoomStatus.recorded && wasLive);
|
|
84
|
+
|
|
85
|
+
if (!shouldEnd || isStreamEnding.current) return;
|
|
86
|
+
|
|
87
|
+
isStreamEnding.current = true;
|
|
88
|
+
setIsPaused(true);
|
|
89
|
+
|
|
90
|
+
if (Platform.OS === 'ios') {
|
|
91
|
+
// iOS: ONLY dismiss fullscreen. DO NOT touch key. DO NOT unmount.
|
|
92
|
+
requestAnimationFrame(() => {
|
|
93
|
+
videoRef.current?.dismissFullscreenPlayer?.();
|
|
94
|
+
});
|
|
95
|
+
} else {
|
|
96
|
+
// Android: HARD destroy
|
|
98
97
|
setTimeout(() => {
|
|
99
|
-
|
|
100
|
-
},
|
|
101
|
-
} else if (shouldShowEndThumbnail && !videoRef.current) {
|
|
102
|
-
// If video ref is already null, show end thumbnail immediately
|
|
103
|
-
setShowEndThumbnail(true);
|
|
104
|
-
} else if (!shouldShowEndThumbnail) {
|
|
105
|
-
setShowEndThumbnail(false);
|
|
98
|
+
setVideoKey((prev) => prev + 1);
|
|
99
|
+
}, 50);
|
|
106
100
|
}
|
|
107
101
|
}, [room?.status, wasLive]);
|
|
108
102
|
|
|
109
|
-
// Start in fullscreen mode on iOS
|
|
110
103
|
useEffect(() => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
104
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
videoRef.current &&
|
|
108
|
+
room &&
|
|
109
|
+
room.status === RoomStatus.live &&
|
|
110
|
+
!videoError &&
|
|
111
|
+
Platform.OS === 'ios'
|
|
112
|
+
) {
|
|
113
|
+
const isTerminated =
|
|
114
|
+
room?.moderation?.terminateLabels &&
|
|
115
|
+
room?.moderation?.terminateLabels?.length > 0;
|
|
116
|
+
|
|
117
|
+
if (!isTerminated) {
|
|
118
|
+
timer = setTimeout(() => {
|
|
119
|
+
videoRef.current?.presentFullscreenPlayer();
|
|
120
|
+
}, 100);
|
|
121
|
+
}
|
|
116
122
|
}
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
|
|
124
|
+
return () => {
|
|
125
|
+
if (timer !== null) {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}, [room, videoError]);
|
|
130
|
+
|
|
131
|
+
const isTerminated =
|
|
132
|
+
room?.moderation?.terminateLabels &&
|
|
133
|
+
room?.moderation?.terminateLabels?.length > 0;
|
|
134
|
+
|
|
135
|
+
const shouldShowEndThumbnail =
|
|
136
|
+
room?.status === RoomStatus.ended ||
|
|
137
|
+
(room?.status === RoomStatus.recorded && wasLive) ||
|
|
138
|
+
isTerminated;
|
|
139
|
+
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (!room?.status) return;
|
|
142
|
+
|
|
143
|
+
const shouldEnd =
|
|
144
|
+
room.status === RoomStatus.ended ||
|
|
145
|
+
(room.status === RoomStatus.recorded && wasLive);
|
|
146
|
+
|
|
147
|
+
if (!shouldEnd || isStreamEnding.current) return;
|
|
148
|
+
|
|
149
|
+
isStreamEnding.current = true;
|
|
150
|
+
setIsPaused(true);
|
|
151
|
+
|
|
152
|
+
if (Platform.OS === 'ios') {
|
|
153
|
+
// iOS: just dismiss fullscreen, DO NOT destroy immediately
|
|
154
|
+
if (videoRef.current) {
|
|
155
|
+
try {
|
|
156
|
+
videoRef.current.dismissFullscreenPlayer?.();
|
|
157
|
+
} catch {}
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
// Android: HARD destroy
|
|
161
|
+
setTimeout(() => {
|
|
162
|
+
setVideoKey((prev) => prev + 1);
|
|
163
|
+
}, 50);
|
|
164
|
+
}
|
|
165
|
+
}, [room?.status, wasLive]);
|
|
119
166
|
|
|
120
167
|
if (!room || error) {
|
|
121
168
|
return (
|
|
@@ -129,21 +176,19 @@ function AmityLiveStreamPlayerPage() {
|
|
|
129
176
|
navigation.goBack();
|
|
130
177
|
};
|
|
131
178
|
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
isProgrammaticDismiss.current = false;
|
|
138
|
-
};
|
|
179
|
+
const videoUrl =
|
|
180
|
+
room.status === RoomStatus.recorded
|
|
181
|
+
? room.recordedPlaybackInfos[0]?.url
|
|
182
|
+
: room.livePlaybackUrl;
|
|
139
183
|
|
|
140
184
|
return (
|
|
141
185
|
<SafeAreaView style={styles.container}>
|
|
142
|
-
{
|
|
186
|
+
{shouldShowEndThumbnail ? (
|
|
143
187
|
<>
|
|
144
188
|
<View style={styles.steamEndContainer}>
|
|
145
189
|
<LiveStreamEndThumbnail />
|
|
146
190
|
</View>
|
|
191
|
+
|
|
147
192
|
<TouchableOpacity style={styles.closeButton} onPress={closePlayer}>
|
|
148
193
|
<SvgXml
|
|
149
194
|
xml={close()}
|
|
@@ -165,35 +210,53 @@ function AmityLiveStreamPlayerPage() {
|
|
|
165
210
|
</View>
|
|
166
211
|
</View>
|
|
167
212
|
)}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
213
|
+
|
|
214
|
+
{!shouldShowEndThumbnail && (
|
|
215
|
+
<Video
|
|
216
|
+
key={
|
|
217
|
+
Platform.OS === 'android' ? `${videoUrl}-${videoKey}` : videoUrl
|
|
218
|
+
}
|
|
219
|
+
ref={videoRef}
|
|
220
|
+
source={{
|
|
221
|
+
uri:
|
|
222
|
+
room.status === RoomStatus.recorded
|
|
223
|
+
? room.recordedPlaybackInfos[0]?.url
|
|
224
|
+
: room.livePlaybackUrl,
|
|
225
|
+
headers: {
|
|
226
|
+
Authorization: `Bearer ${client.token.accessToken}`,
|
|
227
|
+
},
|
|
228
|
+
}}
|
|
229
|
+
style={styles.container}
|
|
230
|
+
resizeMode="contain"
|
|
231
|
+
controls={room?.status === RoomStatus.recorded && !wasLive}
|
|
232
|
+
fullscreen={
|
|
233
|
+
Platform.OS === 'ios' && room.status !== RoomStatus.recorded
|
|
234
|
+
}
|
|
235
|
+
fullscreenOrientation="landscape"
|
|
236
|
+
paused={isPaused}
|
|
237
|
+
muted={false}
|
|
238
|
+
volume={1.0}
|
|
239
|
+
audioOutput="speaker"
|
|
240
|
+
playInBackground={false}
|
|
241
|
+
playWhenInactive={false}
|
|
242
|
+
repeat={false}
|
|
243
|
+
onLoad={() => {
|
|
244
|
+
setPlayerInitialized(true);
|
|
245
|
+
if (room.status === RoomStatus.recorded) {
|
|
246
|
+
setIsPaused(false);
|
|
247
|
+
}
|
|
248
|
+
}}
|
|
249
|
+
onError={(e) => {
|
|
250
|
+
console.log('Video Error: ', e);
|
|
251
|
+
setVideoError(true);
|
|
252
|
+
}}
|
|
253
|
+
onFullscreenPlayerDidDismiss={() => {
|
|
254
|
+
if (Platform.OS === 'ios') {
|
|
255
|
+
closePlayer();
|
|
256
|
+
}
|
|
257
|
+
}}
|
|
258
|
+
/>
|
|
259
|
+
)}
|
|
197
260
|
</View>
|
|
198
261
|
)}
|
|
199
262
|
|
|
@@ -3,5 +3,5 @@ export const RoomStatus = {
|
|
|
3
3
|
live: 'live' as Amity.RoomStatus,
|
|
4
4
|
recorded: 'recorded' as Amity.RoomStatus,
|
|
5
5
|
ended: 'ended' as Amity.RoomStatus,
|
|
6
|
-
waiting_reconnect: '
|
|
6
|
+
waiting_reconnect: 'waitingReconnect' as Amity.RoomStatus,
|
|
7
7
|
};
|