retrieve mouth dragging on button of main header

This commit is contained in:
sanio 2025-07-11 17:58:31 +09:00
parent 50ffaa0894
commit 2ce82a7edc
4 changed files with 122 additions and 4 deletions

View File

@ -78,6 +78,7 @@ export class ApiKeyHeader extends LitElement {
}
.close-button {
-webkit-app-region: no-drag;
position: absolute;
top: 10px;
right: 10px;
@ -157,6 +158,7 @@ export class ApiKeyHeader extends LitElement {
}
.api-input {
-webkit-app-region: no-drag;
width: 100%;
height: 34px;
background: rgba(255, 255, 255, 0.1);
@ -184,6 +186,7 @@ export class ApiKeyHeader extends LitElement {
.provider-column { flex: 1; display: flex; flex-direction: column; align-items: center; }
.provider-label { color: rgba(255, 255, 255, 0.7); font-size: 11px; font-weight: 500; margin-bottom: 6px; }
.api-input, .provider-select {
-webkit-app-region: no-drag;
width: 100%;
height: 34px;
text-align: center;
@ -210,6 +213,7 @@ export class ApiKeyHeader extends LitElement {
.action-button {
-webkit-app-region: no-drag;
width: 100%;
height: 34px;
background: rgba(255, 255, 255, 0.2);

View File

@ -82,6 +82,7 @@ export class MainHeader extends LitElement {
}
.listen-button {
-webkit-app-region: no-drag;
height: 26px;
padding: 0 13px;
background: transparent;
@ -189,6 +190,7 @@ export class MainHeader extends LitElement {
}
.header-actions {
-webkit-app-region: no-drag;
height: 26px;
box-sizing: border-box;
justify-content: flex-start;
@ -260,6 +262,7 @@ export class MainHeader extends LitElement {
}
.settings-button {
-webkit-app-region: no-drag;
padding: 5px;
border-radius: 50%;
background: transparent;
@ -350,6 +353,61 @@ export class MainHeader extends LitElement {
this.actionText = 'Listen';
this.animationEndTimer = null;
this.handleAnimationEnd = this.handleAnimationEnd.bind(this);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.dragState = null;
this.wasJustDragged = false;
}
async handleMouseDown(e) {
e.preventDefault();
const { ipcRenderer } = window.require('electron');
const initialPosition = await ipcRenderer.invoke('get-header-position');
this.dragState = {
initialMouseX: e.screenX,
initialMouseY: e.screenY,
initialWindowX: initialPosition.x,
initialWindowY: initialPosition.y,
moved: false,
};
window.addEventListener('mousemove', this.handleMouseMove, { capture: true });
window.addEventListener('mouseup', this.handleMouseUp, { once: true, capture: true });
}
handleMouseMove(e) {
if (!this.dragState) return;
const deltaX = Math.abs(e.screenX - this.dragState.initialMouseX);
const deltaY = Math.abs(e.screenY - this.dragState.initialMouseY);
if (deltaX > 3 || deltaY > 3) {
this.dragState.moved = true;
}
const newWindowX = this.dragState.initialWindowX + (e.screenX - this.dragState.initialMouseX);
const newWindowY = this.dragState.initialWindowY + (e.screenY - this.dragState.initialMouseY);
const { ipcRenderer } = window.require('electron');
ipcRenderer.invoke('move-header-to', newWindowX, newWindowY);
}
handleMouseUp(e) {
if (!this.dragState) return;
const wasDragged = this.dragState.moved;
window.removeEventListener('mousemove', this.handleMouseMove, { capture: true });
this.dragState = null;
if (wasDragged) {
this.wasJustDragged = true;
setTimeout(() => {
this.wasJustDragged = false;
}, 0);
}
}
toggleVisibility() {
@ -455,6 +513,7 @@ export class MainHeader extends LitElement {
}
invoke(channel, ...args) {
if (this.wasJustDragged) return;
if (window.require) {
window.require('electron').ipcRenderer.invoke(channel, ...args);
}
@ -462,6 +521,7 @@ export class MainHeader extends LitElement {
}
showSettingsWindow(element) {
if (this.wasJustDragged) return;
if (window.require) {
const { ipcRenderer } = window.require('electron');
console.log(`[MainHeader] showSettingsWindow called at ${Date.now()}`);
@ -481,6 +541,7 @@ export class MainHeader extends LitElement {
}
hideSettingsWindow() {
if (this.wasJustDragged) return;
if (window.require) {
console.log(`[MainHeader] hideSettingsWindow called at ${Date.now()}`);
window.require('electron').ipcRenderer.send('hide-settings-window');
@ -488,6 +549,7 @@ export class MainHeader extends LitElement {
}
async _handleListenClick() {
if (this.wasJustDragged) return;
if (this.isTogglingSession) {
return;
}
@ -536,7 +598,7 @@ export class MainHeader extends LitElement {
const showStopIcon = this.actionText === 'Stop' || this.actionText === 'Done';
return html`
<div class="header">
<div class="header" @mousedown=${this.handleMouseDown}>
<button
class="listen-button ${Object.keys(buttonClasses).filter(k => buttonClasses[k]).join(' ')}"
@click=${this._handleListenClick}

View File

@ -56,6 +56,7 @@ export class PermissionHeader extends LitElement {
}
.close-button {
-webkit-app-region: no-drag;
position: absolute;
top: 10px;
right: 10px;
@ -146,6 +147,7 @@ export class PermissionHeader extends LitElement {
}
.action-button {
-webkit-app-region: no-drag;
width: 100%;
height: 34px;
background: rgba(255, 255, 255, 0.2);
@ -187,6 +189,7 @@ export class PermissionHeader extends LitElement {
}
.continue-button {
-webkit-app-region: no-drag;
width: 100%;
height: 34px;
background: rgba(34, 197, 94, 0.8);

View File

@ -37,8 +37,7 @@ const isLiquidGlassSupported = () => {
}
const majorVersion = parseInt(os.release().split('.')[0], 10);
// return majorVersion >= 25; // macOS 26+ (Darwin 25+)
return majorVersion >= 25; // See you soon!
return majorVersion >= 25; // See you soon!
return majorVersion >= 26; // See you soon!
};
let shouldUseLiquidGlass = isLiquidGlassSupported();
if (shouldUseLiquidGlass) {
@ -395,7 +394,6 @@ function createWindows() {
headerLoadOptions.query = { glass: 'true' };
header.loadFile(path.join(__dirname, '../app/header.html'), headerLoadOptions);
header.webContents.once('did-finish-load', () => {
const viewId = liquidGlass.addView(header.getNativeWindowHandle());
const viewId = liquidGlass.addView(header.getNativeWindowHandle());
if (viewId !== -1) {
liquidGlass.unstable_setVariant(viewId, liquidGlass.GlassMaterialVariant.bubbles);
@ -948,6 +946,57 @@ function setupIpcHandlers(movementManager) {
}
});
// ipcMain.handle('get-header-position', () => {
// const header = windowPool.get('header');
// if (header) {
// const [x, y] = header.getPosition();
// return { x, y };
// }
// return { x: 0, y: 0 };
// });
// ipcMain.handle('move-header', (event, newX, newY) => {
// const header = windowPool.get('header');
// if (header) {
// const currentY = newY !== undefined ? newY : header.getBounds().y;
// header.setPosition(newX, currentY, false);
// updateLayout();
// }
// });
// ipcMain.handle('move-header-to', (event, newX, newY) => {
// const header = windowPool.get('header');
// if (header) {
// const targetDisplay = screen.getDisplayNearestPoint({ x: newX, y: newY });
// const { x: workAreaX, y: workAreaY, width, height } = targetDisplay.workArea;
// const headerBounds = header.getBounds();
// // Only clamp if the new position would actually go out of bounds
// // This prevents progressive restriction of movement
// let clampedX = newX;
// let clampedY = newY;
// // Check if we need to clamp X position
// if (newX < workAreaX) {
// clampedX = workAreaX;
// } else if (newX + headerBounds.width > workAreaX + width) {
// clampedX = workAreaX + width - headerBounds.width;
// }
// // Check if we need to clamp Y position
// if (newY < workAreaY) {
// clampedY = workAreaY;
// } else if (newY + headerBounds.height > workAreaY + height) {
// clampedY = workAreaY + height - headerBounds.height;
// }
// header.setPosition(clampedX, clampedY, false);
// updateLayout();
// }
// });
ipcMain.handle('move-window-step', (event, direction) => {
if (movementManager) {