diff options
author | Miina Puuronen <miina.puuronen@qt.io> | 2021-02-22 13:08:33 +0200 |
---|---|---|
committer | Miina Puuronen <miina.puuronen@qt.io> | 2021-03-04 12:46:11 +0000 |
commit | 167e0d5d58ee4f75c5c5c07c13eac758689729e7 (patch) | |
tree | e60823b1ab57b57fa580bcff31b4057897e53c95 | |
parent | ee960929ea8b70f4d21737b058885a8174cf78ad (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.txt | 2 | ||||
-rw-r--r-- | src/datasources/qmldesignerusageeventsource.cpp | 68 | ||||
-rw-r--r-- | src/datasources/qmldesignerusageeventsource.h | 13 | ||||
-rw-r--r-- | src/images/star_empty.png | bin | 0 -> 876 bytes | |||
-rw-r--r-- | src/images/star_empty@2x.png | bin | 0 -> 1688 bytes | |||
-rw-r--r-- | src/images/star_filled.png | bin | 0 -> 669 bytes | |||
-rw-r--r-- | src/images/star_filled@2x.png | bin | 0 -> 1246 bytes | |||
-rw-r--r-- | src/src.pro | 2 | ||||
-rw-r--r-- | src/ui/FeedbackPopup.qml | 164 | ||||
-rw-r--r-- | src/usagestatistic.qrc | 5 |
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 Binary files differnew file mode 100644 index 0000000..3ea5966 --- /dev/null +++ b/src/images/star_empty.png diff --git a/src/images/star_empty@2x.png b/src/images/star_empty@2x.png Binary files differnew file mode 100644 index 0000000..a06ef89 --- /dev/null +++ b/src/images/star_empty@2x.png diff --git a/src/images/star_filled.png b/src/images/star_filled.png Binary files differnew file mode 100644 index 0000000..0180fde --- /dev/null +++ b/src/images/star_filled.png diff --git a/src/images/star_filled@2x.png b/src/images/star_filled@2x.png Binary files differnew file mode 100644 index 0000000..2d8be01 --- /dev/null +++ b/src/images/star_filled@2x.png 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> |