@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4576271826 → 12.0.0-alpha.4620237415

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 (37) hide show
  1. package/Components/Cell/Cell.tsx +8 -1
  2. package/Components/Focusable/__tests__/index.android.test.tsx +72 -0
  3. package/Components/Focusable/index.android.tsx +15 -9
  4. package/Components/FocusableList/FocusableChild.ts +2 -2
  5. package/Components/FocusableList/index.tsx +11 -12
  6. package/Components/FocusableScrollView/index.tsx +1 -1
  7. package/Components/Image/Image.android.tsx +1 -1
  8. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +6 -1
  9. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +12 -0
  10. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +6 -5
  11. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +2 -2
  12. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  13. package/Components/MasterCell/utils/index.ts +3 -4
  14. package/Components/PlayerContainer/PlayerContainer.tsx +14 -8
  15. package/Components/Transitioner/Transitioner.tsx +13 -3
  16. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +5 -0
  17. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +3 -9
  18. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +38 -40
  19. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +9 -6
  20. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +28 -26
  21. package/Components/VideoModal/PlayerDetails.tsx +16 -2
  22. package/Components/VideoModal/PlayerWrapper.tsx +40 -10
  23. package/Components/VideoModal/VideoModal.tsx +33 -27
  24. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +7 -0
  25. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -0
  26. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +56 -10
  27. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -1
  28. package/Components/ZappFrameworkComponents/BarView/Buttons/BackButton.tsx +7 -2
  29. package/Components/ZappFrameworkComponents/BarView/Buttons/CloseButton.tsx +7 -2
  30. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +87 -0
  31. package/Components/ZappFrameworkComponents/Buttons/ActionButton.tsx +9 -4
  32. package/Contexts/CachedDimensionsContext/index.ts +13 -9
  33. package/Contexts/ConfirmDialogState/index.ts +1 -1
  34. package/Contexts/ScreenContext/index.tsx +6 -1
  35. package/const.ts +6 -0
  36. package/index.js +3 -0
  37. package/package.json +5 -5
@@ -276,13 +276,20 @@ export class CellComponent extends React.Component<Props, State> {
276
276
  skipFocusManagerRegistration={skipFocusManagerRegistration}
277
277
  >
278
278
  {(focused, event) => {
279
+ const isFocused = this.isCellFocused(focused);
280
+
281
+ if (isFocused) {
282
+ const accessibilityManager = AccessibilityManager.getInstance();
283
+ accessibilityManager.readText({ text: item.title });
284
+ }
285
+
279
286
  return (
280
287
  <FocusableCell
281
288
  {...{
282
289
  index,
283
290
  CellRenderer,
284
291
  item,
285
- focused: this.isCellFocused(focused),
292
+ focused: isFocused,
286
293
  scrollTo: this.scrollToIndex(event),
287
294
  behavior,
288
295
  }}
@@ -0,0 +1,72 @@
1
+ import React from "react";
2
+ import { render, act } from "@testing-library/react-native";
3
+ import { Touchable } from "../../Touchable";
4
+
5
+ const mockUseIsRTL = jest.fn();
6
+
7
+ jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
8
+ useIsRTL: mockUseIsRTL,
9
+ }));
10
+
11
+ const mockUseFocusManager = jest.fn();
12
+
13
+ jest.mock("@applicaster/zapp-react-native-utils/focusManager", () => ({
14
+ useFocusManager: mockUseFocusManager,
15
+ }));
16
+
17
+ const mockUsePrevious = jest.fn();
18
+
19
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/utils", () => ({
20
+ usePrevious: mockUsePrevious,
21
+ }));
22
+
23
+ const { Focusable } = require("../index.android");
24
+
25
+ describe("Focusable", () => {
26
+ const mockFocusManager = {
27
+ isFocused: jest.fn(),
28
+ onDisableFocusChange: jest.fn(),
29
+ registerFocusable: jest.fn(),
30
+ focusedId: "test-id",
31
+ };
32
+
33
+ beforeEach(() => {
34
+ jest.clearAllMocks();
35
+ mockUseIsRTL.mockReturnValue(false);
36
+ mockUseFocusManager.mockReturnValue(mockFocusManager);
37
+ mockUsePrevious.mockReturnValue(false);
38
+ });
39
+
40
+ it("updates disableFocus state when disableFocus prop changes", () => {
41
+ const { rerender } = render(
42
+ <Focusable id="test-id" disableFocus={false}>
43
+ <Touchable testID="touchable" />
44
+ </Focusable>
45
+ );
46
+
47
+ rerender(
48
+ <Focusable id="test-id" disableFocus={true}>
49
+ <Touchable testID="touchable" />
50
+ </Focusable>
51
+ );
52
+
53
+ expect(mockFocusManager.onDisableFocusChange).toHaveBeenCalledWith(
54
+ "test-id"
55
+ );
56
+ });
57
+
58
+ it("calls focusManager.registerFocusable on mount and unregisters on unmount", () => {
59
+ const unregister = jest.fn();
60
+ mockFocusManager.registerFocusable.mockReturnValue(unregister);
61
+
62
+ const { unmount } = render(
63
+ <Focusable id="test-id">
64
+ <Touchable testID="touchable" />
65
+ </Focusable>
66
+ );
67
+
68
+ expect(mockFocusManager.registerFocusable).toHaveBeenCalled();
69
+ act(() => unmount());
70
+ expect(unregister).toHaveBeenCalled();
71
+ });
72
+ });
@@ -128,7 +128,10 @@ function FocusableComponent(props: Props, forwardedRef) {
128
128
 
129
129
  const _onBlur = React.useCallback(
130
130
  (ref, options = {}) => {
131
- setFocused(false);
131
+ if (ref.props.id !== focusManager.focusedId) {
132
+ setFocused(false);
133
+ }
134
+
132
135
  onBlur?.(ref, options);
133
136
  },
134
137
  [onBlur]
@@ -148,15 +151,14 @@ function FocusableComponent(props: Props, forwardedRef) {
148
151
  [isRTL, nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight]
149
152
  );
150
153
 
151
- const contextState = React.useMemo(
152
- () => ({
154
+ const contextState = React.useMemo(() => {
155
+ return {
153
156
  focused,
154
157
  ...parentFocus,
155
158
  ref: touchableRef,
156
159
  setIsFocusable,
157
- }),
158
- [parentFocus, focused]
159
- );
160
+ };
161
+ }, [parentFocus, focused]);
160
162
 
161
163
  return (
162
164
  <Touchable
@@ -173,9 +175,13 @@ function FocusableComponent(props: Props, forwardedRef) {
173
175
  {...parentFocus}
174
176
  >
175
177
  <FocusableContext.Provider value={contextState}>
176
- {typeof children === "function"
177
- ? children(focused, parentFocus, touchableRef)
178
- : children}
178
+ {React.useMemo(
179
+ () =>
180
+ typeof children === "function"
181
+ ? children(focused, parentFocus, touchableRef)
182
+ : children,
183
+ [children, focused, parentFocus]
184
+ )}
179
185
  </FocusableContext.Provider>
180
186
  </Touchable>
181
187
  );
@@ -31,14 +31,14 @@ const useParentFocus = (
31
31
 
32
32
  function FocusableChildComponent(props) {
33
33
  const { setIsFocusable, ...focusableContext } = useFocusable();
34
+ const focused = useCellState(props.id);
35
+
34
36
  const parentFocus = useParentFocus(props, focusableContext);
35
37
 
36
38
  const onLoadFailed = React.useCallback(() => {
37
39
  setIsFocusable(false);
38
40
  }, []);
39
41
 
40
- const focused = useCellState(props.id);
41
-
42
42
  return props.renderItem({
43
43
  ...props,
44
44
  focused,
@@ -88,6 +88,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
88
88
  data = [],
89
89
  // eslint-disable-next-line unused-imports/no-unused-vars
90
90
  onAllComponentsLoaded, // TODO: re-implement it
91
+ omitPropsPropagation = [],
91
92
  } = props;
92
93
 
93
94
  useCheckItemIdsForUnique({ componentId: props.id, items: data });
@@ -252,9 +253,9 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
252
253
  ]
253
254
  );
254
255
 
255
- const flatListProps = React.useMemo(
256
- () =>
257
- R.omit([
256
+ const getFlatListProps = React.useCallback(
257
+ R.omit(
258
+ [
258
259
  "onListElementFocus",
259
260
  "onListElementPress",
260
261
  "onListElementPressOut",
@@ -267,17 +268,17 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
267
268
  "focusableItemProps",
268
269
  "renderItem",
269
270
  "extraChildrenData",
270
- "extraData",
271
- "keyExtractor",
272
271
  "onAllComponentsLoaded",
273
272
  "focused",
274
273
  "id",
275
274
  "initialFocusDirection",
276
275
  "withStateMemory",
277
276
  "useSequentialLoading",
278
- ...(props.omitPropsPropagation || []),
279
- ])(props),
280
- [props]
277
+ ...omitPropsPropagation,
278
+ ],
279
+ R.__
280
+ ),
281
+ [omitPropsPropagation]
281
282
  );
282
283
 
283
284
  const onEndReached = React.useCallback(
@@ -289,7 +290,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
289
290
 
290
291
  const initialNumToRender = toFiniteNumberWithDefault(
291
292
  10,
292
- flatListProps.initialNumToRender
293
+ props.initialNumToRender
293
294
  );
294
295
 
295
296
  return (
@@ -298,12 +299,10 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
298
299
  <FlatList
299
300
  focusable={false}
300
301
  scrollEnabled={false}
301
- extraData={props.extraData}
302
302
  ref={ref}
303
- {...flatListProps}
303
+ {...getFlatListProps(props)}
304
304
  renderItem={renderItem}
305
305
  onEndReached={onEndReached}
306
- keyExtractor={props.keyExtractor}
307
306
  initialNumToRender={initialNumToRender}
308
307
  />
309
308
  </ChildrenFocusDeactivatorView>
@@ -284,7 +284,7 @@ function FocusableScrollViewComponent(props: Props, ref) {
284
284
  };
285
285
 
286
286
  return (
287
- <View onLayout={onItemLayout}>
287
+ <View key={id} onLayout={onItemLayout}>
288
288
  <Focusable
289
289
  {...nextFocus}
290
290
  onFocus={(element, direction) =>
@@ -8,5 +8,5 @@ import { useImageSource } from "./utils";
8
8
  export const QBImage = (props: FastImageProps) => {
9
9
  const source = useImageSource(props.source);
10
10
 
11
- return <FastImage {...props} source={source} />;
11
+ return <FastImage useLastImageAsDefaultSource {...props} source={source} />;
12
12
  };
@@ -3,6 +3,7 @@ import {
3
3
  ifElseFocusedSelected,
4
4
  ifElseSelected,
5
5
  } from "@applicaster/zapp-react-native-utils/cellUtils";
6
+ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
6
7
 
7
8
  import { getPositionStyles } from "./utils";
8
9
 
@@ -31,7 +32,11 @@ export const CellBadge = ({
31
32
  return {
32
33
  type: View, // Cell badge view
33
34
  style: {
34
- flex: 1,
35
+ flex: platformSelect({
36
+ tvos: 0,
37
+ android_tv: 0,
38
+ default: 1,
39
+ }),
35
40
  position: "absolute",
36
41
  ...getPositionStyles(position, {
37
42
  width: value("cell_badge_width"),
@@ -5,6 +5,7 @@ import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/acti
5
5
  import * as R from "ramda";
6
6
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
7
7
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
8
+ import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
8
9
 
9
10
  const { Logger } = getXray();
10
11
 
@@ -44,6 +45,11 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
44
45
 
45
46
  const actionContext = useActions(pluginIdentifier);
46
47
 
48
+ const accessibilityManager = useAccessibilityManager({});
49
+
50
+ const { ttsLabel = "" } =
51
+ actionContext?.initialEntryState(item)?.getAccessibility?.(item) || {};
52
+
47
53
  const onPress = (event) => {
48
54
  event?.preventDefault?.();
49
55
 
@@ -88,6 +94,12 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
88
94
  mouse: focusable.mouse,
89
95
  });
90
96
  });
97
+
98
+ if (ttsLabel) {
99
+ accessibilityManager.readText({
100
+ text: ttsLabel,
101
+ });
102
+ }
91
103
  };
92
104
 
93
105
  const handleBlur = (_focusable, _direction) => {
@@ -38,21 +38,22 @@ function Image({
38
38
 
39
39
  const shouldRenderImg = source && !error;
40
40
 
41
+ // Default placeholder image fallback is empty string because it won't rerender
42
+ // in case of undefined or {uri: undefined} source
43
+ // https://github.com/facebook/react-native/issues/9195
41
44
  const defaultPlaceHolderImage = React.useMemo(
42
45
  () => ({ uri: placeholderImage || "" }),
43
46
  [source, error]
44
47
  );
45
48
 
46
- const _source = shouldRenderImg
47
- ? withDimensions(source)
48
- : defaultPlaceHolderImage;
49
-
50
49
  return (
51
50
  // @ts-ignore
52
51
  <MemoizedImage
53
52
  style={style as ImageStyle}
54
53
  onError={() => setErrorState(true)}
55
- source={_source?.uri ? _source : undefined}
54
+ source={
55
+ shouldRenderImg ? withDimensions(source) : defaultPlaceHolderImage
56
+ }
56
57
  {...R.omit(["source"], otherProps)}
57
58
  />
58
59
  );
@@ -31,10 +31,10 @@ function Image({
31
31
 
32
32
  return (
33
33
  <RnImage
34
- defaultSource={placeholderImage || ""}
34
+ defaultSource={placeholderImage || null}
35
35
  style={style}
36
36
  source={updatedSource}
37
- {...R.omit(["source"], otherProps)}
37
+ {...R.omit(["source", "placeholderImage"], otherProps)}
38
38
  />
39
39
  );
40
40
  }
@@ -39,6 +39,6 @@ describe("image with no source", () => {
39
39
  );
40
40
 
41
41
  const testInstance = testRenderer.root;
42
- expect(testInstance.findByType(Image).props.source).toBeUndefined();
42
+ expect(testInstance.findByType(Image).props.source).toEqual({ uri: "" });
43
43
  });
44
44
  });
@@ -53,10 +53,9 @@ function resolveColorForProp(entry, style, colorProp) {
53
53
  const colorFromProp = style[colorProp];
54
54
  const nestedEntryValue = R.path(colorFromProp.split("."), entry);
55
55
 
56
- if (
57
- nestedEntryValue === undefined &&
58
- !validateColor(colorFromProp.replace(".00", "")) // https://github.com/dreamyguy/validate-color/issues/44
59
- ) {
56
+ const color = colorFromProp.replace(".00", "").replace(".0", ""); // https://github.com/dreamyguy/validate-color/issues/44
57
+
58
+ if (nestedEntryValue === undefined && !validateColor(color)) {
60
59
  logWarning(colorFromProp, style, entry, nestedEntryValue);
61
60
  }
62
61
 
@@ -362,13 +362,15 @@ const PlayerContainerComponent = (props: Props) => {
362
362
  const toggleFullscreen = (event) => {
363
363
  const { fullscreen = false } = event || {};
364
364
 
365
- if (fullscreen) {
366
- playerEvent("onFullscreenPlayerWillPresent");
367
- navigator.fullscreenVideoModal();
368
- } else {
369
- playerEvent("onFullscreenPlayerWillDismiss");
370
- navigator.maximiseVideoModal();
371
- }
365
+ setTimeout(() => {
366
+ if (fullscreen) {
367
+ navigator.fullscreenVideoModal();
368
+ playerEvent("onFullscreenPlayerWillPresent");
369
+ } else {
370
+ navigator.maximiseVideoModal();
371
+ playerEvent("onFullscreenPlayerWillDismiss");
372
+ }
373
+ });
372
374
  };
373
375
 
374
376
  const onCellTap = (entry) => {
@@ -463,6 +465,10 @@ const PlayerContainerComponent = (props: Props) => {
463
465
 
464
466
  if (mode === VideoModalMode.FULLSCREEN) {
465
467
  toggleFullscreen({ fullscreen: false });
468
+
469
+ if (!isModal) {
470
+ playerManager.closeNativePlayer();
471
+ }
466
472
  }
467
473
 
468
474
  return !!(
@@ -519,7 +525,7 @@ const PlayerContainerComponent = (props: Props) => {
519
525
  }
520
526
 
521
527
  return () => {
522
- playerEvent("player_did_close");
528
+ playerEvent("player_did_close", { item });
523
529
 
524
530
  if (!isModal) {
525
531
  showNavBar(true);
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { update, compose, tail, append, take, identity } from "ramda";
3
+ import { update, compose, tail, append, take, identity, isNil } from "ramda";
4
4
 
5
5
  import { AnimationManager } from "./AnimationManager";
6
6
  import { Scene } from "./Scene";
@@ -50,6 +50,10 @@ function scenesForBackTransition(props: SceneProps, { scenes }) {
50
50
  : [prepareScene(props.children), scenes[0]];
51
51
  }
52
52
 
53
+ const isModalClosed = (navigator) => {
54
+ return !!isNil(navigator?.modalData);
55
+ };
56
+
53
57
  type Props = {
54
58
  transitionConfig: any;
55
59
  children: React.ReactNode;
@@ -313,7 +317,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
313
317
  <Scene
314
318
  key={scenes[from.index].key}
315
319
  pathname={scenes[from.index].key}
316
- isActive={scenes[from.index].key === this.props.navigator.currentRoute}
320
+ isActive={
321
+ scenes[from.index].key === this.props.navigator.currentRoute &&
322
+ isModalClosed(this.props.navigator)
323
+ }
317
324
  style={from.style}
318
325
  pointerEvents="none"
319
326
  overlayStyle={from.overlayStyle}
@@ -329,7 +336,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
329
336
  const toScene = scenes[to.index] && (
330
337
  <Scene
331
338
  pathname={scenes[to.index].key}
332
- isActive={scenes[to.index].key === this.props.navigator.currentRoute}
339
+ isActive={
340
+ scenes[to.index].key === this.props.navigator.currentRoute &&
341
+ isModalClosed(this.props.navigator)
342
+ }
333
343
  key={scenes[to.index].key}
334
344
  style={to.style}
335
345
  overlayStyle={to.overlayStyle}
@@ -31,6 +31,11 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
31
31
  playerId="player1"
32
32
  resizeMode="cover"
33
33
  screenConfig={Object {}}
34
+ source={
35
+ Object {
36
+ "uri": "",
37
+ }
38
+ }
34
39
  style={Object {}}
35
40
  />
36
41
  </View>
@@ -45,15 +45,9 @@ export const AnimatedPlayerModalWrapper = (props: Props) => {
45
45
  }
46
46
 
47
47
  React.useEffect(() => {
48
- const translateYListener = translateY.addListener(() => {
49
- (playerAnimationState === PlayerAnimationStateEnum.minimize ||
50
- playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
51
- setStartComponentsAnimation(true);
52
- });
53
-
54
- return () => {
55
- translateYListener && translateY.removeListener(translateYListener);
56
- };
48
+ (playerAnimationState === PlayerAnimationStateEnum.minimize ||
49
+ playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
50
+ setStartComponentsAnimation(true);
57
51
  }, [playerAnimationState]);
58
52
 
59
53
  return (
@@ -66,9 +66,10 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
66
66
  const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
67
67
  useNavigation();
68
68
 
69
- const isMaximazedModal = videoModalState.mode === "MAXIMIZED";
70
- const isMinimizedModal = videoModalState.mode === "MINIMIZED";
71
- const previousItemId = usePrevious(videoModalState.item?.id);
69
+ const { mode: videoModalMode, item: videoModalItem } = videoModalState;
70
+ const isMaximazedModal = videoModalMode === "MAXIMIZED";
71
+ const isMinimizedModal = videoModalMode === "MINIMIZED";
72
+ const previousItemId = usePrevious(videoModalItem?.id);
72
73
 
73
74
  const isNotMinimizeMaximazeAnimation =
74
75
  playerAnimationState !== PlayerAnimationStateEnum.minimize &&
@@ -81,9 +82,9 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
81
82
 
82
83
  const isAudioItem = React.useMemo(
83
84
  () =>
84
- videoModalState.item?.content?.type?.includes?.("audio") ||
85
- videoModalState.item?.type?.value === "audio",
86
- [videoModalState.item]
85
+ videoModalItem?.content?.type?.includes?.("audio") ||
86
+ videoModalItem?.type?.value === "audio",
87
+ [videoModalItem]
87
88
  );
88
89
 
89
90
  // Refs for components
@@ -114,7 +115,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
114
115
  const preparedTranslationY =
115
116
  Math.abs(translationY) - lastScrollYValue.current;
116
117
 
117
- if (videoModalState.mode === "MAXIMIZED") {
118
+ if (videoModalMode === "MAXIMIZED") {
118
119
  const endOffsetY =
119
120
  lastSnap + preparedTranslationY + dragToss * velocityY + 150;
120
121
 
@@ -161,7 +162,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
161
162
  resetPlayerAnimationState();
162
163
  }
163
164
  },
164
- [lastSnap, modalSnapPoints, playerAnimationState, videoModalState.mode]
165
+ [lastSnap, modalSnapPoints, playerAnimationState, videoModalMode]
165
166
  );
166
167
 
167
168
  const onScroll = React.useCallback(({ nativeEvent }) => {
@@ -196,10 +197,9 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
196
197
  }, []);
197
198
 
198
199
  React.useEffect(() => {
199
- if (
200
- videoModalState.mode === "MINIMIZED" &&
201
- videoModalState.previousMode === "MAXIMIZED"
202
- ) {
200
+ const { mode, previousMode, item } = videoModalState;
201
+
202
+ if (mode === "MINIMIZED" && previousMode === "MAXIMIZED") {
203
203
  // set animation to the minimize values if moving from the player to another screen
204
204
  if (playerAnimationState === null) {
205
205
  setScrollModalAnimatedValue(
@@ -214,21 +214,17 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
214
214
  dragScrollY,
215
215
  dragVideoPlayerY
216
216
  );
217
- } else {
218
- resetPlayerAnimationState();
219
217
  }
220
- }
221
-
222
- if (
223
- (videoModalState.mode === "MAXIMIZED" &&
224
- videoModalState.previousMode === "MINIMIZED" &&
225
- previousItemId === videoModalState.item?.id) ||
226
- previousItemId !== videoModalState.item?.id
218
+ } else if (
219
+ playerAnimationState === null &&
220
+ ((previousItemId === item?.id &&
221
+ mode === "MAXIMIZED" &&
222
+ (previousMode === "MINIMIZED" || previousMode === "MAXIMIZED")) ||
223
+ (previousItemId !== item?.id && mode !== "FULLSCREEN"))
227
224
  ) {
228
225
  setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
229
- setTimeout(() => resetPlayerAnimationState());
230
226
  }
231
- }, [videoModalState, previousItemId]);
227
+ }, [videoModalState]);
232
228
 
233
229
  React.useEffect(() => {
234
230
  if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
@@ -253,22 +249,22 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
253
249
  translateYOffset,
254
250
  getAnimatedConfig(modalSnapPoints[1])
255
251
  ).start(() => {
256
- setTimeout(() => {
257
- minimiseVideoModal();
258
-
259
- setScrollModalAnimatedValue(
260
- translateYOffset,
261
- modalSnapPoints[1],
262
- setLastSnap
263
- );
264
-
265
- resetScrollAnimatedValues(
266
- lastScrollY,
267
- lastScrollYValue,
268
- dragScrollY,
269
- dragVideoPlayerY
270
- );
271
- }, 150);
252
+ minimiseVideoModal();
253
+
254
+ setScrollModalAnimatedValue(
255
+ translateYOffset,
256
+ modalSnapPoints[1],
257
+ setLastSnap
258
+ );
259
+
260
+ resetScrollAnimatedValues(
261
+ lastScrollY,
262
+ lastScrollYValue,
263
+ dragScrollY,
264
+ dragVideoPlayerY
265
+ );
266
+
267
+ resetPlayerAnimationState();
272
268
  });
273
269
  } else if (playerAnimationState === PlayerAnimationStateEnum.maximaze) {
274
270
  Animated.timing(translateYOffset, getAnimatedConfig(0)).start(() => {
@@ -285,7 +281,9 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
285
281
  resetPlayerAnimationState();
286
282
  });
287
283
  }
284
+ }, [playerAnimationState]);
288
285
 
286
+ React.useEffect(() => {
289
287
  const lastScrollYListenerId = lastScrollY.addListener(({ value }) => {
290
288
  lastScrollYValue.current = value;
291
289
  });
@@ -311,7 +309,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
311
309
  lastScrollY.removeListener(lastScrollYListenerId);
312
310
  dragScrollY.removeListener(dragListenerId);
313
311
  };
314
- }, [playerAnimationState, isAudioItem, modalSnapPoints, isMinimizedModal]);
312
+ }, [playerAnimationState, isAudioItem, isMinimizedModal]);
315
313
 
316
314
  const Wrapper = React.useMemo(
317
315
  () => (Platform.OS === "android" ? GestureHandlerRootView : View),