Commit 839ff9f5 authored by Marco Martin's avatar Marco Martin
Browse files

Put user feedback in landing page

Replace the Baloo settings with the user feedback in the landing page. This is hopefully a way to make more people enable feedback
parent aa76fa99
......@@ -69,6 +69,9 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
)
find_package(AccountsQt5 ${ACCOUNTSQT_DEP_VERSION} CONFIG)
find_package(KUserFeedback)
set_package_properties(AccountsQt5 PROPERTIES DESCRIPTION "Accounts management library for Qt applications"
URL "https://gitlab.com/accounts-sso/libaccounts-qt"
TYPE OPTIONAL
......
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_landingpage\")
set(HAVE_KUSERFEEDBACK ${KUserFeedback_FOUND})
configure_file(config-landingpage.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-landingpage.h)
########### next target ###############
set(kcm_landingpage_SRCS
landingpage.cpp
......@@ -11,12 +15,12 @@ kcmutils_generate_module_data(
kcm_landingpage_SRCS
MODULE_DATA_HEADER landingpagedata.h
MODULE_DATA_CLASS_NAME LandingPageData
SETTINGS_HEADERS landingpage_kdeglobalssettings.h landingpage_baloosettings.h
SETTINGS_CLASSES LandingPageGlobalsSettings BalooSettings
SETTINGS_HEADERS landingpage_kdeglobalssettings.h landingpage_feedbacksettings.h
SETTINGS_CLASSES LandingPageGlobalsSettings FeedbackSettings
)
kconfig_add_kcfg_files(kcm_landingpage_SRCS landingpage_kdeglobalssettings.kcfgc GENERATE_MOC)
kconfig_add_kcfg_files(kcm_landingpage_SRCS landingpage_baloosettings.kcfgc GENERATE_MOC)
kconfig_add_kcfg_files(kcm_landingpage_SRCS landingpage_feedbacksettings.kcfgc GENERATE_MOC)
add_library(kcm_landingpage MODULE ${kcm_landingpage_SRCS})
......@@ -36,11 +40,15 @@ if(X11_FOUND)
target_link_libraries(kcm_landingpage ${X11_LIBRARIES} Qt5::X11Extras)
endif()
if (KUserFeedback_FOUND)
target_link_libraries(kcm_landingpage KUserFeedbackCore)
endif()
kcoreaddons_desktop_to_json(kcm_landingpage "kcm_landingpage.desktop" SERVICE_TYPES kcmodule.desktop)
########### install files ###############
install(FILES landingpage_kdeglobalssettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install(FILES landingpage_baloosettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install(FILES landingpage_feedbacksettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install(FILES kcm_landingpage.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
install(TARGETS kcm_landingpage DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
......
#cmakedefine01 HAVE_KUSERFEEDBACK
......@@ -40,7 +40,7 @@
#include "landingpagedata.h"
#include "landingpage_kdeglobalssettings.h"
#include "landingpage_baloosettings.h"
#include "landingpage_feedbacksettings.h"
#include <KActivities/Stats/ResultModel>
#include <KActivities/Stats/ResultSet>
......@@ -56,6 +56,9 @@ using namespace KAStats::Terms;
K_PLUGIN_FACTORY_WITH_JSON(KCMLandingPageFactory, "kcm_landingpage.json", registerPlugin<KCMLandingPage>(); registerPlugin<LandingPageData>();)
// Program to icon hash
static QHash<QString, QString> s_programs = {{"plasmashell", "plasmashell"}, {"plasma-discover", "plasmadiscover"}};
MostUsedModel::MostUsedModel(QObject *parent)
: QSortFilterProxyModel (parent)
......@@ -177,7 +180,7 @@ KCMLandingPage::KCMLandingPage(QObject *parent, const QVariantList &args)
, m_data(new LandingPageData(this))
{
qmlRegisterType<LandingPageGlobalsSettings>();
qmlRegisterType<BalooSettings>();
qmlRegisterType<FeedbackSettings>();
qmlRegisterType<MostUsedModel>();
qmlRegisterType<LookAndFeelGroup>();
......@@ -203,6 +206,76 @@ KCMLandingPage::KCMLandingPage(QObject *parent, const QVariantList &args)
connect(globalsSettings(), &LandingPageGlobalsSettings::lookAndFeelPackageChanged,
this, [this]() {m_lnfDirty = true;});
QVector<QProcess *> processes;
for (const auto &exec : s_programs.keys()) {
QProcess *p = new QProcess(this);
p->setProgram(exec);
p->setArguments({QStringLiteral("--feedback")});
p->start();
connect(p, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &KCMLandingPage::programFinished);
processes << p;
}
}
inline void swap(QJsonValueRef v1, QJsonValueRef v2)
{
QJsonValue temp(v1);
v1 = QJsonValue(v2);
v2 = temp;
}
void KCMLandingPage::programFinished(int exitCode)
{
auto mo = KUserFeedback::Provider::staticMetaObject;
const int modeEnumIdx = mo.indexOfEnumerator("TelemetryMode");
Q_ASSERT(modeEnumIdx >= 0);
const auto modeEnum = mo.enumerator(modeEnumIdx);
QProcess *p = qobject_cast<QProcess *>(sender());
const QString program = p->program();
if (exitCode) {
qWarning() << "Could not check" << program;
return;
}
QTextStream stream(p);
for (QString line; stream.readLineInto(&line);) {
int sepIdx = line.indexOf(QLatin1String(": "));
if (sepIdx < 0) {
break;
}
const QString mode = line.left(sepIdx);
bool ok;
const int modeValue = modeEnum.keyToValue(qPrintable(mode), &ok);
if (!ok) {
qWarning() << "error:" << mode << "is not a valid mode";
continue;
}
const QString description = line.mid(sepIdx + 1);
m_uses[modeValue][description] << s_programs[program];
}
p->deleteLater();
#if HAVE_KUSERFEEDBACK
m_feedbackSources = {};
for (auto it = m_uses.constBegin(), itEnd = m_uses.constEnd(); it != itEnd; ++it) {
const auto modeUses = *it;
for (auto itMode = modeUses.constBegin(), itModeEnd = modeUses.constEnd(); itMode != itModeEnd; ++itMode) {
m_feedbackSources << QJsonObject({{"mode", it.key()}, {"icons", *itMode}, {"description", itMode.key()}});
}
}
std::sort(m_feedbackSources.begin(), m_feedbackSources.end(), [](const QJsonValue &valueL, const QJsonValue &valueR) {return true;
const QJsonObject objL(valueL.toObject()), objR(valueR.toObject());
const auto modeL = objL["mode"].toInt(), modeR = objR["mode"].toInt();
return modeL < modeR || (modeL == modeR && objL["description"].toString() < objR["description"].toString());
});
Q_EMIT feedbackSourcesChanged();
#endif
}
MostUsedModel *KCMLandingPage::mostUsedModel() const
......@@ -215,11 +288,19 @@ LandingPageGlobalsSettings *KCMLandingPage::globalsSettings() const
return m_data->landingPageGlobalsSettings();
}
BalooSettings *KCMLandingPage::balooSettings() const
#if HAVE_KUSERFEEDBACK
bool KCMLandingPage::feedbackEnabled() const
{
return m_data->balooSettings();
KUserFeedback::Provider p;
return p.isEnabled();
}
FeedbackSettings *KCMLandingPage::feedbackSettings() const
{
return m_data->feedbackSettings();
}
#endif
void KCMLandingPage::save()
{
ManagedConfigModule::save();
......@@ -231,19 +312,6 @@ void KCMLandingPage::save()
message.setArguments(args);
QDBusConnection::sessionBus().send(message);
// Update Baloo config or start/stop Baloo
if (balooSettings()->indexingEnabled()) {
// Trying to start baloo when it is already running is fine
const QString exe = QStandardPaths::findExecutable(QStringLiteral("baloo_file"));
QProcess::startDetached(exe, QStringList());
} else {
QDBusMessage message =
QDBusMessage::createMethodCall(QStringLiteral("org.kde.baloo"), QStringLiteral("/"), QStringLiteral("org.kde.baloo.main"), QStringLiteral("quit"));
QDBusConnection::sessionBus().asyncCall(message);
}
if (m_lnfDirty) {
QProcess::startDetached(QStringLiteral("plasma-apply-lookandfeel"), QStringList({QStringLiteral("-a"), m_data->landingPageGlobalsSettings()->lookAndFeelPackage()}));
}
......
......@@ -20,16 +20,19 @@
#ifndef _KCM_LANDINGPAGE_H
#define _KCM_LANDINGPAGE_H
#include "config-landingpage.h"
#include <KQuickAddons/ManagedConfigModule>
#include <KPackage/Package>
#include <QJsonValue>
#include <QJsonArray>
class QStandardItemModel;
class LandingPageData;
class LandingPageGlobalsSettings;
class BalooSettings;
class BalooData;
class FeedbackSettings;
namespace KActivities {
namespace Stats {
......@@ -79,7 +82,11 @@ class KCMLandingPage : public KQuickAddons::ManagedConfigModule
Q_OBJECT
Q_PROPERTY(MostUsedModel *mostUsedModel READ mostUsedModel CONSTANT)
Q_PROPERTY(LandingPageGlobalsSettings *globalsSettings READ globalsSettings CONSTANT)
Q_PROPERTY(BalooSettings *balooSettings READ balooSettings CONSTANT)
#if HAVE_KUSERFEEDBACK
Q_PROPERTY(bool feedbackEnabled READ feedbackEnabled CONSTANT)
Q_PROPERTY(FeedbackSettings *feedbackSettings READ feedbackSettings CONSTANT)
Q_PROPERTY(QJsonArray feedbackSources MEMBER m_feedbackSources NOTIFY feedbackSourcesChanged)
#endif
Q_PROPERTY(LookAndFeelGroup *defaultLightLookAndFeel READ defaultLightLookAndFeel CONSTANT)
Q_PROPERTY(LookAndFeelGroup *defaultDarkLookAndFeel READ defaultDarkLookAndFeel CONSTANT)
......@@ -87,10 +94,16 @@ public:
KCMLandingPage(QObject *parent, const QVariantList &args);
~KCMLandingPage() override {}
void programFinished(int exitCode);
MostUsedModel *mostUsedModel() const;
LandingPageGlobalsSettings *globalsSettings() const;
BalooSettings *balooSettings() const;
#if HAVE_KUSERFEEDBACK
bool feedbackEnabled() const;
FeedbackSettings *feedbackSettings() const;
#endif
LookAndFeelGroup *defaultLightLookAndFeel() const;
LookAndFeelGroup *defaultDarkLookAndFeel() const;
......@@ -101,6 +114,11 @@ public:
public Q_SLOTS:
void save() override;
#if HAVE_KUSERFEEDBACK
Q_SIGNALS:
void feedbackSourcesChanged();
#endif
private:
LandingPageData *m_data;
......@@ -109,6 +127,10 @@ private:
MostUsedModel *m_mostUsedModel = nullptr;
QHash<int, QHash<QString, QJsonArray>> m_uses;
#if HAVE_KUSERFEEDBACK
QJsonArray m_feedbackSources;
#endif
bool m_lnfDirty = false;
};
......
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="baloofilerc" />
<group name="Basic Settings">
<entry name="IndexingEnabled" key="Indexing-Enabled" type="Bool">
<label>Enable file indexer</label>
<default>true</default>
</entry>
</group>
</kcfg>
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="PlasmaUserFeedback" />
<group name="Global">
<entry name="feedbackLevel" key="FeedbackLevel" type="Int">
<default code="true">KUserFeedback::Provider::NoTelemetry</default>
</entry>
</group>
</kcfg>
File=landingpage_baloosettings.kcfg
ClassName=BalooSettings
File=landingpage_feedbacksettings.kcfg
ClassName=FeedbackSettings
IncludeFiles="KUserFeedback/Provider"
Mutators=true
DefaultValueGetters=true
GenerateProperties=true
ParentInConstructor=true
Notifiers=Indexing-Enabled
/*
* Copyright 2021 Marco Martin <mart@kde.org>
* Copyright 2018 Furkan Tokac <furkantokac34@gmail.com>
* Copyright (C) 2019 Nate Graham <nate@kde.org>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.7
import QtQuick.Controls 2.5 as QQC2
import QtQuick.Layouts 1.3
import QtQuick.Window 2.2
import org.kde.kirigami 2.5 as Kirigami
import org.kde.kcm 1.6 as KCM
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.userfeedback 1.0 as UserFeedback
ColumnLayout {
property alias slider: statisticsModeSlider
enabled: kcm.feedbackEnabled
RowLayout {
QQC2.Slider {
id: statisticsModeSlider
readonly property var currentMode: modeOptions[value]
Layout.fillWidth: true
Layout.minimumWidth: Kirigami.Units.gridUnit * 21
Layout.maximumWidth: Kirigami.Units.gridUnit * 21
readonly property var modeOptions: [UserFeedback.Provider.NoTelemetry, UserFeedback.Provider.BasicSystemInformation, UserFeedback.Provider.BasicUsageStatistics,
UserFeedback.Provider.DetailedSystemInformation, UserFeedback.Provider.DetailedUsageStatistics]
from: 0
to: modeOptions.length - 1
stepSize: 1
snapMode: QQC2.Slider.SnapAlways
function findIndex(array, what, defaultValue) {
for (var v in array) {
if (array[v] == what)
return v;
}
return defaultValue;
}
value: findIndex(modeOptions, kcm.feedbackSettings.feedbackLevel, 0)
onMoved: {
kcm.feedbackSettings.feedbackLevel = modeOptions[value]
}
KCM.SettingStateBinding {
configObject: kcm.feedbackSettings
settingName: "feedbackLevel"
extraEnabledConditions: kcm.feedbackEnabled
}
UserFeedback.FeedbackConfigUiController {
id: feedbackController
applicationName: i18n("Plasma")
}
}
KCM.ContextualHelpButton {
toolTipText: {
let description = i18n("You can help KDE improve Plasma by contributing information on how you use it, so we can focus on things that matter to you.<nl/><nl/>Contributing this information is optional and entirely anonymous. We never collect your personal data, files you use, websites you visit, or information that could identify you.");
if (kcm.feedbackSettings.feedbackLevel === UserFeedback.Provider.NoTelemetry) {
return "<h4>" + i18n("No data will be sent.") + "</h4><nl/><p>" + description + "</p>";
}
let text = "<p>" + description + "</p><nl/><h4>" + i18n("The following information will be sent:") + "</h4><ul>";
for (let i in kcm.feedbackSources) {
text += "<li>" + kcm.feedbackSources[i].description + "</li>";
}
text += "</ul>";
return text;
}
}
}
QQC2.Label {
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: Kirigami.Units.gridUnit * 21
wrapMode: Text.WordWrap
text: feedbackController.telemetryName(statisticsModeSlider.currentMode)
}
}
......@@ -189,16 +189,17 @@ KCM.AbstractKCM {
}
Item {
Kirigami.FormData.isSection: false
// This is outside the loaded in order to have perfect label alignemnt
Layout.preferredHeight: Kirigami.Units.smallSpacing
visible: feedbackLoader.visible
}
QQC2.CheckBox {
Kirigami.FormData.label: i18n("File Indexing:")
text: i18n("Enabled")
checked: kcm.balooSettings.indexingEnabled
onToggled: {
kcm.balooSettings.indexingEnabled = checked
}
// This is in a loader because the import FeedbackControls uses won't always exist being KUserFeedback optional
Loader {
id: feedbackLoader
visible: item !== null
Kirigami.FormData.label: item ? i18n("Send User Feedback:") : ""
Kirigami.FormData.buddyFor: item ? item.slider : null
source: Qt.resolvedUrl("FeedbackControls.qml")
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment