@@ -25,48 +25,64 @@ import kotlin.js.js
2525import kotlin.js.toJsArray
2626import kotlin.js.toJsNumber
2727
28+ @OptIn(ExperimentalWasmJsInterop ::class )
2829internal class WebHapticFeedback : HapticFeedback {
29- @OptIn(ExperimentalWasmJsInterop ::class )
30+ // Check if API is supported before doing anything
31+ private val isVibrationSupported = isVibrationSupported()
32+
33+ // Declare these hardcoded patterns to avoid js-interop on every call
34+ private val ConfirmVibrationPattern : JsArray <JsNumber > = vibrationPatternOf(18 , 32 , 36 )
35+ private val RejectVibrationPattern : JsArray <JsNumber > = vibrationPatternOf(18 , 28 , 18 , 28 , 18 )
36+ private val SinglePulseVibrationPattern : JsArray <JsNumber > = vibrationPatternOf(12 )
37+ private val SoftTickVibrationPattern : JsArray <JsNumber > = vibrationPatternOf(6 )
38+
3039 override fun performHapticFeedback (hapticFeedbackType : HapticFeedbackType ) {
31- vibrate(vibrationPatternFor(hapticFeedbackType))
40+ if (! isVibrationSupported) return
41+ val pattern = vibrationPatternFor(hapticFeedbackType) ? : return
42+ vibrate(pattern)
3243 }
33- }
3444
35- // TODO: to eventually avoid the hardcoded values, follow the new browser API proposal https://github.com/WICG/web-haptics
36- // and rely on it once it's implemented
37- @OptIn(ExperimentalWasmJsInterop ::class )
38- internal fun vibrationPatternFor (hapticFeedbackType : HapticFeedbackType ): JsArray <JsNumber > =
39- when (hapticFeedbackType) {
40- HapticFeedbackType .Confirm -> vibrationPatternOf(18 , 32 , 36 )
41- HapticFeedbackType .Reject -> vibrationPatternOf(18 , 28 , 18 , 28 , 18 )
42- HapticFeedbackType .ContextClick ,
43- HapticFeedbackType .GestureEnd ,
44- HapticFeedbackType .GestureThresholdActivate ,
45- HapticFeedbackType .LongPress ,
46- HapticFeedbackType .ToggleOff ,
47- HapticFeedbackType .ToggleOn ,
48- HapticFeedbackType .VirtualKey -> vibrationPatternOf(12 )
49- HapticFeedbackType .KeyboardTap ,
50- HapticFeedbackType .SegmentFrequentTick ,
51- HapticFeedbackType .SegmentTick ,
52- HapticFeedbackType .TextHandleMove -> vibrationPatternOf(6 )
53- else -> vibrationPatternOf(12 )
45+ // We don't have a high-level browser API right now. So we hardcode the patterns here.
46+ // TODO: to eventually avoid the hardcoded values, follow the new browser API proposal https://github.com/WICG/web-haptics
47+ // and rely on it once it's implemented
48+ @OptIn(ExperimentalWasmJsInterop ::class )
49+ internal fun vibrationPatternFor (hapticFeedbackType : HapticFeedbackType ): JsArray <JsNumber >? {
50+ return when (hapticFeedbackType) {
51+ HapticFeedbackType .Confirm -> ConfirmVibrationPattern
52+ HapticFeedbackType .Reject -> RejectVibrationPattern
53+ HapticFeedbackType .ContextClick ,
54+ HapticFeedbackType .GestureEnd ,
55+ HapticFeedbackType .GestureThresholdActivate ,
56+ HapticFeedbackType .LongPress ,
57+ HapticFeedbackType .ToggleOff ,
58+ HapticFeedbackType .ToggleOn ,
59+ HapticFeedbackType .VirtualKey -> SinglePulseVibrationPattern
60+ HapticFeedbackType .KeyboardTap ,
61+ HapticFeedbackType .SegmentFrequentTick ,
62+ HapticFeedbackType .SegmentTick -> SoftTickVibrationPattern
63+ HapticFeedbackType .TextHandleMove -> null
64+ else -> null
65+ }
5466 }
67+ }
5568
5669@OptIn(ExperimentalWasmJsInterop ::class )
5770private fun vibrationPatternOf (vararg durations : Int ): JsArray <JsNumber > =
5871 durations.map { it.toDouble().toJsNumber() }.toJsArray()
5972
73+ @OptIn(ExperimentalWasmJsInterop ::class )
74+ private fun isVibrationSupported (): Boolean = js(
75+ // language=javascript
76+ """
77+ typeof window !== 'undefined' &&
78+ window.navigator != null &&
79+ typeof window.navigator.vibrate === 'function'
80+ """
81+ )
82+
6083// language=javascript
6184@OptIn(ExperimentalWasmJsInterop ::class )
6285private fun vibrate (pattern : JsArray <JsNumber >) {
63- js(
64- """
65- if (typeof window !== 'undefined' &&
66- window.navigator != null &&
67- typeof window.navigator.vibrate === 'function') {
68- window.navigator.vibrate(pattern)
69- }
70- """
71- )
86+ // Assuming the API support has been checked in advance, we can safely call it
87+ js(" window.navigator.vibrate(pattern)" )
7288}
0 commit comments