From fb24ffd20da2de27d9e5e2e894760c15f2ad8b7f Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Fri, 24 Mar 2023 13:52:17 +0000 Subject: [PATCH] Show a map for location events --- .gitignore | 1 + src/models/messageeventmodel.cpp | 25 +++++++ src/models/messageeventmodel.h | 3 + src/qml/Component/Timeline/EventDelegate.qml | 5 ++ .../Component/Timeline/LocationDelegate.qml | 67 +++++++++++++++++++ src/res.qrc | 1 + 6 files changed, 102 insertions(+) create mode 100644 src/qml/Component/Timeline/LocationDelegate.qml diff --git a/.gitignore b/.gitignore index 4ace39cb8..31f488477 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ kate.project.ctags.* *.user .flatpak-builder/ .idea/ +cmake-build-debug diff --git a/src/models/messageeventmodel.cpp b/src/models/messageeventmodel.cpp index c3c2041c5..82d7838f2 100644 --- a/src/models/messageeventmodel.cpp +++ b/src/models/messageeventmodel.cpp @@ -69,6 +69,8 @@ QHash MessageEventModel::roleNames() const roles[IsRedactedRole] = "isRedacted"; roles[GenericDisplayRole] = "genericDisplay"; roles[IsPendingRole] = "isPending"; + roles[LatitudeRole] = "latitude"; + roles[LongitudeRole] = "longitude"; return roles; } @@ -510,6 +512,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const return DelegateType::Audio; case MessageEventType::Video: return DelegateType::Video; + case MessageEventType::Location: + return DelegateType::Location; default: break; } @@ -564,6 +568,9 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const } if (auto e = eventCast(&evt)) { + if(e->msgtype() == Quotient::MessageEventType::Location) { + return e->contentJson(); + } // Cannot use e.contentJson() here because some // EventContent classes inject values into the copy of the // content JSON stored in EventContent::Base @@ -810,6 +817,24 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const return false; } + if (role == LatitudeRole) { + const auto geoUri = evt.contentJson()["geo_uri"_ls].toString(); + if (geoUri.isEmpty()) { + return {}; + } + const auto latitude = geoUri.split(u':')[1].split(u',')[0]; + return latitude.toFloat(); + } + + if (role == LongitudeRole) { + const auto geoUri = evt.contentJson()["geo_uri"_ls].toString(); + if (geoUri.isEmpty()) { + return {}; + } + const auto latitude = geoUri.split(u':')[1].split(u',')[1]; + return latitude.toFloat(); + } + if (role == ReadMarkersRole) { #ifdef QUOTIENT_07 auto userIds = room()->userIdsAtEvent(evt.id()); diff --git a/src/models/messageeventmodel.h b/src/models/messageeventmodel.h index 4add993a5..a9ffc7d4f 100644 --- a/src/models/messageeventmodel.h +++ b/src/models/messageeventmodel.h @@ -26,6 +26,7 @@ public: Encrypted, ReadMarker, Poll, + Location, Other, }; Q_ENUM(DelegateType); @@ -75,6 +76,8 @@ public: AuthorDisplayNameRole, IsRedactedRole, IsPendingRole, + LatitudeRole, + LongitudeRole, LastRole, // Keep this last }; Q_ENUM(EventRoles) diff --git a/src/qml/Component/Timeline/EventDelegate.qml b/src/qml/Component/Timeline/EventDelegate.qml index 564c035de..e2f1605da 100644 --- a/src/qml/Component/Timeline/EventDelegate.qml +++ b/src/qml/Component/Timeline/EventDelegate.qml @@ -75,6 +75,11 @@ DelegateChooser { delegate: PollDelegate {} } + DelegateChoice { + roleValue: MessageEventModel.Location + delegate: LocationDelegate {} + } + DelegateChoice { roleValue: MessageEventModel.Other delegate: Item {} diff --git a/src/qml/Component/Timeline/LocationDelegate.qml b/src/qml/Component/Timeline/LocationDelegate.qml new file mode 100644 index 000000000..192be8254 --- /dev/null +++ b/src/qml/Component/Timeline/LocationDelegate.qml @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2021 Tobias Fella +// SPDX-License-Identifier: GPL-2.0-or-later + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import QtLocation 5.15 +import QtPositioning 5.15 + +import org.kde.kirigami 2.15 as Kirigami + +import org.kde.neochat 1.0 + +TimelineContainer { + id: locationDelegate + + ColumnLayout { + Layout.maximumWidth: locationDelegate.contentMaxWidth + Layout.preferredWidth: locationDelegate.contentMaxWidth + Map { + id: map + Layout.fillWidth: true + Layout.preferredHeight: locationDelegate.contentMaxWidth / 16 * 9 + + center: QtPositioning.coordinate(model.latitude, model.longitude) + zoomLevel: 15 + plugin: Plugin { + name: "osm" + PluginParameter { + name: "osm.useragent" + value: Application.name + "/" + Application.version + " (kde-devel@kde.org)" + } + PluginParameter { + name: "osm.mapping.providersrepository.address" + value: "https://autoconfig.kde.org/qtlocation/" + } + } + + onCopyrightLinkActivated: Qt.openUrlExternally(link) + + + MapQuickItem { + id: point + + anchorPoint.x: sourceItem.width / 2 + anchorPoint.y: sourceItem.height / 2 + coordinate: QtPositioning.coordinate(model.latitude, model.longitude) + autoFadeIn: false + + sourceItem: Kirigami.Icon { + width: height + height: Kirigami.Units.iconSizes.medium + source: "flag-blue" + } + } + + TapHandler { + acceptedButtons: Qt.LeftButton + onLongPressed: openMessageContext(model, "", model.message) + } + TapHandler { + acceptedButtons: Qt.RightButton + onTapped: openMessageContext(model, "", model.message) + } + } + } +} diff --git a/src/res.qrc b/src/res.qrc index 622257589..4cc2b8f78 100644 --- a/src/res.qrc +++ b/src/res.qrc @@ -107,5 +107,6 @@ qml/Component/Emoji/EmojiDelegate.qml qml/Component/Emoji/EmojiGrid.qml qml/Page/SearchPage.qml + qml/Component/Timeline/LocationDelegate.qml