|
|
@@ -8,102 +8,125 @@
|
|
|
:poster="series?.cover"
|
|
|
:controls="false"
|
|
|
class="object-contain w-full h-full"
|
|
|
- @timeupdate="onTimeUpdate"
|
|
|
- @play="() => (userPaused = false)"
|
|
|
- @pause="() => (userPaused = true)"
|
|
|
+ @play="onVideoDidPlay"
|
|
|
+ @pause="onVideoDidPause"
|
|
|
+ @click="exitImmersive"
|
|
|
+ @ended="emit('ended')"
|
|
|
></video>
|
|
|
<img
|
|
|
v-show="!playUrl && series"
|
|
|
:src="series?.cover"
|
|
|
class="object-contain w-full h-full"
|
|
|
/>
|
|
|
-
|
|
|
- <div
|
|
|
- v-show="!draggingData.dragging"
|
|
|
- class="mask-info absolute w-full h-full top-0 left-0"
|
|
|
- >
|
|
|
- <IonSpinner
|
|
|
- v-if="!series || !episode"
|
|
|
- name="crescent"
|
|
|
- class="absolute left-0 top-0 right-0 bottom-0 m-auto text-lg"
|
|
|
- />
|
|
|
- <IonIcon
|
|
|
- v-if="showPlayBtn"
|
|
|
- :icon="playCircle"
|
|
|
- class="absolute left-0 top-0 right-0 bottom-0 m-auto text-6xl opacity-80"
|
|
|
- @click="onPlay"
|
|
|
- />
|
|
|
- <IonIcon
|
|
|
- v-if="showPauseBtn"
|
|
|
- :icon="pauseCircle"
|
|
|
- class="absolute left-0 top-0 right-0 bottom-0 m-auto text-6xl opacity-80"
|
|
|
- />
|
|
|
- <div class="tool-bar flex">
|
|
|
- <div class="px-2 flex items-center" @click="router.back()">
|
|
|
+ <Transition name="fade">
|
|
|
+ <div
|
|
|
+ v-show="!hideControls"
|
|
|
+ class="mask-info absolute w-full h-full top-0 left-0"
|
|
|
+ @click="enterImmersive"
|
|
|
+ >
|
|
|
+ <IonSpinner
|
|
|
+ v-if="!series || !episode"
|
|
|
+ name="crescent"
|
|
|
+ class="absolute left-0 top-0 right-0 bottom-0 m-auto text-lg"
|
|
|
+ />
|
|
|
+ <template v-if="!loading">
|
|
|
<IonIcon
|
|
|
- :icon="chevronBack"
|
|
|
- class="text-2xl opacity-80 h-10"
|
|
|
+ v-if="showPlayBtn"
|
|
|
+ :icon="playCircle"
|
|
|
+ class="absolute left-0 top-0 right-0 bottom-0 m-auto text-7xl opacity-60"
|
|
|
+ @click.stop="onPlay"
|
|
|
/>
|
|
|
- </div>
|
|
|
- <div class="flex-1"></div>
|
|
|
- <div class="px-4 flex items-center">
|
|
|
<IonIcon
|
|
|
- :icon="ellipsisHorizontal"
|
|
|
- class="text-2xl opacity-80 h-10"
|
|
|
+ v-else
|
|
|
+ :icon="pauseCircle"
|
|
|
+ class="absolute left-0 top-0 right-0 bottom-0 m-auto text-7xl opacity-60"
|
|
|
+ @click.stop="playing = false"
|
|
|
/>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- class="title-info absolute bottom-0 left-0 right-0 drop-shadow px-4"
|
|
|
- v-show="series"
|
|
|
- >
|
|
|
- <div class="pr-20">
|
|
|
- <div class="text-base line-clamp-1">
|
|
|
- {{ series?.title }}
|
|
|
+ </template>
|
|
|
+ <div class="tool-bar flex">
|
|
|
+ <div class="px-2 flex items-center" @click="router.back()">
|
|
|
+ <IonIcon
|
|
|
+ :icon="chevronBack"
|
|
|
+ class="text-2xl opacity-80 h-10"
|
|
|
+ />
|
|
|
</div>
|
|
|
- <div class="text-sm text-opacity-80 text-white">
|
|
|
- Episode {{ episode?.episodeNum }}
|
|
|
+ <div class="flex-1"></div>
|
|
|
+ <div class="px-4 flex items-center">
|
|
|
+ <IonIcon
|
|
|
+ :icon="ellipsisHorizontal"
|
|
|
+ class="text-2xl opacity-80 h-10"
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div ref="dragTarget" class="py-3">
|
|
|
+ <div
|
|
|
+ class="title-info absolute bottom-0 left-0 right-0 drop-shadow px-4"
|
|
|
+ v-show="series"
|
|
|
+ >
|
|
|
+ <div class="pr-20">
|
|
|
+ <div class="text-base line-clamp-1">
|
|
|
+ {{ series?.title }}
|
|
|
+ </div>
|
|
|
+ <div class="text-sm text-opacity-80 text-white">
|
|
|
+ Episode {{ episode?.episodeNum }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div ref="dragTarget" class="py-3">
|
|
|
+ <div
|
|
|
+ class="progress-bar h-[2px] bg-white bg-opacity-20 rounded"
|
|
|
+ ref="progressBar"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ v-if="loading"
|
|
|
+ class="loading bg-white h-[2px] rounded bg-opacity-80"
|
|
|
+ ></div>
|
|
|
+ <div
|
|
|
+ v-else
|
|
|
+ class="progress bg-white h-[2px] rounded bg-opacity-80"
|
|
|
+ :style="{ width: progress + '%' }"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
<div
|
|
|
- class="progress-bar h-[2px] bg-white bg-opacity-20 rounded"
|
|
|
- ref="progressBar"
|
|
|
+ class="dive-into h-[44px] flex items-center text-xs bg-opacity-20 bg-black px-4 rounded"
|
|
|
+ @click.stop="showEpisodesModal = true"
|
|
|
>
|
|
|
- <div
|
|
|
- v-if="loading"
|
|
|
- class="loading bg-white h-[2px] rounded bg-opacity-80"
|
|
|
- ></div>
|
|
|
- <div
|
|
|
- v-else
|
|
|
- class="progress bg-white h-[2px] rounded bg-opacity-80"
|
|
|
- :style="{ width: progress + '%' }"
|
|
|
- ></div>
|
|
|
+ <IonIcon :icon="filter" class="text-base" />
|
|
|
+ <div class="flex-1 ml-2 text-white text-opacity-80">
|
|
|
+ {{ series?.totalEpisodes }} Episodes
|
|
|
+ </div>
|
|
|
+ <IonIcon :icon="chevronForward" class="text-base" />
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
<div
|
|
|
- class="dive-into h-[44px] flex items-center text-xs bg-opacity-20 bg-black px-4 rounded"
|
|
|
- @click.stop="showEpisodesModal = true"
|
|
|
+ class="absolute right-4 bottom-32 flex flex-col"
|
|
|
+ v-if="series"
|
|
|
>
|
|
|
- <IonIcon :icon="filter" class="text-base" />
|
|
|
- <div class="flex-1 ml-2 text-white text-opacity-80">
|
|
|
- {{ series?.totalEpisodes }} Episodes
|
|
|
+ <div
|
|
|
+ class="btn flex flex-col items-center justify-center"
|
|
|
+ @click.stop="emit('save')"
|
|
|
+ >
|
|
|
+ <IonIcon
|
|
|
+ :class="{ 'text-prim': saved }"
|
|
|
+ :icon="bookmark"
|
|
|
+ class="text-4xl opacity-80"
|
|
|
+ />
|
|
|
+ <div class="text-xs">
|
|
|
+ {{ saved ? "Saved" : "Save" }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="btn flex flex-col items-center justify-center mt-4"
|
|
|
+ >
|
|
|
+ <IonIcon
|
|
|
+ :icon="arrowRedo"
|
|
|
+ class="text-4xl opacity-80"
|
|
|
+ />
|
|
|
+ <div class="text-xs">Share</div>
|
|
|
</div>
|
|
|
- <IonIcon :icon="chevronForward" class="text-base" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="absolute right-4 bottom-32 flex flex-col" v-if="series">
|
|
|
- <div class="btn flex flex-col items-center justify-center">
|
|
|
- <IonIcon :icon="bookmark" class="text-4xl opacity-80" />
|
|
|
- <div class="text-xs">Save</div>
|
|
|
- </div>
|
|
|
- <div class="btn flex flex-col items-center justify-center mt-4">
|
|
|
- <IonIcon :icon="arrowRedo" class="text-4xl opacity-80" />
|
|
|
- <div class="text-xs">Share</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </Transition>
|
|
|
<div
|
|
|
class="absolute left-4 right-4 bottom-24 shadow"
|
|
|
v-if="draggingData.dragging"
|
|
|
@@ -114,11 +137,15 @@
|
|
|
<span
|
|
|
class="inline-block text-center w-16 text-white text-opacity-90"
|
|
|
>
|
|
|
- {{ toDuration }}
|
|
|
+ {{
|
|
|
+ formatDuration(
|
|
|
+ (duration * draggingData.toProgress) / 100
|
|
|
+ )
|
|
|
+ }}
|
|
|
</span>
|
|
|
/
|
|
|
<span class="inline-block text-center w-16">
|
|
|
- {{ formatDuration(draggingData.videoDuration) }}
|
|
|
+ {{ formatDuration(duration) }}
|
|
|
</span>
|
|
|
</div>
|
|
|
<div class="progress-bar-large h-2 bg-white bg-opacity-20 rounded">
|
|
|
@@ -128,111 +155,114 @@
|
|
|
></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <ion-modal
|
|
|
- ref="modal"
|
|
|
- class="episodes-modal"
|
|
|
- :is-open="showEpisodesModal"
|
|
|
- :initial-breakpoint="1"
|
|
|
- :breakpoints="[0, 1]"
|
|
|
- @ionModalDidDismiss="showEpisodesModal = false"
|
|
|
- >
|
|
|
- <ion-content>
|
|
|
- <div class="flex flex-col h-full">
|
|
|
- <div class="text-lg mt-4 mx-4">{{ series?.title }}</div>
|
|
|
- <div class="text-sm mt-1 mx-4 text-white text-opacity-80">
|
|
|
- {{ series?.totalEpisodes }} Episodes
|
|
|
- </div>
|
|
|
- <div class="flex-1 flex flex-wrap overflow-auto mt-4 ml-4 mr-1">
|
|
|
+ <ion-modal
|
|
|
+ ref="modal"
|
|
|
+ class="episodes-modal"
|
|
|
+ :is-open="showEpisodesModal"
|
|
|
+ :initial-breakpoint="1"
|
|
|
+ :breakpoints="[0, 1]"
|
|
|
+ @ionModalDidDismiss="showEpisodesModal = false"
|
|
|
+ >
|
|
|
+ <ion-content>
|
|
|
+ <div class="flex flex-col h-full">
|
|
|
+ <div class="text-lg mt-4 mx-4">{{ series?.title }}</div>
|
|
|
+ <div class="text-sm mt-1 mx-4 text-white text-opacity-80">
|
|
|
+ {{ series?.totalEpisodes }} Episodes
|
|
|
+ </div>
|
|
|
<div
|
|
|
- class="pr-3 w-1/4 mb-3"
|
|
|
- v-for="(item, n) in episodes || []"
|
|
|
- :key="item.id"
|
|
|
- @click="chooseEpisode(n)"
|
|
|
+ class="flex-1 flex flex-wrap overflow-auto mt-4 ml-4 mr-1"
|
|
|
>
|
|
|
<div
|
|
|
- class="episode-btn h-10 bg-neutral-800 rounded flex items-center justify-center relative"
|
|
|
- :class="{ active: item.id === episode?.id }"
|
|
|
+ class="pr-3 w-1/4 mb-3"
|
|
|
+ v-for="(item, n) in episodes || []"
|
|
|
+ :key="item.id"
|
|
|
+ @click="chooseEpisode(n)"
|
|
|
>
|
|
|
- <IonIcon
|
|
|
- v-if="parseInt(item.price) > 0"
|
|
|
- :icon="lockClosed"
|
|
|
- class="absolute top-1 right-1 text-sm"
|
|
|
- />
|
|
|
- {{ item.episodeNum }}
|
|
|
+ <div
|
|
|
+ class="episode-btn h-10 bg-neutral-800 rounded flex items-center justify-center relative"
|
|
|
+ :class="{ active: item.id === episode?.id }"
|
|
|
+ >
|
|
|
+ <IonIcon
|
|
|
+ v-if="parseInt(item.price) > 0"
|
|
|
+ :icon="lockClosed"
|
|
|
+ class="absolute top-1 right-1 text-sm"
|
|
|
+ />
|
|
|
+ {{ item.episodeNum }}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </ion-content>
|
|
|
- </ion-modal>
|
|
|
+ </ion-content>
|
|
|
+ </ion-modal>
|
|
|
|
|
|
- <ion-modal
|
|
|
- ref="modal"
|
|
|
- class="pay-modal"
|
|
|
- :is-open="showPayModal"
|
|
|
- :initial-breakpoint="1"
|
|
|
- :breakpoints="[0, 1]"
|
|
|
- @ionModalDidDismiss="showPayModal = false"
|
|
|
- >
|
|
|
- <ion-content>
|
|
|
- <div class="divide-y divide-neutral-600 text-white">
|
|
|
- <div class="mb-6">
|
|
|
- <div
|
|
|
- class="mt-6 text-center text-sm text-prim text-opacity-80"
|
|
|
- >
|
|
|
- You haven't unlocked this episode yet
|
|
|
- </div>
|
|
|
- <div class="text-center text-xl mt-2 font-bold">
|
|
|
- Join the Membership
|
|
|
- </div>
|
|
|
- <div class="text-center text-sm mt-1 px-4">
|
|
|
- unlock and watch all our videos without any limit
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="flex space-x-4 pt-6 px-4">
|
|
|
- <div
|
|
|
- v-for="(item, n) in plans"
|
|
|
- :key="n"
|
|
|
- class="h-44 bg-neutral-700 flex-1 rounded-lg flex flex-col items-center border-neutral-500 border-2 overflow-hidden relative"
|
|
|
- :class="{ '!border-prim': selectedPlan === n }"
|
|
|
- @click="selectedPlan = n"
|
|
|
- >
|
|
|
+ <ion-modal
|
|
|
+ ref="modal"
|
|
|
+ class="pay-modal"
|
|
|
+ :is-open="showPayModal"
|
|
|
+ :initial-breakpoint="1"
|
|
|
+ :breakpoints="[0, 1]"
|
|
|
+ @ionModalDidDismiss="showPayModal = false"
|
|
|
+ >
|
|
|
+ <ion-content>
|
|
|
+ <div class="divide-y divide-neutral-600 text-white">
|
|
|
+ <div class="mb-6">
|
|
|
<div
|
|
|
- class="absolute top-0 left-0 bg-prim rounded-br-lg text-xs px-2 py-1"
|
|
|
- v-if="n === 0"
|
|
|
+ class="mt-6 text-center text-sm text-prim text-opacity-80"
|
|
|
>
|
|
|
- Exclusive
|
|
|
+ You haven't unlocked this episode yet
|
|
|
</div>
|
|
|
- <div class="mt-8 text-xl font-bold flex-1">
|
|
|
- {{ item.title }}
|
|
|
+ <div class="text-center text-xl mt-2 font-bold">
|
|
|
+ Join the Membership
|
|
|
</div>
|
|
|
- <div class="flex-1">
|
|
|
- <div
|
|
|
- class="bg-prim bg-opacity-30 rounded-full px-3 py-1 text-opacity-50 text-sm"
|
|
|
- >
|
|
|
- {{ item.desc }}
|
|
|
- </div>
|
|
|
+ <div class="text-center text-sm mt-1 px-4">
|
|
|
+ unlock and watch all our videos without any limit
|
|
|
</div>
|
|
|
+ </div>
|
|
|
+ <div class="flex space-x-4 pt-6 px-4">
|
|
|
<div
|
|
|
- class="h-8 bg-neutral-500 self-stretch text-base font-bold flex items-center justify-center"
|
|
|
- :class="{ 'bg-prim': selectedPlan === n }"
|
|
|
+ v-for="(item, n) in plans"
|
|
|
+ :key="n"
|
|
|
+ class="h-44 bg-neutral-700 flex-1 rounded-lg flex flex-col items-center border-neutral-500 border-2 overflow-hidden relative"
|
|
|
+ :class="{ '!border-prim': selectedPlan === n }"
|
|
|
+ @click="selectedPlan = n"
|
|
|
>
|
|
|
- <ion-label color=""> ${{ item.price }}</ion-label>
|
|
|
+ <div
|
|
|
+ class="absolute top-0 left-0 bg-prim rounded-br-lg text-xs px-2 py-1"
|
|
|
+ v-if="n === 0"
|
|
|
+ >
|
|
|
+ Exclusive
|
|
|
+ </div>
|
|
|
+ <div class="mt-8 text-xl font-bold flex-1">
|
|
|
+ {{ item.title }}
|
|
|
+ </div>
|
|
|
+ <div class="flex-1">
|
|
|
+ <div
|
|
|
+ class="bg-prim bg-opacity-30 rounded-full px-3 py-1 text-opacity-50 text-sm"
|
|
|
+ >
|
|
|
+ {{ item.desc }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="h-8 bg-neutral-500 self-stretch text-base font-bold flex items-center justify-center"
|
|
|
+ :class="{ 'bg-prim': selectedPlan === n }"
|
|
|
+ >
|
|
|
+ <ion-label color="">
|
|
|
+ ${{ item.price }}
|
|
|
+ </ion-label>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <IonButton
|
|
|
- color="tertiary"
|
|
|
- expand="block"
|
|
|
- class="mx-4 mt-8 font-bold"
|
|
|
- >
|
|
|
- ${{ plans[selectedPlan].price }} Pay Now
|
|
|
- </IonButton>
|
|
|
- </ion-content>
|
|
|
- </ion-modal>
|
|
|
+ <IonButton
|
|
|
+ color="tertiary"
|
|
|
+ expand="block"
|
|
|
+ class="mx-4 mt-8 font-bold"
|
|
|
+ >
|
|
|
+ ${{ plans[selectedPlan].price }} Pay Now
|
|
|
+ </IonButton>
|
|
|
+ </ion-content>
|
|
|
+ </ion-modal>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
|
import { Ref, computed, nextTick, onMounted, reactive, ref, watch } from "vue";
|
|
|
@@ -259,20 +289,24 @@ import {
|
|
|
lockClosed,
|
|
|
} from "ionicons/icons";
|
|
|
import http from "@/plugins/http";
|
|
|
+import { watchThrottled } from "@vueuse/core";
|
|
|
|
|
|
const props = defineProps({
|
|
|
active: Boolean,
|
|
|
series: Object,
|
|
|
episode: Object,
|
|
|
episodes: Array<any>,
|
|
|
+ saved: Boolean,
|
|
|
});
|
|
|
-const emit = defineEmits(["chooseEpisode"]);
|
|
|
+const emit = defineEmits(["chooseEpisode", "save", "ended"]);
|
|
|
const router = useIonRouter();
|
|
|
const video: Ref<HTMLVideoElement | null> = ref(null);
|
|
|
const { playing, currentTime, duration, volume } = useMediaControls(video);
|
|
|
-const userPaused = ref(false);
|
|
|
const showPauseBtn = ref(false);
|
|
|
-const progress = ref(0);
|
|
|
+const progress = computed(() => {
|
|
|
+ if (isNaN(duration.value) || duration.value === 0) return 0;
|
|
|
+ return (currentTime.value / duration.value) * 100;
|
|
|
+});
|
|
|
const loading = ref(false);
|
|
|
const dragTarget = ref();
|
|
|
const progressBar: Ref<HTMLElement | null> = ref(null);
|
|
|
@@ -305,8 +339,21 @@ const plans = [
|
|
|
},
|
|
|
];
|
|
|
const selectedPlan = ref(0);
|
|
|
+const immersive = ref(false);
|
|
|
+
|
|
|
+const showPlayBtn = computed(() => {
|
|
|
+ if (!props.series || loading.value) return false;
|
|
|
+ if (!playUrl.value) return true;
|
|
|
+ if (!playing.value) return true;
|
|
|
+ return false;
|
|
|
+});
|
|
|
+
|
|
|
+const hideControls = computed(() => {
|
|
|
+ return draggingData.dragging || (playing.value && immersive.value);
|
|
|
+});
|
|
|
|
|
|
function formatDuration(duration: number) {
|
|
|
+ if (isNaN(duration)) return "00:00";
|
|
|
const minutes = Math.floor(duration / 60)
|
|
|
.toString()
|
|
|
.padStart(2, "0");
|
|
|
@@ -315,15 +362,11 @@ function formatDuration(duration: number) {
|
|
|
.padStart(2, "0");
|
|
|
return `${minutes}:${seconds}`;
|
|
|
}
|
|
|
-const toDuration = computed(() => {
|
|
|
- return formatDuration(
|
|
|
- Math.floor((draggingData.toProgress * draggingData.videoDuration) / 100)
|
|
|
- );
|
|
|
-});
|
|
|
+
|
|
|
const dragHandler = ({ movement: [x, y], dragging }: any) => {
|
|
|
if (dragging && !draggingData.dragging) {
|
|
|
draggingData.barWidth = useElementBounding(progressBar).width.value;
|
|
|
- draggingData.videoDuration = 100;
|
|
|
+ draggingData.videoDuration = duration.value;
|
|
|
draggingData.progress = progress.value;
|
|
|
draggingData.toProgress = progress.value;
|
|
|
draggingData.dragging = true;
|
|
|
@@ -338,16 +381,11 @@ const dragHandler = ({ movement: [x, y], dragging }: any) => {
|
|
|
);
|
|
|
if (!dragging) {
|
|
|
draggingData.dragging = false;
|
|
|
+ currentTime.value = (duration.value * draggingData.toProgress) / 100;
|
|
|
}
|
|
|
+ console.log(JSON.stringify(draggingData));
|
|
|
};
|
|
|
|
|
|
-function onTimeUpdate() {
|
|
|
- if (video.value) {
|
|
|
- progress.value =
|
|
|
- (video.value!.currentTime! / video.value!.duration!) * 100;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
function getEpisode() {
|
|
|
if (!props.episode) return;
|
|
|
loading.value = true;
|
|
|
@@ -369,12 +407,14 @@ function getEpisode() {
|
|
|
}
|
|
|
loading.value = false;
|
|
|
}
|
|
|
-
|
|
|
+useDrag(dragHandler, {
|
|
|
+ domTarget: dragTarget,
|
|
|
+ eventOptions: {
|
|
|
+ capture: true,
|
|
|
+ },
|
|
|
+});
|
|
|
onMounted(() => {
|
|
|
getEpisode();
|
|
|
- useDrag(dragHandler, {
|
|
|
- domTarget: dragTarget,
|
|
|
- });
|
|
|
});
|
|
|
watch(
|
|
|
() => props.episode,
|
|
|
@@ -393,16 +433,7 @@ watch(
|
|
|
}
|
|
|
);
|
|
|
|
|
|
-const showPlayBtn = computed(() => {
|
|
|
- if (!props.series || loading.value) return false;
|
|
|
- if (!playUrl.value) return true;
|
|
|
- if (userPaused.value) return true;
|
|
|
- if (!playing.value) return true;
|
|
|
- return false;
|
|
|
-});
|
|
|
-
|
|
|
function onPlay() {
|
|
|
- console.log("onPlay", playUrl.value);
|
|
|
if (playUrl.value) {
|
|
|
playing.value = true;
|
|
|
} else if (needPay.value) {
|
|
|
@@ -416,6 +447,45 @@ function chooseEpisode(n: number) {
|
|
|
emit("chooseEpisode", n);
|
|
|
}, 100);
|
|
|
}
|
|
|
+
|
|
|
+const videoPlayTimeout = ref<any>(0);
|
|
|
+const immersiveTimeout = ref<any>(0);
|
|
|
+
|
|
|
+function enterImmersive() {
|
|
|
+ if (playing.value) {
|
|
|
+ console.log("enterImmersive");
|
|
|
+ immersive.value = true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function exitImmersive() {
|
|
|
+ console.log("exitImmersive");
|
|
|
+ immersive.value = false;
|
|
|
+ clearTimeout(immersiveTimeout.value);
|
|
|
+ immersiveTimeout.value = setTimeout(enterImmersive, 3000);
|
|
|
+}
|
|
|
+
|
|
|
+function onVideoDidPlay() {
|
|
|
+ videoPlayTimeout.value = setTimeout(enterImmersive, 3000);
|
|
|
+}
|
|
|
+
|
|
|
+function onVideoDidPause() {
|
|
|
+ exitImmersive();
|
|
|
+}
|
|
|
+
|
|
|
+function onVideoEnd() {}
|
|
|
+
|
|
|
+watchThrottled(
|
|
|
+ currentTime,
|
|
|
+ () => {
|
|
|
+ http.post("/playHistories", {
|
|
|
+ seriesId: props.series?.id,
|
|
|
+ episodeId: props.episode?.id,
|
|
|
+ duration: currentTime.value,
|
|
|
+ });
|
|
|
+ },
|
|
|
+ { throttle: 3000 }
|
|
|
+);
|
|
|
</script>
|
|
|
<style lang="less" scoped>
|
|
|
.mask-info {
|
|
|
@@ -470,4 +540,13 @@ ion-modal {
|
|
|
.pay-modal {
|
|
|
--height: 460px;
|
|
|
}
|
|
|
+.fade-enter-active,
|
|
|
+.fade-leave-active {
|
|
|
+ transition: opacity 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.fade-enter-from,
|
|
|
+.fade-leave-to {
|
|
|
+ opacity: 0;
|
|
|
+}
|
|
|
</style>
|