File size: 3,577 Bytes
89a2873
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

import { createSignal } from "solid-js"

const OS_NAME = (() => {
  if (navigator.userAgent.includes("Mac")) return "macos"
  if (navigator.userAgent.includes("Windows")) return "windows"
  if (navigator.userAgent.includes("Linux")) return "linux"
  return "unknown"
})()

const [webviewZoom, setWebviewZoom] = createSignal(1)
let requestedZoom = 1
let pinchZoomEnabled = false
let wheelPinch = undefined as
  | {
      active: boolean
      startZoom: number
      totalDelta: number
      timeout: ReturnType<typeof setTimeout> | undefined
    }
  | undefined

const MAX_ZOOM_LEVEL = 10
const MIN_ZOOM_LEVEL = 0.2
const WHEEL_PINCH_THRESHOLD = 20
const WHEEL_PINCH_STEP = 0.2
const WHEEL_PINCH_END_DELAY = 160

const clamp = (value: number) => Math.min(Math.max(value, MIN_ZOOM_LEVEL), MAX_ZOOM_LEVEL)

const applyZoom = (next: number) => {
  requestedZoom = next
  void window.api
    .setZoomFactor(next)
    .then(() => {
      if (requestedZoom !== next) return
      setWebviewZoom(next)
    })
    .catch(() => {
      if (requestedZoom !== next) return
      requestedZoom = webviewZoom()
    })
}

window.api.onZoomFactorChanged((factor) => {
  requestedZoom = clamp(factor)
  setWebviewZoom(requestedZoom)
})

void window.api.getPinchZoomEnabled().then((enabled) => {
  pinchZoomEnabled = enabled
})

window.api.onPinchZoomEnabledChanged((enabled) => {
  pinchZoomEnabled = enabled
  resetWheelPinch()
})

const setPinchZoomEnabled = (enabled: boolean) => {
  pinchZoomEnabled = enabled
  resetWheelPinch()
  return window.api.setPinchZoomEnabled(enabled)
}

const resetZoom = () => applyZoom(1)
const zoomIn = () => applyZoom(clamp(requestedZoom + 0.2))
const zoomOut = () => applyZoom(clamp(requestedZoom - 0.2))

const resetWheelPinch = () => {
  clearTimeout(wheelPinch?.timeout)
  wheelPinch = undefined
}

const normalizeWheelDelta = (event: WheelEvent) => {
  if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) return event.deltaY * 16
  if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) return event.deltaY * window.innerHeight
  return event.deltaY
}

const updateWheelPinch = (event: WheelEvent) => {
  wheelPinch ??= {
    active: false,
    startZoom: requestedZoom,
    totalDelta: 0,
    timeout: undefined,
  }

  clearTimeout(wheelPinch.timeout)
  wheelPinch.timeout = setTimeout(resetWheelPinch, WHEEL_PINCH_END_DELAY)
  wheelPinch.totalDelta += normalizeWheelDelta(event)

  if (!wheelPinch.active && Math.abs(wheelPinch.totalDelta) < WHEEL_PINCH_THRESHOLD) return
  if (!wheelPinch.active) {
    wheelPinch.active = true
    wheelPinch.startZoom = requestedZoom
    wheelPinch.totalDelta = 0
    return
  }

  wheelPinch.active = true
  applyZoom(clamp(wheelPinch.startZoom - (wheelPinch.totalDelta / WHEEL_PINCH_THRESHOLD) * WHEEL_PINCH_STEP))
}

window.addEventListener(
  "wheel",
  (event) => {
    if (!pinchZoomEnabled) return
    if (!event.ctrlKey) return

    event.preventDefault()
    updateWheelPinch(event)
  },
  { passive: false },
)

window.addEventListener("keydown", (event) => {
  if (!(OS_NAME === "macos" ? event.metaKey : event.ctrlKey)) return

  if (event.key === "-") {
    event.preventDefault()
    zoomOut()
    return
  }
  if (event.key === "=" || event.key === "+") {
    event.preventDefault()
    zoomIn()
    return
  }
  if (event.key === "0") {
    event.preventDefault()
    resetZoom()
  }
})

export { webviewZoom, resetZoom, setPinchZoomEnabled, zoomIn, zoomOut }