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

@ -125,6 +125,9 @@ const BeaconViewDialog: React.FC<IProps> = ({ initialFocusedBeacon, roomId, matr
setFocusedBeaconState({ beacon, ts: Date.now() });
};
const hasOwnBeacon =
liveBeacons.filter((beacon) => beacon?.beaconInfoOwner === matrixClient.getUserId()).length > 0;
return (
<BaseDialog className="mx_BeaconViewDialog" onFinished={onFinished} fixedWidth={false}>
<MatrixClientContext.Provider value={matrixClient}>
@ -136,6 +139,7 @@ const BeaconViewDialog: React.FC<IProps> = ({ initialFocusedBeacon, roomId, matr
interactive
onError={setMapDisplayError}
className="mx_BeaconViewDialog_map"
allowGeolocate={!hasOwnBeacon}
>
{({ map }: { map: maplibregl.Map }) => (
<>

View file

@ -23,10 +23,9 @@ import { ClientEvent, IClientWellKnown } from "matrix-js-sdk/src/client";
import { _t } from "../../../languageHandler";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import Modal from "../../../Modal";
import SdkConfig from "../../../SdkConfig";
import { tileServerFromWellKnown } from "../../../utils/WellKnownUtils";
import { GenericPosition, genericPositionFromGeolocation, getGeoUri } from "../../../utils/beacon";
import { LocationShareError, findMapStyleUrl } from "../../../utils/location";
import { LocationShareError, findMapStyleUrl, positionFailureMessage } from "../../../utils/location";
import ErrorDialog from "../dialogs/ErrorDialog";
import AccessibleButton from "../elements/AccessibleButton";
import { MapError } from "./MapError";
@ -266,21 +265,3 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
}
export default LocationPicker;
function positionFailureMessage(code: number): string {
const brand = SdkConfig.get().brand;
switch (code) {
case 1:
return _t(
"%(brand)s was denied permission to fetch your location. " +
"Please allow location access in your browser settings.",
{ brand },
);
case 2:
return _t("Failed to fetch your location. Please try again later.");
case 3:
return _t("Timed out trying to fetch your location. Please try again later.");
case 4:
return _t("Unknown error fetching location. Please try again later.");
}
}

View file

@ -68,6 +68,7 @@ export default class LocationViewDialog extends React.Component<IProps, IState>
onError={this.onError}
interactive
className="mx_LocationViewDialog_map"
allowGeolocate={true}
>
{({ map }) => (
<>

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