shift-shell/initialstart/setupstate.cpp
Marco Allegretti 42d41351e2 Add profile-aware initial setup
Detect the device class, stage the selected experience, and write the resulting setup choices through SetupState.

Load the new device and experience modules before the existing setup pages, and use the Shift icon on the finished page.
2026-05-11 10:03:07 +02:00

257 lines
7.2 KiB
C++

// SPDX-FileCopyrightText: 2026 Marco Allegretti
// SPDX-License-Identifier: EUPL-1.2
#include "setupstate.h"
#include "devicecontext.h"
#include <KConfigGroup>
#include <KSharedConfig>
#include <QCoreApplication>
#include <QJSEngine>
#include <QProcess>
#include <QQmlEngine>
const QString CONFIG_FILE = QStringLiteral("plasmamobilerc");
const QString GENERAL_CONFIG_GROUP = QStringLiteral("General");
const QString INITIAL_START_CONFIG_GROUP = QStringLiteral("InitialStart");
SetupState::SetupState(QObject *parent)
: QObject(parent)
{
useRecommendedSettings();
}
SetupState *SetupState::self()
{
static auto *instance = new SetupState(qApp);
return instance;
}
SetupState *SetupState::create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
{
Q_UNUSED(qmlEngine)
Q_UNUSED(jsEngine)
return self();
}
QString SetupState::deviceClass() const
{
return m_deviceClass;
}
void SetupState::setDeviceClass(const QString &deviceClass)
{
if (m_deviceClass == deviceClass) {
return;
}
m_deviceClass = deviceClass;
Q_EMIT deviceClassChanged();
}
QString SetupState::experienceProfile() const
{
return m_experienceProfile;
}
void SetupState::setExperienceProfile(const QString &experienceProfile)
{
if (m_experienceProfile == experienceProfile) {
return;
}
m_experienceProfile = experienceProfile;
Q_EMIT experienceProfileChanged();
}
QString SetupState::primaryInput() const
{
return m_primaryInput;
}
void SetupState::setPrimaryInput(const QString &primaryInput)
{
if (m_primaryInput == primaryInput) {
return;
}
m_primaryInput = primaryInput;
Q_EMIT primaryInputChanged();
}
bool SetupState::convergenceModeEnabled() const
{
return m_convergenceModeEnabled;
}
void SetupState::setConvergenceModeEnabled(bool enabled)
{
if (m_convergenceModeEnabled == enabled) {
return;
}
m_convergenceModeEnabled = enabled;
emitShellSettingsChanged();
}
bool SetupState::gamingModeEnabled() const
{
return m_gamingModeEnabled;
}
void SetupState::setGamingModeEnabled(bool enabled)
{
if (m_gamingModeEnabled == enabled) {
return;
}
m_gamingModeEnabled = enabled;
emitShellSettingsChanged();
}
bool SetupState::navigationPanelEnabled() const
{
return m_navigationPanelEnabled;
}
void SetupState::setNavigationPanelEnabled(bool enabled)
{
if (m_navigationPanelEnabled == enabled) {
return;
}
m_navigationPanelEnabled = enabled;
emitShellSettingsChanged();
}
bool SetupState::dynamicTilingEnabled() const
{
return m_dynamicTilingEnabled;
}
void SetupState::setDynamicTilingEnabled(bool enabled)
{
if (m_dynamicTilingEnabled == enabled) {
return;
}
m_dynamicTilingEnabled = enabled;
emitShellSettingsChanged();
}
bool SetupState::snapLayoutsEnabled() const
{
return m_snapLayoutsEnabled;
}
void SetupState::setSnapLayoutsEnabled(bool enabled)
{
if (m_snapLayoutsEnabled == enabled) {
return;
}
m_snapLayoutsEnabled = enabled;
emitShellSettingsChanged();
}
bool SetupState::autoHidePanelsEnabled() const
{
return m_autoHidePanelsEnabled;
}
void SetupState::setAutoHidePanelsEnabled(bool enabled)
{
if (m_autoHidePanelsEnabled == enabled) {
return;
}
m_autoHidePanelsEnabled = enabled;
emitShellSettingsChanged();
}
void SetupState::useRecommendedSettings()
{
auto *context = DeviceContext::self();
setDeviceClass(context->recommendedDeviceClass());
if (context->recommendedExperienceProfile() == QLatin1String("gaming")) {
setPrimaryInput(QStringLiteral("gamepad"));
} else if (context->hasTouch() && !context->hasKeyboard() && !context->hasMouse()) {
setPrimaryInput(QStringLiteral("touch"));
} else {
setPrimaryInput(QStringLiteral("keyboardMouse"));
}
applyExperienceDefaults(context->recommendedExperienceProfile());
}
void SetupState::applyDeviceDefaults(const QString &deviceClass, const QString &primaryInput)
{
setDeviceClass(deviceClass);
setPrimaryInput(primaryInput);
if (deviceClass == QLatin1String("handheld") || deviceClass == QLatin1String("mini-pc")) {
applyExperienceDefaults(QStringLiteral("gaming"));
} else if (deviceClass == QLatin1String("laptop") || deviceClass == QLatin1String("desktop")) {
applyExperienceDefaults(QStringLiteral("desktop"));
} else if (deviceClass == QLatin1String("dual-screen") || deviceClass == QLatin1String("foldable")) {
applyExperienceDefaults(QStringLiteral("hybrid"));
} else {
applyExperienceDefaults(QStringLiteral("mobile"));
}
}
void SetupState::applyExperienceDefaults(const QString &experienceProfile)
{
setExperienceProfile(experienceProfile);
if (experienceProfile == QLatin1String("gaming")) {
setConvergenceModeEnabled(false);
setGamingModeEnabled(true);
setNavigationPanelEnabled(false);
setDynamicTilingEnabled(false);
setSnapLayoutsEnabled(false);
setAutoHidePanelsEnabled(true);
} else if (experienceProfile == QLatin1String("desktop")) {
setConvergenceModeEnabled(true);
setGamingModeEnabled(false);
setNavigationPanelEnabled(false);
setDynamicTilingEnabled(true);
setSnapLayoutsEnabled(true);
setAutoHidePanelsEnabled(false);
} else if (experienceProfile == QLatin1String("hybrid")) {
setConvergenceModeEnabled(true);
setGamingModeEnabled(false);
setNavigationPanelEnabled(false);
setDynamicTilingEnabled(true);
setSnapLayoutsEnabled(true);
setAutoHidePanelsEnabled(true);
} else {
setConvergenceModeEnabled(false);
setGamingModeEnabled(false);
setNavigationPanelEnabled(false);
setDynamicTilingEnabled(false);
setSnapLayoutsEnabled(false);
setAutoHidePanelsEnabled(false);
}
}
void SetupState::apply(bool applyToRunningSession)
{
auto config = KSharedConfig::openConfig(CONFIG_FILE);
KConfigGroup general(config, GENERAL_CONFIG_GROUP);
general.writeEntry("setupDeviceClass", m_deviceClass, KConfigGroup::Notify);
general.writeEntry("setupExperienceProfile", m_experienceProfile, KConfigGroup::Notify);
general.writeEntry("setupPrimaryInput", m_primaryInput, KConfigGroup::Notify);
general.writeEntry("convergenceModeEnabled", m_convergenceModeEnabled, KConfigGroup::Notify);
general.writeEntry("gamingModeEnabled", m_gamingModeEnabled, KConfigGroup::Notify);
general.writeEntry("navigationPanelEnabled", m_navigationPanelEnabled, KConfigGroup::Notify);
general.writeEntry("dynamicTilingEnabled", m_dynamicTilingEnabled, KConfigGroup::Notify);
general.writeEntry("snapLayoutsEnabled", m_snapLayoutsEnabled, KConfigGroup::Notify);
general.writeEntry("autoHidePanelsEnabled", m_autoHidePanelsEnabled, KConfigGroup::Notify);
KConfigGroup initialStart(config, INITIAL_START_CONFIG_GROUP);
initialStart.writeEntry("wizardRun", true, KConfigGroup::Notify);
config->sync();
if (applyToRunningSession) {
QProcess::startDetached(QStringLiteral("plasma-mobile-envmanager"), {QStringLiteral("--apply-settings")});
}
}
void SetupState::emitShellSettingsChanged()
{
Q_EMIT shellSettingsChanged();
}