@applicaster/quick-brick-player 13.0.0-rc.110 → 13.0.0-rc.111
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/package.json +5 -6
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +63 -124
- package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +2 -9
- package/src/Player/AudioLayer/Layout/MobileLayout.tsx +4 -5
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +2 -3
- package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +2 -3
- package/src/Player/hooks/useIsCasting.tsx +57 -0
- package/src/Player/index.tsx +10 -5
- package/src/QuickBrickPlayer.tsx +3 -0
- package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.ts +0 -3
- package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.web.ts +0 -3
- package/src/Player/AudioLayer/LinearGradient/index.ts +0 -1
- package/src/Player/AudioLayer/MagicBG/index.tsx +0 -155
- package/src/utils/utils.ts +0 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "13.0.0-rc.
|
|
3
|
+
"version": "13.0.0-rc.111",
|
|
4
4
|
"description": "Quick Brick Player",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
},
|
|
36
36
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.
|
|
38
|
+
"@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.111",
|
|
39
39
|
"@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.56",
|
|
40
|
-
"@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.
|
|
41
|
-
"@applicaster/zapp-react-native-ui-components": "13.0.0-rc.
|
|
42
|
-
"@applicaster/zapp-react-native-utils": "13.0.0-rc.
|
|
40
|
+
"@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.111",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "13.0.0-rc.111",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "13.0.0-rc.111",
|
|
43
43
|
"query-string": "7.1.3",
|
|
44
44
|
"react-native-web-linear-gradient": "1.1.2",
|
|
45
45
|
"shaka-player": "4.3.5",
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"@applicaster/applicaster-types": "*",
|
|
53
53
|
"@applicaster/blur": "*",
|
|
54
54
|
"@applicaster/quick-brick-xray": "*",
|
|
55
|
-
"@applicaster/react-native-color-thief": "*",
|
|
56
55
|
"@applicaster/zapp-pipes-v2-client": "*",
|
|
57
56
|
"@applicaster/zapp-react-dom-ui-components": "*",
|
|
58
57
|
"@applicaster/zapp-react-native-redux": "*",
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
2
3
|
import {
|
|
4
|
+
Dimensions as ScreenDimensions,
|
|
3
5
|
StyleSheet,
|
|
4
|
-
ViewStyle,
|
|
5
6
|
View,
|
|
6
|
-
|
|
7
|
+
ViewStyle,
|
|
7
8
|
} from "react-native";
|
|
8
9
|
|
|
9
|
-
import {
|
|
10
|
+
import { Edge, SafeAreaView } from "react-native-safe-area-context";
|
|
10
11
|
import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
|
|
11
12
|
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
12
13
|
import * as R from "ramda";
|
|
@@ -20,11 +21,8 @@ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
|
20
21
|
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
21
22
|
import { PlayerDetails } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/PlayerDetails";
|
|
22
23
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
23
|
-
import { useEffect, useState } from "react";
|
|
24
|
-
import { MagicBG } from "./MagicBG";
|
|
25
24
|
import { formatSpeed } from "./utils";
|
|
26
25
|
import {
|
|
27
|
-
addQueryParam,
|
|
28
26
|
getBottomSheetModalDefaultItemIcon,
|
|
29
27
|
getBottomSheetModalIconProps,
|
|
30
28
|
getBottomSheetModalItemProps,
|
|
@@ -33,20 +31,18 @@ import {
|
|
|
33
31
|
} from "../Utils";
|
|
34
32
|
import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
|
|
35
33
|
import {
|
|
34
|
+
AnimatedScrollModal,
|
|
36
35
|
AnimationComponent,
|
|
37
36
|
ComponentAnimationType,
|
|
38
|
-
AnimatedScrollModal,
|
|
39
37
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
40
38
|
import { PADDING_HORIZONTAL } from "./Layout/const";
|
|
41
39
|
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
42
40
|
import {
|
|
41
|
+
SLEEP_TIMER_OFF,
|
|
43
42
|
SleepTimerController,
|
|
44
43
|
SleepTimerState,
|
|
45
|
-
SLEEP_TIMER_OFF,
|
|
46
44
|
} from "./SleepTimerManager";
|
|
47
|
-
import {
|
|
48
|
-
import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
49
|
-
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
45
|
+
import { DEFAULT_SPEED, PlaybackSpeed, SpeedController } from "./SpeedManager";
|
|
50
46
|
import { openBottomSheetModal } from "@applicaster/zapp-react-native-utils/modalState";
|
|
51
47
|
import { getSleepTimerOptions } from "../Const/sleepTimerOptions";
|
|
52
48
|
import { speedOptions } from "../Const/speedOptions";
|
|
@@ -65,7 +61,6 @@ type Dimensions = {
|
|
|
65
61
|
|
|
66
62
|
type Configuration = {
|
|
67
63
|
[key: string]: any;
|
|
68
|
-
magic_background?: boolean;
|
|
69
64
|
audio_player_background_image_query?: string;
|
|
70
65
|
audio_player_background_image_default_color?: string;
|
|
71
66
|
tablet_landscape_sidebar_width?: string;
|
|
@@ -75,7 +70,6 @@ type Configuration = {
|
|
|
75
70
|
type Props = {
|
|
76
71
|
children: React.ReactNode;
|
|
77
72
|
inline?: boolean;
|
|
78
|
-
docked?: boolean;
|
|
79
73
|
configuration: Configuration;
|
|
80
74
|
style: ViewStyle & Dimensions;
|
|
81
75
|
entry: ZappEntry;
|
|
@@ -108,10 +102,8 @@ const edges: Edge[] = ["right", "left", "top"];
|
|
|
108
102
|
export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
109
103
|
const player = usePlayer();
|
|
110
104
|
const playerState = usePlayerState("audio-player-wrapper");
|
|
111
|
-
const theme = useTheme();
|
|
112
105
|
|
|
113
106
|
const {
|
|
114
|
-
docked,
|
|
115
107
|
configuration,
|
|
116
108
|
style,
|
|
117
109
|
entry,
|
|
@@ -330,114 +322,61 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
330
322
|
player?.seekTo(0);
|
|
331
323
|
}, [player]);
|
|
332
324
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
<
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
style={Styles.playerContainer}
|
|
340
|
-
>
|
|
341
|
-
<AnimatedScrollModal>
|
|
342
|
-
<View style={Styles.playerContainer} onLayout={onLayout}>
|
|
343
|
-
<Layout
|
|
344
|
-
entry={entry}
|
|
345
|
-
playerState={playerState}
|
|
346
|
-
layoutState={layoutState}
|
|
347
|
-
value={value}
|
|
348
|
-
onPlaybackButtonPress={onPlaybackButtonPress}
|
|
349
|
-
onRewindButtonPress={onRewindButtonPress}
|
|
350
|
-
onForwardButtonPress={onForwardButtonPress}
|
|
351
|
-
onPlayerSeek={onPlayerSeek}
|
|
352
|
-
onSkipStart={onSkipStart}
|
|
353
|
-
onSpeedButtonPress={onSpeedButtonPress}
|
|
354
|
-
onSleepButtonPress={onSleepButtonPress}
|
|
355
|
-
playbackSpeedName={formatSpeed(playbackSpeed.value)}
|
|
356
|
-
playbackSleepName={
|
|
357
|
-
sleepTimerState.timer.value === 0
|
|
358
|
-
? "sleep_timer"
|
|
359
|
-
: "sleep_timer_active"
|
|
360
|
-
}
|
|
361
|
-
sleepTimerDate={sleepTimerState.timerDate}
|
|
362
|
-
cancelSleepTimer={cancelSleepTimer}
|
|
363
|
-
onSkipLive={onSkipLive}
|
|
364
|
-
onCloseVideoModal={onCloseVideoModal}
|
|
365
|
-
maximiseVideoModal={maximiseVideoModal}
|
|
366
|
-
configuration={configuration}
|
|
367
|
-
dimensions={dimensions}
|
|
368
|
-
playNextData={playNextData}
|
|
369
|
-
title={title}
|
|
370
|
-
summary={summary}
|
|
371
|
-
defaultDimensions={defaultDimensions}
|
|
372
|
-
/>
|
|
373
|
-
<View style={Styles.paddingHorizontal}>
|
|
374
|
-
{children}
|
|
375
|
-
<AnimationComponent
|
|
376
|
-
animationType={ComponentAnimationType.componentFade}
|
|
377
|
-
>
|
|
378
|
-
<PlayerDetails
|
|
379
|
-
isAudioPlayer
|
|
380
|
-
configuration={configuration}
|
|
381
|
-
style={Styles.playerDetails}
|
|
382
|
-
entry={entry}
|
|
383
|
-
isTabletLandscape={isTabletLandscape}
|
|
384
|
-
/>
|
|
385
|
-
</AnimationComponent>
|
|
386
|
-
</View>
|
|
387
|
-
</View>
|
|
388
|
-
</AnimatedScrollModal>
|
|
389
|
-
</AnimationComponent>
|
|
390
|
-
</SafeAreaView>
|
|
391
|
-
);
|
|
392
|
-
}, [
|
|
393
|
-
docked,
|
|
394
|
-
style,
|
|
395
|
-
entry,
|
|
396
|
-
playerState,
|
|
397
|
-
layoutState,
|
|
398
|
-
value,
|
|
399
|
-
onPlaybackButtonPress,
|
|
400
|
-
onRewindButtonPress,
|
|
401
|
-
onForwardButtonPress,
|
|
402
|
-
onPlayerSeek,
|
|
403
|
-
onCloseVideoModal,
|
|
404
|
-
maximiseVideoModal,
|
|
405
|
-
configuration,
|
|
406
|
-
dimensions,
|
|
407
|
-
children,
|
|
408
|
-
playNextData,
|
|
409
|
-
onSkipStart,
|
|
410
|
-
onSkipLive,
|
|
411
|
-
sleepTimerState.timer.value,
|
|
412
|
-
sleepTimerState.timerDate,
|
|
413
|
-
]);
|
|
414
|
-
|
|
415
|
-
if (configuration.magic_background) {
|
|
416
|
-
const baseUrl = imageSrcFromMediaItem(entry, null);
|
|
417
|
-
|
|
418
|
-
const queryParamName =
|
|
419
|
-
configuration.audio_player_background_image_query || "width";
|
|
420
|
-
|
|
421
|
-
const defaultBackgroundColor =
|
|
422
|
-
configuration.audio_player_background_image_default_color ||
|
|
423
|
-
theme?.app_background_color;
|
|
424
|
-
|
|
425
|
-
const queryParamValue = 15;
|
|
426
|
-
|
|
427
|
-
const url =
|
|
428
|
-
baseUrl && addQueryParam(baseUrl, queryParamName, queryParamValue);
|
|
429
|
-
|
|
430
|
-
return (
|
|
431
|
-
<MagicBG
|
|
432
|
-
image={url}
|
|
433
|
-
fallbackUrl={baseUrl}
|
|
434
|
-
colors={entry?.extensions?.backgroundColors}
|
|
435
|
-
defaultColor={defaultBackgroundColor}
|
|
325
|
+
return (
|
|
326
|
+
<SafeAreaView style={[style, Styles.playerContainer]} edges={edges}>
|
|
327
|
+
<AnimationComponent
|
|
328
|
+
animationType={ComponentAnimationType.moveUpComponent}
|
|
329
|
+
additionalData={{ saveArea: true }}
|
|
330
|
+
style={Styles.playerContainer}
|
|
436
331
|
>
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
332
|
+
<AnimatedScrollModal>
|
|
333
|
+
<View style={Styles.playerContainer} onLayout={onLayout}>
|
|
334
|
+
<Layout
|
|
335
|
+
entry={entry}
|
|
336
|
+
playerState={playerState}
|
|
337
|
+
layoutState={layoutState}
|
|
338
|
+
value={value}
|
|
339
|
+
onPlaybackButtonPress={onPlaybackButtonPress}
|
|
340
|
+
onRewindButtonPress={onRewindButtonPress}
|
|
341
|
+
onForwardButtonPress={onForwardButtonPress}
|
|
342
|
+
onPlayerSeek={onPlayerSeek}
|
|
343
|
+
onSkipStart={onSkipStart}
|
|
344
|
+
onSpeedButtonPress={onSpeedButtonPress}
|
|
345
|
+
onSleepButtonPress={onSleepButtonPress}
|
|
346
|
+
playbackSpeedName={formatSpeed(playbackSpeed.value)}
|
|
347
|
+
playbackSleepName={
|
|
348
|
+
sleepTimerState.timer.value === 0
|
|
349
|
+
? "sleep_timer"
|
|
350
|
+
: "sleep_timer_active"
|
|
351
|
+
}
|
|
352
|
+
sleepTimerDate={sleepTimerState.timerDate}
|
|
353
|
+
cancelSleepTimer={cancelSleepTimer}
|
|
354
|
+
onSkipLive={onSkipLive}
|
|
355
|
+
onCloseVideoModal={onCloseVideoModal}
|
|
356
|
+
maximiseVideoModal={maximiseVideoModal}
|
|
357
|
+
configuration={configuration}
|
|
358
|
+
dimensions={dimensions}
|
|
359
|
+
playNextData={playNextData}
|
|
360
|
+
title={title}
|
|
361
|
+
summary={summary}
|
|
362
|
+
/>
|
|
363
|
+
<View style={Styles.paddingHorizontal}>
|
|
364
|
+
{children}
|
|
365
|
+
<AnimationComponent
|
|
366
|
+
animationType={ComponentAnimationType.componentFade}
|
|
367
|
+
>
|
|
368
|
+
<PlayerDetails
|
|
369
|
+
isAudioPlayer
|
|
370
|
+
configuration={configuration}
|
|
371
|
+
style={Styles.playerDetails}
|
|
372
|
+
entry={entry}
|
|
373
|
+
isTabletLandscape={isTabletLandscape}
|
|
374
|
+
/>
|
|
375
|
+
</AnimationComponent>
|
|
376
|
+
</View>
|
|
377
|
+
</View>
|
|
378
|
+
</AnimatedScrollModal>
|
|
379
|
+
</AnimationComponent>
|
|
380
|
+
</SafeAreaView>
|
|
381
|
+
);
|
|
443
382
|
};
|
|
@@ -30,7 +30,6 @@ type Props = {
|
|
|
30
30
|
layoutState: QuickBrickPlayer.LayoutState;
|
|
31
31
|
playerState: QuickBrickPlayer.PlayerState;
|
|
32
32
|
value: GetValue;
|
|
33
|
-
configuration: QuickBrickPlayer.AudioPlayerProps["configuration"];
|
|
34
33
|
dimensions: QuickBrickPlayer.AudioPlayerProps["dimensions"];
|
|
35
34
|
onCloseVideoModal: () => void;
|
|
36
35
|
onPlayerSeek: (targetTime: number) => void;
|
|
@@ -181,7 +180,6 @@ export const DockedControls = (props: Props) => {
|
|
|
181
180
|
layoutState,
|
|
182
181
|
playerState,
|
|
183
182
|
value,
|
|
184
|
-
configuration,
|
|
185
183
|
dimensions,
|
|
186
184
|
onCloseVideoModal,
|
|
187
185
|
onPlayerSeek,
|
|
@@ -254,12 +252,7 @@ export const DockedControls = (props: Props) => {
|
|
|
254
252
|
),
|
|
255
253
|
]}
|
|
256
254
|
>
|
|
257
|
-
<View
|
|
258
|
-
style={[
|
|
259
|
-
styles.contentInfo,
|
|
260
|
-
!configuration.magic_background && backgroundColorStyle(value),
|
|
261
|
-
]}
|
|
262
|
-
>
|
|
255
|
+
<View style={[styles.contentInfo, backgroundColorStyle(value)]}>
|
|
263
256
|
<ContentInfo
|
|
264
257
|
content={{ ...entry, title, summary }}
|
|
265
258
|
value={value}
|
|
@@ -273,7 +266,7 @@ export const DockedControls = (props: Props) => {
|
|
|
273
266
|
isTablet
|
|
274
267
|
? styles.controlsContainerForTablet
|
|
275
268
|
: styles.controlsContainerForMobile,
|
|
276
|
-
|
|
269
|
+
backgroundColorStyle(value),
|
|
277
270
|
]}
|
|
278
271
|
>
|
|
279
272
|
<Controls
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { View, ViewStyle
|
|
2
|
+
import { StyleSheet, View, ViewStyle } from "react-native";
|
|
3
3
|
import {
|
|
4
|
-
useSafeAreaInsets,
|
|
5
4
|
useSafeAreaFrame,
|
|
5
|
+
useSafeAreaInsets,
|
|
6
6
|
} from "react-native-safe-area-context";
|
|
7
7
|
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
8
8
|
|
|
@@ -13,11 +13,11 @@ import { Controls } from "./Controls";
|
|
|
13
13
|
|
|
14
14
|
import { useMobileLayoutImageSize, useTransportInfoHeight } from "./hooks";
|
|
15
15
|
import { DockedControls } from "./DockedControls";
|
|
16
|
-
import {
|
|
16
|
+
import { DEBUG, withDebug } from "./debug";
|
|
17
17
|
import {
|
|
18
|
+
BottomDebugSquare,
|
|
18
19
|
LeftDebugSquare,
|
|
19
20
|
RightDebugSquare,
|
|
20
|
-
BottomDebugSquare,
|
|
21
21
|
} from "./Debug/index";
|
|
22
22
|
|
|
23
23
|
import { Props } from "./types";
|
|
@@ -218,7 +218,6 @@ export function MobileLayout({
|
|
|
218
218
|
layoutState={layoutState}
|
|
219
219
|
playerState={playerState}
|
|
220
220
|
value={value}
|
|
221
|
-
configuration={configuration}
|
|
222
221
|
dimensions={dimensions}
|
|
223
222
|
onCloseVideoModal={onCloseVideoModal}
|
|
224
223
|
onPlayerSeek={onPlayerSeek}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { View, ViewStyle
|
|
2
|
+
import { StyleSheet, View, ViewStyle } from "react-native";
|
|
3
3
|
import {
|
|
4
|
-
useSafeAreaInsets,
|
|
5
4
|
useSafeAreaFrame,
|
|
5
|
+
useSafeAreaInsets,
|
|
6
6
|
} from "react-native-safe-area-context";
|
|
7
7
|
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
8
8
|
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
@@ -203,7 +203,6 @@ export function TabletLandscapeLayout({
|
|
|
203
203
|
layoutState={layoutState}
|
|
204
204
|
playerState={playerState}
|
|
205
205
|
value={value}
|
|
206
|
-
configuration={configuration}
|
|
207
206
|
dimensions={dimensions}
|
|
208
207
|
onCloseVideoModal={onCloseVideoModal}
|
|
209
208
|
onPlayerSeek={onPlayerSeek}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { View, ViewStyle
|
|
2
|
+
import { StyleSheet, View, ViewStyle } from "react-native";
|
|
3
3
|
import {
|
|
4
|
-
useSafeAreaInsets,
|
|
5
4
|
useSafeAreaFrame,
|
|
5
|
+
useSafeAreaInsets,
|
|
6
6
|
} from "react-native-safe-area-context";
|
|
7
7
|
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
8
8
|
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
@@ -211,7 +211,6 @@ export function TabletPortraitLayout({
|
|
|
211
211
|
layoutState={layoutState}
|
|
212
212
|
playerState={playerState}
|
|
213
213
|
value={value}
|
|
214
|
-
configuration={configuration}
|
|
215
214
|
dimensions={dimensions}
|
|
216
215
|
onCloseVideoModal={onCloseVideoModal}
|
|
217
216
|
onPlayerSeek={onPlayerSeek}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
3
|
+
import { useAppState } from "@applicaster/zapp-react-native-utils/reactHooks/app";
|
|
4
|
+
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
5
|
+
|
|
6
|
+
const CHROMECAST_IDENTIFIER = "quick-brick-chromecast-action";
|
|
7
|
+
|
|
8
|
+
const fakeEntry: any = {
|
|
9
|
+
title: "Chromecast use is casting fake entry",
|
|
10
|
+
id: "quick-brick-use-is-casting-fake-entry",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Returns the cast action state connection status, does not update when app is in background on Apple platforms
|
|
15
|
+
* On other platforms, it continues to check the cast action state even when the app is in background
|
|
16
|
+
*/
|
|
17
|
+
export const useIsCasting = () => {
|
|
18
|
+
const actionContext = useActions(CHROMECAST_IDENTIFIER);
|
|
19
|
+
const appState = useAppState();
|
|
20
|
+
const isAppInForeground = appState === "active";
|
|
21
|
+
const shouldOnlyUpdateInForeground = isApplePlatform();
|
|
22
|
+
|
|
23
|
+
const [castActionState, setCastActionState] = React.useState(
|
|
24
|
+
!actionContext ? null : actionContext.initialEntryState(fakeEntry)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
if (!shouldOnlyUpdateInForeground || isAppInForeground) {
|
|
29
|
+
if (!(!actionContext && castActionState !== null)) {
|
|
30
|
+
setCastActionState(actionContext.initialEntryState(fakeEntry));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, [
|
|
34
|
+
actionContext,
|
|
35
|
+
setCastActionState,
|
|
36
|
+
isAppInForeground,
|
|
37
|
+
shouldOnlyUpdateInForeground,
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
if (typeof actionContext?.addListener === "function") {
|
|
42
|
+
return actionContext?.addListener(String(fakeEntry.id), (state) => {
|
|
43
|
+
// Only check foreground state on Apple platforms
|
|
44
|
+
if (!shouldOnlyUpdateInForeground || isAppInForeground) {
|
|
45
|
+
setCastActionState(state);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}, [
|
|
50
|
+
setCastActionState,
|
|
51
|
+
actionContext,
|
|
52
|
+
isAppInForeground,
|
|
53
|
+
shouldOnlyUpdateInForeground,
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
return !!castActionState?.connected;
|
|
57
|
+
};
|
package/src/Player/index.tsx
CHANGED
|
@@ -74,6 +74,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
74
74
|
state: QuickBrickPlayer.NativePlayerState = {
|
|
75
75
|
audioTrackId: null,
|
|
76
76
|
textTrackId: null,
|
|
77
|
+
isCasting: this.props.isCasting,
|
|
77
78
|
|
|
78
79
|
// TODO: Can be deleted, on controller logic
|
|
79
80
|
isAd: false,
|
|
@@ -698,6 +699,10 @@ export default class VideoPlayer extends React.Component<
|
|
|
698
699
|
];
|
|
699
700
|
};
|
|
700
701
|
|
|
702
|
+
get supportNativeCast() {
|
|
703
|
+
return this.props.controller.supportNativeCast();
|
|
704
|
+
}
|
|
705
|
+
|
|
701
706
|
render() {
|
|
702
707
|
const {
|
|
703
708
|
docked,
|
|
@@ -710,12 +715,9 @@ export default class VideoPlayer extends React.Component<
|
|
|
710
715
|
muted,
|
|
711
716
|
style,
|
|
712
717
|
castAction,
|
|
713
|
-
controller,
|
|
714
718
|
startComponentsAnimation,
|
|
715
719
|
} = this.props;
|
|
716
720
|
|
|
717
|
-
const supportNativeCast = controller.supportNativeCast();
|
|
718
|
-
|
|
719
721
|
const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
|
|
720
722
|
this.state;
|
|
721
723
|
|
|
@@ -995,11 +997,14 @@ export default class VideoPlayer extends React.Component<
|
|
|
995
997
|
const backgroundImageKey =
|
|
996
998
|
this.getPluginConfiguration()?.player_preview_image_key;
|
|
997
999
|
|
|
1000
|
+
const shouldRenderNativePlayer =
|
|
1001
|
+
!this.props.isCasting || this.supportNativeCast;
|
|
1002
|
+
|
|
998
1003
|
const renderMobilePlayer = () => {
|
|
999
1004
|
return isFullScreenAudioPlayer && isAudioItem ? (
|
|
1000
1005
|
// Ensure the View remains in the native hierarchy for proper rendering and interaction
|
|
1001
1006
|
<View collapsable={false} style={containerStyle}>
|
|
1002
|
-
{
|
|
1007
|
+
{shouldRenderNativePlayer ? (
|
|
1003
1008
|
<this.props.PlayerComponent
|
|
1004
1009
|
ref={this._assignRoot}
|
|
1005
1010
|
{...nativeEvents}
|
|
@@ -1051,7 +1056,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
1051
1056
|
/>
|
|
1052
1057
|
) : null}
|
|
1053
1058
|
|
|
1054
|
-
{
|
|
1059
|
+
{shouldRenderNativePlayer ? (
|
|
1055
1060
|
<AnimationComponent
|
|
1056
1061
|
animationType={ComponentAnimationType.player}
|
|
1057
1062
|
additionalData={{
|
package/src/QuickBrickPlayer.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import Player from "./Player";
|
|
|
5
5
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
6
6
|
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
7
7
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
8
|
+
import { useIsCasting } from "./Player/hooks/useIsCasting";
|
|
8
9
|
|
|
9
10
|
const CHROMECAST_IDENTIFIER = "quick-brick-chromecast-action";
|
|
10
11
|
|
|
@@ -24,6 +25,7 @@ const QuickBrickPlayerComponent = (
|
|
|
24
25
|
}, [props.PlayerComponent]);
|
|
25
26
|
|
|
26
27
|
const castAction = useActions(CHROMECAST_IDENTIFIER);
|
|
28
|
+
const isCasting = useIsCasting();
|
|
27
29
|
|
|
28
30
|
const isModal = Boolean(props?.isModal);
|
|
29
31
|
const isScreenDisabled = !controller?.isFullScreenSupported() || !isModal;
|
|
@@ -48,6 +50,7 @@ const QuickBrickPlayerComponent = (
|
|
|
48
50
|
{...props}
|
|
49
51
|
ref={ref}
|
|
50
52
|
castAction={!props?.disableCastAction && castAction}
|
|
53
|
+
isCasting={isCasting}
|
|
51
54
|
PlayerComponent={props.PlayerComponent}
|
|
52
55
|
openPiP={openPiP}
|
|
53
56
|
closePiP={closePiP}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./LinearGradientProxy";
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
/* eslint-disable react/prop-types */
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
import { Animated, StyleSheet, View } from "react-native";
|
|
4
|
-
import LinearGradient from "../LinearGradient";
|
|
5
|
-
import { getDominantColor, getPalettes } from "../../../utils/utils";
|
|
6
|
-
import { useEffect } from "react";
|
|
7
|
-
|
|
8
|
-
type MagicBGProps = {
|
|
9
|
-
children: React.ReactNode;
|
|
10
|
-
image: string;
|
|
11
|
-
fallbackUrl?: string;
|
|
12
|
-
defaultColor: string;
|
|
13
|
-
colors: string[];
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const defaultColors = {
|
|
17
|
-
overlay: "rgba(0, 0, 0, 0.35)",
|
|
18
|
-
defaultGradientStart: "rgba(0, 0, 0, 0.25)",
|
|
19
|
-
defaultGradientEnd: "rgba(0, 0, 0, 0)",
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const styles = StyleSheet.create({
|
|
23
|
-
container: {
|
|
24
|
-
flex: 1,
|
|
25
|
-
},
|
|
26
|
-
fullScreenOverlay: {
|
|
27
|
-
...StyleSheet.absoluteFillObject,
|
|
28
|
-
backgroundColor: defaultColors.overlay,
|
|
29
|
-
},
|
|
30
|
-
gradientOverlay: {
|
|
31
|
-
position: "absolute",
|
|
32
|
-
bottom: 0,
|
|
33
|
-
left: 0,
|
|
34
|
-
right: 0,
|
|
35
|
-
height: "100%",
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const fetchPaletteAndDominantColor = async (imageUrl: string) => {
|
|
40
|
-
const palette = await getPalettes(imageUrl);
|
|
41
|
-
|
|
42
|
-
const colors = palette.map(
|
|
43
|
-
(color: { r: number; g: number; b: number }) =>
|
|
44
|
-
`rgb(${color.r}, ${color.g}, ${color.b})`
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
const dominant = await getDominantColor(imageUrl);
|
|
48
|
-
const dominantColor = `rgb(${dominant.r}, ${dominant.g}, ${dominant.b})`;
|
|
49
|
-
|
|
50
|
-
return { gradientColors: colors.slice(0, 2).reverse(), dominantColor };
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export const MagicBG: React.FC<MagicBGProps> = ({
|
|
54
|
-
children,
|
|
55
|
-
image,
|
|
56
|
-
fallbackUrl = "",
|
|
57
|
-
colors = [],
|
|
58
|
-
defaultColor,
|
|
59
|
-
}) => {
|
|
60
|
-
const [dominantColor, setDominantColor] =
|
|
61
|
-
React.useState<string>(defaultColor);
|
|
62
|
-
|
|
63
|
-
const [gradientColors, setGradientColors] = React.useState<string[]>([
|
|
64
|
-
defaultColors.defaultGradientStart,
|
|
65
|
-
defaultColors.defaultGradientEnd,
|
|
66
|
-
]);
|
|
67
|
-
|
|
68
|
-
const [backgroundColorAnim] = React.useState(new Animated.Value(0)); // from 0 to 1
|
|
69
|
-
const [gradientOpacityAnim] = React.useState(new Animated.Value(0)); // from 0 to 1
|
|
70
|
-
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
const animateColors = () => {
|
|
73
|
-
Animated.timing(backgroundColorAnim, {
|
|
74
|
-
toValue: 1,
|
|
75
|
-
duration: 500,
|
|
76
|
-
useNativeDriver: false,
|
|
77
|
-
}).start();
|
|
78
|
-
|
|
79
|
-
Animated.timing(gradientOpacityAnim, {
|
|
80
|
-
toValue: 1,
|
|
81
|
-
duration: 500,
|
|
82
|
-
useNativeDriver: false,
|
|
83
|
-
}).start();
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const fetchColors = async () => {
|
|
87
|
-
if (colors && colors.length > 0) {
|
|
88
|
-
setGradientColors(colors.slice(0, 2));
|
|
89
|
-
setDominantColor(colors[0]);
|
|
90
|
-
animateColors();
|
|
91
|
-
} else if (image) {
|
|
92
|
-
try {
|
|
93
|
-
const { gradientColors, dominantColor } =
|
|
94
|
-
await fetchPaletteAndDominantColor(image);
|
|
95
|
-
|
|
96
|
-
setGradientColors(gradientColors);
|
|
97
|
-
setDominantColor(dominantColor);
|
|
98
|
-
animateColors();
|
|
99
|
-
} catch (error) {
|
|
100
|
-
try {
|
|
101
|
-
const { gradientColors, dominantColor } =
|
|
102
|
-
await fetchPaletteAndDominantColor(fallbackUrl);
|
|
103
|
-
|
|
104
|
-
setGradientColors(gradientColors);
|
|
105
|
-
setDominantColor(dominantColor);
|
|
106
|
-
animateColors();
|
|
107
|
-
} catch {
|
|
108
|
-
setGradientColors([
|
|
109
|
-
defaultColors.defaultGradientStart,
|
|
110
|
-
defaultColors.defaultGradientEnd,
|
|
111
|
-
]);
|
|
112
|
-
|
|
113
|
-
setDominantColor(defaultColor);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
} else {
|
|
117
|
-
setGradientColors([
|
|
118
|
-
defaultColors.defaultGradientStart,
|
|
119
|
-
defaultColors.defaultGradientEnd,
|
|
120
|
-
]);
|
|
121
|
-
|
|
122
|
-
setDominantColor(defaultColor);
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
fetchColors();
|
|
127
|
-
}, []);
|
|
128
|
-
|
|
129
|
-
const interpolatedBackgroundColor = backgroundColorAnim.interpolate({
|
|
130
|
-
inputRange: [0, 1],
|
|
131
|
-
outputRange: ["black", dominantColor],
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
return (
|
|
135
|
-
<Animated.View
|
|
136
|
-
style={[
|
|
137
|
-
styles.container,
|
|
138
|
-
{ backgroundColor: interpolatedBackgroundColor },
|
|
139
|
-
]}
|
|
140
|
-
>
|
|
141
|
-
<View style={styles.fullScreenOverlay} />
|
|
142
|
-
|
|
143
|
-
<Animated.View
|
|
144
|
-
style={[styles.gradientOverlay, { opacity: gradientOpacityAnim }]}
|
|
145
|
-
>
|
|
146
|
-
<LinearGradient
|
|
147
|
-
colors={gradientColors}
|
|
148
|
-
style={StyleSheet.absoluteFill}
|
|
149
|
-
/>
|
|
150
|
-
</Animated.View>
|
|
151
|
-
|
|
152
|
-
{children}
|
|
153
|
-
</Animated.View>
|
|
154
|
-
);
|
|
155
|
-
};
|
package/src/utils/utils.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import RNColorThief from "@applicaster/react-native-color-thief";
|
|
2
|
-
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
3
|
-
|
|
4
|
-
const { log_error } = createLogger({
|
|
5
|
-
subsystem: "UIComponent",
|
|
6
|
-
category: "MagicBackground",
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
export const getDominantColor = async (imageUrl: string): Promise<any> => {
|
|
10
|
-
try {
|
|
11
|
-
return await RNColorThief.getColor(imageUrl, 1, false);
|
|
12
|
-
} catch (error) {
|
|
13
|
-
log_error("Failed to get the dominant color", { error });
|
|
14
|
-
throw error;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const getPalettes = async (imageUrl: string): Promise<any> => {
|
|
19
|
-
try {
|
|
20
|
-
return await RNColorThief.getPalette(imageUrl, 3, 1, true);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
log_error("Failed to get the palette", { error });
|
|
23
|
-
throw error;
|
|
24
|
-
}
|
|
25
|
-
};
|