diff options
-rw-r--r-- | src/datasources/qmldesignerusageeventsource.cpp | 97 | ||||
-rw-r--r-- | src/datasources/qmldesignerusageeventsource.h | 10 | ||||
-rw-r--r-- | src/images/star_empty.png | bin | 876 -> 0 bytes | |||
-rw-r--r-- | src/images/star_empty@2x.png | bin | 1688 -> 0 bytes | |||
-rw-r--r-- | src/images/star_filled.png | bin | 669 -> 0 bytes | |||
-rw-r--r-- | src/images/star_filled@2x.png | bin | 1246 -> 0 bytes | |||
-rw-r--r-- | src/ui/FeedbackPopup.qml | 158 | ||||
-rw-r--r-- | src/usagestatistic.qrc | 5 | ||||
-rw-r--r-- | src/usagestatisticplugin.cpp | 32 | ||||
-rw-r--r-- | src/usagestatisticplugin.h | 1 |
10 files changed, 77 insertions, 226 deletions
diff --git a/src/datasources/qmldesignerusageeventsource.cpp b/src/datasources/qmldesignerusageeventsource.cpp index 06fc090..3a2d571 100644 --- a/src/datasources/qmldesignerusageeventsource.cpp +++ b/src/datasources/qmldesignerusageeventsource.cpp @@ -55,7 +55,7 @@ const char qmlDesignerFeedbackTextKey[] = "qmlDesignerFeedbackTextKey"; const char qmlDesignerFeedbackRatingKey[] = "qmlDesignerFeedbackRatingKey"; const char qmlDesignerFeedbackPoppedKey[] = "qmlDesignerFeedbackPoppedKey"; -QmlDesignerUsageEventSource::QmlDesignerUsageEventSource() +QmlDesignerUsageEventSource::QmlDesignerUsageEventSource(bool enabled) : KUserFeedback::AbstractDataSource("qmlDesignerUsageEvents", Provider::DetailedUsageStatistics) { const auto plugins = ExtensionSystem::PluginManager::plugins(); @@ -66,11 +66,28 @@ QmlDesignerUsageEventSource::QmlDesignerUsageEventSource() SIGNAL(usageStatisticsNotifier(QString)), this, SLOT(handleUsageStatisticsNotifier(QString))); + + connect(qmlDesignerPlugin, + SIGNAL(usageStatisticsUsageTimer(QString, int)), + this, + SLOT(handleUsageStatisticsUsageTimer(QString, int))); + + connect(qmlDesignerPlugin, + SIGNAL(usageStatisticsUsageDuration(QString, int)), + this, + SLOT(handleUsageStatisticsUsageDuration(QString, int))); + connect(qmlDesignerPlugin, - SIGNAL(usageStatisticsUsageTimer(QString,int)), + SIGNAL(usageStatisticsInsertFeedback(QString, QString, int)), this, - SLOT(handleUsageStatisticsUsageTimer(QString,int))); + SLOT(insertFeedback(QString, QString, int))); + + connect(this, + SIGNAL(launchPopup(QString)), + qmlDesignerPlugin, + SLOT(lauchFeedbackPopup(QString))); } + m_enabled = enabled; } QString QmlDesignerUsageEventSource::name() const @@ -83,41 +100,14 @@ 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) +void QmlDesignerUsageEventSource::insertFeedback(const QString &identifier, + const QString &feedback, + int rating) { if (!feedback.isEmpty()) - m_feedbackTextData.insert(currentIdentifier, feedback); + m_feedbackTextData.insert(identifier, 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(QString,int))); - QObject::connect(root, SIGNAL(closeClicked()), this, SLOT(closeFeedbackPopup())); - } - - m_feedbackWidget->show(); + m_feedbackRatingData.insert(identifier, rating); } void QmlDesignerUsageEventSource::handleUsageStatisticsNotifier(const QString &identifier) @@ -137,30 +127,33 @@ void QmlDesignerUsageEventSource::handleUsageStatisticsUsageTimer(const QString if (it != m_timeData.end()) { it.value() = it.value().toInt() + elapsed; - // Show the user feedback prompt after time limit is passed - static const QSet<QString> supportedViews{"formEditor", - "3DEditor", - "statesEditor,", - "timeline", - "itemLibrary", - "assetsLibrary", - "transitionEditor", - "curveEditor", - "propertyEditor", - "textEditor", - "materialBrowser", - "navigatorView"}; - static const int timeLimit = 864'000'00; // 1 day - if (supportedViews.contains(identifier) && !m_feedbackPoppedData[identifier].toBool() - && m_timeData.value(identifier).toInt() >= timeLimit) { - launchPopup(identifier); + static const int timeLimit = 14400000; // 4 hours + if (m_enabled && !m_feedbackPoppedData[identifier].toBool() + && m_timeData.value(identifier).toInt() >= timeLimit) { m_feedbackPoppedData[identifier] = QVariant(true); + emit launchPopup(identifier); } } else { m_timeData.insert(identifier, elapsed); } } +void QmlDesignerUsageEventSource::handleUsageStatisticsUsageDuration(const QString &identifier, + int elapsed) +{ + auto it = m_eventData.find(identifier); + + if (it != m_eventData.end()) { + QVariantList list = it.value().toList(); + list.append(elapsed); + it.value() = list; + } else { + QVariantList list; + list.append(elapsed); + m_eventData.insert(identifier, list); + } +} + QVariant QmlDesignerUsageEventSource::data() { return QVariantMap{{qmlDesignerEventsKey, m_eventData}, {qmlDesignerTimesKey, m_timeData}, diff --git a/src/datasources/qmldesignerusageeventsource.h b/src/datasources/qmldesignerusageeventsource.h index 9843555..99c5db3 100644 --- a/src/datasources/qmldesignerusageeventsource.h +++ b/src/datasources/qmldesignerusageeventsource.h @@ -38,7 +38,7 @@ class QmlDesignerUsageEventSource : public QObject, public KUserFeedback::Abstra Q_OBJECT public: - QmlDesignerUsageEventSource(); + QmlDesignerUsageEventSource(bool enabled); public: QString name() const override; @@ -51,13 +51,14 @@ public: void storeImpl(QSettings *settings) override; void resetImpl(QSettings *settings) override; +signals: 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(); + void handleUsageStatisticsUsageDuration(const QString &identifier, int elapsed); + void insertFeedback(const QString &identifier, const QString &feedback, int rating); private: QMap<QString, QVariant> m_eventData; @@ -67,7 +68,8 @@ private: QHash<QString, QVariant> m_feedbackTextData; QHash<QString, QVariant> m_feedbackRatingData; QHash<QString, QVariant> m_feedbackPoppedData; - QPointer<QQuickWidget> m_feedbackWidget; + + bool m_enabled = false; }; } // namespace Internal diff --git a/src/images/star_empty.png b/src/images/star_empty.png Binary files differdeleted file mode 100644 index 3ea5966..0000000 --- a/src/images/star_empty.png +++ /dev/null diff --git a/src/images/star_empty@2x.png b/src/images/star_empty@2x.png Binary files differdeleted file mode 100644 index a06ef89..0000000 --- a/src/images/star_empty@2x.png +++ /dev/null diff --git a/src/images/star_filled.png b/src/images/star_filled.png Binary files differdeleted file mode 100644 index 0180fde..0000000 --- a/src/images/star_filled.png +++ /dev/null diff --git a/src/images/star_filled@2x.png b/src/images/star_filled@2x.png Binary files differdeleted file mode 100644 index 2d8be01..0000000 --- a/src/images/star_filled@2x.png +++ /dev/null diff --git a/src/ui/FeedbackPopup.qml b/src/ui/FeedbackPopup.qml deleted file mode 100644 index a8b5455..0000000 --- a/src/ui/FeedbackPopup.qml +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************** -** -** 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.Window 2.15 - -Rectangle { - id: root_rectangle - - property int rating: 0 - - 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 { - text: "Skip" - color: parent.hovered ? Qt.darker("#999999", 1.9) : Qt.darker("#999999", 1.2) - font { family: "Titillium"; pixelSize: 14 } - horizontalAlignment: Text.AlignHCenter - } - - background: Rectangle { - anchors.fill: parent - color: "#ffffff" - border { color: "#999999"; width: 1 } - } - - onClicked: root_rectangle.closeClicked() - } - - Button { - id: buttonSubmit - - width: 80 - height: 28 - enabled: rating > 0 - - contentItem: Text { - text: "Submit"; - color: enabled ? "white" : Qt.lighter("#999999", 1.3) - font { family: "Titillium"; pixelSize: 14 } - horizontalAlignment: Text.AlignHCenter - } - - background: Rectangle { - anchors.fill: parent - color: enabled ? parent.hovered ? Qt.lighter("#0094ce", 1.2) : "#0094ce" : "white" - border { color: enabled ? "#999999" : Qt.lighter("#999999", 1.3); width: 1 } - } - - onClicked: { - root_rectangle.submitFeedback(textarea.text, rating); - root_rectangle.closeClicked(); - } - } - } -} diff --git a/src/usagestatistic.qrc b/src/usagestatistic.qrc index f0b34f8..8ab02df 100644 --- a/src/usagestatistic.qrc +++ b/src/usagestatistic.qrc @@ -2,10 +2,5 @@ <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> diff --git a/src/usagestatisticplugin.cpp b/src/usagestatisticplugin.cpp index 992e4b1..e34e851 100644 --- a/src/usagestatisticplugin.cpp +++ b/src/usagestatisticplugin.cpp @@ -65,6 +65,7 @@ #include "common/utils.h" #include <QGuiApplication> +#include <QTimer> namespace UsageStatistic { namespace Internal { @@ -73,6 +74,11 @@ UsageStatisticPlugin::UsageStatisticPlugin() = default; UsageStatisticPlugin::~UsageStatisticPlugin() = default; +static bool telemetryLevelNotSet(const KUserFeedback::Provider &provider) +{ + return provider.telemetryMode() == KUserFeedback::Provider::NoTelemetry; +} + bool UsageStatisticPlugin::initialize(const QStringList &arguments, QString *errorString) { Q_UNUSED(arguments) @@ -111,7 +117,7 @@ static void addQtCreatorDataSources(KUserFeedback::Provider &provider) provider.addDataSource(new ExamplesDataSource); provider.addDataSource(new KitSource); provider.addDataSource(new QmlDesignerUsageTimeSource); - provider.addDataSource(new QmlDesignerUsageEventSource); + provider.addDataSource(new QmlDesignerUsageEventSource(!telemetryLevelNotSet(provider))); } static void addServiceDataSource(const std::shared_ptr<KUserFeedback::Provider> &provider) @@ -136,12 +142,16 @@ bool UsageStatisticPlugin::delayedInitialize() restoreSettings(); showFirstTimeMessage(); + submitDataOnFirstStart(); return true; } ExtensionSystem::IPlugin::ShutdownFlag UsageStatisticPlugin::aboutToShutdown() { + if (m_provider) + m_provider->submit(); + storeSettings(); return SynchronousShutdown; @@ -173,7 +183,10 @@ void UsageStatisticPlugin::restoreSettings() static constexpr int encouragementTimeSec() { return 1800; } static constexpr int encouragementIntervalDays() { return 1; } -static constexpr int submissionIntervalDays() { return 10; } +static constexpr int submissionIntervalDays() +{ + return 1; +} void UsageStatisticPlugin::createProvider() { @@ -206,11 +219,6 @@ static bool runFirstTime(const KUserFeedback::Provider &provider) return false; } -static bool telemetryLevelNotSet(const KUserFeedback::Provider &provider) -{ - return provider.telemetryMode() == KUserFeedback::Provider::NoTelemetry; -} - void UsageStatisticPlugin::showFirstTimeMessage() { if (m_provider && runFirstTime(*m_provider) && telemetryLevelNotSet(*m_provider)) { @@ -218,6 +226,16 @@ void UsageStatisticPlugin::showFirstTimeMessage() } } +void UsageStatisticPlugin::submitDataOnFirstStart() +{ + /* + * On first start submit data after 10 minutes. + */ + + if (m_provider && runFirstTime(*m_provider) && !telemetryLevelNotSet(*m_provider)) + QTimer::singleShot(1000 * 60 * 10, this, [this]() { m_provider->submit(); }); +} + static ::Utils::InfoBarEntry makeInfoBarEntry() { static auto infoText = UsageStatisticPlugin::tr( diff --git a/src/usagestatisticplugin.h b/src/usagestatisticplugin.h index 0fb6278..a74624e 100644 --- a/src/usagestatisticplugin.h +++ b/src/usagestatisticplugin.h @@ -59,6 +59,7 @@ private: void createProvider(); void showEncouragementMessage(); void showFirstTimeMessage(); + void submitDataOnFirstStart(); private: std::shared_ptr<KUserFeedback::Provider> m_provider; |