Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 684b061

Browse files
authored
Support sharing custom locations. (#7185)
Add the ability to click on the map to share a specific named location.
1 parent 1262021 commit 684b061

File tree

3 files changed

+81
-14
lines changed

3 files changed

+81
-14
lines changed

src/components/views/location/LocationPicker.tsx

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const LocationShareTypeDropdown = ({
4141
onChange,
4242
}: IDropdownProps) => {
4343
const options = [
44-
// <div key={LocationShareType.Custom}>{ _t("Share custom location") }</div>,
44+
<div key={LocationShareType.Custom}>{ _t("Share custom location") }</div>,
4545
<div key={LocationShareType.OnceOff}>{ _t("Share my current location as a once off") }</div>,
4646
// <div key={LocationShareType.OneMin}>{ _t("Share my current location for one minute") }</div>,
4747
// <div key={LocationShareType.FiveMins}>{ _t("Share my current location for five minutes") }</div>,
@@ -56,7 +56,9 @@ const LocationShareTypeDropdown = ({
5656
return <Dropdown
5757
id="mx_LocationShareTypeDropdown"
5858
className="mx_LocationShareTypeDropdown"
59-
onOptionChange={(key: string)=>{ onChange(LocationShareType[LocationShareType[parseInt(key)]]); }}
59+
onOptionChange={(key: string) => {
60+
onChange(LocationShareType[LocationShareType[parseInt(key)]]);
61+
}}
6062
menuWidth={width}
6163
label={label}
6264
value={value.toString()}
@@ -74,13 +76,14 @@ interface IState {
7476
description: string;
7577
type: LocationShareType;
7678
position?: GeolocationPosition;
77-
manual: boolean;
79+
manualPosition?: GeolocationPosition;
7880
error: Error;
7981
}
8082

8183
@replaceableComponent("views.location.LocationPicker")
8284
class LocationPicker extends React.Component<IProps, IState> {
8385
private map: maplibregl.Map;
86+
private marker: maplibregl.Marker;
8487
private geolocate: maplibregl.GeolocateControl;
8588

8689
constructor(props) {
@@ -90,7 +93,7 @@ class LocationPicker extends React.Component<IProps, IState> {
9093
description: _t("My location"),
9194
type: LocationShareType.OnceOff,
9295
position: undefined,
93-
manual: false,
96+
manualPosition: undefined,
9497
error: undefined,
9598
};
9699
}
@@ -113,23 +116,63 @@ class LocationPicker extends React.Component<IProps, IState> {
113116
});
114117
this.map.addControl(this.geolocate);
115118

116-
this.map.on('error', (e)=>{
119+
this.map.on('error', (e) => {
117120
logger.error("Failed to load map: check map_style_url in config.json has a valid URL and API key", e.error);
118121
this.setState({ error: e.error });
119122
});
120123

121-
this.map.on('load', ()=>{
124+
this.map.on('load', () => {
122125
this.geolocate.trigger();
123126
});
124127

128+
this.map.on('click', (e) => {
129+
this.addMarker(e.lngLat);
130+
this.storeManualPosition(e.lngLat);
131+
this.setState({ type: LocationShareType.Custom });
132+
});
133+
125134
this.geolocate.on('geolocate', this.onGeolocate);
126135
}
127136

137+
private addMarker(lngLat: maplibregl.LngLat): void {
138+
if (this.marker) return;
139+
this.marker = new maplibregl.Marker({
140+
draggable: true,
141+
})
142+
.setLngLat(lngLat)
143+
.addTo(this.map)
144+
.on('dragend', () => {
145+
this.storeManualPosition(this.marker.getLngLat());
146+
});
147+
}
148+
149+
private removeMarker(): void {
150+
if (!this.marker) return;
151+
this.marker.remove();
152+
this.marker = undefined;
153+
}
154+
155+
private storeManualPosition(lngLat: maplibregl.LngLat): void {
156+
const manualPosition: GeolocationPosition = {
157+
coords: {
158+
longitude: lngLat.lng,
159+
latitude: lngLat.lat,
160+
altitude: undefined,
161+
accuracy: undefined,
162+
altitudeAccuracy: undefined,
163+
heading: undefined,
164+
speed: undefined,
165+
},
166+
timestamp: Date.now(),
167+
};
168+
this.setState({ manualPosition });
169+
}
170+
128171
componentWillUnmount() {
129172
this.geolocate.off('geolocate', this.onGeolocate);
130173
}
131174

132-
private onGeolocate = (position) => {
175+
private onGeolocate = (position: GeolocationPosition) => {
133176
this.setState({ position });
134177
};
135178

@@ -146,16 +189,33 @@ class LocationPicker extends React.Component<IProps, IState> {
146189
};
147190

148191
private onOk = () => {
192+
const position = (this.state.type == LocationShareType.Custom) ?
193+
this.state.manualPosition : this.state.position;
194+
149195
this.props.onChoose(
150-
this.state.position ? this.getGeoUri(this.state.position) : undefined,
151-
this.state.position ? this.state.position.timestamp : undefined,
196+
position ? this.getGeoUri(position) : undefined,
197+
position ? position.timestamp : undefined,
152198
this.state.type,
153199
this.state.description,
154200
);
155201
this.props.onFinished();
156202
};
157203

158204
private onTypeChange= (type: LocationShareType) => {
205+
if (type == LocationShareType.Custom) {
206+
if (!this.state.manualPosition) {
207+
this.setState({ manualPosition: this.state.position });
208+
}
209+
if (this.state.manualPosition) {
210+
this.addMarker(new maplibregl.LngLat(
211+
this.state.manualPosition?.coords.longitude,
212+
this.state.manualPosition?.coords.latitude,
213+
));
214+
}
215+
} else {
216+
this.removeMarker();
217+
}
218+
159219
this.setState({ type });
160220
};
161221

@@ -189,7 +249,7 @@ class LocationPicker extends React.Component<IProps, IState> {
189249
<DialogButtons primaryButton={_t('Share')}
190250
onPrimaryButtonClick={this.onOk}
191251
onCancel={this.props.onFinished}
192-
disabled={!this.state.position} />
252+
primaryDisabled={!this.state.position} />
193253
</form>
194254
</div>
195255
</div>

src/components/views/messages/MLocationBody.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,22 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {
7676

7777
componentDidMount() {
7878
const config = SdkConfig.get();
79+
const coordinates = new maplibregl.LngLat(this.coords.longitude, this.coords.latitude);
80+
7981
this.map = new maplibregl.Map({
8082
container: this.getBodyId(),
8183
style: config.map_style_url,
82-
center: [this.coords.longitude, this.coords.latitude],
84+
center: coordinates,
8385
zoom: 13,
8486
});
8587

86-
new maplibregl.Marker()
87-
.setLngLat([this.coords.longitude, this.coords.latitude])
88+
new maplibregl.Popup({
89+
closeButton: false,
90+
closeOnClick: false,
91+
closeOnMove: false,
92+
})
93+
.setLngLat(coordinates)
94+
.setHTML(this.description)
8895
.addTo(this.map);
8996

9097
this.map.on('error', (e)=>{
@@ -106,7 +113,6 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {
106113
return <div className="mx_MLocationBody">
107114
<div id={this.getBodyId()} className="mx_MLocationBody_map" />
108115
{ error }
109-
<span className="mx_EventTile_body">{ this.description }</span>
110116
</div>;
111117
}
112118
}

src/i18n/strings/en_EN.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,6 +2103,7 @@
21032103
"edited": "edited",
21042104
"Submit logs": "Submit logs",
21052105
"Can't load this message": "Can't load this message",
2106+
"Share custom location": "Share custom location",
21062107
"Share my current location as a once off": "Share my current location as a once off",
21072108
"My location": "My location",
21082109
"Type of location share": "Type of location share",

0 commit comments

Comments
 (0)