homescreens/halcyon: Add settings page

Add a settings page to halcyon, which allows for toggling whether the
wallpaper is blurred and double tapping on the homescreen to lock the
device. This also does a bit of refactoring for folio and halcyon to
share the same wallpaper blurring item.
This commit is contained in:
Devin Lin 2025-06-25 19:22:58 -04:00
parent 5d33295443
commit 1d3ceb5801
11 changed files with 344 additions and 41 deletions

View file

@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: 2023-2025 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
Loader {
id: root
property real blurOpacity
property Item wallpaperItem
sourceComponent: Item {
id: wallpaper
anchors.fill: parent
// only take samples from wallpaper when we need the blur for performance
ShaderEffectSource {
id: controlledWallpaperSource
anchors.fill: parent
live: blur.visible
hideSource: false
visible: false
sourceItem: root.wallpaperItem
}
// wallpaper blur
// we attempted to use MultiEffect in the past, but it had very poor performance on the PinePhone
FastBlur {
id: blur
radius: 50
cached: true
source: controlledWallpaperSource
anchors.fill: parent
visible: opacity > 0
opacity: root.blurOpacity
}
}
}

View file

@ -31,45 +31,20 @@ ContainmentItem {
forceActiveFocus();
}
Loader {
id: wallpaperBlurLoader
MobileShell.HomeScreenWallpaperBlur {
id: wallpaperBlur
active: folio.FolioSettings.showWallpaperBlur
anchors.fill: parent
wallpaperItem: Plasmoid.wallpaperGraphicsObject
sourceComponent: Item {
id: wallpaper
anchors.fill: parent
// only take samples from wallpaper when we need the blur for performance
ShaderEffectSource {
id: controlledWallpaperSource
anchors.fill: parent
sourceItem: Plasmoid.wallpaperGraphicsObject
live: blur.visible
hideSource: false
visible: false
}
// wallpaper blur
// we attempted to use MultiEffect in the past, but it had very poor performance on the PinePhone
FastBlur {
id: blur
radius: 50
cached: true
source: controlledWallpaperSource
anchors.fill: parent
visible: opacity > 0
opacity: Math.min(1,
Math.max(
1 - homeScreen.contentOpacity,
folio.HomeScreenState.appDrawerOpenProgress * 2, // blur faster during swipe
folio.HomeScreenState.searchWidgetOpenProgress * 1.5, // blur faster during swipe
folio.HomeScreenState.folderOpenProgress
)
)
}
}
blurOpacity: Math.min(1,
Math.max(
1 - homeScreen.contentOpacity,
folio.HomeScreenState.appDrawerOpenProgress * 2, // blur faster during swipe
folio.HomeScreenState.searchWidgetOpenProgress * 1.5, // blur faster during swipe
folio.HomeScreenState.folderOpenProgress
)
)
}
WindowPlugin.WindowMaximizedTracker {

View file

@ -5,6 +5,7 @@ add_definitions(-DTRANSLATION_DOMAIN=\"plasma_applet_org.kde.plasma.mobile.homes
set(homescreen_SRCS
homescreen.cpp
halcyonsettings.cpp
)
add_library(org.kde.plasma.mobile.homescreen.halcyon MODULE ${homescreen_SRCS})
@ -14,11 +15,11 @@ target_link_libraries(org.kde.plasma.mobile.homescreen.halcyon
Qt::Qml
Qt::Quick
Plasma::Plasma
Plasma::KWaylandClient
KF6::I18n
KF6::Service
KF6::KIOGui
KF6::Notifications
Plasma::KWaylandClient
KF6::WindowSystem
)

View file

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: 2025 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "halcyonsettings.h"
const QString CFG_KEY_SHOW_WALLPAPER_BLUR = QStringLiteral("showWallpaperBlur");
const QString CFG_KEY_DOUBLE_TAP_TO_SLEEP = QStringLiteral("doubleTapToSleep");
HalcyonSettings::HalcyonSettings(QObject *parent, KConfigGroup config)
: QObject{parent}
, m_config{config}
{
load();
}
bool HalcyonSettings::showWallpaperBlur() const
{
return m_showWallpaperBlur;
}
void HalcyonSettings::setShowWallpaperBlur(bool showWallpaperBlur)
{
if (m_showWallpaperBlur != showWallpaperBlur) {
m_showWallpaperBlur = showWallpaperBlur;
Q_EMIT showWallpaperBlurChanged();
save();
}
}
bool HalcyonSettings::doubleTapToSleep() const
{
return m_doubleTapToSleep;
}
void HalcyonSettings::setDoubleTapToSleep(bool doubleTapToSleep)
{
if (m_doubleTapToSleep != doubleTapToSleep) {
m_doubleTapToSleep = doubleTapToSleep;
Q_EMIT doubleTapToSleepChanged();
save();
}
}
void HalcyonSettings::save()
{
m_config.writeEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, m_showWallpaperBlur);
m_config.writeEntry(CFG_KEY_DOUBLE_TAP_TO_SLEEP, m_doubleTapToSleep);
m_config.sync();
}
void HalcyonSettings::load()
{
m_showWallpaperBlur = m_config.readEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, false);
m_doubleTapToSleep = m_config.readEntry(CFG_KEY_DOUBLE_TAP_TO_SLEEP, true);
}

View file

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: 2025 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QObject>
#include <KConfigGroup>
class HalcyonSettings : public QObject
{
Q_OBJECT
Q_PROPERTY(bool showWallpaperBlur READ showWallpaperBlur WRITE setShowWallpaperBlur NOTIFY showWallpaperBlurChanged)
Q_PROPERTY(bool doubleTapToSleep READ doubleTapToSleep WRITE setDoubleTapToSleep NOTIFY doubleTapToSleepChanged)
public:
HalcyonSettings(QObject *parent = nullptr, KConfigGroup config = {});
bool showWallpaperBlur() const;
void setShowWallpaperBlur(bool blurWallpaper);
bool doubleTapToSleep() const;
void setDoubleTapToSleep(bool doubleTapToSleep);
Q_SIGNALS:
void showWallpaperBlurChanged();
void doubleTapToSleepChanged();
private:
void save();
void load();
bool m_showWallpaperBlur{false};
bool m_doubleTapToSleep{true};
KConfigGroup m_config;
};

View file

@ -11,12 +11,18 @@
HomeScreen::HomeScreen(QObject *parent, const KPluginMetaData &data, const QVariantList &args)
: Plasma::Containment{parent, data, args}
, m_settings{new HalcyonSettings{this, config()}}
{
setHasConfigurationInterface(true);
}
HomeScreen::~HomeScreen() = default;
HalcyonSettings *HomeScreen::settings() const
{
return m_settings;
}
K_PLUGIN_CLASS(HomeScreen)
#include "homescreen.moc"

View file

@ -5,14 +5,22 @@
#include <Plasma/Containment>
#include "halcyonsettings.h"
class HomeScreen : public Plasma::Containment
{
Q_OBJECT
Q_PROPERTY(HalcyonSettings *settings READ settings CONSTANT)
public:
HomeScreen(QObject *parent, const KPluginMetaData &data, const QVariantList &args);
~HomeScreen() override;
HalcyonSettings *settings() const;
Q_SIGNALS:
void showingDesktopChanged(bool showingDesktop);
private:
HalcyonSettings *m_settings{nullptr};
};

View file

@ -13,6 +13,9 @@ import org.kde.draganddrop as DragDrop
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin
import org.kde.plasma.private.mobileshell as MobileShell
import "settings" as Settings
Item {
id: root
@ -62,7 +65,7 @@ Item {
}
}
SettingsScreen {
Settings.SettingsScreen {
id: settings
bottomMargin: root.bottomMargin
anchors.fill: parent
@ -104,6 +107,15 @@ Item {
}
onLongPressed: root.openConfigure()
onDoubleTapped: {
if (Plasmoid.settings.doubleTapToSleep) {
doubleTapToSleep.doubleTapped();
}
}
}
MobileShell.DoubleTapToSleep {
id: doubleTapToSleep
}
FavoritesView {

View file

@ -56,11 +56,23 @@ ContainmentItem {
screenGeometry: Plasmoid.containment.screenGeometry
}
MobileShell.HomeScreenWallpaperBlur {
id: wallpaperBlur
active: Plasmoid.settings.showWallpaperBlur
anchors.fill: parent
wallpaperItem: Plasmoid.wallpaperGraphicsObject
blurOpacity: Math.min(1,
Math.max(1 - homeScreen.contentOpacity,
halcyonHomeScreen.settingsOpenFactor
)
)
}
Rectangle {
id: darkenBackground
color: (halcyonHomeScreen.page == 1 ? Qt.rgba(0, 0, 0, 0.7) : Qt.rgba(0, 0, 0, 0.2))
anchors.fill: parent
z: -1
Behavior on color {
ColorAnimation { duration: Kirigami.Units.longDuration }
}
@ -71,7 +83,6 @@ ContainmentItem {
color: Qt.rgba(0, 0, 0, 0.7)
opacity: halcyonHomeScreen.settingsOpenFactor
anchors.fill: parent
z: -1
Behavior on color {
ColorAnimation { duration: Kirigami.Units.longDuration }
}

View file

@ -103,12 +103,40 @@ Item {
onClicked: {
root.homeScreen.settingsOpen = false;
root.homeScreen.openContainmentSettings();
if (settingsWindowLoader.active) {
// Ensure that if the window is already opened, it gets raised to the top
settingsWindowLoader.item.hide();
settingsWindowLoader.item.showMaximized();
} else {
settingsWindowLoader.active = true;
}
}
}
}
}
// Only load settings window when visible
Loader {
id: settingsWindowLoader
asynchronous: true
active: false
onLoaded: item.showMaximized();
sourceComponent: SettingsWindow {
onVisibleChanged: {
if (!visible) {
settingsWindowLoader.active = false;
}
}
onRequestConfigureMenu: {
root.homeScreen.openContainmentSettings();
}
}
}
// Only load wallpaper selector when visible
Loader {
id: wallpaperSelectorLoader
asynchronous: true

View file

@ -0,0 +1,129 @@
// SPDX-FileCopyrightText: 2023-2025 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import QtQuick.Dialogs
import QtQuick.Controls as QQC2
import org.kde.plasma.plasmoid
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
Window {
id: root
flags: Qt.FramelessWindowHint
color: 'transparent'
onVisibleChanged: {
if (visible) {
opacityAnim.to = 1;
opacityAnim.restart();
}
}
onClosing: (close) => {
if (applicationItem.opacity !== 0) {
close.accepted = false;
opacityAnim.to = 0;
opacityAnim.restart();
}
}
signal requestConfigureMenu()
Kirigami.ApplicationItem {
id: applicationItem
anchors.fill: parent
opacity: 0
NumberAnimation on opacity {
id: opacityAnim
duration: 200
easing.type: Easing.OutCubic
onFinished: {
if (applicationItem.opacity === 0) {
root.close();
}
}
}
scale: 0.7 + 0.3 * applicationItem.opacity
pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.ToolBar
pageStack.globalToolBar.showNavigationButtons: Kirigami.ApplicationHeaderStyle.NoNavigationButtons;
pageStack.initialPage: Kirigami.ScrollablePage {
id: page
opacity: applicationItem.opacity
titleDelegate: RowLayout {
QQC2.ToolButton {
Layout.leftMargin: -Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing
icon.name: "arrow-left"
onClicked: root.close()
}
Kirigami.Heading {
level: 1
text: page.title
}
}
title: i18n("Homescreen Settings")
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0
ColumnLayout {
FormCard.FormHeader {
title: i18n("Homescreen")
}
FormCard.FormCard {
FormCard.FormSwitchDelegate {
id: showWallpaperBlur
text: i18nc("@option:check", "Show wallpaper blur effect")
checked: Plasmoid.settings.showWallpaperBlur
onCheckedChanged: {
if (checked != Plasmoid.settings.showWallpaperBlur) {
Plasmoid.settings.showWallpaperBlur = checked;
}
}
}
FormCard.FormDelegateSeparator { above: showWallpaperBlur; below: doubleTapToSleepSwitch }
FormCard.FormSwitchDelegate {
id: doubleTapToSleepSwitch
text: i18n("Double tap to lock device")
checked: Plasmoid.settings.doubleTapToSleep
onCheckedChanged: {
if (checked != Plasmoid.settings.doubleTapToSleep) {
Plasmoid.settings.doubleTapToSleep = checked;
}
}
}
}
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.largeSpacing
Layout.bottomMargin: Kirigami.Units.gridUnit
FormCard.FormButtonDelegate {
id: containmentSettings
text: i18nc("@action:button", "Switch between homescreens and more wallpaper options")
icon.name: 'settings-configure'
onClicked: root.requestConfigureMenu()
}
}
}
}
}
}