mirror of
https://github.com/Boof2015/astra-mobile.git
synced 2026-08-19 12:14:47 +02:00
better seek bar
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
export const SCRUB_DETENT_SPACING_DP = 16;
|
||||
export const SCRUB_TICK_MIN_INTERVAL_MS = 90;
|
||||
export const SCRUB_TICK_ACTIVATION_DISTANCE_DP = 6;
|
||||
|
||||
export interface ScrubDetentState {
|
||||
detentIndex: number;
|
||||
lastTickAtMs: number | null;
|
||||
startPositionDp: number;
|
||||
activated: boolean;
|
||||
}
|
||||
|
||||
export interface ScrubDetentUpdate {
|
||||
state: ScrubDetentState;
|
||||
shouldTick: boolean;
|
||||
}
|
||||
|
||||
function clampPosition(positionDp: number, widthDp: number): number {
|
||||
if (!Number.isFinite(positionDp) || !Number.isFinite(widthDp) || widthDp <= 0) return 0;
|
||||
return Math.min(widthDp, Math.max(0, positionDp));
|
||||
}
|
||||
|
||||
function detentIndex(positionDp: number, widthDp: number): number {
|
||||
return Math.floor(clampPosition(positionDp, widthDp) / SCRUB_DETENT_SPACING_DP);
|
||||
}
|
||||
|
||||
/** Begin silently at the detent under the initial touch. */
|
||||
export function beginScrubDetents(positionDp: number, widthDp: number): ScrubDetentState {
|
||||
const startPositionDp = clampPosition(positionDp, widthDp);
|
||||
return {
|
||||
detentIndex: detentIndex(startPositionDp, widthDp),
|
||||
lastTickAtMs: null,
|
||||
startPositionDp,
|
||||
activated: false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance to the detent under the finger. The index always advances even when
|
||||
* rate-limited, so skipped ticks never catch up after movement stops.
|
||||
*/
|
||||
export function updateScrubDetents(
|
||||
state: ScrubDetentState,
|
||||
positionDp: number,
|
||||
widthDp: number,
|
||||
nowMs: number
|
||||
): ScrubDetentUpdate {
|
||||
const nextPositionDp = clampPosition(positionDp, widthDp);
|
||||
const nextIndex = detentIndex(nextPositionDp, widthDp);
|
||||
const activated =
|
||||
state.activated ||
|
||||
Math.abs(nextPositionDp - state.startPositionDp) >= SCRUB_TICK_ACTIVATION_DISTANCE_DP;
|
||||
if (!activated || nextIndex === state.detentIndex) {
|
||||
return {
|
||||
state: { ...state, detentIndex: nextIndex, activated },
|
||||
shouldTick: false,
|
||||
};
|
||||
}
|
||||
|
||||
const canTick =
|
||||
state.lastTickAtMs == null ||
|
||||
nowMs - state.lastTickAtMs >= SCRUB_TICK_MIN_INTERVAL_MS;
|
||||
|
||||
return {
|
||||
state: {
|
||||
detentIndex: nextIndex,
|
||||
lastTickAtMs: canTick ? nowMs : state.lastTickAtMs,
|
||||
startPositionDp: state.startPositionDp,
|
||||
activated,
|
||||
},
|
||||
shouldTick: canTick,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user