8000 fix(useWakeLock): should delay wake lock request if document is hidde… · vueuse/vueuse@5ca57d0 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Commit 5ca57d0

Browse files
authored
fix(useWakeLock): should delay wake lock request if document is hidden (#4055)
1 parent f8e862b commit 5ca57d0

File tree

3 files changed

+138
-59
lines changed

3 files changed

+138
-59
lines changed

packages/core/useWakeLock/index.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ Reactive [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API
1111
```js
1212
import { useWakeLock } from '@vueuse/core'
1313

14-
const { isSupported, isActive, request, release } = useWakeLock()
14+
const { isSupported, isActive, forceRequest, request, release } = useWakeLock()
1515
```
1616

17-
If `request` is called,` isActive` will be **true**, and if `release` is called, or other tab is displayed, or the window is minimized,`isActive` will be **false**.
17+
When `request` is called, the wake lock will be requested if the document is visible. Otherwise, the request will be queued until the document becomes visible. If the request is successful, `isActive` will be **true**. Whenever the document is hidden, the `isActive` will be **false**.
18+
19+
When `release` is called, the wake lock will be released. If there is a queued request, it will be canceled.
20+
21+
To request a wake lock immediately, even if the document is hidden, use `forceRequest`. Note that this may throw an error if the document is hidden.

packages/core/useWakeLock/index.test.ts

Lines changed: 98 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@ import { describe, expect, it } from 'vitest'
44
import type { WakeLockSentinel } from '.'
55
import { useWakeLock } from '.'
66

7+
class MockWakeLockSentinel extends EventTarget {
8+
released = false
9+
release() {
10+
this.released = true
11+
return Promise.resolve()
12+
}
13+
}
14+
function defineWakeLockAPI() {
15+
const sentinel = new MockWakeLockSentinel()
16+
Object.defineProperty(navigator, 'wakeLock', {
17+
value: { request: async () => sentinel as WakeLockSentinel },
18+
writable: true,
19+
})
20+
return sentinel
21+
}
22+
23+
class MockDocument extends EventTarget {
24+
visibilityState = 'hidden'
25+
}
26+
727
describe('useWakeLock', () => {
828
it('isActive not changed if not supported', async () => {
929
const { isActive, request, release } = useWakeLock({ navigator: {} as Navigator })
@@ -20,28 +40,13 @@ describe('useWakeLock', () => {
2040
})
2141

2242
it('isActive changed if supported', async () => {
23-
const createWakeLock = () => {
24-
let _released = false
25-
return {
26-
get released() {
27-
return _released
28-
},
29-
release: () => {
30-
_released = true
31-
return Promise.resolve()
32-
},
33-
} as WakeLockSentinel
34-
}
35-
36-
Object.defineProperty(navigator, 'wakeLock', {
37-
value: { request: () => createWakeLock() },
38-
writable: true,
39-
})
40-
const { isActive, request, release } = useWakeLock()
43+
defineWakeLockAPI()
44+
45+
const { isActive, forceRequest, release } = useWakeLock()
4146

4247
expect(isActive.value).toBeFalsy()
4348

44-
await request('screen')
49+
await forceRequest('screen')
4550

4651
expect(isActive.value).toBeTruthy()
4752

@@ -51,23 +56,8 @@ describe('useWakeLock', () => {
5156
})
5257

5358
it('isActive changed if show other tabs or minimize window', async () => {
54-
const createWakeLock = () => {
55-
let _released = false
56-
return {
57-
get released() {
58-
return _released
59-
},
60-
release: () => {
61-
_released = true
62-
return Promise.resolve()
63-
},
64-
} as WakeLockSentinel
65-
}
66-
67-
Object.defineProperty(navigator, 'wakeLock', {
68-
value: { request: () => createWakeLock() },
69-
writable: true,
70-
})
59+
defineWakeLockAPI()
60+
7161
const { isActive, request } = useWakeLock()
7262

7363
expect(isActive.value).toBeFalsy()
@@ -83,4 +73,76 @@ describe('useWakeLock', () => {
8373

8474
expect(isActive.value).toBeTruthy()
8575
})
76+
77+
it('it should delay requesting if document is hidden', async () => {
78+
defineWakeLockAPI()
79+
const mockDocument = new MockDocument()
80+
81+
const { isActive, request } = useWakeLock({ document: mockDocument as Document })
82+
83+
await request('screen')
84+
85+
expect(isActive.value).toBeFalsy()
86+
87+
mockDocument.visibilityState = 'visible'
88+
mockDocument.dispatchEvent(new Event('visibilitychange'))
89+
90+
await nextTick()
91+
await nextTick()
92+
93+
expect(isActive.value).toBeTruthy()
94+
})
95+
96+
it('it should cancel requesting if released is called before document become visible', async () => {
97+
defineWakeLockAPI()
98+
const mockDocument = new MockDocument()
99+
100+
const { isActive, request, release } = useWakeLock({ document: mockDocument as Document })
101+
102+
await request('screen')
103+
104+
expect(isActive.value).toBeFalsy()
105+
106+
await release()
107+
108+
expect(isActive.value).toBeFalsy()
109+
110+
mockDocument.visibilityState = 'visible'
111+
mockDocument.dispatchEvent(new Event('visibilitychange'))
112+
113+
await nextTick()
114+
await nextTick()
115+
116+
expect(isActive.value).toBeFalsy()
117+
})
118+
119+
it('it should be inactive if wake lock is released for some reasons', async () => {
120+
const sentinel = defineWakeLockAPI()
121+
const mockDocument = new MockDocument()
122+
mockDocument.visibilityState = 'visible'
123+
124+
const { isActive, request } = useWakeLock({ document: mockDocument as Document })
125+
126+
await request('screen')
127+
128+
expect(isActive.value).toBeTruthy()
129+
130+
mockDocument.visibilityState = 'hidden'
131+
mockDocument.dispatchEvent(new Event('visibilitychange'))
132+
sentinel.dispatchEvent(new Event('release'))
133+
134+
await nextTick()
135+
await nextTick()
136+
137+
expect(isActive.value).toBeFalsy()
138+
139+
mockDocument.visibilityState = 'visible'
140+
mockDocument.dispatchEvent(new Event('visibilitychange'))
141+
await request('screen')
142+
143+
await nextTick()
144+
await nextTick()
145+
146+
expect(isActive.value).toBeTruthy()
147+
})
86148
})

packages/core/useWakeLock/index.ts

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { ref } from 'vue-demi'
1+
import { computed, ref, shallowRef } from 'vue-demi'
2+
import { whenever } from '@vueuse/shared'
23
import { useEventListener } from '../useEventListener'
34
import { useSupported } from '../useSupported'
45
import type { ConfigurableDocument, ConfigurableNavigator } from '../_configurable'
56
import { defaultDocument, defaultNavigator } from '../_configurable'
7+
import { useDocumentVisibility } from '../useDocumentVisibility'
68

79
type WakeLockType = 'screen'
810

@@ -29,42 +31,53 @@ export function useWakeLock(options: UseWakeLockOptions = {}) {
2931
navigator = defaultNavigator,
3032
document = defaultDocument,
3133
} = options
32-
let wakeLock: WakeLockSentinel | null
34+
const requestedType = ref<WakeLockType | false>(false)
35+
const sentinel = shallowRef<WakeLockSentinel | null>(null)
36+
const documentVisibility = useDocumentVisibility({ document })
3337
const isSupported = useSupported(() => navigator && 'wakeLock' in navigator)
34-
const isActive = ref(false)
38+
const isActive = computed(() => !!sentinel.value && documentVisibility.value === 'visible')
3539

36-
async function onVisibilityChange() {
37-
if (!isSupported.value || !wakeLock)
38-
return
40+
if (isSupported.value) {
41+
useEventListener(sentinel, 'release', () => {
42+
requestedType.value = sentinel.value?.type ?? false
43+
})
3944

40-
if (document && document.visibilityState === 'visible')
41-
wakeLock = await (navigator as NavigatorWithWakeLock).wakeLock.request('screen')
42-
43-
isActive.value = !wakeLock.released
45+
whenever(
46+
() => documentVisibility.value === 'visible' && document?.visibilityState === 'visible' && requestedType.value,
47+
(type) => {
48+
requestedType.value = false
49+
forceRequest(type)
50+
},
51+
)
4452
}
4553

46-
if (document)
47-
useEventListener(document, 'visibilitychange', onVisibilityChange, { passive: true })
54+
async function forceRequest(type: WakeLockType) {
55+
await sentinel.value?.release()
56+
sentinel.value = isSupported.value
57+
? await (navigator as NavigatorWithWakeLock).wakeLock.request(type)
58+
: null
59+
}
4860

4961
async function request(type: WakeLockType) {
50-
if (!isSupported.value)
51-
return
52-
wakeLock = await (navigator as NavigatorWithWakeLock).wakeLock.request(type)
53-
isActive.value = !wakeLock.released
62+
if (documentVisibility.value === 'visible')
63+
await forceRequest(type)
64+
else
65+
requestedType.value = type
5466
}
5567

5668
async function release() {
57-
if (!isSupported.value || !wakeLock)
58-
return
59-
await wakeLock.release()
60-
isActive.value = !wakeLock.released
61-
wakeLock = null
69+
requestedType.value = false
70+
const s = sentinel.value
71+
sentinel.value = null
72+
await s?.release()
6273
}
6374

6475
return {
76+
sentinel,
6577
isSupported,
6678
isActive,
6779
request,
80+
forceRequest,
6881
release,
6982
}
7083
}

0 commit comments

Comments
 (0)
0