Skip to content

Commit

Permalink
✨ feat: 托盘菜单完善
Browse files Browse the repository at this point in the history
  • Loading branch information
imsyy committed Sep 26, 2024
1 parent 2b6d68e commit 62c9dc3
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 50 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
- ✨ 支持扫码登录
- 📱 支持手机号登录
- 📅 自动进行每日签到及云贝签到
- 💻 支持桌面歌词
- 💻 支持切换为本地播放器,此模式将不会连接网络
- 🎨 封面主题色自适应,支持全站着色
- 🌚 Light / Dark / Auto 模式自动切换
Expand Down
5 changes: 5 additions & 0 deletions electron/main/ipcMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,11 @@ const initTrayIpcMain = (
tray?.setPlayMode(mode);
});

// 喜欢状态切换
ipcMain.on("like-status-change", (_, likeStatus: boolean) => {
tray?.setLikeState(likeStatus);
});

// 桌面歌词开关
ipcMain.on("change-desktop-lyric", (_, val: boolean) => {
tray?.setDesktopLyricShow(val);
Expand Down
36 changes: 15 additions & 21 deletions electron/main/tray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ type PlayState = "play" | "pause" | "loading";
let playMode: PlayMode = "repeat";
let playState: PlayState = "pause";
let playName: string = "未播放歌曲";
let likeSong: boolean = false;
let desktopLyricShow: boolean = false;
let desktopLyricLock: boolean = false;

export interface MainTray {
setTitle(title: string): void;
setPlayMode(mode: PlayMode): void;
setLikeState(like: boolean): void;
setPlayState(state: PlayState): void;
setPlayName(name: string): void;
setDesktopLyricShow(show: boolean): void;
Expand All @@ -34,11 +36,11 @@ export interface MainTray {

// 托盘图标
const trayIcon = (filename: string) => {
// const rootPath = isDev
// ? join(__dirname, "../../public/icons/tray")
// : join(app.getAppPath(), "../../public/icons/tray");
// return nativeImage.createFromPath(join(rootPath, filename));
return nativeImage.createFromPath(join(__dirname, `../../public/icons/tray/${filename}`));
const rootPath = isDev
? join(__dirname, "../../public/icons/tray")
: join(app.getAppPath(), "../../public/icons/tray");
return nativeImage.createFromPath(join(rootPath, filename));
// return nativeImage.createFromPath(join(__dirname, `../../public/icons/tray/${filename}`));
};

// 托盘菜单
Expand All @@ -60,7 +62,6 @@ const createTrayMenu = (
id: "name",
label: playName,
icon: showIcon("music"),
accelerator: "CmdOrCtrl+Alt+S",
click: () => {
win.show();
win.focus();
Expand All @@ -71,19 +72,10 @@ const createTrayMenu = (
},
{
id: "toogleLikeSong",
label: "添加到我喜欢",
icon: showIcon("unlike"),
accelerator: "CmdOrCtrl+Alt+L",
label: likeSong ? "从我喜欢中移除" : "添加到我喜欢",
icon: showIcon(likeSong ? "like" : "unlike"),
click: () => win.webContents.send("toogleLikeSong"),
},
{
id: "unLike",
label: "从我喜欢中移除",
icon: showIcon("like"),
visible: false,
accelerator: "CmdOrCtrl+Alt+L",
click: () => win.webContents.send("unlike-song"),
},
{
id: "changeMode",
label:
Expand Down Expand Up @@ -123,21 +115,18 @@ const createTrayMenu = (
id: "playNext",
label: "上一曲",
icon: showIcon("prev"),
accelerator: "CmdOrCtrl+Left",
click: () => win.webContents.send("playPrev"),
},
{
id: "playOrPause",
label: playState === "pause" ? "播放" : "暂停",
icon: showIcon(playState === "pause" ? "play" : "pause"),
accelerator: "CmdOrCtrl+Space",
click: () => win.webContents.send(playState === "pause" ? "play" : "pause"),
},
{
id: "playNext",
label: "下一曲",
icon: showIcon("next"),
accelerator: "CmdOrCtrl+Right",
click: () => win.webContents.send("playNext"),
},
{
Expand Down Expand Up @@ -176,7 +165,6 @@ const createTrayMenu = (
id: "exit",
label: "退出",
icon: showIcon("power"),
accelerator: "CmdOrCtrl+Alt+Q",
click: () => {
win.close();
// app.exit(0);
Expand Down Expand Up @@ -255,6 +243,12 @@ class CreateTray implements MainTray {
// 更新菜单
this.initTrayMenu();
}
// 设置喜欢状态
setLikeState(like: boolean) {
likeSong = like;
// 更新菜单
this.initTrayMenu();
}
// 桌面歌词开关
setDesktopLyricShow(show: boolean) {
desktopLyricShow = show;
Expand Down
7 changes: 6 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,12 @@
<!-- 全屏播放器 -->
<Teleport to="body">
<Transition name="up" mode="out-in">
<FullPlayer v-if="statusStore.showFullPlayer || statusStore.fullPlayerActive" />
<FullPlayer
v-if="
statusStore.showFullPlayer ||
(statusStore.fullPlayerActive && settingStore.fullPlayerCache)
"
/>
</Transition>
</Teleport>
</Provider>
Expand Down
9 changes: 2 additions & 7 deletions src/components/List/SongList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@
<div v-if="type !== 'radio'" class="actions" @click.stop @dblclick.stop>
<!-- 喜欢歌曲 -->
<SvgIcon
:name="isLikeSong(item.id) ? 'Favorite' : 'FavoriteBorder'"
:name="dataStore.isLikeSong(item.id) ? 'Favorite' : 'FavoriteBorder'"
:size="20"
@click.stop="toLikeSong(item, !isLikeSong(item.id))"
@click.stop="toLikeSong(item, !dataStore.isLikeSong(item.id))"
@delclick.stop
/>
</div>
Expand Down Expand Up @@ -381,11 +381,6 @@ const sortSelect = (key: SortType) => {
}
};
// 是否为喜欢歌曲
const isLikeSong = (id: number) => {
return dataStore.userLikeData.songs.includes(id);
};
// 滚动至播放歌曲
const scrollTo = (index: number) => {
if (index === 0) songListScrollTop.value = 0;
Expand Down
92 changes: 75 additions & 17 deletions src/components/Modal/LoginQRCode.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
<template>
<div class="login-qrcode">
<div class="qr-img">
<n-qr-code
<div
v-if="qrImg"
:value="qrImg"
:class="['qr', { success: qrStatusCode === 802, error: qrStatusCode === 800 }]"
:size="160"
:icon-size="30"
icon-src="/icons/favicon.png?assest"
error-correction-level="H"
/>
>
<n-qr-code
:value="qrImg"
:size="160"
:icon-size="30"
icon-src="/icons/favicon.png?assest"
error-correction-level="H"
/>
<!-- 待确认 -->
<Transition name="fade" mode="out-in">
<div v-if="loginName" class="login-data">
<n-image
:src="loginAvatar.replace(/^http:/, 'https:') + '?param=100y100'"
class="cover"
preview-disabled
@load="coverLoaded"
>
<template #placeholder>
<div class="cover-loading">
<img src="/images/avatar.jpg?assest" class="loading-img" alt="loading-img" />
</div>
</template>
</n-image>
<n-text>{{ loginName }}</n-text>
</div>
</Transition>
</div>
<n-skeleton v-else class="qr" />
</div>
<n-text class="tip" depth="3">{{ qrTipText }}</n-text>
Expand All @@ -18,6 +39,7 @@

<script setup lang="ts">
import { qrKey, checkQr } from "@/api/login";
import { coverLoaded } from "@/utils/helper";
const emit = defineEmits<{
saveLogin: [any];
Expand All @@ -41,11 +63,17 @@ const qrTipText = computed(() => {
return qrCodeTip[qrStatusCode.value] || "遇到未知状态,请重试";
});
// 待确认数据
const loginName = ref<string>("");
const loginAvatar = ref<string>("");
// 获取二维码
const getQrData = async () => {
try {
pauseCheck();
qrStatusCode.value = 801;
loginName.value = "";
loginAvatar.value = "";
// 获取 key
const res = await qrKey();
qrImg.value = `https://music.163.com/login?codekey=${res.data.unikey}`;
Expand All @@ -63,7 +91,7 @@ const getQrData = async () => {
const checkQrStatus = async () => {
if (!qrUnikey.value) return;
// 检查状态
const { code, cookie } = await checkQr(qrUnikey.value);
const { code, cookie, nickname, avatarUrl } = await checkQr(qrUnikey.value);
switch (code) {
// 二维码过期
case 800:
Expand All @@ -77,6 +105,8 @@ const checkQrStatus = async () => {
// 待确认
case 802:
qrStatusCode.value = 802;
loginName.value = nickname;
loginAvatar.value = avatarUrl;
break;
// 登录成功
case 803:
Expand Down Expand Up @@ -115,15 +145,43 @@ onBeforeUnmount(pauseCheck);
border-radius: 12px;
overflow: hidden;
.qr {
padding: 0;
height: 180px;
width: 180px;
min-height: 180px;
min-width: 180px;
transition: opacity 0.3s;
:deep(canvas) {
width: 100% !important;
height: 100% !important;
position: relative;
display: flex;
align-items: center;
justify-content: center;
.n-qr-code {
padding: 0;
height: 180px;
width: 180px;
min-height: 180px;
min-width: 180px;
transition:
opacity 0.3s,
filter 0.3s;
:deep(canvas) {
width: 100% !important;
height: 100% !important;
}
}
.login-data {
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
z-index: 1;
.cover {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
margin-bottom: 8px;
}
}
&.success {
.n-qr-code {
opacity: 0.5;
filter: blur(4px);
}
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/components/Setting/PlaySetting.vue
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@
class="set"
/>
</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.fullPlayerCache" class="set" :round="false" />
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">显示前奏倒计时</n-text>
Expand Down
2 changes: 2 additions & 0 deletions src/stores/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ interface SettingState {
routeAnimation: "none" | "fade" | "zoom" | "slide" | "up";
useRealIP: boolean;
realIP: string;
fullPlayerCache: boolean;
}

export const useSettingStore = defineStore({
Expand All @@ -104,6 +105,7 @@ export const useSettingStore = defineStore({
showTaskbarProgress: false, // 显示任务栏进度
checkUpdateOnStart: true, // 启动时检查更新
preventSleep: false, // 是否禁止休眠
fullPlayerCache: false, // 全屏播放器缓存
// 播放
songLevel: "exhigh", // 音质
playDevice: "default", // 播放设备
Expand Down
3 changes: 3 additions & 0 deletions src/utils/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { openUserLogin } from "./modal";
import { debounce } from "lodash-es";
import { isBeforeSixAM } from "./time";
import { dailyRecommend } from "@/api/rec";
import { isElectron } from "./helper";

// 是否登录
export const isLogin = () => !!getCookie("MUSIC_U");
Expand Down Expand Up @@ -182,6 +183,8 @@ export const toLikeSong = debounce(
}
// 更新
dataStore.setUserLikeData("songs", likeList);
// ipc
if (isElectron) window.electron.ipcRenderer.send("like-status-change", like);
} else {
window.$message.error(`${like ? "喜欢" : "取消"}音乐时发生错误`);
return;
Expand Down
4 changes: 2 additions & 2 deletions src/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export const formatSongsList = (data: any[]): SongType[] => {
name: (item.album || item.al)?.name,
cover: (item.album || item.al)?.picUrl,
},
alia: isArray(item.alia || item.alias || item.transNames)
? item.alia?.[0] || item.alias?.[0] || item.transNames?.[0]
alia: isArray(item.alia || item.alias || item.transNames || item.tns)
? item.alia?.[0] || item.alias?.[0] || item.transNames?.[0] || item.tns?.[0]
: item.alia,
dj: item.dj
? {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/initIpc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { isElectron } from "./helper";
import { openUpdateApp } from "./modal";
import { useMusicStore, useDataStore } from "@/stores";
import player from "./player";
import { toLikeSong } from "./auth";

// 全局 IPC 事件
const initIpc = () => {
Expand All @@ -22,6 +24,12 @@ const initIpc = () => {
window.electron.ipcRenderer.on("volumeDown", () => player.setVolume("down"));
// 播放模式切换
window.electron.ipcRenderer.on("changeMode", (_, mode) => player.togglePlayMode(mode));
// 喜欢歌曲
window.electron.ipcRenderer.on("toogleLikeSong", async () => {
const dataStore = useDataStore();
const musicStore = useMusicStore();
await toLikeSong(musicStore.playSong, !dataStore.isLikeSong(musicStore.playSong.id));
});
// 桌面歌词开关
window.electron.ipcRenderer.on("toogleDesktopLyric", () => player.toggleDesktopLyric());
window.electron.ipcRenderer.on("closeDesktopLyric", () => player.toggleDesktopLyric());
Expand Down
Loading

0 comments on commit 62c9dc3

Please sign in to comment.