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

Commit 15c2fb6

Browse files
author
Kerry
authored
Live location sharing - open location in OpenStreetMap (PSF-1040) (#8695)
* share plain lat,lon string from beacon tooltip and list item Signed-off-by: Kerry Archibald <[email protected]> * export makeMapSiteLink helper fn Signed-off-by: Kerry Archibald <[email protected]> * use currentColor in external-link.svg Signed-off-by: Kerry Archibald <[email protected]> * add open in openstreetmap link Signed-off-by: Kerry Archibald <[email protected]> * fussy import ordering Signed-off-by: Kerry Archibald <[email protected]> * fix icon color var Signed-off-by: Kerry Archibald <[email protected]>
1 parent 12abbf4 commit 15c2fb6

File tree

14 files changed

+254
-31
lines changed

14 files changed

+254
-31
lines changed

res/css/_components.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
@import "./components/views/beacon/_LiveTimeRemaining.scss";
1515
@import "./components/views/beacon/_OwnBeaconStatus.scss";
1616
@import "./components/views/beacon/_RoomLiveShareWarning.scss";
17+
@import "./components/views/beacon/_ShareLatestLocation.scss";
1718
@import "./components/views/beacon/_StyledLiveBeaconIcon.scss";
1819
@import "./components/views/location/_EnableLiveShare.scss";
1920
@import "./components/views/location/_LiveDurationDropdown.scss";

res/css/components/views/beacon/_BeaconStatusTooltip.scss

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ limitations under the License.
2121
height: 38px;
2222
box-sizing: content-box;
2323
padding-top: $spacing-8;
24-
25-
// override copyable text style to make compact
26-
.mx_CopyableText_copyButton {
27-
margin-left: 0 !important;
28-
}
2924
}
3025

3126
.mx_BeaconStatusTooltip_inner {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
Copyright 2022 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_ShareLatestLocation_icon {
18+
height: 13px;
19+
width: 13px;
20+
color: $secondary-content;
21+
}
22+
23+
.mx_ShareLatestLocation_copy {
24+
// override copyable text style to make compact
25+
.mx_CopyableText_copyButton {
26+
margin-left: $spacing-8 !important;
27+
}
28+
}

res/img/external-link.svg

Lines changed: 1 addition & 1 deletion
Loading

src/components/views/beacon/BeaconListItem.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ import { useEventEmitterState } from '../../../hooks/useEventEmitter';
2323
import { humanizeTime } from '../../../utils/humanize';
2424
import { _t } from '../../../languageHandler';
2525
import MemberAvatar from '../avatars/MemberAvatar';
26-
import CopyableText from '../elements/CopyableText';
2726
import BeaconStatus from './BeaconStatus';
2827
import { BeaconDisplayStatus } from './displayStatus';
2928
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
29+
import ShareLatestLocation from './ShareLatestLocation';
3030

3131
interface Props {
3232
beacon: Beacon;
@@ -69,10 +69,7 @@ const BeaconListItem: React.FC<Props> = ({ beacon }) => {
6969
label={beaconMember?.name || beacon.beaconInfo.description || beacon.beaconInfoOwner}
7070
displayStatus={BeaconDisplayStatus.Active}
7171
>
72-
<CopyableText
73-
border={false}
74-
getTextToCopy={() => latestLocationState?.uri}
75-
/>
72+
<ShareLatestLocation latestLocationState={latestLocationState} />
7673
</BeaconStatus>
7774
<span className='mx_BeaconListItem_lastUpdated'>{ _t("Updated %(humanizedUpdateTime)s", { humanizedUpdateTime }) }</span>
7875
</div>

src/components/views/beacon/BeaconStatusTooltip.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import { Beacon } from 'matrix-js-sdk/src/matrix';
1919
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
2020

2121
import MatrixClientContext from '../../../contexts/MatrixClientContext';
22-
import CopyableText from '../elements/CopyableText';
2322
import BeaconStatus from './BeaconStatus';
2423
import { BeaconDisplayStatus } from './displayStatus';
24+
import ShareLatestLocation from './ShareLatestLocation';
2525

2626
interface Props {
2727
beacon: Beacon;
@@ -50,10 +50,7 @@ const BeaconStatusTooltip: React.FC<Props> = ({ beacon }) => {
5050
displayLiveTimeRemaining
5151
className='mx_BeaconStatusTooltip_inner'
5252
>
53-
<CopyableText
54-
border={false}
55-
getTextToCopy={() => beacon.latestLocationState?.uri}
56-
/>
53+
<ShareLatestLocation latestLocationState={beacon.latestLocationState} />
5754
</BeaconStatus>
5855
</div>;
5956
};
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
Copyright 2022 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, { useEffect, useState } from 'react';
18+
import { BeaconLocationState } from 'matrix-js-sdk/src/content-helpers';
19+
20+
import { Icon as ExternalLinkIcon } from '../../../../res/img/external-link.svg';
21+
import { _t } from '../../../languageHandler';
22+
import { makeMapSiteLink, parseGeoUri } from '../../../utils/location';
23+
import CopyableText from '../elements/CopyableText';
24+
import TooltipTarget from '../elements/TooltipTarget';
25+
26+
interface Props {
27+
latestLocationState?: BeaconLocationState;
28+
}
29+
30+
const ShareLatestLocation: React.FC<Props> = ({ latestLocationState }) => {
31+
const [coords, setCoords] = useState(null);
32+
useEffect(() => {
33+
if (!latestLocationState) {
34+
return;
35+
}
36+
const coords = parseGeoUri(latestLocationState.uri);
37+
setCoords(coords);
38+
}, [latestLocationState]);
39+
40+
if (!latestLocationState || !coords) {
41+
return null;
42+
}
43+
44+
const latLonString = `${coords.latitude},${coords.longitude}`;
45+
const mapLink = makeMapSiteLink(coords);
46+
47+
return <>
48+
<TooltipTarget label={_t('Open in OpenStreetMap')}>
49+
<a
50+
data-test-id='open-location-in-osm'
51+
href={mapLink}
52+
target='_blank'
53+
rel='noreferrer noopener'
54+
>
55+
<ExternalLinkIcon className='mx_ShareLatestLocation_icon' />
56+
</a>
57+
</TooltipTarget>
58+
<CopyableText
59+
className='mx_ShareLatestLocation_copy'
60+
border={false}
61+
getTextToCopy={() => latLonString}
62+
/>
63+
</>;
64+
};
65+
66+
export default ShareLatestLocation;

src/components/views/context_menus/MessageContextMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
5050
import { GetRelationsForEvent, IEventTileOps } from "../rooms/EventTile";
5151
import { OpenForwardDialogPayload } from "../../../dispatcher/payloads/OpenForwardDialogPayload";
5252
import { OpenReportEventDialogPayload } from "../../../dispatcher/payloads/OpenReportEventDialogPayload";
53-
import { createMapSiteLink } from '../../../utils/location';
53+
import { createMapSiteLinkFromEvent } from '../../../utils/location';
5454

5555
interface IProps extends IPosition {
5656
chevronFace: ChevronFace;
@@ -360,7 +360,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
360360

361361
let openInMapSiteButton: JSX.Element;
362362
if (this.canOpenInMapSite(mxEvent)) {
363-
const mapSiteLink = createMapSiteLink(mxEvent);
363+
const mapSiteLink = createMapSiteLinkFromEvent(mxEvent);
364364
openInMapSiteButton = (
365365
<IconizedContextMenuOption
366366
iconClassName="mx_MessageContextMenu_iconOpenInMapSite"

src/components/views/elements/CopyableText.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ interface IProps {
2727
children?: React.ReactNode;
2828
getTextToCopy: () => string;
2929
border?: boolean;
30+
className?: string;
3031
}
3132

32-
const CopyableText: React.FC<IProps> = ({ children, getTextToCopy, border=true }) => {
33+
const CopyableText: React.FC<IProps> = ({ children, getTextToCopy, border=true, className }) => {
3334
const [tooltip, setTooltip] = useState<string | undefined>(undefined);
3435

3536
const onCopyClickInternal = async (e: ButtonEvent) => {
@@ -44,11 +45,11 @@ const CopyableText: React.FC<IProps> = ({ children, getTextToCopy, border=true }
4445
}
4546
};
4647

47-
const className = classNames("mx_CopyableText", {
48+
const combinedClassName = classNames("mx_CopyableText", className, {
4849
mx_CopyableText_border: border,
4950
});
5051

51-
return <div className={className}>
52+
return <div className={combinedClassName}>
5253
{ children }
5354
<AccessibleTooltipButton
5455
title={tooltip ?? _t("Copy")}

src/utils/location/map.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export const createMarker = (coords: GeolocationCoordinates, element: HTMLElemen
6565
return marker;
6666
};
6767

68-
const makeLink = (coords: GeolocationCoordinates): string => {
68+
export const makeMapSiteLink = (coords: GeolocationCoordinates): string => {
6969
return (
7070
"https://www.openstreetmap.org/" +
7171
`?mlat=${coords.latitude}` +
@@ -74,18 +74,18 @@ const makeLink = (coords: GeolocationCoordinates): string => {
7474
);
7575
};
7676

77-
export const createMapSiteLink = (event: MatrixEvent): string => {
77+
export const createMapSiteLinkFromEvent = (event: MatrixEvent): string => {
7878
const content: Object = event.getContent();
7979
const mLocation = content[M_LOCATION.name];
8080
if (mLocation !== undefined) {
8181
const uri = mLocation["uri"];
8282
if (uri !== undefined) {
83-
return makeLink(parseGeoUri(uri));
83+
return makeMapSiteLink(parseGeoUri(uri));
8484
}
8585
} else {
8686
const geoUri = content["geo_uri"];
8787
if (geoUri) {
88-
return makeLink(parseGeoUri(geoUri));
88+
return makeMapSiteLink(parseGeoUri(geoUri));
8989
}
9090
}
9191
return null;

0 commit comments

Comments
 (0)