1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-07-23 08:55:26 +02:00

feature: improve location sharing

- share position to different conversations at the
  same time
- Be able to stop sharing positions with the current
  conversation only
- UI improvements to know who is sharing and who
  you are sharing to
- Watchdog

Change-Id: I1402f0d1b1fc117087988b1cc45f1fd05d2a83ac
GitLab: #888
This commit is contained in:
Nicolas Vengeon 2022-11-08 14:07:07 -05:00 committed by Sébastien Blin
parent e5b54ad787
commit 933cce8cef
14 changed files with 575 additions and 103 deletions

View file

@ -178,6 +178,7 @@ set(COMMON_SOURCES
${APP_SRC_DIR}/utils.cpp
${APP_SRC_DIR}/mainapplication.cpp
${APP_SRC_DIR}/messagesadapter.cpp
${APP_SRC_DIR}/positionobject.cpp
${APP_SRC_DIR}/positionmanager.cpp
${APP_SRC_DIR}/accountadapter.cpp
${APP_SRC_DIR}/calladapter.cpp
@ -233,6 +234,7 @@ set(COMMON_HEADERS
${APP_SRC_DIR}/mainapplication.h
${APP_SRC_DIR}/qrimageprovider.h
${APP_SRC_DIR}/messagesadapter.h
${APP_SRC_DIR}/positionobject.h
${APP_SRC_DIR}/positionmanager.h
${APP_SRC_DIR}/accountadapter.h
${APP_SRC_DIR}/calladapter.h

View file

@ -19,6 +19,8 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
@ -45,6 +47,8 @@ Item {
property alias presenceStatus: presenceIndicator.status
property bool showPresenceIndicator: true
property bool showSharePositionIndicator: false
property bool showSharedPositionIndicator: false
property alias fillMode: image.fillMode
onImageIdChanged: image.updateSource()
@ -116,4 +120,48 @@ Item {
visible: showPresenceIndicator
}
RowLayout {
id: positionIndicatorLayout
anchors.left: root.left
anchors.leftMargin: -1
anchors.bottom: root.bottom
anchors.bottomMargin: -1
spacing: 0
property real sizeI: root.width * JamiTheme.avatarPresenceRatio
Rectangle {
id: sharePositionIndicator
visible: showSharePositionIndicator
Layout.preferredWidth: parent.sizeI
Layout.preferredHeight: parent.sizeI
color: JamiTheme.backgroundColor
radius: parent.sizeI * 0.5
Image {
anchors.fill: parent
ColorOverlay {
anchors.fill: parent
source: parent
color: JamiTheme.sharePositionIndicatorColor
}
source: JamiResources.my_location_svg
}
}
Rectangle {
id: sharedPositionIndicator
visible: showSharedPositionIndicator
Layout.preferredWidth: parent.sizeI
Layout.preferredHeight: parent.sizeI
color: JamiTheme.backgroundColor
radius: parent.sizeI * 0.5
Image {
anchors.fill: parent
ColorOverlay {
anchors.fill: parent
source: parent
color: JamiTheme.sharedPositionIndicatorColor
}
source: JamiResources.my_location_svg
}
}
}
}

View file

@ -299,15 +299,25 @@ Item {
property string raiseHand: qsTr("Raise hand")
property string layoutSettings: qsTr("Layout settings")
// Share location
// Share location/position
property string shareLocation: qsTr("Share location")
property string stopSharingLocation: qsTr("Stop sharing location")
property string stopSharingLocation: qsTr("Stop sharing")
property string shortSharing: qsTr("10 minutes")
property string longSharing: qsTr("One hour")
property string minutesLeft: qsTr("%1 minutes left")
property string minuteLeft: qsTr("%1 minute left")
property string locationServicesError: qsTr("Jami needs to access to your location.\nIn Device Settings, please turn on Location Services.\nOther participants' location can still be received.")
property string locationServicesClosedError: qsTr("Please check your Internet connection.")
property string locationServicesError: qsTr("Your precise location could not be determined.\nIn Device Settings, please turn on \"Location Services\".\nOther participants' location can still be received.")
property string locationServicesClosedError: qsTr("Your precise location could not be determined. Please check your Internet connection.")
property string stopAllSharings: qsTr("Turn off location sharing");
property string stopConvSharing: qsTr("Stop location sharing in this conversation");
property string stopSharingPopupBody: qsTr("Location is shared in several conversations");
property string minimizeMapTooltip: qsTr("Minimize");
property string maximizeMapTooltip: qsTr("Maximize");
property string reduceMapTooltip: qsTr("Reduce");
property string extendMapTooltip: qsTr("Extend");
property string dragMapTooltip: qsTr("Drag");
property string centerMapTooltip: qsTr("Center");
property string closeMapTooltip: qsTr("Close");
// Chatview header
property string hideChat: qsTr("Hide chat")

View file

@ -213,6 +213,8 @@ Item {
//mapPosition
property color mapButtonsOverlayColor: darkTheme ? "#000000" : "#f0f0f0"
property color mapButtonColor: darkTheme ? "#f0f0f0" : "#000000"
property color sharePositionIndicatorColor: red_
property color sharedPositionIndicatorColor: urgentOrange_
// Files To Send Container
property color removeFileButtonColor: Qt.rgba(96, 95, 97, 0.5)
@ -318,7 +320,7 @@ Item {
property real preferredDialogWidth: 400
property real preferredDialogHeight: 300
property real minimumPreviewWidth: 120
property real minimumMapWidth: 230
property real minimumMapWidth: 250
property real pluginHandlersPopupViewHeight: 200
property real pluginHandlersPopupViewDelegateHeight: 50
property real secondaryDialogDimension: 500

View file

@ -28,6 +28,8 @@ Item {
property alias imageId: avatar.imageId
property alias showPresenceIndicator: avatar.showPresenceIndicator
property alias showSharePositionIndicator: avatar.showSharePositionIndicator
property alias showSharedPositionIndicator: avatar.showSharedPositionIndicator
property alias animationMode: animation.mode
SpinningAnimation {

View file

@ -68,10 +68,22 @@ ItemDelegate {
imageId: UID
showPresenceIndicator: Presence !== undefined ? Presence : false
showSharePositionIndicator: PositionManager.isPositionSharedToConv(UID)
showSharedPositionIndicator: PositionManager.isConvSharingPosition(UID)
Layout.preferredWidth: JamiTheme.smartListAvatarSize
Layout.preferredHeight: JamiTheme.smartListAvatarSize
Connections {
target: PositionManager
function onPositionShareConvIdsChanged () {
avatar.showSharePositionIndicator = PositionManager.isPositionSharedToConv(UID)
}
function onSharingUrisChanged () {
avatar.showSharedPositionIndicator = PositionManager.isConvSharingPosition(UID)
}
}
Rectangle {
id: overlayHighlighted
visible: highlighted && !interactive

View file

@ -28,7 +28,7 @@ Positioning::Positioning(QString uri, QObject* parent)
source_ = QGeoPositionInfoSource::createDefaultSource(this);
QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Positioning::requestPosition);
timer->start(2000);
timer->start(5000);
connect(source_, &QGeoPositionInfoSource::errorOccurred, this, &Positioning::slotError);
connect(source_, &QGeoPositionInfoSource::positionUpdated, this, &Positioning::positionUpdated);
// if location services are activated, positioning will be activated automatically
@ -38,11 +38,6 @@ Positioning::Positioning(QString uri, QObject* parent)
&Positioning::locationServicesActivated);
}
Positioning::~Positioning()
{
sendStopSharingMsg();
}
void
Positioning::start()
{
@ -60,16 +55,6 @@ Positioning::stop()
isPositioning = false;
}
void
Positioning::sendStopSharingMsg()
{
QJsonObject jsonObj;
jsonObj.insert("type", QJsonValue("Stop"));
QJsonDocument doc(jsonObj);
QString strJson(doc.toJson(QJsonDocument::Compact));
Q_EMIT newPosition(uri_, strJson, -1, "");
}
QString
Positioning::convertToJson(const QGeoPositionInfo& info)
{

View file

@ -28,8 +28,6 @@ class Positioning : public QObject
public:
Positioning(QString uri, QObject* parent = 0);
~Positioning();
/**
* start to retreive the current position
*/
@ -42,7 +40,6 @@ public:
* send a stop signal to other peers to tell them
* you stoped sharing yout position
*/
void sendStopSharingMsg();
QString convertToJson(const QGeoPositionInfo& info);
void setUri(QString uri);

View file

@ -19,8 +19,10 @@ PositionManager::PositionManager(LRCInstance* instance, QObject* parent)
});
connect(timerStopSharing_, &QTimer::timeout, [=] { stopSharingPosition(); });
connect(lrcInstance_, &LRCInstance::selectedConvUidChanged, [this]() {
Q_EMIT positionShareConvIdsChanged();
set_mapAutoOpening(true);
});
set_isMapActive(false);
}
void
@ -28,8 +30,14 @@ PositionManager::safeInit()
{
connect(lrcInstance_, &LRCInstance::currentAccountIdChanged, [this]() {
connectConversationModel();
set_sharingUris({});
objectListSharingUris_.clear();
set_positionShareConvIds({});
localPositioning_->setUri(lrcInstance_->getCurrentAccountInfo().profileInfo.uri);
});
set_sharingUris({});
objectListSharingUris_.clear();
set_positionShareConvIds({});
localPositioning_.reset(new Positioning(lrcInstance_->getCurrentAccountInfo().profileInfo.uri));
connectConversationModel();
}
@ -49,8 +57,7 @@ PositionManager::connectConversationModel()
void
PositionManager::startPositioning()
{
sharingUris_.clear();
currentConvSharingUris_.clear();
localPositioning_->start();
connect(localPositioning_.get(),
&Positioning::newPosition,
@ -70,8 +77,54 @@ PositionManager::stopPositioning()
localPositioning_->stop();
}
QString
PositionManager::getSelectedConvId()
{
return lrcInstance_->get_selectedConvUid();
}
bool
PositionManager::isConvSharingPosition(const QString& convUri)
{
const auto& convParticipants = lrcInstance_->getConversationFromConvUid(convUri)
.participantsUris();
Q_FOREACH (const auto& id, convParticipants) {
if (id != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
if (sharingUris_.contains(id)) {
return true;
}
}
}
return false;
}
void
PositionManager::onOwnPositionReceived(const QString& peerId, const QString& body)
PositionManager::loadPreviousLocations()
{
QVariantMap shareInfo;
for (auto it = objectListSharingUris_.begin(); it != objectListSharingUris_.end(); it++) {
QJsonObject jsonObj;
jsonObj.insert("type", QJsonValue("Position"));
jsonObj.insert("lat", it.value()->getLatitude().toString());
jsonObj.insert("long", it.value()->getLongitude().toString());
QJsonDocument doc(jsonObj);
QString strJson(doc.toJson(QJsonDocument::Compact));
onPositionReceived(it.key(), strJson, -1, "");
}
}
bool
PositionManager::isPositionSharedToConv(const QString& convUri)
{
if (positionShareConvIds_.length()) {
auto iter = std::find(positionShareConvIds_.begin(), positionShareConvIds_.end(), convUri);
return (iter != positionShareConvIds_.end());
}
return false;
}
void
PositionManager::sendPosition(const QString& peerId, const QString& body)
{
try {
Q_FOREACH (const auto& id, positionShareConvIds_) {
@ -89,13 +142,26 @@ PositionManager::onOwnPositionReceived(const QString& peerId, const QString& bod
}
}
void
PositionManager::onWatchdogTimeout()
{
QObject* obj = sender();
auto it = std::find_if(objectListSharingUris_.cbegin(),
objectListSharingUris_.cend(),
[obj](const auto& it) { return it == obj; });
if (it != objectListSharingUris_.cend()) {
QString stopMsg("{\"type\":\"Stop\"}");
onPositionReceived(it.key(), stopMsg, -1, "");
}
}
void
PositionManager::sharePosition(int maximumTime)
{
connect(localPositioning_.get(),
&Positioning::newPosition,
this,
&PositionManager::onOwnPositionReceived,
&PositionManager::sendPosition,
Qt::UniqueConnection);
try {
@ -109,11 +175,29 @@ PositionManager::sharePosition(int maximumTime)
}
void
PositionManager::stopSharingPosition()
PositionManager::stopSharingPosition(const QString convId)
{
localPositioning_->sendStopSharingMsg();
stopPositionTimers();
set_positionShareConvIds({});
QString stopMsg;
stopMsg = "{\"type\":\"Stop\"}";
if (convId == "") {
sendPosition(lrcInstance_->getCurrentAccountInfo().profileInfo.uri, stopMsg);
stopPositionTimers();
set_positionShareConvIds({});
} else {
const auto& convInfo = lrcInstance_->getConversationFromConvUid(convId);
Q_FOREACH (const QString& uri, convInfo.participantsUris()) {
if (lrcInstance_->getCurrentAccountInfo().profileInfo.uri != uri) {
lrcInstance_->getCurrentAccountInfo().contactModel->sendDhtMessage(uri,
stopMsg,
APPLICATION_GEO);
}
}
auto iter = std::find(positionShareConvIds_.begin(), positionShareConvIds_.end(), convId);
if (iter != positionShareConvIds_.end()) {
positionShareConvIds_.remove(std::distance(positionShareConvIds_.begin(), iter));
}
Q_EMIT positionShareConvIdsChanged();
}
}
void
@ -197,10 +281,9 @@ PositionManager::onPositionReceived(const QString& peerId,
->getConversationFromConvUid(
lrcInstance_->get_selectedConvUid())
.participantsUris();
// to know if the position received is from someone in the current conversation
bool isPeerIdInConv = (std::find(convParticipants.begin(), convParticipants.end(), peerId)
!= convParticipants.end());
if (!isPeerIdInConv)
return;
QVariantMap newPosition = parseJsonPosition(body, peerId);
auto getShareInfo = [&](bool update) -> QVariantMap {
@ -217,36 +300,79 @@ PositionManager::onPositionReceived(const QString& peerId,
if (!endSharing) {
// open map on position reception
if (!isMapActive_ && mapAutoOpening_
if (!isMapActive_ && mapAutoOpening_ && isPeerIdInConv
&& peerId != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
set_isMapActive(true);
}
}
auto iter = std::find(sharingUris_.begin(), sharingUris_.end(), peerId);
if (iter == sharingUris_.end()) {
auto iter = std::find(currentConvSharingUris_.begin(), currentConvSharingUris_.end(), peerId);
if (iter == currentConvSharingUris_.end()) {
// New share
if (!endSharing) {
sharingUris_.insert(peerId);
Q_EMIT positionShareAdded(getShareInfo(false));
}
Q_EMIT sharingUrisChanged();
// list to save more information on position + watchdog
auto it = objectListSharingUris_.find(peerId);
if (it == objectListSharingUris_.end()) {
auto obj = new PositionObject(newPosition["lat"], newPosition["long"], this);
objectListSharingUris_.insert(peerId, obj);
connect(obj,
&PositionObject::timeout,
this,
&PositionManager::onWatchdogTimeout,
Qt::DirectConnection);
}
if (isPeerIdInConv) {
currentConvSharingUris_.insert(peerId);
Q_EMIT positionShareAdded(getShareInfo(false));
}
// stop sharing position
} else {
sharingUris_.remove(peerId);
Q_EMIT sharingUrisChanged();
auto it = objectListSharingUris_.find(peerId);
if (it != objectListSharingUris_.end()) {
it.value()->deleteLater();
objectListSharingUris_.erase(it);
}
}
} else {
// Update/remove existing
if (endSharing) {
// Remove (avoid self)
if (peerId != lrcInstance_->getCurrentAccountInfo().profileInfo.uri) {
sharingUris_.remove(peerId);
// Remove
sharingUris_.remove(peerId);
Q_EMIT sharingUrisChanged();
auto it = objectListSharingUris_.find(peerId);
if (it != objectListSharingUris_.end()) {
it.value()->deleteLater();
objectListSharingUris_.erase(it);
}
if (isPeerIdInConv) {
currentConvSharingUris_.remove(peerId);
Q_EMIT positionShareRemoved(peerId);
// close the map if you're not sharing and the only remaining position is yours
if (!positionShareConvIds_.length() && sharingUris_.size() == 1
&& sharingUris_.contains(
lrcInstance_->getCurrentAccountInfo().profileInfo.uri)) {
// close the map if you're not sharing and you don't receive position anymore
if (!positionShareConvIds_.length()
&& ((sharingUris_.size() == 1
&& sharingUris_.contains(
lrcInstance_->getCurrentAccountInfo().profileInfo.uri))
|| sharingUris_.size() == 0)) {
set_isMapActive(false);
}
}
} else {
// Update
Q_EMIT positionShareUpdated(getShareInfo(true));
if (isPeerIdInConv)
Q_EMIT positionShareUpdated(getShareInfo(true));
// reset watchdog
auto it = objectListSharingUris_.find(peerId);
if (it != objectListSharingUris_.end()) {
it.value()->resetWatchdog();
}
}
}
}

View file

@ -21,6 +21,7 @@
#include "lrcinstance.h"
#include "qmladapterbase.h"
#include "positioning.h"
#include "positionobject.h"
#include <QObject>
#include <QString>
@ -31,6 +32,7 @@ class PositionManager : public QmlAdapterBase
QML_RO_PROPERTY(bool, isMapActive)
QML_RO_PROPERTY(int, timeSharingRemaining)
QML_PROPERTY(QList<QString>, positionShareConvIds)
QML_PROPERTY(QSet<QString>, sharingUris)
QML_PROPERTY(bool, mapAutoOpening)
public:
explicit PositionManager(LRCInstance* instance, QObject* parent = nullptr);
@ -54,9 +56,16 @@ protected:
Q_INVOKABLE void connectConversationModel();
Q_INVOKABLE void setMapActive(bool state);
Q_INVOKABLE void sharePosition(int maximumTime);
Q_INVOKABLE void stopSharingPosition(const QString convId = "");
Q_INVOKABLE void startPositioning();
Q_INVOKABLE void stopPositioning();
Q_INVOKABLE void stopSharingPosition();
Q_INVOKABLE QString getSelectedConvId();
Q_INVOKABLE bool isPositionSharedToConv(const QString& convUri);
Q_INVOKABLE bool isConvSharingPosition(const QString& convUri);
Q_INVOKABLE void loadPreviousLocations();
private Q_SLOTS:
void onPositionErrorReceived(const QString error);
@ -64,11 +73,13 @@ private Q_SLOTS:
const QString& body,
const uint64_t& timestamp,
const QString& daemonId);
void onOwnPositionReceived(const QString& peerId, const QString& body);
void sendPosition(const QString& peerId, const QString& body);
void onWatchdogTimeout();
private:
std::unique_ptr<Positioning> localPositioning_;
QTimer* timerTimeLeftSharing_ = nullptr;
QTimer* timerStopSharing_ = nullptr;
QSet<QString> sharingUris_;
QSet<QString> currentConvSharingUris_;
QMap<QString, PositionObject*> objectListSharingUris_;
};

View file

@ -0,0 +1,30 @@
#include "positionobject.h"
PositionObject::PositionObject(QVariant latitude, QVariant longitude, QObject* parent)
: QObject(parent)
, resetTime(20000)
, longitude_(longitude)
, latitude_(latitude)
{
watchdog_ = new QTimer(this);
watchdog_->start(resetTime);
connect(watchdog_, &QTimer::timeout, this, &PositionObject::timeout);
}
void
PositionObject::resetWatchdog()
{
watchdog_->start(resetTime);
}
QVariant
PositionObject::getLongitude()
{
return longitude_;
}
QVariant
PositionObject::getLatitude()
{
return latitude_;
}

28
src/app/positionobject.h Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include "qvariant.h"
#include <QObject>
#include <QString>
#include <QTimer>
#include <QDebug>
class PositionObject : public QObject
{
Q_OBJECT
public:
PositionObject(QVariant latitude, QVariant longitude, QObject* parent = nullptr);
Q_SIGNAL void timeout();
void resetWatchdog();
QVariant getLongitude();
QVariant getLatitude();
private:
QVariant latitude_;
QVariant longitude_;
int resetTime;
QTimer* watchdog_;
};

View file

@ -106,10 +106,6 @@ Rectangle {
}
}
}
Component.onDestruction: {
PositionManager.stopSharingPosition();
PositionManager.stopPositioning();
}
Component.onCompleted: {
loadHtml(UtilsAdapter.qStringFromFile(mapHtml), mapHtml)
@ -122,6 +118,8 @@ Rectangle {
webView.isLoaded = true
runJavaScript("setMapView([" + 0 + ","+ 0 + "], " + 1 + " );" );
PositionManager.startPositioning()
//load locations that were received before this conversation was opened
PositionManager.loadPreviousLocations();
}
}
}
@ -152,7 +150,6 @@ Rectangle {
onClicked: {
buttonsChoseSharing.shortSharing = true
}
}
MaterialButton {
@ -195,69 +192,108 @@ Rectangle {
}
}
MaterialButton {
id: sharePositionButton
preferredWidth: text.contentWidth
textLeftPadding: JamiTheme.buttontextPadding
textRightPadding: JamiTheme.buttontextPadding
primary: true
text: webView.isSharing ? JamiStrings.stopSharingLocation : JamiStrings.shareLocation
color: isError
? JamiTheme.buttonTintedGreyInactive
: webView.isSharing ? JamiTheme.buttonTintedRed : JamiTheme.buttonTintedBlue
hoveredColor: isError
? JamiTheme.buttonTintedGreyInactive
: webView.isSharing ? JamiTheme.buttonTintedRedHovered : JamiTheme.buttonTintedBlueHovered
pressedColor: isError
? JamiTheme.buttonTintedGreyInactive
: webView.isSharing ? JamiTheme.buttonTintedRedPressed: JamiTheme.buttonTintedBluePressed
RowLayout {
id: sharePositionLayout
Layout.alignment: Qt.AlignHCenter
property bool isHovered: false
property string positioningError: "default"
property bool isError: positioningError.length
MaterialButton {
id: sharePositionButton
function errorString(posError) {
if (posError === "locationServicesError")
return JamiStrings.locationServicesError
return JamiStrings.locationServicesClosedError
}
preferredWidth: text.contentWidth
textLeftPadding: JamiTheme.buttontextPadding
textRightPadding: JamiTheme.buttontextPadding
primary: true
visible: ! PositionManager.isPositionSharedToConv(PositionManager.getSelectedConvId())
text: JamiStrings.shareLocation
color: isError
? JamiTheme.buttonTintedGreyInactive
: JamiTheme.buttonTintedBlue
hoveredColor: isError
? JamiTheme.buttonTintedGreyInactive
: JamiTheme.buttonTintedBlueHovered
pressedColor: isError
? JamiTheme.buttonTintedGreyInactive
: JamiTheme.buttonTintedBluePressed
Layout.alignment: Qt.AlignHCenter
property bool isHovered: false
property string positioningError: "default"
property bool isError: positioningError.length
function errorString(posError) {
if (posError === "locationServicesError")
return JamiStrings.locationServicesError
return JamiStrings.locationServicesClosedError
}
onClicked: {
if (!isError) {
if (webView.isSharing) {
PositionManager.stopSharingPosition();
} else {
if (buttonsChoseSharing.shortSharing)
onClicked: {
if (!isError) {
if( buttonsChoseSharing.shortSharing)
PositionManager.sharePosition(10 * 60 * 1000);
else
PositionManager.sharePosition(60 * 60 * 1000);
visible = false
}
}
onHoveredChanged: {
isHovered = !isHovered
}
MaterialToolTip {
visible: sharePositionButton.isHovered
&& sharePositionButton.isError && (sharePositionButton.positioningError !== "default")
x: 0
y: 0
text: sharePositionButton.errorString(sharePositionButton.positioningError)
}
Connections {
target: PositionManager
function onPositioningError (err) {
sharePositionButton.positioningError = err;
}
}
}
MaterialButton {
id: stopSharingPositionButton
onHoveredChanged: {
isHovered = !isHovered
}
MaterialToolTip {
visible: sharePositionButton.isHovered
&& sharePositionButton.isError && (sharePositionButton.positioningError !== "default")
x: 0
y: 0
text: sharePositionButton.errorString(sharePositionButton.positioningError)
}
Connections {
target: PositionManager
function onPositioningError (err) {
sharePositionButton.positioningError = err;
preferredWidth: text.contentWidth
textLeftPadding: JamiTheme.buttontextPadding
textRightPadding: JamiTheme.buttontextPadding
primary: true
visible: webView.isSharing
text: JamiStrings.stopSharingLocation
color: isError
? JamiTheme.buttonTintedGreyInactive
: JamiTheme.buttonTintedRed
hoveredColor: isError
? JamiTheme.buttonTintedGreyInactive
: JamiTheme.buttonTintedRedHovered
pressedColor: isError
? JamiTheme.buttonTintedGreyInactive
: JamiTheme.buttonTintedRedPressed
Layout.alignment: Qt.AlignHCenter
property bool isHovered: false
property string positioningError
property bool isError: positioningError.length
onClicked: {
if (!isError) {
if (PositionManager.positionShareConvIds.length >= 2) {
stopSharingPositionPopup.open()
} else {
PositionManager.stopSharingPosition();
sharePositionButton.visible = true
}
}
}
}
}
}
StopSharingPositionPopup {
id: stopSharingPositionPopup
property alias shareButtonVisibility: sharePositionButton.visible
}
Rectangle {
id: buttonOverlay
@ -277,6 +313,7 @@ Rectangle {
PushButton {
id: btnCenter
toolTipText: JamiStrings.centerMapTooltip
imageColor: JamiTheme.mapButtonColor
normalColor: JamiTheme.transparentColor
source: JamiResources.share_location_svg
@ -288,6 +325,7 @@ Rectangle {
PushButton {
id: btnMove
toolTipText: JamiStrings.dragMapTooltip
imageColor: JamiTheme.mapButtonColor
normalColor: JamiTheme.transparentColor
source: JamiResources.move_svg
@ -303,8 +341,11 @@ Rectangle {
}
PushButton {
id: btnminimise
id: btnminimize
toolTipText: isMinimised
? JamiStrings.extendMapTooltip
: JamiStrings.minimizeMapTooltip
imageColor: JamiTheme.mapButtonColor
normalColor: JamiTheme.transparentColor
source: isMinimised
@ -319,6 +360,9 @@ Rectangle {
PushButton {
id: btnmaximise
toolTipText: isFullScreen
? JamiStrings.reduceMapTooltip
: JamiStrings.maximizeMapTooltip
imageColor: JamiTheme.mapButtonColor
normalColor: JamiTheme.transparentColor
source: isFullScreen? JamiResources.close_fullscreen_24dp_svg : JamiResources.open_in_full_24dp_svg
@ -335,11 +379,13 @@ Rectangle {
PushButton {
id: btnClose
toolTipText: JamiStrings.closeMapTooltip
imageColor: JamiTheme.mapButtonColor
normalColor: JamiTheme.transparentColor
source: JamiResources.round_close_24dp_svg
onClicked: {
PositionManager.stopPositioning();
PositionManager.setMapActive(false);
PositionManager.mapAutoOpening = false;

View file

@ -0,0 +1,173 @@
/*
* Copyright (C) 2022 Savoir-faire Linux Inc.
* Author: Nicolas Vengeon <nicolas.vengeon@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import Qt5Compat.GraphicalEffects
import "../../commoncomponents"
Popup {
id: root
width: popupContent.width
height: popupContent.height
parent: Overlay.overlay
// center in parent
x: Math.round((parent.width - width) / 2)
y: Math.round((parent.height - height) / 2)
signal joinClicked
modal:true
padding: 0
visible: false
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
Rectangle {
id: container
anchors.fill: parent
radius: JamiTheme.modalPopupRadius
color: JamiTheme.secondaryBackgroundColor
ColumnLayout {
id: popupContent
Layout.alignment: Qt.AlignCenter
PushButton {
id: btnClose
Layout.alignment: Qt.AlignRight
width: 30
height: 30
imageContainerWidth: 30
imageContainerHeight : 30
Layout.margins: 8
radius : 5
imageColor: "grey"
normalColor: JamiTheme.transparentColor
source: JamiResources.round_close_24dp_svg
onClicked: { root.visible = false }
}
Text {
Layout.leftMargin: 20
Layout.rightMargin: 20
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: JamiTheme.popuptextSize
font.weight: Font.Medium
wrapMode: Text.WordWrap
color: JamiTheme.textColor
text: JamiStrings.stopSharingPopupBody
}
RowLayout{
Layout.margins: JamiTheme.popupButtonsMargin
Layout.alignment: Qt.AlignCenter
MaterialButton {
preferredWidth: text.contentWidth
textLeftPadding: JamiTheme.buttontextPadding
textRightPadding: JamiTheme.buttontextPadding
color: JamiTheme.buttonTintedBlue
hoveredColor: JamiTheme.buttonTintedBlueHovered
pressedColor: JamiTheme.buttonTintedBluePressed
text: JamiStrings.stopConvSharing
onClicked: {
PositionManager.stopSharingPosition(PositionManager.getSelectedConvId())
shareButtonVisibility = true
root.close()
}
}
MaterialButton {
preferredWidth: text.contentWidth
textLeftPadding: JamiTheme.buttontextPadding
textRightPadding: JamiTheme.buttontextPadding
color: JamiTheme.buttonTintedRed
hoveredColor: JamiTheme.buttonTintedRedHovered
pressedColor: JamiTheme.buttonTintedRedPressed
text: JamiStrings.stopAllSharings
onClicked: {
PositionManager.stopSharingPosition()
shareButtonVisibility = true
root.close()
}
}
}
}
}
background: Rectangle {
color: JamiTheme.transparentColor
}
Overlay.modal: Rectangle {
color: JamiTheme.transparentColor
// Color animation for overlay when pop up is shown.
ColorAnimation on color {
to: JamiTheme.popupOverlayColor
duration: 500
}
}
DropShadow {
z: -1
width: root.width
height: root.height
horizontalOffset: 3.0
verticalOffset: 3.0
radius: container.radius * 4
color: JamiTheme.shadowColor
source: container
transparentBorder: true
}
enter: Transition {
NumberAnimation {
properties: "opacity"; from: 0.0; to: 1.0
duration: JamiTheme.shortFadeDuration
}
}
exit: Transition {
NumberAnimation {
properties: "opacity"; from: 1.0; to: 0.0
duration: JamiTheme.shortFadeDuration
}
}
}