mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-07-23 08:55:26 +02:00
feature: improve location sharing
- share position to different conversations at the same time - Be able to stop sharing positions with the current conversation only - UI improvements to know who is sharing and who you are sharing to - Watchdog Change-Id: I1402f0d1b1fc117087988b1cc45f1fd05d2a83ac GitLab: #888
This commit is contained in:
parent
e5b54ad787
commit
933cce8cef
14 changed files with 575 additions and 103 deletions
|
@ -178,6 +178,7 @@ set(COMMON_SOURCES
|
|||
${APP_SRC_DIR}/utils.cpp
|
||||
${APP_SRC_DIR}/mainapplication.cpp
|
||||
${APP_SRC_DIR}/messagesadapter.cpp
|
||||
${APP_SRC_DIR}/positionobject.cpp
|
||||
${APP_SRC_DIR}/positionmanager.cpp
|
||||
${APP_SRC_DIR}/accountadapter.cpp
|
||||
${APP_SRC_DIR}/calladapter.cpp
|
||||
|
@ -233,6 +234,7 @@ set(COMMON_HEADERS
|
|||
${APP_SRC_DIR}/mainapplication.h
|
||||
${APP_SRC_DIR}/qrimageprovider.h
|
||||
${APP_SRC_DIR}/messagesadapter.h
|
||||
${APP_SRC_DIR}/positionobject.h
|
||||
${APP_SRC_DIR}/positionmanager.h
|
||||
${APP_SRC_DIR}/accountadapter.h
|
||||
${APP_SRC_DIR}/calladapter.h
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
@ -45,6 +47,8 @@ Item {
|
|||
|
||||
property alias presenceStatus: presenceIndicator.status
|
||||
property bool showPresenceIndicator: true
|
||||
property bool showSharePositionIndicator: false
|
||||
property bool showSharedPositionIndicator: false
|
||||
property alias fillMode: image.fillMode
|
||||
|
||||
onImageIdChanged: image.updateSource()
|
||||
|
@ -116,4 +120,48 @@ Item {
|
|||
|
||||
visible: showPresenceIndicator
|
||||
}
|
||||
RowLayout {
|
||||
id: positionIndicatorLayout
|
||||
anchors.left: root.left
|
||||
anchors.leftMargin: -1
|
||||
anchors.bottom: root.bottom
|
||||
anchors.bottomMargin: -1
|
||||
spacing: 0
|
||||
property real sizeI: root.width * JamiTheme.avatarPresenceRatio
|
||||
Rectangle {
|
||||
id: sharePositionIndicator
|
||||
visible: showSharePositionIndicator
|
||||
Layout.preferredWidth: parent.sizeI
|
||||
Layout.preferredHeight: parent.sizeI
|
||||
color: JamiTheme.backgroundColor
|
||||
radius: parent.sizeI * 0.5
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
ColorOverlay {
|
||||
anchors.fill: parent
|
||||
source: parent
|
||||
color: JamiTheme.sharePositionIndicatorColor
|
||||
}
|
||||
source: JamiResources.my_location_svg
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: sharedPositionIndicator
|
||||
visible: showSharedPositionIndicator
|
||||
Layout.preferredWidth: parent.sizeI
|
||||
Layout.preferredHeight: parent.sizeI
|
||||
color: JamiTheme.backgroundColor
|
||||
radius: parent.sizeI * 0.5
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
ColorOverlay {
|
||||
anchors.fill: parent
|
||||
source: parent
|
||||
color: JamiTheme.sharedPositionIndicatorColor
|
||||
}
|
||||
source: JamiResources.my_location_svg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -299,15 +299,25 @@ Item {
|
|||
property string raiseHand: qsTr("Raise hand")
|
||||
property string layoutSettings: qsTr("Layout settings")
|
||||
|
||||
// Share location
|
||||
// Share location/position
|
||||
property string shareLocation: qsTr("Share location")
|
||||
property string stopSharingLocation: qsTr("Stop sharing location")
|
||||
property string stopSharingLocation: qsTr("Stop sharing")
|
||||
property string shortSharing: qsTr("10 minutes")
|
||||
property string longSharing: qsTr("One hour")
|
||||
property string minutesLeft: qsTr("%1 minutes left")
|
||||
property string minuteLeft: qsTr("%1 minute left")
|
||||
property string locationServicesError: qsTr("Jami needs to access to your location.\nIn Device Settings, please turn on Location Services.\nOther participants' location can still be received.")
|
||||
property string locationServicesClosedError: qsTr("Please check your Internet connection.")
|
||||
property string locationServicesError: qsTr("Your precise location could not be determined.\nIn Device Settings, please turn on \"Location Services\".\nOther participants' location can still be received.")
|
||||
property string locationServicesClosedError: qsTr("Your precise location could not be determined. Please check your Internet connection.")
|
||||
property string stopAllSharings: qsTr("Turn off location sharing");
|
||||
property string stopConvSharing: qsTr("Stop location sharing in this conversation");
|
||||
property string stopSharingPopupBody: qsTr("Location is shared in several conversations");
|
||||
property string minimizeMapTooltip: qsTr("Minimize");
|
||||
property string maximizeMapTooltip: qsTr("Maximize");
|
||||
property string reduceMapTooltip: qsTr("Reduce");
|
||||
property string extendMapTooltip: qsTr("Extend");
|
||||
property string dragMapTooltip: qsTr("Drag");
|
||||
property string centerMapTooltip: qsTr("Center");
|
||||
property string closeMapTooltip: qsTr("Close");
|
||||
|
||||
// Chatview header
|
||||
property string hideChat: qsTr("Hide chat")
|
||||
|
|
|
@ -213,6 +213,8 @@ Item {
|
|||
//mapPosition
|
||||
property color mapButtonsOverlayColor: darkTheme ? "#000000" : "#f0f0f0"
|
||||
property color mapButtonColor: darkTheme ? "#f0f0f0" : "#000000"
|
||||
property color sharePositionIndicatorColor: red_
|
||||
property color sharedPositionIndicatorColor: urgentOrange_
|
||||
|
||||
// Files To Send Container
|
||||
property color removeFileButtonColor: Qt.rgba(96, 95, 97, 0.5)
|
||||
|
@ -318,7 +320,7 @@ Item {
|
|||
property real preferredDialogWidth: 400
|
||||
property real preferredDialogHeight: 300
|
||||
property real minimumPreviewWidth: 120
|
||||
property real minimumMapWidth: 230
|
||||
property real minimumMapWidth: 250
|
||||
property real pluginHandlersPopupViewHeight: 200
|
||||
property real pluginHandlersPopupViewDelegateHeight: 50
|
||||
property real secondaryDialogDimension: 500
|
||||
|
|
|
@ -28,6 +28,8 @@ Item {
|
|||
|
||||
property alias imageId: avatar.imageId
|
||||
property alias showPresenceIndicator: avatar.showPresenceIndicator
|
||||
property alias showSharePositionIndicator: avatar.showSharePositionIndicator
|
||||
property alias showSharedPositionIndicator: avatar.showSharedPositionIndicator
|
||||
property alias animationMode: animation.mode
|
||||
|
||||
SpinningAnimation {
|
||||
|
|
|
@ -68,10 +68,22 @@ ItemDelegate {
|
|||
|
||||
imageId: UID
|
||||
showPresenceIndicator: Presence !== undefined ? Presence : false
|
||||
showSharePositionIndicator: PositionManager.isPositionSharedToConv(UID)
|
||||
showSharedPositionIndicator: PositionManager.isConvSharingPosition(UID)
|
||||
|
||||
Layout.preferredWidth: JamiTheme.smartListAvatarSize
|
||||
Layout.preferredHeight: JamiTheme.smartListAvatarSize
|
||||
|
||||
Connections {
|
||||
target: PositionManager
|
||||
function onPositionShareConvIdsChanged () {
|
||||
avatar.showSharePositionIndicator = PositionManager.isPositionSharedToConv(UID)
|
||||
}
|
||||
function onSharingUrisChanged () {
|
||||
avatar.showSharedPositionIndicator = PositionManager.isConvSharingPosition(UID)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: overlayHighlighted
|
||||
visible: highlighted && !interactive
|
||||
|
|
|
@ -28,7 +28,7 @@ Positioning::Positioning(QString uri, QObject* parent)
|
|||
source_ = QGeoPositionInfoSource::createDefaultSource(this);
|
||||
QTimer* timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, &Positioning::requestPosition);
|
||||
timer->start(2000);
|
||||
timer->start(5000);
|
||||
connect(source_, &QGeoPositionInfoSource::errorOccurred, this, &Positioning::slotError);
|
||||
connect(source_, &QGeoPositionInfoSource::positionUpdated, this, &Positioning::positionUpdated);
|
||||
// if location services are activated, positioning will be activated automatically
|
||||
|
@ -38,11 +38,6 @@ Positioning::Positioning(QString uri, QObject* parent)
|
|||
&Positioning::locationServicesActivated);
|
||||
}
|
||||
|
||||
Positioning::~Positioning()
|
||||
{
|
||||
sendStopSharingMsg();
|
||||
}
|
||||
|
||||
void
|
||||
Positioning::start()
|
||||
{
|
||||
|
@ -60,16 +55,6 @@ Positioning::stop()
|
|||
isPositioning = false;
|
||||
}
|
||||
|
||||
void
|
||||
Positioning::sendStopSharingMsg()
|
||||
{
|
||||
QJsonObject jsonObj;
|
||||
jsonObj.insert("type", QJsonValue("Stop"));
|
||||
QJsonDocument doc(jsonObj);
|
||||
QString strJson(doc.toJson(QJsonDocument::Compact));
|
||||
Q_EMIT newPosition(uri_, strJson, -1, "");
|
||||
}
|
||||
|
||||
QString
|
||||
Positioning::convertToJson(const QGeoPositionInfo& info)
|
||||
{
|
||||
|
|
|
@ -28,8 +28,6 @@ class Positioning : public QObject
|
|||
|
||||
public:
|
||||
Positioning(QString uri, QObject* parent = 0);
|
||||
~Positioning();
|
||||
|
||||
/**
|
||||
* start to retreive the current position
|
||||
*/
|
||||
|
@ -42,7 +40,6 @@ public:
|
|||
* send a stop signal to other peers to tell them
|
||||
* you stoped sharing yout position
|
||||
*/
|
||||
void sendStopSharingMsg();
|
||||
QString convertToJson(const QGeoPositionInfo& info);
|
||||
|
||||
void setUri(QString uri);
|
||||
|
|
|
@ -19,8 +19,10 @@ PositionManager::PositionManager(LRCInstance* instance, QObject* parent)
|
|||
});
|
||||
connect(timerStopSharing_, &QTimer::timeout, [=] { stopSharingPosition(); });
|
||||
connect(lrcInstance_, &LRCInstance::selectedConvUidChanged, [this]() {
|
||||
Q_EMIT positionShareConvIdsChanged();
|
||||
set_mapAutoOpening(true);
|
||||
});
|
||||
set_isMapActive(false);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -28,8 +30,14 @@ PositionManager::safeInit()
|
|||
{
|
||||
connect(lrcInstance_, &LRCInstance::currentAccountIdChanged, [this]() {
|
||||
connectConversationModel();
|
||||
set_sharingUris({});
|
||||
objectListSharingUris_.clear();
|
||||
set_positionShareConvIds({});
|
||||
localPositioning_->setUri(lrcInstance_->getCurrentAccountInfo().profileInfo.uri);
|
||||
});
|
||||
set_sharingUris({});
|
||||
objectListSharingUris_.clear();
|
||||
set_positionShareConvIds({});
|
||||
localPositioning_.reset(new Positioning(lrcInstance_->getCurrentAccountInfo().profileInfo.uri));
|
||||
connectConversationModel();
|
||||
}
|
||||
|
@ -49,8 +57,7 @@ PositionManager::connectConversationModel()
|
|||
void
|
||||
PositionManager::startPositioning()
|
||||
{
|
||||
sharingUris_.clear();
|
||||
|
||||
currentConvSharingUris_.clear();
|
||||
localPositioning_->start();
|
||||
connect(localPositioning_.get(),
|
||||
&Positioning::newPosition,
|
||||
|
@ -70,8 +77,54 @@ PositionManager::stopPositioning()
|
|||
localPositioning_->stop();
|
||||
}
|
||||
|
||||
QString
|
||||
PositionManager::getSelectedConvId()
|
||||
{
|
||||
return lrcInstance_->get_selectedConvUid();
|
||||
}
|
||||
|
||||
bool
|
||||
PositionManager::isConvSharingPosition(const QString& convUri)
|
||||
{
|
||||
const auto& convParticipants = lrcInstance_->getConversationFromConvUid(convUri)
|
||||
.participantsUris();
|
||||
Q_FOREACH (const auto& id, convParticipants) {
|
||||
if (id != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
|
||||
if (sharingUris_.contains(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
PositionManager::onOwnPositionReceived(const QString& peerId, const QString& body)
|
||||
PositionManager::loadPreviousLocations()
|
||||
{
|
||||
QVariantMap shareInfo;
|
||||
for (auto it = objectListSharingUris_.begin(); it != objectListSharingUris_.end(); it++) {
|
||||
QJsonObject jsonObj;
|
||||
jsonObj.insert("type", QJsonValue("Position"));
|
||||
jsonObj.insert("lat", it.value()->getLatitude().toString());
|
||||
jsonObj.insert("long", it.value()->getLongitude().toString());
|
||||
QJsonDocument doc(jsonObj);
|
||||
QString strJson(doc.toJson(QJsonDocument::Compact));
|
||||
onPositionReceived(it.key(), strJson, -1, "");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PositionManager::isPositionSharedToConv(const QString& convUri)
|
||||
{
|
||||
if (positionShareConvIds_.length()) {
|
||||
auto iter = std::find(positionShareConvIds_.begin(), positionShareConvIds_.end(), convUri);
|
||||
return (iter != positionShareConvIds_.end());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
PositionManager::sendPosition(const QString& peerId, const QString& body)
|
||||
{
|
||||
try {
|
||||
Q_FOREACH (const auto& id, positionShareConvIds_) {
|
||||
|
@ -89,13 +142,26 @@ PositionManager::onOwnPositionReceived(const QString& peerId, const QString& bod
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
PositionManager::onWatchdogTimeout()
|
||||
{
|
||||
QObject* obj = sender();
|
||||
auto it = std::find_if(objectListSharingUris_.cbegin(),
|
||||
objectListSharingUris_.cend(),
|
||||
[obj](const auto& it) { return it == obj; });
|
||||
if (it != objectListSharingUris_.cend()) {
|
||||
QString stopMsg("{\"type\":\"Stop\"}");
|
||||
onPositionReceived(it.key(), stopMsg, -1, "");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PositionManager::sharePosition(int maximumTime)
|
||||
{
|
||||
connect(localPositioning_.get(),
|
||||
&Positioning::newPosition,
|
||||
this,
|
||||
&PositionManager::onOwnPositionReceived,
|
||||
&PositionManager::sendPosition,
|
||||
Qt::UniqueConnection);
|
||||
|
||||
try {
|
||||
|
@ -109,11 +175,29 @@ PositionManager::sharePosition(int maximumTime)
|
|||
}
|
||||
|
||||
void
|
||||
PositionManager::stopSharingPosition()
|
||||
PositionManager::stopSharingPosition(const QString convId)
|
||||
{
|
||||
localPositioning_->sendStopSharingMsg();
|
||||
stopPositionTimers();
|
||||
set_positionShareConvIds({});
|
||||
QString stopMsg;
|
||||
stopMsg = "{\"type\":\"Stop\"}";
|
||||
if (convId == "") {
|
||||
sendPosition(lrcInstance_->getCurrentAccountInfo().profileInfo.uri, stopMsg);
|
||||
stopPositionTimers();
|
||||
set_positionShareConvIds({});
|
||||
} else {
|
||||
const auto& convInfo = lrcInstance_->getConversationFromConvUid(convId);
|
||||
Q_FOREACH (const QString& uri, convInfo.participantsUris()) {
|
||||
if (lrcInstance_->getCurrentAccountInfo().profileInfo.uri != uri) {
|
||||
lrcInstance_->getCurrentAccountInfo().contactModel->sendDhtMessage(uri,
|
||||
stopMsg,
|
||||
APPLICATION_GEO);
|
||||
}
|
||||
}
|
||||
auto iter = std::find(positionShareConvIds_.begin(), positionShareConvIds_.end(), convId);
|
||||
if (iter != positionShareConvIds_.end()) {
|
||||
positionShareConvIds_.remove(std::distance(positionShareConvIds_.begin(), iter));
|
||||
}
|
||||
Q_EMIT positionShareConvIdsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -197,10 +281,9 @@ PositionManager::onPositionReceived(const QString& peerId,
|
|||
->getConversationFromConvUid(
|
||||
lrcInstance_->get_selectedConvUid())
|
||||
.participantsUris();
|
||||
// to know if the position received is from someone in the current conversation
|
||||
bool isPeerIdInConv = (std::find(convParticipants.begin(), convParticipants.end(), peerId)
|
||||
!= convParticipants.end());
|
||||
if (!isPeerIdInConv)
|
||||
return;
|
||||
|
||||
QVariantMap newPosition = parseJsonPosition(body, peerId);
|
||||
auto getShareInfo = [&](bool update) -> QVariantMap {
|
||||
|
@ -217,36 +300,79 @@ PositionManager::onPositionReceived(const QString& peerId,
|
|||
|
||||
if (!endSharing) {
|
||||
// open map on position reception
|
||||
if (!isMapActive_ && mapAutoOpening_
|
||||
if (!isMapActive_ && mapAutoOpening_ && isPeerIdInConv
|
||||
&& peerId != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
|
||||
set_isMapActive(true);
|
||||
}
|
||||
}
|
||||
auto iter = std::find(sharingUris_.begin(), sharingUris_.end(), peerId);
|
||||
if (iter == sharingUris_.end()) {
|
||||
auto iter = std::find(currentConvSharingUris_.begin(), currentConvSharingUris_.end(), peerId);
|
||||
if (iter == currentConvSharingUris_.end()) {
|
||||
// New share
|
||||
if (!endSharing) {
|
||||
sharingUris_.insert(peerId);
|
||||
Q_EMIT positionShareAdded(getShareInfo(false));
|
||||
}
|
||||
Q_EMIT sharingUrisChanged();
|
||||
|
||||
// list to save more information on position + watchdog
|
||||
auto it = objectListSharingUris_.find(peerId);
|
||||
if (it == objectListSharingUris_.end()) {
|
||||
auto obj = new PositionObject(newPosition["lat"], newPosition["long"], this);
|
||||
|
||||
objectListSharingUris_.insert(peerId, obj);
|
||||
connect(obj,
|
||||
&PositionObject::timeout,
|
||||
this,
|
||||
&PositionManager::onWatchdogTimeout,
|
||||
Qt::DirectConnection);
|
||||
}
|
||||
|
||||
if (isPeerIdInConv) {
|
||||
currentConvSharingUris_.insert(peerId);
|
||||
Q_EMIT positionShareAdded(getShareInfo(false));
|
||||
}
|
||||
// stop sharing position
|
||||
} else {
|
||||
sharingUris_.remove(peerId);
|
||||
Q_EMIT sharingUrisChanged();
|
||||
auto it = objectListSharingUris_.find(peerId);
|
||||
if (it != objectListSharingUris_.end()) {
|
||||
it.value()->deleteLater();
|
||||
objectListSharingUris_.erase(it);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Update/remove existing
|
||||
if (endSharing) {
|
||||
// Remove (avoid self)
|
||||
if (peerId != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
|
||||
sharingUris_.remove(peerId);
|
||||
// Remove
|
||||
|
||||
sharingUris_.remove(peerId);
|
||||
Q_EMIT sharingUrisChanged();
|
||||
auto it = objectListSharingUris_.find(peerId);
|
||||
if (it != objectListSharingUris_.end()) {
|
||||
it.value()->deleteLater();
|
||||
objectListSharingUris_.erase(it);
|
||||
}
|
||||
if (isPeerIdInConv) {
|
||||
currentConvSharingUris_.remove(peerId);
|
||||
Q_EMIT positionShareRemoved(peerId);
|
||||
// close the map if you're not sharing and the only remaining position is yours
|
||||
if (!positionShareConvIds_.length() && sharingUris_.size() == 1
|
||||
&& sharingUris_.contains(
|
||||
lrcInstance_->getCurrentAccountInfo().profileInfo.uri)) {
|
||||
// close the map if you're not sharing and you don't receive position anymore
|
||||
if (!positionShareConvIds_.length()
|
||||
&& ((sharingUris_.size() == 1
|
||||
&& sharingUris_.contains(
|
||||
lrcInstance_->getCurrentAccountInfo().profileInfo.uri))
|
||||
|| sharingUris_.size() == 0)) {
|
||||
set_isMapActive(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Update
|
||||
Q_EMIT positionShareUpdated(getShareInfo(true));
|
||||
if (isPeerIdInConv)
|
||||
Q_EMIT positionShareUpdated(getShareInfo(true));
|
||||
// reset watchdog
|
||||
|
||||
auto it = objectListSharingUris_.find(peerId);
|
||||
if (it != objectListSharingUris_.end()) {
|
||||
it.value()->resetWatchdog();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "lrcinstance.h"
|
||||
#include "qmladapterbase.h"
|
||||
#include "positioning.h"
|
||||
#include "positionobject.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
@ -31,6 +32,7 @@ class PositionManager : public QmlAdapterBase
|
|||
QML_RO_PROPERTY(bool, isMapActive)
|
||||
QML_RO_PROPERTY(int, timeSharingRemaining)
|
||||
QML_PROPERTY(QList<QString>, positionShareConvIds)
|
||||
QML_PROPERTY(QSet<QString>, sharingUris)
|
||||
QML_PROPERTY(bool, mapAutoOpening)
|
||||
public:
|
||||
explicit PositionManager(LRCInstance* instance, QObject* parent = nullptr);
|
||||
|
@ -54,9 +56,16 @@ protected:
|
|||
Q_INVOKABLE void connectConversationModel();
|
||||
Q_INVOKABLE void setMapActive(bool state);
|
||||
Q_INVOKABLE void sharePosition(int maximumTime);
|
||||
Q_INVOKABLE void stopSharingPosition(const QString convId = "");
|
||||
|
||||
Q_INVOKABLE void startPositioning();
|
||||
Q_INVOKABLE void stopPositioning();
|
||||
Q_INVOKABLE void stopSharingPosition();
|
||||
|
||||
Q_INVOKABLE QString getSelectedConvId();
|
||||
Q_INVOKABLE bool isPositionSharedToConv(const QString& convUri);
|
||||
Q_INVOKABLE bool isConvSharingPosition(const QString& convUri);
|
||||
|
||||
Q_INVOKABLE void loadPreviousLocations();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPositionErrorReceived(const QString error);
|
||||
|
@ -64,11 +73,13 @@ private Q_SLOTS:
|
|||
const QString& body,
|
||||
const uint64_t& timestamp,
|
||||
const QString& daemonId);
|
||||
void onOwnPositionReceived(const QString& peerId, const QString& body);
|
||||
void sendPosition(const QString& peerId, const QString& body);
|
||||
void onWatchdogTimeout();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Positioning> localPositioning_;
|
||||
QTimer* timerTimeLeftSharing_ = nullptr;
|
||||
QTimer* timerStopSharing_ = nullptr;
|
||||
QSet<QString> sharingUris_;
|
||||
QSet<QString> currentConvSharingUris_;
|
||||
QMap<QString, PositionObject*> objectListSharingUris_;
|
||||
};
|
||||
|
|
30
src/app/positionobject.cpp
Normal file
30
src/app/positionobject.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "positionobject.h"
|
||||
|
||||
PositionObject::PositionObject(QVariant latitude, QVariant longitude, QObject* parent)
|
||||
: QObject(parent)
|
||||
, resetTime(20000)
|
||||
, longitude_(longitude)
|
||||
, latitude_(latitude)
|
||||
|
||||
{
|
||||
watchdog_ = new QTimer(this);
|
||||
watchdog_->start(resetTime);
|
||||
connect(watchdog_, &QTimer::timeout, this, &PositionObject::timeout);
|
||||
}
|
||||
|
||||
void
|
||||
PositionObject::resetWatchdog()
|
||||
{
|
||||
watchdog_->start(resetTime);
|
||||
}
|
||||
|
||||
QVariant
|
||||
PositionObject::getLongitude()
|
||||
{
|
||||
return longitude_;
|
||||
}
|
||||
QVariant
|
||||
PositionObject::getLatitude()
|
||||
{
|
||||
return latitude_;
|
||||
}
|
28
src/app/positionobject.h
Normal file
28
src/app/positionobject.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "qvariant.h"
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
|
||||
class PositionObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PositionObject(QVariant latitude, QVariant longitude, QObject* parent = nullptr);
|
||||
|
||||
Q_SIGNAL void timeout();
|
||||
|
||||
void resetWatchdog();
|
||||
|
||||
QVariant getLongitude();
|
||||
QVariant getLatitude();
|
||||
|
||||
private:
|
||||
QVariant latitude_;
|
||||
QVariant longitude_;
|
||||
int resetTime;
|
||||
QTimer* watchdog_;
|
||||
};
|
|
@ -106,10 +106,6 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
Component.onDestruction: {
|
||||
PositionManager.stopSharingPosition();
|
||||
PositionManager.stopPositioning();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
loadHtml(UtilsAdapter.qStringFromFile(mapHtml), mapHtml)
|
||||
|
@ -122,6 +118,8 @@ Rectangle {
|
|||
webView.isLoaded = true
|
||||
runJavaScript("setMapView([" + 0 + ","+ 0 + "], " + 1 + " );" );
|
||||
PositionManager.startPositioning()
|
||||
//load locations that were received before this conversation was opened
|
||||
PositionManager.loadPreviousLocations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +150,6 @@ Rectangle {
|
|||
onClicked: {
|
||||
buttonsChoseSharing.shortSharing = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
|
@ -195,69 +192,108 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: sharePositionButton
|
||||
|
||||
preferredWidth: text.contentWidth
|
||||
textLeftPadding: JamiTheme.buttontextPadding
|
||||
textRightPadding: JamiTheme.buttontextPadding
|
||||
primary: true
|
||||
text: webView.isSharing ? JamiStrings.stopSharingLocation : JamiStrings.shareLocation
|
||||
color: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: webView.isSharing ? JamiTheme.buttonTintedRed : JamiTheme.buttonTintedBlue
|
||||
hoveredColor: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: webView.isSharing ? JamiTheme.buttonTintedRedHovered : JamiTheme.buttonTintedBlueHovered
|
||||
pressedColor: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: webView.isSharing ? JamiTheme.buttonTintedRedPressed: JamiTheme.buttonTintedBluePressed
|
||||
RowLayout {
|
||||
id: sharePositionLayout
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
property bool isHovered: false
|
||||
property string positioningError: "default"
|
||||
property bool isError: positioningError.length
|
||||
MaterialButton {
|
||||
id: sharePositionButton
|
||||
|
||||
function errorString(posError) {
|
||||
if (posError === "locationServicesError")
|
||||
return JamiStrings.locationServicesError
|
||||
return JamiStrings.locationServicesClosedError
|
||||
}
|
||||
preferredWidth: text.contentWidth
|
||||
textLeftPadding: JamiTheme.buttontextPadding
|
||||
textRightPadding: JamiTheme.buttontextPadding
|
||||
primary: true
|
||||
visible: ! PositionManager.isPositionSharedToConv(PositionManager.getSelectedConvId())
|
||||
text: JamiStrings.shareLocation
|
||||
color: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: JamiTheme.buttonTintedBlue
|
||||
hoveredColor: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: JamiTheme.buttonTintedBlueHovered
|
||||
pressedColor: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: JamiTheme.buttonTintedBluePressed
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
property bool isHovered: false
|
||||
property string positioningError: "default"
|
||||
property bool isError: positioningError.length
|
||||
function errorString(posError) {
|
||||
if (posError === "locationServicesError")
|
||||
return JamiStrings.locationServicesError
|
||||
return JamiStrings.locationServicesClosedError
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (!isError) {
|
||||
if (webView.isSharing) {
|
||||
PositionManager.stopSharingPosition();
|
||||
} else {
|
||||
if (buttonsChoseSharing.shortSharing)
|
||||
onClicked: {
|
||||
if (!isError) {
|
||||
if( buttonsChoseSharing.shortSharing)
|
||||
PositionManager.sharePosition(10 * 60 * 1000);
|
||||
else
|
||||
PositionManager.sharePosition(60 * 60 * 1000);
|
||||
visible = false
|
||||
}
|
||||
}
|
||||
|
||||
onHoveredChanged: {
|
||||
isHovered = !isHovered
|
||||
}
|
||||
|
||||
MaterialToolTip {
|
||||
visible: sharePositionButton.isHovered
|
||||
&& sharePositionButton.isError && (sharePositionButton.positioningError !== "default")
|
||||
x: 0
|
||||
y: 0
|
||||
text: sharePositionButton.errorString(sharePositionButton.positioningError)
|
||||
}
|
||||
Connections {
|
||||
target: PositionManager
|
||||
function onPositioningError (err) {
|
||||
sharePositionButton.positioningError = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
MaterialButton {
|
||||
id: stopSharingPositionButton
|
||||
|
||||
onHoveredChanged: {
|
||||
isHovered = !isHovered
|
||||
}
|
||||
|
||||
MaterialToolTip {
|
||||
visible: sharePositionButton.isHovered
|
||||
&& sharePositionButton.isError && (sharePositionButton.positioningError !== "default")
|
||||
x: 0
|
||||
y: 0
|
||||
text: sharePositionButton.errorString(sharePositionButton.positioningError)
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: PositionManager
|
||||
function onPositioningError (err) {
|
||||
sharePositionButton.positioningError = err;
|
||||
preferredWidth: text.contentWidth
|
||||
textLeftPadding: JamiTheme.buttontextPadding
|
||||
textRightPadding: JamiTheme.buttontextPadding
|
||||
primary: true
|
||||
visible: webView.isSharing
|
||||
text: JamiStrings.stopSharingLocation
|
||||
color: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: JamiTheme.buttonTintedRed
|
||||
hoveredColor: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: JamiTheme.buttonTintedRedHovered
|
||||
pressedColor: isError
|
||||
? JamiTheme.buttonTintedGreyInactive
|
||||
: JamiTheme.buttonTintedRedPressed
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
property bool isHovered: false
|
||||
property string positioningError
|
||||
property bool isError: positioningError.length
|
||||
onClicked: {
|
||||
if (!isError) {
|
||||
if (PositionManager.positionShareConvIds.length >= 2) {
|
||||
stopSharingPositionPopup.open()
|
||||
} else {
|
||||
PositionManager.stopSharingPosition();
|
||||
sharePositionButton.visible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StopSharingPositionPopup {
|
||||
id: stopSharingPositionPopup
|
||||
|
||||
property alias shareButtonVisibility: sharePositionButton.visible
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: buttonOverlay
|
||||
|
||||
|
@ -277,6 +313,7 @@ Rectangle {
|
|||
PushButton {
|
||||
id: btnCenter
|
||||
|
||||
toolTipText: JamiStrings.centerMapTooltip
|
||||
imageColor: JamiTheme.mapButtonColor
|
||||
normalColor: JamiTheme.transparentColor
|
||||
source: JamiResources.share_location_svg
|
||||
|
@ -288,6 +325,7 @@ Rectangle {
|
|||
PushButton {
|
||||
id: btnMove
|
||||
|
||||
toolTipText: JamiStrings.dragMapTooltip
|
||||
imageColor: JamiTheme.mapButtonColor
|
||||
normalColor: JamiTheme.transparentColor
|
||||
source: JamiResources.move_svg
|
||||
|
@ -303,8 +341,11 @@ Rectangle {
|
|||
}
|
||||
|
||||
PushButton {
|
||||
id: btnminimise
|
||||
id: btnminimize
|
||||
|
||||
toolTipText: isMinimised
|
||||
? JamiStrings.extendMapTooltip
|
||||
: JamiStrings.minimizeMapTooltip
|
||||
imageColor: JamiTheme.mapButtonColor
|
||||
normalColor: JamiTheme.transparentColor
|
||||
source: isMinimised
|
||||
|
@ -319,6 +360,9 @@ Rectangle {
|
|||
PushButton {
|
||||
id: btnmaximise
|
||||
|
||||
toolTipText: isFullScreen
|
||||
? JamiStrings.reduceMapTooltip
|
||||
: JamiStrings.maximizeMapTooltip
|
||||
imageColor: JamiTheme.mapButtonColor
|
||||
normalColor: JamiTheme.transparentColor
|
||||
source: isFullScreen? JamiResources.close_fullscreen_24dp_svg : JamiResources.open_in_full_24dp_svg
|
||||
|
@ -335,11 +379,13 @@ Rectangle {
|
|||
PushButton {
|
||||
id: btnClose
|
||||
|
||||
toolTipText: JamiStrings.closeMapTooltip
|
||||
imageColor: JamiTheme.mapButtonColor
|
||||
normalColor: JamiTheme.transparentColor
|
||||
source: JamiResources.round_close_24dp_svg
|
||||
|
||||
onClicked: {
|
||||
PositionManager.stopPositioning();
|
||||
PositionManager.setMapActive(false);
|
||||
PositionManager.mapAutoOpening = false;
|
||||
|
||||
|
|
173
src/app/webengine/map/StopSharingPositionPopup.qml
Normal file
173
src/app/webengine/map/StopSharingPositionPopup.qml
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Savoir-faire Linux Inc.
|
||||
* Author: Nicolas Vengeon <nicolas.vengeon@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
|
||||
import "../../commoncomponents"
|
||||
|
||||
Popup {
|
||||
id: root
|
||||
|
||||
width: popupContent.width
|
||||
height: popupContent.height
|
||||
|
||||
parent: Overlay.overlay
|
||||
|
||||
// center in parent
|
||||
x: Math.round((parent.width - width) / 2)
|
||||
y: Math.round((parent.height - height) / 2)
|
||||
|
||||
signal joinClicked
|
||||
|
||||
modal:true
|
||||
padding: 0
|
||||
|
||||
visible: false
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
Rectangle {
|
||||
id: container
|
||||
|
||||
anchors.fill: parent
|
||||
radius: JamiTheme.modalPopupRadius
|
||||
color: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
ColumnLayout {
|
||||
id: popupContent
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
PushButton {
|
||||
id: btnClose
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
width: 30
|
||||
height: 30
|
||||
imageContainerWidth: 30
|
||||
imageContainerHeight : 30
|
||||
Layout.margins: 8
|
||||
radius : 5
|
||||
imageColor: "grey"
|
||||
normalColor: JamiTheme.transparentColor
|
||||
source: JamiResources.round_close_24dp_svg
|
||||
onClicked: { root.visible = false }
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.leftMargin: 20
|
||||
Layout.rightMargin: 20
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pixelSize: JamiTheme.popuptextSize
|
||||
font.weight: Font.Medium
|
||||
wrapMode: Text.WordWrap
|
||||
color: JamiTheme.textColor
|
||||
text: JamiStrings.stopSharingPopupBody
|
||||
}
|
||||
|
||||
RowLayout{
|
||||
Layout.margins: JamiTheme.popupButtonsMargin
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
MaterialButton {
|
||||
preferredWidth: text.contentWidth
|
||||
textLeftPadding: JamiTheme.buttontextPadding
|
||||
textRightPadding: JamiTheme.buttontextPadding
|
||||
|
||||
color: JamiTheme.buttonTintedBlue
|
||||
hoveredColor: JamiTheme.buttonTintedBlueHovered
|
||||
pressedColor: JamiTheme.buttonTintedBluePressed
|
||||
text: JamiStrings.stopConvSharing
|
||||
|
||||
onClicked: {
|
||||
PositionManager.stopSharingPosition(PositionManager.getSelectedConvId())
|
||||
shareButtonVisibility = true
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
preferredWidth: text.contentWidth
|
||||
textLeftPadding: JamiTheme.buttontextPadding
|
||||
textRightPadding: JamiTheme.buttontextPadding
|
||||
|
||||
color: JamiTheme.buttonTintedRed
|
||||
hoveredColor: JamiTheme.buttonTintedRedHovered
|
||||
pressedColor: JamiTheme.buttonTintedRedPressed
|
||||
|
||||
text: JamiStrings.stopAllSharings
|
||||
|
||||
onClicked: {
|
||||
PositionManager.stopSharingPosition()
|
||||
shareButtonVisibility = true
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: JamiTheme.transparentColor
|
||||
}
|
||||
|
||||
Overlay.modal: Rectangle {
|
||||
color: JamiTheme.transparentColor
|
||||
// Color animation for overlay when pop up is shown.
|
||||
ColorAnimation on color {
|
||||
to: JamiTheme.popupOverlayColor
|
||||
duration: 500
|
||||
}
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
z: -1
|
||||
width: root.width
|
||||
height: root.height
|
||||
horizontalOffset: 3.0
|
||||
verticalOffset: 3.0
|
||||
radius: container.radius * 4
|
||||
color: JamiTheme.shadowColor
|
||||
source: container
|
||||
transparentBorder: true
|
||||
}
|
||||
|
||||
enter: Transition {
|
||||
NumberAnimation {
|
||||
properties: "opacity"; from: 0.0; to: 1.0
|
||||
duration: JamiTheme.shortFadeDuration
|
||||
}
|
||||
}
|
||||
|
||||
exit: Transition {
|
||||
NumberAnimation {
|
||||
properties: "opacity"; from: 1.0; to: 0.0
|
||||
duration: JamiTheme.shortFadeDuration
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue