diff --git a/src/components/views/beacon/LeftPanelLiveShareWarning.tsx b/src/components/views/beacon/LeftPanelLiveShareWarning.tsx index 43b00a8fa76..b93d8de1ae7 100644 --- a/src/components/views/beacon/LeftPanelLiveShareWarning.tsx +++ b/src/components/views/beacon/LeftPanelLiveShareWarning.tsx @@ -15,8 +15,8 @@ limitations under the License. */ import classNames from 'classnames'; -import React from 'react'; -import { BeaconIdentifier, Room } from 'matrix-js-sdk/src/matrix'; +import React, { useEffect } from 'react'; +import { Beacon, BeaconIdentifier, Room } from 'matrix-js-sdk/src/matrix'; import { useEventEmitterState } from '../../../hooks/useEventEmitter'; import { _t } from '../../../languageHandler'; @@ -61,6 +61,25 @@ const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): strin return _t('You are sharing your live location'); }; +const useLivenessMonitor = (liveBeaconIds: BeaconIdentifier[], beacons: Map): void => { + useEffect(() => { + // chromium sets the minimum timer interval to 1000ms + // for inactive tabs + // refresh beacon monitors when the tab becomes active again + const onPageVisibilityChanged = () => { + if (document.visibilityState === 'visible') { + liveBeaconIds.map(identifier => beacons.get(identifier)?.monitorLiveness()); + } + }; + if (liveBeaconIds.length) { + document.addEventListener("visibilitychange", onPageVisibilityChanged); + } + () => { + document.removeEventListener("visibilitychange", onPageVisibilityChanged); + }; + }, [liveBeaconIds, beacons]); +}; + const LeftPanelLiveShareWarning: React.FC = ({ isMinimized }) => { const isMonitoringLiveLocation = useEventEmitterState( OwnBeaconStore.instance, @@ -91,6 +110,8 @@ const LeftPanelLiveShareWarning: React.FC = ({ isMinimized }) => { const hasLocationPublishErrors = !!beaconIdsWithLocationPublishError.length; const hasStoppingErrors = !!beaconIdsWithStoppingError.length; + useLivenessMonitor(liveBeaconIds, OwnBeaconStore.instance.beacons); + if (!isMonitoringLiveLocation) { return null; } diff --git a/test/components/views/beacon/LeftPanelLiveShareWarning-test.tsx b/test/components/views/beacon/LeftPanelLiveShareWarning-test.tsx index d02f4d0c3d4..a05fbf348f7 100644 --- a/test/components/views/beacon/LeftPanelLiveShareWarning-test.tsx +++ b/test/components/views/beacon/LeftPanelLiveShareWarning-test.tsx @@ -34,6 +34,7 @@ jest.mock('../../../../src/stores/OwnBeaconStore', () => { public getBeaconById = jest.fn(); public getLiveBeaconIds = jest.fn().mockReturnValue([]); public readonly beaconUpdateErrors = new Map(); + public readonly beacons = new Map(); } return { // @ts-ignore @@ -103,6 +104,10 @@ describe('', () => { mocked(OwnBeaconStore.instance).getLiveBeaconIds.mockReturnValue([beacon2.identifier, beacon1.identifier]); }); + afterAll(() => { + jest.spyOn(document, 'addEventListener').mockRestore(); + }); + it('renders correctly when not minimized', () => { const component = getComponent(); expect(component).toMatchSnapshot(); @@ -195,6 +200,24 @@ describe('', () => { expect(component.html()).toBe(null); }); + it('refreshes beacon liveness monitors when pagevisibilty changes to visible', () => { + OwnBeaconStore.instance.beacons.set(beacon1.identifier, beacon1); + OwnBeaconStore.instance.beacons.set(beacon2.identifier, beacon2); + const beacon1MonitorSpy = jest.spyOn(beacon1, 'monitorLiveness'); + const beacon2MonitorSpy = jest.spyOn(beacon1, 'monitorLiveness'); + + jest.spyOn(document, 'addEventListener').mockImplementation( + (_e, listener) => (listener as EventListener)(new Event('')), + ); + + expect(beacon1MonitorSpy).not.toHaveBeenCalled(); + + getComponent(); + + expect(beacon1MonitorSpy).toHaveBeenCalled(); + expect(beacon2MonitorSpy).toHaveBeenCalled(); + }); + describe('stopping errors', () => { it('renders stopping error', () => { OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error('error'));