From 3353cfc4988104478606944550171a182eb5d511 Mon Sep 17 00:00:00 2001 From: Devin Lin Date: Fri, 29 Apr 2022 16:15:53 -0400 Subject: [PATCH] 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. --- CMakeLists.txt | 1 + components/mobileshell/CMakeLists.txt | 2 ++ components/mobileshell/haptics.cpp | 26 +++++++++++++++++++ components/mobileshell/haptics.h | 18 +++++++++++++ components/mobileshell/mobileshellplugin.cpp | 5 ++++ .../mobileshell/mobileshellsettings.cpp | 14 ++++++++++ components/mobileshell/mobileshellsettings.h | 5 ++++ .../QuickSettingsFullDelegate.qml | 9 ++++++- .../QuickSettingsMinimizedDelegate.qml | 9 ++++++- .../qml/navigationpanel/NavigationPanel.qml | 3 +++ kcms/mobileshell/package/contents/ui/main.qml | 24 +++++++++++++++++ look-and-feel/contents/lockscreen/Keypad.qml | 5 ++++ .../contents/logout/ActionButton.qml | 4 +++ look-and-feel/contents/logout/Logout.qml | 6 +++++ 14 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 components/mobileshell/haptics.cpp create mode 100644 components/mobileshell/haptics.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b8ea595..11155b6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Qml Quick QuickCompiler + Feedback ) if (QUICK_COMPILER) diff --git a/components/mobileshell/CMakeLists.txt b/components/mobileshell/CMakeLists.txt index 12bb431e..60e059e0 100644 --- a/components/mobileshell/CMakeLists.txt +++ b/components/mobileshell/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) set(mobileshellplugin_SRCS mobileshellplugin.cpp + haptics.cpp mobileshellsettings.cpp quicksetting.cpp quicksettingsmodel.cpp @@ -37,6 +38,7 @@ target_link_libraries(mobileshellplugin Qt::Qml Qt::Gui Qt::Quick + Qt::Feedback KF5::ConfigWidgets # for KStandardAction KF5::KIOGui KF5::Plasma diff --git a/components/mobileshell/haptics.cpp b/components/mobileshell/haptics.cpp new file mode 100644 index 00000000..85b6f738 --- /dev/null +++ b/components/mobileshell/haptics.cpp @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2022 Devin Lin + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "haptics.h" + +#include + +#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(); + } +} diff --git a/components/mobileshell/haptics.h b/components/mobileshell/haptics.h new file mode 100644 index 00000000..549008e7 --- /dev/null +++ b/components/mobileshell/haptics.h @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2022 Devin Lin + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include + +class Haptics : public QObject +{ + Q_OBJECT + +public: + static Haptics *self(); + + Q_INVOKABLE void buttonVibrate(); +}; diff --git a/components/mobileshell/mobileshellplugin.cpp b/components/mobileshell/mobileshellplugin.cpp index d3444a45..536954ca 100644 --- a/components/mobileshell/mobileshellplugin.cpp +++ b/components/mobileshell/mobileshellplugin.cpp @@ -19,6 +19,7 @@ #include "taskswitcher/displaysmodel.h" +#include "haptics.h" #include "mobileshellsettings.h" #include "quicksetting.h" #include "quicksettingsmodel.h" @@ -38,6 +39,10 @@ void MobileShellPlugin::registerTypes(const char *uri) return ShellUtil::instance(); }); + qmlRegisterSingletonType(uri, 1, 0, "Haptics", [](QQmlEngine *, QJSEngine *) -> QObject * { + return Haptics::self(); + }); + qmlRegisterSingletonType(uri, 1, 0, "MobileShellSettings", [](QQmlEngine *, QJSEngine *) -> QObject * { return MobileShellSettings::self(); }); diff --git a/components/mobileshell/mobileshellsettings.cpp b/components/mobileshell/mobileshellsettings.cpp index abd5a07b..ce87987a 100644 --- a/components/mobileshell/mobileshellsettings.cpp +++ b/components/mobileshell/mobileshellsettings.cpp @@ -26,6 +26,7 @@ MobileShellSettings::MobileShellSettings(QObject *parent) connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) -> void { if (group.name() == GENERAL_CONFIG_GROUP) { + Q_EMIT vibrationsEnabledChanged(); Q_EMIT navigationPanelEnabledChanged(); } else if (group.name() == QUICKSETTINGS_CONFIG_GROUP) { 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 { auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP}; diff --git a/components/mobileshell/mobileshellsettings.h b/components/mobileshell/mobileshellsettings.h index cfb124cd..742f4f81 100644 --- a/components/mobileshell/mobileshellsettings.h +++ b/components/mobileshell/mobileshellsettings.h @@ -14,6 +14,7 @@ class MobileShellSettings : public QObject { Q_OBJECT + Q_PROPERTY(bool vibrationsEnabled READ vibrationsEnabled WRITE setVibrationsEnabled NOTIFY vibrationsEnabledChanged) Q_PROPERTY(bool navigationPanelEnabled READ navigationPanelEnabled WRITE setNavigationPanelEnabled NOTIFY navigationPanelEnabledChanged) public: @@ -21,6 +22,9 @@ public: MobileShellSettings(QObject *parent = nullptr); + bool vibrationsEnabled() const; + void setVibrationsEnabled(bool vibrationsEnabled); + bool navigationPanelEnabled() const; void setNavigationPanelEnabled(bool navigationPanelEnabled); @@ -31,6 +35,7 @@ public: void setDisabledQuickSettings(QList &list); Q_SIGNALS: + void vibrationsEnabledChanged(); void navigationPanelEnabledChanged(); void enabledQuickSettingsChanged(); void disabledQuickSettingsChanged(); diff --git a/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettingsFullDelegate.qml b/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettingsFullDelegate.qml index 207bf44a..64da5aba 100644 --- a/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettingsFullDelegate.qml +++ b/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettingsFullDelegate.qml @@ -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.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 "../../components" as Components @@ -41,8 +42,14 @@ QuickSettingsDelegate { contentItem: MouseArea { id: mouseArea + + onPressed: MobileShell.Haptics.buttonVibrate() onClicked: root.delegateClick() - onPressAndHold: root.delegatePressAndHold() + onPressAndHold: { + MobileShell.Haptics.buttonVibrate(); + root.delegatePressAndHold(); + } + cursorShape: Qt.PointingHandCursor PlasmaCore.IconItem { diff --git a/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettingsMinimizedDelegate.qml b/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettingsMinimizedDelegate.qml index 3ce0c437..3859c8f7 100644 --- a/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettingsMinimizedDelegate.qml +++ b/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettingsMinimizedDelegate.qml @@ -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.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 "../../components" as Components @@ -37,8 +38,14 @@ QuickSettingsDelegate { contentItem: MouseArea { id: mouseArea + + onPressed: MobileShell.Haptics.buttonVibrate(); onClicked: root.delegateClick() - onPressAndHold: root.delegatePressAndHold() + onPressAndHold: { + MobileShell.Haptics.buttonVibrate(); + root.delegatePressAndHold(); + } + cursorShape: Qt.PointingHandCursor PlasmaCore.IconItem { diff --git a/components/mobileshell/qml/navigationpanel/NavigationPanel.qml b/components/mobileshell/qml/navigationpanel/NavigationPanel.qml index 74e52590..c15882cd 100644 --- a/components/mobileshell/qml/navigationpanel/NavigationPanel.qml +++ b/components/mobileshell/qml/navigationpanel/NavigationPanel.qml @@ -61,6 +61,9 @@ Item { startMouseX = oldMouseX = mouse.y; startMouseY = oldMouseY = mouse.y; activeButton = icons.childAt(mouse.x, mouse.y); + if (activeButton && activeButton.enabled) { + MobileShell.Haptics.buttonVibrate(); + } } onPositionChanged: { diff --git a/kcms/mobileshell/package/contents/ui/main.qml b/kcms/mobileshell/package/contents/ui/main.qml index 0ab3b112..ff9dea2f 100644 --- a/kcms/mobileshell/package/contents/ui/main.qml +++ b/kcms/mobileshell/package/contents/ui/main.qml @@ -30,6 +30,30 @@ KCM.SimpleKCM { MobileForm.FormCard { 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 { spacing: 0 diff --git a/look-and-feel/contents/lockscreen/Keypad.qml b/look-and-feel/contents/lockscreen/Keypad.qml index d1742367..5267e22e 100644 --- a/look-and-feel/contents/lockscreen/Keypad.qml +++ b/look-and-feel/contents/lockscreen/Keypad.qml @@ -8,9 +8,12 @@ import QtQuick 2.12 import QtQuick.Controls 2.1 import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.12 + import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.core 2.0 as PlasmaCore 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 Rectangle { @@ -188,6 +191,7 @@ Rectangle { anchors.fill: parent onPressedChanged: { if (pressed) { + MobileShell.Haptics.buttonVibrate(); parent.color = keypadRoot.buttonPressedColor; } else { parent.color = keypadRoot.buttonColor; @@ -205,6 +209,7 @@ Rectangle { } onPressAndHold: { if (modelData === "R") { + MobileShell.Haptics.buttonVibrate(); passwordBar.clear(); } } diff --git a/look-and-feel/contents/logout/ActionButton.qml b/look-and-feel/contents/logout/ActionButton.qml index e7cf536a..5b9a6e1f 100644 --- a/look-and-feel/contents/logout/ActionButton.qml +++ b/look-and-feel/contents/logout/ActionButton.qml @@ -5,8 +5,10 @@ */ import QtQuick 2.8 + import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 3.0 as PlasmaComponents3 +import org.kde.plasma.private.mobileshell 1.0 as MobileShell Item { id: root @@ -19,6 +21,7 @@ Item { property alias circleVisiblity: iconCircle.visible property int fontSize: config.fontSize readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + signal clicked activeFocusOnTab: true @@ -102,6 +105,7 @@ Item { id: mouseArea hoverEnabled: true onClicked: root.clicked() + onPressed: MobileShell.Haptics.buttonVibrate(); anchors.fill: parent } diff --git a/look-and-feel/contents/logout/Logout.qml b/look-and-feel/contents/logout/Logout.qml index 51eba761..c872cbe4 100644 --- a/look-and-feel/contents/logout/Logout.qml +++ b/look-and-feel/contents/logout/Logout.qml @@ -13,6 +13,7 @@ import QtQuick.Controls 2.8 as Controls import org.kde.plasma.core 2.0 as PlasmaCore 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 PlasmaCore.ColorScope { @@ -27,6 +28,8 @@ PlasmaCore.ColorScope { signal cancelRequested() signal lockScreenRequested() + Component.onCompleted: MobileShell.Haptics.buttonVibrate(); + Controls.Action { onTriggered: root.cancelRequested() shortcut: "Escape" @@ -55,6 +58,7 @@ PlasmaCore.ColorScope { ParallelAnimation { id: openAnim + running: true ScaleAnimator { target: lay from: 10 @@ -80,6 +84,8 @@ PlasmaCore.ColorScope { SequentialAnimation { id: closeAnim + running: false + property var callback function execute(call) { callback = call;