Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions src/components/Player/MainPlayer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,9 @@
class="time-container"
vertical
>
<div class="time" @click="showCountDown = !showCountDown">
<n-text v-if="showCountDown" depth="2">-{{ msToTime(statusStore.duration - statusStore.currentTime) }}</n-text>
<n-text v-else depth="2">{{ msToTime(statusStore.currentTime) }}</n-text>
<n-text depth="2">{{ msToTime(statusStore.duration) }}</n-text>
<div class="time" @click="toggleTimeFormat">
<n-text depth="2">{{ timeDisplay0 }}</n-text>
<n-text depth="2">{{ timeDisplay1 }}</n-text>
</div>
<!-- 定时关闭 -->
<n-tag
Expand All @@ -190,7 +189,7 @@
<script setup lang="ts">
import type { DropdownOption } from "naive-ui";
import { useMusicStore, useStatusStore, useDataStore, useSettingStore } from "@/stores";
import { msToTime, convertSecondsToTime } from "@/utils/time";
import { convertSecondsToTime } from "@/utils/time";
import { renderIcon, coverLoaded, copyData } from "@/utils/helper";
import { toLikeSong } from "@/utils/auth";
import {
Expand All @@ -202,6 +201,7 @@ import {
} from "@/utils/modal";
import { useSongManager } from "@/core/player/SongManager";
import { usePlayerController } from "@/core/player/PlayerController";
import { getTimeDisplay, TIME_FORMATS } from "@/utils/format";

const router = useRouter();
const dataStore = useDataStore();
Expand All @@ -212,7 +212,14 @@ const settingStore = useSettingStore();
const player = usePlayerController();
const songManager = useSongManager();

const showCountDown = ref(false);
const timeDisplay = getTimeDisplay(() => settingStore.timeFormatMainPlayer, statusStore);
const timeDisplay0 = timeDisplay(0);
const timeDisplay1 = timeDisplay(1);

const toggleTimeFormat = () => {
const currentIndex = TIME_FORMATS.indexOf(settingStore.timeFormatMainPlayer)
settingStore.timeFormatMainPlayer = TIME_FORMATS[(currentIndex + 1) % TIME_FORMATS.length];
};
Comment on lines +219 to +222
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

toggleTimeFormat 函数中的逻辑与 PlayerControl.vue 中的几乎完全相同,只是操作的 settingStore 属性不同。为了遵循 DRY (Don't Repeat Yourself) 原则并提高代码的可维护性,建议将这个切换逻辑提取到一个公共的工具函数中,例如在 src/utils/format.ts 中创建一个 getNextTimeFormat 函数。这样两个组件都可以复用这个逻辑。


// 歌曲更多操作
const songMoreOptions = computed<DropdownOption[]>(() => {
Expand Down
18 changes: 14 additions & 4 deletions src/components/Player/PlayerControl.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@
</div>
<!-- 进度条 -->
<div class="slider">
<span>{{ msToTime(statusStore.currentTime) }}</span>
<span @click="toggleTimeFormat">{{ timeDisplay0 }}</span>
<PlayerSlider :show-tooltip="false" />
<span>{{ msToTime(statusStore.duration) }}</span>
<span @click="toggleTimeFormat">{{ timeDisplay1 }}</span>
</div>
</div>
<n-flex class="right" align="center" justify="end">
Expand All @@ -95,19 +95,29 @@
</template>

<script setup lang="ts">
import { useMusicStore, useStatusStore, useDataStore } from "@/stores";
import { msToTime } from "@/utils/time";
import { useMusicStore, useStatusStore, useDataStore, useSettingStore } from "@/stores";
import { openDownloadSong, openPlaylistAdd } from "@/utils/modal";
import { toLikeSong } from "@/utils/auth";
import { useSongManager } from "@/core/player/SongManager";
import { usePlayerController } from "@/core/player/PlayerController";
import { getTimeDisplay, TIME_FORMATS } from "@/utils/format";

const dataStore = useDataStore();
const musicStore = useMusicStore();
const statusStore = useStatusStore();
const settingStore = useSettingStore();

const songManager = useSongManager();
const player = usePlayerController();

const timeDisplay = getTimeDisplay(() => settingStore.timeFormatFullPlayer, statusStore);
const timeDisplay0 = timeDisplay(0);
const timeDisplay1 = timeDisplay(1);

const toggleTimeFormat = () => {
const currentIndex = TIME_FORMATS.indexOf(settingStore.timeFormatFullPlayer);
settingStore.timeFormatFullPlayer = TIME_FORMATS[(currentIndex + 1) % TIME_FORMATS.length];
};
Comment on lines +117 to +120
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

toggleTimeFormat 函数中的逻辑与 MainPlayer.vue 中的几乎完全相同。为了提高代码的复用性和可维护性,建议将此逻辑抽象成一个可复用的工具函数,并放置在 src/utils/format.ts 文件中。

</script>

<style lang="scss" scoped>
Expand Down
68 changes: 55 additions & 13 deletions src/components/Setting/PlaySetting.vue
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,17 @@
/>
</n-card>
</n-collapse-transition>
<n-card class="set-item">
<div class="label">
<n-text class="name">播放器时间样式</n-text>
<n-text class="tip" :depth="3">播放页面底部的时间如何显示(单击底部时间可以快速切换)</n-text>
</div>
<n-select
v-model:value="settingStore.timeFormatFullPlayer"
:options="timeFormatOptions"
class="set"
/>
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">播放器主色跟随封面</n-text>
Expand All @@ -250,13 +261,6 @@
</div>
<n-switch v-model:value="settingStore.countDownShow" class="set" :round="false" />
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">底栏歌词显示</n-text>
<n-text class="tip" :depth="3">在播放时将歌手信息更改为歌词</n-text>
</div>
<n-switch v-model:value="settingStore.barLyricShow" class="set" :round="false" />
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">播放器元素自动隐藏</n-text>
Expand All @@ -271,12 +275,6 @@
</div>
<n-switch v-model:value="settingStore.showPlayMeta" class="set" :round="false" />
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">播放列表歌曲数量</n-text>
</div>
<n-switch v-model:value="settingStore.showPlaylistCount" class="set" :round="false" />
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">动态封面</n-text>
Expand Down Expand Up @@ -304,6 +302,35 @@
/>
</n-card>
</div>
<div class="set-list">
<n-h3 prefix="bar"> 全局播放器 </n-h3>
<n-card class="set-item">
<div class="label">
<n-text class="name">底栏时间样式</n-text>
<n-text class="tip" :depth="3">
全局播放器右侧的时间如何显示(单击底栏时间可以快速切换)
</n-text>
</div>
<n-select
v-model:value="settingStore.timeFormatMainPlayer"
:options="timeFormatOptions"
class="set"
/>
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">播放列表歌曲数量</n-text>
</div>
<n-switch v-model:value="settingStore.showPlaylistCount" class="set" :round="false" />
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">底栏歌词显示</n-text>
<n-text class="tip" :depth="3">在播放时将歌手信息更改为歌词</n-text>
</div>
<n-switch v-model:value="settingStore.barLyricShow" class="set" :round="false" />
</n-card>
</div>
</div>
</template>

Expand Down Expand Up @@ -380,6 +407,21 @@ const songLevelData = {
},
};

const timeFormatOptions = [
{
label: "播放时间 / 总时长",
value: "current-total",
},
{
label: "剩余时间 / 总时长",
value: "remaining-total",
},
{
label: "播放时间 / 剩余时间",
value: "current-remaining",
},
];

// 获取全部输出设备
const getOutputDevices = async () => {
const allDevices = await navigator.mediaDevices.enumerateDevices();
Expand Down
7 changes: 7 additions & 0 deletions src/stores/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { SongUnlockServer } from "@/core/player/SongManager";
import type { SongLevelType } from "@/types/main";
import { defaultAMLLDbServer } from "@/utils/meta";
import { CURRENT_SETTING_SCHEMA_VERSION, settingMigrations } from "./migrations/settingMigrations";
import { TimeFormat } from "@/utils/format";

export interface SettingState {
/** Schema 版本号(可选,用于数据迁移) */
Expand Down Expand Up @@ -129,6 +130,10 @@ export interface SettingState {
countDownShow: boolean;
/** 显示歌词条 */
barLyricShow: boolean;
/** 全局播放器时间格式 **/
timeFormatMainPlayer: TimeFormat;
/** 播放页面时间格式 */
timeFormatFullPlayer: TimeFormat;
/** 播放器类型 */
playerType: "cover" | "record";
/** 背景类型 */
Expand Down Expand Up @@ -328,6 +333,8 @@ export const useSettingStore = defineStore("setting", {
],
countDownShow: true,
barLyricShow: true,
timeFormatMainPlayer: "current-total",
timeFormatFullPlayer: "current-total",
playerType: "cover",
playerBackgroundType: "blur",
playerBackgroundFps: 30,
Expand Down
26 changes: 26 additions & 0 deletions src/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,29 @@ export const getPlayerInfo = (song?: SongType, sep: string = "/"): string | null
if (!info) return null;
return `${info.name} - ${info.artist}`;
};

// 歌曲播放时间显示类型
export type TimeDisplayType = "current" | "total" | "remaining";

// 歌曲播放时间显示格式
export const TIME_FORMATS = ["current-total", "remaining-total", "current-remaining"] as const;
export type TimeFormat = typeof TIME_FORMATS[number];

export const displayTimeFormat = (format: TimeFormat): [TimeDisplayType, TimeDisplayType] => {
switch (format) {
case "current-total": return ["current", "total"];
case "remaining-total": return ["remaining", "total"];
case "current-remaining": return ["current", "remaining"];
}
Comment on lines +364 to +369
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这个 switch 语句没有处理所有 TimeFormat 类型之外的意外值。虽然 TypeScript 的类型系统可以在编译时提供保障,但考虑到设置可能从 localStorage 中读取,数据可能存在损坏或来自旧版本的风险。为了增强代码的健壮性,建议添加一个 default 分支作为回退,以防止在 format 值为意外值时函数返回 undefined 导致运行时错误。

Suggested change
export const displayTimeFormat = (format: TimeFormat): [TimeDisplayType, TimeDisplayType] => {
switch (format) {
case "current-total": return ["current", "total"];
case "remaining-total": return ["remaining", "total"];
case "current-remaining": return ["current", "remaining"];
}
export const displayTimeFormat = (format: TimeFormat): [TimeDisplayType, TimeDisplayType] => {
switch (format) {
case "current-total": return ["current", "total"];
case "remaining-total": return ["remaining", "total"];
case "current-remaining": return ["current", "remaining"];
default: return ["current", "total"];
}
};

};

export const getTimeDisplay = (
format: () => TimeFormat, statusStore: { currentTime: number, duration: number }
) => (index: number) => computed(() => {
const display = displayTimeFormat(format())[index];
switch (display) {
case "current": return msToTime(statusStore.currentTime);
case "total": return msToTime(statusStore.duration);
case "remaining": return "-" + msToTime(statusStore.duration - statusStore.currentTime);
}
});
Comment on lines +372 to +381

This comment was marked as outdated.