Add option to find own location in map views

This commit is contained in:
Johannes Marbach 2023-02-04 19:58:19 +01:00
parent a756b33fe9
commit e5a7e83b48
6 changed files with 93 additions and 25 deletions

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ReactNode, useContext, useEffect } from "react";
import React, { ReactNode, useContext, useEffect, useState } from "react";
import classNames from "classnames";
import * as maplibregl from "maplibre-gl";
import { ClientEvent, IClientWellKnown } from "matrix-js-sdk/src/matrix";
@ -22,10 +22,13 @@ import { logger } from "matrix-js-sdk/src/logger";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import { parseGeoUri } from "../../../utils/location";
import { parseGeoUri, positionFailureMessage } from "../../../utils/location";
import { tileServerFromWellKnown } from "../../../utils/WellKnownUtils";
import { useMap } from "../../../utils/location/useMap";
import { Bounds } from "../../../utils/beacon/bounds";
import Modal from "../../../Modal";
import ErrorDialog from "../dialogs/ErrorDialog";
import { _t } from "../../../languageHandler";
const useMapWithStyle = ({
id,
@ -33,12 +36,14 @@ const useMapWithStyle = ({
onError,
interactive,
bounds,
allowGeolocate,
}: {
id: string;
centerGeoUri?: string;
onError(error: Error): void;
interactive?: boolean;
bounds?: Bounds;
onError(error: Error): void;
allowGeolocate: boolean;
}): {
map: maplibregl.Map;
bodyId: string;
@ -86,12 +91,41 @@ const useMapWithStyle = ({
}
}, [map, bounds]);
const [geolocate] = useState(
allowGeolocate
? new maplibregl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true,
},
trackUserLocation: false,
})
: null,
);
useEffect(() => {
if (map && geolocate) {
map.addControl(geolocate);
geolocate.on("error", onGeolocateError);
return () => {
geolocate.off("error", onGeolocateError);
};
}
}, [map, geolocate]);
return {
map,
bodyId,
};
};
const onGeolocateError = (e: GeolocationPositionError): void => {
logger.error("Could not fetch location", e);
Modal.createDialog(ErrorDialog, {
title: _t("Could not fetch location"),
description: positionFailureMessage(e.code),
});
};
interface MapProps {
id: string;
interactive?: boolean;
@ -105,13 +139,24 @@ interface MapProps {
centerGeoUri?: string;
bounds?: Bounds;
className?: string;
allowGeolocate?: boolean;
onClick?: () => void;
onError?: (error: Error) => void;
children?: (renderProps: { map: maplibregl.Map }) => ReactNode;
}
const Map: React.FC<MapProps> = ({ bounds, centerGeoUri, children, className, id, interactive, onError, onClick }) => {
const { map, bodyId } = useMapWithStyle({ centerGeoUri, onError, id, interactive, bounds });
const Map: React.FC<MapProps> = ({
bounds,
centerGeoUri,
children,
className,
allowGeolocate,
id,
interactive,
onError,
onClick,
}) => {
const { map, bodyId } = useMapWithStyle({ centerGeoUri, onError, id, interactive, bounds, allowGeolocate });
const onMapClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
// Eat click events when clicking the attribution button