From 07d7564b1e3a5c0dfd76ba8b3e1f6eba2ea90762 Mon Sep 17 00:00:00 2001 From: memorydream <34763046+memorydream@users.noreply.github.com> Date: Fri, 29 Apr 2022 21:16:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20windows=E7=BC=A9=E7=95=A5=E5=9B=BE?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E6=A0=8F=20(#1551)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 从 v1 引入图标 * feat: windows缩略图工具栏 * 更新windows任务栏控制图标 图标基于microsoft fluent icon修改 移除like和unlike * update * 启动时显示taskbar buttons --- src/main/assets/icons/taskbar/next.png | Bin 0 -> 936 bytes src/main/assets/icons/taskbar/pause.png | Bin 0 -> 612 bytes src/main/assets/icons/taskbar/play.png | Bin 0 -> 844 bytes src/main/assets/icons/taskbar/previous.png | Bin 0 -> 890 bytes src/main/assets/icons/{ => tray}/exit.png | Bin src/main/assets/icons/{ => tray}/left.png | Bin src/main/assets/icons/{ => tray}/like.png | Bin src/main/assets/icons/{ => tray}/menu.png | Bin src/main/assets/icons/{ => tray}/menu@88.png | Bin src/main/assets/icons/{ => tray}/pause.png | Bin src/main/assets/icons/{ => tray}/play.png | Bin src/main/assets/icons/{ => tray}/repeat.png | Bin src/main/assets/icons/{ => tray}/right.png | Bin src/main/assets/icons/{ => tray}/unlike.png | Bin src/main/index.ts | 11 ++- src/main/ipcMain.ts | 19 +++- src/main/tray.ts | 4 +- src/main/windowsTaskbar.ts | 86 +++++++++++++++++++ src/renderer/IpcRendererReact.tsx | 9 +- src/shared/IpcChannels.ts | 5 -- 20 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 src/main/assets/icons/taskbar/next.png create mode 100644 src/main/assets/icons/taskbar/pause.png create mode 100644 src/main/assets/icons/taskbar/play.png create mode 100644 src/main/assets/icons/taskbar/previous.png rename src/main/assets/icons/{ => tray}/exit.png (100%) rename src/main/assets/icons/{ => tray}/left.png (100%) rename src/main/assets/icons/{ => tray}/like.png (100%) rename src/main/assets/icons/{ => tray}/menu.png (100%) rename src/main/assets/icons/{ => tray}/menu@88.png (100%) rename src/main/assets/icons/{ => tray}/pause.png (100%) rename src/main/assets/icons/{ => tray}/play.png (100%) rename src/main/assets/icons/{ => tray}/repeat.png (100%) rename src/main/assets/icons/{ => tray}/right.png (100%) rename src/main/assets/icons/{ => tray}/unlike.png (100%) create mode 100644 src/main/windowsTaskbar.ts diff --git a/src/main/assets/icons/taskbar/next.png b/src/main/assets/icons/taskbar/next.png new file mode 100644 index 0000000000000000000000000000000000000000..a2a42c073358ef4dea74be3d3f801e2dc433cafa GIT binary patch literal 936 zcmV;Z16TZsP)r!Z3SBeK~Mw{D}R8mM#6e02}C5BW%hoYnRA&r1J1Cn<*b$f~nJRxOHe-<)aH^i(%pXqtVJ&OsgvW%3b9zy$ok!iolgckd zr4Gm(!XiS5AYKv_Swp9QUus@5YwQbDeDkb}N0Yz7CZ;$tWX07YeyL*Dr`eNH3BjDbHa>=%TPHek;3a)3k%GdqtlGD_e=%uBQwmrQ3m4e#gBy#&2?(7960skYF@9 zxJc4lTv~#bB#0!0Tm+YvATTLhYitzzGdVP<(B>v7E*6qwxrNc>AVzZgj`-~QxG&#p ztph*2=iKj{bKkx9J&FF!<_>7k-+?o*Xft;M`oahvEA1K47w`evU=3I`0ildCPo&dn zQLop9&*x+DCpZOjO7&z=6pO_n2y?E|h7AO)+wF>2ET*sM9_l4!#&?j@hKA6%!OZvk zMuXW=ld%;3^fNG9Suhx+Mx#N|Xp{?|fD1D% z$1QD&aG==b}SN~I_e2vDt7 zdqc4uaA+(l`&Qo2p}tb7P&^)|R;$JS6*vIz?EGX?p8#((B@zkJG>v+_9@kn2dthpD z78`BinidKL;dZr!Z3SBeK~Mw{D}R8mM#6e02}C5BW%hoYnRA&r1J1Cn<*b$f~nJRxOHe-<)aH^i(%pXqtVJ&OsgvW%3b9zy$ok!iolgckd zr4Gm(!XiS5AYKv_Swp9QUus@5YwQbDeDkb}N0Yz7CZ;$tWX07YeyL*Dr`eNH3BjDbHa>=%TPHek;3a)3k%GdqtlGD_e=%uBQwmrQ3m4e#gBy#&2?(7960s&>(orhfi#HQTa$TM)e_q6*D`W3vakyV3vfr*p4TPx?5{U=iJi@ zAtW4Tc)FVv6Jsjq!Bd}Xaf2bH6t2c yhy$y4Ec>*IAzH;O3BznvB|j4hQ{7k_uL+!Lp;n^(8FI`30000r!Z3SBeK~Mw{D}R8mM#6e02}C5BW%hoYnRA&r1J1Cn<*b$f~nJRxOHe-<)aH^i(%pXqtVJ&OsgvW%3b9zy$ok!iolgckd zr4Gm(!XiS5AYKv_Swp9QUus@5YwQbDeDkb}N0Yz7CZ;$tWX07YeyL*Dr`eNH3BjDbHa>=%TPHek;3a)3k%GdqtlGD_e=%uBQwmrQ3m4e#gBy#&2?(7960s4n@dR7ZK7I(7~a31_zs|n~J313nX21v8{t(KoXAs5iS&~O&a6Y zAHD=G$@#eFUhWlQnSveI!GCw)8C-%bP-^Zgl?vImO{%IAD#zd)Y?NYA6onkeAx;!U z)ND3c!i>N%SOb3wwcG74fqVo(K($&;ib7Pkz)Dfej6jNdy&f5cAw>ZM2Sp^m3Rsk; zDS4hpx~@yn4J5`QqPYS&n>dcC)9H|=X~gRWfd{tph;j*}XgnTMtJRV_?hS(dEXhIw zDH;xkJc}pbOF`jXAPZ!@OA$;a6M+_qYPI?S;W{|Y66b0WFS6^p+?H36f-8{gSeYwG zl7zb5?({ajM&VsBlhv7#IRjWs;rqU5G#ZcijQ9NmI01d|V{)&-U@#E%dYy}NA@1`b z*aLmASf&rVFbv7EEbcS&0*-(RipMlf`gUBuquLoL=eR~8zHn{V literal 0 HcmV?d00001 diff --git a/src/main/assets/icons/taskbar/previous.png b/src/main/assets/icons/taskbar/previous.png new file mode 100644 index 0000000000000000000000000000000000000000..6003dd26b1d84b11765d8cdc65e576132db5174c GIT binary patch literal 890 zcmV-=1BLvFP)r!Z3SBeK~Mw{D}R8mM#6e02}C5BW%hoYnRA&r1J1Cn<*b$f~nJRxOHe-<)aH^i(%pXqtVJ&OsgvW%3b9zy$ok!iolgckd zr4Gm(!XiS5AYKv_Swp9QUus@5YwQbDeDkb}N0Yz7CZ;$tWX07YeyL*Dr`eNH3BjDbHa>=%TPHek;3a)3k%GdqtlGD_e=%uBQwmrQ3m4e#gBy#&2?(7960s}CsnM`J;-%o=TRJsF4;L)-yJraq`EH0A)R`Da)!ovgy<#L(E2%(c$s`qvMH&u=OiAywbI(+_aSgUA5b=0iv|6pH*1b?&H0}h> zI3HM?fF0YmN!N8M6bghJ?BwTqPKSYd)~8|_`5Q0_hr_}!jHyp`0(WP>AG=MMpMc0_ zv!dVc3$}q2yTFnS`7=KQb|@4Qi9|yB-@IJ^`NP>j(R=U=_PrV`_LXno8>j)#Zvde; QkN^Mx07*qoM6N<$f_gEY7XSbN literal 0 HcmV?d00001 diff --git a/src/main/assets/icons/exit.png b/src/main/assets/icons/tray/exit.png similarity index 100% rename from src/main/assets/icons/exit.png rename to src/main/assets/icons/tray/exit.png diff --git a/src/main/assets/icons/left.png b/src/main/assets/icons/tray/left.png similarity index 100% rename from src/main/assets/icons/left.png rename to src/main/assets/icons/tray/left.png diff --git a/src/main/assets/icons/like.png b/src/main/assets/icons/tray/like.png similarity index 100% rename from src/main/assets/icons/like.png rename to src/main/assets/icons/tray/like.png diff --git a/src/main/assets/icons/menu.png b/src/main/assets/icons/tray/menu.png similarity index 100% rename from src/main/assets/icons/menu.png rename to src/main/assets/icons/tray/menu.png diff --git a/src/main/assets/icons/menu@88.png b/src/main/assets/icons/tray/menu@88.png similarity index 100% rename from src/main/assets/icons/menu@88.png rename to src/main/assets/icons/tray/menu@88.png diff --git a/src/main/assets/icons/pause.png b/src/main/assets/icons/tray/pause.png similarity index 100% rename from src/main/assets/icons/pause.png rename to src/main/assets/icons/tray/pause.png diff --git a/src/main/assets/icons/play.png b/src/main/assets/icons/tray/play.png similarity index 100% rename from src/main/assets/icons/play.png rename to src/main/assets/icons/tray/play.png diff --git a/src/main/assets/icons/repeat.png b/src/main/assets/icons/tray/repeat.png similarity index 100% rename from src/main/assets/icons/repeat.png rename to src/main/assets/icons/tray/repeat.png diff --git a/src/main/assets/icons/right.png b/src/main/assets/icons/tray/right.png similarity index 100% rename from src/main/assets/icons/right.png rename to src/main/assets/icons/tray/right.png diff --git a/src/main/assets/icons/unlike.png b/src/main/assets/icons/tray/unlike.png similarity index 100% rename from src/main/assets/icons/unlike.png rename to src/main/assets/icons/tray/unlike.png diff --git a/src/main/index.ts b/src/main/index.ts index 8bd000b..d052fd6 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -14,6 +14,7 @@ import log from './log' import { initIpcMain } from './ipcMain' import { createTray, YPMTray } from './tray' import { IpcChannels } from '@/shared/IpcChannels' +import { createTaskbar, Thumbar } from './windowsTaskbar' const isWindows = process.platform === 'win32' const isMac = process.platform === 'darwin' @@ -32,6 +33,7 @@ interface TypedElectronStore { class Main { win: BrowserWindow | null = null tray: YPMTray | null = null + thumbar: Thumbar | null = null store = new Store({ defaults: { window: { @@ -62,7 +64,8 @@ class Main { this.handleAppEvents() this.handleWindowEvents() this.createTray() - initIpcMain(this.win, this.tray) + this.createThumbar() + initIpcMain(this.win, this.tray, this.thumbar) this.initDevTools() }) } @@ -93,6 +96,10 @@ class Main { } } + createThumbar() { + if (isWindows) this.thumbar = createTaskbar(this.win!) + } + createWindow() { const options: BrowserWindowConstructorOptions = { title: 'YesPlayMusic', @@ -150,7 +157,7 @@ class Main { handleAppEvents() { app.on('window-all-closed', () => { this.win = null - if (process.platform !== 'darwin') app.quit() + if (!isMac) app.quit() }) app.on('second-instance', () => { diff --git a/src/main/ipcMain.ts b/src/main/ipcMain.ts index a6cb2c3..6078a35 100644 --- a/src/main/ipcMain.ts +++ b/src/main/ipcMain.ts @@ -6,6 +6,7 @@ import log from './log' import fs from 'fs' import { APIs } from '../shared/CacheAPIs' import { YPMTray } from './tray' +import { Thumbar } from './windowsTaskbar' const on = ( channel: T, @@ -14,9 +15,14 @@ const on = ( ipcMain.on(channel, listener) } -export function initIpcMain(win: BrowserWindow | null, tray: YPMTray | null) { +export function initIpcMain( + win: BrowserWindow | null, + tray: YPMTray | null, + thumbar: Thumbar | null +) { initWindowIpcMain(win) initTrayIpcMain(tray) + initTaskbarIpcMain(thumbar) } /** @@ -45,7 +51,7 @@ function initWindowIpcMain(win: BrowserWindow | null) { function initTrayIpcMain(tray: YPMTray | null) { on(IpcChannels.SetTrayTooltip, (e, { text }) => tray?.setTooltip(text)) - on(IpcChannels.SetTrayLikeState, (e, { isLiked }) => + on(IpcChannels.Like, (e, { isLiked }) => tray?.setLikeState(isLiked) ) @@ -55,6 +61,15 @@ function initTrayIpcMain(tray: YPMTray | null) { on(IpcChannels.Repeat, (e, { mode }) => tray?.setRepeatMode(mode)) } +/** + * 处理需要thumbar对象的事件 + * @param {Thumbar} thumbar + */ +function initTaskbarIpcMain(thumbar: Thumbar | null) { + on(IpcChannels.Play, () => thumbar?.setPlayState(true)) + on(IpcChannels.Pause, () => thumbar?.setPlayState(false)) +} + /** * 清除API缓存 */ diff --git a/src/main/tray.ts b/src/main/tray.ts index cc46bd2..4191c7a 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -12,8 +12,8 @@ import { RepeatMode } from '@/shared/playerDataTypes' const iconDirRoot = process.env.NODE_ENV === 'development' - ? path.join(process.cwd(), './src/main/assets/icons') - : path.join(__dirname, './assets/icons') + ? path.join(process.cwd(), './src/main/assets/icons/tray') + : path.join(__dirname, './assets/icons/tray') enum MenuItemIDs { Play = 'play', diff --git a/src/main/windowsTaskbar.ts b/src/main/windowsTaskbar.ts new file mode 100644 index 0000000..ffac443 --- /dev/null +++ b/src/main/windowsTaskbar.ts @@ -0,0 +1,86 @@ +import { IpcChannels } from '@/shared/IpcChannels' +import { BrowserWindow, nativeImage, ThumbarButton } from 'electron' +import path from 'path' + +enum ItemKeys { + Play = 'play', + Pause = 'pause', + Previous = 'previous', + Next = 'next', +} + +type ThumbarButtonMap = Map + +const iconDirRoot = + process.env.NODE_ENV === 'development' + ? path.join(process.cwd(), './src/main/assets/icons/taskbar') + : path.join(__dirname, './assets/icons/taskbar') + +function createNativeImage(filename: string) { + return nativeImage.createFromPath(path.join(iconDirRoot, filename)) +} + +function createThumbarButtons(win: BrowserWindow): ThumbarButtonMap { + return new Map() + .set(ItemKeys.Play, { + click: () => win.webContents.send(IpcChannels.Play), + icon: createNativeImage('play.png'), + tooltip: '播放', + }) + .set(ItemKeys.Pause, { + click: () => win.webContents.send(IpcChannels.Pause), + icon: createNativeImage('pause.png'), + tooltip: '暂停', + }) + .set(ItemKeys.Previous, { + click: () => win.webContents.send(IpcChannels.Previous), + icon: createNativeImage('previous.png'), + tooltip: '上一首', + }) + .set(ItemKeys.Next, { + click: () => win.webContents.send(IpcChannels.Next), + icon: createNativeImage('next.png'), + tooltip: '下一首', + }) +} + +export interface Thumbar { + setPlayState(isPlaying: boolean): void +} + +class ThumbarImpl implements Thumbar { + private _win: BrowserWindow + private _buttons: ThumbarButtonMap + + private _playOrPause: ThumbarButton + private _previous: ThumbarButton + private _next: ThumbarButton + + constructor(win: BrowserWindow) { + this._win = win + this._buttons = createThumbarButtons(win) + + this._playOrPause = this._buttons.get(ItemKeys.Play)! + this._previous = this._buttons.get(ItemKeys.Previous)! + this._next = this._buttons.get(ItemKeys.Next)! + } + + private _updateThumbarButtons(clear: boolean) { + this._win.setThumbarButtons( + clear + ? [] + : [this._previous, this._playOrPause, this._next] + ) + } + + setPlayState(isPlaying: boolean) { + this._playOrPause = this._buttons.get( + isPlaying ? ItemKeys.Pause : ItemKeys.Play + )! + this._updateThumbarButtons(false) + } +} + +export function createTaskbar(win: BrowserWindow): Thumbar { + return new ThumbarImpl(win) +} diff --git a/src/renderer/IpcRendererReact.tsx b/src/renderer/IpcRendererReact.tsx index fcf5c80..52a880c 100644 --- a/src/renderer/IpcRendererReact.tsx +++ b/src/renderer/IpcRendererReact.tsx @@ -33,7 +33,7 @@ const IpcRendererReact = () => { }, [track]) useEffect(() => { - window.ipcRenderer?.send(IpcChannels.SetTrayLikeState, { + window.ipcRenderer?.send(IpcChannels.Like, { isLiked: userLikedSongs?.ids?.includes(track?.id ?? 0) ?? false, }) }, [userLikedSongs, track]) @@ -46,6 +46,13 @@ const IpcRendererReact = () => { setIsPlaying(playing) }, [state]) + useEffectOnce(() => { + // 用于显示 windows taskbar buttons + if (playerSnapshot.track?.id) { + window.ipcRenderer?.send(IpcChannels.Pause) + } + }) + return <> } diff --git a/src/shared/IpcChannels.ts b/src/shared/IpcChannels.ts index 98400e7..c2f09e6 100644 --- a/src/shared/IpcChannels.ts +++ b/src/shared/IpcChannels.ts @@ -11,7 +11,6 @@ export const enum IpcChannels { DevDbExportJson = 'dev-db-export-json', CacheCoverColor = 'cache-cover-color', SetTrayTooltip = 'set-tray-tooltip', - SetTrayLikeState = 'set-tray-like-state', // 准备三个播放相关channel, 为 mpris 预留接口 Play = 'play', Pause = 'pause', @@ -41,9 +40,6 @@ export interface IpcChannelsParams { [IpcChannels.SetTrayTooltip]: { text: string } - [IpcChannels.SetTrayLikeState]: { - isLiked: boolean - } [IpcChannels.Play]: void [IpcChannels.Pause]: void [IpcChannels.PlayOrPause]: void @@ -68,7 +64,6 @@ export interface IpcChannelsReturns { [IpcChannels.DevDbExportJson]: void [IpcChannels.CacheCoverColor]: void [IpcChannels.SetTrayTooltip]: void - [IpcChannels.SetTrayLikeState]: void [IpcChannels.Play]: void [IpcChannels.Pause]: void [IpcChannels.PlayOrPause]: void