kcm: Add vibration setting for shell, and add vibrations

We can control shell vibrations from here, which can be replaced once there is a mechanism to control system-wide vibrations for QtFeedback.
This commit is contained in:
Devin Lin 2022-04-29 16:15:53 -04:00
parent 151bb9dbfc
commit 3353cfc498
14 changed files with 129 additions and 2 deletions

View file

@ -46,6 +46,7 @@ find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED
Qml Qml
Quick Quick
QuickCompiler QuickCompiler
Feedback
) )
if (QUICK_COMPILER) if (QUICK_COMPILER)

View file

@ -6,6 +6,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
set(mobileshellplugin_SRCS set(mobileshellplugin_SRCS
mobileshellplugin.cpp mobileshellplugin.cpp
haptics.cpp
mobileshellsettings.cpp mobileshellsettings.cpp
quicksetting.cpp quicksetting.cpp
quicksettingsmodel.cpp quicksettingsmodel.cpp
@ -37,6 +38,7 @@ target_link_libraries(mobileshellplugin
Qt::Qml Qt::Qml
Qt::Gui Qt::Gui
Qt::Quick Qt::Quick
Qt::Feedback
KF5::ConfigWidgets # for KStandardAction KF5::ConfigWidgets # for KStandardAction
KF5::KIOGui KF5::KIOGui
KF5::Plasma KF5::Plasma

View file

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "haptics.h"
#include <QFeedbackHapticsEffect>
#include "mobileshellsettings.h"
Haptics *Haptics::self()
{
static Haptics *singleton = new Haptics();
return singleton;
}
void Haptics::buttonVibrate()
{
if (MobileShellSettings::self()->vibrationsEnabled()) {
QFeedbackHapticsEffect rumble;
rumble.setIntensity(0.5);
rumble.setDuration(100);
rumble.start();
}
}

View file

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QObject>
class Haptics : public QObject
{
Q_OBJECT
public:
static Haptics *self();
Q_INVOKABLE void buttonVibrate();
};

View file

@ -19,6 +19,7 @@
#include "taskswitcher/displaysmodel.h" #include "taskswitcher/displaysmodel.h"
#include "haptics.h"
#include "mobileshellsettings.h" #include "mobileshellsettings.h"
#include "quicksetting.h" #include "quicksetting.h"
#include "quicksettingsmodel.h" #include "quicksettingsmodel.h"
@ -38,6 +39,10 @@ void MobileShellPlugin::registerTypes(const char *uri)
return ShellUtil::instance(); return ShellUtil::instance();
}); });
qmlRegisterSingletonType<Haptics>(uri, 1, 0, "Haptics", [](QQmlEngine *, QJSEngine *) -> QObject * {
return Haptics::self();
});
qmlRegisterSingletonType<MobileShellSettings>(uri, 1, 0, "MobileShellSettings", [](QQmlEngine *, QJSEngine *) -> QObject * { qmlRegisterSingletonType<MobileShellSettings>(uri, 1, 0, "MobileShellSettings", [](QQmlEngine *, QJSEngine *) -> QObject * {
return MobileShellSettings::self(); return MobileShellSettings::self();
}); });

View file

@ -26,6 +26,7 @@ MobileShellSettings::MobileShellSettings(QObject *parent)
connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) -> void { connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) -> void {
if (group.name() == GENERAL_CONFIG_GROUP) { if (group.name() == GENERAL_CONFIG_GROUP) {
Q_EMIT vibrationsEnabledChanged();
Q_EMIT navigationPanelEnabledChanged(); Q_EMIT navigationPanelEnabledChanged();
} else if (group.name() == QUICKSETTINGS_CONFIG_GROUP) { } else if (group.name() == QUICKSETTINGS_CONFIG_GROUP) {
Q_EMIT enabledQuickSettingsChanged(); Q_EMIT enabledQuickSettingsChanged();
@ -34,6 +35,19 @@ MobileShellSettings::MobileShellSettings(QObject *parent)
}); });
} }
bool MobileShellSettings::vibrationsEnabled() const
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
return group.readEntry("vibrationsEnabled", true);
}
void MobileShellSettings::setVibrationsEnabled(bool vibrationsEnabled)
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
group.writeEntry("vibrationsEnabled", vibrationsEnabled, KConfigGroup::Notify);
m_config->sync();
}
bool MobileShellSettings::navigationPanelEnabled() const bool MobileShellSettings::navigationPanelEnabled() const
{ {
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP}; auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};

View file

@ -14,6 +14,7 @@
class MobileShellSettings : public QObject class MobileShellSettings : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool vibrationsEnabled READ vibrationsEnabled WRITE setVibrationsEnabled NOTIFY vibrationsEnabledChanged)
Q_PROPERTY(bool navigationPanelEnabled READ navigationPanelEnabled WRITE setNavigationPanelEnabled NOTIFY navigationPanelEnabledChanged) Q_PROPERTY(bool navigationPanelEnabled READ navigationPanelEnabled WRITE setNavigationPanelEnabled NOTIFY navigationPanelEnabledChanged)
public: public:
@ -21,6 +22,9 @@ public:
MobileShellSettings(QObject *parent = nullptr); MobileShellSettings(QObject *parent = nullptr);
bool vibrationsEnabled() const;
void setVibrationsEnabled(bool vibrationsEnabled);
bool navigationPanelEnabled() const; bool navigationPanelEnabled() const;
void setNavigationPanelEnabled(bool navigationPanelEnabled); void setNavigationPanelEnabled(bool navigationPanelEnabled);
@ -31,6 +35,7 @@ public:
void setDisabledQuickSettings(QList<QString> &list); void setDisabledQuickSettings(QList<QString> &list);
Q_SIGNALS: Q_SIGNALS:
void vibrationsEnabledChanged();
void navigationPanelEnabledChanged(); void navigationPanelEnabledChanged();
void enabledQuickSettingsChanged(); void enabledQuickSettingsChanged();
void disabledQuickSettingsChanged(); void disabledQuickSettingsChanged();

View file

@ -12,6 +12,7 @@ import org.kde.kirigami 2.12 as Kirigami
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.private.nanoshell 2.0 as NanoShell import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
import "../../components" as Components import "../../components" as Components
@ -41,8 +42,14 @@ QuickSettingsDelegate {
contentItem: MouseArea { contentItem: MouseArea {
id: mouseArea id: mouseArea
onPressed: MobileShell.Haptics.buttonVibrate()
onClicked: root.delegateClick() onClicked: root.delegateClick()
onPressAndHold: root.delegatePressAndHold() onPressAndHold: {
MobileShell.Haptics.buttonVibrate();
root.delegatePressAndHold();
}
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
PlasmaCore.IconItem { PlasmaCore.IconItem {

View file

@ -11,6 +11,7 @@ import org.kde.kirigami 2.12 as Kirigami
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.private.nanoshell 2.0 as NanoShell import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
import "../../components" as Components import "../../components" as Components
@ -37,8 +38,14 @@ QuickSettingsDelegate {
contentItem: MouseArea { contentItem: MouseArea {
id: mouseArea id: mouseArea
onPressed: MobileShell.Haptics.buttonVibrate();
onClicked: root.delegateClick() onClicked: root.delegateClick()
onPressAndHold: root.delegatePressAndHold() onPressAndHold: {
MobileShell.Haptics.buttonVibrate();
root.delegatePressAndHold();
}
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
PlasmaCore.IconItem { PlasmaCore.IconItem {

View file

@ -61,6 +61,9 @@ Item {
startMouseX = oldMouseX = mouse.y; startMouseX = oldMouseX = mouse.y;
startMouseY = oldMouseY = mouse.y; startMouseY = oldMouseY = mouse.y;
activeButton = icons.childAt(mouse.x, mouse.y); activeButton = icons.childAt(mouse.x, mouse.y);
if (activeButton && activeButton.enabled) {
MobileShell.Haptics.buttonVibrate();
}
} }
onPositionChanged: { onPositionChanged: {

View file

@ -30,6 +30,30 @@ KCM.SimpleKCM {
MobileForm.FormCard { MobileForm.FormCard {
Layout.fillWidth: true Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
title: i18n("General")
}
MobileForm.FormSwitchDelegate {
text: i18n("Shell Vibrations")
description: i18n("Whether to have vibrations enabled in the shell.")
checked: !MobileShell.MobileShellSettings.vibrationsEnabled
onCheckedChanged: {
if (checked != !MobileShell.MobileShellSettings.vibrationsEnabled) {
MobileShell.MobileShellSettings.vibrationsEnabled = !checked;
}
}
}
}
}
MobileForm.FormCard {
Layout.fillWidth: true
Layout.topMargin: Kirigami.Units.largeSpacing
contentItem: ColumnLayout { contentItem: ColumnLayout {
spacing: 0 spacing: 0

View file

@ -8,9 +8,12 @@ import QtQuick 2.12
import QtQuick.Controls 2.1 import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.12 import QtGraphicalEffects 1.12
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.workspace.keyboardlayout 1.0 import org.kde.plasma.workspace.keyboardlayout 1.0
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.kirigami 2.12 as Kirigami import org.kde.kirigami 2.12 as Kirigami
Rectangle { Rectangle {
@ -188,6 +191,7 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
onPressedChanged: { onPressedChanged: {
if (pressed) { if (pressed) {
MobileShell.Haptics.buttonVibrate();
parent.color = keypadRoot.buttonPressedColor; parent.color = keypadRoot.buttonPressedColor;
} else { } else {
parent.color = keypadRoot.buttonColor; parent.color = keypadRoot.buttonColor;
@ -205,6 +209,7 @@ Rectangle {
} }
onPressAndHold: { onPressAndHold: {
if (modelData === "R") { if (modelData === "R") {
MobileShell.Haptics.buttonVibrate();
passwordBar.clear(); passwordBar.clear();
} }
} }

View file

@ -5,8 +5,10 @@
*/ */
import QtQuick 2.8 import QtQuick 2.8
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
Item { Item {
id: root id: root
@ -19,6 +21,7 @@ Item {
property alias circleVisiblity: iconCircle.visible property alias circleVisiblity: iconCircle.visible
property int fontSize: config.fontSize property int fontSize: config.fontSize
readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software
signal clicked signal clicked
activeFocusOnTab: true activeFocusOnTab: true
@ -102,6 +105,7 @@ Item {
id: mouseArea id: mouseArea
hoverEnabled: true hoverEnabled: true
onClicked: root.clicked() onClicked: root.clicked()
onPressed: MobileShell.Haptics.buttonVibrate();
anchors.fill: parent anchors.fill: parent
} }

View file

@ -13,6 +13,7 @@ import QtQuick.Controls 2.8 as Controls
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kcoreaddons 1.0 as KCoreAddons import org.kde.kcoreaddons 1.0 as KCoreAddons
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.private.sessions 2.0 import org.kde.plasma.private.sessions 2.0
PlasmaCore.ColorScope { PlasmaCore.ColorScope {
@ -27,6 +28,8 @@ PlasmaCore.ColorScope {
signal cancelRequested() signal cancelRequested()
signal lockScreenRequested() signal lockScreenRequested()
Component.onCompleted: MobileShell.Haptics.buttonVibrate();
Controls.Action { Controls.Action {
onTriggered: root.cancelRequested() onTriggered: root.cancelRequested()
shortcut: "Escape" shortcut: "Escape"
@ -55,6 +58,7 @@ PlasmaCore.ColorScope {
ParallelAnimation { ParallelAnimation {
id: openAnim id: openAnim
running: true
ScaleAnimator { ScaleAnimator {
target: lay target: lay
from: 10 from: 10
@ -80,6 +84,8 @@ PlasmaCore.ColorScope {
SequentialAnimation { SequentialAnimation {
id: closeAnim id: closeAnim
running: false
property var callback property var callback
function execute(call) { function execute(call) {
callback = call; callback = call;