interactions.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. (function () {
  2. 'use strict';
  3. const petEl = document.getElementById('pet');
  4. const ctxMenu = document.getElementById('context-menu');
  5. const invoke = window.__TAURI__?.core?.invoke;
  6. let dragStartX = 0, dragStartY = 0;
  7. let pressTimer = null;
  8. let isDragging = false;
  9. // ── 右键菜单 ──────────────────────────────
  10. petEl.addEventListener('contextmenu', function (e) {
  11. e.preventDefault();
  12. const x = Math.min(e.clientX, window.innerWidth - 130);
  13. const y = Math.min(e.clientY, window.innerHeight - 100);
  14. ctxMenu.style.left = x + 'px';
  15. ctxMenu.style.top = y + 'px';
  16. ctxMenu.style.display = 'block';
  17. });
  18. document.addEventListener('click', function (e) {
  19. if (!ctxMenu.contains(e.target)) ctxMenu.style.display = 'none';
  20. });
  21. document.addEventListener('keydown', function (e) {
  22. if (e.key === 'Escape') ctxMenu.style.display = 'none';
  23. });
  24. ctxMenu.addEventListener('click', function (e) {
  25. const item = e.target.closest('.item');
  26. if (!item) return;
  27. const action = item.dataset.action;
  28. ctxMenu.style.display = 'none';
  29. if (action === 'settings') invoke?.('open_settings');
  30. else if (action === 'quit') { try { invoke?.('quit_app'); } catch (_) { window.close(); } }
  31. });
  32. // ── 点击 / 长按 / 拖拽 ───────────────────
  33. petEl.addEventListener('mousedown', function (e) {
  34. dragStartX = e.clientX;
  35. dragStartY = e.clientY;
  36. isDragging = false;
  37. pressTimer = setTimeout(() => {
  38. localReact('pet');
  39. if (backendEnabled()) notifyInteract('pet', {});
  40. }, 1500);
  41. });
  42. petEl.addEventListener('mousemove', function (e) {
  43. const dx = e.clientX - dragStartX;
  44. const dy = e.clientY - dragStartY;
  45. if (Math.abs(dx) > 4 || Math.abs(dy) > 4) {
  46. isDragging = true;
  47. clearTimeout(pressTimer);
  48. notifyDragStart();
  49. }
  50. });
  51. petEl.addEventListener('mouseup', function (e) {
  52. clearTimeout(pressTimer);
  53. if (!isDragging) {
  54. localReact('click');
  55. // 未登录 / 离线时不打后端,避免只剩「打卡失败」噪音,仅保留本地互动反馈。
  56. if (backendEnabled()) notifyInteract('click', {});
  57. } else {
  58. notifyDragEnd();
  59. }
  60. });
  61. // 本地即时反馈:不依赖后端也能看到宠物对点击的响应。
  62. function localReact(kind) {
  63. try { if (window.cfcPetAPI && window.cfcPetAPI.react) window.cfcPetAPI.react(kind); } catch (_) { /* noop */ }
  64. }
  65. // 是否已连后端(有令牌)。默认允许,bridge 拉到设置后按 hasToken 修正。
  66. function backendEnabled() {
  67. return window.__petHasToken !== false;
  68. }
  69. function notifyInteract(action, data) {
  70. try {
  71. window.cfcHost.onInteract(action, JSON.stringify(data));
  72. } catch (err) { console.log('[interaction]', action, data); }
  73. }
  74. function notifyDragStart() {
  75. try { window.cfcHost.onDragStart(); } catch (e) { /* noop */ }
  76. }
  77. function notifyDragEnd() {
  78. try { window.cfcHost.onDragEnd(); } catch (e) { /* noop */ }
  79. }
  80. })();