aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiina Puuronen <miina.puuronen@qt.io>2021-02-22 13:08:33 +0200
committerMiina Puuronen <miina.puuronen@qt.io>2021-03-04 12:46:11 +0000
commit167e0d5d58ee4f75c5c5c07c13eac758689729e7 (patch)
treee60823b1ab57b57fa580bcff31b4057897e53c95
parentee960929ea8b70f4d21737b058885a8174cf78ad (diff)
Implement user feedback popupv4.15.0-beta1
Task-number: QDS-3500 Change-Id: I1a732b77de6d2bb411586b810c695cdfea01aa00 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/datasources/qmldesignerusageeventsource.cpp68
-rw-r--r--src/datasources/qmldesignerusageeventsource.h13
-rw-r--r--src/images/star_empty.pngbin0 -> 876 bytes
-rw-r--r--src/images/star_empty@2x.pngbin0 -> 1688 bytes
-rw-r--r--src/images/star_filled.pngbin0 -> 669 bytes
-rw-r--r--src/images/star_filled@2x.pngbin0 -> 1246 bytes
-rw-r--r--src/src.pro2
-rw-r--r--src/ui/FeedbackPopup.qml164
-rw-r--r--src/usagestatistic.qrc5
10 files changed, 250 insertions, 4 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2660834..58c0f82 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -14,7 +14,7 @@ find_package(KUserFeedback REQUIRED)
add_qtc_plugin(UsageStatistic
PLUGIN_DEPENDS
QtCreator::Core QtCreator::Debugger QtCreator::ProjectExplorer QtCreator::QtSupport
- DEPENDS Qt5::Widgets QtCreator::ExtensionSystem QtCreator::Utils KUserFeedbackCore KUserFeedbackWidgets
+ DEPENDS Qt5::Widgets Qt5::QuickWidgets QtCreator::ExtensionSystem QtCreator::Utils KUserFeedbackCore KUserFeedbackWidgets
SOURCES
usagestatisticplugin.cpp
datasources/qtclicensesource.cpp
diff --git a/src/datasources/qmldesignerusageeventsource.cpp b/src/datasources/qmldesignerusageeventsource.cpp
index 66a335e..1782ef1 100644
--- a/src/datasources/qmldesignerusageeventsource.cpp
+++ b/src/datasources/qmldesignerusageeventsource.cpp
@@ -30,6 +30,7 @@
#include <extensionsystem/iplugin.h>
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
+#include <QtQuick/QQuickItem>
#include <KUserFeedback/Provider>
@@ -49,6 +50,11 @@ static bool isQmlDesigner(const ExtensionSystem::PluginSpec *spec)
const char qmlDesignerEventsKey[] = "qmlDesignerEvents";
const char qmlDesignerTimesKey[] = "qmlDesignerTimes";
+// For feedback popup
+const char qmlDesignerFeedbackTextKey[] = "qmlDesignerFeedbackTextKey";
+const char qmlDesignerFeedbackRatingKey[] = "qmlDesignerFeedbackRatingKey";
+const char qmlDesignerFeedbackPoppedKey[] = "qmlDesignerFeedbackPoppedKey";
+
QmlDesignerUsageEventSource::QmlDesignerUsageEventSource()
: KUserFeedback::AbstractDataSource("qmlDesignerUsageEvents", Provider::DetailedUsageStatistics)
{
@@ -77,6 +83,43 @@ QString QmlDesignerUsageEventSource::description() const
return tr("What views and actions are used in QML Design mode.");
}
+void QmlDesignerUsageEventSource::closeFeedbackPopup()
+{
+ m_feedbackWidget->deleteLater();
+}
+
+void QmlDesignerUsageEventSource::insertFeedback(const QString &feedback, int rating)
+{
+ if (!feedback.isEmpty())
+ m_feedbackTextData.insert(currentIdentifier, feedback);
+
+ m_feedbackRatingData.insert(currentIdentifier, rating);
+}
+
+void QmlDesignerUsageEventSource::launchPopup(const QString &identifier)
+{
+ currentIdentifier = identifier;
+
+ if (!m_feedbackWidget) {
+ m_feedbackWidget = new QQuickWidget(Core::ICore::dialogParent());
+ m_feedbackWidget->setSource(QUrl("qrc:/usagestatistic/ui/FeedbackPopup.qml"));
+ m_feedbackWidget->setWindowModality(Qt::ApplicationModal);
+ m_feedbackWidget->setWindowFlags(Qt::SplashScreen);
+ m_feedbackWidget->setAttribute(Qt::WA_DeleteOnClose);
+
+ QQuickItem *root = m_feedbackWidget->rootObject();
+ QObject *title = root->findChild<QObject *>("title");
+ QString name = tr("Enjoying %1?").arg(identifier);
+ title->setProperty("text", name);
+
+ QObject::connect(root, SIGNAL(submitFeedback(QString, int)),
+ this, SLOT(insertFeedback(const QString, int)));
+ QObject::connect(root, SIGNAL(closeClicked()), this, SLOT(closeFeedbackPopup()));
+ }
+
+ m_feedbackWidget->show();
+}
+
void QmlDesignerUsageEventSource::handleUsageStatisticsNotifier(const QString &identifier)
{
auto it = m_eventData.find(identifier);
@@ -91,15 +134,28 @@ void QmlDesignerUsageEventSource::handleUsageStatisticsUsageTimer(const QString
{
auto it = m_timeData.find(identifier);
- if (it != m_timeData.end())
+ if (it != m_timeData.end()) {
it.value() = it.value().toInt() + elapsed;
- else
+
+ // Show the user feedback prompt after time limit is passed
+ static const QSet<QString> supportedViews {"Form Editor", "3D Editor", "Timeline",
+ "Transition Editor", "Curve Editor"};
+ static const int timeLimit = 864'000'000; // 10 days
+ if (supportedViews.contains(identifier) && !m_feedbackPoppedData[identifier].toBool()
+ && m_timeData.value(identifier).toInt() >= timeLimit) {
+ launchPopup(identifier);
+ m_feedbackPoppedData[identifier] = QVariant(true);
+ }
+ } else {
m_timeData.insert(identifier, elapsed);
+ }
}
QVariant QmlDesignerUsageEventSource::data()
{
- return QVariantMap{{qmlDesignerEventsKey, m_eventData}, {qmlDesignerTimesKey, m_timeData}};
+ return QVariantMap{{qmlDesignerEventsKey, m_eventData}, {qmlDesignerTimesKey, m_timeData},
+ {qmlDesignerFeedbackTextKey, m_feedbackTextData}, {qmlDesignerFeedbackRatingKey, m_feedbackRatingData},
+ {qmlDesignerFeedbackPoppedKey, m_feedbackPoppedData}};
}
void QmlDesignerUsageEventSource::loadImpl(QSettings *settings)
@@ -107,6 +163,9 @@ void QmlDesignerUsageEventSource::loadImpl(QSettings *settings)
auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
m_eventData = settings->value(qmlDesignerEventsKey).toMap();
m_timeData = settings->value(qmlDesignerTimesKey).toMap();
+ m_feedbackTextData = settings->value(qmlDesignerFeedbackTextKey).toHash();
+ m_feedbackRatingData = settings->value(qmlDesignerFeedbackRatingKey).toHash();
+ m_feedbackPoppedData = settings->value(qmlDesignerFeedbackPoppedKey).toHash();
}
void QmlDesignerUsageEventSource::storeImpl(QSettings *settings)
@@ -114,6 +173,9 @@ void QmlDesignerUsageEventSource::storeImpl(QSettings *settings)
auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
settings->setValue(qmlDesignerEventsKey, m_eventData);
settings->setValue(qmlDesignerTimesKey, m_timeData);
+ settings->setValue(qmlDesignerFeedbackTextKey, m_feedbackTextData);
+ settings->setValue(qmlDesignerFeedbackRatingKey, m_feedbackRatingData);
+ settings->setValue(qmlDesignerFeedbackPoppedKey, m_feedbackPoppedData);
}
void QmlDesignerUsageEventSource::resetImpl(QSettings *settings)
diff --git a/src/datasources/qmldesignerusageeventsource.h b/src/datasources/qmldesignerusageeventsource.h
index c51055b..9843555 100644
--- a/src/datasources/qmldesignerusageeventsource.h
+++ b/src/datasources/qmldesignerusageeventsource.h
@@ -26,7 +26,9 @@
#include <KUserFeedback/AbstractDataSource>
+#include <QHash>
#include <QMap>
+#include <QQuickWidget>
namespace UsageStatistic {
namespace Internal {
@@ -41,6 +43,7 @@ public:
public:
QString name() const override;
QString description() const override;
+ QString currentIdentifier; // feedback popup
QVariant data() override;
@@ -48,13 +51,23 @@ public:
void storeImpl(QSettings *settings) override;
void resetImpl(QSettings *settings) override;
+ void launchPopup(const QString &identifier); // launch user feedback popup
+
public slots:
void handleUsageStatisticsNotifier(const QString &identifier);
void handleUsageStatisticsUsageTimer(const QString &identifier, int elapsed);
+ void insertFeedback(const QString &feedback, int rating);
+ void closeFeedbackPopup();
private:
QMap<QString, QVariant> m_eventData;
QMap<QString, QVariant> m_timeData;
+
+ // user feedback data
+ QHash<QString, QVariant> m_feedbackTextData;
+ QHash<QString, QVariant> m_feedbackRatingData;
+ QHash<QString, QVariant> m_feedbackPoppedData;
+ QPointer<QQuickWidget> m_feedbackWidget;
};
} // namespace Internal
diff --git a/src/images/star_empty.png b/src/images/star_empty.png
new file mode 100644
index 0000000..3ea5966
--- /dev/null
+++ b/src/images/star_empty.png
Binary files differ
diff --git a/src/images/star_empty@2x.png b/src/images/star_empty@2x.png
new file mode 100644
index 0000000..a06ef89
--- /dev/null
+++ b/src/images/star_empty@2x.png
Binary files differ
diff --git a/src/images/star_filled.png b/src/images/star_filled.png
new file mode 100644
index 0000000..0180fde
--- /dev/null
+++ b/src/images/star_filled.png
Binary files differ
diff --git a/src/images/star_filled@2x.png b/src/images/star_filled@2x.png
new file mode 100644
index 0000000..2d8be01
--- /dev/null
+++ b/src/images/star_filled@2x.png
Binary files differ
diff --git a/src/src.pro b/src/src.pro
index 41ab62e..40400c9 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,5 +1,7 @@
DEFINES += USAGESTATISTIC_LIBRARY
+QT += quickwidgets
+
INCLUDEPATH *= "$${PWD}"
CONFIG += c++1z
diff --git a/src/ui/FeedbackPopup.qml b/src/ui/FeedbackPopup.qml
new file mode 100644
index 0000000..7ec8b3c
--- /dev/null
+++ b/src/ui/FeedbackPopup.qml
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Window 2.15
+
+Rectangle {
+ id: root_rectangle
+
+ property int rating: 1
+
+ signal submitFeedback(string feedback, int rating)
+ signal closeClicked()
+
+ width: 740
+ height: 382
+ border { color: "#0094ce"; width: 1 }
+
+ Text {
+ id: h1
+ objectName: "title"
+ color: "#333333"
+ text: "Enjoying Qt Design Studio?"
+ font { family: "Titillium"; capitalization: Font.AllUppercase; pixelSize: 21 }
+ anchors { horizontalCenter: parent.horizontalCenter; top: parent.top; topMargin: 50 }
+ }
+
+ Text {
+ id: h2
+ color: "#333333"
+ text: "Tap a star to rate the usefulness of the feature"
+ font { family: "Titillium"; pixelSize: 21 }
+ anchors { horizontalCenter: parent.horizontalCenter; top: h1.bottom; topMargin: 12 }
+ }
+
+ Row {
+ id: starRow
+ width: 246; height: 42; spacing: 6.5
+ anchors { horizontalCenter: parent.horizontalCenter; top: h2.bottom; topMargin: 32 }
+
+ Repeater { // create the stars
+ id: rep
+ model: 5
+ Image {
+ source: "../images/star_empty.png"
+ fillMode: Image.PreserveAspectFit
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ for (var i = 0; i < 5; ++i) {
+ rep.itemAt(i).source = i <= index ? "../images/star_filled.png"
+ : "../images/star_empty.png"
+ }
+ rating = index + 1
+ }
+ }
+ }
+ }
+ }
+
+ ScrollView {
+ id: scroll_textarea
+ width: 436
+ height: 96
+ anchors { horizontalCenter: parent.horizontalCenter; top: starRow.bottom; topMargin: 28 }
+
+ TextArea {
+ id: textarea
+ width: 426
+ height: 90
+ color: "#333333";
+ placeholderText: "We highly appreciate additional feedback.\nBouquets or Brickbats, suggestions, all welcome!"
+ font { pixelSize: 14; family: "Titillium" }
+ wrapMode: Text.Wrap
+ }
+
+ background: Rectangle {
+ border { color: "#e6e6e6"; width: 1 }
+ }
+ }
+
+ Row {
+ id: buttonRow
+ anchors { horizontalCenter: parent.horizontalCenter; top: scroll_textarea.bottom; topMargin: 28 }
+ spacing: 10
+
+ Button {
+ id: buttonSkip
+ width: 80
+ height: 28
+
+ contentItem: Text {
+ id: bskip_text
+ text: "Skip"
+ color: "#999999"
+ font { family: "Titillium"; pixelSize: 14 }
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ background: Rectangle {
+ id: bskip_bg
+ anchors.fill: parent
+ color: "#ffffff"
+ border { color: "#999999"; width: 1 }
+ }
+
+ onHoveredChanged: bskip_text.color = hovered ? "#666666" : "#999999"
+ onClicked: root_rectangle.closeClicked()
+ }
+
+ Button {
+ id: buttonSubmit
+
+ width: 80
+ height: 28
+
+ contentItem: Text {
+ id: bsub_text
+ text: "Submit";
+ color: "white"
+ font { family: "Titillium"; pixelSize: 14 }
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ background: Rectangle {
+ id: bsub_bg
+ anchors.fill: parent
+ color: "#0094ce"
+ border { color: "#999999"; width: 1 }
+ }
+
+ onHoveredChanged: bsub_bg.color = hovered ? Qt.lighter("#0094ce", 1.2) : "#0094ce"
+ onClicked: {
+ root_rectangle.submitFeedback(textarea.text, rating);
+ root_rectangle.closeClicked();
+ }
+ }
+ }
+}
diff --git a/src/usagestatistic.qrc b/src/usagestatistic.qrc
index 8ab02df..f0b34f8 100644
--- a/src/usagestatistic.qrc
+++ b/src/usagestatistic.qrc
@@ -2,5 +2,10 @@
<qresource prefix="/usagestatistic">
<file>images/settingscategory_usagestatistic.png</file>
<file>images/settingscategory_usagestatistic@2x.png</file>
+ <file>images/star_empty.png</file>
+ <file>images/star_empty@2x.png</file>
+ <file>images/star_filled.png</file>
+ <file>images/star_filled@2x.png</file>
+ <file>ui/FeedbackPopup.qml</file>
</qresource>
</RCC>