Open map in a dialog when it is clicked (#7465)
This commit is contained in:
parent
59ef2704f0
commit
707f8cd878
9 changed files with 286 additions and 67 deletions
|
@ -25,6 +25,8 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
|
|||
import { IBodyProps } from "./IBodyProps";
|
||||
import { _t } from '../../../languageHandler';
|
||||
import MemberAvatar from '../avatars/MemberAvatar';
|
||||
import Modal from '../../../Modal';
|
||||
import LocationViewDialog from '../location/LocationViewDialog';
|
||||
|
||||
interface IState {
|
||||
error: Error;
|
||||
|
@ -32,54 +34,29 @@ interface IState {
|
|||
|
||||
@replaceableComponent("views.messages.MLocationBody")
|
||||
export default class MLocationBody extends React.Component<IBodyProps, IState> {
|
||||
private map: maplibregl.Map;
|
||||
private coords: GeolocationCoordinates;
|
||||
|
||||
constructor(props: IBodyProps) {
|
||||
super(props);
|
||||
|
||||
// unfortunately we're stuck supporting legacy `content.geo_uri`
|
||||
// events until the end of days, or until we figure out mutable
|
||||
// events - so folks can read their old chat history correctly.
|
||||
// https://github.com/matrix-org/matrix-doc/issues/3516
|
||||
const content = this.props.mxEvent.getContent();
|
||||
const loc = content[LOCATION_EVENT_TYPE.name];
|
||||
const uri = loc ? loc.uri : content['geo_uri'];
|
||||
|
||||
this.coords = parseGeoUri(uri);
|
||||
this.coords = parseGeoUri(locationEventGeoUri(this.props.mxEvent));
|
||||
this.state = {
|
||||
error: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const config = SdkConfig.get();
|
||||
const coordinates = new maplibregl.LngLat(
|
||||
this.coords.longitude, this.coords.latitude);
|
||||
if (this.state.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.map = new maplibregl.Map({
|
||||
container: this.getBodyId(),
|
||||
style: config.map_style_url,
|
||||
center: coordinates,
|
||||
zoom: 13,
|
||||
});
|
||||
|
||||
new maplibregl.Marker({
|
||||
element: document.getElementById(this.getMarkerId()),
|
||||
anchor: 'bottom',
|
||||
offset: [0, -1],
|
||||
})
|
||||
.setLngLat(coordinates)
|
||||
.addTo(this.map);
|
||||
|
||||
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 });
|
||||
});
|
||||
createMap(
|
||||
this.coords,
|
||||
false,
|
||||
this.getBodyId(),
|
||||
this.getMarkerId(),
|
||||
(e: Error) => this.setState({ error: e }),
|
||||
);
|
||||
}
|
||||
|
||||
private getBodyId = () => {
|
||||
|
@ -90,33 +67,127 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {
|
|||
return `mx_MLocationBody_marker_${this.props.mxEvent.getId()}`;
|
||||
};
|
||||
|
||||
render() {
|
||||
const error = this.state.error ?
|
||||
<div className="mx_EventTile_tileError mx_EventTile_body">
|
||||
{ _t("Failed to load map") }
|
||||
</div> : null;
|
||||
private onClick = (
|
||||
event: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
) => {
|
||||
// Don't open map if we clicked the attribution button
|
||||
const target = event.target as Element;
|
||||
if (target.classList.contains("maplibregl-ctrl-attrib-button")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return <div className="mx_MLocationBody">
|
||||
<div id={this.getBodyId()} className="mx_MLocationBody_map" />
|
||||
{ error }
|
||||
<div className="mx_MLocationBody_marker" id={this.getMarkerId()}>
|
||||
<div className="mx_MLocationBody_markerBorder">
|
||||
<MemberAvatar
|
||||
member={this.props.mxEvent.sender}
|
||||
width={27}
|
||||
height={27}
|
||||
viewUserOnClick={false}
|
||||
/>
|
||||
Modal.createTrackedDialog(
|
||||
'Location View',
|
||||
'',
|
||||
LocationViewDialog,
|
||||
{ mxEvent: this.props.mxEvent },
|
||||
"mx_LocationViewDialog_wrapper",
|
||||
false, // isPriority
|
||||
true, // isStatic
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <LocationBodyContent
|
||||
mxEvent={this.props.mxEvent}
|
||||
bodyId={this.getBodyId()}
|
||||
markerId={this.getMarkerId()}
|
||||
error={this.state.error}
|
||||
onClick={this.onClick}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
interface ILocationBodyContentProps {
|
||||
mxEvent: MatrixEvent;
|
||||
bodyId: string;
|
||||
markerId: string;
|
||||
error: Error;
|
||||
onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
}
|
||||
|
||||
export function LocationBodyContent(props: ILocationBodyContentProps) {
|
||||
return <div className="mx_MLocationBody">
|
||||
{
|
||||
props.error
|
||||
? <div className="mx_EventTile_tileError mx_EventTile_body">
|
||||
{ _t("Failed to load map") }
|
||||
</div>
|
||||
<img
|
||||
className="mx_MLocationBody_pointer"
|
||||
src={require("../../../../res/img/location/pointer.svg")}
|
||||
width="9"
|
||||
height="5"
|
||||
: null
|
||||
}
|
||||
<div
|
||||
id={props.bodyId}
|
||||
onClick={props.onClick}
|
||||
className="mx_MLocationBody_map"
|
||||
/>
|
||||
<div className="mx_MLocationBody_marker" id={props.markerId}>
|
||||
<div className="mx_MLocationBody_markerBorder">
|
||||
<MemberAvatar
|
||||
member={props.mxEvent.sender}
|
||||
width={27}
|
||||
height={27}
|
||||
viewUserOnClick={false}
|
||||
/>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
<img
|
||||
className="mx_MLocationBody_pointer"
|
||||
src={require("../../../../res/img/location/pointer.svg")}
|
||||
width="9"
|
||||
height="5"
|
||||
/>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
export function createMap(
|
||||
coords: GeolocationCoordinates,
|
||||
interactive: boolean,
|
||||
bodyId: string,
|
||||
markerId: string,
|
||||
onError: (error: Error) => void,
|
||||
): maplibregl.Map {
|
||||
const styleUrl = SdkConfig.get().map_style_url;
|
||||
const coordinates = new maplibregl.LngLat(coords.longitude, coords.latitude);
|
||||
|
||||
const map = new maplibregl.Map({
|
||||
container: bodyId,
|
||||
style: styleUrl,
|
||||
center: coordinates,
|
||||
zoom: 13,
|
||||
interactive,
|
||||
});
|
||||
|
||||
new maplibregl.Marker({
|
||||
element: document.getElementById(markerId),
|
||||
anchor: 'bottom',
|
||||
offset: [0, -1],
|
||||
})
|
||||
.setLngLat(coordinates)
|
||||
.addTo(map);
|
||||
|
||||
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,
|
||||
);
|
||||
onError(e.error);
|
||||
});
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the geo-URI contained within a location event.
|
||||
*/
|
||||
export function locationEventGeoUri(mxEvent: MatrixEvent): string {
|
||||
// unfortunately we're stuck supporting legacy `content.geo_uri`
|
||||
// events until the end of days, or until we figure out mutable
|
||||
// events - so folks can read their old chat history correctly.
|
||||
// https://github.com/matrix-org/matrix-doc/issues/3516
|
||||
const content = mxEvent.getContent();
|
||||
const loc = LOCATION_EVENT_TYPE.findIn(content) as { uri?: string };
|
||||
return loc ? loc.uri : content['geo_uri'];
|
||||
}
|
||||
|
||||
export function parseGeoUri(uri: string): GeolocationCoordinates {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue