diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx
index 8d4efdfa70..3c22d06345 100644
--- a/src/components/views/location/LocationPicker.tsx
+++ b/src/components/views/location/LocationPicker.tsx
@@ -41,7 +41,7 @@ const LocationShareTypeDropdown = ({
onChange,
}: IDropdownProps) => {
const options = [
- //
{ _t("Share custom location") }
,
+ { _t("Share custom location") }
,
{ _t("Share my current location as a once off") }
,
// { _t("Share my current location for one minute") }
,
// { _t("Share my current location for five minutes") }
,
@@ -56,7 +56,9 @@ const LocationShareTypeDropdown = ({
return { onChange(LocationShareType[LocationShareType[parseInt(key)]]); }}
+ onOptionChange={(key: string) => {
+ onChange(LocationShareType[LocationShareType[parseInt(key)]]);
+ }}
menuWidth={width}
label={label}
value={value.toString()}
@@ -74,13 +76,14 @@ interface IState {
description: string;
type: LocationShareType;
position?: GeolocationPosition;
- manual: boolean;
+ manualPosition?: GeolocationPosition;
error: Error;
}
@replaceableComponent("views.location.LocationPicker")
class LocationPicker extends React.Component {
private map: maplibregl.Map;
+ private marker: maplibregl.Marker;
private geolocate: maplibregl.GeolocateControl;
constructor(props) {
@@ -90,7 +93,7 @@ class LocationPicker extends React.Component {
description: _t("My location"),
type: LocationShareType.OnceOff,
position: undefined,
- manual: false,
+ manualPosition: undefined,
error: undefined,
};
}
@@ -113,23 +116,63 @@ class LocationPicker extends React.Component {
});
this.map.addControl(this.geolocate);
- this.map.on('error', (e)=>{
+ this.map.on('error', (e) => {
logger.error("Failed to load map: check map_style_url in config.json has a valid URL and API key", e.error);
this.setState({ error: e.error });
});
- this.map.on('load', ()=>{
+ this.map.on('load', () => {
this.geolocate.trigger();
});
+ this.map.on('click', (e) => {
+ this.addMarker(e.lngLat);
+ this.storeManualPosition(e.lngLat);
+ this.setState({ type: LocationShareType.Custom });
+ });
+
this.geolocate.on('geolocate', this.onGeolocate);
}
+ private addMarker(lngLat: maplibregl.LngLat): void {
+ if (this.marker) return;
+ this.marker = new maplibregl.Marker({
+ draggable: true,
+ })
+ .setLngLat(lngLat)
+ .addTo(this.map)
+ .on('dragend', () => {
+ this.storeManualPosition(this.marker.getLngLat());
+ });
+ }
+
+ private removeMarker(): void {
+ if (!this.marker) return;
+ this.marker.remove();
+ this.marker = undefined;
+ }
+
+ private storeManualPosition(lngLat: maplibregl.LngLat): void {
+ const manualPosition: GeolocationPosition = {
+ coords: {
+ longitude: lngLat.lng,
+ latitude: lngLat.lat,
+ altitude: undefined,
+ accuracy: undefined,
+ altitudeAccuracy: undefined,
+ heading: undefined,
+ speed: undefined,
+ },
+ timestamp: Date.now(),
+ };
+ this.setState({ manualPosition });
+ }
+
componentWillUnmount() {
this.geolocate.off('geolocate', this.onGeolocate);
}
- private onGeolocate = (position) => {
+ private onGeolocate = (position: GeolocationPosition) => {
this.setState({ position });
};
@@ -146,9 +189,12 @@ class LocationPicker extends React.Component {
};
private onOk = () => {
+ const position = (this.state.type == LocationShareType.Custom) ?
+ this.state.manualPosition : this.state.position;
+
this.props.onChoose(
- this.state.position ? this.getGeoUri(this.state.position) : undefined,
- this.state.position ? this.state.position.timestamp : undefined,
+ position ? this.getGeoUri(position) : undefined,
+ position ? position.timestamp : undefined,
this.state.type,
this.state.description,
);
@@ -156,6 +202,20 @@ class LocationPicker extends React.Component {
};
private onTypeChange= (type: LocationShareType) => {
+ if (type == LocationShareType.Custom) {
+ if (!this.state.manualPosition) {
+ this.setState({ manualPosition: this.state.position });
+ }
+ if (this.state.manualPosition) {
+ this.addMarker(new maplibregl.LngLat(
+ this.state.manualPosition?.coords.longitude,
+ this.state.manualPosition?.coords.latitude,
+ ));
+ }
+ } else {
+ this.removeMarker();
+ }
+
this.setState({ type });
};
@@ -189,7 +249,7 @@ class LocationPicker extends React.Component {
+ primaryDisabled={!this.state.position} />
diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx
index 8e096fa382..49ff063f40 100644
--- a/src/components/views/messages/MLocationBody.tsx
+++ b/src/components/views/messages/MLocationBody.tsx
@@ -76,15 +76,22 @@ export default class MLocationBody extends React.Component {
componentDidMount() {
const config = SdkConfig.get();
+ const coordinates = new maplibregl.LngLat(this.coords.longitude, this.coords.latitude);
+
this.map = new maplibregl.Map({
container: this.getBodyId(),
style: config.map_style_url,
- center: [this.coords.longitude, this.coords.latitude],
+ center: coordinates,
zoom: 13,
});
- new maplibregl.Marker()
- .setLngLat([this.coords.longitude, this.coords.latitude])
+ new maplibregl.Popup({
+ closeButton: false,
+ closeOnClick: false,
+ closeOnMove: false,
+ })
+ .setLngLat(coordinates)
+ .setHTML(this.description)
.addTo(this.map);
this.map.on('error', (e)=>{
@@ -106,7 +113,6 @@ export default class MLocationBody extends React.Component {
return
{ error }
-
{ this.description }
;
}
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 2116b8cfa8..1637b0908c 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2103,6 +2103,7 @@
"edited": "edited",
"Submit logs": "Submit logs",
"Can't load this message": "Can't load this message",
+ "Share custom location": "Share custom location",
"Share my current location as a once off": "Share my current location as a once off",
"My location": "My location",
"Type of location share": "Type of location share",