|
261 | 261 | var compactSurfacePendingModelOpen = false; |
262 | 262 | var compactSurfaceResizeSession = null; |
263 | 263 | var compactSurfaceDesktopResizeActive = false; |
| 264 | + var compactSurfaceDesktopDragActive = false; |
| 265 | + var IDLE_CAT1_COMPACT_MIRROR_TIMEOUT_MS = 1600; |
| 266 | + var idleCat1CompactMirrorElement = null; |
| 267 | + var idleCat1CompactMirrorTimer = 0; |
| 268 | + var idleCat1CompactMirrorLastDetail = null; |
264 | 269 |
|
265 | 270 | function normalizeCompactDesktopRect(raw) { |
266 | 271 | if (!raw) return null; |
|
306 | 311 | } |
307 | 312 |
|
308 | 313 | function handleDesktopCompactLayoutChange(layout) { |
| 314 | + compactSurfaceDesktopDragActive = !!(layout && layout.dragging); |
309 | 315 | var nextAnchorSnapshot = getCompactDesktopLayoutAnchorSnapshot(layout); |
310 | 316 | var baseAnchorChanged = false; |
311 | 317 | if (!nextAnchorSnapshot) { |
|
641 | 647 | }; |
642 | 648 | } |
643 | 649 |
|
| 650 | + function getIdleCat1CompactMirrorElement() { |
| 651 | + if (idleCat1CompactMirrorElement && idleCat1CompactMirrorElement.isConnected) { |
| 652 | + return idleCat1CompactMirrorElement; |
| 653 | + } |
| 654 | + var host = document.body; |
| 655 | + if (!host) return null; |
| 656 | + var element = document.createElement('div'); |
| 657 | + element.id = 'neko-idle-cat1-compact-mirror'; |
| 658 | + element.className = 'neko-idle-cat1-compact-mirror'; |
| 659 | + element.setAttribute('data-compact-geometry-owner', 'surface'); |
| 660 | + element.setAttribute('data-compact-geometry-item', 'cat1Mirror'); |
| 661 | + element.setAttribute('aria-hidden', 'true'); |
| 662 | + element.hidden = true; |
| 663 | + var image = document.createElement('img'); |
| 664 | + image.className = 'neko-idle-cat1-compact-mirror-art'; |
| 665 | + image.alt = ''; |
| 666 | + image.draggable = false; |
| 667 | + element.appendChild(image); |
| 668 | + host.appendChild(element); |
| 669 | + idleCat1CompactMirrorElement = element; |
| 670 | + return element; |
| 671 | + } |
| 672 | + |
| 673 | + function clearIdleCat1CompactMirrorTimer() { |
| 674 | + if (!idleCat1CompactMirrorTimer) return; |
| 675 | + window.clearTimeout(idleCat1CompactMirrorTimer); |
| 676 | + idleCat1CompactMirrorTimer = 0; |
| 677 | + } |
| 678 | + |
| 679 | + function hideIdleCat1CompactMirror(reason) { |
| 680 | + clearIdleCat1CompactMirrorTimer(); |
| 681 | + var element = idleCat1CompactMirrorElement; |
| 682 | + if (element) { |
| 683 | + element.hidden = true; |
| 684 | + element.removeAttribute('data-active'); |
| 685 | + element.style.removeProperty('left'); |
| 686 | + element.style.removeProperty('top'); |
| 687 | + element.style.removeProperty('width'); |
| 688 | + element.style.removeProperty('height'); |
| 689 | + } |
| 690 | + idleCat1CompactMirrorLastDetail = null; |
| 691 | + scheduleCompactMinimizeBallTracking(); |
| 692 | + syncCompactInteractionGeometry(); |
| 693 | + } |
| 694 | + |
| 695 | + function getIdleCat1CompactMirrorWindowBounds() { |
| 696 | + var windowBounds = getCompactSurfaceDesktopWindowBounds(); |
| 697 | + if (windowBounds) return windowBounds; |
| 698 | + var x = Number(window.screenX); |
| 699 | + var y = Number(window.screenY); |
| 700 | + return { |
| 701 | + x: Number.isFinite(x) ? x : 0, |
| 702 | + y: Number.isFinite(y) ? y : 0 |
| 703 | + }; |
| 704 | + } |
| 705 | + |
| 706 | + function getIdleCat1CompactMirrorPageRect(detail) { |
| 707 | + var surface = normalizeCompactDesktopRect(detail && detail.surfaceScreenRect); |
| 708 | + if (!surface) return null; |
| 709 | + var catRect = detail && detail.catRect ? detail.catRect : null; |
| 710 | + var catWidth = Math.round(Number(catRect && catRect.width) || 112); |
| 711 | + var catHeight = Math.round(Number(catRect && catRect.height) || 112); |
| 712 | + if (catWidth <= 0 || catHeight <= 0) return null; |
| 713 | + var windowBounds = getIdleCat1CompactMirrorWindowBounds(); |
| 714 | + var surfaceLeft = surface.left - (Number(windowBounds.x) || 0); |
| 715 | + var surfaceTop = surface.top - (Number(windowBounds.y) || 0); |
| 716 | + var sidePadding = Math.max(0, Number(detail && detail.sidePaddingPx) || 12); |
| 717 | + var capInset = Math.max(sidePadding, surface.height / 2 + sidePadding); |
| 718 | + var edgePadding = Math.min(capInset, Math.max(0, surface.width / 2)); |
| 719 | + var minCenterX = surfaceLeft + edgePadding; |
| 720 | + var maxCenterX = surfaceLeft + surface.width - edgePadding; |
| 721 | + var ratio = Number(detail && detail.anchorRatio); |
| 722 | + if (!Number.isFinite(ratio)) ratio = 0.5; |
| 723 | + ratio = Math.max(0, Math.min(1, ratio)); |
| 724 | + var centerX = maxCenterX >= minCenterX |
| 725 | + ? minCenterX + (maxCenterX - minCenterX) * ratio |
| 726 | + : surfaceLeft + surface.width / 2; |
| 727 | + var overlap = Number(detail && detail.overlapPx); |
| 728 | + if (!Number.isFinite(overlap)) overlap = 28; |
| 729 | + return { |
| 730 | + left: Math.round(centerX - catWidth / 2), |
| 731 | + top: Math.round(surfaceTop - catHeight + overlap), |
| 732 | + width: catWidth, |
| 733 | + height: catHeight |
| 734 | + }; |
| 735 | + } |
| 736 | + |
| 737 | + function showIdleCat1CompactMirror(detail) { |
| 738 | + var element = getIdleCat1CompactMirrorElement(); |
| 739 | + var rect = getIdleCat1CompactMirrorPageRect(detail); |
| 740 | + if (!element || !rect) { |
| 741 | + hideIdleCat1CompactMirror('invalid'); |
| 742 | + return; |
| 743 | + } |
| 744 | + idleCat1CompactMirrorLastDetail = Object.assign({}, detail || {}); |
| 745 | + var image = element.querySelector('.neko-idle-cat1-compact-mirror-art'); |
| 746 | + if (image) { |
| 747 | + var src = detail && detail.assetUrl ? String(detail.assetUrl) : '/static/assets/neko-idle/cat-idle-cat1.gif'; |
| 748 | + if (image.getAttribute('src') !== src) image.setAttribute('src', src); |
| 749 | + image.style.transform = detail && detail.facingRight ? 'scaleX(-1)' : 'scaleX(1)'; |
| 750 | + } |
| 751 | + element.style.left = rect.left + 'px'; |
| 752 | + element.style.top = rect.top + 'px'; |
| 753 | + element.style.width = rect.width + 'px'; |
| 754 | + element.style.height = rect.height + 'px'; |
| 755 | + element.hidden = false; |
| 756 | + element.setAttribute('data-active', 'true'); |
| 757 | + clearIdleCat1CompactMirrorTimer(); |
| 758 | + idleCat1CompactMirrorTimer = window.setTimeout(function () { |
| 759 | + hideIdleCat1CompactMirror('timeout'); |
| 760 | + }, IDLE_CAT1_COMPACT_MIRROR_TIMEOUT_MS); |
| 761 | + scheduleCompactMinimizeBallTracking(); |
| 762 | + syncCompactInteractionGeometry(); |
| 763 | + } |
| 764 | + |
| 765 | + function refreshIdleCat1CompactMirrorPosition() { |
| 766 | + var element = idleCat1CompactMirrorElement; |
| 767 | + if (!element || element.hidden || !idleCat1CompactMirrorLastDetail) return; |
| 768 | + var rect = getIdleCat1CompactMirrorPageRect(idleCat1CompactMirrorLastDetail); |
| 769 | + if (!rect) return; |
| 770 | + element.style.left = rect.left + 'px'; |
| 771 | + element.style.top = rect.top + 'px'; |
| 772 | + element.style.width = rect.width + 'px'; |
| 773 | + element.style.height = rect.height + 'px'; |
| 774 | + syncCompactInteractionGeometry(); |
| 775 | + } |
| 776 | + |
| 777 | + function handleIdleCat1CompactMirrorState(event) { |
| 778 | + var detail = event && event.detail && typeof event.detail === 'object' ? event.detail : null; |
| 779 | + if (!detail || !detail.active) { |
| 780 | + hideIdleCat1CompactMirror(detail && detail.reason ? detail.reason : 'inactive'); |
| 781 | + return; |
| 782 | + } |
| 783 | + showIdleCat1CompactMirror(detail); |
| 784 | + } |
| 785 | + |
644 | 786 | function dispatchCompactSurfaceLayoutChange(rect) { |
645 | 787 | var detail = rect || null; |
646 | 788 | if (detail && isElectronChatWindow()) { |
|
649 | 791 | resizeActive: !!compactSurfaceResizeSession |
650 | 792 | }); |
651 | 793 | } |
| 794 | + if (detail) { |
| 795 | + detail = Object.assign({}, detail, { |
| 796 | + dragging: !!(dragState && dragState.compactSurface) || compactSurfaceDesktopDragActive |
| 797 | + }); |
| 798 | + } |
652 | 799 | window.dispatchEvent(new CustomEvent('neko:compact-surface-layout-change', { |
653 | 800 | detail: detail |
654 | 801 | })); |
|
1018 | 1165 | var item = element.getAttribute('data-compact-geometry-item') || ''; |
1019 | 1166 | if (item === 'choice' && element.getAttribute('data-choice-layer-open') !== 'true') return false; |
1020 | 1167 | if (item === 'toolFan' && element.getAttribute('data-compact-input-tool-fan-open') !== 'true') return false; |
1021 | | - if (element.getAttribute('aria-hidden') === 'true' && item !== 'resizeHandle') return false; |
| 1168 | + if (element.getAttribute('aria-hidden') === 'true' && item !== 'resizeHandle' && item !== 'cat1Mirror') return false; |
1022 | 1169 | var style = window.getComputedStyle ? window.getComputedStyle(element) : null; |
1023 | 1170 | if (style && (style.display === 'none' || style.visibility === 'hidden')) return false; |
1024 | 1171 | return true; |
|
1275 | 1422 | !root.contains(element) |
1276 | 1423 | && !element.classList.contains('compact-input-tool-fan') |
1277 | 1424 | && !element.classList.contains('compact-chat-choice-anchor') |
| 1425 | + && !element.classList.contains('neko-idle-cat1-compact-mirror') |
1278 | 1426 | ) return items; |
1279 | 1427 | if (!shouldIncludeCompactGeometryElement(element)) return items; |
1280 | 1428 | var compactGeometryItem = element.getAttribute('data-compact-geometry-item'); |
1281 | 1429 | if (compactGeometryItem === 'toolFan') { |
1282 | 1430 | return items.concat(collectCompactToolFanGeometryItems(element)); |
1283 | 1431 | } |
| 1432 | + if (compactGeometryItem === 'cat1Mirror') { |
| 1433 | + var mirrorRect = getCompactGeometryElementRect(element); |
| 1434 | + if (mirrorRect) { |
| 1435 | + items.push({ |
| 1436 | + id: 'cat1Mirror:native', |
| 1437 | + owner: 'surface', |
| 1438 | + kind: 'cat1Mirror', |
| 1439 | + visualRect: mirrorRect, |
| 1440 | + hitRect: null, |
| 1441 | + nativeRect: mirrorRect, |
| 1442 | + interactive: false |
| 1443 | + }); |
| 1444 | + } |
| 1445 | + return items; |
| 1446 | + } |
1284 | 1447 | if (element.getAttribute('data-compact-geometry-hit-scope') === 'children') { |
1285 | 1448 | return items.concat(collectCompactCompositeGeometryItems(element, compactGeometryItem)); |
1286 | 1449 | } |
|
1409 | 1572 | Math.round(target.left), |
1410 | 1573 | Math.round(target.top), |
1411 | 1574 | Math.round(target.width), |
1412 | | - Math.round(target.height || COMPACT_SURFACE_DEFAULT_HEIGHT) |
| 1575 | + Math.round(target.height || COMPACT_SURFACE_DEFAULT_HEIGHT), |
| 1576 | + (!!(dragState && dragState.compactSurface) || compactSurfaceDesktopDragActive) ? 'dragging' : 'idle' |
1413 | 1577 | ].join(':'); |
1414 | 1578 | if (snapshot === compactSurfaceAnchorSnapshot) { |
1415 | 1579 | return; |
|
4746 | 4910 | cancelActiveAnimation(); // 清理进行中的折叠/展开回调 |
4747 | 4911 | clearIdleDockState(); |
4748 | 4912 | deactivateToolCursor(); |
| 4913 | + hideIdleCat1CompactMirror('close-window'); |
4749 | 4914 |
|
4750 | 4915 | // 如果当前处于最小化状态,恢复 shell 到正常态 |
4751 | 4916 | if (minimized) { |
|
4860 | 5025 | var changedTouch = opts.changedTouches && opts.changedTouches.length > 0 ? opts.changedTouches[0] : null; |
4861 | 5026 |
|
4862 | 5027 | var wasMoved = dragState.moved; |
| 5028 | + var wasCompactSurface = !!dragState.compactSurface; |
4863 | 5029 |
|
4864 | 5030 | var shell = getShell(); |
4865 | 5031 | if (shell) { |
|
4872 | 5038 |
|
4873 | 5039 | dragState = null; |
4874 | 5040 | document.body.classList.remove('react-chat-window-dragging'); |
| 5041 | + if (wasCompactSurface && wasMoved) { |
| 5042 | + var compactRect = getCurrentCompactSurfaceRect(); |
| 5043 | + if (compactRect) { |
| 5044 | + dispatchCompactSurfaceLayoutChange(compactRect); |
| 5045 | + } |
| 5046 | + } |
4875 | 5047 |
|
4876 | 5048 | // 移动过的拖拽不该再变成点击:吞掉 mouseup 落点补发的那一次 click。 |
4877 | 5049 | if (wasMoved) { |
|
5452 | 5624 | if (!detail) return; |
5453 | 5625 | scheduleElectronCat1PairMoveBounds(detail.screenRect || detail.bounds); |
5454 | 5626 | }); |
| 5627 | + window.addEventListener('neko:idle-cat1-compact-mirror-state', handleIdleCat1CompactMirrorState); |
5455 | 5628 | window.addEventListener('live2d-return-click', function () { |
5456 | 5629 | if (hasElectronIdleDockPendingOrActive()) { exitElectronIdleDock(); } |
5457 | 5630 | if (hasIdleDockPendingOrActive()) { exitIdleDock(); return; } |
|
5471 | 5644 | window.addEventListener('neko:desktop-compact-layout-change', function (event) { |
5472 | 5645 | var layout = event && event.detail ? event.detail : window.__nekoDesktopCompactLayout; |
5473 | 5646 | handleDesktopCompactLayoutChange(layout || null); |
| 5647 | + refreshIdleCat1CompactMirrorPosition(); |
5474 | 5648 | }); |
5475 | 5649 | if (window.__nekoDesktopCompactLayout) { |
5476 | 5650 | handleDesktopCompactLayoutChange(window.__nekoDesktopCompactLayout); |
|
0 commit comments