From c66d54ba3990ccef8ab7668beff4551080c839a6 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 14 Nov 2021 00:16:26 +0000 Subject: [PATCH 01/28] first ugly cut at a location picker via maplibre --- package.json | 1 + res/css/views/location/_LocationPicker.scss | 38 ++++ res/css/views/rooms/_MessageComposer.scss | 4 + .../views/location/LocationPicker.tsx | 156 +++++++++++++++ .../views/rooms/MessageComposer.tsx | 58 ++++++ src/i18n/strings/en_EN.json | 13 ++ src/settings/Settings.tsx | 6 + yarn.lock | 177 +++++++++++++++++- 8 files changed, 452 insertions(+), 1 deletion(-) create mode 100644 res/css/views/location/_LocationPicker.scss create mode 100644 src/components/views/location/LocationPicker.tsx diff --git a/package.json b/package.json index c96942a4621..be92dabc396 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.20", + "maplibre-gl": "^1.15.2", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", "matrix-widget-api": "^0.1.0-beta.17", "minimist": "^1.2.5", diff --git a/res/css/views/location/_LocationPicker.scss b/res/css/views/location/_LocationPicker.scss new file mode 100644 index 00000000000..9af6920c020 --- /dev/null +++ b/res/css/views/location/_LocationPicker.scss @@ -0,0 +1,38 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_LocationPicker { + width: 450px; + height: 450px; + + border-radius: 4px; + + display: flex; +} + +.mx_LocationPicker_header { + padding: 4px 8px 0; + border-bottom: 1px solid $message-action-bar-border-color; +} + +.mx_LocationPicker_footer { + border-top: 1px solid $message-action-bar-border-color; + min-height: 72px; + + display: flex; + align-items: center; +} + diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 36472beae8d..edcce95b1f2 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -263,6 +263,10 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/composer/emoji.svg'); } +.mx_MessageComposer_location::before { + mask-image: url('$(res)/img/element-icons/roomlist/explore.svg'); +} + .mx_MessageComposer_stickers::before { mask-image: url('$(res)/img/element-icons/room/composer/sticker.svg'); } diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx new file mode 100644 index 00000000000..5a3541673ad --- /dev/null +++ b/src/components/views/location/LocationPicker.tsx @@ -0,0 +1,156 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import maplibregl from 'maplibre-gl'; + +import SdkConfig from '../../../SdkConfig'; +import Field from "../elements/Field"; +import DialogButtons from "../elements/DialogButtons"; +import Dropdown from "../elements/Dropdown"; + +import { _t } from '../../../languageHandler'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; + +enum LocationShareType { + CUSTOM = -1, + ONE_OFF = 0, + ONE_MIN = 60, + FIVE_MINS = 5 * 60, + THIRTY_MINS = 30 * 60, + ONE_HOUR = 60 * 60, + THREE_HOURS = 3 * 60 * 60, + SIX_HOURS = 6 * 60 * 60, + ONE_DAY = 24 * 60 * 60, + FOREVER = Number.MAX_SAFE_INTEGER, +} + +interface IDropdownProps { + value: JoinRule; + label: string; + width?: number; + onChange(type: LocationShareType): void; +} + +const LocationShareTypeDropdown = ({ + value, + width = 448, + onChange, +}: IDropDownProps) => { + const options = [ +
{ _t("custom location") }
, +
{ _t("current location as a one off") }
, +
{ _t("current location for one minute") }
, +
{ _t("current location for five minutes") }
, +
{ _t("current location for thirty minutes") }
, +
{ _t("current location for one hour") }
, +
{ _t("current location for three hours") }
, +
{ _t("current location for six hours") }
, +
{ _t("current location for one day") }
, +
{ _t("current location until I disable it") }
, + ]; + + return + { options } + ; +}; + +interface IProps { + onChoose(uri: string, type: string, description: string, beacon: boolean): boolean; +} + +interface IState { + description: string; + type: LocationShareType; +} + +@replaceableComponent("views.location.LocationPicker") +class LocationPicker extends React.Component { + + constructor(props) { + super(props); + + this.state = { + description: "", + type: LocationShareType.ONE_OFF, + }; + } + + componentDidMount() { + const config = SdkConfig.get(); + var map = new maplibregl.Map({ + container: 'mx_LocationPicker_map', + style: config.map_style_url, + center: [0, 0], + zoom: 1, + }); + } + + onDescriptionChange(description: string) { + // TODO + } + + onOk() { + // TODO + } + + onCancel() { + // TODO + } + + onTypeChange(type: LocationShareType) { + + } + + render() { + return ( +
+
+ Share location +
+
+
+
+
+ + + +
+ + +
+ ); + } +} + +export default LocationPicker; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index a9bf62f887b..ae145d6d0f5 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -50,6 +50,7 @@ import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInse import { Action } from "../../../dispatcher/actions"; import EditorModel from "../../../editor/model"; import EmojiPicker from '../emojipicker/EmojiPicker'; +import LocationPicker from '../location/LocationPicker'; import MemberStatusMessageAvatar from "../avatars/MemberStatusMessageAvatar"; import UIStore, { UI_EVENTS } from '../../../stores/UIStore'; import Modal from "../../../Modal"; @@ -126,6 +127,47 @@ const EmojiButton: React.FC = ({ addEmoji, menuPosition, narr ; }; +interface ILocationButtonProps { + room: Room; + shareLocation: (uri: string, type: string, description: string, beacon: boolean) => boolean; + menuPosition: any; // TODO: Types + narrowMode: boolean; +} + +const LocationButton: React.FC = ({ shareLocation, menuPosition, narrowMode }) => { + const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); + + let contextMenu; + if (menuDisplayed) { + const position = menuPosition ?? aboveLeftOf(button.current.getBoundingClientRect()); + contextMenu = + + ; + } + + const className = classNames( + "mx_MessageComposer_button", + "mx_MessageComposer_location", + { + "mx_MessageComposer_button_highlight": menuDisplayed, + }, + ); + + // TODO: replace ContextMenuTooltipButton with a unified representation of + // the header buttons and the right panel buttons + return + + + { contextMenu } + ; +}; + + interface IUploadButtonProps { roomId: string; relation?: IEventRelation | null; @@ -419,6 +461,11 @@ export default class MessageComposer extends React.Component { return true; }; + private shareLocation = (uri: string, type: string, description: string, beacon: boolean): boolean => { + console.log("Share location", uri, type, description, beacon); + return true; + } + private sendMessage = async () => { if (this.state.haveRecording && this.voiceRecordingButton.current) { // There shouldn't be any text message to send when a voice recording is active, so @@ -486,6 +533,17 @@ export default class MessageComposer extends React.Component { relation={this.props.relation} />, ); + if (SettingsStore.getValue("feature_location_share")) { + buttons.push( + , + ); + } buttons.push( , ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6a22904f310..0e6bc40cc53 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -828,6 +828,7 @@ "Offline encrypted messaging using dehydrated devices": "Offline encrypted messaging using dehydrated devices", "Send pseudonymous analytics data": "Send pseudonymous analytics data", "Polls (under active development)": "Polls (under active development)", + "Location sharing (under active development)": "Location sharing (under active development)", "Show info about bridges in room settings": "Show info about bridges in room settings", "New layout switcher (with message bubbles)": "New layout switcher (with message bubbles)", "Meta Spaces": "Meta Spaces", @@ -1613,6 +1614,7 @@ "Send message": "Send message", "Emoji picker": "Emoji picker", "Add emoji": "Add emoji", + "Share location": "Share location", "Upload file": "Upload file", "You do not have permission to start polls in this room.": "You do not have permission to start polls in this room.", "Create poll": "Create poll", @@ -2056,6 +2058,17 @@ "edited": "edited", "Submit logs": "Submit logs", "Can't load this message": "Can't load this message", + "custom location": "custom location", + "current location as a one off": "current location as a one off", + "current location for one minute": "current location for one minute", + "current location for five minutes": "current location for five minutes", + "current location for thirty minutes": "current location for thirty minutes", + "current location for one hour": "current location for one hour", + "current location for three hours": "current location for three hours", + "current location for six hours": "current location for six hours", + "current location for one day": "current location for one day", + "current location until I disable it": "current location until I disable it", + "Share my": "Share my", "Failed to load group members": "Failed to load group members", "Filter community members": "Filter community members", "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Are you sure you want to remove '%(roomName)s' from %(groupId)s?", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index c263317dc49..c326b968a1a 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -259,6 +259,12 @@ export const SETTINGS: {[setting: string]: ISetting} = { displayName: _td("Polls (under active development)"), default: false, }, + "feature_location_share": { + isFeature: true, + supportedLevels: LEVELS_FEATURE, + displayName: _td("Location sharing (under active development)"), + default: false, + }, "doNotDisturb": { supportedLevels: [SettingLevel.DEVICE], default: false, diff --git a/yarn.lock b/yarn.lock index 7140510564a..a9bd0fab70f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1306,6 +1306,56 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@mapbox/geojson-rewind@^0.5.0": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@mapbox/geojson-rewind/-/geojson-rewind-0.5.1.tgz#adbe16dc683eb40e90934c51a5e28c7bbf44f4e1" + integrity sha512-eL7fMmfTBKjrb+VFHXCGv9Ot0zc3C0U+CwXo1IrP+EPwDczLoXv34Tgq3y+2mPSFNVUXgU42ILWJTC7145KPTA== + dependencies: + get-stream "^6.0.1" + minimist "^1.2.5" + +"@mapbox/geojson-types@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz#9aecf642cb00eab1080a57c4f949a65b4a5846d6" + integrity sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw== + +"@mapbox/jsonlint-lines-primitives@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234" + integrity sha1-zlblOfg1UrWNENZy6k1vya3HsjQ= + +"@mapbox/mapbox-gl-supported@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz#f60b6a55a5d8e5ee908347d2ce4250b15103dc8e" + integrity sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg== + +"@mapbox/point-geometry@0.1.0", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2" + integrity sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI= + +"@mapbox/tiny-sdf@^1.1.1": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz#424c620a96442b20402552be70a7f62a8407cc59" + integrity sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw== + +"@mapbox/unitbezier@^0.0.0": + version "0.0.0" + resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz#15651bd553a67b8581fb398810c98ad86a34524e" + integrity sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4= + +"@mapbox/vector-tile@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz#d3a74c90402d06e89ec66de49ec817ff53409666" + integrity sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw== + dependencies: + "@mapbox/point-geometry" "~0.1.0" + +"@mapbox/whoots-js@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe" + integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q== + "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz": version "3.2.3" resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz#cc332fdd25c08ef0e40f4d33fc3f822a0f98b6f4" @@ -2996,6 +3046,11 @@ css-what@^5.0.0, css-what@^5.0.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== +csscolorparser@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b" + integrity sha1-s085HupNqPPpgjHizNjfnAQfFxs= + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -3277,6 +3332,11 @@ domutils@^2.5.2, domutils@^2.6.0, domutils@^2.7.0: domelementtype "^2.2.0" domhandler "^4.2.0" +earcut@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.3.tgz#d44ced2ff5a18859568e327dd9c7d46b16f55cf4" + integrity sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -4112,6 +4172,11 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +geojson-vt@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/geojson-vt/-/geojson-vt-3.2.1.tgz#f8adb614d2c1d3f6ee7c4265cad4bbf3ad60c8b7" + integrity sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg== + get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -4150,6 +4215,11 @@ get-stream@^5.0.0: dependencies: pump "^3.0.0" +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -4175,6 +4245,11 @@ gfm.css@^1.1.2: resolved "https://registry.yarnpkg.com/gfm.css/-/gfm.css-1.1.2.tgz#94acfa600672663b9dd0fd4b6ee5d11c8dbc161e" integrity sha512-KhK3rqxMj+UTLRxWnfUA5n8XZYMWfHrrcCxtWResYR2B3hWIqBM6v9FPGZSlVuX+ScLewizOvNkjYXuPs95ThQ== +gl-matrix@^3.2.1: + version "3.4.3" + resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.4.3.tgz#fc1191e8320009fd4d20e9339595c6041ddc22c9" + integrity sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA== + glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -4256,6 +4331,11 @@ graceful-fs@^4.2.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +grid-index@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/grid-index/-/grid-index-1.1.0.tgz#97f8221edec1026c8377b86446a7c71e79522ea7" + integrity sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -4465,7 +4545,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13: +ieee754@^1.1.12, ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5638,6 +5718,11 @@ katex@^0.12.0: dependencies: commander "^2.19.0" +kdbush@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-3.0.0.tgz#f8484794d47004cc2d85ed3a79353dbe0abc2bf0" + integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew== + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -5864,6 +5949,35 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +maplibre-gl@^1.15.2: + version "1.15.2" + resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-1.15.2.tgz#7fb47868b62455af916c090903f2154394450f9c" + integrity sha512-uPeV530apb4JfX3cRFfE+awFnbcJTOnCv2QvY4mw4huiInbybElWYkNzTs324YLSADq0f4bidRoYcR81ho3aLA== + dependencies: + "@mapbox/geojson-rewind" "^0.5.0" + "@mapbox/geojson-types" "^1.0.2" + "@mapbox/jsonlint-lines-primitives" "^2.0.2" + "@mapbox/mapbox-gl-supported" "^1.5.0" + "@mapbox/point-geometry" "^0.1.0" + "@mapbox/tiny-sdf" "^1.1.1" + "@mapbox/unitbezier" "^0.0.0" + "@mapbox/vector-tile" "^1.3.1" + "@mapbox/whoots-js" "^3.1.0" + csscolorparser "~1.0.3" + earcut "^2.2.2" + geojson-vt "^3.2.1" + gl-matrix "^3.2.1" + grid-index "^1.1.0" + minimist "^1.2.5" + murmurhash-js "^1.0.0" + pbf "^3.2.1" + potpack "^1.0.1" + quickselect "^2.0.0" + rw "^1.3.3" + supercluster "^7.1.0" + tinyqueue "^2.0.3" + vt-pbf "^3.1.1" + mathml-tag-names@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" @@ -6101,6 +6215,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +murmurhash-js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51" + integrity sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E= + nanoid@^3.1.28: version "3.1.30" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" @@ -6570,6 +6689,14 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pbf@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/pbf/-/pbf-3.2.1.tgz#b4c1b9e72af966cd82c6531691115cc0409ffe2a" + integrity sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ== + dependencies: + ieee754 "^1.1.12" + resolve-protobuf-schema "^2.1.0" + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -6731,6 +6858,11 @@ posthog-js@1.12.2: dependencies: fflate "^0.4.1" +potpack@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14" + integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -6790,6 +6922,11 @@ prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" +protocol-buffers-schema@^3.3.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03" + integrity sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw== + psl@^1.1.28, psl@^1.1.33: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" @@ -6865,6 +7002,11 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +quickselect@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" + integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw== + raf-schd@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" @@ -7262,6 +7404,13 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-protobuf-schema@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz#9ca9a9e69cf192bbdaf1006ec1973948aa4a3758" + integrity sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ== + dependencies: + protocol-buffers-schema "^3.3.1" + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -7335,6 +7484,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rw@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" + integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q= + rxjs@^6.5.2: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -7915,6 +8069,13 @@ sugarss@^2.0.0: dependencies: postcss "^7.0.2" +supercluster@^7.1.0: + version "7.1.4" + resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-7.1.4.tgz#6762aabfd985d3390b49f13b815567d5116a828a" + integrity sha512-GhKkRM1jMR6WUwGPw05fs66pOFWhf59lXq+Q3J3SxPvhNcmgOtLRV6aVQPMRsmXdpaeFJGivt+t7QXUPL3ff4g== + dependencies: + kdbush "^3.0.0" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -8011,6 +8172,11 @@ tiny-invariant@^1.0.6: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== +tinyqueue@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08" + integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA== + tmatch@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-2.0.1.tgz#0c56246f33f30da1b8d3d72895abaf16660f38cf" @@ -8406,6 +8572,15 @@ vfile@^4.0.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" +vt-pbf@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.3.tgz#68fd150756465e2edae1cc5c048e063916dcfaac" + integrity sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA== + dependencies: + "@mapbox/point-geometry" "0.1.0" + "@mapbox/vector-tile" "^1.3.1" + pbf "^3.2.1" + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" From 7970b903aa04f402015d79808eba05d92f77fb4e Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 14 Nov 2021 00:50:54 +0000 Subject: [PATCH 02/28] fix css --- res/css/_common.scss | 5 ++- res/css/_components.scss | 1 + res/css/views/location/_LocationPicker.scss | 18 ++++---- .../views/location/LocationPicker.tsx | 45 +++++++++---------- src/i18n/strings/en_EN.json | 21 +++++---- 5 files changed, 47 insertions(+), 43 deletions(-) diff --git a/res/css/_common.scss b/res/css/_common.scss index d6d139d2bd4..62af26bbb61 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -1,7 +1,8 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd -Copyright 2017 New Vector Ltd +Copyright 2017 - 2019 New Vector Ltd +Copyright 2019 - 2021 The Matrix.org Foundation C.I.C Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +21,8 @@ limitations under the License. @import "./_font-weights.scss"; @import "./_animations.scss"; +@import url("maplibre-gl/dist/maplibre-gl.css"); + $hover-transition: 0.08s cubic-bezier(.46, .03, .52, .96); // quadratic $selected-message-border-width: 4px; diff --git a/res/css/_components.scss b/res/css/_components.scss index f59da633d71..07353b5b240 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -172,6 +172,7 @@ @import "./views/groups/_GroupPublicityToggle.scss"; @import "./views/groups/_GroupRoomList.scss"; @import "./views/groups/_GroupUserSettings.scss"; +@import "./views/location/_LocationPicker.scss"; @import "./views/messages/_CallEvent.scss"; @import "./views/messages/_CreateEvent.scss"; @import "./views/messages/_DateSeparator.scss"; diff --git a/res/css/views/location/_LocationPicker.scss b/res/css/views/location/_LocationPicker.scss index 9af6920c020..5e7ae28f01a 100644 --- a/res/css/views/location/_LocationPicker.scss +++ b/res/css/views/location/_LocationPicker.scss @@ -16,23 +16,25 @@ limitations under the License. .mx_LocationPicker { width: 450px; - height: 450px; + height: 500px; border-radius: 4px; display: flex; + flex-direction: column; } -.mx_LocationPicker_header { - padding: 4px 8px 0; - border-bottom: 1px solid $message-action-bar-border-color; + +#mx_LocationPicker_map { + height: 324px; } .mx_LocationPicker_footer { - border-top: 1px solid $message-action-bar-border-color; - min-height: 72px; + margin: 24px; + // border-top: 1px solid $message-action-bar-border-color; + // min-height: 72px; - display: flex; - align-items: center; + // display: flex; + // align-items: center; } diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 5a3541673ad..95d6f7450cb 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -47,29 +47,28 @@ interface IDropdownProps { const LocationShareTypeDropdown = ({ value, - width = 448, + width, onChange, }: IDropDownProps) => { const options = [ -
{ _t("custom location") }
, -
{ _t("current location as a one off") }
, -
{ _t("current location for one minute") }
, -
{ _t("current location for five minutes") }
, -
{ _t("current location for thirty minutes") }
, -
{ _t("current location for one hour") }
, -
{ _t("current location for three hours") }
, -
{ _t("current location for six hours") }
, -
{ _t("current location for one day") }
, -
{ _t("current location until I disable it") }
, +
{ _t("Share custom location") }
, +
{ _t("Share my current location as a one off") }
, +
{ _t("Share my current location for one minute") }
, +
{ _t("Share my current location for five minutes") }
, +
{ _t("Share my current location for thirty minutes") }
, +
{ _t("Share my current location for one hour") }
, +
{ _t("Share my current location for three hours") }
, +
{ _t("Share my current location for six hours") }
, +
{ _t("Share my current location for one day") }
, +
{ _t("Share my current location until I disable it") }
, ]; return { options } ; @@ -125,29 +124,29 @@ class LocationPicker extends React.Component { render() { return (
-
- Share location -
-
-
+
+ -
- - + + + +
); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0e6bc40cc53..1db58c9a768 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2058,17 +2058,16 @@ "edited": "edited", "Submit logs": "Submit logs", "Can't load this message": "Can't load this message", - "custom location": "custom location", - "current location as a one off": "current location as a one off", - "current location for one minute": "current location for one minute", - "current location for five minutes": "current location for five minutes", - "current location for thirty minutes": "current location for thirty minutes", - "current location for one hour": "current location for one hour", - "current location for three hours": "current location for three hours", - "current location for six hours": "current location for six hours", - "current location for one day": "current location for one day", - "current location until I disable it": "current location until I disable it", - "Share my": "Share my", + "Share custom location": "Share custom location", + "Share my current location as a one off": "Share my current location as a one off", + "Share my current location for one minute": "Share my current location for one minute", + "Share my current location for five minutes": "Share my current location for five minutes", + "Share my current location for thirty minutes": "Share my current location for thirty minutes", + "Share my current location for one hour": "Share my current location for one hour", + "Share my current location for three hours": "Share my current location for three hours", + "Share my current location for six hours": "Share my current location for six hours", + "Share my current location for one day": "Share my current location for one day", + "Share my current location until I disable it": "Share my current location until I disable it", "Failed to load group members": "Failed to load group members", "Filter community members": "Filter community members", "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Are you sure you want to remove '%(roomName)s' from %(groupId)s?", From 12bb69bfd078d9d0789f1e237e91360dfe65973b Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 14 Nov 2021 00:57:00 +0000 Subject: [PATCH 03/28] fix dropdown height --- res/css/views/location/_LocationPicker.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/css/views/location/_LocationPicker.scss b/res/css/views/location/_LocationPicker.scss index 5e7ae28f01a..393d5b2cb32 100644 --- a/res/css/views/location/_LocationPicker.scss +++ b/res/css/views/location/_LocationPicker.scss @@ -36,5 +36,9 @@ limitations under the License. // display: flex; // align-items: center; + + .mx_Dropdown_menu { + max-height: 140px; + } } From 1b75489866991e40c1da1c8b4b6556d06dc66648 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 14 Nov 2021 23:28:59 +0000 Subject: [PATCH 04/28] fix form --- .../views/location/LocationPicker.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 95d6f7450cb..45efd5618bf 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -105,21 +105,21 @@ class LocationPicker extends React.Component { }); } - onDescriptionChange(description: string) { - // TODO - } + private onDescriptionChange = (ev: ChangeEvent) => { + this.setState({ description: ev.target.value }); + }; - onOk() { + private onOk = () => { // TODO - } + }; - onCancel() { + private onCancel = () => { // TODO - } - - onTypeChange(type: LocationShareType) { + }; - } + private onTypeChange= (type: LocationShareType) => { + this.setState({ type }); + }; render() { return ( From cd9ea959728d2b3a504dd4b31d7a7c967ed001ce Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 14 Nov 2021 23:29:10 +0000 Subject: [PATCH 05/28] use right icon --- res/css/views/rooms/_MessageComposer.scss | 2 +- res/img/element-icons/room/composer/location.svg | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 res/img/element-icons/room/composer/location.svg diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index edcce95b1f2..2f7b407f586 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -264,7 +264,7 @@ limitations under the License. } .mx_MessageComposer_location::before { - mask-image: url('$(res)/img/element-icons/roomlist/explore.svg'); + mask-image: url('$(res)/img/element-icons/room/composer/location.svg'); } .mx_MessageComposer_stickers::before { diff --git a/res/img/element-icons/room/composer/location.svg b/res/img/element-icons/room/composer/location.svg new file mode 100644 index 00000000000..71186454433 --- /dev/null +++ b/res/img/element-icons/room/composer/location.svg @@ -0,0 +1,3 @@ + + + From 3a779b7c6ec3a2a5a4c64fe7a76a09992cd49289 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 15 Nov 2021 00:17:18 +0000 Subject: [PATCH 06/28] hook up locationpicker --- .../views/location/LocationPicker.tsx | 54 ++++++++++++++++--- .../views/rooms/MessageComposer.tsx | 6 +-- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 45efd5618bf..2baec8a54a4 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -75,12 +75,14 @@ const LocationShareTypeDropdown = ({ }; interface IProps { - onChoose(uri: string, type: string, description: string, beacon: boolean): boolean; + onChoose(uri: string, ts: integer, type: LocationShareType, description: string): boolean; + onCancel(); } interface IState { description: string; type: LocationShareType; + position: GeolocationPosition; } @replaceableComponent("views.location.LocationPicker") @@ -92,29 +94,67 @@ class LocationPicker extends React.Component { this.state = { description: "", type: LocationShareType.ONE_OFF, + position: undefined, }; } componentDidMount() { const config = SdkConfig.get(); - var map = new maplibregl.Map({ + this.map = new maplibregl.Map({ container: 'mx_LocationPicker_map', style: config.map_style_url, center: [0, 0], zoom: 1, }); + + // Add geolocate control to the map. + this.geolocate = new maplibregl.GeolocateControl({ + positionOptions: { + enableHighAccuracy: true + }, + trackUserLocation: true, + }); + this.map.addControl(this.geolocate); + + this.map.on('load', ()=>{ + this.geolocate.trigger(); + }); + + this.geolocate.on('geolocate', this.onGeolocate); + } + + componentWillUnmount() { + this.geolocate.off('geolocate', this.onGeolocate); + } + + private onGeolocate = (position) => { + this.setState({ position }); } private onDescriptionChange = (ev: ChangeEvent) => { this.setState({ description: ev.target.value }); }; - private onOk = () => { - // TODO + private getGeoUri = () => { + if (!this.state.position) { + return; + } + + return (`geo:${ this.state.position.coords.latitude }` + + `,${ this.state.position.coords.longitude }` + + ( this.state.position.coords.altitude != null ? + `,${this.state.position.coords.altitude}` : '' ) + + `;u=${ this.state.position.coords.accuracy }`); }; - private onCancel = () => { - // TODO + private onOk = () => { + this.props.onChoose( + this.getGeoUri(), + this.state.position ? this.state.position.timestamp : undefined, + this.state.type, + this.state.description, + ); + this.props.onFinished(); }; private onTypeChange= (type: LocationShareType) => { @@ -144,7 +184,7 @@ class LocationPicker extends React.Component { + onCancel={this.props.onFinished} /> diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index ae145d6d0f5..5b5365defc7 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -141,7 +141,7 @@ const LocationButton: React.FC = ({ shareLocation, menuPos if (menuDisplayed) { const position = menuPosition ?? aboveLeftOf(button.current.getBoundingClientRect()); contextMenu = - + ; } @@ -461,8 +461,8 @@ export default class MessageComposer extends React.Component { return true; }; - private shareLocation = (uri: string, type: string, description: string, beacon: boolean): boolean => { - console.log("Share location", uri, type, description, beacon); + private shareLocation = (uri: string, ts: int, type: LocationShareType, description: string): boolean => { + console.log("Share location", uri, ts, type, description); return true; } From 3b0a3a22798e72f41075f589aa0c108996022c06 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 15 Nov 2021 00:55:52 +0000 Subject: [PATCH 07/28] actually send m.location events --- .../views/location/LocationPicker.tsx | 18 +++++++----------- .../views/rooms/MessageComposer.tsx | 19 +++++++++++++++++-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 2baec8a54a4..355aeff27fb 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -135,21 +135,17 @@ class LocationPicker extends React.Component { this.setState({ description: ev.target.value }); }; - private getGeoUri = () => { - if (!this.state.position) { - return; - } - - return (`geo:${ this.state.position.coords.latitude }` + - `,${ this.state.position.coords.longitude }` + - ( this.state.position.coords.altitude != null ? - `,${this.state.position.coords.altitude}` : '' ) + - `;u=${ this.state.position.coords.accuracy }`); + private getGeoUri = (position) => { + return (`geo:${ position.coords.latitude },` + + position.coords.longitude + + ( position.coords.altitude != null ? + `,${ position.coords.altitude }` : '' ) + + `;u=${ position.coords.accuracy }`); }; private onOk = () => { this.props.onChoose( - this.getGeoUri(), + this.state.position ? this.getGeoUri(this.state.position) : undefined, this.state.position ? this.state.position.timestamp : undefined, this.state.type, this.state.description, diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 5b5365defc7..d5d3dbdf1ab 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -59,6 +59,8 @@ import RoomContext from '../../../contexts/RoomContext'; import { POLL_START_EVENT_TYPE } from "../../../polls/consts"; import ErrorDialog from "../dialogs/ErrorDialog"; import PollCreateDialog from "../elements/PollCreateDialog"; +import { MsgType } from "matrix-js-sdk/src/@types/event"; +import { logger } from "matrix-js-sdk/src/logger"; let instanceCount = 0; const NARROW_MODE_BREAKPOINT = 500; @@ -129,7 +131,7 @@ const EmojiButton: React.FC = ({ addEmoji, menuPosition, narr interface ILocationButtonProps { room: Room; - shareLocation: (uri: string, type: string, description: string, beacon: boolean) => boolean; + shareLocation: (uri: string, ts: int, type: LocationShareType, description: string) => boolean; menuPosition: any; // TODO: Types narrowMode: boolean; } @@ -462,7 +464,20 @@ export default class MessageComposer extends React.Component { }; private shareLocation = (uri: string, ts: int, type: LocationShareType, description: string): boolean => { - console.log("Share location", uri, ts, type, description); + try { + const text = `${description ? description : 'Location'} at ${uri} at ${new Date(ts).toISOString()}`; + // noinspection ES6MissingAwait - we don't care if it fails, it'll get queued. + MatrixClientPeg.get().sendMessage(this.props.room.roomId, { + "body": text, + "msgtype": MsgType.Location, + "geo_uri": uri, + "org.matrix.msc3488.location": { uri, description }, + "org.matrix.msc3488.ts": ts, + // TODO: MSC1767 fallbacks for text & thumbnail + }); + } catch (e) { + logger.error("Error sending location:", e); + } return true; } From 6ce1e86ae3ca1507c028a4002957c8ea9555c203 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 15 Nov 2021 02:04:42 +0000 Subject: [PATCH 08/28] view m.location --- res/css/_components.scss | 1 + res/css/views/messages/_MLocationBody.scss | 22 ++++++ .../views/messages/MLocationBody.tsx | 77 +++++++++++++++++++ .../views/messages/MessageEvent.tsx | 8 ++ .../views/rooms/MessageComposer.tsx | 3 +- 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 res/css/views/messages/_MLocationBody.scss create mode 100644 src/components/views/messages/MLocationBody.tsx diff --git a/res/css/_components.scss b/res/css/_components.scss index 07353b5b240..2d8906914fb 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -182,6 +182,7 @@ @import "./views/messages/_MImageBody.scss"; @import "./views/messages/_MImageReplyBody.scss"; @import "./views/messages/_MJitsiWidgetEvent.scss"; +@import "./views/messages/_MLocationBody.scss"; @import "./views/messages/_MNoticeBody.scss"; @import "./views/messages/_MPollBody.scss"; @import "./views/messages/_MStickerBody.scss"; diff --git a/res/css/views/messages/_MLocationBody.scss b/res/css/views/messages/_MLocationBody.scss new file mode 100644 index 00000000000..a8f378b0eac --- /dev/null +++ b/res/css/views/messages/_MLocationBody.scss @@ -0,0 +1,22 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_MLocationBody { + width: 450px; + height: 300px; + + border-radius: $timelineImageBorderRadius; +} diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx new file mode 100644 index 00000000000..04e17cf51b7 --- /dev/null +++ b/src/components/views/messages/MLocationBody.tsx @@ -0,0 +1,77 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import maplibregl from 'maplibre-gl'; +import SdkConfig from '../../../SdkConfig'; +import { _t } from '../../../languageHandler'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { IBodyProps } from "./IBodyProps"; + +@replaceableComponent("views.messages.MLocationBody") +export default class MLocationBody extends React.Component { + constructor(props: IBodyProps) { + super(props); + + const content = this.props.mxEvent.getContent(); + const uri = content['org.matrix.msc3488.location'] ? + content['org.matrix.msc3488.location'].uri : + content['geo_uri']; + + this.coords = this.parseGeoUri(uri); + } + + private parseGeoUri = (uri) => { + const m = uri.match(/^\s*geo:(.*?)\s*$/); + if (!m) return; + const parts = m[1].split(';'); + const coords = parts[0].split(','); + let uncertainty; + for (const param of parts.slice(1)) { + const m = param.match(/u=(.*)/); + if (m) uncertainty = m[1]; + } + return { + 'latitude': coords[0], + 'longitude': coords[1], + 'altitude': coords[2], + 'accuracy': uncertainty, + }; + }; + + componentDidMount() { + const config = SdkConfig.get(); + this.map = new maplibregl.Map({ + container: this.getBodyId(), + style: config.map_style_url, + center: [this.coords.longitude, this.coords.latitude], + zoom: 13, + }); + + var marker = new maplibregl.Marker() + .setLngLat([this.coords.longitude, this.coords.latitude]) + .addTo(this.map); + } + + private getBodyId = () => { + return `mx_MLocationBody_${this.props.mxEvent.getId()}`; + }; + + render() { + return
+
; + } +} diff --git a/src/components/views/messages/MessageEvent.tsx b/src/components/views/messages/MessageEvent.tsx index 9590cd1ed76..5e6c6daabd9 100644 --- a/src/components/views/messages/MessageEvent.tsx +++ b/src/components/views/messages/MessageEvent.tsx @@ -121,6 +121,14 @@ export default class MessageEvent extends React.Component implements IMe BodyType = sdk.getComponent('messages.MPollBody'); } } + + if ((type && type === "org.matrix.msc3488.location") || + (type && type === EventType.RoomMessage && msgtype && msgtype === MsgType.Location)) { + // TODO: tidy this up once location sharing is out of labs + if (SettingsStore.getValue("feature_location_share")) { + BodyType = sdk.getComponent('messages.MLocationBody'); + } + } } if (SettingsStore.getValue("feature_mjolnir")) { diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index d5d3dbdf1ab..2568bd2287f 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -464,8 +464,9 @@ export default class MessageComposer extends React.Component { }; private shareLocation = (uri: string, ts: int, type: LocationShareType, description: string): boolean => { + if (!uri) return false; try { - const text = `${description ? description : 'Location'} at ${uri} at ${new Date(ts).toISOString()}`; + const text = `${description ? description : 'Location'} at ${uri} as of ${new Date(ts).toISOString()}`; // noinspection ES6MissingAwait - we don't care if it fails, it'll get queued. MatrixClientPeg.get().sendMessage(this.props.room.roomId, { "body": text, From e7cd207fa3a1637f6d245d21c32b70ab19ac2eba Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 15 Nov 2021 02:07:54 +0000 Subject: [PATCH 09/28] border radius on picker --- res/css/views/location/_LocationPicker.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/views/location/_LocationPicker.scss b/res/css/views/location/_LocationPicker.scss index 393d5b2cb32..406cdafcd78 100644 --- a/res/css/views/location/_LocationPicker.scss +++ b/res/css/views/location/_LocationPicker.scss @@ -27,6 +27,7 @@ limitations under the License. #mx_LocationPicker_map { height: 324px; + border-radius: 8px 8px 0px 0px; } .mx_LocationPicker_footer { From fc41580e2dcf8f356d1b4274efe42ff9aa14cfea Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 21 Nov 2021 17:37:17 +0100 Subject: [PATCH 10/28] fix lint --- .../views/location/LocationPicker.tsx | 33 +++++++++---------- .../views/messages/MLocationBody.tsx | 14 ++++---- .../views/rooms/MessageComposer.tsx | 3 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 355aeff27fb..2894c0424f1 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -47,20 +47,21 @@ interface IDropdownProps { const LocationShareTypeDropdown = ({ value, + label, width, onChange, -}: IDropDownProps) => { +}: IDropdownProps) => { const options = [ -
{ _t("Share custom location") }
, -
{ _t("Share my current location as a one off") }
, -
{ _t("Share my current location for one minute") }
, -
{ _t("Share my current location for five minutes") }
, -
{ _t("Share my current location for thirty minutes") }
, -
{ _t("Share my current location for one hour") }
, -
{ _t("Share my current location for three hours") }
, -
{ _t("Share my current location for six hours") }
, -
{ _t("Share my current location for one day") }
, -
{ _t("Share my current location until I disable it") }
, +
{ _t("Share custom location") }
, +
{ _t("Share my current location as a one off") }
, +
{ _t("Share my current location for one minute") }
, +
{ _t("Share my current location for five minutes") }
, +
{ _t("Share my current location for thirty minutes") }
, +
{ _t("Share my current location for one hour") }
, +
{ _t("Share my current location for three hours") }
, +
{ _t("Share my current location for six hours") }
, +
{ _t("Share my current location for one day") }
, +
{ _t("Share my current location until I disable it") }
, ]; return { - constructor(props) { super(props); @@ -95,7 +95,7 @@ class LocationPicker extends React.Component { description: "", type: LocationShareType.ONE_OFF, position: undefined, - }; + }; } componentDidMount() { @@ -110,7 +110,7 @@ class LocationPicker extends React.Component { // Add geolocate control to the map. this.geolocate = new maplibregl.GeolocateControl({ positionOptions: { - enableHighAccuracy: true + enableHighAccuracy: true, }, trackUserLocation: true, }); @@ -129,7 +129,7 @@ class LocationPicker extends React.Component { private onGeolocate = (position) => { this.setState({ position }); - } + }; private onDescriptionChange = (ev: ChangeEvent) => { this.setState({ description: ev.target.value }); @@ -160,8 +160,7 @@ class LocationPicker extends React.Component { render() { return (
-
-
+
{ 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 uri = content['org.matrix.msc3488.location'] ? - content['org.matrix.msc3488.location'].uri : - content['geo_uri']; + content['org.matrix.msc3488.location'].uri : + content['geo_uri']; this.coords = this.parseGeoUri(uri); } @@ -61,7 +64,7 @@ export default class MLocationBody extends React.Component { zoom: 13, }); - var marker = new maplibregl.Marker() + new maplibregl.Marker() .setLngLat([this.coords.longitude, this.coords.latitude]) .addTo(this.map); } @@ -71,7 +74,6 @@ export default class MLocationBody extends React.Component { }; render() { - return
-
; + return
; } } diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 2568bd2287f..7d9d1f76a69 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -169,7 +169,6 @@ const LocationButton: React.FC = ({ shareLocation, menuPos ; }; - interface IUploadButtonProps { roomId: string; relation?: IEventRelation | null; @@ -480,7 +479,7 @@ export default class MessageComposer extends React.Component { logger.error("Error sending location:", e); } return true; - } + }; private sendMessage = async () => { if (this.state.haveRecording && this.voiceRecordingButton.current) { From ccd416dd45ddc315bd53068138923a4c95ac96e5 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 21 Nov 2021 18:57:28 +0100 Subject: [PATCH 11/28] fix css var --- res/css/views/messages/_MLocationBody.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/messages/_MLocationBody.scss b/res/css/views/messages/_MLocationBody.scss index a8f378b0eac..7777012518a 100644 --- a/res/css/views/messages/_MLocationBody.scss +++ b/res/css/views/messages/_MLocationBody.scss @@ -18,5 +18,5 @@ limitations under the License. width: 450px; height: 300px; - border-radius: $timelineImageBorderRadius; + border-radius: $timeline-image-border-radius; } From eebf29dbc7418e54bf2e294ec95d65989d8b7eae Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 21 Nov 2021 20:05:58 +0100 Subject: [PATCH 12/28] fix types --- package.json | 1 + .../views/location/LocationPicker.tsx | 35 ++++++++----------- .../views/location/LocationShareType.tsx | 28 +++++++++++++++ .../views/messages/MLocationBody.tsx | 24 +++++++++---- .../views/rooms/MessageComposer.tsx | 5 +-- src/i18n/strings/en_EN.json | 1 + src/settings/controllers/SettingController.ts | 2 ++ yarn.lock | 5 +++ 8 files changed, 71 insertions(+), 30 deletions(-) create mode 100644 src/components/views/location/LocationShareType.tsx diff --git a/package.json b/package.json index be92dabc396..856e55354a7 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "@babel/runtime": "^7.12.5", "@sentry/browser": "^6.11.0", "@sentry/tracing": "^6.11.0", + "@types/geojson": "^7946.0.8", "await-lock": "^2.1.0", "blurhash": "^1.1.3", "browser-encrypt-attachment": "^0.3.0", diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 2894c0424f1..17f5b57167d 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -21,25 +21,13 @@ import SdkConfig from '../../../SdkConfig'; import Field from "../elements/Field"; import DialogButtons from "../elements/DialogButtons"; import Dropdown from "../elements/Dropdown"; +import { LocationShareType } from "./LocationShareType"; import { _t } from '../../../languageHandler'; import { replaceableComponent } from "../../../utils/replaceableComponent"; -enum LocationShareType { - CUSTOM = -1, - ONE_OFF = 0, - ONE_MIN = 60, - FIVE_MINS = 5 * 60, - THIRTY_MINS = 30 * 60, - ONE_HOUR = 60 * 60, - THREE_HOURS = 3 * 60 * 60, - SIX_HOURS = 6 * 60 * 60, - ONE_DAY = 24 * 60 * 60, - FOREVER = Number.MAX_SAFE_INTEGER, -} - interface IDropdownProps { - value: JoinRule; + value: LocationShareType; label: string; width?: number; onChange(type: LocationShareType): void; @@ -67,17 +55,18 @@ const LocationShareTypeDropdown = ({ return { onChange(LocationShareType[LocationShareType[parseInt(key)]]) }} + menuWidth={width} + label={label} + value={value.toString()} > { options } ; }; interface IProps { - onChoose(uri: string, ts: integer, type: LocationShareType, description: string): boolean; - onCancel(); + onChoose(uri: string, ts: number, type: LocationShareType, description: string): boolean; + onFinished(); } interface IState { @@ -88,6 +77,9 @@ interface IState { @replaceableComponent("views.location.LocationPicker") class LocationPicker extends React.Component { + private map : maplibregl.Map; + private geolocate : maplibregl.GeolocateControl; + constructor(props) { super(props); @@ -131,7 +123,7 @@ class LocationPicker extends React.Component { this.setState({ position }); }; - private onDescriptionChange = (ev: ChangeEvent) => { + private onDescriptionChange = (ev: React.ChangeEvent) => { this.setState({ description: ev.target.value }); }; @@ -162,9 +154,10 @@ class LocationPicker extends React.Component {
- + diff --git a/src/components/views/location/LocationShareType.tsx b/src/components/views/location/LocationShareType.tsx new file mode 100644 index 00000000000..b0e1611fbe6 --- /dev/null +++ b/src/components/views/location/LocationShareType.tsx @@ -0,0 +1,28 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export enum LocationShareType { + CUSTOM = -1, + ONE_OFF = 0, + ONE_MIN = 60, + FIVE_MINS = 5 * 60, + THIRTY_MINS = 30 * 60, + ONE_HOUR = 60 * 60, + THREE_HOURS = 3 * 60 * 60, + SIX_HOURS = 6 * 60 * 60, + ONE_DAY = 24 * 60 * 60, + FOREVER = Number.MAX_SAFE_INTEGER, +} diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 32da5d6267d..630d9e972ca 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -19,9 +19,16 @@ import maplibregl from 'maplibre-gl'; import SdkConfig from '../../../SdkConfig'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IBodyProps } from "./IBodyProps"; +import { LocationShareType } from "../location/LocationShareType"; + +interface IState { +} @replaceableComponent("views.messages.MLocationBody") export default class MLocationBody extends React.Component { + private map : maplibregl.Map; + private coords : GeolocationCoordinates; + constructor(props: IBodyProps) { super(props); @@ -37,21 +44,24 @@ export default class MLocationBody extends React.Component { this.coords = this.parseGeoUri(uri); } - private parseGeoUri = (uri) => { + private parseGeoUri = (uri: string) : GeolocationCoordinates => { const m = uri.match(/^\s*geo:(.*?)\s*$/); if (!m) return; const parts = m[1].split(';'); const coords = parts[0].split(','); - let uncertainty; + let uncertainty : number; for (const param of parts.slice(1)) { const m = param.match(/u=(.*)/); - if (m) uncertainty = m[1]; + if (m) uncertainty = parseFloat(m[1]); } return { - 'latitude': coords[0], - 'longitude': coords[1], - 'altitude': coords[2], - 'accuracy': uncertainty, + latitude: parseFloat(coords[0]), + longitude: parseFloat(coords[1]), + altitude: parseFloat(coords[2]), + accuracy: uncertainty, + altitudeAccuracy: undefined, + heading: undefined, + speed: undefined, }; }; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 2a457945390..50f2ab40aff 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -61,6 +61,7 @@ import ErrorDialog from "../dialogs/ErrorDialog"; import PollCreateDialog from "../elements/PollCreateDialog"; import { MsgType } from "matrix-js-sdk/src/@types/event"; import { logger } from "matrix-js-sdk/src/logger"; +import { LocationShareType } from "../location/LocationShareType"; let instanceCount = 0; const NARROW_MODE_BREAKPOINT = 500; @@ -131,7 +132,7 @@ const EmojiButton: React.FC = ({ addEmoji, menuPosition, narr interface ILocationButtonProps { room: Room; - shareLocation: (uri: string, ts: int, type: LocationShareType, description: string) => boolean; + shareLocation: (uri: string, ts: number, type: LocationShareType, description: string) => boolean; menuPosition: any; // TODO: Types narrowMode: boolean; } @@ -462,7 +463,7 @@ export default class MessageComposer extends React.Component { return true; }; - private shareLocation = (uri: string, ts: int, type: LocationShareType, description: string): boolean => { + private shareLocation = (uri: string, ts: number, type: LocationShareType, description: string): boolean => { if (!uri) return false; try { const text = `${description ? description : 'Location'} at ${uri} as of ${new Date(ts).toISOString()}`; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4380e4aedf2..531eb2ade1f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2077,6 +2077,7 @@ "Share my current location for six hours": "Share my current location for six hours", "Share my current location for one day": "Share my current location for one day", "Share my current location until I disable it": "Share my current location until I disable it", + "Type of location share": "Type of location share", "Failed to load group members": "Failed to load group members", "Filter community members": "Filter community members", "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Are you sure you want to remove '%(roomName)s' from %(groupId)s?", diff --git a/src/settings/controllers/SettingController.ts b/src/settings/controllers/SettingController.ts index ba78597da7b..292b2d63e59 100644 --- a/src/settings/controllers/SettingController.ts +++ b/src/settings/controllers/SettingController.ts @@ -54,6 +54,8 @@ export default abstract class SettingController { */ public onChange(level: SettingLevel, roomId: string, newValue: any) { // do nothing by default + + // FIXME: force a fresh on the RoomView for the roomId in question } /** diff --git a/yarn.lock b/yarn.lock index a9bd0fab70f..df42eb60c62 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1722,6 +1722,11 @@ "@types/fbemitter" "*" "@types/react" "*" +"@types/geojson@^7946.0.8": + version "7946.0.8" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca" + integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA== + "@types/graceful-fs@^4.1.2": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" From 426f7b31f3d1f7985dfcc8d1403697e5359c6d40 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 21 Nov 2021 20:14:11 +0100 Subject: [PATCH 13/28] only send loc if you have one --- src/components/views/location/LocationPicker.tsx | 7 +++++-- src/i18n/strings/en_EN.json | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 17f5b57167d..6f73c5ca4ce 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -73,6 +73,7 @@ interface IState { description: string; type: LocationShareType; position: GeolocationPosition; + manual: boolean; } @replaceableComponent("views.location.LocationPicker") @@ -84,9 +85,10 @@ class LocationPicker extends React.Component { super(props); this.state = { - description: "", + description: _t("My location"), type: LocationShareType.ONE_OFF, position: undefined, + manual: false, }; } @@ -172,7 +174,8 @@ class LocationPicker extends React.Component { + onCancel={this.props.onFinished} + disabled={!this.state.position} />
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 531eb2ade1f..5c8b43e8d1a 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2077,6 +2077,7 @@ "Share my current location for six hours": "Share my current location for six hours", "Share my current location for one day": "Share my current location for one day", "Share my current location until I disable it": "Share my current location until I disable it", + "My location": "My location", "Type of location share": "Type of location share", "Failed to load group members": "Failed to load group members", "Filter community members": "Filter community members", From 94f1ff9f1ac3d2da7487388ceb8d7f062e36347a Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 21 Nov 2021 20:17:41 +0100 Subject: [PATCH 14/28] disable the streaming options until they're hooked up --- .../views/location/LocationPicker.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 6f73c5ca4ce..9dbff856882 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -40,16 +40,16 @@ const LocationShareTypeDropdown = ({ onChange, }: IDropdownProps) => { const options = [ -
{ _t("Share custom location") }
, + //
{ _t("Share custom location") }
,
{ _t("Share my current location as a one off") }
, -
{ _t("Share my current location for one minute") }
, -
{ _t("Share my current location for five minutes") }
, -
{ _t("Share my current location for thirty minutes") }
, -
{ _t("Share my current location for one hour") }
, -
{ _t("Share my current location for three hours") }
, -
{ _t("Share my current location for six hours") }
, -
{ _t("Share my current location for one day") }
, -
{ _t("Share my current location until I disable it") }
, + //
{ _t("Share my current location for one minute") }
, + //
{ _t("Share my current location for five minutes") }
, + //
{ _t("Share my current location for thirty minutes") }
, + //
{ _t("Share my current location for one hour") }
, + //
{ _t("Share my current location for three hours") }
, + //
{ _t("Share my current location for six hours") }
, + //
{ _t("Share my current location for one day") }
, + //
{ _t("Share my current location until I disable it") }
, ]; return Date: Sun, 21 Nov 2021 20:53:15 +0100 Subject: [PATCH 15/28] lint --- src/components/views/location/LocationPicker.tsx | 6 +++--- src/components/views/messages/MLocationBody.tsx | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 9dbff856882..4a43f3fba11 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -55,7 +55,7 @@ const LocationShareTypeDropdown = ({ return { onChange(LocationShareType[LocationShareType[parseInt(key)]]) }} + onOptionChange={(key: string)=>{ onChange(LocationShareType[LocationShareType[parseInt(key)]]); }} menuWidth={width} label={label} value={value.toString()} @@ -78,8 +78,8 @@ interface IState { @replaceableComponent("views.location.LocationPicker") class LocationPicker extends React.Component { - private map : maplibregl.Map; - private geolocate : maplibregl.GeolocateControl; + private map: maplibregl.Map; + private geolocate: maplibregl.GeolocateControl; constructor(props) { super(props); diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 630d9e972ca..0f21479a8b9 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -19,15 +19,14 @@ import maplibregl from 'maplibre-gl'; import SdkConfig from '../../../SdkConfig'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IBodyProps } from "./IBodyProps"; -import { LocationShareType } from "../location/LocationShareType"; interface IState { } @replaceableComponent("views.messages.MLocationBody") export default class MLocationBody extends React.Component { - private map : maplibregl.Map; - private coords : GeolocationCoordinates; + private map: maplibregl.Map; + private coords: GeolocationCoordinates; constructor(props: IBodyProps) { super(props); @@ -44,12 +43,12 @@ export default class MLocationBody extends React.Component { this.coords = this.parseGeoUri(uri); } - private parseGeoUri = (uri: string) : GeolocationCoordinates => { + private parseGeoUri = (uri: string): GeolocationCoordinates => { const m = uri.match(/^\s*geo:(.*?)\s*$/); if (!m) return; const parts = m[1].split(';'); const coords = parts[0].split(','); - let uncertainty : number; + let uncertainty: number; for (const param of parts.slice(1)) { const m = param.match(/u=(.*)/); if (m) uncertainty = parseFloat(m[1]); From 644fe03375929e8144c323311a70101a18c206e3 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 21 Nov 2021 21:01:16 +0100 Subject: [PATCH 16/28] more lint --- res/css/_common.scss | 1 - res/css/views/location/_LocationPicker.scss | 2 -- 2 files changed, 3 deletions(-) diff --git a/res/css/_common.scss b/res/css/_common.scss index ad0e0d1c2db..7bb3a156830 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -20,7 +20,6 @@ limitations under the License. @import "./_font-sizes.scss"; @import "./_font-weights.scss"; @import "./_animations.scss"; - @import url("maplibre-gl/dist/maplibre-gl.css"); $hover-transition: 0.08s cubic-bezier(.46, .03, .52, .96); // quadratic diff --git a/res/css/views/location/_LocationPicker.scss b/res/css/views/location/_LocationPicker.scss index 406cdafcd78..62d1a0b5f09 100644 --- a/res/css/views/location/_LocationPicker.scss +++ b/res/css/views/location/_LocationPicker.scss @@ -24,7 +24,6 @@ limitations under the License. flex-direction: column; } - #mx_LocationPicker_map { height: 324px; border-radius: 8px 8px 0px 0px; @@ -42,4 +41,3 @@ limitations under the License. max-height: 140px; } } - From f774e71864aa8f92e515e854f80df1fc41b064e8 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 21 Nov 2021 21:03:02 +0100 Subject: [PATCH 17/28] fix i18n --- src/i18n/strings/en_EN.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 5c8b43e8d1a..3ad8ff1b5ef 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2067,16 +2067,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 one off": "Share my current location as a one off", - "Share my current location for one minute": "Share my current location for one minute", - "Share my current location for five minutes": "Share my current location for five minutes", - "Share my current location for thirty minutes": "Share my current location for thirty minutes", - "Share my current location for one hour": "Share my current location for one hour", - "Share my current location for three hours": "Share my current location for three hours", - "Share my current location for six hours": "Share my current location for six hours", - "Share my current location for one day": "Share my current location for one day", - "Share my current location until I disable it": "Share my current location until I disable it", "My location": "My location", "Type of location share": "Type of location share", "Failed to load group members": "Failed to load group members", From 80a15a128fee594442227190a4e3dac821def4db Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 21 Nov 2021 21:14:39 +0100 Subject: [PATCH 18/28] show descriptions --- res/css/views/messages/_MLocationBody.scss | 3 ++- src/components/views/messages/MLocationBody.tsx | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/res/css/views/messages/_MLocationBody.scss b/res/css/views/messages/_MLocationBody.scss index 7777012518a..2144ff151f4 100644 --- a/res/css/views/messages/_MLocationBody.scss +++ b/res/css/views/messages/_MLocationBody.scss @@ -14,9 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_MLocationBody { +.mx_MLocationBody_map { width: 450px; height: 300px; border-radius: $timeline-image-border-radius; } + diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 0f21479a8b9..56a23c98cd1 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -27,6 +27,7 @@ interface IState { export default class MLocationBody extends React.Component { private map: maplibregl.Map; private coords: GeolocationCoordinates; + private description: string; constructor(props: IBodyProps) { super(props); @@ -41,6 +42,12 @@ export default class MLocationBody extends React.Component { content['geo_uri']; this.coords = this.parseGeoUri(uri); + + this.description = + (content['org.matrix.msc3488.location'] && + content['org.matrix.msc3488.location'].description !== undefined) ? + content['org.matrix.msc3488.location'].description : + content['body']; } private parseGeoUri = (uri: string): GeolocationCoordinates => { @@ -83,6 +90,9 @@ export default class MLocationBody extends React.Component { }; render() { - return
; + return
+
+ { this.description } +
; } } From 92ba926b3c9789ad15bc5eaa1d6a21bc9571e807 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 22 Nov 2021 19:09:52 +0100 Subject: [PATCH 19/28] incorporate review --- res/css/views/location/_LocationPicker.scss | 6 +---- res/css/views/messages/_MLocationBody.scss | 1 - .../views/location/LocationPicker.tsx | 24 +++++++++---------- .../views/location/LocationShareType.tsx | 20 ++++++++-------- .../views/messages/MLocationBody.tsx | 5 +--- .../views/rooms/MessageComposer.tsx | 4 ++-- 6 files changed, 26 insertions(+), 34 deletions(-) diff --git a/res/css/views/location/_LocationPicker.scss b/res/css/views/location/_LocationPicker.scss index 62d1a0b5f09..a3c135215b7 100644 --- a/res/css/views/location/_LocationPicker.scss +++ b/res/css/views/location/_LocationPicker.scss @@ -15,6 +15,7 @@ limitations under the License. */ .mx_LocationPicker { + // placeholder sizing to be replaced once there's a proper design width: 450px; height: 500px; @@ -31,11 +32,6 @@ limitations under the License. .mx_LocationPicker_footer { margin: 24px; - // border-top: 1px solid $message-action-bar-border-color; - // min-height: 72px; - - // display: flex; - // align-items: center; .mx_Dropdown_menu { max-height: 140px; diff --git a/res/css/views/messages/_MLocationBody.scss b/res/css/views/messages/_MLocationBody.scss index 2144ff151f4..5bb90fbf7b0 100644 --- a/res/css/views/messages/_MLocationBody.scss +++ b/res/css/views/messages/_MLocationBody.scss @@ -20,4 +20,3 @@ limitations under the License. border-radius: $timeline-image-border-radius; } - diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 4a43f3fba11..e585b2885d7 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -40,16 +40,16 @@ const LocationShareTypeDropdown = ({ onChange, }: IDropdownProps) => { const options = [ - //
{ _t("Share custom location") }
, -
{ _t("Share my current location as a one off") }
, - //
{ _t("Share my current location for one minute") }
, - //
{ _t("Share my current location for five minutes") }
, - //
{ _t("Share my current location for thirty minutes") }
, - //
{ _t("Share my current location for one hour") }
, - //
{ _t("Share my current location for three hours") }
, - //
{ _t("Share my current location for six hours") }
, - //
{ _t("Share my current location for one day") }
, - //
{ _t("Share my current location until I disable it") }
, + //
{ _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") }
, + //
{ _t("Share my current location for thirty minutes") }
, + //
{ _t("Share my current location for one hour") }
, + //
{ _t("Share my current location for three hours") }
, + //
{ _t("Share my current location for six hours") }
, + //
{ _t("Share my current location for one day") }
, + //
{ _t("Share my current location until I disable it") }
, ]; return { this.state = { description: _t("My location"), - type: LocationShareType.ONE_OFF, + type: LocationShareType.OnceOff, position: undefined, manual: false, }; diff --git a/src/components/views/location/LocationShareType.tsx b/src/components/views/location/LocationShareType.tsx index b0e1611fbe6..53508bda86d 100644 --- a/src/components/views/location/LocationShareType.tsx +++ b/src/components/views/location/LocationShareType.tsx @@ -15,14 +15,14 @@ limitations under the License. */ export enum LocationShareType { - CUSTOM = -1, - ONE_OFF = 0, - ONE_MIN = 60, - FIVE_MINS = 5 * 60, - THIRTY_MINS = 30 * 60, - ONE_HOUR = 60 * 60, - THREE_HOURS = 3 * 60 * 60, - SIX_HOURS = 6 * 60 * 60, - ONE_DAY = 24 * 60 * 60, - FOREVER = Number.MAX_SAFE_INTEGER, + Custom = -1, + OnceOff = 0, + OneMine = 60, + FiveMins = 5 * 60, + ThirtyMins = 30 * 60, + OneHour = 60 * 60, + ThreeHours = 3 * 60 * 60, + SixHours = 6 * 60 * 60, + OneDay = 24 * 60 * 60, + Forever = Number.MAX_SAFE_INTEGER, } diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 56a23c98cd1..ac6d873d037 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -20,11 +20,8 @@ import SdkConfig from '../../../SdkConfig'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IBodyProps } from "./IBodyProps"; -interface IState { -} - @replaceableComponent("views.messages.MLocationBody") -export default class MLocationBody extends React.Component { +export default class MLocationBody extends React.Component { private map: maplibregl.Map; private coords: GeolocationCoordinates; private description: string; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 50f2ab40aff..a2a927c2a2c 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -93,7 +93,7 @@ function SendButton(props: ISendButtonProps) { interface IEmojiButtonProps { addEmoji: (unicode: string) => boolean; - menuPosition: any; // TODO: Types + menuPosition: AboveLeftOf; narrowMode: boolean; } @@ -133,7 +133,7 @@ const EmojiButton: React.FC = ({ addEmoji, menuPosition, narr interface ILocationButtonProps { room: Room; shareLocation: (uri: string, ts: number, type: LocationShareType, description: string) => boolean; - menuPosition: any; // TODO: Types + menuPosition: AboveLeftOf; narrowMode: boolean; } From 5531d091041ffaa46addc2639334637f0ca8d72d Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 22 Nov 2021 19:17:04 +0100 Subject: [PATCH 20/28] use fancy optional chaining Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/messages/MLocationBody.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index ac6d873d037..38972e00080 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -41,10 +41,7 @@ export default class MLocationBody extends React.Component { this.coords = this.parseGeoUri(uri); this.description = - (content['org.matrix.msc3488.location'] && - content['org.matrix.msc3488.location'].description !== undefined) ? - content['org.matrix.msc3488.location'].description : - content['body']; + content['org.matrix.msc3488.location']?.description ?? content['body']; } private parseGeoUri = (uri: string): GeolocationCoordinates => { From 8fd4310f39fa3ca16cab5d288ce7813a133fccd6 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 22 Nov 2021 20:54:03 +0100 Subject: [PATCH 21/28] add createObjectURL mock --- test/setupTests.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/setupTests.js b/test/setupTests.js index e719f715c9e..0b92c0c8546 100644 --- a/test/setupTests.js +++ b/test/setupTests.js @@ -15,3 +15,5 @@ global.TextDecoder = TextDecoder; configure({ adapter: new Adapter() }); +// maplibre requires a createObjectURL mock +global.URL.createObjectURL = jest.fn(); From 097c8f7b9a76e10d2b50222def7c4400491eb49a Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 22 Nov 2021 20:16:47 +0000 Subject: [PATCH 22/28] fix i18n --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3ad8ff1b5ef..eb014542479 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2067,7 +2067,7 @@ "edited": "edited", "Submit logs": "Submit logs", "Can't load this message": "Can't load this message", - "Share my current location as a one off": "Share my current location as a one off", + "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", "Failed to load group members": "Failed to load group members", From 982d5b7bbf04e200738b2923f9a16b04f3dfaf31 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 28 Nov 2021 23:36:14 +0000 Subject: [PATCH 23/28] warn if API key not set when showing maps --- .../views/messages/MLocationBody.tsx | 21 ++++++++++++++++++- src/settings/Settings.tsx | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 38972e00080..94da8880aa3 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -20,8 +20,12 @@ import SdkConfig from '../../../SdkConfig'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IBodyProps } from "./IBodyProps"; +interface IState { + fail: boolean; +} + @replaceableComponent("views.messages.MLocationBody") -export default class MLocationBody extends React.Component { +export default class MLocationBody extends React.Component { private map: maplibregl.Map; private coords: GeolocationCoordinates; private description: string; @@ -39,6 +43,9 @@ export default class MLocationBody extends React.Component { content['geo_uri']; this.coords = this.parseGeoUri(uri); + this.state = { + fail: false, + }; this.description = content['org.matrix.msc3488.location']?.description ?? content['body']; @@ -74,6 +81,12 @@ export default class MLocationBody extends React.Component { zoom: 13, }); + try { + this.map.getStyle(); + } catch (e) { + this.setState({ fail: true }); + } + new maplibregl.Marker() .setLngLat([this.coords.longitude, this.coords.latitude]) .addTo(this.map); @@ -84,8 +97,14 @@ export default class MLocationBody extends React.Component { }; render() { + const error = this.state.fail ? +
+ Failed to load map - check config.json has a valid API key +
: null; + return
+ { error } { this.description }
; } diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 05c343c8ac2..4d371bdeb49 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -318,6 +318,7 @@ export const SETTINGS: {[setting: string]: ISetting} = { }, "feature_location_share": { isFeature: true, + labsGroup: LabGroup.Messaging, supportedLevels: LEVELS_FEATURE, displayName: _td("Location sharing (under active development)"), default: false, From 49c590c4e06733167a9e013b69548aa3d1e171c8 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 5 Dec 2021 12:23:37 +0000 Subject: [PATCH 24/28] export LocationShareType enum correctly --- src/components/views/location/LocationShareType.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/location/LocationShareType.tsx b/src/components/views/location/LocationShareType.tsx index 53508bda86d..200b9ca1825 100644 --- a/src/components/views/location/LocationShareType.tsx +++ b/src/components/views/location/LocationShareType.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -export enum LocationShareType { +enum LocationShareType { Custom = -1, OnceOff = 0, OneMine = 60, @@ -26,3 +26,5 @@ export enum LocationShareType { OneDay = 24 * 60 * 60, Forever = Number.MAX_SAFE_INTEGER, } + +export default LocationShareType; \ No newline at end of file From f088094e7edb71b807a07b4210ba1970dea6e86c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 5 Dec 2021 12:23:56 +0000 Subject: [PATCH 25/28] hook up map failure error correctly --- res/css/views/location/_LocationPicker.scss | 5 +++++ .../views/location/LocationPicker.tsx | 16 +++++++++++++++- src/components/views/messages/MLocationBody.tsx | 17 +++++++++-------- src/i18n/strings/en_EN.json | 1 + 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/res/css/views/location/_LocationPicker.scss b/res/css/views/location/_LocationPicker.scss index a3c135215b7..b386268cec2 100644 --- a/res/css/views/location/_LocationPicker.scss +++ b/res/css/views/location/_LocationPicker.scss @@ -37,3 +37,8 @@ limitations under the License. max-height: 140px; } } + +.mx_LocationPicker_error { + color: red; + margin: auto; +} diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index e585b2885d7..dbe0e7a69b6 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -21,10 +21,11 @@ import SdkConfig from '../../../SdkConfig'; import Field from "../elements/Field"; import DialogButtons from "../elements/DialogButtons"; import Dropdown from "../elements/Dropdown"; -import { LocationShareType } from "./LocationShareType"; +import LocationShareType from "./LocationShareType"; import { _t } from '../../../languageHandler'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { logger } from "matrix-js-sdk/src/logger"; interface IDropdownProps { value: LocationShareType; @@ -74,6 +75,7 @@ interface IState { type: LocationShareType; position?: GeolocationPosition; manual: boolean; + error: Error; } @replaceableComponent("views.location.LocationPicker") @@ -89,6 +91,7 @@ class LocationPicker extends React.Component { type: LocationShareType.OnceOff, position: undefined, manual: false, + error: undefined, }; } @@ -110,6 +113,11 @@ class LocationPicker extends React.Component { }); this.map.addControl(this.geolocate); + 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 }); + }); + this.map.on('load', ()=>{ this.geolocate.trigger(); }); @@ -152,9 +160,15 @@ class LocationPicker extends React.Component { }; render() { + const error = this.state.error ? +
+ { _t("Failed to load map") } +
: null; + return (
+ { error }
{ zoom: 13, }); - try { - this.map.getStyle(); - } catch (e) { - this.setState({ fail: true }); - } - new maplibregl.Marker() .setLngLat([this.coords.longitude, this.coords.latitude]) .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 }); + }); } private getBodyId = () => { @@ -97,9 +98,9 @@ export default class MLocationBody extends React.Component { }; render() { - const error = this.state.fail ? + const error = this.state.error ?
- Failed to load map - check config.json has a valid API key + { _t("Failed to load map") }
: null; return
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index cc58cbf113d..cc24b68419c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2065,6 +2065,7 @@ "Declining …": "Declining …", "%(name)s wants to verify": "%(name)s wants to verify", "You sent a verification request": "You sent a verification request", + "Failed to load map": "Failed to load map", "Vote not registered": "Vote not registered", "Sorry, your vote was not registered. Please try again.": "Sorry, your vote was not registered. Please try again.", "No votes cast": "No votes cast", From 58ebf2aea21f39b1f07417e0ac4f94010a7f6464 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 5 Dec 2021 12:25:21 +0000 Subject: [PATCH 26/28] fix lint --- src/components/views/location/LocationShareType.tsx | 2 +- src/components/views/rooms/MessageComposer.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/views/location/LocationShareType.tsx b/src/components/views/location/LocationShareType.tsx index 200b9ca1825..957860514ef 100644 --- a/src/components/views/location/LocationShareType.tsx +++ b/src/components/views/location/LocationShareType.tsx @@ -27,4 +27,4 @@ enum LocationShareType { Forever = Number.MAX_SAFE_INTEGER, } -export default LocationShareType; \ No newline at end of file +export default LocationShareType; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 37c4d2da1ba..b6cf4e9f6dc 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -49,7 +49,6 @@ import { Action } from "../../../dispatcher/actions"; import EditorModel from "../../../editor/model"; import EmojiPicker from '../emojipicker/EmojiPicker'; import LocationPicker from '../location/LocationPicker'; -import MemberStatusMessageAvatar from "../avatars/MemberStatusMessageAvatar"; import UIStore, { UI_EVENTS } from '../../../stores/UIStore'; import Modal from "../../../Modal"; import { RelationType } from 'matrix-js-sdk/src/@types/event'; From e6842ba3e73a8343158fc3eda9fb709307a03222 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 5 Dec 2021 12:28:19 +0000 Subject: [PATCH 27/28] fix type --- src/components/views/rooms/MessageComposer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index b6cf4e9f6dc..d64bef9d2d8 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -58,7 +58,7 @@ import ErrorDialog from "../dialogs/ErrorDialog"; import PollCreateDialog from "../elements/PollCreateDialog"; import { MsgType } from "matrix-js-sdk/src/@types/event"; import { logger } from "matrix-js-sdk/src/logger"; -import { LocationShareType } from "../location/LocationShareType"; +import LocationShareType from "../location/LocationShareType"; import { SettingUpdatedPayload } from "../../../dispatcher/payloads/SettingUpdatedPayload"; let instanceCount = 0; From d6b805afbde0ce182edb48086500c9ca3e63ac5e Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 5 Dec 2021 12:30:21 +0000 Subject: [PATCH 28/28] fix types --- src/components/views/location/LocationPicker.tsx | 2 +- src/components/views/messages/MLocationBody.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index dbe0e7a69b6..8d4efdfa709 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -115,7 +115,7 @@ class LocationPicker extends React.Component { 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 }); + this.setState({ error: e.error }); }); this.map.on('load', ()=>{ diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 6009b78a42e..8e096fa3820 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -23,7 +23,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from '../../../languageHandler'; interface IState { - fail: boolean; + error: Error; } @replaceableComponent("views.messages.MLocationBody") @@ -46,7 +46,7 @@ export default class MLocationBody extends React.Component { this.coords = this.parseGeoUri(uri); this.state = { - fail: false, + error: undefined, }; this.description = @@ -89,7 +89,7 @@ export default class MLocationBody extends React.Component { 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 }); + this.setState({ error: e.error }); }); }