Commit 9e1d43bd authored by Janet Blackquill's avatar Janet Blackquill 🌈
Browse files

Get KISS ever closer to an MVP

parent 5a9c95fc
......@@ -18,6 +18,9 @@ include(KDEInstallDirs)
find_package(Qt5 COMPONENTS Core Quick QuickControls2 DBus REQUIRED)
find_package(KF5I18n)
find_package(KF5Config)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(DefaultPermissions
OWNER_WRITE OWNER_READ OWNER_EXECUTE
......
......@@ -24,6 +24,7 @@ target_link_libraries(org.kde.initialsystemsetup
PRIVATE
Qt5::Core Qt5::Quick Qt5::QuickControls2 Qt5::DBus
KF5::I18n KF5::ConfigCore
PkgConfig::GIO
)
configure_file(org.kde.initialsystemsetup.service.in org.kde.initialsystemsetup.service @ONLY)
......@@ -33,6 +34,13 @@ install(
DESTINATION ${KDE_INSTALL_SYSTEMDUNITDIR}/system
)
install(
FILES org.kde.initialsystemsetup.gschema.xml
DESTINATION ${KDE_INSTALL_DATADIR}/glib-2.0/schemas
)
install(CODE "execute_process(COMMAND glib-compile-schemas ${KDE_INSTALL_FULL_DATADIR}/glib-2.0/schemas)")
install(TARGETS org.kde.initialsystemsetup
PERMISSIONS ${DefaultPermissions} SETUID
DESTINATION ${KDE_INSTALL_BINDIR}
......
......@@ -10,13 +10,45 @@ ApplicationWindow {
visible: true
property string language: ""
property int currentPage: 0
onCurrentPageChanged: {
staccy.currentItem.apply()
staccy.replace(`qrc:/pages/${KISS.pages[currentPage]}/Page.qml`)
}
Rectangle {
anchors.fill: parent
color: "#404040"
}
RowLayout {
anchors {
left: kardo.left
right: kardo.right
top: kardo.bottom
topMargin: Kirigami.Units.largeSpacing
}
Button {
text: "Previous"
visible: appWindow.currentPage > 0
onClicked: appWindow.currentPage--
}
Item {
Layout.fillWidth: true
}
Button {
text: "Next"
visible: (staccy.currentItem.canNext) && (appWindow.currentPage + 1 != KISS.pages.length)
onClicked: appWindow.currentPage++
}
}
Kirigami.Card {
id: kardo
height: parent.height > Kirigami.Units.gridUnit * 30 ? Kirigami.Units.gridUnit * 30 : parent.height
width: parent.width > Kirigami.Units.gridUnit * 20 ? Kirigami.Units.gridUnit * 20 : parent.width
......@@ -67,18 +99,24 @@ ApplicationWindow {
clip: true
initialItem: "pages/locale/Page.qml"
}
}
}
initialItem: `pages/${KISS.pages[0]}/Page.qml`
Connections {
target: KISS
function onFinished(success) {
if (success) {
staccy.replace("qrc:/pages/ready/Page.qml")
replaceEnter: Transition {
PropertyAnimation {
property: "opacity"
from: 0
to: 1
}
}
replaceExit: Transition {
PropertyAnimation {
property: "opacity"
from: 1
to: 0
}
}
}
}
}
}
......@@ -6,13 +6,20 @@ ListView {
model: KISS.locales
property string title: "Welcome"
property string description: "Select a language to begin setup"
property bool canNext: true
function apply() {
KISS.targetLanguage = currentItem.code
}
delegate: Kirigami.BasicListItem {
text: modelData.name
property string code: modelData.code
onClicked: {
appWindow.language = modelData.code
staccy.push("qrc:/pages/user/Page.qml")
KISS.targetLanguage = modelData.code
appWindow.currentPage++
}
}
}
......@@ -5,6 +5,9 @@ import org.kde.kirigami 2.10 as Kirigami
Item {
property string title: ""
property bool canNext: false
function apply() {}
ColumnLayout {
anchors.centerIn: parent
......
......@@ -5,6 +5,18 @@ import org.kde.kirigami 2.10 as Kirigami
Item {
property string title: "User Setup"
property string description: "Let's set up your user account"
property bool canNext: (
name.text !== "" &&
user.text !== "" &&
pass.text !== ""
)
function apply() {
KISS.realname = name.text
KISS.username = user.text
KISS.password = pass.text
KISS.admin = true
}
Kirigami.FormLayout {
anchors.centerIn: parent
......@@ -12,24 +24,28 @@ Item {
TextField {
id: name
text: KISS.username
Kirigami.FormData.label: "Realname:"
}
TextField {
id: user
text: KISS.password
Kirigami.FormData.label: "Username:"
}
Kirigami.PasswordField {
id: pass
text: KISS.password
Kirigami.FormData.label: "Password:"
}
Button {
text: "Create user"
text: "Confirm"
onClicked: {
KISS.createAccount(name.text, user.text, pass.text, true, appWindow.language)
}
onClicked: appWindow.currentPage++
}
}
}
......@@ -5,14 +5,17 @@
#include "../Backend.h"
#include "../systemd.h"
#include "../Settings.h"
class SDDMBackend : public Backend {
public: SDDMBackend() {}
public: void yeetToSession(const QString& username) override {
KConfig conf("/etc/sddm.conf");
auto grp = conf.group("Autologin");
grp.writeEntry("User", username);
grp.writeEntry("Session", "plasmawayland.desktop");
grp.writeEntry("Session", Settings::instance()->session());
Systemd::instance()->enableService("sddm");
Systemd::instance()->startService("sddm");
}
......
......@@ -13,8 +13,15 @@
#include "systemd.h"
#include "Backend.h"
#include "Settings.h"
#include "DisplayManagerBackends/SDDM.h"
#include <optional>
static auto backends = QMap<QString,std::function<Backend*()>> {
{"sddm", []() -> Backend* { return new SDDMBackend; } }
};
struct Language
{
Q_GADGET
......@@ -38,7 +45,8 @@ class KISS : public QObject
public: KISS(QObject* parent = nullptr) : QObject(parent)
{
m_backend = new SDDMBackend;
m_backend = backends[Settings::instance()->displayManager()]();
auto locs = KLocalizedString::availableDomainTranslations("plasmashell").values();
std::transform(locs.begin(), locs.end(), std::back_inserter(m_locales), [](const QString& locale) -> QVariant {
return QVariant::fromValue(Language {
......@@ -57,38 +65,53 @@ class KISS : public QObject
delete m_backend;
}
Q_PROPERTY(QVariantList locales READ locales)
Q_PROPERTY(QVariantList locales READ locales CONSTANT)
public: QVariantList locales() const
{
return m_locales;
}
public: Q_SIGNAL void finished(bool success);
public: Q_INVOKABLE void createAccount(const QString& realname, const QString& username, const QString& password, const bool& admin, const QString& language)
Q_PROPERTY(QStringList pages READ pages CONSTANT)
public: QStringList pages() const
{
auto watcher = new QDBusPendingCallWatcher(m_accountsInterface->CreateUser(username, realname, admin ? 1 : 0), this);
connect(watcher, &QDBusPendingCallWatcher::finished, [=, this](QDBusPendingCallWatcher* self) {
QDBusPendingReply<QDBusObjectPath> reply = *self;
if (reply.isError()) {
Q_EMIT finished(false);
return;
}
auto user = OrgFreedesktopAccountsUserInterface(QStringLiteral("org.freedesktop.Accounts"), reply.value().path(), QDBusConnection::systemBus(), this);
m_name = user.userName();
user.SetLanguage(language);
user.SetPassword(password, QString());
Q_EMIT finished(true);
});
return Settings::instance()->pages();
}
#define synth_prop(kind, name, default) Q_PROPERTY(kind name READ name WRITE set_ ## name RESET reset_ ## name NOTIFY name ## _changed) \
std::optional<kind> m_ ## name;\
Q_SIGNAL void name ## _changed();\
public: kind name() {\
return m_ ## name.value_or(default);\
}\
public: void set_ ## name(const kind& t) {\
if (!m_ ## name.has_value() || m_ ## name.value() != t) {\
m_ ## name = t; Q_EMIT name ## _changed();\
}\
}\
public: void reset_ ## name() {\
if (m_ ## name.has_value()) {\
m_ ## name.reset(); Q_EMIT name ## _changed();\
}\
}
// The stuff that we may potentially use when setting stuff up
synth_prop(QString, targetLanguage, QStringLiteral("en_US"))
synth_prop(QString, username, QString())
synth_prop(QString, realname, QString())
synth_prop(QString, password, QString())
synth_prop(bool, admin, true)
public: Q_INVOKABLE void disableSelf()
{
auto reply = m_accountsInterface->CreateUser(username(), realname(), admin() ? 1 : 0);
auto user = OrgFreedesktopAccountsUserInterface(QStringLiteral("org.freedesktop.Accounts"), reply.value().path(), QDBusConnection::systemBus(), this);
user.SetLanguage(targetLanguage());
user.SetPassword(password(), QString());
Systemd::instance()->disableService("org.kde.initialsystemsetup");
m_backend->yeetToSession(m_name);
m_backend->yeetToSession(username());
Systemd::instance()->stopService("org.kde.initialsystemsetup");
}
......
#pragma once
#undef signals
#include <gio/gio.h>
class Settings
{
GSettings* m_settings;
QStringList m_pages;
QString m_dm;
QString m_session;
private: Settings()
{
m_settings = g_settings_new("org.kde.initialsystemsetup");
GVariantIter *iter;
gchar *str;
m_pages << "locale";
g_settings_get(m_settings, "stages", "as", &iter);
while (g_variant_iter_loop (iter, "s", &str))
m_pages << QString::fromLocal8Bit(str);
m_pages << "ready";
g_variant_iter_free (iter);
auto session = g_settings_get_string(m_settings, "desktop-session");
m_session = QString::fromLocal8Bit(session);
g_free(session);
auto dm = g_settings_get_string(m_settings, "display-manager-backend");
m_dm = QString::fromLocal8Bit(dm);
g_free(dm);
}
private: ~Settings()
{
g_free(m_settings);
}
public: static Settings* instance()
{
Settings* inst = nullptr;
if (inst == nullptr) {
inst = new Settings;
}
return inst;
}
public: QString displayManager() const
{
return m_dm;
}
public: QString session() const
{
return m_session;
}
public: QStringList pages() const
{
return m_pages;
}
};
<?xml version="1.0" encoding="utf-8"?>
<schemalist>
<enum id="org.kde.initialsystemsetup.DisplayManagers">
<value nick="sddm" value="1" />
</enum>
<schema path="/org/kde/initialsystemsetup/" id="org.kde.initialsystemsetup">
<key name='display-manager-backend' enum='org.kde.initialsystemsetup.DisplayManagers'>
<default>'sddm'</default>
<summary>Display manager being used</summary>
<description>
This tells KISS which display manager is being used on the system.
This allows it to figure out which display manager to enable, and
how to launch a user session.
</description>
</key>
<key name="desktop-session" type="s">
<default>'plasmawayland.desktop'</default>
<summary>Which session to start after setup</summary>
<description>
This tells KISS which desktop file corresponding to an X11 or a
Wayland session should be started after initial system setup is
completed.
</description>
</key>
<key name="stages" type="as">
<default>['user']</default>
<summary>Which pages of the initial setup to show, and in which order.</summary>
<description>
This tells KISS which pages it should show. The language selection page
is always shown first, and the ready page is always shown last. The user
page is required to be in the list of vendor-provided pages, and KISS will
abort if it is not found.
</description>
</key>
</schema>
</schemalist>
Markdown is supported
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