@applicaster/zapp-react-native-utils 13.0.0-alpha.9270615060 → 13.0.0-alpha.9946926334
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/actionsExecutor/ActionExecutorContext.tsx +27 -2
- package/alertUtils/alert.ts +148 -0
- package/alertUtils/index.ts +1 -148
- package/analyticsUtils/AnalyticPlayerListener.ts +18 -1
- package/analyticsUtils/__tests__/__snapshots__/analyticsManagerNoModule.test.js.snap +9 -9
- package/analyticsUtils/helpers/hooks.ts +1 -1
- package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
- package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +10 -8
- package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +693 -0
- package/appUtils/HooksManager/__tests__/hook.test.js +196 -184
- package/appUtils/HooksManager/__tests__/hooksManager.test.js +96 -99
- package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
- package/appUtils/HooksManager/{index.js → index.ts} +121 -112
- package/appUtils/HooksManager/types.ts +116 -0
- package/appUtils/RiverFocusManager/index.js +17 -12
- package/appUtils/accessibilityManager/index.ts +42 -1
- package/appUtils/contextKeysManager/contextResolver.ts +73 -0
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +6 -6
- package/appUtils/focusManager/index.ts +90 -63
- package/appUtils/focusManager/treeDataStructure/Tree/index.js +25 -3
- package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -3
- package/appUtils/focusManager/utils/enums.ts +4 -0
- package/appUtils/{index.js → index.ts} +1 -1
- package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +2 -2
- package/appUtils/keyCodes/__tests__/keyCodes.test.js +4 -4
- package/appUtils/keyCodes/{index.js → index.ts} +2 -0
- package/appUtils/keyCodes/keys/index.ts +3 -0
- package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
- package/appUtils/keyCodes/keys/keys.android.ts +18 -0
- package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
- package/appUtils/keyCodes/keys/keys.ts +15 -0
- package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +4 -3
- package/appUtils/keyCodes/keysByPlatform.ts +8 -0
- package/appUtils/keyInputHandler/KeyInputHandler.ts +10 -32
- package/appUtils/orientationHelper.ts +1 -1
- package/appUtils/platform/platformUtils.ts +0 -14
- package/appUtils/playerManager/index.ts +6 -2
- package/appUtils/playerManager/player.ts +7 -8
- package/appUtils/playerManager/playerNative.ts +1 -1
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -15
- package/arrayUtils/__tests__/__snapshots__/arrayUtils.test.ts.snap +4 -4
- package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
- package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +4 -4
- package/functionUtils/index.ts +15 -11
- package/manifestUtils/__tests__/createConfig.test.js +18 -16
- package/modalState/index.ts +1 -5
- package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +6 -6
- package/navigationUtils/__tests__/itemTypes.test.js +2 -2
- package/navigationUtils/__tests__/navigationUtils.test.js +2 -2
- package/navigationUtils/index.ts +14 -5
- package/package.json +3 -2
- package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -1
- package/reactHooks/cell-click/__tests__/index.test.js +5 -2
- package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +4 -4
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +10 -11
- package/reactHooks/feed/usePipesCacheReset.ts +5 -5
- package/reactHooks/flatList/__tests__/index.test.tsx +30 -21
- package/reactHooks/layout/__tests__/index.test.tsx +10 -10
- package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +14 -28
- package/reactHooks/navigation/__tests__/index.test.tsx +0 -4
- package/reactHooks/navigation/index.ts +29 -218
- package/reactHooks/navigation/useGetBottomTabBarHeight.ts +12 -0
- package/reactHooks/navigation/useGetNavBarTopBorderWidth.ts +14 -0
- package/reactHooks/navigation/useGetTabBarHeight.ts +12 -0
- package/reactHooks/navigation/useIsScreenActive.ts +17 -0
- package/reactHooks/navigation/useNavigationPluginData.ts +15 -0
- package/reactHooks/navigation/useNavigationType.ts +15 -0
- package/reactHooks/navigation/usePathname.ts +4 -0
- package/reactHooks/navigation/useRoute.ts +100 -0
- package/reactHooks/navigation/useUniqueRouteSuffix.ts +41 -0
- package/reactHooks/player/TVSeekControlller/ISeekController.ts +28 -3
- package/reactHooks/player/TVSeekControlller/LongPressSeekController.ts +43 -95
- package/reactHooks/player/TVSeekControlller/TVSeekController.ts +188 -98
- package/reactHooks/player/TVSeekControlller/TapSeekController.ts +35 -55
- package/reactHooks/player/__tests__/useAutoSeek._test.tsx +115 -0
- package/reactHooks/player/__tests__/useTapSeek._test.ts +94 -0
- package/reactHooks/player/const.ts +1 -5
- package/reactUtils/__tests__/reactUtils.test.js +10 -28
- package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +19 -19
- package/reactUtils/createContext/__tests__/__snapshots__/index.test.js.snap +2 -2
- package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -3
- package/reactUtils/createContext/__tests__/helpers.test.js +8 -8
- package/reactUtils/index.ts +0 -14
- package/theme/__mocks__/index.ts +4 -0
- package/appUtils/keyCodes/keys.ios.js +0 -46
- package/appUtils/playerManager/DelayedSeekPlayerWrapper.tsx +0 -180
- /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
- /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
- /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
- /package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +0 -0
- /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
- /package/domUtils/{logger.js → logger.ts} +0 -0
|
@@ -1,116 +1,64 @@
|
|
|
1
|
-
import { ISeekController } from "./ISeekController";
|
|
2
|
-
import { SEEK_TYPE } from "../const";
|
|
3
1
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
2
|
+
ISeekController,
|
|
3
|
+
ISeekControllerDelegate,
|
|
4
|
+
SeekIncrementalBaseStrategy,
|
|
5
|
+
} from "./ISeekController";
|
|
6
|
+
import { SEEK_TYPE } from "../const";
|
|
7
|
+
import { log_debug, log_error, log_verbose } from "./TVSeekController";
|
|
8
|
+
import { interval, Subscription } from "rxjs";
|
|
9
|
+
import { tap } from "rxjs/operators";
|
|
11
10
|
|
|
12
|
-
/**
|
|
13
|
-
* Example interface for the configuration needed for long-press seeking.
|
|
14
|
-
*/
|
|
15
11
|
interface LongPressConfig {
|
|
16
|
-
|
|
17
|
-
TIMER_INTERVAL_MS: number; // ms
|
|
18
|
-
SKIP_INCREMENT_STEP: number; // seconds
|
|
19
|
-
MAX_SKIP_PER_TICK: number; // seconds
|
|
20
|
-
INITIAL_SKIP_AMOUNT: number; // e.g., 10s to start
|
|
12
|
+
TIMER_INTERVAL_MS: number;
|
|
21
13
|
}
|
|
22
14
|
|
|
23
15
|
export class LongPressSeekController implements ISeekController {
|
|
24
|
-
private pressStartTime = 0;
|
|
25
|
-
private isLongPressActive = false;
|
|
26
|
-
private currentSkipAmount = 0;
|
|
27
16
|
private subscription: Subscription | null = null;
|
|
28
|
-
|
|
17
|
+
readonly title = "LongPressSeek";
|
|
29
18
|
constructor(
|
|
30
|
-
private
|
|
19
|
+
private seekControllerDelegate: ISeekControllerDelegate,
|
|
20
|
+
private seekIncrementalStrategy: SeekIncrementalBaseStrategy,
|
|
31
21
|
private config: LongPressConfig
|
|
32
22
|
) {}
|
|
33
23
|
|
|
34
|
-
|
|
24
|
+
onStartSeek(seekType: SEEK_TYPE) {
|
|
35
25
|
this.cleanUpSubscription();
|
|
36
26
|
|
|
37
|
-
log_debug(
|
|
38
|
-
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
log_debug(
|
|
65
|
-
`LongPressSeekController: handle delayed seek type: ${seekType} - currentSkipAmount: ${this.currentSkipAmount}.`
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
this.currentSkipAmount = Math.min(
|
|
69
|
-
this.currentSkipAmount + this.config.SKIP_INCREMENT_STEP,
|
|
70
|
-
this.config.MAX_SKIP_PER_TICK
|
|
71
|
-
);
|
|
72
|
-
})
|
|
73
|
-
);
|
|
74
|
-
})
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
this.subscription = threshold$.subscribe({
|
|
78
|
-
complete: () =>
|
|
79
|
-
log_verbose(
|
|
80
|
-
"LongPressSeekController: Long press subscription complete"
|
|
81
|
-
),
|
|
82
|
-
error: (err) =>
|
|
83
|
-
log_error(
|
|
84
|
-
"LongPressSeekController: Long press subscription error",
|
|
85
|
-
err
|
|
86
|
-
),
|
|
87
|
-
});
|
|
27
|
+
log_debug(`${this.title}: start long press seek type: ${seekType}.`);
|
|
28
|
+
|
|
29
|
+
this.seekControllerDelegate.handlePlayerPause();
|
|
30
|
+
|
|
31
|
+
this.subscription = interval(this.config.TIMER_INTERVAL_MS)
|
|
32
|
+
.pipe(
|
|
33
|
+
tap(() => {
|
|
34
|
+
this.seekControllerDelegate.handleDelayedSeek(
|
|
35
|
+
this.seekIncrementalStrategy.getSkipTime()
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
log_debug(
|
|
39
|
+
`${
|
|
40
|
+
this.title
|
|
41
|
+
}: handle delayed seek type: ${seekType} - multiplier: ${this.seekIncrementalStrategy.getSkipMultiplier()}, currentSkipAmount: ${this.seekIncrementalStrategy.getSkipTime()}.`
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
this.seekIncrementalStrategy.increment();
|
|
45
|
+
})
|
|
46
|
+
)
|
|
47
|
+
.subscribe({
|
|
48
|
+
complete: () =>
|
|
49
|
+
log_verbose(`${this.title}: Long press subscription complete`),
|
|
50
|
+
error: (err) =>
|
|
51
|
+
log_error(`${this.title}: Long press subscription error`, err),
|
|
52
|
+
});
|
|
88
53
|
}
|
|
89
54
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
this.isLongPressActive &&
|
|
95
|
-
pressDuration > this.config.LONG_PRESS_THRESHOLD
|
|
96
|
-
) {
|
|
97
|
-
const offset = this.parent.delayedSeekOffset;
|
|
98
|
-
|
|
99
|
-
if (offset) {
|
|
100
|
-
log_debug(
|
|
101
|
-
`LongPressSeekController: onPressEnd for LongPressSeekController, seek offset: ${offset}`
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
this.parent.seekPlayer(offset);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this.parent.resetAll();
|
|
55
|
+
onSeekEnd() {
|
|
56
|
+
this.cleanUpSubscription();
|
|
57
|
+
this.seekControllerDelegate.handleSeekComplete();
|
|
109
58
|
}
|
|
110
59
|
|
|
111
60
|
reset() {
|
|
112
|
-
this.
|
|
113
|
-
this.currentSkipAmount = 0;
|
|
61
|
+
this.seekIncrementalStrategy.reset();
|
|
114
62
|
this.cleanUpSubscription();
|
|
115
63
|
}
|
|
116
64
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { BehaviorSubject } from "rxjs";
|
|
2
2
|
import { TapSeekController } from "./TapSeekController";
|
|
3
3
|
import { LongPressSeekController } from "./LongPressSeekController";
|
|
4
|
-
import { playerManager } from "../../../appUtils";
|
|
5
4
|
import { SEEK_TYPE } from "../const";
|
|
6
5
|
import { createLogger } from "../../../logger";
|
|
7
6
|
import { Player } from "../../../appUtils/playerManager/player";
|
|
8
7
|
import { SeekKeyHandlerListener } from "../../../appUtils/keyInputHandler/KeyInputHandler";
|
|
8
|
+
import {
|
|
9
|
+
ISeekController,
|
|
10
|
+
ISeekControllerDelegate,
|
|
11
|
+
SeekIncrementalBaseStrategy,
|
|
12
|
+
} from "./ISeekController";
|
|
9
13
|
|
|
10
14
|
export const { log_warning, log_debug, log_info, log_error, log_verbose } =
|
|
11
15
|
createLogger({
|
|
@@ -13,156 +17,242 @@ export const { log_warning, log_debug, log_info, log_error, log_verbose } =
|
|
|
13
17
|
subsystem: "TVSeekController",
|
|
14
18
|
});
|
|
15
19
|
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
export enum SEEK_STRATEGY {
|
|
21
|
+
TAP_SEEK = "TAP_SEEK",
|
|
22
|
+
AUTO_SEEK = "AUTO_SEEK",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const CONFIG_TAP_SEEK = {
|
|
26
|
+
CLICKS_BEFORE_PAUSE: 0,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const CONFIG_LONG_PRESS = {
|
|
30
|
+
TIMER_INTERVAL_MS: 200,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const LONG_PRESS_THRESHOLD = 500;
|
|
34
|
+
const SEEK_END_TIMEOUT_DURATION = 700;
|
|
35
|
+
// prettier-ignore
|
|
36
|
+
|
|
37
|
+
export class TVSeekController
|
|
38
|
+
implements SeekKeyHandlerListener, ISeekControllerDelegate {
|
|
39
|
+
public delayedSeekPosition: number | null = null;
|
|
40
|
+
private readonly playerController: Player;
|
|
21
41
|
private delayedSeekProgressSubject = new BehaviorSubject<number | null>(null);
|
|
42
|
+
isPlayerInitiallyPaused: null | boolean = null;
|
|
43
|
+
currentSeekType: SEEK_TYPE | null = null;
|
|
22
44
|
|
|
23
|
-
|
|
24
|
-
private tapSeekController: TapSeekController;
|
|
25
|
-
private longPressSeekController: LongPressSeekController;
|
|
45
|
+
private currentSeekController: ISeekController;
|
|
46
|
+
private readonly tapSeekController: TapSeekController;
|
|
47
|
+
private readonly longPressSeekController: LongPressSeekController;
|
|
48
|
+
private longPressThresholdTimeout: any | null = null;
|
|
49
|
+
private seekEndTimeout: any | null = null;
|
|
26
50
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
LONG_PRESS_THRESHOLD: 500,
|
|
30
|
-
TIMER_INTERVAL_MS: 300,
|
|
31
|
-
SKIP_INCREMENT_STEP: 5,
|
|
32
|
-
MAX_SKIP_PER_TICK: 300,
|
|
33
|
-
INITIAL_SKIP_AMOUNT: 10,
|
|
34
|
-
};
|
|
51
|
+
constructor(playerController: Player) {
|
|
52
|
+
this.playerController = playerController;
|
|
35
53
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
54
|
+
this.tapSeekController = new TapSeekController(
|
|
55
|
+
this,
|
|
56
|
+
new SeekIncrementalBaseStrategy(),
|
|
57
|
+
CONFIG_TAP_SEEK
|
|
58
|
+
);
|
|
39
59
|
|
|
40
60
|
this.longPressSeekController = new LongPressSeekController(
|
|
41
61
|
this,
|
|
42
|
-
|
|
62
|
+
new SeekIncrementalBaseStrategy(),
|
|
63
|
+
CONFIG_LONG_PRESS
|
|
43
64
|
);
|
|
65
|
+
|
|
66
|
+
this.currentSeekController = this.tapSeekController;
|
|
44
67
|
}
|
|
45
68
|
|
|
46
|
-
getDelayedSeekProgressObservable() {
|
|
69
|
+
getDelayedSeekProgressObservable = () => {
|
|
47
70
|
return this.delayedSeekProgressSubject;
|
|
48
|
-
}
|
|
71
|
+
};
|
|
49
72
|
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
setStrategy = (seekStrategy: SEEK_STRATEGY) => {
|
|
74
|
+
switch (seekStrategy) {
|
|
75
|
+
case SEEK_STRATEGY.TAP_SEEK:
|
|
76
|
+
this.currentSeekController = this.tapSeekController;
|
|
77
|
+
log_debug("TVSeekController: setStrategy - TAP_SEEK");
|
|
52
78
|
|
|
53
|
-
|
|
79
|
+
break;
|
|
80
|
+
case SEEK_STRATEGY.AUTO_SEEK:
|
|
81
|
+
this.currentSeekController = this.longPressSeekController;
|
|
82
|
+
log_debug("TVSeekController: setStrategy - AUTO_SEEK");
|
|
83
|
+
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
}
|
|
54
87
|
};
|
|
55
88
|
|
|
56
|
-
|
|
57
|
-
this.
|
|
89
|
+
handleStartSeek = (seekType: SEEK_TYPE) => {
|
|
90
|
+
this.currentSeekType = seekType;
|
|
58
91
|
|
|
59
|
-
|
|
92
|
+
if (this.isPlayerInitiallyPaused === null) {
|
|
93
|
+
this.isPlayerInitiallyPaused = this.playerController.isPaused();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this.clearLongPressThresholdTimeout();
|
|
97
|
+
this.clearSeekCompleteTimeout();
|
|
98
|
+
this.setStrategy(SEEK_STRATEGY.TAP_SEEK);
|
|
99
|
+
this.currentSeekController.onStartSeek(seekType);
|
|
100
|
+
|
|
101
|
+
this.longPressThresholdTimeout = setTimeout(() => {
|
|
102
|
+
this.setStrategy(SEEK_STRATEGY.AUTO_SEEK);
|
|
103
|
+
this.currentSeekController.onStartSeek(seekType);
|
|
104
|
+
}, LONG_PRESS_THRESHOLD);
|
|
60
105
|
};
|
|
61
106
|
|
|
62
|
-
|
|
63
|
-
this.
|
|
64
|
-
this.tapSeekController.reset();
|
|
107
|
+
onForwardPress = (): boolean => {
|
|
108
|
+
this.handleStartSeek(SEEK_TYPE.FORWARD);
|
|
65
109
|
|
|
66
110
|
return true;
|
|
67
111
|
};
|
|
68
112
|
|
|
69
|
-
|
|
70
|
-
this.
|
|
71
|
-
this.tapSeekController.reset();
|
|
113
|
+
onRewindPress = (): boolean => {
|
|
114
|
+
this.handleStartSeek(SEEK_TYPE.REWIND);
|
|
72
115
|
|
|
73
116
|
return true;
|
|
74
117
|
};
|
|
75
118
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
onForwardPress: this.onForwardPress,
|
|
82
|
-
onRewindPress: this.onRewindPress,
|
|
83
|
-
onForwardLongPress: this.onForwardLongPress,
|
|
84
|
-
onRewindLongPress: this.onRewindLongPress,
|
|
85
|
-
onForwardPressOut: this.onForwardPressOut,
|
|
86
|
-
onRewindPressOut: this.onRewindPressOut,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
119
|
+
onSeekEnd = () => {
|
|
120
|
+
this.clearLongPressThresholdTimeout();
|
|
121
|
+
this.currentSeekController.onSeekEnd();
|
|
122
|
+
};
|
|
89
123
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
124
|
+
onRewindPressOut = () => {
|
|
125
|
+
this.onSeekEnd();
|
|
126
|
+
};
|
|
93
127
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (!player) return;
|
|
128
|
+
onForwardPressOut = () => {
|
|
129
|
+
this.onSeekEnd();
|
|
130
|
+
};
|
|
98
131
|
|
|
99
|
-
|
|
100
|
-
if (this.
|
|
101
|
-
|
|
132
|
+
onVideoProgress = (position: number) => {
|
|
133
|
+
if (this.delayedSeekPosition !== null) {
|
|
134
|
+
return;
|
|
102
135
|
}
|
|
103
136
|
|
|
104
|
-
|
|
105
|
-
|
|
137
|
+
this.delayedSeekProgressSubject.next(position);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
handleDelayedSeek = (offset: number = 0) => {
|
|
141
|
+
this.handlePlayerPause();
|
|
142
|
+
|
|
143
|
+
const currentPos =
|
|
144
|
+
this.delayedSeekPosition === null
|
|
145
|
+
? this.playerController.getPosition()
|
|
146
|
+
: this.delayedSeekPosition;
|
|
147
|
+
|
|
106
148
|
let targetPos = currentPos;
|
|
107
149
|
|
|
108
|
-
if (
|
|
109
|
-
targetPos = Math.min(
|
|
150
|
+
if (this.currentSeekType === SEEK_TYPE.FORWARD) {
|
|
151
|
+
targetPos = Math.min(
|
|
152
|
+
currentPos + offset,
|
|
153
|
+
this.playerController.getSeekableDuration()
|
|
154
|
+
);
|
|
155
|
+
} else if (this.currentSeekType === SEEK_TYPE.REWIND) {
|
|
156
|
+
targetPos = Math.max(0, currentPos - offset);
|
|
110
157
|
} else {
|
|
111
|
-
|
|
158
|
+
log_warning(
|
|
159
|
+
`TVSeekController: handleDelayedSeek - invalid seek type: ${this.currentSeekType}`
|
|
160
|
+
);
|
|
112
161
|
}
|
|
113
162
|
|
|
114
|
-
this.delayedSeekOffset = newOffset;
|
|
115
|
-
|
|
116
163
|
log_debug(
|
|
117
|
-
`TVSeekController: handleDelayedSeek - targetPos: ${targetPos},
|
|
164
|
+
`TVSeekController: handleDelayedSeek - targetPos: ${targetPos}, skipTime: ${offset}`
|
|
118
165
|
);
|
|
119
166
|
|
|
167
|
+
const prevValue = this.delayedSeekProgressSubject.getValue();
|
|
168
|
+
|
|
169
|
+
if (prevValue !== null) {
|
|
170
|
+
const delta = Math.abs(prevValue - targetPos);
|
|
171
|
+
|
|
172
|
+
if (delta < 1) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.delayedSeekPosition = targetPos;
|
|
120
178
|
this.delayedSeekProgressSubject.next(targetPos);
|
|
121
|
-
}
|
|
179
|
+
};
|
|
122
180
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
181
|
+
handleSeekTo = (newPosition: number) => {
|
|
182
|
+
this.playerController.seekTo(newPosition);
|
|
183
|
+
|
|
184
|
+
if (!this.isPlayerInitiallyPaused) {
|
|
185
|
+
this.playerController.play();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
129
188
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (!player) return;
|
|
189
|
+
handleSeek = (offset: number) => {
|
|
190
|
+
this.playerController[this.currentSeekType](offset);
|
|
133
191
|
|
|
134
|
-
if (
|
|
135
|
-
|
|
192
|
+
if (!this.isPlayerInitiallyPaused) {
|
|
193
|
+
this.playerController.play();
|
|
136
194
|
}
|
|
137
|
-
}
|
|
195
|
+
};
|
|
138
196
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
197
|
+
handleSeekComplete = () => {
|
|
198
|
+
this.clearSeekCompleteTimeout();
|
|
199
|
+
|
|
200
|
+
this.seekEndTimeout = setTimeout(() => {
|
|
201
|
+
if (this.delayedSeekPosition !== null) {
|
|
202
|
+
this.handleSeekTo(this.delayedSeekPosition);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
log_debug(
|
|
206
|
+
`handleSeekComplete: Seek finished, type: ${this.currentSeekController.title}, seekPosition: ${this.delayedSeekPosition}. Reset all states and seek position.`
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
this.resetAll();
|
|
210
|
+
}, SEEK_END_TIMEOUT_DURATION);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
isSeeking = (): boolean => {
|
|
214
|
+
return this.delayedSeekPosition !== null;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
handlePlayerPause = () => {
|
|
218
|
+
if (this.playerController.isPaused()) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
this.playerController.pause();
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
clearSeekCompleteTimeout = () => {
|
|
226
|
+
if (this.seekEndTimeout === null) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
clearTimeout(this.seekEndTimeout);
|
|
231
|
+
this.seekEndTimeout = null;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
clearLongPressThresholdTimeout = () => {
|
|
235
|
+
if (this.longPressThresholdTimeout === null) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
clearTimeout(this.longPressThresholdTimeout);
|
|
240
|
+
this.longPressThresholdTimeout = null;
|
|
241
|
+
};
|
|
144
242
|
|
|
145
|
-
/**
|
|
146
|
-
* Reset *all* relevant state and strategy controllers
|
|
147
|
-
*/
|
|
148
243
|
resetAll() {
|
|
149
244
|
log_debug("TVSeekController: Reset all states");
|
|
150
245
|
this.currentSeekType = null;
|
|
151
|
-
this.delayedSeekOffset = null;
|
|
152
246
|
|
|
153
|
-
this.
|
|
247
|
+
this.delayedSeekPosition = null;
|
|
248
|
+
this.isPlayerInitiallyPaused = null;
|
|
249
|
+
|
|
250
|
+
this.clearSeekCompleteTimeout();
|
|
251
|
+
this.clearLongPressThresholdTimeout();
|
|
154
252
|
|
|
155
253
|
this.tapSeekController.reset();
|
|
156
254
|
this.longPressSeekController.reset();
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
private getPlayer() {
|
|
160
|
-
const player = playerManager.getInstanceController();
|
|
161
|
-
|
|
162
|
-
if (!player) {
|
|
163
|
-
log_warning("TVSeekController: No valid player controller found");
|
|
164
|
-
}
|
|
165
255
|
|
|
166
|
-
|
|
256
|
+
this.setStrategy(SEEK_STRATEGY.TAP_SEEK);
|
|
167
257
|
}
|
|
168
258
|
}
|
|
@@ -1,73 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import {
|
|
2
|
+
ISeekController,
|
|
3
|
+
ISeekControllerDelegate,
|
|
4
|
+
SeekIncrementalBaseStrategy,
|
|
5
|
+
} from "./ISeekController";
|
|
6
|
+
import { SEEK_TYPE } from "../const";
|
|
7
|
+
import { log_debug } from "./TVSeekController";
|
|
8
|
+
|
|
9
|
+
interface TapPressConfig {
|
|
10
|
+
CLICKS_BEFORE_PAUSE: number;
|
|
11
|
+
}
|
|
7
12
|
|
|
8
13
|
export class TapSeekController implements ISeekController {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
onPressStart(seekType: SEEK_TYPE) {
|
|
16
|
-
log_debug(`TapSeekController: start tap seek type: ${seekType}.`);
|
|
14
|
+
readonly title = "TapSeek";
|
|
15
|
+
constructor(
|
|
16
|
+
private seekControllerDelegate: ISeekControllerDelegate,
|
|
17
|
+
private seekIncrementalStrategy: SeekIncrementalBaseStrategy,
|
|
18
|
+
private config: TapPressConfig
|
|
19
|
+
) {}
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
onStartSeek = (seekType: SEEK_TYPE) => {
|
|
22
|
+
log_debug(`${this.title}: start tap seek type: ${seekType}.`);
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
this.parent.currentSeekType = seekType;
|
|
25
|
-
|
|
26
|
-
if (this.tapSequenceTimeout) {
|
|
27
|
-
clearTimeout(this.tapSequenceTimeout);
|
|
28
|
-
this.tapSequenceTimeout = null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
this.tapSequenceTimeout = setTimeout(() => {
|
|
32
|
-
if (this.parent.delayedSeekOffset !== null) {
|
|
33
|
-
this.parent.seekPlayer(this.parent.delayedSeekOffset);
|
|
34
|
-
}
|
|
24
|
+
const skipTime = this.seekIncrementalStrategy.getSkipTime();
|
|
25
|
+
const seekMultiplier = this.seekIncrementalStrategy.getSkipMultiplier();
|
|
35
26
|
|
|
27
|
+
if (seekMultiplier > this.config.CLICKS_BEFORE_PAUSE) {
|
|
36
28
|
log_debug(
|
|
37
|
-
|
|
29
|
+
`${this.title}: handle delayed seek type:${seekType} - skipTime: ${skipTime}, seekMultiplier: ${seekMultiplier}.`
|
|
38
30
|
);
|
|
39
31
|
|
|
40
|
-
this.
|
|
41
|
-
}, this.ON_PRESS_RESET_DURATION);
|
|
42
|
-
|
|
43
|
-
const clicksBeforePause = 3;
|
|
44
|
-
const skipTime = getSkipTime(this.seekMultiplier);
|
|
45
|
-
|
|
46
|
-
if (this.seekMultiplier > clicksBeforePause) {
|
|
47
|
-
log_debug(
|
|
48
|
-
`TapSeekController: handle delayed seek type:${seekType} - skipTime: ${skipTime}.`
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
this.parent.handleDelayedSeek(seekType, skipTime);
|
|
32
|
+
this.seekControllerDelegate.handleDelayedSeek(skipTime);
|
|
52
33
|
} else {
|
|
53
34
|
log_debug(
|
|
54
|
-
|
|
35
|
+
`${this.title}: handle seek type:${seekType} - skipTime: ${skipTime}.`
|
|
55
36
|
);
|
|
56
37
|
|
|
57
|
-
this.
|
|
38
|
+
this.seekControllerDelegate.handleSeek(skipTime);
|
|
58
39
|
}
|
|
59
40
|
|
|
60
|
-
this.
|
|
61
|
-
}
|
|
41
|
+
this.seekIncrementalStrategy.increment();
|
|
42
|
+
};
|
|
62
43
|
|
|
63
|
-
|
|
64
|
-
|
|
44
|
+
onSeekEnd = () => {
|
|
45
|
+
this.seekControllerDelegate.handleSeekComplete();
|
|
46
|
+
};
|
|
65
47
|
|
|
66
|
-
|
|
48
|
+
reset = () => {
|
|
49
|
+
log_debug("{this.title}: Reset states");
|
|
67
50
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.tapSequenceTimeout = null;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
51
|
+
this.seekIncrementalStrategy.reset();
|
|
52
|
+
};
|
|
73
53
|
}
|