mirror of
https://github.com/lanyeeee/bilibili-video-downloader.git
synced 2026-09-04 23:17:45 +08:00
pref: 优化下载任务进度条的性能
This commit is contained in:
@@ -4,8 +4,14 @@ import App from './App.vue'
|
||||
import 'virtual:uno.css'
|
||||
import 'lazysizes'
|
||||
import 'lazysizes/plugins/parent-fit/ls.parent-fit'
|
||||
import VueScan, { type VueScanOptions } from 'z-vue-scan'
|
||||
|
||||
const pinia = createPinia()
|
||||
const app = createApp(App)
|
||||
|
||||
const isProduction = import.meta.env.PROD
|
||||
if (!isProduction) {
|
||||
app.use<VueScanOptions>(VueScan, {})
|
||||
}
|
||||
|
||||
app.use(pinia).mount('#app')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="tsx">
|
||||
import { ref, watchEffect, computed, nextTick, DeepReadonly, watch } from 'vue'
|
||||
import { SelectionArea, SelectionEvent } from '@viselect/vue'
|
||||
import { ref, watchEffect, computed, nextTick, DeepReadonly, watch, useTemplateRef } from 'vue'
|
||||
import { PartialSelectionOptions, SelectionArea, SelectionEvent } from '@viselect/vue'
|
||||
import { commands } from '../../../bindings.ts'
|
||||
import { DropdownOption, NIcon } from 'naive-ui'
|
||||
import { PhChecks, PhTrash, PhArrowClockwise } from '@phosphor-icons/vue'
|
||||
@@ -10,9 +10,13 @@ import { ProgressData } from '../DownloadPane.vue'
|
||||
|
||||
const store = useStore()
|
||||
|
||||
const selectionOptions: PartialSelectionOptions = {
|
||||
selectables: '.selectable',
|
||||
features: { deselectOnBlur: true },
|
||||
boundaries: '.completed-progresses-selection-container',
|
||||
}
|
||||
const selectionAreaRef = useTemplateRef('selectionAreaRef')
|
||||
const selectedIds = ref<Set<string>>(new Set())
|
||||
const selectionAreaRef = ref<InstanceType<typeof SelectionArea>>()
|
||||
const progressRefs = ref<InstanceType<typeof DownloadProgress>[]>([])
|
||||
const { dropdownX, dropdownY, dropdownShowing, dropdownOptions, showDropdown } = useDropdown()
|
||||
|
||||
const completedProgresses = computed<[string, DeepReadonly<ProgressData>][]>(() =>
|
||||
@@ -152,41 +156,35 @@ defineExpose({
|
||||
|
||||
<template>
|
||||
<div class="h-full flex flex-col overflow-auto">
|
||||
<SelectionArea
|
||||
ref="selectionAreaRef"
|
||||
class="h-full flex flex-col selection-container px-2"
|
||||
:options="{ selectables: '.selectable', features: { deselectOnBlur: true } }"
|
||||
@contextmenu="showDropdown"
|
||||
@move="updateSelectedIds"
|
||||
@start="unselectAll">
|
||||
<SelectionArea ref="selectionAreaRef" :options="selectionOptions" @move="updateSelectedIds" @start="unselectAll" />
|
||||
<div class="completed-progresses-selection-container h-full flex flex-col px-2" @contextmenu="showDropdown">
|
||||
<div class="animate-pulse text-violet">左键拖动进行框选,右键打开菜单</div>
|
||||
|
||||
<DownloadProgress
|
||||
v-for="[taskId, p] in currentPageProgresses"
|
||||
:key="taskId"
|
||||
:p="p"
|
||||
v-model:selected-ids="selectedIds"
|
||||
ref="progressRefs"
|
||||
:data-key="taskId"
|
||||
:class="['selectable', selectedIds.has(taskId) ? 'selected shadow-md' : 'hover:bg-gray-1']" />
|
||||
<n-dropdown
|
||||
placement="bottom-start"
|
||||
trigger="manual"
|
||||
:x="dropdownX"
|
||||
:y="dropdownY"
|
||||
:options="dropdownOptions"
|
||||
:show="dropdownShowing"
|
||||
:on-clickoutside="() => (dropdownShowing = false)" />
|
||||
</SelectionArea>
|
||||
:p="p"
|
||||
v-model:selected-ids="selectedIds" />
|
||||
</div>
|
||||
|
||||
<n-dropdown
|
||||
placement="bottom-start"
|
||||
trigger="manual"
|
||||
:x="dropdownX"
|
||||
:y="dropdownY"
|
||||
:options="dropdownOptions"
|
||||
:show="dropdownShowing"
|
||||
:on-clickoutside="() => (dropdownShowing = false)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.selection-container {
|
||||
.completed-progresses-selection-container {
|
||||
@apply select-none overflow-auto;
|
||||
}
|
||||
|
||||
.selection-container .selected {
|
||||
.completed-progresses-selection-container .selected {
|
||||
@apply bg-[rgb(204,232,255)];
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="tsx">
|
||||
import { path } from '@tauri-apps/api'
|
||||
import { commands, DownloadTaskState } from '../../../bindings.ts'
|
||||
import { commands } from '../../../bindings.ts'
|
||||
import { useStore } from '../../../store.ts'
|
||||
import {
|
||||
PhWarningCircle,
|
||||
@@ -55,7 +55,9 @@ async function handleProgressDoubleClick() {
|
||||
}
|
||||
}
|
||||
|
||||
function stateToStatus(state: DownloadTaskState): ProgressProps['status'] {
|
||||
const progressStatus = computed<ProgressProps['status']>(() => {
|
||||
const state = props.p.state
|
||||
|
||||
if (state === 'Completed') {
|
||||
return 'success'
|
||||
} else if (state === 'Paused') {
|
||||
@@ -65,9 +67,11 @@ function stateToStatus(state: DownloadTaskState): ProgressProps['status'] {
|
||||
} else {
|
||||
return 'default'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const colorClass = computed<string>(() => {
|
||||
const state = props.p.state
|
||||
|
||||
function stateToColorClass(state: DownloadTaskState) {
|
||||
if (state === 'Downloading') {
|
||||
return 'text-blue-500'
|
||||
} else if (state === 'Pending') {
|
||||
@@ -81,7 +85,7 @@ function stateToColorClass(state: DownloadTaskState) {
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
async function showMp4InFileManager(episodeDir: string, filename: string) {
|
||||
if (store.config === undefined) {
|
||||
@@ -145,7 +149,8 @@ function handleModifyClick() {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="p-2 mb-2 rounded-lg flex flex-col border border-solid border-gray-2"
|
||||
class="selectable p-2 mb-2 rounded-lg flex flex-col border border-solid border-gray-2"
|
||||
:class="selectedIds.has(p.task_id) ? 'selected shadow-md' : 'hover:bg-gray-1'"
|
||||
@contextmenu="handleProgressContextMenu"
|
||||
@dblclick="handleProgressDoubleClick">
|
||||
<div class="flex">
|
||||
@@ -254,7 +259,7 @@ function handleModifyClick() {
|
||||
:up-avatar="p.up_avatar"
|
||||
:up-uid="p.up_uid" />
|
||||
|
||||
<div v-if="p.state !== 'Completed'" :class="[stateToColorClass(p.state), 'flex items-center w-100']">
|
||||
<div v-if="p.state !== 'Completed'" :class="[colorClass, 'flex items-center w-100']">
|
||||
<n-icon :size="22">
|
||||
<PhCloudArrowDown v-if="p.state === 'Downloading'" />
|
||||
<PhClock v-else-if="p.state === 'Pending'" />
|
||||
@@ -264,7 +269,7 @@ function handleModifyClick() {
|
||||
<span class="whitespace-nowrap mr-2">{{ p.stateIndicator }}</span>
|
||||
<n-progress
|
||||
v-if="p.taskIndicator !== ''"
|
||||
:status="stateToStatus(p.state)"
|
||||
:status="progressStatus"
|
||||
:percentage="p.percentage"
|
||||
:processing="p.state === 'Downloading'">
|
||||
{{ p.taskIndicator }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="tsx">
|
||||
import { ref, watchEffect, computed, nextTick, DeepReadonly, watch } from 'vue'
|
||||
import { SelectionArea, SelectionEvent } from '@viselect/vue'
|
||||
import { ref, watchEffect, computed, nextTick, DeepReadonly, watch, useTemplateRef } from 'vue'
|
||||
import { PartialSelectionOptions, SelectionArea, SelectionEvent } from '@viselect/vue'
|
||||
import { commands } from '../../../bindings.ts'
|
||||
import { DropdownOption, NIcon } from 'naive-ui'
|
||||
import { PhPause, PhChecks, PhTrash, PhCaretRight, PhArrowClockwise } from '@phosphor-icons/vue'
|
||||
@@ -10,9 +10,13 @@ import { ProgressData } from '../DownloadPane.vue'
|
||||
|
||||
const store = useStore()
|
||||
|
||||
const selectionOptions: PartialSelectionOptions = {
|
||||
selectables: '.selectable',
|
||||
features: { deselectOnBlur: true },
|
||||
boundaries: '.uncompleted-progresses-selection-container',
|
||||
}
|
||||
const selectionAreaRef = useTemplateRef('selectionAreaRef')
|
||||
const selectedIds = ref<Set<string>>(new Set())
|
||||
const selectionAreaRef = ref<InstanceType<typeof SelectionArea>>()
|
||||
const progressRefs = ref<InstanceType<typeof DownloadProgress>[]>([])
|
||||
const { dropdownX, dropdownY, dropdownShowing, dropdownOptions, showDropdown } = useDropdown()
|
||||
|
||||
const uncompletedProgresses = computed<[string, DeepReadonly<ProgressData>][]>(() =>
|
||||
@@ -210,13 +214,8 @@ defineExpose({
|
||||
|
||||
<template>
|
||||
<div class="h-full flex flex-col overflow-auto">
|
||||
<SelectionArea
|
||||
ref="selectionAreaRef"
|
||||
class="h-full flex flex-col selection-container px-2"
|
||||
:options="{ selectables: '.selectable', features: { deselectOnBlur: true } }"
|
||||
@contextmenu="showDropdown"
|
||||
@move="updateSelectedIds"
|
||||
@start="unselectAll">
|
||||
<SelectionArea ref="selectionAreaRef" :options="selectionOptions" @move="updateSelectedIds" @start="unselectAll" />
|
||||
<div class="h-full flex flex-col uncompleted-progresses-selection-container px-2" @contextmenu="showDropdown">
|
||||
<div class="flex">
|
||||
<span class="animate-pulse text-violet">
|
||||
左键拖动进行框选,右键打开菜单,双击暂停/继续,失败的任务也可以继续
|
||||
@@ -226,12 +225,10 @@ defineExpose({
|
||||
<DownloadProgress
|
||||
v-for="[taskId, p] in currentPageProgresses"
|
||||
:key="taskId"
|
||||
:p="p"
|
||||
v-model:selected-ids="selectedIds"
|
||||
ref="progressRefs"
|
||||
:data-key="taskId"
|
||||
:class="['selectable ', selectedIds.has(taskId) ? 'selected shadow-md' : 'hover:bg-gray-1']" />
|
||||
</SelectionArea>
|
||||
:p="p"
|
||||
v-model:selected-ids="selectedIds" />
|
||||
</div>
|
||||
|
||||
<n-dropdown
|
||||
placement="bottom-start"
|
||||
@@ -245,11 +242,11 @@ defineExpose({
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.selection-container {
|
||||
.uncompleted-progresses-selection-container {
|
||||
@apply select-none overflow-auto;
|
||||
}
|
||||
|
||||
.selection-container .selected {
|
||||
.uncompleted-progresses-selection-container .selected {
|
||||
@apply bg-[rgb(204,232,255)];
|
||||
}
|
||||
</style>
|
||||
|
||||
+9
-1
@@ -38,8 +38,16 @@ function useProgresses() {
|
||||
// 将 `_progresses` 的内容更新到 `progresses` 中,并触发重新渲染
|
||||
const updateProgressesOnFrame = () => {
|
||||
const newProgressesMap = new Map<string, ProgressData>()
|
||||
|
||||
for (const [key, value] of _progresses.entries()) {
|
||||
newProgressesMap.set(key, { ...value })
|
||||
const progressData = progresses.value.get(key)
|
||||
|
||||
if (progressData !== undefined) {
|
||||
Object.assign(progressData, value)
|
||||
newProgressesMap.set(key, progressData)
|
||||
} else {
|
||||
newProgressesMap.set(key, { ...value })
|
||||
}
|
||||
}
|
||||
progresses.value = newProgressesMap
|
||||
|
||||
|
||||
Reference in New Issue
Block a user