Skip to content
Open
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
14 changes: 14 additions & 0 deletions electron/main/ipc/ipc-taskbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ const initTaskbarIpc = () => {
taskbarLyricManager.setContentWidth(width);
});

ipcMain.on("taskbar:set-ignore-mouse-events", (_event, ignore: boolean) => {
taskbarLyricManager.setMousePassthrough(ignore);
});

ipcMain.handle(TASKBAR_IPC_CHANNELS.GET_OPTION, () => getTaskbarConfig());

// 设置配置(增量合并)
Expand Down Expand Up @@ -104,6 +108,16 @@ const initTaskbarIpc = () => {
taskbarLyricManager.handleFadeDone();
});

// 强制重载歌词窗口
ipcMain.on(TASKBAR_IPC_CHANNELS.FORCE_RELOAD, () => {
const currentConfig = getTaskbarConfig();
if (!currentConfig.enabled) return;
taskbarLyricManager.close(false);
setTimeout(() => {
updateWindowVisibility(currentConfig);
}, 500);
});

// 把事件发射到 app 里不太好,但是我觉得也没有必要为了这一个事件创建一个事件总线
// TODO: 如果有了事件总线,通过那个事件总线发射这个事件
(app as EventEmitter).on("explorer-restarted", () => {
Expand Down
4 changes: 4 additions & 0 deletions electron/main/utils/taskbar-lyric-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ class TaskbarLyricManager {
this.getActive().handleFadeDone();
}

setMousePassthrough(ignore: boolean) {
this.getActive().setMousePassthrough(ignore);
}

send(channel: string, ...args: unknown[]) {
this.getActive().send(channel, ...args);
}
Expand Down
21 changes: 21 additions & 0 deletions electron/main/windows/floating-taskbar-lyric-window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class FloatingTaskbarLyricWindow {
private isFadingOut = false;
private lastFloatingAlign: "left" | "right" | null = null;
private lastAlwaysOnTop: boolean | null = null;
private lastFloatingLock: boolean | null = null;

private debouncedSaveBounds = debounce((bounds: Electron.Rectangle) => {
const store = useStore();
Expand Down Expand Up @@ -73,6 +74,7 @@ class FloatingTaskbarLyricWindow {
if (!this.win) return null;

this.applyAlwaysOnTop(true);
this.applyFloatingLock(true);
this.win.loadURL(floatingTaskbarLyricUrl);

const sendTheme = () => {
Expand Down Expand Up @@ -164,6 +166,15 @@ class FloatingTaskbarLyricWindow {
}
}

private applyFloatingLock(force: boolean) {
if (!this.win || this.win.isDestroyed()) return;
const store = useStore();
const floatingLock = store.get("taskbar.floatingLock", false);
if (!force && this.lastFloatingLock === floatingLock) return;
this.lastFloatingLock = floatingLock;
this.setMousePassthrough(floatingLock);
}

updateLayout(_animate: boolean = false) {
if (!this.win || this.win.isDestroyed()) return;

Expand Down Expand Up @@ -210,6 +221,7 @@ class FloatingTaskbarLyricWindow {
this.win.setBounds({ x: nextX, y: nextY, width: nextWidth, height: nextHeight });

this.applyAlwaysOnTop(false);
this.applyFloatingLock(false);
this.sendFloatingAlign(false);
}

Expand Down Expand Up @@ -249,6 +261,15 @@ class FloatingTaskbarLyricWindow {
}
}

setMousePassthrough(ignore: boolean) {
if (!this.win || this.win.isDestroyed()) return;
if (ignore) {
this.win.setIgnoreMouseEvents(true, { forward: true });
} else {
this.win.setIgnoreMouseEvents(false);
}
}

close() {
if (this.win && !this.win.isDestroyed()) {
this.win.close();
Expand Down
9 changes: 9 additions & 0 deletions electron/main/windows/taskbar-lyric-window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,15 @@ class TaskbarLyricWindow {
}
}

public setMousePassthrough(ignore: boolean) {
if (!this.win || this.win.isDestroyed()) return;
if (ignore) {
this.win.setIgnoreMouseEvents(true, { forward: true });
} else {
this.win.setIgnoreMouseEvents(false);
}
}
Comment on lines +471 to +478
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

setMousePassthrough 方法与 electron/main/windows/floating-taskbar-lyric-window.ts 文件中的实现完全相同。这造成了代码重复。为了提高代码的可维护性,建议可以考虑提取一个基类(例如 BaseTaskbarLyricWindow)来包含这些共享的方法。


public destroy() {
if (this.isNativeDisposed) return;
this.debouncedUpdateLayout.cancel();
Expand Down
42 changes: 42 additions & 0 deletions src/components/Setting/config/lyric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,20 @@ export const useLyricSettings = (): SettingConfig => {
},
}),
},
{
key: "taskbarLyricFloatingLock",
label: "锁定模式",
type: "switch",
description: "开启后鼠标将穿透窗口,关闭后可拖动窗口",
show: () => taskbarLyricConfig.mode === "floating",
value: computed({
get: () => taskbarLyricConfig.floatingLock,
set: (v) => {
taskbarLyricConfig.floatingLock = v ?? false;
saveTaskbarLyricConfig({ floatingLock: taskbarLyricConfig.floatingLock });
},
}),
},
{
key: "taskbarLyricFloatingAutoWidth",
label: "悬浮自动宽度",
Expand Down Expand Up @@ -972,6 +986,19 @@ export const useLyricSettings = (): SettingConfig => {
},
}),
},
{
key: "taskbarLyricHideLyrics",
label: "隐藏歌词",
type: "switch",
description: "开启后仅显示歌名和歌手,不显示歌词内容",
value: computed({
get: () => taskbarLyricConfig.hideLyrics,
set: (v) => {
taskbarLyricConfig.hideLyrics = v ?? false;
saveTaskbarLyricConfig({ hideLyrics: taskbarLyricConfig.hideLyrics });
},
}),
},
{
key: "taskbarLyricUseThemeColor",
label: "跟随封面颜色",
Expand Down Expand Up @@ -1238,6 +1265,21 @@ export const useLyricSettings = (): SettingConfig => {
}),
defaultValue: 0.8,
},
{
key: "taskbarLyricForceReload",
label: "强制重载",
type: "button",
description: "关闭并重新创建任务栏歌词窗口,用于修复显示异常",
buttonLabel: "重载",
action: () => {
if (!statusStore.showTaskbarLyric) {
window.$message.warning("请先开启任务栏歌词");
return;
}
window.electron.ipcRenderer.send(TASKBAR_IPC_CHANNELS.FORCE_RELOAD);
window.$message.success("任务栏歌词已重载");
},
},
{
key: "taskbarLyricRestore",
label: "恢复默认配置",
Expand Down
10 changes: 10 additions & 0 deletions src/types/shared/taskbar-ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export interface TaskbarConfig {
floatingHeight: number;
/** 悬浮置顶 */
floatingAlwaysOnTop: boolean;
/** 悬浮锁定模式 */
floatingLock: boolean;
/** 是否启用 */
enabled: boolean;
/** 暂停时显示 */
Expand Down Expand Up @@ -53,6 +55,8 @@ export interface TaskbarConfig {
mainScale: number;
/** 副歌词缩放比例 */
subScale: number;
/** 隐藏歌词,仅显示歌曲信息 */
hideLyrics: boolean;
}

export interface TrackData {
Expand Down Expand Up @@ -130,6 +134,7 @@ export const DEFAULT_TASKBAR_CONFIG: TaskbarConfig = {
floatingWidth: 300,
floatingHeight: 48,
floatingAlwaysOnTop: false,
floatingLock: false,
enabled: false,
showWhenPaused: true,
showCover: true,
Expand All @@ -144,6 +149,7 @@ export const DEFAULT_TASKBAR_CONFIG: TaskbarConfig = {
lineHeight: 1.1,
mainScale: 1.0,
subScale: 0.8,
hideLyrics: false,
};

export const TASKBAR_IPC_CHANNELS = {
Expand Down Expand Up @@ -171,4 +177,8 @@ export const TASKBAR_IPC_CHANNELS = {
* 渲染进程 -> 主进程 (初始化握手)
*/
REQUEST_DATA: "taskbar:request-data",
/**
* 渲染进程 -> 主进程 (强制重载歌词窗口)
*/
FORCE_RELOAD: "taskbar:force-reload",
} as const;
21 changes: 20 additions & 1 deletion src/views/TaskbarLyric/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const taskbarConfig = reactive<TaskbarConfig>({ ...DEFAULT_TASKBAR_CONFIG });
const isFloating = computed(() => route.query.mode === "floating");
const isHovering = ref(false);
const showControls = computed(() => !isFloating.value && isHovering.value);
let lastMousePassthrough: boolean | null = null;

/**
* 只有当 IPC 时间与本地时间误差超过 250ms 时,才同步 IPC 的时间
Expand Down Expand Up @@ -190,6 +191,14 @@ const handleMouseLeave = () => {
isHovering.value = false;
};

const setMousePassthrough = (ignore: boolean) => {
const ipc = window.electron?.ipcRenderer;
if (!ipc) return;
if (lastMousePassthrough === ignore) return;
lastMousePassthrough = ignore;
ipc.send("taskbar:set-ignore-mouse-events", ignore);
};

const controlAction = (action: "playPrev" | "playOrPause" | "playNext") => {
const ipc = window.electron?.ipcRenderer;
if (!ipc) return;
Expand Down Expand Up @@ -355,7 +364,7 @@ const updateBgCache = () => {
watch(mainLyricIndex, updateBgCache);

const displayItems = computed<DisplayItem[]>(() => {
if (!currentLyricText.value) {
if (taskbarConfig.hideLyrics || !currentLyricText.value) {
return createMetadataItems(state.title, state.artist);
}

Expand Down Expand Up @@ -565,6 +574,15 @@ onMounted(() => {
const ipc = window.electron?.ipcRenderer;
if (!ipc) return;

if (isFloating.value) {
setMousePassthrough(taskbarConfig.floatingLock);
watch(
() => taskbarConfig.floatingLock,
(v) => setMousePassthrough(v),
{ immediate: true },
);
Comment on lines +578 to +583
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

setMousePassthrough 的调用是多余的。由于 watch 配置了 { immediate: true }setMousePassthrough 会在侦听器创建时立即用初始值调用一次。因此,watch 前面的 setMousePassthrough(taskbarConfig.floatingLock); 调用是多余的,可以安全地移除。

    watch(
      () => taskbarConfig.floatingLock,
      (v) => setMousePassthrough(v),
      { immediate: true },
    );

}

ipc.on(TASKBAR_IPC_CHANNELS.SYNC_STATE, (_, payload: SyncStatePayload) => {
switch (payload.type) {
case "full-hydration": {
Expand Down Expand Up @@ -698,6 +716,7 @@ $radius: 4px;
margin: 5px 0;
padding: 0 0.9em;
box-sizing: border-box;
position: relative;
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

这个 position: relative 属性似乎是多余的。在其子元素中,需要绝对定位的元素(如 .cover 或歌词动画项)已经被包裹在设置了 position: relative 的容器中(例如 .cover-wrapper, .content, .lyric-list-wrapper)。因此,在顶层元素 .taskbar-lyric 上添加此属性显得多余。如果它没有特殊用途,建议移除以保持 CSS 的整洁。

display: flex;
align-items: center;
justify-content: flex-start;
Expand Down
Loading