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

Commit 1262021

Browse files
authored
Simple static location sharing (#7135)
Adds maplibre as a dependency, and behind a labs flag, lets users send and receive [MSC3488](https://github.com/matrix-org/matrix-doc/blob/matthew/location/proposals/3488-location.md) style location shares - with backwards compatibility with old school `m.location` `msgtype` location shares too. For this to work, you have to define a valid maptile server and API in your config.json's `map_style_url`.
1 parent eb05044 commit 1262021

File tree

17 files changed

+703
-3
lines changed

17 files changed

+703
-3
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"@babel/runtime": "^7.12.5",
5858
"@sentry/browser": "^6.11.0",
5959
"@sentry/tracing": "^6.11.0",
60+
"@types/geojson": "^7946.0.8",
6061
"await-lock": "^2.1.0",
6162
"blurhash": "^1.1.3",
6263
"browser-encrypt-attachment": "^0.3.0",
@@ -83,6 +84,7 @@
8384
"katex": "^0.12.0",
8485
"linkifyjs": "^2.1.9",
8586
"lodash": "^4.17.20",
87+
"maplibre-gl": "^1.15.2",
8688
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
8789
"matrix-widget-api": "^0.1.0-beta.18",
8890
"minimist": "^1.2.5",

res/css/_common.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*
22
Copyright 2015, 2016 OpenMarket Ltd
33
Copyright 2017 Vector Creations Ltd
4-
Copyright 2017 New Vector Ltd
4+
Copyright 2017 - 2019 New Vector Ltd
5+
Copyright 2019 - 2021 The Matrix.org Foundation C.I.C
56
67
Licensed under the Apache License, Version 2.0 (the "License");
78
you may not use this file except in compliance with the License.
@@ -19,6 +20,7 @@ limitations under the License.
1920
@import "./_font-sizes.scss";
2021
@import "./_font-weights.scss";
2122
@import "./_animations.scss";
23+
@import url("maplibre-gl/dist/maplibre-gl.css");
2224

2325
$hover-transition: 0.08s cubic-bezier(.46, .03, .52, .96); // quadratic
2426

res/css/_components.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
@import "./views/groups/_GroupPublicityToggle.scss";
174174
@import "./views/groups/_GroupRoomList.scss";
175175
@import "./views/groups/_GroupUserSettings.scss";
176+
@import "./views/location/_LocationPicker.scss";
176177
@import "./views/messages/_CallEvent.scss";
177178
@import "./views/messages/_CreateEvent.scss";
178179
@import "./views/messages/_DateSeparator.scss";
@@ -182,6 +183,7 @@
182183
@import "./views/messages/_MImageBody.scss";
183184
@import "./views/messages/_MImageReplyBody.scss";
184185
@import "./views/messages/_MJitsiWidgetEvent.scss";
186+
@import "./views/messages/_MLocationBody.scss";
185187
@import "./views/messages/_MNoticeBody.scss";
186188
@import "./views/messages/_MPollBody.scss";
187189
@import "./views/messages/_MStickerBody.scss";
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
Copyright 2021 The Matrix.org Foundation C.I.C
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
.mx_LocationPicker {
18+
// placeholder sizing to be replaced once there's a proper design
19+
width: 450px;
20+
height: 500px;
21+
22+
border-radius: 4px;
23+
24+
display: flex;
25+
flex-direction: column;
26+
}
27+
28+
#mx_LocationPicker_map {
29+
height: 324px;
30+
border-radius: 8px 8px 0px 0px;
31+
}
32+
33+
.mx_LocationPicker_footer {
34+
margin: 24px;
35+
36+
.mx_Dropdown_menu {
37+
max-height: 140px;
38+
}
39+
}
40+
41+
.mx_LocationPicker_error {
42+
color: red;
43+
margin: auto;
44+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
Copyright 2021 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
.mx_MLocationBody_map {
18+
width: 450px;
19+
height: 300px;
20+
21+
border-radius: $timeline-image-border-radius;
22+
}

res/css/views/rooms/_MessageComposer.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ limitations under the License.
256256
mask-image: url('$(res)/img/element-icons/room/composer/emoji.svg');
257257
}
258258

259+
.mx_MessageComposer_location::before {
260+
mask-image: url('$(res)/img/element-icons/room/composer/location.svg');
261+
}
262+
259263
.mx_MessageComposer_stickers::before {
260264
mask-image: url('$(res)/img/element-icons/room/composer/sticker.svg');
261265
}
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
Copyright 2021 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
import maplibregl from 'maplibre-gl';
19+
20+
import SdkConfig from '../../../SdkConfig';
21+
import Field from "../elements/Field";
22+
import DialogButtons from "../elements/DialogButtons";
23+
import Dropdown from "../elements/Dropdown";
24+
import LocationShareType from "./LocationShareType";
25+
26+
import { _t } from '../../../languageHandler';
27+
import { replaceableComponent } from "../../../utils/replaceableComponent";
28+
import { logger } from "matrix-js-sdk/src/logger";
29+
30+
interface IDropdownProps {
31+
value: LocationShareType;
32+
label: string;
33+
width?: number;
34+
onChange(type: LocationShareType): void;
35+
}
36+
37+
const LocationShareTypeDropdown = ({
38+
value,
39+
label,
40+
width,
41+
onChange,
42+
}: IDropdownProps) => {
43+
const options = [
44+
// <div key={LocationShareType.Custom}>{ _t("Share custom location") }</div>,
45+
<div key={LocationShareType.OnceOff}>{ _t("Share my current location as a once off") }</div>,
46+
// <div key={LocationShareType.OneMin}>{ _t("Share my current location for one minute") }</div>,
47+
// <div key={LocationShareType.FiveMins}>{ _t("Share my current location for five minutes") }</div>,
48+
// <div key={LocationShareType.ThirtyMins}>{ _t("Share my current location for thirty minutes") }</div>,
49+
// <div key={LocationShareType.OneHour}>{ _t("Share my current location for one hour") }</div>,
50+
// <div key={LocationShareType.ThreeHours}>{ _t("Share my current location for three hours") }</div>,
51+
// <div key={LocationShareType.SixHours}>{ _t("Share my current location for six hours") }</div>,
52+
// <div key={LocationShareType.OneDay}>{ _t("Share my current location for one day") }</div>,
53+
// <div key={LocationShareType.Forever}>{ _t("Share my current location until I disable it") }</div>,
54+
];
55+
56+
return <Dropdown
57+
id="mx_LocationShareTypeDropdown"
58+
className="mx_LocationShareTypeDropdown"
59+
onOptionChange={(key: string)=>{ onChange(LocationShareType[LocationShareType[parseInt(key)]]); }}
60+
menuWidth={width}
61+
label={label}
62+
value={value.toString()}
63+
>
64+
{ options }
65+
</Dropdown>;
66+
};
67+
68+
interface IProps {
69+
onChoose(uri: string, ts: number, type: LocationShareType, description: string): boolean;
70+
onFinished();
71+
}
72+
73+
interface IState {
74+
description: string;
75+
type: LocationShareType;
76+
position?: GeolocationPosition;
77+
manual: boolean;
78+
error: Error;
79+
}
80+
81+
@replaceableComponent("views.location.LocationPicker")
82+
class LocationPicker extends React.Component<IProps, IState> {
83+
private map: maplibregl.Map;
84+
private geolocate: maplibregl.GeolocateControl;
85+
86+
constructor(props) {
87+
super(props);
88+
89+
this.state = {
90+
description: _t("My location"),
91+
type: LocationShareType.OnceOff,
92+
position: undefined,
93+
manual: false,
94+
error: undefined,
95+
};
96+
}
97+
98+
componentDidMount() {
99+
const config = SdkConfig.get();
100+
this.map = new maplibregl.Map({
101+
container: 'mx_LocationPicker_map',
102+
style: config.map_style_url,
103+
center: [0, 0],
104+
zoom: 1,
105+
});
106+
107+
// Add geolocate control to the map.
108+
this.geolocate = new maplibregl.GeolocateControl({
109+
positionOptions: {
110+
enableHighAccuracy: true,
111+
},
112+
trackUserLocation: true,
113+
});
114+
this.map.addControl(this.geolocate);
115+
116+
this.map.on('error', (e)=>{
117+
logger.error("Failed to load map: check map_style_url in config.json has a valid URL and API key", e.error);
118+
this.setState({ error: e.error });
119+
});
120+
121+
this.map.on('load', ()=>{
122+
this.geolocate.trigger();
123+
});
124+
125+
this.geolocate.on('geolocate', this.onGeolocate);
126+
}
127+
128+
componentWillUnmount() {
129+
this.geolocate.off('geolocate', this.onGeolocate);
130+
}
131+
132+
private onGeolocate = (position) => {
133+
this.setState({ position });
134+
};
135+
136+
private onDescriptionChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
137+
this.setState({ description: ev.target.value });
138+
};
139+
140+
private getGeoUri = (position) => {
141+
return (`geo:${ position.coords.latitude },` +
142+
position.coords.longitude +
143+
( position.coords.altitude != null ?
144+
`,${ position.coords.altitude }` : '' ) +
145+
`;u=${ position.coords.accuracy }`);
146+
};
147+
148+
private onOk = () => {
149+
this.props.onChoose(
150+
this.state.position ? this.getGeoUri(this.state.position) : undefined,
151+
this.state.position ? this.state.position.timestamp : undefined,
152+
this.state.type,
153+
this.state.description,
154+
);
155+
this.props.onFinished();
156+
};
157+
158+
private onTypeChange= (type: LocationShareType) => {
159+
this.setState({ type });
160+
};
161+
162+
render() {
163+
const error = this.state.error ?
164+
<div className="mx_LocationPicker_error">
165+
{ _t("Failed to load map") }
166+
</div> : null;
167+
168+
return (
169+
<div className="mx_LocationPicker">
170+
<div id="mx_LocationPicker_map" />
171+
{ error }
172+
<div className="mx_LocationPicker_footer">
173+
<form onSubmit={this.onOk}>
174+
<LocationShareTypeDropdown
175+
value={this.state.type}
176+
label={_t("Type of location share")}
177+
onChange={this.onTypeChange}
178+
width={400}
179+
/>
180+
181+
<Field
182+
label={_t('Description')}
183+
onChange={this.onDescriptionChange}
184+
value={this.state.description}
185+
width={400}
186+
className="mx_LocationPicker_description"
187+
/>
188+
189+
<DialogButtons primaryButton={_t('Share')}
190+
onPrimaryButtonClick={this.onOk}
191+
onCancel={this.props.onFinished}
192+
disabled={!this.state.position} />
193+
</form>
194+
</div>
195+
</div>
196+
);
197+
}
198+
}
199+
200+
export default LocationPicker;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
Copyright 2021 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
enum LocationShareType {
18+
Custom = -1,
19+
OnceOff = 0,
20+
OneMine = 60,
21+
FiveMins = 5 * 60,
22+
ThirtyMins = 30 * 60,
23+
OneHour = 60 * 60,
24+
ThreeHours = 3 * 60 * 60,
25+
SixHours = 6 * 60 * 60,
26+
OneDay = 24 * 60 * 60,
27+
Forever = Number.MAX_SAFE_INTEGER,
28+
}
29+
30+
export default LocationShareType;

0 commit comments

Comments
 (0)