v0.2.2: Preferences page, About page, full icon set, redesigned permissions list
- Add a Preferences page (reachable from the hamburger menu) with a KColorSchemeManager-backed color scheme switcher - Add an About page reading from KAboutData - Ship a full hicolor icon set (16-128px + scalable) via ecm_install_icons instead of a single flat SVG - Restyle the permissions list after KDE System Settings' Audio page: Kirigami.ListSectionHeader per category, flat separated rows, no card borders - Explicitly declare Kirigami/KirigamiAddons/ColorScheme as CMake dependencies instead of relying on the QML import scanner alone - Add KDEClangFormat/KDEGitCommitHooks, a CMakePresets.json, and a REUSE + clang-format lint CI workflow - Reformat SPDX headers to include copyright, and tidy up a stray namespace inconsistency
@@ -0,0 +1,16 @@
|
|||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
SPDX-License-Identifier: CC0-1.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Reason for the change
|
||||||
|
|
||||||
|
<!-- What problem does this solve, or what does it add? -->
|
||||||
|
|
||||||
|
## Test plan
|
||||||
|
|
||||||
|
<!-- How did you verify this? Build/run steps, commands, etc. -->
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
<!-- If this changes UI, include a before/after. -->
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
name: Build and Publish Flatpak
|
name: Build and Publish Flatpak
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
name: Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request: {}
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
reuse:
|
||||||
|
name: REUSE compliance
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: REUSE Compliance Check
|
||||||
|
uses: fsfe/reuse-action@v3
|
||||||
|
|
||||||
|
clang-format:
|
||||||
|
name: clang-format
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.10
|
||||||
|
options: --privileged
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Configure (generates the KDE .clang-format style)
|
||||||
|
run: cmake -B build -G Ninja -DBUILD_TESTING=OFF
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: |
|
||||||
|
find src autotests -name '*.h' -o -name '*.cpp' | \
|
||||||
|
xargs clang-format --dry-run --Werror
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
name: Build and Test
|
name: Build and Test
|
||||||
|
|
||||||
|
|||||||
@@ -8,3 +8,5 @@
|
|||||||
# Editor / misc
|
# Editor / misc
|
||||||
*.user
|
*.user
|
||||||
*.autosave
|
*.autosave
|
||||||
|
# Generated by ECM's KDEClangFormat module
|
||||||
|
/.clang-format
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
# FlatKontrol - a Kirigami/Qt Flatpak permissions manager
|
# FlatKontrol - a Kirigami/Qt Flatpak permissions manager
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(flatkontrol VERSION 0.2.1 LANGUAGES CXX)
|
project(flatkontrol VERSION 0.2.2 LANGUAGES CXX)
|
||||||
|
|
||||||
set(REQUIRED_QT_VERSION 6.6.0)
|
set(REQUIRED_QT_VERSION 6.6.0)
|
||||||
set(REQUIRED_KF_VERSION 6.5.0)
|
set(REQUIRED_KF_VERSION 6.5.0)
|
||||||
@@ -15,7 +17,10 @@ include(KDEInstallDirs)
|
|||||||
include(KDECMakeSettings)
|
include(KDECMakeSettings)
|
||||||
include(KDECompilerSettings NO_POLICY_SCOPE)
|
include(KDECompilerSettings NO_POLICY_SCOPE)
|
||||||
include(ECMSetupVersion)
|
include(ECMSetupVersion)
|
||||||
|
include(ECMInstallIcons)
|
||||||
include(FeatureSummary)
|
include(FeatureSummary)
|
||||||
|
include(KDEClangFormat)
|
||||||
|
include(KDEGitCommitHooks)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
@@ -39,6 +44,19 @@ find_package(KF6 ${REQUIRED_KF_VERSION} REQUIRED COMPONENTS
|
|||||||
IconThemes
|
IconThemes
|
||||||
Crash
|
Crash
|
||||||
DBusAddons
|
DBusAddons
|
||||||
|
ColorScheme
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(KF6Kirigami ${REQUIRED_KF_VERSION} REQUIRED)
|
||||||
|
set_package_properties(KF6Kirigami PROPERTIES
|
||||||
|
TYPE REQUIRED
|
||||||
|
DESCRIPTION "KDE's next-gen UI framework"
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(KF6KirigamiAddons REQUIRED)
|
||||||
|
set_package_properties(KF6KirigamiAddons PROPERTIES
|
||||||
|
TYPE REQUIRED
|
||||||
|
DESCRIPTION "Add-on components for Kirigami"
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_setup_version(${PROJECT_VERSION}
|
ecm_setup_version(${PROJECT_VERSION}
|
||||||
@@ -46,6 +64,7 @@ ecm_setup_version(${PROJECT_VERSION}
|
|||||||
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/flatkontrol-version.h"
|
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/flatkontrol-version.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(icons)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
@@ -56,11 +75,11 @@ install(PROGRAMS io.github.toservetheking.FlatKontrol.desktop
|
|||||||
DESTINATION ${KDE_INSTALL_APPDIR})
|
DESTINATION ${KDE_INSTALL_APPDIR})
|
||||||
install(FILES io.github.toservetheking.FlatKontrol.metainfo.xml
|
install(FILES io.github.toservetheking.FlatKontrol.metainfo.xml
|
||||||
DESTINATION ${KDE_INSTALL_METAINFODIR})
|
DESTINATION ${KDE_INSTALL_METAINFODIR})
|
||||||
install(FILES icons/io.github.toservetheking.FlatKontrol.svg
|
|
||||||
DESTINATION ${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps)
|
|
||||||
install(FILES LICENSES/GPL-3.0-or-later.txt
|
install(FILES LICENSES/GPL-3.0-or-later.txt
|
||||||
DESTINATION ${KDE_INSTALL_DATAROOTDIR}/licenses/${PROJECT_NAME})
|
DESTINATION ${KDE_INSTALL_DATAROOTDIR}/licenses/${PROJECT_NAME})
|
||||||
|
|
||||||
# Translations: add a po/ directory and re-enable ki18n_install(po) once present.
|
# Translations: add a po/ directory and re-enable ki18n_install(po) once present.
|
||||||
|
|
||||||
|
kde_configure_git_pre_commit_hook(CHECKS CLANG-FORMAT)
|
||||||
|
|
||||||
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"version": 6,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 23,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "ninja-dev",
|
||||||
|
"displayName": "Ninja (dev)",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"binaryDir": "${sourceDir}/build",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug",
|
||||||
|
"BUILD_TESTING": "ON"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
SPDX-License-Identifier: CC0-1.0
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# FlatKontrol
|
# FlatKontrol
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
A Flatpak permissions manager built the KDE way - C++ with a QML/Kirigami
|
A Flatpak permissions manager built the KDE way - C++ with a QML/Kirigami
|
||||||
frontend, ECM/CMake, and KDE Frameworks 6. Think [Flatseal], reimagined as if
|
frontend, ECM/CMake, and KDE Frameworks 6. Think [Flatseal], reimagined as if
|
||||||
the team behind [Elisa] had written it.
|
the team behind [Elisa] had written it.
|
||||||
@@ -51,7 +53,8 @@ toolchain. On Arch/CachyOS:
|
|||||||
```sh
|
```sh
|
||||||
sudo pacman -S --needed cmake extra-cmake-modules base-devel \
|
sudo pacman -S --needed cmake extra-cmake-modules base-devel \
|
||||||
qt6-base qt6-declarative kirigami kirigami-addons \
|
qt6-base qt6-declarative kirigami kirigami-addons \
|
||||||
ki18n kcoreaddons kiconthemes kcrash kdbusaddons kitemmodels qqc2-desktop-style
|
ki18n kcoreaddons kiconthemes kcrash kdbusaddons kitemmodels \
|
||||||
|
kcolorscheme qqc2-desktop-style
|
||||||
```
|
```
|
||||||
|
|
||||||
Then:
|
Then:
|
||||||
@@ -70,6 +73,7 @@ cmake --build build
|
|||||||
- `permissioncatalog.{h,cpp}` - the static catalog of categories and options.
|
- `permissioncatalog.{h,cpp}` - the static catalog of categories and options.
|
||||||
- `portalsbackend.{h,cpp}` - QtDBus PermissionStore client.
|
- `portalsbackend.{h,cpp}` - QtDBus PermissionStore client.
|
||||||
- `permissionscontroller.{h,cpp}` - per-app state, resolution, and the row model.
|
- `permissionscontroller.{h,cpp}` - per-app state, resolution, and the row model.
|
||||||
|
- `appcolorscheme.{h,cpp}` - QML-facing wrapper around `KColorSchemeManager` for the Preferences page.
|
||||||
- `qml/` - Kirigami UI.
|
- `qml/` - Kirigami UI.
|
||||||
|
|
||||||
[Flatseal]: https://github.com/tchx84/Flatseal
|
[Flatseal]: https://github.com/tchx84/Flatseal
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ path = [
|
|||||||
"io.github.toservetheking.FlatKontrol.desktop",
|
"io.github.toservetheking.FlatKontrol.desktop",
|
||||||
"keys/*.asc",
|
"keys/*.asc",
|
||||||
"screenshots/*",
|
"screenshots/*",
|
||||||
|
"icons/*.png",
|
||||||
]
|
]
|
||||||
SPDX-License-Identifier = "GPL-3.0-or-later"
|
SPDX-License-Identifier = "GPL-3.0-or-later"
|
||||||
SPDX-FileCopyrightText = "ToServeTheKing <[email protected]>"
|
SPDX-FileCopyrightText = "ToServeTheKing <[email protected]>"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
add_executable(resolutiontest
|
add_executable(resolutiontest
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#include "keyfile.h"
|
#include "keyfile.h"
|
||||||
#include "permissionscontroller.h"
|
#include "permissionscontroller.h"
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 526 B |
|
After Width: | Height: | Size: 739 B |
|
After Width: | Height: | Size: 971 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,16 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
ecm_install_icons(ICONS
|
||||||
|
sc-apps-flatkontrol.svg
|
||||||
|
128-apps-flatkontrol.png
|
||||||
|
64-apps-flatkontrol.png
|
||||||
|
48-apps-flatkontrol.png
|
||||||
|
44-apps-flatkontrol.png
|
||||||
|
32-apps-flatkontrol.png
|
||||||
|
22-apps-flatkontrol.png
|
||||||
|
16-apps-flatkontrol.png
|
||||||
|
DESTINATION ${KDE_INSTALL_ICONDIR}
|
||||||
|
THEME hicolor
|
||||||
|
)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]> -->
|
||||||
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
|
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
|
||||||
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
|
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
|
||||||
<defs>
|
<defs>
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -61,6 +61,16 @@
|
|||||||
<content_rating type="oars-1.1"/>
|
<content_rating type="oars-1.1"/>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="0.2.2" date="2026-07-03">
|
||||||
|
<description>
|
||||||
|
<ul>
|
||||||
|
<li>Add a Preferences page with a color-scheme switcher</li>
|
||||||
|
<li>Add an About page</li>
|
||||||
|
<li>Ship a full hicolor icon set instead of a single scalable SVG</li>
|
||||||
|
<li>Match KDE System Settings' Audio page layout for the permission list</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="0.2.1" date="2026-07-03">
|
<release version="0.2.1" date="2026-07-03">
|
||||||
<description>
|
<description>
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
id: io.github.toservetheking.FlatKontrol
|
id: io.github.toservetheking.FlatKontrol
|
||||||
runtime: org.kde.Platform
|
runtime: org.kde.Platform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
add_executable(flatkontrol
|
add_executable(flatkontrol
|
||||||
@@ -15,11 +17,14 @@ qt_add_qml_module(flatkontrol
|
|||||||
QML_FILES
|
QML_FILES
|
||||||
qml/Main.qml
|
qml/Main.qml
|
||||||
qml/PermissionsPage.qml
|
qml/PermissionsPage.qml
|
||||||
|
qml/SettingsPage.qml
|
||||||
SOURCES
|
SOURCES
|
||||||
applicationsmodel.cpp
|
applicationsmodel.cpp
|
||||||
applicationsmodel.h
|
applicationsmodel.h
|
||||||
permissionscontroller.cpp
|
permissionscontroller.cpp
|
||||||
permissionscontroller.h
|
permissionscontroller.h
|
||||||
|
appcolorscheme.cpp
|
||||||
|
appcolorscheme.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(flatkontrol PRIVATE ${CMAKE_BINARY_DIR})
|
target_include_directories(flatkontrol PRIVATE ${CMAKE_BINARY_DIR})
|
||||||
@@ -38,6 +43,8 @@ target_link_libraries(flatkontrol PRIVATE
|
|||||||
KF6::IconThemes
|
KF6::IconThemes
|
||||||
KF6::Crash
|
KF6::Crash
|
||||||
KF6::DBusAddons
|
KF6::DBusAddons
|
||||||
|
KF6::ColorScheme
|
||||||
|
KF6::Kirigami
|
||||||
)
|
)
|
||||||
|
|
||||||
install(TARGETS flatkontrol ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
install(TARGETS flatkontrol ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "appcolorscheme.h"
|
||||||
|
|
||||||
|
#include <KColorSchemeManager>
|
||||||
|
|
||||||
|
AppColorScheme::AppColorScheme(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, mSchemes(KColorSchemeManager::instance())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractItemModel *AppColorScheme::colorSchemesModel()
|
||||||
|
{
|
||||||
|
return mSchemes->model();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AppColorScheme::activeColorSchemeName() const
|
||||||
|
{
|
||||||
|
return mSchemes->activeSchemeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppColorScheme::setActiveColorSchemeName(const QString &name)
|
||||||
|
{
|
||||||
|
if (name == activeColorSchemeName()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mSchemes->activateScheme(mSchemes->indexForScheme(name));
|
||||||
|
Q_EMIT activeColorSchemeNameChanged();
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
class KColorSchemeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thin QML-facing wrapper around KColorSchemeManager: exposes the list of
|
||||||
|
* installed color schemes and the currently active one. KColorSchemeManager
|
||||||
|
* autosaves the active scheme itself, so there is nothing else to persist.
|
||||||
|
*/
|
||||||
|
class AppColorScheme : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_SINGLETON
|
||||||
|
Q_PROPERTY(QAbstractItemModel *colorSchemesModel READ colorSchemesModel CONSTANT)
|
||||||
|
Q_PROPERTY(QString activeColorSchemeName READ activeColorSchemeName WRITE setActiveColorSchemeName NOTIFY activeColorSchemeNameChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AppColorScheme(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QAbstractItemModel *colorSchemesModel();
|
||||||
|
QString activeColorSchemeName() const;
|
||||||
|
void setActiveColorSchemeName(const QString &name);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void activeColorSchemeNameChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
KColorSchemeManager *mSchemes;
|
||||||
|
};
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#include "applicationsmodel.h"
|
#include "applicationsmodel.h"
|
||||||
|
|
||||||
#include <KDirWatch>
|
#include <KDirWatch>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "flatpakinstallations.h"
|
#include "flatpakinstallations.h"
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#include "flatpakinstallations.h"
|
#include "flatpakinstallations.h"
|
||||||
#include "keyfile.h"
|
#include "keyfile.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#include "keyfile.h"
|
#include "keyfile.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#include "flatkontrol-version.h"
|
#include "flatkontrol-version.h"
|
||||||
|
|
||||||
#include "applicationsmodel.h"
|
#include "applicationsmodel.h"
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#include "permissioncatalog.h"
|
#include "permissioncatalog.h"
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#include "permissionscontroller.h"
|
#include "permissionscontroller.h"
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "flatpakinstallations.h"
|
#include "flatpakinstallations.h"
|
||||||
@@ -187,7 +192,7 @@ private:
|
|||||||
static bool isFilesystemPreset(const QString &bareToken);
|
static bool isFilesystemPreset(const QString &bareToken);
|
||||||
|
|
||||||
FlatpakInstallations m_installations;
|
FlatpakInstallations m_installations;
|
||||||
FlatKontrol::PortalsBackend m_portals;
|
PortalsBackend m_portals;
|
||||||
|
|
||||||
QString m_appId;
|
QString m_appId;
|
||||||
QString m_appName;
|
QString m_appName;
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#include "portalsbackend.h"
|
#include "portalsbackend.h"
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
@@ -9,9 +14,6 @@
|
|||||||
#include <QDBusMessage>
|
#include <QDBusMessage>
|
||||||
#include <QDBusReply>
|
#include <QDBusReply>
|
||||||
|
|
||||||
namespace FlatKontrol
|
|
||||||
{
|
|
||||||
|
|
||||||
static constexpr uint SUPPORTED_SERVICE_VERSION = 2;
|
static constexpr uint SUPPORTED_SERVICE_VERSION = 2;
|
||||||
static const char *DBUS_PATH = "/org/freedesktop/impl/portal/PermissionStore";
|
static const char *DBUS_PATH = "/org/freedesktop/impl/portal/PermissionStore";
|
||||||
static const char *DBUS_IFACE = "org.freedesktop.impl.portal.PermissionStore";
|
static const char *DBUS_IFACE = "org.freedesktop.impl.portal.PermissionStore";
|
||||||
@@ -253,5 +255,3 @@ void PortalsBackend::reload()
|
|||||||
m_supported.clear();
|
m_supported.clear();
|
||||||
m_reasons.clear();
|
m_reasons.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FlatKontrol
|
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
@@ -8,9 +13,6 @@
|
|||||||
|
|
||||||
class QDBusInterface;
|
class QDBusInterface;
|
||||||
|
|
||||||
namespace FlatKontrol
|
|
||||||
{
|
|
||||||
|
|
||||||
/// Tri-state (plus availability) of a portal permission, matching Flatseal.
|
/// Tri-state (plus availability) of a portal permission, matching Flatseal.
|
||||||
enum class PortalState {
|
enum class PortalState {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
@@ -71,5 +73,3 @@ private:
|
|||||||
QHash<QString, bool> m_supported; // property -> supported
|
QHash<QString, bool> m_supported; // property -> supported
|
||||||
QHash<QString, QString> m_reasons; // property -> reason
|
QHash<QString, QString> m_reasons; // property -> reason
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FlatKontrol
|
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -7,6 +12,7 @@ import QtQuick.Layouts
|
|||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kitemmodels as KItemModels
|
import org.kde.kitemmodels as KItemModels
|
||||||
import org.kde.kirigamiaddons.delegates as Delegates
|
import org.kde.kirigamiaddons.delegates as Delegates
|
||||||
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
import io.github.toservetheking.FlatKontrol
|
import io.github.toservetheking.FlatKontrol
|
||||||
|
|
||||||
Kirigami.ApplicationWindow {
|
Kirigami.ApplicationWindow {
|
||||||
@@ -19,6 +25,44 @@ Kirigami.ApplicationWindow {
|
|||||||
width: Kirigami.Units.gridUnit * 48
|
width: Kirigami.Units.gridUnit * 48
|
||||||
height: Kirigami.Units.gridUnit * 34
|
height: Kirigami.Units.gridUnit * 34
|
||||||
|
|
||||||
|
globalDrawer: Kirigami.GlobalDrawer {
|
||||||
|
isMenu: true
|
||||||
|
actions: [
|
||||||
|
Kirigami.Action {
|
||||||
|
text: i18nc("@action:inmenu", "Preferences…")
|
||||||
|
icon.name: "configure"
|
||||||
|
onTriggered: root.pageStack.pushDialogLayer(settingsPageComponent, {
|
||||||
|
width: root.width
|
||||||
|
}, {
|
||||||
|
width: Kirigami.Units.gridUnit * 24,
|
||||||
|
height: Kirigami.Units.gridUnit * 20,
|
||||||
|
modality: Qt.NonModal
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Kirigami.Action {
|
||||||
|
text: i18nc("@action:inmenu", "About %1", root.title)
|
||||||
|
icon.name: "help-about"
|
||||||
|
onTriggered: root.pageStack.pushDialogLayer(aboutPageComponent, {
|
||||||
|
width: root.width
|
||||||
|
}, {
|
||||||
|
width: Kirigami.Units.gridUnit * 30,
|
||||||
|
height: Kirigami.Units.gridUnit * 30,
|
||||||
|
modality: Qt.NonModal
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: aboutPageComponent
|
||||||
|
FormCard.AboutPage {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: settingsPageComponent
|
||||||
|
SettingsPage {}
|
||||||
|
}
|
||||||
|
|
||||||
ApplicationsModel {
|
ApplicationsModel {
|
||||||
id: appsModel
|
id: appsModel
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
// Styled after KDE System Settings' Audio page (plasma-pa's kcm/ui/main.qml):
|
||||||
|
// Kirigami.ListSectionHeader per category, flat rows indented under the
|
||||||
|
// header and separated by Kirigami.Separator, no card/border around them.
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -8,7 +16,6 @@ import QtQuick.Dialogs
|
|||||||
import Qt.labs.qmlmodels
|
import Qt.labs.qmlmodels
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kitemmodels as KItemModels
|
import org.kde.kitemmodels as KItemModels
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
|
||||||
import io.github.toservetheking.FlatKontrol
|
import io.github.toservetheking.FlatKontrol
|
||||||
|
|
||||||
Kirigami.ScrollablePage {
|
Kirigami.ScrollablePage {
|
||||||
@@ -22,10 +29,12 @@ Kirigami.ScrollablePage {
|
|||||||
|
|
||||||
leftPadding: 0
|
leftPadding: 0
|
||||||
rightPadding: 0
|
rightPadding: 0
|
||||||
topPadding: Kirigami.Units.gridUnit
|
// No topPadding: Kirigami.ListSectionHeader (the first thing on the
|
||||||
|
// page) already carries its own top padding, and stacking ours on top
|
||||||
|
// of that left an oversized gap above the first category.
|
||||||
bottomPadding: Kirigami.Units.gridUnit
|
bottomPadding: Kirigami.Units.gridUnit
|
||||||
|
|
||||||
// A small status marker used across delegates.
|
// A small status marker used across rows.
|
||||||
component StatusBadge: Kirigami.Icon {
|
component StatusBadge: Kirigami.Icon {
|
||||||
property int state: 0
|
property int state: 0
|
||||||
visible: state > 0
|
visible: state > 0
|
||||||
@@ -86,7 +95,7 @@ Kirigami.ScrollablePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: Kirigami.Units.largeSpacing
|
spacing: 0
|
||||||
visible: page.hasSelection
|
visible: page.hasSelection
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
@@ -100,20 +109,29 @@ Kirigami.ScrollablePage {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
FormCard.FormHeader {
|
Kirigami.ListSectionHeader {
|
||||||
title: section.modelData.title
|
Layout.fillWidth: true
|
||||||
|
text: section.modelData.title
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormCard {
|
KItemModels.KSortFilterProxyModel {
|
||||||
KItemModels.KSortFilterProxyModel {
|
id: catModel
|
||||||
id: catModel
|
sourceModel: page.controller
|
||||||
sourceModel: page.controller
|
filterRoleName: "categoryId"
|
||||||
filterRoleName: "categoryId"
|
// No category id is a substring of another, so this is an exact match.
|
||||||
// No category id is a substring of another, so this is an exact match.
|
filterString: section.modelData.id
|
||||||
filterString: section.modelData.id
|
}
|
||||||
}
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||||
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||||
|
spacing: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
id: rowRepeater
|
||||||
model: catModel
|
model: catModel
|
||||||
|
|
||||||
delegate: DelegateChooser {
|
delegate: DelegateChooser {
|
||||||
@@ -122,7 +140,7 @@ Kirigami.ScrollablePage {
|
|||||||
// Toggle
|
// Toggle
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: 0
|
roleValue: 0
|
||||||
delegate: FormCard.FormSwitchDelegate {
|
delegate: ColumnLayout {
|
||||||
id: toggleD
|
id: toggleD
|
||||||
required property int index
|
required property int index
|
||||||
required property string label
|
required property string label
|
||||||
@@ -130,18 +148,51 @@ Kirigami.ScrollablePage {
|
|||||||
required property bool value
|
required property bool value
|
||||||
required property int status
|
required property int status
|
||||||
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
||||||
text: label
|
Layout.fillWidth: true
|
||||||
description: example
|
spacing: Kirigami.Units.smallSpacing
|
||||||
checked: value
|
|
||||||
icon.name: status === 2 ? "document-edit-symbolic" : (status === 1 ? "globe-symbolic" : "")
|
RowLayout {
|
||||||
onToggled: page.controller.setToggleValue(sourceRow, checked)
|
Layout.fillWidth: true
|
||||||
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: toggleD.label
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: toggleD.example
|
||||||
|
visible: text.length > 0
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
font: Kirigami.Theme.smallFont
|
||||||
|
color: Kirigami.Theme.disabledTextColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StatusBadge {
|
||||||
|
state: toggleD.status
|
||||||
|
}
|
||||||
|
QQC2.Switch {
|
||||||
|
checked: toggleD.value
|
||||||
|
onToggled: page.controller.setToggleValue(toggleD.sourceRow, checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
visible: toggleD.index !== rowRepeater.count - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filesystem path (with access mode + Browse)
|
// Filesystem path (with access mode + Browse)
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: 1
|
roleValue: 1
|
||||||
delegate: FormCard.AbstractFormDelegate {
|
delegate: ColumnLayout {
|
||||||
id: fsD
|
id: fsD
|
||||||
required property int index
|
required property int index
|
||||||
required property string value
|
required property string value
|
||||||
@@ -149,7 +200,8 @@ Kirigami.ScrollablePage {
|
|||||||
required property int status
|
required property int status
|
||||||
required property bool removable
|
required property bool removable
|
||||||
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
||||||
background: null
|
Layout.fillWidth: true
|
||||||
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
FolderDialog {
|
FolderDialog {
|
||||||
id: folderDialog
|
id: folderDialog
|
||||||
@@ -160,7 +212,8 @@ Kirigami.ScrollablePage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: RowLayout {
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
QQC2.TextField {
|
QQC2.TextField {
|
||||||
id: fsField
|
id: fsField
|
||||||
@@ -190,21 +243,30 @@ Kirigami.ScrollablePage {
|
|||||||
onClicked: page.controller.removeEntry(fsD.sourceRow)
|
onClicked: page.controller.removeEntry(fsD.sourceRow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
visible: fsD.index !== rowRepeater.count - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persistent (home-relative) path
|
// Persistent (home-relative) path
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: 2
|
roleValue: 2
|
||||||
delegate: FormCard.AbstractFormDelegate {
|
delegate: ColumnLayout {
|
||||||
id: relD
|
id: relD
|
||||||
required property int index
|
required property int index
|
||||||
required property string value
|
required property string value
|
||||||
required property int status
|
required property int status
|
||||||
required property bool removable
|
required property bool removable
|
||||||
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
||||||
background: null
|
Layout.fillWidth: true
|
||||||
contentItem: RowLayout {
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
QQC2.TextField {
|
QQC2.TextField {
|
||||||
text: relD.value
|
text: relD.value
|
||||||
@@ -221,13 +283,19 @@ Kirigami.ScrollablePage {
|
|||||||
onClicked: page.controller.removeEntry(relD.sourceRow)
|
onClicked: page.controller.removeEntry(relD.sourceRow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
visible: relD.index !== rowRepeater.count - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Environment variable
|
// Environment variable
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: 3
|
roleValue: 3
|
||||||
delegate: FormCard.AbstractFormDelegate {
|
delegate: ColumnLayout {
|
||||||
id: varD
|
id: varD
|
||||||
required property int index
|
required property int index
|
||||||
required property string value
|
required property string value
|
||||||
@@ -235,8 +303,11 @@ Kirigami.ScrollablePage {
|
|||||||
required property int status
|
required property int status
|
||||||
required property bool removable
|
required property bool removable
|
||||||
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
||||||
background: null
|
Layout.fillWidth: true
|
||||||
contentItem: RowLayout {
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
QQC2.TextField {
|
QQC2.TextField {
|
||||||
text: varD.value
|
text: varD.value
|
||||||
@@ -262,13 +333,19 @@ Kirigami.ScrollablePage {
|
|||||||
onClicked: page.controller.removeEntry(varD.sourceRow)
|
onClicked: page.controller.removeEntry(varD.sourceRow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
visible: varD.index !== rowRepeater.count - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// D-Bus name policy
|
// D-Bus name policy
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: 4
|
roleValue: 4
|
||||||
delegate: FormCard.AbstractFormDelegate {
|
delegate: ColumnLayout {
|
||||||
id: busD
|
id: busD
|
||||||
required property int index
|
required property int index
|
||||||
required property string value
|
required property string value
|
||||||
@@ -276,8 +353,11 @@ Kirigami.ScrollablePage {
|
|||||||
required property int status
|
required property int status
|
||||||
required property bool removable
|
required property bool removable
|
||||||
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
||||||
background: null
|
Layout.fillWidth: true
|
||||||
contentItem: RowLayout {
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
QQC2.TextField {
|
QQC2.TextField {
|
||||||
text: busD.value
|
text: busD.value
|
||||||
@@ -299,13 +379,19 @@ Kirigami.ScrollablePage {
|
|||||||
onClicked: page.controller.removeEntry(busD.sourceRow)
|
onClicked: page.controller.removeEntry(busD.sourceRow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
visible: busD.index !== rowRepeater.count - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Portal (tri-state)
|
// Portal (tri-state)
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: 5
|
roleValue: 5
|
||||||
delegate: FormCard.FormComboBoxDelegate {
|
delegate: ColumnLayout {
|
||||||
id: portalD
|
id: portalD
|
||||||
required property int index
|
required property int index
|
||||||
required property string label
|
required property string label
|
||||||
@@ -315,19 +401,51 @@ Kirigami.ScrollablePage {
|
|||||||
required property string unsupportedReason
|
required property string unsupportedReason
|
||||||
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
readonly property int sourceRow: catModel.mapToSource(catModel.index(index, 0)).row
|
||||||
readonly property var states: [2, 4, 3]
|
readonly property var states: [2, 4, 3]
|
||||||
text: label
|
Layout.fillWidth: true
|
||||||
description: supported ? example : unsupportedReason
|
spacing: Kirigami.Units.smallSpacing
|
||||||
enabled: supported
|
|
||||||
model: [i18n("Unset"), i18n("Allowed"), i18n("Disallowed")]
|
RowLayout {
|
||||||
currentIndex: value === 4 ? 1 : (value === 3 ? 2 : 0)
|
Layout.fillWidth: true
|
||||||
onActivated: page.controller.setPortalValue(sourceRow, states[currentIndex])
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: portalD.label
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
enabled: portalD.supported
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: portalD.supported ? portalD.example : portalD.unsupportedReason
|
||||||
|
visible: text.length > 0
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
font: Kirigami.Theme.smallFont
|
||||||
|
color: Kirigami.Theme.disabledTextColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QQC2.ComboBox {
|
||||||
|
enabled: portalD.supported
|
||||||
|
model: [i18n("Unset"), i18n("Allowed"), i18n("Disallowed")]
|
||||||
|
currentIndex: portalD.value === 4 ? 1 : (portalD.value === 3 ? 2 : 0)
|
||||||
|
onActivated: page.controller.setPortalValue(portalD.sourceRow, portalD.states[currentIndex])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
visible: portalD.index !== rowRepeater.count - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Add entry" affordance
|
// "Add entry" affordance
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: 6
|
roleValue: 6
|
||||||
delegate: FormCard.FormButtonDelegate {
|
delegate: QQC2.Button {
|
||||||
id: addD
|
id: addD
|
||||||
required property string categoryId
|
required property string categoryId
|
||||||
text: i18nc("@action", "Add…")
|
text: i18nc("@action", "Add…")
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
// Styled after KDE System Settings' Audio page (plasma-pa's kcm/ui/main.qml):
|
||||||
|
// Kirigami.ListSectionHeader per section, flat rows indented under the
|
||||||
|
// header, no card/border around them.
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import org.kde.kirigami as Kirigami
|
||||||
|
import io.github.toservetheking.FlatKontrol
|
||||||
|
|
||||||
|
Kirigami.ScrollablePage {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: i18nc("@title:window", "Preferences")
|
||||||
|
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
// No topPadding: Kirigami.ListSectionHeader (the first thing on the
|
||||||
|
// page) already carries its own top padding, and stacking ours on top
|
||||||
|
// of that left an oversized gap above "Appearance".
|
||||||
|
bottomPadding: Kirigami.Units.gridUnit
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
width: root.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Kirigami.ListSectionHeader {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: i18nc("@title:group", "Appearance")
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||||
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||||
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: i18nc("@label:listbox", "Color scheme")
|
||||||
|
}
|
||||||
|
QQC2.ComboBox {
|
||||||
|
id: colorSchemeCombo
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
model: AppColorScheme.colorSchemesModel
|
||||||
|
textRole: "display"
|
||||||
|
|
||||||
|
delegate: QQC2.ItemDelegate {
|
||||||
|
id: schemeDelegate
|
||||||
|
required property var model
|
||||||
|
width: colorSchemeCombo.width
|
||||||
|
|
||||||
|
icon.source: "image://colorScheme/" + schemeDelegate.model.display
|
||||||
|
icon.color: "transparent"
|
||||||
|
text: schemeDelegate.model.display
|
||||||
|
highlighted: schemeDelegate.model.display === AppColorScheme.activeColorSchemeName
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
AppColorScheme.activeColorSchemeName = schemeDelegate.model.display;
|
||||||
|
colorSchemeCombo.popup.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the closed-box label in sync without fighting the popup's own selection state.
|
||||||
|
displayText: AppColorScheme.activeColorSchemeName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||