213 lines
7.0 KiB
TypeScript
213 lines
7.0 KiB
TypeScript
import {
|
|
extendNumber,
|
|
LifecycleAwareDependComponent,
|
|
MutableEvent,
|
|
MutableObserver,
|
|
MutableState,
|
|
PLVMediaPlayerOnInfoEvent,
|
|
runCatching
|
|
} from '@polyvharmony/media-player-sdk';
|
|
import {
|
|
PLVMPMediaControllerFloatAction,
|
|
PLVMPMediaControllerViewState,
|
|
PLVMPVideoViewLocation
|
|
} from './viewstate/PLVMPMediaControllerViewState';
|
|
import {PLVBrightnessManager} from "../../../utils/PLVBrightnessManager";
|
|
import {PLVMPMediaControllerUseCases} from "./usecase/PLVMPMediaControllerUseCases";
|
|
import {PLVMPMediaControllerRepo} from "../model/PLVMPMediaControllerRepo";
|
|
|
|
export class PLVMPMediaControllerViewModel implements LifecycleAwareDependComponent {
|
|
|
|
private readonly repo: PLVMPMediaControllerRepo
|
|
private readonly useCases: PLVMPMediaControllerUseCases
|
|
|
|
readonly mediaControllerViewState: MutableState<PLVMPMediaControllerViewState>
|
|
// 亮度更新事件,范围 0.0 ~ 1.0
|
|
readonly brightnessUpdateEvent: MutableEvent<number>
|
|
// 音量更新事件,范围 0 ~ 100
|
|
readonly volumeUpdateEvent: MutableEvent<number>
|
|
|
|
private observers: MutableObserver[] = []
|
|
|
|
constructor(
|
|
repo: PLVMPMediaControllerRepo,
|
|
useCases: PLVMPMediaControllerUseCases
|
|
) {
|
|
this.repo = repo
|
|
this.useCases = useCases
|
|
this.mediaControllerViewState = this.repo.mediator.mediaControllerViewState
|
|
this.brightnessUpdateEvent = this.repo.mediator.brightnessUpdateEvent
|
|
this.volumeUpdateEvent = this.repo.mediator.volumeUpdateEvent
|
|
|
|
this.observeSeekFinishEvent()
|
|
this.observeMediaStopState()
|
|
}
|
|
|
|
handleDragSlider(event: 'slide' | 'slideFinish' | 'click', progress: number) {
|
|
switch (event) {
|
|
case "slide":
|
|
this.mediaControllerViewState.mutate({
|
|
progressSliderDragging: true,
|
|
progressSliderWaitSeekFinish: true,
|
|
progressSliderDragPosition: progress
|
|
})
|
|
break;
|
|
case "slideFinish":
|
|
if (this.mediaControllerViewState.value?.progressSliderDragging) {
|
|
this.repo.mediaMediator.seekTo?.apply(null, [this.mediaControllerViewState.value?.progressSliderDragPosition ?? 0])
|
|
}
|
|
this.mediaControllerViewState.mutate({
|
|
progressSliderDragging: false,
|
|
progressSliderDragPosition: 0
|
|
})
|
|
break;
|
|
case "click":
|
|
this.repo.mediaMediator.seekTo?.apply(null, [progress])
|
|
this.mediaControllerViewState.mutate({
|
|
progressSliderWaitSeekFinish: true
|
|
})
|
|
break;
|
|
}
|
|
}
|
|
|
|
handleDragGestureSeek(event: 'update' | 'end', progress: number) {
|
|
switch (event) {
|
|
case "update":
|
|
this.handleDragSlider('slide', progress)
|
|
break;
|
|
case "end":
|
|
this.handleDragSlider('slideFinish', progress)
|
|
break;
|
|
}
|
|
}
|
|
|
|
changeControllerVisible(toVisible?: boolean) {
|
|
const currentVisible = this.mediaControllerViewState.value?.controllerVisible ?? false
|
|
this.mediaControllerViewState.mutate({
|
|
controllerVisible: toVisible ?? !currentVisible
|
|
})
|
|
}
|
|
|
|
handleLongPressSpeeding(event: 'start' | 'end') {
|
|
switch (event) {
|
|
case "start":
|
|
if (!this.repo.mediaMediator.isPlaying?.apply(null)) {
|
|
break;
|
|
}
|
|
this.mediaControllerViewState.mutate({
|
|
longPressSpeeding: true,
|
|
speedBeforeLongPress: this.repo.mediaMediator.getSpeed?.apply(null)
|
|
})
|
|
this.repo.mediaMediator.setSpeed?.apply(null, [2])
|
|
break;
|
|
case "end":
|
|
if (!this.mediaControllerViewState.value?.longPressSpeeding) {
|
|
break;
|
|
}
|
|
this.repo.mediaMediator.setSpeed?.apply(null, [this.mediaControllerViewState.value?.speedBeforeLongPress ?? 1])
|
|
this.mediaControllerViewState.mutate({
|
|
longPressSpeeding: false,
|
|
speedBeforeLongPress: 1
|
|
})
|
|
break;
|
|
}
|
|
}
|
|
|
|
async changeBrightness(direction: 'up' | 'down') {
|
|
const currentBrightnessResult = await runCatching(PLVBrightnessManager.getInstance().getBrightness())
|
|
if (!currentBrightnessResult.success || currentBrightnessResult.data === undefined) {
|
|
return
|
|
}
|
|
const currentBrightness = currentBrightnessResult.data < 0 ? 0.5 : currentBrightnessResult.data
|
|
let nextBrightness = direction === 'up' ? currentBrightness + 0.1 : currentBrightness - 0.1
|
|
nextBrightness = extendNumber(nextBrightness).coerceIn_ext(0, 1)
|
|
const updateResult = await runCatching(PLVBrightnessManager.getInstance().setBrightness(nextBrightness))
|
|
if (updateResult.success) {
|
|
this.brightnessUpdateEvent.value = nextBrightness
|
|
}
|
|
}
|
|
|
|
changeVolume(direction: 'up' | 'down') {
|
|
const currentVolume = this.repo.mediaMediator.getVolume?.apply(null)
|
|
if (currentVolume === undefined) {
|
|
return
|
|
}
|
|
let nextVolume = direction === 'up' ? currentVolume + 10 : currentVolume - 10
|
|
nextVolume = extendNumber(nextVolume).coerceIn_ext(0, 100)
|
|
this.repo.mediaMediator.setVolume?.apply(null, [nextVolume])
|
|
this.volumeUpdateEvent.value = nextVolume
|
|
}
|
|
|
|
lockMediaController(action: 'lock' | 'unlock') {
|
|
switch (action) {
|
|
case "lock":
|
|
this.mediaControllerViewState.mutate({
|
|
controllerLocking: true
|
|
})
|
|
break;
|
|
case "unlock":
|
|
this.mediaControllerViewState.mutate({
|
|
controllerLocking: false
|
|
})
|
|
break;
|
|
}
|
|
}
|
|
|
|
pushFloatActionLayout(layout: PLVMPMediaControllerFloatAction) {
|
|
this.mediaControllerViewState.mutate({
|
|
floatActionLayouts: [...this.mediaControllerViewState.value?.floatActionLayouts ?? [], layout]
|
|
})
|
|
}
|
|
|
|
popFloatActionLayout() {
|
|
const floatActionLayouts = this.mediaControllerViewState.value?.floatActionLayouts ?? []
|
|
if (floatActionLayouts.length === 0) {
|
|
return
|
|
}
|
|
floatActionLayouts.pop()
|
|
this.mediaControllerViewState.mutate({
|
|
floatActionLayouts: floatActionLayouts
|
|
})
|
|
}
|
|
|
|
updateVideoViewLocation(videoViewLocation: PLVMPVideoViewLocation) {
|
|
this.mediaControllerViewState.mutate({
|
|
videoViewLocation: videoViewLocation
|
|
})
|
|
}
|
|
|
|
private observeSeekFinishEvent() {
|
|
this.repo.mediaMediator.onInfoEvent?.observe((onInfo) => {
|
|
if (this.mediaControllerViewState.value?.progressSliderWaitSeekFinish
|
|
&& [PLVMediaPlayerOnInfoEvent.MEDIA_INFO_AUDIO_SEEK_RENDERING_START,
|
|
PLVMediaPlayerOnInfoEvent.MEDIA_INFO_VIDEO_SEEK_RENDERING_START,
|
|
PLVMediaPlayerOnInfoEvent.MEDIA_INFO_AUDIO_RENDERING_START,
|
|
PLVMediaPlayerOnInfoEvent.MEDIA_INFO_VIDEO_RENDERING_START
|
|
].includes(onInfo.what)) {
|
|
this.mediaControllerViewState.mutate({
|
|
progressSliderWaitSeekFinish: false
|
|
})
|
|
}
|
|
}).pushTo(this.observers)
|
|
}
|
|
|
|
private observeMediaStopState() {
|
|
this.repo.mediator.businessErrorState.observe((error) => {
|
|
this.mediaControllerViewState.mutate({
|
|
errorOverlayLayoutVisible: error !== null
|
|
})
|
|
}).pushTo(this.observers)
|
|
|
|
this.repo.mediator.playCompleteState.observe((complete) => {
|
|
this.mediaControllerViewState.mutate({
|
|
completeOverlayLayoutVisible: complete
|
|
})
|
|
}).pushTo(this.observers)
|
|
}
|
|
|
|
onDestroy() {
|
|
MutableObserver.disposeAll(this.observers)
|
|
this.observers = []
|
|
}
|
|
|
|
} |