mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-08-04 06:45:45 +02:00
Feature: unpin location sharing map
- Refactoring - Unpined map - handle multiple maps (one map per account) Change-Id: I2b0abf284ccfe27b986f03915c5942d721403211 Gitlab: #901
This commit is contained in:
parent
c36ccb5fa9
commit
d06902e3b7
22 changed files with 1162 additions and 600 deletions
1
resources/icons/unpin.svg
Normal file
1
resources/icons/unpin.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h13.95v3H9v30h30V25.05h3V39q0 1.2-.9 2.1-.9.9-2.1.9Zm10.1-10.95L17 28.9 36.9 9H25.95V6H42v16.05h-3v-10.9Z"/></svg>
|
After Width: | Height: | Size: 241 B |
|
@ -54,7 +54,9 @@ extern const QString defaultDownloadPath;
|
||||||
X(WindowGeometry, QRectF(qQNaN(), qQNaN(), 0., 0.)) \
|
X(WindowGeometry, QRectF(qQNaN(), qQNaN(), 0., 0.)) \
|
||||||
X(WindowState, QWindow::AutomaticVisibility) \
|
X(WindowState, QWindow::AutomaticVisibility) \
|
||||||
X(EnableExperimentalSwarm, false) \
|
X(EnableExperimentalSwarm, false) \
|
||||||
X(LANG, "SYSTEM")
|
X(LANG, "SYSTEM") \
|
||||||
|
X(PositionShareDuration, 15) \
|
||||||
|
X(PositionShareLimit, true)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A class to expose settings keys in both c++ and QML.
|
* A class to expose settings keys in both c++ and QML.
|
||||||
|
|
|
@ -309,8 +309,12 @@ Item {
|
||||||
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 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 locationServicesClosedError: qsTr("Your precise location could not be determined. Please check your Internet connection.")
|
||||||
property string stopAllSharings: qsTr("Turn off location sharing");
|
property string stopAllSharings: qsTr("Turn off location sharing");
|
||||||
property string stopConvSharing: qsTr("Stop location sharing in this conversation");
|
property string shortStopAllSharings: qsTr("Turn off sharing");
|
||||||
|
property string stopConvSharing: qsTr("Stop location sharing in this conversation (%1)");
|
||||||
property string stopSharingPopupBody: qsTr("Location is shared in several conversations");
|
property string stopSharingPopupBody: qsTr("Location is shared in several conversations");
|
||||||
|
property string unpinStopSharingTooltip: qsTr("Pin map to be able to share location or to turn off location in specific conversations");
|
||||||
|
property string stopSharingSeveralConversationTooltip: qsTr("Location is shared in several conversations, click to choose how to turn off location sharing")
|
||||||
|
property string shareLocationToolTip: qsTr("Share location to participants of this conversation (%1)");
|
||||||
property string minimizeMapTooltip: qsTr("Minimize");
|
property string minimizeMapTooltip: qsTr("Minimize");
|
||||||
property string maximizeMapTooltip: qsTr("Maximize");
|
property string maximizeMapTooltip: qsTr("Maximize");
|
||||||
property string reduceMapTooltip: qsTr("Reduce");
|
property string reduceMapTooltip: qsTr("Reduce");
|
||||||
|
@ -318,6 +322,11 @@ Item {
|
||||||
property string dragMapTooltip: qsTr("Drag");
|
property string dragMapTooltip: qsTr("Drag");
|
||||||
property string centerMapTooltip: qsTr("Center");
|
property string centerMapTooltip: qsTr("Center");
|
||||||
property string closeMapTooltip: qsTr("Close");
|
property string closeMapTooltip: qsTr("Close");
|
||||||
|
property string unpin: qsTr("Unpin");
|
||||||
|
property string pinWindow: qsTr("Pin");
|
||||||
|
property string positionShareDuration: qsTr("Position share duration");
|
||||||
|
property string positionShareLimit: qsTr("Limit the duration of location sharing");
|
||||||
|
property string locationSharingLabel: qsTr("Location sharing");
|
||||||
|
|
||||||
// Chatview header
|
// Chatview header
|
||||||
property string hideChat: qsTr("Hide chat")
|
property string hideChat: qsTr("Hide chat")
|
||||||
|
@ -694,6 +703,7 @@ Item {
|
||||||
// SmartList
|
// SmartList
|
||||||
property string clearText: qsTr("Clear Text")
|
property string clearText: qsTr("Clear Text")
|
||||||
property string conversations: qsTr("Conversations")
|
property string conversations: qsTr("Conversations")
|
||||||
|
property string conversation: qsTr("Conversation")
|
||||||
property string searchResults: qsTr("Search Results")
|
property string searchResults: qsTr("Search Results")
|
||||||
|
|
||||||
// SmartList context menu
|
// SmartList context menu
|
||||||
|
|
|
@ -34,7 +34,7 @@ Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool allMessagesLoaded
|
property bool allMessagesLoaded
|
||||||
|
property var mapPositions: PositionManager.mapStatus
|
||||||
signal needToHideConversationInCall
|
signal needToHideConversationInCall
|
||||||
signal messagesCleared
|
signal messagesCleared
|
||||||
signal messagesLoaded
|
signal messagesLoaded
|
||||||
|
@ -51,18 +51,28 @@ Rectangle {
|
||||||
addMemberPanel.visible = false
|
addMemberPanel.visible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function instanceMapObject() {
|
||||||
|
if (WITH_WEBENGINE) {
|
||||||
|
var component = Qt.createComponent("qrc:/webengine/map/MapPosition.qml");
|
||||||
|
var sprite = component.createObject(root, {maxWidth: root.width, maxHeight: root.height});
|
||||||
|
|
||||||
|
if (sprite === null) {
|
||||||
|
// Error Handling
|
||||||
|
console.log("Error creating object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: PositionManager
|
||||||
|
|
||||||
|
function onOpenNewMap() {
|
||||||
|
instanceMapObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
color: JamiTheme.chatviewBgColor
|
color: JamiTheme.chatviewBgColor
|
||||||
|
|
||||||
property string currentConvId: CurrentConversation.id
|
property string currentConvId: CurrentConversation.id
|
||||||
onCurrentConvIdChanged: PositionManager.setMapActive(false);
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: mapLoader
|
|
||||||
|
|
||||||
active: PositionManager.isMapActive
|
|
||||||
z: 10
|
|
||||||
source: WITH_WEBENGINE ? "qrc:/webengine/map/MapPosition.qml" : ""
|
|
||||||
}
|
|
||||||
|
|
||||||
HostPopup {
|
HostPopup {
|
||||||
id: hostPopup
|
id: hostPopup
|
||||||
|
|
|
@ -190,7 +190,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
onShowMapClicked: {
|
onShowMapClicked: {
|
||||||
PositionManager.setMapActive(true);
|
PositionManager.setMapActive(CurrentAccount.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
onSendFileButtonClicked: jamiFileDialog.open()
|
onSendFileButtonClicked: jamiFileDialog.open()
|
||||||
|
|
|
@ -65,12 +65,33 @@ ColumnLayout {
|
||||||
spacing: JamiTheme.chatViewFooterRowSpacing
|
spacing: JamiTheme.chatViewFooterRowSpacing
|
||||||
|
|
||||||
PushButton {
|
PushButton {
|
||||||
id: sendFileButton
|
id: showMapButton
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Layout.leftMargin: marginSize
|
Layout.leftMargin: marginSize
|
||||||
Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize
|
Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize
|
||||||
Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize
|
Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize
|
||||||
|
visible: WITH_WEBENGINE && !CurrentConversation.isSip
|
||||||
|
|
||||||
|
radius: JamiTheme.chatViewFooterButtonRadius
|
||||||
|
preferredSize: JamiTheme.chatViewFooterButtonIconSize
|
||||||
|
|
||||||
|
toolTipText: JamiStrings.shareLocation
|
||||||
|
|
||||||
|
source: JamiResources.share_location_svg
|
||||||
|
|
||||||
|
normalColor: JamiTheme.primaryBackgroundColor
|
||||||
|
imageColor: JamiTheme.messageWebViewFooterButtonImageColor
|
||||||
|
|
||||||
|
onClicked: root.showMapClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton {
|
||||||
|
id: sendFileButton
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize
|
||||||
|
Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize
|
||||||
|
|
||||||
radius: JamiTheme.chatViewFooterButtonRadius
|
radius: JamiTheme.chatViewFooterButtonRadius
|
||||||
preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6
|
preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6
|
||||||
|
@ -130,27 +151,6 @@ ColumnLayout {
|
||||||
Component.onCompleted: JamiQmlUtils.videoRecordMessageButtonObj = videoRecordMessageButton
|
Component.onCompleted: JamiQmlUtils.videoRecordMessageButtonObj = videoRecordMessageButton
|
||||||
}
|
}
|
||||||
|
|
||||||
PushButton {
|
|
||||||
id: showMapButton
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize
|
|
||||||
Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize
|
|
||||||
visible: WITH_WEBENGINE && !CurrentConversation.isSip
|
|
||||||
|
|
||||||
radius: JamiTheme.chatViewFooterButtonRadius
|
|
||||||
preferredSize: JamiTheme.chatViewFooterButtonIconSize
|
|
||||||
|
|
||||||
toolTipText: JamiStrings.shareLocation
|
|
||||||
|
|
||||||
source: JamiResources.share_location_svg
|
|
||||||
|
|
||||||
normalColor: JamiTheme.primaryBackgroundColor
|
|
||||||
imageColor: JamiTheme.messageWebViewFooterButtonImageColor
|
|
||||||
|
|
||||||
onClicked: root.showMapClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageBarTextArea {
|
MessageBarTextArea {
|
||||||
id: textArea
|
id: textArea
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,8 @@ ItemDelegate {
|
||||||
|
|
||||||
imageId: UID
|
imageId: UID
|
||||||
showPresenceIndicator: Presence !== undefined ? Presence : false
|
showPresenceIndicator: Presence !== undefined ? Presence : false
|
||||||
showSharePositionIndicator: PositionManager.isPositionSharedToConv(UID)
|
showSharePositionIndicator: PositionManager.isPositionSharedToConv(accountId, UID)
|
||||||
showSharedPositionIndicator: PositionManager.isConvSharingPosition(UID)
|
showSharedPositionIndicator: PositionManager.isConvSharingPosition(accountId, UID)
|
||||||
|
|
||||||
Layout.preferredWidth: JamiTheme.smartListAvatarSize
|
Layout.preferredWidth: JamiTheme.smartListAvatarSize
|
||||||
Layout.preferredHeight: JamiTheme.smartListAvatarSize
|
Layout.preferredHeight: JamiTheme.smartListAvatarSize
|
||||||
|
@ -77,10 +77,10 @@ ItemDelegate {
|
||||||
Connections {
|
Connections {
|
||||||
target: PositionManager
|
target: PositionManager
|
||||||
function onPositionShareConvIdsCountChanged () {
|
function onPositionShareConvIdsCountChanged () {
|
||||||
avatar.showSharePositionIndicator = PositionManager.isPositionSharedToConv(UID)
|
avatar.showSharePositionIndicator = PositionManager.isPositionSharedToConv(accountId, UID)
|
||||||
}
|
}
|
||||||
function onSharingUrisCountChanged () {
|
function onSharingUrisCountChanged () {
|
||||||
avatar.showSharedPositionIndicator = PositionManager.isConvSharingPosition(UID)
|
avatar.showSharedPositionIndicator = PositionManager.isConvSharingPosition(accountId, UID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,12 @@
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
Positioning::Positioning(QString uri, QObject* parent)
|
Positioning::Positioning(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, uri_(uri)
|
|
||||||
{
|
{
|
||||||
source_ = QGeoPositionInfoSource::createDefaultSource(this);
|
source_ = QGeoPositionInfoSource::createDefaultSource(this);
|
||||||
QTimer* timer = new QTimer(this);
|
timer_ = new QTimer(this);
|
||||||
connect(timer, &QTimer::timeout, this, &Positioning::requestPosition);
|
connect(timer_, &QTimer::timeout, this, &Positioning::requestPosition);
|
||||||
timer->start(5000);
|
|
||||||
connect(source_, &QGeoPositionInfoSource::errorOccurred, this, &Positioning::slotError);
|
connect(source_, &QGeoPositionInfoSource::errorOccurred, this, &Positioning::slotError);
|
||||||
connect(source_, &QGeoPositionInfoSource::positionUpdated, this, &Positioning::positionUpdated);
|
connect(source_, &QGeoPositionInfoSource::positionUpdated, this, &Positioning::positionUpdated);
|
||||||
// if location services are activated, positioning will be activated automatically
|
// if location services are activated, positioning will be activated automatically
|
||||||
|
@ -41,6 +39,8 @@ Positioning::Positioning(QString uri, QObject* parent)
|
||||||
void
|
void
|
||||||
Positioning::start()
|
Positioning::start()
|
||||||
{
|
{
|
||||||
|
requestPosition();
|
||||||
|
timer_->start(10000);
|
||||||
if (source_ && !isPositioning) {
|
if (source_ && !isPositioning) {
|
||||||
source_->startUpdates();
|
source_->startUpdates();
|
||||||
isPositioning = true;
|
isPositioning = true;
|
||||||
|
@ -53,6 +53,7 @@ Positioning::stop()
|
||||||
if (source_ && isPositioning)
|
if (source_ && isPositioning)
|
||||||
source_->stopUpdates();
|
source_->stopUpdates();
|
||||||
isPositioning = false;
|
isPositioning = false;
|
||||||
|
timer_->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
|
@ -70,17 +71,11 @@ Positioning::convertToJson(const QGeoPositionInfo& info)
|
||||||
return strJson;
|
return strJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Positioning::setUri(QString uri)
|
|
||||||
{
|
|
||||||
uri_ = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Positioning::positionUpdated(const QGeoPositionInfo& info)
|
Positioning::positionUpdated(const QGeoPositionInfo& info)
|
||||||
{
|
{
|
||||||
Q_EMIT positioningError("");
|
Q_EMIT positioningError("");
|
||||||
Q_EMIT newPosition("", uri_, convertToJson(info), -1, "");
|
Q_EMIT newPosition(convertToJson(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Positioning : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Positioning(QString uri, QObject* parent = 0);
|
Positioning(QObject* parent = 0);
|
||||||
/**
|
/**
|
||||||
* start to retreive the current position
|
* start to retreive the current position
|
||||||
*/
|
*/
|
||||||
|
@ -42,8 +42,6 @@ public:
|
||||||
*/
|
*/
|
||||||
QString convertToJson(const QGeoPositionInfo& info);
|
QString convertToJson(const QGeoPositionInfo& info);
|
||||||
|
|
||||||
void setUri(QString uri);
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void slotError(QGeoPositionInfoSource::Error error);
|
void slotError(QGeoPositionInfoSource::Error error);
|
||||||
void positionUpdated(const QGeoPositionInfo& info);
|
void positionUpdated(const QGeoPositionInfo& info);
|
||||||
|
@ -57,15 +55,12 @@ private Q_SLOTS:
|
||||||
void locationServicesActivated();
|
void locationServicesActivated();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void newPosition(const QString& unused_AccountId,
|
void newPosition(const QString& body);
|
||||||
const QString& peerId,
|
|
||||||
const QString& body,
|
|
||||||
const uint64_t& timestamp,
|
|
||||||
const QString& daemonId);
|
|
||||||
void positioningError(const QString error);
|
void positioningError(const QString error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString uri_;
|
QString uri_;
|
||||||
QGeoPositionInfoSource* source_ = nullptr;
|
QGeoPositionInfoSource* source_ = nullptr;
|
||||||
bool isPositioning = false;
|
bool isPositioning = false;
|
||||||
|
QTimer* timer_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#include "positionmanager.h"
|
#include "positionmanager.h"
|
||||||
|
|
||||||
#include "qtutils.h"
|
#include "appsettingsmanager.h"
|
||||||
|
|
||||||
|
#include "qtutils.h"
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
@ -9,31 +10,40 @@
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
|
||||||
PositionManager::PositionManager(SystemTray* systemTray, LRCInstance* instance, QObject* parent)
|
PositionManager::PositionManager(AppSettingsManager* settingsManager,
|
||||||
|
SystemTray* systemTray,
|
||||||
|
LRCInstance* instance,
|
||||||
|
QObject* parent)
|
||||||
: QmlAdapterBase(instance, parent)
|
: QmlAdapterBase(instance, parent)
|
||||||
, systemTray_(systemTray)
|
, systemTray_(systemTray)
|
||||||
|
, settingsManager_(settingsManager)
|
||||||
{
|
{
|
||||||
timerTimeLeftSharing_ = new QTimer(this);
|
countdownTimer_ = new QTimer(this);
|
||||||
timerStopSharing_ = new QTimer(this);
|
connect(countdownTimer_, &QTimer::timeout, this, &PositionManager::countdownUpdate);
|
||||||
connect(timerTimeLeftSharing_, &QTimer::timeout, [=] {
|
connect(lrcInstance_,
|
||||||
set_timeSharingRemaining(timerStopSharing_->remainingTime());
|
&LRCInstance::selectedConvUidChanged,
|
||||||
});
|
this,
|
||||||
connect(timerStopSharing_, &QTimer::timeout, [=] { stopSharingPosition(); });
|
&PositionManager::onNewConversation,
|
||||||
connect(lrcInstance_, &LRCInstance::selectedConvUidChanged, [this]() {
|
Qt::UniqueConnection);
|
||||||
set_mapAutoOpening(true);
|
connect(lrcInstance_,
|
||||||
});
|
&LRCInstance::currentAccountIdChanged,
|
||||||
connect(lrcInstance_, &LRCInstance::currentAccountIdChanged, [this]() {
|
this,
|
||||||
if (!localPositioning_) // Not yet initialized
|
&PositionManager::onNewAccount,
|
||||||
return;
|
Qt::UniqueConnection);
|
||||||
localPositioning_->setUri(lrcInstance_->getCurrentAccountInfo().profileInfo.uri);
|
connect(
|
||||||
});
|
this,
|
||||||
set_isMapActive(false);
|
&PositionManager::localPositionReceived,
|
||||||
|
this,
|
||||||
|
[this](const QString& accountId, const QString& peerId, const QString& body) {
|
||||||
|
onPositionReceived(accountId, peerId, body, -1, "");
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::safeInit()
|
PositionManager::safeInit()
|
||||||
{
|
{
|
||||||
localPositioning_.reset(new Positioning(lrcInstance_->getCurrentAccountInfo().profileInfo.uri));
|
localPositioning_.reset(new Positioning());
|
||||||
connectAccountModel();
|
connectAccountModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,41 +60,36 @@ PositionManager::connectAccountModel()
|
||||||
void
|
void
|
||||||
PositionManager::startPositioning()
|
PositionManager::startPositioning()
|
||||||
{
|
{
|
||||||
currentConvSharingUris_.clear();
|
if (localPositioning_)
|
||||||
localPositioning_->start();
|
localPositioning_->start();
|
||||||
connect(localPositioning_.get(),
|
|
||||||
&Positioning::newPosition,
|
|
||||||
this,
|
|
||||||
&PositionManager::onPositionReceived,
|
|
||||||
Qt::UniqueConnection);
|
|
||||||
connect(localPositioning_.get(),
|
connect(localPositioning_.get(),
|
||||||
&Positioning::positioningError,
|
&Positioning::positioningError,
|
||||||
this,
|
this,
|
||||||
&PositionManager::onPositionErrorReceived,
|
&PositionManager::onPositionErrorReceived,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
|
connect(
|
||||||
|
localPositioning_.get(),
|
||||||
|
&Positioning::newPosition,
|
||||||
|
this,
|
||||||
|
[this](const QString& body) { sendPosition(body, true); },
|
||||||
|
Qt::UniqueConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::stopPositioning()
|
PositionManager::stopPositioning()
|
||||||
{
|
{
|
||||||
localPositioning_->stop();
|
if (localPositioning_)
|
||||||
}
|
localPositioning_->stop();
|
||||||
|
|
||||||
QString
|
|
||||||
PositionManager::getSelectedConvId()
|
|
||||||
{
|
|
||||||
return lrcInstance_->get_selectedConvUid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PositionManager::isConvSharingPosition(const QString& convUri)
|
PositionManager::isConvSharingPosition(const QString& accountId, const QString& convUri)
|
||||||
{
|
{
|
||||||
const auto& convParticipants = lrcInstance_->getConversationFromConvUid(convUri)
|
const auto& convParticipants = lrcInstance_->getConversationFromConvUid(convUri)
|
||||||
.participantsUris();
|
.participantsUris();
|
||||||
Q_FOREACH (const auto& id, convParticipants) {
|
Q_FOREACH (const auto& id, convParticipants) {
|
||||||
if (id != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
|
if (id != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
|
||||||
if (objectListSharingUris_.contains(
|
if (objectListSharingUris_.contains(PositionKey {accountId, id})) {
|
||||||
QPair<QString, QString> {lrcInstance_->get_currentAccountId(), id})) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,36 +98,53 @@ PositionManager::isConvSharingPosition(const QString& convUri)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::loadPreviousLocations()
|
PositionManager::loadPreviousLocations(QString& accountId)
|
||||||
{
|
{
|
||||||
QVariantMap shareInfo;
|
QVariantMap shareInfo;
|
||||||
for (auto it = objectListSharingUris_.begin(); it != objectListSharingUris_.end(); it++) {
|
for (auto it = objectListSharingUris_.begin(); it != objectListSharingUris_.end(); it++) {
|
||||||
QJsonObject jsonObj;
|
if (it.key().first == accountId) {
|
||||||
jsonObj.insert("type", QJsonValue("Position"));
|
QJsonObject jsonObj;
|
||||||
jsonObj.insert("lat", it.value()->getLatitude().toString());
|
jsonObj.insert("type", QJsonValue("Position"));
|
||||||
jsonObj.insert("long", it.value()->getLongitude().toString());
|
jsonObj.insert("lat", it.value()->getLatitude().toString());
|
||||||
QJsonDocument doc(jsonObj);
|
jsonObj.insert("long", it.value()->getLongitude().toString());
|
||||||
QString strJson(doc.toJson(QJsonDocument::Compact));
|
QJsonDocument doc(jsonObj);
|
||||||
onPositionReceived(it.key().first, it.key().second, strJson, -1, "");
|
QString strJson(doc.toJson(QJsonDocument::Compact));
|
||||||
|
// parse the position from json
|
||||||
|
QVariantMap positionReceived = parseJsonPosition(it.key().first,
|
||||||
|
it.key().second,
|
||||||
|
strJson);
|
||||||
|
addPositionToMap(it.key(), positionReceived);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
PositionManager::getmapTitle(QString& accountId, QString convId)
|
||||||
|
{
|
||||||
|
if (!convId.isEmpty() && !accountId.isEmpty()) {
|
||||||
|
return lrcInstance_->getAccountInfo(accountId).conversationModel->title(convId);
|
||||||
|
}
|
||||||
|
if (!accountId.isEmpty())
|
||||||
|
return lrcInstance_->getAccountInfo(accountId).registeredName;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PositionManager::isPositionSharedToConv(const QString& convUid)
|
PositionManager::isPositionSharedToConv(const QString& accountId, const QString& convUid)
|
||||||
{
|
{
|
||||||
if (positionShareConvIds_.length()) {
|
if (positionShareConvIds_.length()) {
|
||||||
auto iter = std::find(positionShareConvIds_.begin(),
|
auto iter = std::find(positionShareConvIds_.begin(),
|
||||||
positionShareConvIds_.end(),
|
positionShareConvIds_.end(),
|
||||||
QPair<QString, QString> {lrcInstance_->get_currentAccountId(),
|
PositionKey {accountId, convUid});
|
||||||
convUid});
|
|
||||||
return (iter != positionShareConvIds_.end());
|
return (iter != positionShareConvIds_.end());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::sendPosition(const QString& body)
|
PositionManager::sendPosition(const QString& body, bool triggersLocalPosition)
|
||||||
{
|
{
|
||||||
|
// send position to positionShareConvIds_ participants
|
||||||
try {
|
try {
|
||||||
Q_FOREACH (const auto& key, positionShareConvIds_) {
|
Q_FOREACH (const auto& key, positionShareConvIds_) {
|
||||||
const auto& convInfo = lrcInstance_->getConversationFromConvUid(key.second, key.first);
|
const auto& convInfo = lrcInstance_->getConversationFromConvUid(key.second, key.first);
|
||||||
|
@ -137,6 +159,15 @@ PositionManager::sendPosition(const QString& body)
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
qDebug() << Q_FUNC_INFO << e.what();
|
qDebug() << Q_FUNC_INFO << e.what();
|
||||||
}
|
}
|
||||||
|
if (triggersLocalPosition) {
|
||||||
|
// send own position to every account with an opened map
|
||||||
|
QMutexLocker lk(&mapStatusMutex_);
|
||||||
|
for (auto it = mapStatus_.begin(); it != mapStatus_.end(); it++) {
|
||||||
|
Q_EMIT localPositionReceived(it.key(),
|
||||||
|
lrcInstance_->getAccountInfo(it.key()).profileInfo.uri,
|
||||||
|
body);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -149,26 +180,17 @@ PositionManager::onWatchdogTimeout()
|
||||||
if (it != objectListSharingUris_.cend()) {
|
if (it != objectListSharingUris_.cend()) {
|
||||||
QString stopMsg("{\"type\":\"Stop\"}");
|
QString stopMsg("{\"type\":\"Stop\"}");
|
||||||
onPositionReceived(it.key().first, it.key().second, stopMsg, -1, "");
|
onPositionReceived(it.key().first, it.key().second, stopMsg, -1, "");
|
||||||
|
makeVisibleSharingButton(it.key().first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::sharePosition(int maximumTime)
|
PositionManager::sharePosition(int maximumTime, QString accountId, QString convId)
|
||||||
{
|
{
|
||||||
connect(
|
|
||||||
localPositioning_.get(),
|
|
||||||
&Positioning::newPosition,
|
|
||||||
this,
|
|
||||||
[&](const QString&, const QString&, const QString& body, const uint64_t&, const QString&) {
|
|
||||||
sendPosition(body);
|
|
||||||
},
|
|
||||||
Qt::UniqueConnection);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startPositionTimers(maximumTime);
|
if (settingsManager_->getValue(Settings::Key::PositionShareLimit) == true)
|
||||||
const auto convUid = lrcInstance_->get_selectedConvUid();
|
startPositionTimers(maximumTime);
|
||||||
positionShareConvIds_.append(
|
positionShareConvIds_.append(PositionKey {accountId, convId});
|
||||||
QPair<QString, QString> {lrcInstance_->get_currentAccountId(), convUid});
|
|
||||||
set_positionShareConvIdsCount(positionShareConvIds_.size());
|
set_positionShareConvIdsCount(positionShareConvIds_.size());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
qDebug() << "Exception during sharePosition:";
|
qDebug() << "Exception during sharePosition:";
|
||||||
|
@ -176,17 +198,46 @@ PositionManager::sharePosition(int maximumTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::stopSharingPosition(const QString convId)
|
PositionManager::stopSharingPosition(QString accountId, const QString convId)
|
||||||
{
|
{
|
||||||
QString stopMsg;
|
QString stopMsg;
|
||||||
stopMsg = "{\"type\":\"Stop\"}";
|
stopMsg = "{\"type\":\"Stop\"}";
|
||||||
if (convId == "") {
|
if (accountId == "") {
|
||||||
sendPosition(stopMsg);
|
sendPosition(stopMsg, false);
|
||||||
stopPositionTimers();
|
stopPositionTimers();
|
||||||
positionShareConvIds_.clear();
|
positionShareConvIds_.clear();
|
||||||
set_positionShareConvIdsCount(positionShareConvIds_.size());
|
|
||||||
} else {
|
} else {
|
||||||
const auto& convInfo = lrcInstance_->getConversationFromConvUid(convId);
|
if (convId == "") {
|
||||||
|
stopPositionTimers(accountId);
|
||||||
|
for (auto it = positionShareConvIds_.begin(); it != positionShareConvIds_.end();) {
|
||||||
|
if (it->first == accountId) {
|
||||||
|
sendStopMessage(accountId, it->second);
|
||||||
|
it = positionShareConvIds_.erase(it);
|
||||||
|
} else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendStopMessage(accountId, convId);
|
||||||
|
auto iter = std::find(positionShareConvIds_.begin(),
|
||||||
|
positionShareConvIds_.end(),
|
||||||
|
PositionKey {accountId, convId});
|
||||||
|
if (iter != positionShareConvIds_.end()) {
|
||||||
|
positionShareConvIds_.remove(std::distance(positionShareConvIds_.begin(), iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!positionShareConvIds_.size())
|
||||||
|
countdownTimer_->stop();
|
||||||
|
set_positionShareConvIdsCount(positionShareConvIds_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::sendStopMessage(QString accountId, const QString convId)
|
||||||
|
{
|
||||||
|
QString stopMsg;
|
||||||
|
stopMsg = "{\"type\":\"Stop\"}";
|
||||||
|
if (accountId != "" && convId != "") {
|
||||||
|
const auto& convInfo = lrcInstance_->getConversationFromConvUid(convId, accountId);
|
||||||
Q_FOREACH (const QString& uri, convInfo.participantsUris()) {
|
Q_FOREACH (const QString& uri, convInfo.participantsUris()) {
|
||||||
if (lrcInstance_->getCurrentAccountInfo().profileInfo.uri != uri) {
|
if (lrcInstance_->getCurrentAccountInfo().profileInfo.uri != uri) {
|
||||||
lrcInstance_->getCurrentAccountInfo().contactModel->sendDhtMessage(uri,
|
lrcInstance_->getCurrentAccountInfo().contactModel->sendDhtMessage(uri,
|
||||||
|
@ -194,22 +245,68 @@ PositionManager::stopSharingPosition(const QString convId)
|
||||||
APPLICATION_GEO);
|
APPLICATION_GEO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto iter = std::find(positionShareConvIds_.begin(),
|
|
||||||
positionShareConvIds_.end(),
|
|
||||||
QPair<QString, QString> {lrcInstance_->get_currentAccountId(),
|
|
||||||
convId});
|
|
||||||
if (iter != positionShareConvIds_.end()) {
|
|
||||||
positionShareConvIds_.remove(std::distance(positionShareConvIds_.begin(), iter));
|
|
||||||
}
|
|
||||||
set_positionShareConvIdsCount(positionShareConvIds_.size());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::setMapActive(bool state)
|
PositionManager::unPinMap(QString key)
|
||||||
{
|
{
|
||||||
set_isMapActive(state);
|
QMutexLocker lk(&mapStatusMutex_);
|
||||||
Q_EMIT isMapActiveChanged();
|
if (mapStatus_.find(key) != mapStatus_.end()) {
|
||||||
|
mapStatus_[key] = true;
|
||||||
|
Q_EMIT mapStatusChanged();
|
||||||
|
Q_EMIT unPinMapSignal(key);
|
||||||
|
} else {
|
||||||
|
qWarning() << "Error: Can't unpin a map that doesn't exist";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::pinMap(QString key)
|
||||||
|
{
|
||||||
|
QMutexLocker lk(&mapStatusMutex_);
|
||||||
|
if (mapStatus_.find(key) != mapStatus_.end()) {
|
||||||
|
// map can be pined only if it's in the right account
|
||||||
|
if (key == lrcInstance_->get_currentAccountId()) {
|
||||||
|
mapStatus_[key] = false;
|
||||||
|
lk.unlock();
|
||||||
|
Q_EMIT mapStatusChanged();
|
||||||
|
Q_EMIT pinMapSignal(key);
|
||||||
|
} else {
|
||||||
|
lk.unlock();
|
||||||
|
setMapInactive(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::setMapInactive(const QString key)
|
||||||
|
{
|
||||||
|
QMutexLocker lk(&mapStatusMutex_);
|
||||||
|
if (mapStatus_.find(key) != mapStatus_.end()) {
|
||||||
|
mapStatus_.remove(key);
|
||||||
|
Q_EMIT mapStatusChanged();
|
||||||
|
Q_EMIT closeMap(key);
|
||||||
|
if (!mapStatus_.size()) {
|
||||||
|
stopPositioning();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning() << "Error: Can't set inactive a map that doesn't exists";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::setMapActive(QString key)
|
||||||
|
{
|
||||||
|
if (mapStatus_.find(key) == mapStatus_.end()) {
|
||||||
|
mapStatus_.insert(key, false);
|
||||||
|
Q_EMIT mapStatusChanged();
|
||||||
|
// creation on QML
|
||||||
|
Q_EMIT openNewMap();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pinMap(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
|
@ -233,7 +330,9 @@ PositionManager::getAvatar(const QString& accountId, const QString& uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap
|
QVariantMap
|
||||||
PositionManager::parseJsonPosition(const QString& body, const QString& peerId)
|
PositionManager::parseJsonPosition(const QString& accountId,
|
||||||
|
const QString& peerId,
|
||||||
|
const QString& body)
|
||||||
{
|
{
|
||||||
QJsonDocument temp = QJsonDocument::fromJson(body.toUtf8());
|
QJsonDocument temp = QJsonDocument::fromJson(body.toUtf8());
|
||||||
QJsonObject jsonObject = temp.object();
|
QJsonObject jsonObject = temp.object();
|
||||||
|
@ -250,6 +349,7 @@ PositionManager::parseJsonPosition(const QString& body, const QString& peerId)
|
||||||
pos["time"] = i.value().toVariant();
|
pos["time"] = i.value().toVariant();
|
||||||
|
|
||||||
pos["author"] = peerId;
|
pos["author"] = peerId;
|
||||||
|
pos["account"] = accountId;
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -257,17 +357,25 @@ PositionManager::parseJsonPosition(const QString& body, const QString& peerId)
|
||||||
void
|
void
|
||||||
PositionManager::startPositionTimers(int timeSharing)
|
PositionManager::startPositionTimers(int timeSharing)
|
||||||
{
|
{
|
||||||
set_timeSharingRemaining(timeSharing);
|
mapTimerCountDown_[lrcInstance_->get_currentAccountId()] = timeSharing;
|
||||||
timerTimeLeftSharing_->start(1000);
|
countdownUpdate();
|
||||||
timerStopSharing_->start(timeSharing);
|
countdownTimer_->start(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::stopPositionTimers()
|
PositionManager::stopPositionTimers(QString accountId)
|
||||||
{
|
{
|
||||||
set_timeSharingRemaining(0);
|
// reset all timers
|
||||||
timerTimeLeftSharing_->stop();
|
if (accountId == nullptr) {
|
||||||
timerStopSharing_->stop();
|
mapTimerCountDown_.clear();
|
||||||
|
} else {
|
||||||
|
auto it = mapTimerCountDown_.find(accountId);
|
||||||
|
if (it != mapTimerCountDown_.end()) {
|
||||||
|
mapTimerCountDown_.erase(it);
|
||||||
|
}
|
||||||
|
if (!mapTimerCountDown_.size())
|
||||||
|
countdownTimer_->stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -304,6 +412,151 @@ PositionManager::showNotification(const QString& accountId,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::onNewConversation()
|
||||||
|
{
|
||||||
|
set_mapAutoOpening(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::onNewAccount()
|
||||||
|
{
|
||||||
|
QMutexLocker lk(&mapStatusMutex_);
|
||||||
|
for (auto it = mapStatus_.begin(); it != mapStatus_.end();) {
|
||||||
|
if (it.value() == false) {
|
||||||
|
Q_EMIT closeMap(it.key());
|
||||||
|
it = mapStatus_.erase(it);
|
||||||
|
Q_EMIT mapStatusChanged();
|
||||||
|
} else {
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PositionManager::isNewMessageTriggersMap(bool endSharing,
|
||||||
|
const QString& uri,
|
||||||
|
const QString& accountId)
|
||||||
|
{
|
||||||
|
QMutexLocker lk(&mapStatusMutex_);
|
||||||
|
return !endSharing && (accountId == lrcInstance_->get_currentAccountId()) && mapAutoOpening_
|
||||||
|
&& (uri != lrcInstance_->getCurrentAccountInfo().profileInfo.uri)
|
||||||
|
&& (mapStatus_.find(accountId) == mapStatus_.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::countdownUpdate()
|
||||||
|
{
|
||||||
|
// First removal of timers and shared position
|
||||||
|
auto end = std::find_if(mapTimerCountDown_.begin(),
|
||||||
|
mapTimerCountDown_.end(),
|
||||||
|
[](const auto& end) { return end == 0; });
|
||||||
|
if (end != mapTimerCountDown_.end()) {
|
||||||
|
Q_EMIT sendCountdownUpdate(end.key(), end.value());
|
||||||
|
stopSharingPosition(end.key());
|
||||||
|
}
|
||||||
|
// When removals are done, countdown can be updated
|
||||||
|
for (auto it = mapTimerCountDown_.begin(); it != mapTimerCountDown_.end(); it++) {
|
||||||
|
if (it.value() != 0) {
|
||||||
|
Q_EMIT sendCountdownUpdate(it.key(), it.value());
|
||||||
|
it.value() -= 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::addPositionToMap(PositionKey key, QVariantMap position)
|
||||||
|
{
|
||||||
|
// avatar only sent one time to qml, when a new position is added
|
||||||
|
position["avatar"] = getAvatar(key.first, key.second);
|
||||||
|
Q_EMIT positionShareAdded(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::addPositionToMemory(PositionKey key, QVariantMap positionReceived)
|
||||||
|
{
|
||||||
|
// add the position to the list
|
||||||
|
auto obj = new PositionObject(positionReceived["lat"], positionReceived["long"], this);
|
||||||
|
objectListSharingUris_.insert(key, obj);
|
||||||
|
|
||||||
|
// information for qml
|
||||||
|
set_sharingUrisCount(objectListSharingUris_.size());
|
||||||
|
|
||||||
|
// watchdog
|
||||||
|
connect(obj,
|
||||||
|
&PositionObject::timeout,
|
||||||
|
this,
|
||||||
|
&PositionManager::onWatchdogTimeout,
|
||||||
|
Qt::DirectConnection);
|
||||||
|
|
||||||
|
auto& accountId = key.first;
|
||||||
|
auto& uri = key.second;
|
||||||
|
// Add position to the current map if needed)
|
||||||
|
addPositionToMap(key, positionReceived);
|
||||||
|
|
||||||
|
// show notification
|
||||||
|
if (accountId != "") {
|
||||||
|
QMutexLocker lk(&mapStatusMutex_);
|
||||||
|
if (mapStatus_.find(accountId) == mapStatus_.end()) {
|
||||||
|
auto& convInfo = lrcInstance_->getConversationFromPeerUri(uri, accountId);
|
||||||
|
if (!convInfo.uid.isEmpty()) {
|
||||||
|
showNotification(accountId, convInfo.uid, uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::updatePositionInMemory(PositionKey key, QVariantMap positionReceived)
|
||||||
|
{
|
||||||
|
auto it = objectListSharingUris_.find(key);
|
||||||
|
if (it != objectListSharingUris_.end()) {
|
||||||
|
if (it.value()) {
|
||||||
|
// reset watchdog
|
||||||
|
it.value()->resetWatchdog();
|
||||||
|
// update position
|
||||||
|
it.value()->updatePosition(positionReceived["lat"], positionReceived["long"]);
|
||||||
|
} else {
|
||||||
|
qWarning() << "error in PositionManager::updatePositionInMemory(), it.value() is null";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning()
|
||||||
|
<< "Error: A position intented to be updated while not in objectListSharingUris_ ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// update position on the map (if needed)
|
||||||
|
Q_EMIT positionShareUpdated(positionReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionManager::removePositionFromMemory(PositionKey key, QVariantMap positionReceived)
|
||||||
|
{
|
||||||
|
// Remove
|
||||||
|
auto it = objectListSharingUris_.find(key);
|
||||||
|
if (it != objectListSharingUris_.end()) {
|
||||||
|
// free memory
|
||||||
|
it.value()->deleteLater();
|
||||||
|
// delete value
|
||||||
|
objectListSharingUris_.erase(it);
|
||||||
|
// update list count for qml
|
||||||
|
set_sharingUrisCount(objectListSharingUris_.size());
|
||||||
|
} else {
|
||||||
|
qWarning()
|
||||||
|
<< "Error: A position intented to be removed while not in objectListSharingUris_ ";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if needed, remove from map
|
||||||
|
Q_EMIT positionShareRemoved(key.second, positionReceived["account"].toString());
|
||||||
|
// close the map if you're not sharing and you don't receive position anymore
|
||||||
|
if (!positionShareConvIds_.length()
|
||||||
|
&& ((sharingUrisCount_ == 1
|
||||||
|
&& objectListSharingUris_.begin().key().second
|
||||||
|
== lrcInstance_->getCurrentAccountInfo().profileInfo.uri)
|
||||||
|
|| sharingUrisCount_ == 0)) {
|
||||||
|
setMapInactive(lrcInstance_->get_currentAccountId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PositionManager::onPositionReceived(const QString& accountId,
|
PositionManager::onPositionReceived(const QString& accountId,
|
||||||
const QString& peerId,
|
const QString& peerId,
|
||||||
|
@ -311,106 +564,34 @@ PositionManager::onPositionReceived(const QString& accountId,
|
||||||
const uint64_t& timestamp,
|
const uint64_t& timestamp,
|
||||||
const QString& daemonId)
|
const QString& daemonId)
|
||||||
{
|
{
|
||||||
// only show shared positions from contacts in the current conversation
|
// handlers variables
|
||||||
const auto& convParticipants = lrcInstance_
|
|
||||||
->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());
|
|
||||||
|
|
||||||
QVariantMap newPosition = parseJsonPosition(body, peerId);
|
// parse the position from json
|
||||||
auto getShareInfo = [&](bool update) -> QVariantMap {
|
QVariantMap positionReceived = parseJsonPosition(accountId, peerId, body);
|
||||||
QVariantMap shareInfo;
|
|
||||||
shareInfo["author"] = peerId;
|
|
||||||
if (!update) {
|
|
||||||
shareInfo["avatar"] = getAvatar(accountId, peerId);
|
|
||||||
}
|
|
||||||
shareInfo["long"] = newPosition["long"];
|
|
||||||
shareInfo["lat"] = newPosition["lat"];
|
|
||||||
return shareInfo;
|
|
||||||
};
|
|
||||||
auto endSharing = newPosition["type"] == "Stop";
|
|
||||||
|
|
||||||
auto key = QPair<QString, QString> {accountId, peerId};
|
// is it a message that notify an end of position sharing
|
||||||
|
auto endSharing = positionReceived["type"] == "Stop";
|
||||||
|
|
||||||
if (!endSharing) {
|
// key to identify the peer
|
||||||
// open map on position reception
|
auto key = PositionKey {accountId, peerId};
|
||||||
if (!isMapActive_ && mapAutoOpening_ && isPeerIdInConv
|
|
||||||
&& peerId != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
|
// check if the position exists in all shared positions, even if not visible to the screen
|
||||||
set_isMapActive(true);
|
auto findPeerIdinAllPeers = objectListSharingUris_.find(key);
|
||||||
}
|
|
||||||
|
// open the map on position reception if needed
|
||||||
|
if (isNewMessageTriggersMap(endSharing, peerId, accountId)) {
|
||||||
|
setMapActive(accountId);
|
||||||
}
|
}
|
||||||
auto iter = std::find(currentConvSharingUris_.begin(), currentConvSharingUris_.end(), key);
|
|
||||||
if (iter == currentConvSharingUris_.end()) {
|
|
||||||
// New share
|
|
||||||
if (!endSharing) {
|
|
||||||
// list to save more information on position + watchdog
|
|
||||||
auto it = objectListSharingUris_.find(key);
|
|
||||||
auto isNewSharing = it == objectListSharingUris_.end();
|
|
||||||
if (isNewSharing) {
|
|
||||||
auto obj = new PositionObject(newPosition["lat"], newPosition["long"], this);
|
|
||||||
|
|
||||||
objectListSharingUris_.insert(key, obj);
|
// if the position already exists
|
||||||
set_sharingUrisCount(objectListSharingUris_.size());
|
if (findPeerIdinAllPeers != objectListSharingUris_.end()) {
|
||||||
connect(obj,
|
if (endSharing)
|
||||||
&PositionObject::timeout,
|
removePositionFromMemory(key, positionReceived);
|
||||||
this,
|
else
|
||||||
&PositionManager::onWatchdogTimeout,
|
updatePositionInMemory(key, positionReceived);
|
||||||
Qt::DirectConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPeerIdInConv) {
|
|
||||||
currentConvSharingUris_.insert(key);
|
|
||||||
Q_EMIT positionShareAdded(getShareInfo(false));
|
|
||||||
} else if (isNewSharing && accountId != "") {
|
|
||||||
auto& convInfo = lrcInstance_->getConversationFromPeerUri(peerId, accountId);
|
|
||||||
if (!convInfo.uid.isEmpty()) {
|
|
||||||
showNotification(accountId, convInfo.uid, peerId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// stop sharing position
|
|
||||||
} else {
|
|
||||||
auto it = objectListSharingUris_.find(key);
|
|
||||||
if (it != objectListSharingUris_.end()) {
|
|
||||||
it.value()->deleteLater();
|
|
||||||
objectListSharingUris_.erase(it);
|
|
||||||
set_sharingUrisCount(objectListSharingUris_.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Update/remove existing
|
// It is the first time a position is received from this peer
|
||||||
if (endSharing) {
|
addPositionToMemory(key, positionReceived);
|
||||||
// Remove
|
|
||||||
auto it = objectListSharingUris_.find(key);
|
|
||||||
if (it != objectListSharingUris_.end()) {
|
|
||||||
it.value()->deleteLater();
|
|
||||||
objectListSharingUris_.erase(it);
|
|
||||||
set_sharingUrisCount(objectListSharingUris_.size());
|
|
||||||
}
|
|
||||||
if (isPeerIdInConv) {
|
|
||||||
currentConvSharingUris_.remove(key);
|
|
||||||
Q_EMIT positionShareRemoved(peerId);
|
|
||||||
// close the map if you're not sharing and you don't receive position anymore
|
|
||||||
if (!positionShareConvIds_.length()
|
|
||||||
&& ((sharingUrisCount_ == 1
|
|
||||||
&& objectListSharingUris_.contains(QPair<QString, QString> {
|
|
||||||
"", lrcInstance_->getCurrentAccountInfo().profileInfo.uri}))
|
|
||||||
|| sharingUrisCount_ == 0)) {
|
|
||||||
set_isMapActive(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Update
|
|
||||||
if (isPeerIdInConv)
|
|
||||||
Q_EMIT positionShareUpdated(getShareInfo(true));
|
|
||||||
// reset watchdog
|
|
||||||
|
|
||||||
auto it = objectListSharingUris_.find(key);
|
|
||||||
if (it != objectListSharingUris_.end()) {
|
|
||||||
it.value()->resetWatchdog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,19 +24,21 @@
|
||||||
#include "positionobject.h"
|
#include "positionobject.h"
|
||||||
#include "systemtray.h"
|
#include "systemtray.h"
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
class PositionManager : public QmlAdapterBase
|
class PositionManager : public QmlAdapterBase
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_RO_PROPERTY(bool, isMapActive)
|
// map of elements : map key and isUnpin
|
||||||
QML_RO_PROPERTY(int, timeSharingRemaining)
|
QML_PROPERTY(QVariantMap, mapStatus)
|
||||||
|
QML_PROPERTY(bool, mapAutoOpening)
|
||||||
QML_PROPERTY(int, positionShareConvIdsCount)
|
QML_PROPERTY(int, positionShareConvIdsCount)
|
||||||
QML_PROPERTY(int, sharingUrisCount)
|
QML_PROPERTY(int, sharingUrisCount)
|
||||||
QML_PROPERTY(bool, mapAutoOpening)
|
|
||||||
public:
|
public:
|
||||||
explicit PositionManager(SystemTray* systemTray,
|
explicit PositionManager(AppSettingsManager* settingsManager,
|
||||||
|
SystemTray* systemTray,
|
||||||
LRCInstance* instance,
|
LRCInstance* instance,
|
||||||
QObject* parent = nullptr);
|
QObject* parent = nullptr);
|
||||||
~PositionManager() = default;
|
~PositionManager() = default;
|
||||||
|
@ -45,30 +47,49 @@ Q_SIGNALS:
|
||||||
void positioningError(const QString error);
|
void positioningError(const QString error);
|
||||||
void positionShareAdded(const QVariantMap& shareInfo);
|
void positionShareAdded(const QVariantMap& shareInfo);
|
||||||
void positionShareUpdated(const QVariantMap& posInfo);
|
void positionShareUpdated(const QVariantMap& posInfo);
|
||||||
void positionShareRemoved(const QString& uri);
|
void positionShareRemoved(const QString& uri, const QString& accountId);
|
||||||
|
void openNewMap();
|
||||||
|
void closeMap(const QString& key);
|
||||||
|
void pinMapSignal(const QString& key);
|
||||||
|
void unPinMapSignal(const QString& key);
|
||||||
|
void localPositionReceived(const QString& accountId, const QString& peerId, const QString& body);
|
||||||
|
void makeVisibleSharingButton(const QString& accountId);
|
||||||
|
void sendCountdownUpdate(const QString& accountId, const int remainingTime);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void safeInit() override;
|
void safeInit() override;
|
||||||
|
|
||||||
QString getAvatar(const QString& accountId, const QString& peerId);
|
QString getAvatar(const QString& accountId, const QString& peerId);
|
||||||
QVariantMap parseJsonPosition(const QString& body, const QString& peerId);
|
QVariantMap parseJsonPosition(const QString& accountId,
|
||||||
|
const QString& peerId,
|
||||||
|
const QString& body);
|
||||||
|
void addPositionToMap(PositionKey key, QVariantMap position);
|
||||||
|
void addPositionToMemory(PositionKey key, QVariantMap positionReceived);
|
||||||
|
void updatePositionInMemory(PositionKey key, QVariantMap positionReceived);
|
||||||
|
void removePositionFromMemory(PositionKey key, QVariantMap positionReceived);
|
||||||
void positionWatchDog();
|
void positionWatchDog();
|
||||||
void startPositionTimers(int timeSharing);
|
void startPositionTimers(int timeSharing);
|
||||||
void stopPositionTimers();
|
void stopPositionTimers(QString accountId = {});
|
||||||
|
bool isNewMessageTriggersMap(bool endSharing, const QString& uri, const QString& accountId);
|
||||||
|
void countdownUpdate();
|
||||||
|
void sendStopMessage(QString accountId = "", const QString convId = "");
|
||||||
|
|
||||||
Q_INVOKABLE void connectAccountModel();
|
Q_INVOKABLE void connectAccountModel();
|
||||||
Q_INVOKABLE void setMapActive(bool state);
|
Q_INVOKABLE void pinMap(QString key);
|
||||||
Q_INVOKABLE void sharePosition(int maximumTime);
|
Q_INVOKABLE void unPinMap(QString key);
|
||||||
Q_INVOKABLE void stopSharingPosition(const QString convId = "");
|
Q_INVOKABLE void setMapActive(QString key);
|
||||||
|
Q_INVOKABLE void setMapInactive(const QString key);
|
||||||
|
Q_INVOKABLE void sharePosition(int maximumTime, QString accountId, QString convId);
|
||||||
|
Q_INVOKABLE void stopSharingPosition(QString accountId = "", const QString convId = "");
|
||||||
|
|
||||||
Q_INVOKABLE void startPositioning();
|
Q_INVOKABLE void startPositioning();
|
||||||
Q_INVOKABLE void stopPositioning();
|
Q_INVOKABLE void stopPositioning();
|
||||||
|
|
||||||
Q_INVOKABLE QString getSelectedConvId();
|
Q_INVOKABLE bool isPositionSharedToConv(const QString& accountId, const QString& convUid);
|
||||||
Q_INVOKABLE bool isPositionSharedToConv(const QString& convUri);
|
Q_INVOKABLE bool isConvSharingPosition(const QString& accountId, const QString& convUri);
|
||||||
Q_INVOKABLE bool isConvSharingPosition(const QString& convUri);
|
|
||||||
|
|
||||||
Q_INVOKABLE void loadPreviousLocations();
|
Q_INVOKABLE void loadPreviousLocations(QString& accountId);
|
||||||
|
Q_INVOKABLE QString getmapTitle(QString& accountId, QString convId = "");
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onPositionErrorReceived(const QString error);
|
void onPositionErrorReceived(const QString error);
|
||||||
|
@ -77,16 +98,21 @@ private Q_SLOTS:
|
||||||
const QString& body,
|
const QString& body,
|
||||||
const uint64_t& timestamp,
|
const uint64_t& timestamp,
|
||||||
const QString& daemonId);
|
const QString& daemonId);
|
||||||
void sendPosition(const QString& body);
|
void sendPosition(const QString& body, bool triggersLocalPosition = true);
|
||||||
void onWatchdogTimeout();
|
void onWatchdogTimeout();
|
||||||
void showNotification(const QString& accountId, const QString& convId, const QString& from);
|
void showNotification(const QString& accountId, const QString& convId, const QString& from);
|
||||||
|
void onNewConversation();
|
||||||
|
void onNewAccount();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SystemTray* systemTray_;
|
SystemTray* systemTray_;
|
||||||
std::unique_ptr<Positioning> localPositioning_;
|
std::unique_ptr<Positioning> localPositioning_;
|
||||||
QTimer* timerTimeLeftSharing_ = nullptr;
|
QMap<QString, int> mapTimerCountDown_;
|
||||||
QTimer* timerStopSharing_ = nullptr;
|
QTimer* countdownTimer_ = nullptr;
|
||||||
QSet<QPair<QString, QString>> currentConvSharingUris_;
|
// map of all shared position by peers
|
||||||
QMap<QPair<QString, QString>, PositionObject*> objectListSharingUris_;
|
QMap<PositionKey, PositionObject*> objectListSharingUris_;
|
||||||
QList<QPair<QString, QString>> positionShareConvIds_;
|
// list of all the peers the user is sharing position to
|
||||||
|
QList<PositionKey> positionShareConvIds_;
|
||||||
|
QMutex mapStatusMutex_;
|
||||||
|
AppSettingsManager* settingsManager_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
PositionObject::PositionObject(QVariant latitude, QVariant longitude, QObject* parent)
|
PositionObject::PositionObject(QVariant latitude, QVariant longitude, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, resetTime(20000)
|
, resetTime(40000)
|
||||||
, longitude_(longitude)
|
, longitude_(longitude)
|
||||||
, latitude_(latitude)
|
, latitude_(latitude)
|
||||||
|
|
||||||
|
@ -28,3 +28,10 @@ PositionObject::getLatitude()
|
||||||
{
|
{
|
||||||
return latitude_;
|
return latitude_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionObject::updatePosition(QVariant latitude, QVariant longitude)
|
||||||
|
{
|
||||||
|
longitude_ = longitude;
|
||||||
|
latitude_ = latitude;
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ public:
|
||||||
QVariant getLongitude();
|
QVariant getLongitude();
|
||||||
QVariant getLatitude();
|
QVariant getLatitude();
|
||||||
|
|
||||||
|
void updatePosition(QVariant latitude, QVariant longitude);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVariant latitude_;
|
QVariant latitude_;
|
||||||
QVariant longitude_;
|
QVariant longitude_;
|
||||||
|
|
|
@ -112,7 +112,7 @@ registerTypes(QQmlEngine* engine,
|
||||||
// setup the adapters (their lifetimes are that of MainApplication)
|
// setup the adapters (their lifetimes are that of MainApplication)
|
||||||
auto callAdapter = new CallAdapter(systemTray, lrcInstance, parent);
|
auto callAdapter = new CallAdapter(systemTray, lrcInstance, parent);
|
||||||
auto messagesAdapter = new MessagesAdapter(settingsManager, previewEngine, lrcInstance, parent);
|
auto messagesAdapter = new MessagesAdapter(settingsManager, previewEngine, lrcInstance, parent);
|
||||||
auto positionManager = new PositionManager(systemTray, lrcInstance, parent);
|
auto positionManager = new PositionManager(settingsManager, systemTray, lrcInstance, parent);
|
||||||
auto conversationsAdapter = new ConversationsAdapter(systemTray, lrcInstance, parent);
|
auto conversationsAdapter = new ConversationsAdapter(systemTray, lrcInstance, parent);
|
||||||
auto avAdapter = new AvAdapter(lrcInstance, parent);
|
auto avAdapter = new AvAdapter(lrcInstance, parent);
|
||||||
auto contactAdapter = new ContactAdapter(lrcInstance, parent);
|
auto contactAdapter = new ContactAdapter(lrcInstance, parent);
|
||||||
|
|
|
@ -63,6 +63,16 @@ Rectangle {
|
||||||
itemWidth: preferredColumnWidth
|
itemWidth: preferredColumnWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// location sharing setting panel
|
||||||
|
LocationSharingSettings {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||||
|
Layout.leftMargin: JamiTheme.preferredMarginSize
|
||||||
|
Layout.rightMargin: JamiTheme.preferredMarginSize
|
||||||
|
|
||||||
|
itemWidth: preferredColumnWidth
|
||||||
|
}
|
||||||
|
|
||||||
// file transfer setting panel
|
// file transfer setting panel
|
||||||
FileTransferSettings {
|
FileTransferSettings {
|
||||||
id: fileTransferSettings
|
id: fileTransferSettings
|
||||||
|
|
150
src/app/settingsview/components/LocationSharingSettings.qml
Normal file
150
src/app/settingsview/components/LocationSharingSettings.qml
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import net.jami.Models 1.1
|
||||||
|
import net.jami.Adapters 1.1
|
||||||
|
import net.jami.Enums 1.1
|
||||||
|
import net.jami.Constants 1.1
|
||||||
|
|
||||||
|
import "../../commoncomponents"
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int itemWidth
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: JamiStrings.locationSharingLabel
|
||||||
|
font.pointSize: JamiTheme.headerFontSize
|
||||||
|
font.kerning: true
|
||||||
|
color: JamiTheme.textColor
|
||||||
|
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleSwitch {
|
||||||
|
id: isTimeLimit
|
||||||
|
|
||||||
|
visible: WITH_WEBENGINE
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: JamiTheme.preferredMarginSize
|
||||||
|
|
||||||
|
checked: UtilsAdapter.getAppValue(Settings.PositionShareLimit)
|
||||||
|
|
||||||
|
labelText: JamiStrings.positionShareLimit
|
||||||
|
fontPointSize: JamiTheme.settingsFontSize
|
||||||
|
|
||||||
|
tooltipText: JamiStrings.positionShareLimit
|
||||||
|
|
||||||
|
onSwitchToggled: {
|
||||||
|
positionSharingLimitation = !UtilsAdapter.getAppValue(Settings.PositionShareLimit)
|
||||||
|
UtilsAdapter.setAppValue(Settings.PositionShareLimit,
|
||||||
|
positionSharingLimitation)
|
||||||
|
|
||||||
|
}
|
||||||
|
property bool positionSharingLimitation: UtilsAdapter.getAppValue(Settings.PositionShareLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: timeSharingLocation
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: JamiTheme.preferredFieldHeight
|
||||||
|
Layout.leftMargin: JamiTheme.preferredMarginSize
|
||||||
|
visible: isTimeLimit.positionSharingLimitation
|
||||||
|
|
||||||
|
function standartCountdown(minutes) {
|
||||||
|
var hour = Math.floor(minutes / 60)
|
||||||
|
var min = minutes % 60
|
||||||
|
if (hour) {
|
||||||
|
if (min)
|
||||||
|
return qsTr("%1h%2min").arg(hour).arg(min)
|
||||||
|
else
|
||||||
|
return qsTr("%1h").arg(hour)
|
||||||
|
}
|
||||||
|
return qsTr("%1min").arg(min)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: JamiTheme.preferredMarginSize / 2
|
||||||
|
|
||||||
|
color: JamiTheme.textColor
|
||||||
|
text: JamiStrings.positionShareDuration
|
||||||
|
font.pointSize: JamiTheme.settingsFontSize
|
||||||
|
font.kerning: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: timeSharingLocationValueLabel
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: JamiTheme.preferredMarginSize / 2
|
||||||
|
|
||||||
|
color: JamiTheme.textColor
|
||||||
|
text: timeSharingLocation.standartCountdown(UtilsAdapter.getAppValue(Settings.PositionShareDuration))
|
||||||
|
|
||||||
|
font.pointSize: JamiTheme.settingsFontSize
|
||||||
|
font.kerning: true
|
||||||
|
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: timeSharingSlider
|
||||||
|
|
||||||
|
Layout.maximumWidth: itemWidth
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
value: Math.log(UtilsAdapter.getAppValue(Settings.PositionShareDuration))
|
||||||
|
|
||||||
|
from: 0.5
|
||||||
|
to: Math.log(600)
|
||||||
|
stepSize: 0.05
|
||||||
|
|
||||||
|
onMoved: {
|
||||||
|
timeSharingLocationValueLabel.text = timeSharingLocation.standartCountdown(Math.floor(Math.exp(value)))
|
||||||
|
UtilsAdapter.setAppValue(Settings.PositionShareDuration, Math.floor(Math.exp(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialToolTip {
|
||||||
|
id: toolTip
|
||||||
|
|
||||||
|
text: JamiStrings.positionShareDuration
|
||||||
|
visible: parent.hovered
|
||||||
|
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
@ -23,373 +24,212 @@ import QtWebEngine
|
||||||
|
|
||||||
import net.jami.Models 1.1
|
import net.jami.Models 1.1
|
||||||
import net.jami.Adapters 1.1
|
import net.jami.Adapters 1.1
|
||||||
|
import net.jami.Enums 1.1
|
||||||
import net.jami.Constants 1.1
|
import net.jami.Constants 1.1
|
||||||
|
|
||||||
import "../../commoncomponents"
|
import "../../commoncomponents"
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
id: mapPopup
|
id: root
|
||||||
|
|
||||||
x: xPos
|
property bool isUnpin: false
|
||||||
y: yPos
|
property real maxWidth
|
||||||
width: isFullScreen ? root.width : windowSize
|
property real maxHeight
|
||||||
height: isMinimised
|
property string attachedAccountId
|
||||||
? buttonOverlay.height + buttonsChoseSharing.height + 30
|
property string currentAccountId: CurrentAccount.id
|
||||||
: isFullScreen ? root.height - yPos : windowSize
|
property string currentConvId: CurrentConversation.id
|
||||||
|
property bool isSharing: (PositionManager.positionShareConvIdsCount !== 0)
|
||||||
|
property bool isSharingToCurrentConversation
|
||||||
|
|
||||||
property bool isFullScreen: false
|
function closeMapPosition() {
|
||||||
property bool isMinimised: false
|
root.destroy()
|
||||||
property real windowSize: windowPreferedSize > JamiTheme.minimumMapWidth
|
}
|
||||||
? windowPreferedSize
|
|
||||||
: JamiTheme.minimumMapWidth
|
|
||||||
property real windowPreferedSize: root.width > root.height
|
|
||||||
? root.height / 3
|
|
||||||
: root.width / 3
|
|
||||||
property real xPos: 0
|
|
||||||
property real yPos: JamiTheme.chatViewHeaderPreferredHeight
|
|
||||||
|
|
||||||
WebEngineView {
|
Connections {
|
||||||
id: webView
|
target: PositionManager
|
||||||
|
|
||||||
width: parent.width
|
function onPinMapSignal(key) {
|
||||||
height: parent.height
|
if (key === attachedAccountId) {
|
||||||
|
isUnpin = false
|
||||||
property string mapHtml: ":/webengine/map/map.html"
|
mapObject.state = "pin"
|
||||||
property string olCss: ":/webengine/map/ol.css"
|
windowUnpin.close()
|
||||||
property string mapJs: "../../webengine/map/map.js"
|
|
||||||
property string olJs: "../../webengine/map/ol.js"
|
|
||||||
property bool isLoaded: false
|
|
||||||
property var positionList: PositionManager.positionList;
|
|
||||||
property var avatarPositionList: PositionManager.avatarPositionList;
|
|
||||||
property bool isSharing: (PositionManager.positionShareConvIdsCount !== 0 )
|
|
||||||
|
|
||||||
function loadScripts () {
|
|
||||||
var scriptMapJs = {
|
|
||||||
sourceUrl: Qt.resolvedUrl(mapJs),
|
|
||||||
injectionPoint: WebEngineScript.DocumentReady,
|
|
||||||
worldId: WebEngineScript.MainWorld
|
|
||||||
}
|
|
||||||
|
|
||||||
var scriptOlJs = {
|
|
||||||
sourceUrl: Qt.resolvedUrl(olJs),
|
|
||||||
injectionPoint: WebEngineScript.DocumentReady,
|
|
||||||
worldId: WebEngineScript.MainWorld
|
|
||||||
}
|
|
||||||
|
|
||||||
userScripts.collection = [ scriptOlJs, scriptMapJs ]
|
|
||||||
}
|
|
||||||
Connections {
|
|
||||||
target: PositionManager
|
|
||||||
|
|
||||||
function onPositionShareAdded(shareInfo) {
|
|
||||||
if(webView.isLoaded) {
|
|
||||||
var curLong = shareInfo.long
|
|
||||||
var curLat = shareInfo.lat
|
|
||||||
webView.runJavaScript("newPosition([" + curLong + "," + curLat + "], '" + shareInfo.author + "', '" + shareInfo.avatar + "' )" );
|
|
||||||
webView.runJavaScript("zoomTolayersExtent()" );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function onPositionShareUpdated(shareInfo) {
|
|
||||||
if(webView.isLoaded) {
|
|
||||||
var curLong = shareInfo.long
|
|
||||||
var curLat = shareInfo.lat
|
|
||||||
webView.runJavaScript("updatePosition([" + curLong + "," + curLat + "], '" + shareInfo.author + "' )" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onPositionShareRemoved(author) {
|
|
||||||
if(webView.isLoaded) {
|
|
||||||
webView.runJavaScript("removePosition( '" + author + "' )" );
|
|
||||||
webView.runJavaScript("zoomTolayersExtent()" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
function onCloseMap(key) {
|
||||||
loadHtml(UtilsAdapter.qStringFromFile(mapHtml), mapHtml)
|
if (key === attachedAccountId )
|
||||||
loadScripts()
|
closeMapPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoadingChanged: function (loadingInfo) {
|
function onUnPinMapSignal(key) {
|
||||||
if (loadingInfo.status === WebEngineView.LoadSucceededStatus) {
|
if (key === attachedAccountId ) {
|
||||||
runJavaScript(UtilsAdapter.getStyleSheet("olcss",UtilsAdapter.qStringFromFile(olCss)))
|
isUnpin = true
|
||||||
webView.isLoaded = true
|
mapObject.state = "unpin"
|
||||||
runJavaScript("setMapView([" + 0 + ","+ 0 + "], " + 1 + " );" );
|
windowUnpin.show()
|
||||||
PositionManager.startPositioning()
|
|
||||||
//load locations that were received before this conversation was opened
|
|
||||||
PositionManager.loadPreviousLocations();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
Window {
|
||||||
id: buttonsChoseSharing
|
id: windowUnpin
|
||||||
|
|
||||||
anchors.horizontalCenter: mapPopup.horizontalCenter
|
width: parentPin.width
|
||||||
anchors.margins: 10
|
height: parentPin.height
|
||||||
anchors.bottom: mapPopup.bottom
|
visible: false
|
||||||
|
title: PositionManager.getmapTitle(attachedAccountId)
|
||||||
|
|
||||||
property bool shortSharing: true
|
Item {
|
||||||
|
id: parentUnPin
|
||||||
|
|
||||||
RowLayout {
|
width: mapObject.width
|
||||||
Layout.alignment: Qt.AlignHCenter
|
height: mapObject.height
|
||||||
|
|
||||||
MaterialButton {
|
|
||||||
id: shortSharingButton
|
|
||||||
|
|
||||||
preferredWidth: text.contentWidth
|
|
||||||
visible: !webView.isSharing
|
|
||||||
textLeftPadding: JamiTheme.buttontextPadding
|
|
||||||
textRightPadding: JamiTheme.buttontextPadding
|
|
||||||
primary: true
|
|
||||||
text: JamiStrings.shortSharing
|
|
||||||
color: buttonsChoseSharing.shortSharing ? JamiTheme.buttonTintedBluePressed : JamiTheme.buttonTintedBlue
|
|
||||||
fontSize: JamiTheme.timerButtonsFontSize
|
|
||||||
onClicked: {
|
|
||||||
buttonsChoseSharing.shortSharing = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialButton {
|
|
||||||
id: longSharingButton
|
|
||||||
|
|
||||||
preferredWidth: text.contentWidth
|
|
||||||
visible: !webView.isSharing
|
|
||||||
textLeftPadding: JamiTheme.buttontextPadding
|
|
||||||
textRightPadding: JamiTheme.buttontextPadding
|
|
||||||
primary: true
|
|
||||||
text: JamiStrings.longSharing
|
|
||||||
color: !buttonsChoseSharing.shortSharing ? JamiTheme.buttonTintedBluePressed : JamiTheme.buttonTintedBlue
|
|
||||||
fontSize: JamiTheme.timerButtonsFontSize
|
|
||||||
onClicked: {
|
|
||||||
buttonsChoseSharing.shortSharing = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
|
|
||||||
radius: 10
|
|
||||||
width: textTimer.width + 15
|
|
||||||
height: textTimer.height + 15
|
|
||||||
color: JamiTheme.mapButtonsOverlayColor
|
|
||||||
visible: webView.isSharing && PositionManager.timeSharingRemaining
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: textTimer
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
color: JamiTheme.mapButtonColor
|
|
||||||
text: remainingTimeMs <= 1
|
|
||||||
? JamiStrings.minuteLeft.arg(remainingTimeMs)
|
|
||||||
: JamiStrings.minutesLeft.arg(remainingTimeMs)
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
|
|
||||||
property int remainingTimeMs: Math.ceil(PositionManager.timeSharingRemaining / 1000 / 60)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
onClosing: {
|
||||||
id: sharePositionLayout
|
if (isUnpin) {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
PositionManager.setMapInactive(attachedAccountId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MaterialButton {
|
Item {
|
||||||
id: sharePositionButton
|
id: parentPin
|
||||||
|
|
||||||
preferredWidth: text.contentWidth
|
width: mapObject.width
|
||||||
textLeftPadding: JamiTheme.buttontextPadding
|
height: mapObject.height
|
||||||
textRightPadding: JamiTheme.buttontextPadding
|
|
||||||
primary: true
|
Rectangle {
|
||||||
visible: ! PositionManager.isPositionSharedToConv(PositionManager.getSelectedConvId())
|
id: mapObject
|
||||||
text: JamiStrings.shareLocation
|
|
||||||
color: isError
|
x: xPos
|
||||||
? JamiTheme.buttonTintedGreyInactive
|
y: yPos
|
||||||
: JamiTheme.buttonTintedBlue
|
width: root.isUnpin
|
||||||
hoveredColor: isError
|
? windowUnpin.width
|
||||||
? JamiTheme.buttonTintedGreyInactive
|
: isFullScreen ? root.maxWidth : windowSize
|
||||||
: JamiTheme.buttonTintedBlueHovered
|
height: root.isUnpin
|
||||||
pressedColor: isError
|
? windowUnpin.height
|
||||||
? JamiTheme.buttonTintedGreyInactive
|
: isFullScreen ? root.maxHeight - yPos : windowSize
|
||||||
: JamiTheme.buttonTintedBluePressed
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
property bool isFullScreen: false
|
||||||
property bool isHovered: false
|
property real windowSize: windowPreferedSize > JamiTheme.minimumMapWidth
|
||||||
property string positioningError: "default"
|
? windowPreferedSize
|
||||||
property bool isError: positioningError.length
|
: JamiTheme.minimumMapWidth
|
||||||
function errorString(posError) {
|
property real windowPreferedSize: root.maxWidth > root.maxHeight
|
||||||
if (posError === "locationServicesError")
|
? root.maxHeight / 3
|
||||||
return JamiStrings.locationServicesError
|
: root.maxWidth / 3
|
||||||
return JamiStrings.locationServicesClosedError
|
property real xPos: 0
|
||||||
|
property real yPos: root.isUnpin ? 0 : JamiTheme.chatViewHeaderPreferredHeight
|
||||||
|
|
||||||
|
states: [ State {
|
||||||
|
name: "unpin"
|
||||||
|
ParentChange { target: mapObject; parent: parentUnPin; x:0; y:0 }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "pin"
|
||||||
|
ParentChange { target: mapObject; parent: parentPin; x:xPos; y:JamiTheme.chatViewHeaderPreferredHeight }
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
property alias webView: webView
|
||||||
|
|
||||||
onClicked: {
|
WebEngineView {
|
||||||
if (!isError) {
|
id: webView
|
||||||
if( buttonsChoseSharing.shortSharing)
|
|
||||||
PositionManager.sharePosition(10 * 60 * 1000);
|
layer.enabled: !isFullScreen
|
||||||
else
|
layer.effect: OpacityMask {
|
||||||
PositionManager.sharePosition(60 * 60 * 1000);
|
maskSource:
|
||||||
visible = false
|
Rectangle {
|
||||||
|
width: webView.width
|
||||||
|
height: webView.height
|
||||||
|
radius: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onHoveredChanged: {
|
width: parent.width
|
||||||
isHovered = !isHovered
|
height: parent.height
|
||||||
}
|
|
||||||
|
|
||||||
MaterialToolTip {
|
property string mapHtml: ":/webengine/map/map.html"
|
||||||
visible: sharePositionButton.isHovered
|
property string olCss: ":/webengine/map/ol.css"
|
||||||
&& sharePositionButton.isError && (sharePositionButton.positioningError !== "default")
|
property string mapJs: "../../webengine/map/map.js"
|
||||||
x: 0
|
property string olJs: "../../webengine/map/ol.js"
|
||||||
y: 0
|
property bool isLoaded: false
|
||||||
text: sharePositionButton.errorString(sharePositionButton.positioningError)
|
property var positionList: PositionManager.positionList;
|
||||||
|
property var avatarPositionList: PositionManager.avatarPositionList;
|
||||||
|
|
||||||
|
function loadScripts () {
|
||||||
|
var scriptMapJs = {
|
||||||
|
sourceUrl: Qt.resolvedUrl(mapJs),
|
||||||
|
injectionPoint: WebEngineScript.DocumentReady,
|
||||||
|
worldId: WebEngineScript.MainWorld
|
||||||
|
}
|
||||||
|
|
||||||
|
var scriptOlJs = {
|
||||||
|
sourceUrl: Qt.resolvedUrl(olJs),
|
||||||
|
injectionPoint: WebEngineScript.DocumentReady,
|
||||||
|
worldId: WebEngineScript.MainWorld
|
||||||
|
}
|
||||||
|
|
||||||
|
userScripts.collection = [ scriptOlJs, scriptMapJs ]
|
||||||
}
|
}
|
||||||
Connections {
|
Connections {
|
||||||
target: PositionManager
|
target: PositionManager
|
||||||
function onPositioningError (err) {
|
|
||||||
sharePositionButton.positioningError = err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MaterialButton {
|
|
||||||
id: stopSharingPositionButton
|
|
||||||
|
|
||||||
preferredWidth: text.contentWidth
|
function onPositionShareAdded(shareInfo) {
|
||||||
textLeftPadding: JamiTheme.buttontextPadding
|
if(webView.isLoaded) {
|
||||||
textRightPadding: JamiTheme.buttontextPadding
|
if (shareInfo.account === attachedAccountId) {
|
||||||
primary: true
|
var curLong = shareInfo.long
|
||||||
visible: webView.isSharing
|
var curLat = shareInfo.lat
|
||||||
text: JamiStrings.stopSharingLocation
|
webView.runJavaScript("newPosition([" + curLong + "," + curLat + "], '" + shareInfo.author + "', '" + shareInfo.avatar + "' )" );
|
||||||
color: isError
|
webView.runJavaScript("zoomTolayersExtent()" );
|
||||||
? JamiTheme.buttonTintedGreyInactive
|
}
|
||||||
: JamiTheme.buttonTintedRed
|
}
|
||||||
hoveredColor: isError
|
}
|
||||||
? JamiTheme.buttonTintedGreyInactive
|
|
||||||
: JamiTheme.buttonTintedRedHovered
|
function onPositionShareUpdated(shareInfo) {
|
||||||
pressedColor: isError
|
if(webView.isLoaded) {
|
||||||
? JamiTheme.buttonTintedGreyInactive
|
if (shareInfo.account === attachedAccountId) {
|
||||||
: JamiTheme.buttonTintedRedPressed
|
var curLong = shareInfo.long
|
||||||
Layout.alignment: Qt.AlignHCenter
|
var curLat = shareInfo.lat
|
||||||
property bool isHovered: false
|
webView.runJavaScript("updatePosition([" + curLong + "," + curLat + "], '" + shareInfo.author + "' )" );
|
||||||
property string positioningError
|
}
|
||||||
property bool isError: positioningError.length
|
}
|
||||||
onClicked: {
|
}
|
||||||
if (!isError) {
|
|
||||||
if (PositionManager.positionShareConvIdsCount >= 2) {
|
function onPositionShareRemoved(author, accountId) {
|
||||||
stopSharingPositionPopup.open()
|
if(webView.isLoaded) {
|
||||||
} else {
|
if (accountId === attachedAccountId) {
|
||||||
PositionManager.stopSharingPosition();
|
webView.runJavaScript("removePosition( '" + author + "' )" );
|
||||||
sharePositionButton.visible = true
|
webView.runJavaScript("zoomTolayersExtent()" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StopSharingPositionPopup {
|
Component.onCompleted: {
|
||||||
id: stopSharingPositionPopup
|
loadHtml(UtilsAdapter.qStringFromFile(mapHtml), mapHtml)
|
||||||
|
loadScripts()
|
||||||
property alias shareButtonVisibility: sharePositionButton.visible
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: buttonOverlay
|
|
||||||
|
|
||||||
anchors.right: webView.right
|
|
||||||
anchors.top: webView.top
|
|
||||||
anchors.margins: 10
|
|
||||||
radius: 10
|
|
||||||
width: lay.width + 10
|
|
||||||
height: lay.height + 10
|
|
||||||
color: JamiTheme.mapButtonsOverlayColor
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: lay
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
PushButton {
|
|
||||||
id: btnCenter
|
|
||||||
|
|
||||||
toolTipText: JamiStrings.centerMapTooltip
|
|
||||||
imageColor: JamiTheme.mapButtonColor
|
|
||||||
normalColor: JamiTheme.transparentColor
|
|
||||||
source: JamiResources.share_location_svg
|
|
||||||
onClicked: {
|
|
||||||
webView.runJavaScript("zoomTolayersExtent()" );
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PushButton {
|
onLoadingChanged: function (loadingInfo) {
|
||||||
id: btnMove
|
if (loadingInfo.status === WebEngineView.LoadSucceededStatus) {
|
||||||
|
attachedAccountId = CurrentAccount.id
|
||||||
toolTipText: JamiStrings.dragMapTooltip
|
runJavaScript(UtilsAdapter.getStyleSheet("olcss",UtilsAdapter.qStringFromFile(olCss)))
|
||||||
imageColor: JamiTheme.mapButtonColor
|
webView.isLoaded = true
|
||||||
normalColor: JamiTheme.transparentColor
|
runJavaScript("setMapView([" + 0 + ","+ 0 + "], " + 1 + " );" );
|
||||||
source: JamiResources.move_svg
|
PositionManager.startPositioning()
|
||||||
|
//load locations that were received before this conversation was opened
|
||||||
MouseArea {
|
PositionManager.loadPreviousLocations(attachedAccountId);
|
||||||
anchors.fill: parent
|
|
||||||
drag.target: mapPopup
|
|
||||||
drag.minimumX: 0
|
|
||||||
drag.maximumX: root.width - mapPopup.width
|
|
||||||
drag.minimumY: 0
|
|
||||||
drag.maximumY: root.height - mapPopup.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PushButton {
|
|
||||||
id: btnminimize
|
|
||||||
|
|
||||||
toolTipText: isMinimised
|
|
||||||
? JamiStrings.extendMapTooltip
|
|
||||||
: JamiStrings.minimizeMapTooltip
|
|
||||||
imageColor: JamiTheme.mapButtonColor
|
|
||||||
normalColor: JamiTheme.transparentColor
|
|
||||||
source: isMinimised
|
|
||||||
? JamiResources.close_fullscreen_24dp_svg
|
|
||||||
: JamiResources.minimize_svg
|
|
||||||
onClicked: {
|
|
||||||
isMinimised = !isMinimised
|
|
||||||
isFullScreen = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
onClicked: {
|
|
||||||
if (!isFullScreen && !isMinimised) {
|
|
||||||
mapPopup.x = mapPopup.xPos
|
|
||||||
mapPopup.y = mapPopup.yPos
|
|
||||||
}
|
}
|
||||||
isFullScreen = !isFullScreen
|
|
||||||
isMinimised = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PushButton {
|
MapPositionSharingControl {}
|
||||||
id: btnClose
|
|
||||||
|
|
||||||
toolTipText: JamiStrings.closeMapTooltip
|
MapPositionOverlay {}
|
||||||
imageColor: JamiTheme.mapButtonColor
|
|
||||||
normalColor: JamiTheme.transparentColor
|
|
||||||
source: JamiResources.round_close_24dp_svg
|
|
||||||
|
|
||||||
onClicked: {
|
StopSharingPositionPopup {
|
||||||
PositionManager.stopPositioning();
|
id: stopSharingPositionPopup
|
||||||
PositionManager.setMapActive(false);
|
|
||||||
PositionManager.mapAutoOpening = false;
|
|
||||||
|
|
||||||
}
|
property alias attachedAccountId: root.attachedAccountId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
125
src/app/webengine/map/MapPositionOverlay.qml
Normal file
125
src/app/webengine/map/MapPositionOverlay.qml
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* 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 net.jami.Constants 1.1
|
||||||
|
import net.jami.Adapters 1.1
|
||||||
|
|
||||||
|
import "../../commoncomponents"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
anchors.right: webView.right
|
||||||
|
anchors.top: webView.top
|
||||||
|
anchors.margins: 10
|
||||||
|
radius: 10
|
||||||
|
width: lay.width + 10
|
||||||
|
height: lay.height + 10
|
||||||
|
color: JamiTheme.mapButtonsOverlayColor
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: lay
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
PushButton {
|
||||||
|
id: btnUnpin
|
||||||
|
|
||||||
|
toolTipText: !isUnpin ? JamiStrings.unpin : JamiStrings.pinWindow
|
||||||
|
imageColor: JamiTheme.mapButtonColor
|
||||||
|
normalColor: JamiTheme.transparentColor
|
||||||
|
source: JamiResources.unpin_svg
|
||||||
|
onClicked: {
|
||||||
|
if (!isUnpin) {
|
||||||
|
PositionManager.unPinMap(attachedAccountId)
|
||||||
|
} else {
|
||||||
|
PositionManager.pinMap(attachedAccountId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton {
|
||||||
|
id: btnCenter
|
||||||
|
|
||||||
|
toolTipText: JamiStrings.centerMapTooltip
|
||||||
|
imageColor: JamiTheme.mapButtonColor
|
||||||
|
normalColor: JamiTheme.transparentColor
|
||||||
|
source: JamiResources.share_location_svg
|
||||||
|
onClicked: {
|
||||||
|
webView.runJavaScript("zoomTolayersExtent()" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton {
|
||||||
|
id: btnMove
|
||||||
|
|
||||||
|
toolTipText: JamiStrings.dragMapTooltip
|
||||||
|
imageColor: JamiTheme.mapButtonColor
|
||||||
|
normalColor: JamiTheme.transparentColor
|
||||||
|
source: JamiResources.move_svg
|
||||||
|
visible: !isUnpin
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
drag.target: mapObject
|
||||||
|
drag.minimumX: 0
|
||||||
|
drag.maximumX: maxWidth - mapObject.maxWidth
|
||||||
|
drag.minimumY: 0
|
||||||
|
drag.maximumY: maxHeight - mapObject.maxHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton {
|
||||||
|
id: btnMaximise
|
||||||
|
|
||||||
|
visible: !isUnpin
|
||||||
|
toolTipText: mapObject.isFullScreen
|
||||||
|
? JamiStrings.reduceMapTooltip
|
||||||
|
: JamiStrings.maximizeMapTooltip
|
||||||
|
imageColor: JamiTheme.mapButtonColor
|
||||||
|
normalColor: JamiTheme.transparentColor
|
||||||
|
source: mapObject.isFullScreen? JamiResources.close_fullscreen_24dp_svg : JamiResources.open_in_full_24dp_svg
|
||||||
|
onClicked: {
|
||||||
|
if (!mapObject.isFullScreen) {
|
||||||
|
mapObject.x = mapObject.xPos
|
||||||
|
mapObject.y = mapObject.yPos
|
||||||
|
}
|
||||||
|
|
||||||
|
mapObject.isFullScreen = !mapObject.isFullScreen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton {
|
||||||
|
id: btnClose
|
||||||
|
|
||||||
|
toolTipText: JamiStrings.closeMapTooltip
|
||||||
|
imageColor: JamiTheme.mapButtonColor
|
||||||
|
normalColor: JamiTheme.transparentColor
|
||||||
|
source: JamiResources.round_close_24dp_svg
|
||||||
|
visible: !isUnpin
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
PositionManager.setMapInactive(attachedAccountId)
|
||||||
|
PositionManager.mapAutoOpening = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
203
src/app/webengine/map/MapPositionSharingControl.qml
Normal file
203
src/app/webengine/map/MapPositionSharingControl.qml
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* 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 net.jami.Constants 1.1
|
||||||
|
import net.jami.Adapters 1.1
|
||||||
|
import net.jami.Enums 1.1
|
||||||
|
|
||||||
|
import "../../commoncomponents"
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
anchors.horizontalCenter: mapObject.horizontalCenter
|
||||||
|
anchors.margins: 10
|
||||||
|
anchors.bottom: mapObject.bottom
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
radius: 10
|
||||||
|
Layout.preferredWidth: textTimer.width + 15
|
||||||
|
Layout.preferredHeight: textTimer.height + 15
|
||||||
|
color: JamiTheme.mapButtonsOverlayColor
|
||||||
|
visible: textTimer.remainingTimeMs === 0
|
||||||
|
? false
|
||||||
|
: isUnpin
|
||||||
|
? isSharing
|
||||||
|
: isSharingToCurrentConversation
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: textTimer
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: JamiTheme.mapButtonColor
|
||||||
|
text: standartCountdown(Math.floor(remainingTimeMs / 1000))
|
||||||
|
|
||||||
|
function standartCountdown(seconds) {
|
||||||
|
var minutes = Math.floor(seconds / 60);
|
||||||
|
var hour = Math.floor(minutes / 60)
|
||||||
|
minutes = minutes % 60
|
||||||
|
var sec = seconds % 60
|
||||||
|
if (hour) {
|
||||||
|
if (minutes)
|
||||||
|
return qsTr("%1h%2min").arg(hour).arg(minutes)
|
||||||
|
else
|
||||||
|
return qsTr("%1h").arg(hour)
|
||||||
|
}
|
||||||
|
if (minutes) {
|
||||||
|
if (sec)
|
||||||
|
return qsTr("%1m%2sec").arg(minutes).arg(sec)
|
||||||
|
else
|
||||||
|
return qsTr("%1m").arg(minutes)
|
||||||
|
|
||||||
|
}
|
||||||
|
return qsTr("%1sec").arg(sec)
|
||||||
|
}
|
||||||
|
|
||||||
|
property int remainingTimeMs: 0
|
||||||
|
Connections {
|
||||||
|
target: PositionManager
|
||||||
|
function onSendCountdownUpdate(accountId, remainingTime) {
|
||||||
|
if (accountId === attachedAccountId) {
|
||||||
|
textTimer.remainingTimeMs = remainingTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: sharePositionLayout
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
MaterialButton {
|
||||||
|
id: sharePositionButton
|
||||||
|
|
||||||
|
preferredWidth: text.contentWidth
|
||||||
|
textLeftPadding: JamiTheme.buttontextPadding
|
||||||
|
textRightPadding: JamiTheme.buttontextPadding
|
||||||
|
primary: true
|
||||||
|
visible: !isSharingToCurrentConversation && !isUnpin
|
||||||
|
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
|
||||||
|
property int positionShareConvIdsCount: PositionManager.positionShareConvIdsCount
|
||||||
|
property string currentConvId: CurrentConversation.id
|
||||||
|
property bool isMapUnpin: isUnpin
|
||||||
|
|
||||||
|
function errorString(posError) {
|
||||||
|
if (posError === "locationServicesError")
|
||||||
|
return JamiStrings.locationServicesError
|
||||||
|
return JamiStrings.locationServicesClosedError
|
||||||
|
}
|
||||||
|
|
||||||
|
onPositionShareConvIdsCountChanged: {
|
||||||
|
isSharingToCurrentConversation = PositionManager.isPositionSharedToConv(attachedAccountId, currentConvId)
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentConvIdChanged: {
|
||||||
|
isSharingToCurrentConversation = PositionManager.isPositionSharedToConv(attachedAccountId, currentConvId)
|
||||||
|
}
|
||||||
|
|
||||||
|
onIsMapUnpinChanged: {
|
||||||
|
isSharingToCurrentConversation = PositionManager.isPositionSharedToConv(attachedAccountId, currentConvId)
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
var sharingDuration = 60 * 1000 * UtilsAdapter.getAppValue(Settings.PositionShareDuration)
|
||||||
|
if (!isError && !isUnpin) {
|
||||||
|
PositionManager.sharePosition(sharingDuration, attachedAccountId, currentConvId);
|
||||||
|
}
|
||||||
|
webView.runJavaScript("zoomTolayersExtent()" );
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialToolTip {
|
||||||
|
property bool isSharingPossible: !(sharePositionButton.isError && (sharePositionButton.positioningError !== "default"))
|
||||||
|
|
||||||
|
visible: sharePositionButton.hovered
|
||||||
|
text: isSharingPossible
|
||||||
|
? JamiStrings.shareLocationToolTip.arg(PositionManager.getmapTitle(attachedAccountId, currentConvId))
|
||||||
|
: sharePositionButton.errorString(sharePositionButton.positioningError)
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: PositionManager
|
||||||
|
function onPositioningError (err) {
|
||||||
|
sharePositionButton.positioningError = err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialButton {
|
||||||
|
id: stopSharingPositionButton
|
||||||
|
|
||||||
|
preferredWidth: text.contentWidth
|
||||||
|
textLeftPadding: JamiTheme.buttontextPadding
|
||||||
|
textRightPadding: JamiTheme.buttontextPadding
|
||||||
|
primary: true
|
||||||
|
visible: isSharing
|
||||||
|
text: stopAllSharing
|
||||||
|
? JamiStrings.shortStopAllSharings
|
||||||
|
: JamiStrings.stopSharingLocation
|
||||||
|
color: isError
|
||||||
|
? JamiTheme.buttonTintedGreyInactive
|
||||||
|
: JamiTheme.buttonTintedRed
|
||||||
|
hoveredColor: isError
|
||||||
|
? JamiTheme.buttonTintedGreyInactive
|
||||||
|
: JamiTheme.buttonTintedRedHovered
|
||||||
|
pressedColor: isError
|
||||||
|
? JamiTheme.buttonTintedGreyInactive
|
||||||
|
: JamiTheme.buttonTintedRedPressed
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
toolTipText: stopAllSharing
|
||||||
|
? isUnpin
|
||||||
|
? JamiStrings.unpinStopSharingTooltip
|
||||||
|
: JamiStrings.stopAllSharings
|
||||||
|
: JamiStrings.stopSharingSeveralConversationTooltip
|
||||||
|
property bool isHovered: false
|
||||||
|
property string positioningError
|
||||||
|
property bool isError: positioningError.length
|
||||||
|
property bool stopAllSharing: !(PositionManager.positionShareConvIdsCount >= 2 && !isUnpin && isSharingToCurrentConversation)
|
||||||
|
onClicked: {
|
||||||
|
if (!isError) {
|
||||||
|
if (stopAllSharing) {
|
||||||
|
PositionManager.stopSharingPosition();
|
||||||
|
} else {
|
||||||
|
stopSharingPositionPopup.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,12 +19,11 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import Qt5Compat.GraphicalEffects
|
||||||
|
|
||||||
import net.jami.Models 1.1
|
import net.jami.Models 1.1
|
||||||
import net.jami.Adapters 1.1
|
import net.jami.Adapters 1.1
|
||||||
import net.jami.Constants 1.1
|
import net.jami.Constants 1.1
|
||||||
import Qt5Compat.GraphicalEffects
|
|
||||||
|
|
||||||
|
|
||||||
import "../../commoncomponents"
|
import "../../commoncomponents"
|
||||||
|
|
||||||
|
@ -101,11 +100,10 @@ Popup {
|
||||||
color: JamiTheme.buttonTintedBlue
|
color: JamiTheme.buttonTintedBlue
|
||||||
hoveredColor: JamiTheme.buttonTintedBlueHovered
|
hoveredColor: JamiTheme.buttonTintedBlueHovered
|
||||||
pressedColor: JamiTheme.buttonTintedBluePressed
|
pressedColor: JamiTheme.buttonTintedBluePressed
|
||||||
text: JamiStrings.stopConvSharing
|
text: JamiStrings.stopConvSharing.arg(PositionManager.getmapTitle(attachedAccountId, CurrentConversation.id))
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PositionManager.stopSharingPosition(PositionManager.getSelectedConvId())
|
PositionManager.stopSharingPosition(attachedAccountId, CurrentConversation.id)
|
||||||
shareButtonVisibility = true
|
|
||||||
root.close()
|
root.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,12 +121,10 @@ Popup {
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PositionManager.stopSharingPosition()
|
PositionManager.stopSharingPosition()
|
||||||
shareButtonVisibility = true
|
|
||||||
root.close()
|
root.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ var proj = new ol.proj.Projection({
|
||||||
extent: extent
|
extent: extent
|
||||||
})
|
})
|
||||||
|
|
||||||
function setSource (coordos, authorI,imageI) {
|
function setSource (coordos, avatar) {
|
||||||
var coord = ol.proj.fromLonLat(coordos)
|
var coord = ol.proj.fromLonLat(coordos)
|
||||||
var pointFeature = new ol.Feature({
|
var pointFeature = new ol.Feature({
|
||||||
geometry: new ol.geom.Point(coord),
|
geometry: new ol.geom.Point(coord),
|
||||||
|
@ -69,16 +69,16 @@ function setSource (coordos, authorI,imageI) {
|
||||||
})
|
})
|
||||||
|
|
||||||
var preStyle = new ol.style.Icon({
|
var preStyle = new ol.style.Icon({
|
||||||
src: "data:image/png;base64," + imageI})
|
src: "data:image/png;base64," + avatar})
|
||||||
|
|
||||||
//resize the image to 40 px
|
//resize the image to 35 px
|
||||||
var image = preStyle.getImage()
|
var image = preStyle.getImage()
|
||||||
if (!image.width) {
|
if (!image.width) {
|
||||||
image.addEventListener('load', function () {
|
image.addEventListener('load', function () {
|
||||||
preStyle.setScale([40 / image.width, 40 / image.height])
|
preStyle.setScale([35 / image.width, 35 / image.height])
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
preStyle.setScale([40 / image.width, 40 / image.height])
|
preStyle.setScale([35 / image.width, 35 / image.height])
|
||||||
}
|
}
|
||||||
|
|
||||||
var iconStyle = new ol.style.Style({
|
var iconStyle = new ol.style.Style({
|
||||||
|
@ -93,18 +93,24 @@ function setSource (coordos, authorI,imageI) {
|
||||||
return vectorSource
|
return vectorSource
|
||||||
}
|
}
|
||||||
|
|
||||||
function newPosition (coordos, authorI, image) {
|
function newPosition (coordos, authorUri, avatar) {
|
||||||
vectorSource = setSource(coordos, authorI, image)
|
var layerArray = map.getLayers().getArray();
|
||||||
|
for (var i = 0; i < layerArray.length; i++ ){
|
||||||
|
if(layerArray[i].layer_type === authorUri) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vectorSource = setSource(coordos, avatar)
|
||||||
var iconLayer = new ol.layer.Vector({source: vectorSource})
|
var iconLayer = new ol.layer.Vector({source: vectorSource})
|
||||||
iconLayer.layer_type = authorI
|
iconLayer.layer_type = authorUri
|
||||||
map.addLayer(iconLayer)
|
map.addLayer(iconLayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePosition (coordos, authorI) {
|
function updatePosition (coordos, authorUri) {
|
||||||
var coord = ol.proj.fromLonLat(coordos);
|
var coord = ol.proj.fromLonLat(coordos);
|
||||||
var layerArray = map.getLayers().getArray();
|
var layerArray = map.getLayers().getArray();
|
||||||
for (var i = 0; i < layerArray.length; i++ ){
|
for (var i = 0; i < layerArray.length; i++ ){
|
||||||
if(layerArray[i].layer_type === authorI) {
|
if(layerArray[i].layer_type === authorUri) {
|
||||||
layerArray[i].getSource().getFeatures()[0].getGeometry().setCoordinates(coord)
|
layerArray[i].getSource().getFeatures()[0].getGeometry().setCoordinates(coord)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -123,10 +129,10 @@ function zoomTolayersExtent() {
|
||||||
padding: [80 ,80 ,80 ,80]})
|
padding: [80 ,80 ,80 ,80]})
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePosition (authorI) {
|
function removePosition (authorUri) {
|
||||||
var layerArray = map.getLayers().getArray();
|
var layerArray = map.getLayers().getArray();
|
||||||
for (var i = 0; i < layerArray.length; i++ ){
|
for (var i = 0; i < layerArray.length; i++ ){
|
||||||
if(layerArray[i].layer_type === authorI) {
|
if(layerArray[i].layer_type === authorUri) {
|
||||||
map.removeLayer(layerArray[i])
|
map.removeLayer(layerArray[i])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
typedef QMap<QString, QString> MapStringString;
|
typedef QMap<QString, QString> MapStringString;
|
||||||
typedef QMap<QString, int> MapStringInt;
|
typedef QMap<QString, int> MapStringInt;
|
||||||
typedef QMap<QString, double> MapStringDouble;
|
typedef QMap<QString, double> MapStringDouble;
|
||||||
|
typedef QMap<QPair<QString, QString>, bool> MapPairStrStrBool;
|
||||||
typedef QVector<int> VectorInt;
|
typedef QVector<int> VectorInt;
|
||||||
typedef QVector<uint> VectorUInt;
|
typedef QVector<uint> VectorUInt;
|
||||||
typedef QVector<qulonglong> VectorULongLong;
|
typedef QVector<qulonglong> VectorULongLong;
|
||||||
|
@ -41,6 +42,8 @@ typedef QMap<QString, QMap<QString, QStringList>> MapStringMapStringStringList;
|
||||||
typedef QMap<QString, QStringList> MapStringStringList;
|
typedef QMap<QString, QStringList> MapStringStringList;
|
||||||
typedef QVector<QByteArray> VectorVectorByte;
|
typedef QVector<QByteArray> VectorVectorByte;
|
||||||
typedef uint64_t DataTransferId;
|
typedef uint64_t DataTransferId;
|
||||||
|
// accountId, conversationId
|
||||||
|
typedef QPair<QString, QString> PositionKey;
|
||||||
|
|
||||||
constexpr static const char* TRUE_STR = "true";
|
constexpr static const char* TRUE_STR = "true";
|
||||||
constexpr static const char* TEXT_PLAIN = "text/plain";
|
constexpr static const char* TEXT_PLAIN = "text/plain";
|
||||||
|
|
Loading…
Add table
Reference in a new issue