Commit 9a575ad4 authored by Devin Lin's avatar Devin Lin 🎨
Browse files

kcm: Add vibration intensity and duration

parent fc300d1a
Pipeline #172321 passed with stage
in 1 minute and 2 seconds
......@@ -27,6 +27,8 @@ 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 vibrationIntensityChanged();
Q_EMIT vibrationDurationChanged();
Q_EMIT animationsEnabledChanged();
Q_EMIT navigationPanelEnabledChanged();
} else if (group.name() == QUICKSETTINGS_CONFIG_GROUP) {
......@@ -49,6 +51,32 @@ void MobileShellSettings::setVibrationsEnabled(bool vibrationsEnabled)
m_config->sync();
}
int MobileShellSettings::vibrationDuration() const
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
return group.readEntry("vibrationDuration", 100);
}
void MobileShellSettings::setVibrationDuration(int vibrationDuration)
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
group.writeEntry("vibrationDuration", vibrationDuration, KConfigGroup::Notify);
m_config->sync();
}
qreal MobileShellSettings::vibrationIntensity() const
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
return group.readEntry("vibrationDuration", 0.5);
}
void MobileShellSettings::setVibrationIntensity(qreal vibrationIntensity)
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
group.writeEntry("vibrationDuration", vibrationIntensity, KConfigGroup::Notify);
m_config->sync();
}
bool MobileShellSettings::animationsEnabled() const
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
......
......@@ -11,10 +11,17 @@
#include <KSharedConfig>
#include <QObject>
/**
* @short Wrapper class to access and control mobile shell specific settings.
*
* @author Devin Lin <devin@kde.org>
*/
class MobileShellSettings : public QObject
{
Q_OBJECT
Q_PROPERTY(bool vibrationsEnabled READ vibrationsEnabled WRITE setVibrationsEnabled NOTIFY vibrationsEnabledChanged)
Q_PROPERTY(int vibrationDuration READ vibrationDuration WRITE setVibrationDuration NOTIFY vibrationDurationChanged)
Q_PROPERTY(qreal vibrationIntensity READ vibrationIntensity WRITE setVibrationIntensity NOTIFY vibrationIntensityChanged)
Q_PROPERTY(bool animationsEnabled READ animationsEnabled WRITE setAnimationsEnabled NOTIFY animationsEnabledChanged)
Q_PROPERTY(bool navigationPanelEnabled READ navigationPanelEnabled WRITE setNavigationPanelEnabled NOTIFY navigationPanelEnabledChanged)
......@@ -23,23 +30,102 @@ public:
MobileShellSettings(QObject *parent = nullptr);
/**
* Get whether shell vibrations are enabled.
*/
bool vibrationsEnabled() const;
/**
* Set whether shell vibrations should be enabled.
*
* @param vibrationsEnabled Whether vibrations are enabled.
*/
void setVibrationsEnabled(bool vibrationsEnabled);
/**
* Get the duration of a standard vibration event, in milliseconds.
* Different types of vibration events may be calculated off of this.
*/
int vibrationDuration() const;
/**
* Set the duration of a standard vibration event, in milliseconds.
*
* @param vibrationDuration The duration of a standard vibration event.
*/
void setVibrationDuration(int vibrationDuration);
/**
* Get the intensity of a standard vibration event, which is a value between
* zero and one.
*/
qreal vibrationIntensity() const;
/**
* Set the intensity of a standard vibration event.
*
* @param vibrationIntensity The intensity of a standard vibration event, between zero and one.
*/
void setVibrationIntensity(qreal vibrationIntensity);
/**
* Whether animations are enabled in the shell.
*
* If false, vibrations will either be disabled or minimized as much as possible.
* TODO: integrate with animation speed (in settings at "Workspace Behaviour->General Behaviour"),
* which affects applications as well.
*/
bool animationsEnabled() const;
/**
* Set whether animations are enabled in the shell.
*
* @param animationsEnabled Whether animations should be enabled in the shell.
*/
void setAnimationsEnabled(bool animationsEnabled);
/**
* Whether the navigation panel is enabled.
*
* If this is false, then gesture based navigation is used.
*/
bool navigationPanelEnabled() const;
/**
* Set whether the navigation panel is enabled.
*
* @param navigationPanelEnabled Whether the navigation panel should be enabled.
*/
void setNavigationPanelEnabled(bool navigationPanelEnabled);
/**
* Get the list of IDs of quick settings that are enabled.
*/
QList<QString> enabledQuickSettings() const;
/**
* Set the list of quick settings that are enabled.
*
* @param list A list of quick setting IDs.
*/
void setEnabledQuickSettings(QList<QString> &list);
/**
* Get the list of IDs of quick settings that are disabled.
*/
QList<QString> disabledQuickSettings() const;
/**
* Set the list of quick settings that are disabled.
*
* @param list A list of quick setting IDs.
*/
void setDisabledQuickSettings(QList<QString> &list);
Q_SIGNALS:
void vibrationsEnabledChanged();
void vibrationIntensityChanged();
void vibrationDurationChanged();
void navigationPanelEnabledChanged();
void animationsEnabledChanged();
void enabledQuickSettingsChanged();
......
......@@ -16,8 +16,8 @@ QtObject {
function buttonVibrate() {
if (MobileShell.MobileShellSettings.vibrationsEnabled) {
if (hapticsEffect.status == Loader.Ready) {
hapticsEffect.item.intensity = 0.5;
hapticsEffect.item.duration = 100;
hapticsEffect.item.intensity = MobileShell.MobileShellSettings.vibrationIntensity;
hapticsEffect.item.duration = MobileShell.MobileShellSettings.vibrationDuration;
hapticsEffect.item.start();
}
}
......
/*
* SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kcm 1.3 as KCM
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import "mobileform" as MobileForm
Kirigami.ScrollablePage {
id: root
title: i18n("Shell Vibrations")
leftPadding: 0
rightPadding: 0
topPadding: Kirigami.Units.gridUnit
bottomPadding: Kirigami.Units.gridUnit
ColumnLayout {
spacing: 0
width: root.width
MobileForm.FormCard {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormSwitchDelegate {
id: shellVibrationsSwitch
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;
}
}
}
Kirigami.Separator {
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.fillWidth: true
opacity: (!shellVibrationsSwitch.controlHovered && !vibrationIntensityDelegate.controlHovered) ? 0.5 : 0
}
MobileForm.FormComboBoxDelegate {
id: vibrationIntensityDelegate
text: i18n("Vibration Intensity")
description: i18n("How intense shell vibrations should be.")
property string lowIntensityString: i18nc("Low intensity", "Low")
property string mediumIntensityString: i18nc("Medium intensity", "Medium")
property string highIntensityString: i18nc("High intensity", "High")
currentValue: {
let intensity = MobileShell.MobileShellSettings.vibrationIntensity;
if (intensity <= 0.2) {
return lowIntensityString;
} else if (intensity <= 0.5) {
return mediumIntensityString;
} else {
return highIntensityString;
}
}
model: ListModel {
// we can't use i18n with ListElement
Component.onCompleted: {
append({"name": vibrationIntensityDelegate.highIntensityString, "value": 1.0});
append({"name": vibrationIntensityDelegate.mediumIntensityString, "value": 0.5});
append({"name": vibrationIntensityDelegate.lowIntensityString, "value": 0.2});
}
}
dialogDelegate: QQC2.RadioDelegate {
implicitWidth: Kirigami.Units.gridUnit * 16
topPadding: Kirigami.Units.smallSpacing * 2
bottomPadding: Kirigami.Units.smallSpacing * 2
text: name
checked: vibrationIntensityDelegate.currentValue === name
onCheckedChanged: {
if (checked) {
MobileShell.MobileShellSettings.vibrationIntensity = value;
}
}
}
}
Kirigami.Separator {
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.fillWidth: true
opacity: (!vibrationIntensityDelegate.controlHovered && !vibrationDurationDelegate.controlHovered) ? 0.5 : 0
}
MobileForm.FormComboBoxDelegate {
id: vibrationDurationDelegate
text: i18n("Vibration Duration")
description: i18n("How long shell vibrations should be.")
property string longString: i18nc("Long duration", "Long")
property string mediumString: i18nc("Medium duration", "Medium")
property string shortString: i18nc("Short duration", "Short")
currentValue: {
let duration = MobileShell.MobileShellSettings.vibrationDuration;
if (duration >= 100) {
return longString;
} else if (duration >= 50) {
return mediumString;
} else {
return shortString;
}
}
model: ListModel {
// we can't use i18n with ListElement
Component.onCompleted: {
append({"name": vibrationDurationDelegate.longString, "value": 100});
append({"name": vibrationDurationDelegate.mediumString, "value": 50});
append({"name": vibrationDurationDelegate.shortString, "value": 15});
}
}
dialogDelegate: QQC2.RadioDelegate {
implicitWidth: Kirigami.Units.gridUnit * 16
topPadding: Kirigami.Units.smallSpacing * 2
bottomPadding: Kirigami.Units.smallSpacing * 2
text: name
checked: vibrationDurationDelegate.currentValue === name
onCheckedChanged: {
if (checked) {
MobileShell.MobileShellSettings.vibrationDuration = value;
}
}
}
}
}
}
MobileForm.FormSectionText {
text: i18n("Keyboard vibrations are controlled separately in the keyboard settings module.")
}
}
}
......@@ -37,18 +37,21 @@ KCM.SimpleKCM {
title: i18n("General")
}
MobileForm.FormSwitchDelegate {
MobileForm.FormButtonDelegate {
id: shellVibrationsButton
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;
}
}
onClicked: kcm.push("VibrationForm.qml")
}
Kirigami.Separator {
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.fillWidth: true
opacity: (!shellVibrationsButton.controlHovered && !animationsSwitch.controlHovered) ? 0.5 : 0
}
MobileForm.FormSwitchDelegate {
id: animationsSwitch
text: i18n("Animations")
description: i18n("If this is off, animations will be reduced as much as possible.")
checked: MobileShell.MobileShellSettings.animationsEnabled
......
......@@ -17,9 +17,29 @@ AbstractFormDelegate {
// TODO
property string currentValue: ""
property alias dialogDelegate: repeater.delegate
property alias model: repeater.model
Layout.fillWidth: true
onClicked: dialog.open()
Kirigami.Dialog {
id: dialog
showCloseButton: false
title: root.text
ColumnLayout {
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
spacing: 0
Repeater {
id: repeater
}
}
}
contentItem: RowLayout {
ColumnLayout {
Layout.fillWidth: true
......
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