openreplay/frontend/app/player/player/Player.ts
Delirium 2cd96b0df0
Highlight UI (#2951)
* ui: start highlight ui

* ui: tag items

* ui: connecting highlights to notes api...

* Highlight feature refinements (#2948)

* ui: move clips player to foss, connect notes api to hl

* ui: tune note/hl editing, prevent zoom slider body from jumping around

* ui: safe check for tag

* ui: fix thumbnail gen

* ui: fix thumbnail gen

* ui: make player modal wider, add shadow

* ui: custom warn barge for clips

* ui: swap icon for note event wrapper

* ui: rm other, fix cancel

* ui: moving around creation modal

* ui: bg tint

* ui: rm disabled for text btn

* ui: fix ownership sorting

* ui: close player on bg click

* ui: fix query, fix min distance for default range

* ui: move hl list header out of list comp

* ui: spot list header segmented size

* Various improvements in highlights (#2955)

* ui: update hl in hlPanel comp

* ui: rm debug

* ui: fix icons file

---------

Co-authored-by: Sudheer Salavadi <connect.uxmaster@gmail.com>
2025-01-24 09:59:54 +01:00

120 lines
3.6 KiB
TypeScript

import * as typedLocalStorage from './localStorage';
import type { Store } from '../common/types';
import Animator, { IMessageManager } from './Animator';
import type { GetState as AnimatorGetState } from './Animator';
export const SPEED_OPTIONS = [0.5, 1, 2, 4, 8, 16]
import type { Message } from "Player/web/messages";
/* == separate this == */
const HIGHEST_SPEED = 16
const SPEED_STORAGE_KEY = "__$player-speed$__"
const SKIP_STORAGE_KEY = "__$player-skip$__"
const SKIP_TO_ISSUE_STORAGE_KEY = "__$session-skipToIssue$__"
const AUTOPLAY_STORAGE_KEY = "__$player-autoplay$__"
const SHOW_EVENTS_STORAGE_KEY = "__$player-show-events$__"
const storedSpeed: number = typedLocalStorage.number(SPEED_STORAGE_KEY)
const initialSpeed = SPEED_OPTIONS.includes(storedSpeed) ? storedSpeed : 1
const initialSkip = typedLocalStorage.boolean(SKIP_STORAGE_KEY)
const initialSkipToIssue = typedLocalStorage.boolean(SKIP_TO_ISSUE_STORAGE_KEY)
const initialAutoplay = typedLocalStorage.boolean(AUTOPLAY_STORAGE_KEY)
const initialShowEvents = typedLocalStorage.boolean(SHOW_EVENTS_STORAGE_KEY)
export type State = typeof Player.INITIAL_STATE
/* == */
export default class Player extends Animator {
static INITIAL_STATE = {
...Animator.INITIAL_STATE,
skipToIssue: initialSkipToIssue,
showEvents: initialShowEvents,
autoplay: initialAutoplay,
skip: initialSkip,
speed: initialSpeed,
range: [0, 0] as [number, number],
} as const
constructor(private pState: Store<State & AnimatorGetState>, private manager: IMessageManager) {
super(pState, manager)
// Autoplay
if (pState.get().autoplay) {
let autoPlay = true;
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
const { playing } = pState.get();
autoPlay = playing
if (playing) {
this.pause();
}
} else if (autoPlay) {
this.play();
}
})
if (!document.hidden) {
this.play();
}
}
}
/* === TODO: incapsulate in LSCache === */
toggleAutoplay() {
const autoplay = !this.pState.get().autoplay
localStorage.setItem(AUTOPLAY_STORAGE_KEY, `${autoplay}`);
this.pState.update({ autoplay })
}
//TODO: move to react part (with localStorage-cache react hook)?
toggleEvents() {
const showEvents = !this.pState.get().showEvents
localStorage.setItem(SHOW_EVENTS_STORAGE_KEY, `${showEvents}`);
this.pState.update({ showEvents })
}
// TODO: move to React part
toggleSkipToIssue() {
const skipToIssue = !this.pState.get().skipToIssue
localStorage.setItem(SKIP_TO_ISSUE_STORAGE_KEY, `${skipToIssue}`);
this.pState.update({ skipToIssue })
}
toggleSkip() {
const skip = !this.pState.get().skip
localStorage.setItem(SKIP_STORAGE_KEY, `${skip}`);
this.pState.update({ skip })
}
private updateSpeed(speed: number) {
localStorage.setItem(SPEED_STORAGE_KEY, `${speed}`);
this.pState.update({ speed })
}
toggleSpeed(index: number | null) {
const { speed } = this.pState.get();
const newSpeedIndex = index === null ? null : Math.max(0, Math.min(SPEED_OPTIONS.length - 1, index));
this.updateSpeed(newSpeedIndex === null ? speed * 2 : SPEED_OPTIONS[newSpeedIndex]);
}
speedUp() {
const { speed } = this.pState.get()
this.updateSpeed(Math.min(HIGHEST_SPEED, speed * 2))
}
speedDown() {
const { speed } = this.pState.get()
this.updateSpeed(Math.max(1, speed / 2))
}
// toggle range (start, end)
toggleRange(start: number, end: number) {
this.pState.update({ range: [start, end] })
}
clean() {
this.pause()
this.manager.clean()
}
}