feat: add tray icon color customization (#2414)

- Implemented functionality to change the tray icon color based on user settings.
- Added new IPC event to update the tray icon dynamically.
- Updated the settings view to allow users to select between auto, light, and dark themes for the tray icon.
- Enhanced tray implementation to utilize the store for icon theme settings.
This commit is contained in:
657
2025-10-23 17:53:37 +08:00
committed by GitHub
parent 210df7650f
commit c47d009526
9 changed files with 118 additions and 8 deletions

View File

@@ -388,7 +388,11 @@ class Background {
// create tray
if (isCreateTray) {
this.trayEventEmitter = new EventEmitter();
this.ypmTrayImpl = createTray(this.window, this.trayEventEmitter);
this.ypmTrayImpl = createTray(
this.window,
this.trayEventEmitter,
this.store
);
}
// init ipcMain

View File

@@ -319,5 +319,8 @@ export function initIpcMain(win, store, trayEventEmitter) {
ipcMain.on('updateTrayLikeState', (_, isLiked) => {
trayEventEmitter.emit('updateLikeState', isLiked);
});
ipcMain.on('updateTrayIcon', () => {
trayEventEmitter.emit('updateIcon');
});
}
}

View File

@@ -102,10 +102,11 @@ function createMenuTemplate(win) {
// 添加左键支持
// 2022.05.17
class YPMTrayLinuxImpl {
constructor(tray, win, emitter) {
constructor(tray, win, emitter, store) {
this.tray = tray;
this.win = win;
this.emitter = emitter;
this.store = store;
this.template = undefined;
this.initTemplate();
this.contextMenu = Menu.buildFromTemplate(this.template);
@@ -146,14 +147,37 @@ class YPMTrayLinuxImpl {
this.contextMenu.getMenuItemById('unlike').visible = isLiked;
this.tray.setContextMenu(this.contextMenu);
});
this.emitter.on('updateIcon', () => {
this.updateIcon();
});
}
updateIcon() {
let trayIconSetting = this.store.get('settings.trayIconTheme') || 'auto';
let iconTheme;
if (trayIconSetting === 'auto') {
iconTheme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark';
} else {
iconTheme = trayIconSetting;
}
let icon = nativeImage
.createFromPath(path.join(__static, `img/icons/menu-${iconTheme}@88.png`))
.resize({
height: 20,
width: 20,
});
this.tray.setImage(icon);
}
}
class YPMTrayWindowsImpl {
constructor(tray, win, emitter) {
constructor(tray, win, emitter, store) {
this.tray = tray;
this.win = win;
this.emitter = emitter;
this.store = store;
this.template = createMenuTemplate(win);
this.contextMenu = Menu.buildFromTemplate(this.template);
@@ -193,12 +217,39 @@ class YPMTrayWindowsImpl {
isPlaying => (this.isPlaying = isPlaying)
);
this.emitter.on('updateLikeState', isLiked => (this.isLiked = isLiked));
this.emitter.on('updateIcon', () => {
this.updateIcon();
});
}
updateIcon() {
let trayIconSetting = this.store.get('settings.trayIconTheme') || 'auto';
let iconTheme;
if (trayIconSetting === 'auto') {
iconTheme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark';
} else {
iconTheme = trayIconSetting;
}
let icon = nativeImage
.createFromPath(path.join(__static, `img/icons/menu-${iconTheme}@88.png`))
.resize({
height: 20,
width: 20,
});
this.tray.setImage(icon);
}
}
export function createTray(win, eventEmitter) {
// 感觉图标颜色应该不属于界面主题范畴,只需要跟随系统主题
let iconTheme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark';
export function createTray(win, eventEmitter, store) {
let trayIconSetting = store.get('settings.trayIconTheme') || 'auto';
let iconTheme;
if (trayIconSetting === 'auto') {
iconTheme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark';
} else {
iconTheme = trayIconSetting;
}
let icon = nativeImage
.createFromPath(path.join(__static, `img/icons/menu-${iconTheme}@88.png`))
@@ -211,6 +262,6 @@ export function createTray(win, eventEmitter) {
tray.setToolTip('YesPlayMusic');
return isLinux
? new YPMTrayLinuxImpl(tray, win, eventEmitter)
: new YPMTrayWindowsImpl(tray, win, eventEmitter);
? new YPMTrayLinuxImpl(tray, win, eventEmitter, store)
: new YPMTrayWindowsImpl(tray, win, eventEmitter, store);
}

View File

@@ -169,6 +169,12 @@ export default {
light: 'Light',
dark: 'Dark',
},
trayIcon: {
text: 'Tray Icon Color',
auto: 'Auto',
light: 'Light',
dark: 'Dark',
},
automaticallyCacheSongs: 'Automatically cache songs',
clearSongsCache: 'Clear Songs Cache',
cacheCount: 'Cached {song} songs ({size})',

View File

@@ -164,6 +164,12 @@ export default {
light: 'Aydınlık',
dark: 'Karanlık',
},
trayIcon: {
text: 'Tepsi Simgesi Rengi',
auto: 'Otomatik',
light: 'Aydınlık',
dark: 'Karanlık',
},
automaticallyCacheSongs: 'Müzikleri otomatik çerezle',
clearSongsCache: 'Müzik çerezlerini temizle',
cacheCount: 'Çerezlenen {song} Müzikler ({size})',

View File

@@ -170,6 +170,12 @@ export default {
light: '浅色',
dark: '深色',
},
trayIcon: {
text: '托盘图标颜色',
auto: '自动',
light: '浅色',
dark: '深色',
},
automaticallyCacheSongs: '自动缓存歌曲',
clearSongsCache: '清除歌曲缓存',
cacheCount: '已缓存 {song} 首 ({size})',

View File

@@ -166,6 +166,12 @@ export default {
light: '淺色',
dark: '深色',
},
trayIcon: {
text: '工作列圖示顏色',
auto: '自動',
light: '淺色',
dark: '深色',
},
automaticallyCacheSongs: '自動快取歌曲',
clearSongsCache: '清除歌曲快取',
cacheCount: '已快取 {song} 首 ({size})',

View File

@@ -30,6 +30,7 @@ let localStorage = {
showLibraryDefault: false,
subTitleDefault: false,
linuxEnableCustomTitlebar: false,
trayIconTheme: 'auto',
enabledPlaylistCategories,
proxyConfig: {
protocol: 'noProxy',

View File

@@ -56,6 +56,18 @@
</select>
</div>
</div>
<div v-if="isElectron" class="item">
<div class="left">
<div class="title"> {{ $t('settings.trayIcon.text') }} </div>
</div>
<div class="right">
<select v-model="trayIconTheme">
<option value="auto">{{ $t('settings.trayIcon.auto') }}</option>
<option value="light">{{ $t('settings.trayIcon.light') }}</option>
<option value="dark">{{ $t('settings.trayIcon.dark') }}</option>
</select>
</div>
</div>
<div class="item">
<div class="left">
<div class="title">
@@ -907,6 +919,21 @@ export default {
changeAppearance(value);
},
},
trayIconTheme: {
get() {
if (this.settings.trayIconTheme === undefined) return 'auto';
return this.settings.trayIconTheme;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'trayIconTheme',
value,
});
if (this.isElectron) {
ipcRenderer.send('updateTrayIcon', value);
}
},
},
musicQuality: {
get() {
return this.settings.musicQuality ?? 320000;