Live location share - show loading UI for beacons with start timestamp in the future (PSF-1081) (#8775)

* check for beacons that are yet to start and show loading ui

Signed-off-by: Kerry Archibald <kerrya@element.io>

* update snapshots for js-sdk rename

Signed-off-by: Kerry Archibald <kerrya@element.io>

* remove debug

Signed-off-by: Kerry Archibald <kerrya@element.io>

* Update test/components/views/messages/MBeaconBody-test.tsx

Co-authored-by: Travis Ralston <travisr@matrix.org>

* Update src/components/views/beacon/displayStatus.ts

Co-authored-by: Travis Ralston <travisr@matrix.org>

Co-authored-by: Travis Ralston <travisr@matrix.org>
This commit is contained in:
Kerry 2022-06-09 14:25:30 +02:00 committed by GitHub
parent 1d79c78f21
commit 2bdb4d396a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 4 deletions

View File

@ -25,14 +25,18 @@ export enum BeaconDisplayStatus {
export const getBeaconDisplayStatus = (
isLive: boolean,
latestLocationState?: BeaconLocationState,
error?: Error): BeaconDisplayStatus => {
error?: Error,
waitingToStart?: boolean,
): BeaconDisplayStatus => {
if (error) {
return BeaconDisplayStatus.Error;
}
if (waitingToStart) {
return BeaconDisplayStatus.Loading;
}
if (!isLive) {
return BeaconDisplayStatus.Stopped;
}
if (!latestLocationState) {
return BeaconDisplayStatus.Loading;
}

View File

@ -23,7 +23,7 @@ import MatrixClientContext from '../../../contexts/MatrixClientContext';
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
import { useBeacon } from '../../../utils/beacon';
import { isBeaconWaitingToStart, useBeacon } from '../../../utils/beacon';
import { isSelfLocation } from '../../../utils/location';
import { BeaconDisplayStatus, getBeaconDisplayStatus } from '../beacon/displayStatus';
import BeaconStatus from '../beacon/BeaconStatus';
@ -39,6 +39,7 @@ const useBeaconState = (beaconInfoEvent: MatrixEvent): {
description?: string;
latestLocationState?: BeaconLocationState;
isLive?: boolean;
waitingToStart?: boolean;
} => {
const beacon = useBeacon(beaconInfoEvent);
@ -56,12 +57,19 @@ const useBeaconState = (beaconInfoEvent: MatrixEvent): {
return {};
}
// a beacon's starting timestamp can be in the future
// (either from small deviations in system clock times, or on purpose from another client)
// a beacon is only live between its start timestamp and expiry
// detect when a beacon is waiting to become live
// and display a loading state
const waitingToStart = !!beacon && isBeaconWaitingToStart(beacon);
const { description } = beacon.beaconInfo;
return {
beacon,
description,
isLive,
waitingToStart,
latestLocationState,
};
};
@ -84,12 +92,13 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent }, ref) =>
beacon,
isLive,
latestLocationState,
waitingToStart,
} = useBeaconState(mxEvent);
const mapId = useUniqueId(mxEvent.getId());
const matrixClient = useContext(MatrixClientContext);
const [error, setError] = useState<Error>();
const displayStatus = getBeaconDisplayStatus(isLive, latestLocationState, error);
const displayStatus = getBeaconDisplayStatus(isLive, latestLocationState, error, waitingToStart);
const markerRoomMember = isSelfLocation(mxEvent.getContent()) ? mxEvent.sender : undefined;
const isOwnBeacon = beacon?.beaconInfoOwner === matrixClient.getUserId();

View File

@ -39,3 +39,10 @@ export const sortBeaconsByLatestExpiry = (left: Beacon, right: Beacon): number =
// aka sort by timestamp descending
export const sortBeaconsByLatestCreation = (left: Beacon, right: Beacon): number =>
right.beaconInfo.timestamp - left.beaconInfo.timestamp;
// a beacon's starting timestamp can be in the future
// (either from small deviations in system clock times, or on purpose from another client)
// a beacon is only live between its start timestamp and expiry
// detect when a beacon is waiting to become live
export const isBeaconWaitingToStart = (beacon: Beacon): boolean =>
!beacon.isLive && beacon.beaconInfo.timestamp > Date.now() && getBeaconExpiryTimestamp(beacon) > Date.now();

View File

@ -111,6 +111,19 @@ describe('<MBeaconBody />', () => {
expect(component.text()).toEqual("Live location ended");
});
it('renders loading beacon UI for a beacon that has not started yet', () => {
const beaconInfoEvent = makeBeaconInfoEvent(
aliceId,
roomId,
// puts this beacons start timestamp in the future
{ isLive: true, timestamp: now + 60000, timeout: 500 },
'$alice-room1-1',
);
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
const component = getComponent({ mxEvent: beaconInfoEvent });
expect(component.text()).toEqual("Loading live location...");
});
it('does not open maximised map when on click when beacon is stopped', () => {
const beaconInfoEvent = makeBeaconInfoEvent(aliceId,
roomId,