9 Commits
Author SHA1 Message Date
zach bc6b0d50ab Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 34s
Python / lint-format (pull_request) Successful in 35s
Python / test (pull_request) Successful in 1m11s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m58s
C++ / build (pull_request) Successful in 4m31s
2026-06-29 22:10:45 +02:00
AramJonghuandzach bc9d8af0fe update to clang-tidy + workflow improvement cpp build & lint check (#130)
### Goal

Idea is to reduce the annoyances and research which clang-tidy rules make sense and actually have benefits in our project.

Also considering immediately resolving most if not all tidy warnings.

### Current Changes

- `.clang-tidy` has changes to follow the guidelines we have been following silently. Some rules were different from how we program.
    - Note that naming is completely removed and won't be checked. In a future PR (where we go over the code to fix linting issues), we can reintroduce them and make sure they fit our codebase consistently.
- tidy rules are not considered errors anymore (stopped compile).
- CI/CD addition to build check and clang-tidy check. Tried to get clang-tidy check to show when failed, but that causes complications in its checks; so now it is simply silent when failing.
- Dockerfile that creates an arch container as cache for the CI/CD, prevents redownload of dependencies each run. Instead, it runs weekly (or optionally a different interval).

### Current complications

- To push the docker container build, it would require this webserver to allow larger filesize pushes (need ~2GB). Current workaround is arguably better where docker build is pushed to runner server.
- Figuring out which clang-tidy rules make sense.

Reviewed-on: #130
Co-authored-by: AramJonghu <aramjonghu@tutamail.com>
Co-committed-by: AramJonghu <aramjonghu@tutamail.com>
2026-06-29 22:10:26 +02:00
zach 7d65578a5f proper VERSION var 2026-06-29 19:37:11 +02:00
zach f883b3d7fe versioning 2026-06-29 18:57:32 +02:00
zach f27c9afc25 more methods for wifi and scanning + layout
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 15s
Python / test (pull_request) Successful in 29s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m6s
2026-06-26 15:15:03 +02:00
Inorishio 5962fc8354 Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 17s
Python / lint-format (pull_request) Successful in 27s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m39s
2026-06-24 18:58:36 +02:00
Inorishio 1adcb9841c Added network properties, nicNames, netDevices, networkName < reminder I should use layouts.
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 16s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m52s
2026-06-22 23:34:58 +02:00
Inorishio 0e0f8555ed fixing singleton in helpers for network + getting output from systray 2026-06-15 20:48:01 +02:00
Inorishio 1d63e67554 removed network module and moved it to tray, have a popout window without content! everything still in wi.i.p. 2026-06-13 18:22:03 +02:00
19 changed files with 569 additions and 134 deletions
+10 -19
View File
@@ -2,29 +2,20 @@
Checks: > Checks: >
-*, -*,
bugprone-*, bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-narrowing-conversions,
-bugprone-implicit-widening-of-multiplication-result,
clang-analyzer-*, clang-analyzer-*,
modernize-*, cppcoreguidelines-init-variables,
-modernize-use-trailing-return-type, misc-no-recursion,
performance-*, concurrency-mt-unsafe,
readability-braces-around-statements,
readability-else-after-return, readability-else-after-return,
readability-identifier-naming, readability-make-member-function-const,
readability-redundant-*, readability-redundant-*,
readability-simplify-*, readability-simplify-*,
CheckOptions: modernize-use-override,
readability-identifier-naming.ClassCase: CamelCase modernize-use-nullptr,
readability-identifier-naming.EnumCase: CamelCase modernize-deprecated-headers,
readability-identifier-naming.FunctionCase: camelBack
readability-identifier-naming.MemberCase: camelBack
readability-identifier-naming.MemberPrefix: m_
readability-identifier-naming.MethodCase: camelBack
readability-identifier-naming.NamespaceCase: CamelCase
readability-identifier-naming.ParameterCase: camelBack
readability-identifier-naming.PrivateMemberPrefix: m_
readability-identifier-naming.StaticConstantCase: UPPER_CASE
readability-identifier-naming.StaticConstantPrefix: k
readability-identifier-naming.VariableCase: camelBack
WarningsAsErrors: "*"
HeaderFilterRegex: ".*" HeaderFilterRegex: ".*"
FormatStyle: file FormatStyle: file
+22
View File
@@ -0,0 +1,22 @@
name: Rebuild CI Image
on:
schedule:
- cron: '0 6 * * 1'
workflow_dispatch:
jobs:
build:
runs-on: alpine
env:
IMAGE: git.aramjonghu.nl/aramjonghu/zshell-ci:latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build image
run: docker build -t "$IMAGE" -f ci/Dockerfile .
- name: Push image
run: docker push "$IMAGE"
+29
View File
@@ -0,0 +1,29 @@
name: C++
on:
pull_request:
jobs:
build:
runs-on: alpine
container:
image: git.aramjonghu.nl/aramjonghu/zshell-ci:latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure
run: cmake -B build -G Ninja -DENABLE_MODULES=plugin -DCMAKE_BUILD_TYPE=Release
- name: Build
run: ninja -C build
- name: clang-tidy
continue-on-error: true
run: |
set -o pipefail
run-clang-tidy -p build -j $(nproc) -header-filter="Plugins/.*" 2>&1 | \
grep -v 'Suppressed\|non-user\|non-system\|unknown argument.*mno-direct'
+1
View File
@@ -15,3 +15,4 @@ dist/
**/target/ **/target/
**/test-plugins/ **/test-plugins/
**/Charts/ **/Charts/
**/network-dev/
+37 -8
View File
@@ -1,6 +1,35 @@
cmake_minimum_required(VERSION 3.19) cmake_minimum_required(VERSION 3.19)
project(ZShell) if(NOT DEFINED VERSION)
execute_process(
COMMAND git describe --tags --abbrev=0
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_LAST_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
if (GIT_LAST_TAG)
string(REGEX REPLACE "^v" "" GIT_LAST_TAG "${GIT_LAST_TAG}")
string(REPLACE "." ";" VERSION_LIST "${GIT_LAST_TAG}")
list(GET VERSION_LIST 0 VERSION_MAJOR)
list(GET VERSION_LIST 1 VERSION_MINOR)
execute_process(
COMMAND git rev-list v${VERSION_MAJOR}.${VERSION_MINOR}.0..HEAD --count
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE VERSION_PATCH
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
endif()
endif()
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
project(ZShell VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
message(STATUS "ZShell version: ${VERSION}")
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -15,11 +44,11 @@ set(INSTALL_QSCONFDIR "etc/xdg/quickshell/zshell" CACHE STRING "Quickshell confi
set(INSTALL_GREETERCONFDIR "etc/xdg/quickshell/zshell-greeter" CACHE STRING "Quickshell greeter install dir") set(INSTALL_GREETERCONFDIR "etc/xdg/quickshell/zshell-greeter" CACHE STRING "Quickshell greeter install dir")
add_compile_options( add_compile_options(
-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wall -Wextra -Wpedantic -Wshadow -Wconversion
-Wold-style-cast -Wnull-dereference -Wdouble-promotion -Wold-style-cast -Wnull-dereference -Wdouble-promotion
-Wformat=2 -Wfloat-equal -Woverloaded-virtual -Wformat=2 -Wfloat-equal -Woverloaded-virtual
-Wsign-conversion -Wredundant-decls -Wswitch -Wsign-conversion -Wredundant-decls -Wswitch
-Wunreachable-code -Wunreachable-code
) )
@@ -30,8 +59,8 @@ endif()
if("shell" IN_LIST ENABLE_MODULES) if("shell" IN_LIST ENABLE_MODULES)
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths) foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}") install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
endforeach() endforeach()
# Disable watching for changes # Disable watching for changes
file(READ shell.qml SHELL_QML) file(READ shell.qml SHELL_QML)
-4
View File
@@ -40,10 +40,6 @@ JsonObject {
id: "tray", id: "tray",
enabled: true enabled: true
}, },
{
id: "network",
enabled: false
},
{ {
id: "clock", id: "clock",
enabled: true enabled: true
+125
View File
@@ -0,0 +1,125 @@
pragma Singleton
import Quickshell
import Quickshell.Networking
import QtQuick
Singleton {
id: root
readonly property list<NetworkDevice> devices: Networking.devices.values
readonly property list<Network> networks: initialBuildNetworks()
property bool scanning: false
readonly property list<WifiDevice> wifiDevices: devices.filter(d => wifiDevice(d))
readonly property bool wifiEnabled: Networking.wifiEnabled
// Original code
readonly property list<NetworkDevice> netDevice: Networking.devices.values
readonly property string networkName: getNetworkName()
readonly property list<string> nicNames: networkInterfaceCardNames()
// Useless will prob remove
function getConnectedDevices() {
let connectedDevices = [];
for (var i = 0; i < netDevice.length; i++) {
if (netDevice[i].connected === true) {
connectedDevices.push(netDevice[i].name);
}
}
return connectedDevices;
}
// SHOULD retrieve network names of connected devices
// Currently only gives connected nic name
function getNetworkName() {
const devices = netDevice.filter(device => device.connected === true);
for (var i = 0; i < devices.length; i++) {
return devices[i].name;
}
return "Failed network name";
}
// Searches wired/wireless devices and sets them in a list
function networkInterfaceCardNames() {
let nicList = [];
for (let i = 0; i < netDevice.length; ++i) {
nicList.push(netDevice[i].name);
}
return nicList;
}
//
function initialBuildNetworks(): void {
const init = [];
for (const d of wifiDevices) {
d.scannerEnabled = true;
init.push(...d.networks.values);
d.scannerEnabled = false;
}
networks = init;
}
function isSecure(security): bool {
return !(security === WifiSecurityType.Open);
}
function rebuildNetworks(): void {
if (!scanning)
return;
const next = [];
for (const d of wifiDevices) {
next.push(...d.networks.values);
}
networks = next;
}
function rescanWifi(): void {
scanning = true;
setScan(true);
scanTimer.restart();
}
function setScan(value: bool): void {
for (const d of wifiDevices) {
d.scannerEnabled = value;
}
}
function setWifi(value: bool): void {
Networking.wifiEnabled = value;
}
function wifiDevice(dev): bool {
return dev.type === DeviceType.Wifi;
}
Timer {
id: scanTimer
interval: 5000
repeat: false
onTriggered: {
root.rebuildNetworks();
root.setScan(false);
root.scanning = false;
}
}
Timer {
interval: 500
repeat: true
running: root.scanning
onTriggered: {
root.rebuildNetworks();
}
}
}
-10
View File
@@ -9,7 +9,6 @@ import qs.Config
import qs.Helpers import qs.Helpers
import qs.Modules.SysTray import qs.Modules.SysTray
import qs.Modules.SysTray.Widgets import qs.Modules.SysTray.Widgets
import qs.Modules.Network
import qs.Modules.Updates import qs.Modules.Updates
RowLayout { RowLayout {
@@ -185,15 +184,6 @@ RowLayout {
} }
} }
DelegateChoice {
roleValue: "network"
delegate: WrappedLoader {
sourceComponent: NetworkWidget {
}
}
}
DelegateChoice { DelegateChoice {
roleValue: "media" roleValue: "media"
-1
View File
@@ -10,7 +10,6 @@ import qs.Config
import qs.Helpers import qs.Helpers
import qs.Modules.SysTray import qs.Modules.SysTray
import qs.Modules.SysTray.Widgets import qs.Modules.SysTray.Widgets
import qs.Modules.Network
Item { Item {
id: root id: root
-1
View File
@@ -6,7 +6,6 @@ import QtQuick
import qs.Config import qs.Config
import qs.Components import qs.Components
import qs.Modules.WSOverview import qs.Modules.WSOverview
import qs.Modules.Network
import qs.Modules.SysTray.Popouts import qs.Modules.SysTray.Popouts
import qs.Modules.Updates import qs.Modules.Updates
-36
View File
@@ -1,36 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Networking
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Modules
import qs.Helpers as Helpers
Item {
id: root
required property var wrapper
ColumnLayout {
id: layout
spacing: 8
Repeater {
model: Helpers.Network.devices
CustomRadioButton {
id: network
required property NetworkDevice modelData
checked: Helpers.Network.activeDevice?.name === modelData.name
text: modelData.description
visible: modelData.name !== "lo"
}
}
}
}
-25
View File
@@ -1,25 +0,0 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules
Item {
id: root
anchors.bottom: parent.bottom
anchors.top: parent.top
implicitWidth: layout.implicitWidth
RowLayout {
id: layout
anchors.bottom: parent.bottom
anchors.top: parent.top
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
text: "android_wifi_4_bar"
}
}
}
+219
View File
@@ -0,0 +1,219 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Components
import qs.Config
import qs.Helpers
CustomClippingRect {
id: root
required property var wrapper
anchors.horizontalCenter: parent.horizontalCenter
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: networkPopContent.height + networks.implicitHeight + networkPopContent.anchors.margins + networks.anchors.margins * 2
implicitWidth: 500 + 8 * 2
radius: (20 - Appearance.padding.small) * Appearance.rounding.scale
ColumnLayout {
id: networkPopContent
anchors.left: parent.left
anchors.margins: Appearance.padding.large
anchors.right: parent.right
anchors.top: parent.top
CustomText {
Layout.preferredHeight: visible ? implicitHeight : 0
Layout.rightMargin: Appearance.padding.extraSmall
font.pointSize: Appearance.font.size.large
text: qsTr("Network")
}
Toggle {
Layout.preferredHeight: visible ? implicitHeight : 0
checked: Network.wifiEnabled
label: qsTr("WiFi enabled")
toggle.onToggled: Network.setWifi(checked)
}
CustomText {
Layout.preferredHeight: visible ? implicitHeight : 0
Layout.rightMargin: Appearance.padding.extraSmall
Layout.topMargin: visible ? Appearance.spacing.small : 0
color: DynamicColors.palette.m3onSurfaceVariant
text: qsTr("%1 networks available").arg(Network.networks.length) // qmllint disable missing-property
}
}
ColumnLayout {
id: networks
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: Appearance.padding.large
anchors.right: parent.right
anchors.top: networkPopContent.bottom
Repeater {
model: ScriptModel {
values: [...Network.networks]
}
RowLayout {
id: networkItem
required property var modelData
Layout.fillWidth: true
Layout.preferredHeight: visible ? implicitHeight : 0
Layout.rightMargin: Appearance.padding.extraSmall
opacity: 0
scale: 0.7
spacing: Appearance.spacing.small
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
Behavior on scale {
Anim {
}
}
Component.onCompleted: {
opacity = 1;
scale = 1;
}
MaterialIcon {
color: networkItem.modelData.active ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant
text: Icons.getNetworkIcon(networkItem.modelData.signalStrength * 100, Network.isSecure(networkItem.modelData.security))
}
CustomText {
Layout.fillWidth: true
Layout.leftMargin: Appearance.spacing.extraSmall
Layout.rightMargin: Appearance.spacing.extraSmall
color: networkItem.modelData.active ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface
elide: Text.ElideRight
text: networkItem.modelData.name
}
CustomRect {
color: Qt.alpha(DynamicColors.palette.m3primary, networkItem.modelData.active ? 1 : 0)
implicitHeight: wirelessConnectIcon.implicitHeight + Appearance.padding.extraSmall
implicitWidth: implicitHeight
radius: Appearance.rounding.full
// CircularIndicator {
// anchors.fill: parent
// running: networkItem.loading
// }
StateLayer {
color: networkItem.modelData.active ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
onClicked: {
console.log(Network.devices[1].scannerEnabled, Network.devices[2].scannerEnabled, Network.devices[3].scannerEnabled, Network.devices[4].scannerEnabled);
}
}
MaterialIcon {
id: wirelessConnectIcon
anchors.centerIn: parent
animate: true
color: networkItem.modelData.active ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
text: networkItem.modelData.active ? "link_off" : "link"
// opacity: networkItem.loading ? 0 : 1
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
}
}
}
}
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: visible ? implicitHeight : 0
Layout.topMargin: visible ? Appearance.spacing.small : 0
color: DynamicColors.palette.m3primaryContainer
implicitHeight: rescanBtn.implicitHeight + Appearance.padding.small
radius: Appearance.rounding.full
StateLayer {
color: DynamicColors.palette.m3onPrimaryContainer
enabled: !Network.scanning
onClicked: Network.rescanWifi()
}
RowLayout {
id: rescanBtn
anchors.centerIn: parent
opacity: Network.scanning ? 0 : 1
spacing: Appearance.spacing.small
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
MaterialIcon {
id: scanIcon
Layout.topMargin: Math.round(fontInfo.pointSize * 0.0575)
animate: true
color: DynamicColors.palette.m3onPrimaryContainer
text: "wifi_find"
}
CustomText {
Layout.topMargin: -Math.round(scanIcon.fontInfo.pointSize * 0.0575)
color: DynamicColors.palette.m3onPrimaryContainer
text: qsTr("Rescan networks")
}
}
CircularIndicator {
anchors.centerIn: parent
bgColor: "transparent"
implicitSize: parent.implicitHeight - Appearance.padding.large
running: Network.scanning
strokeWidth: Appearance.padding.extraSmall / 2
}
}
}
component Toggle: RowLayout {
property alias checked: toggle.checked
required property string label
property alias toggle: toggle
Layout.fillWidth: true
Layout.rightMargin: Appearance.padding.extraSmall
spacing: Appearance.spacing.small
CustomText {
Layout.fillWidth: true
text: parent.label
}
CustomSwitch {
id: toggle
}
}
}
+9
View File
@@ -52,6 +52,11 @@ RowLayout {
id: "audio", id: "audio",
item: child item: child
}; };
if (child.objectName === "networkWidget" && Config.barConfig.popouts.network)
return {
id: "network",
item: child
};
if (child.objectName === "upowerWidget" && Config.barConfig.popouts.upower) if (child.objectName === "upowerWidget" && Config.barConfig.popouts.upower)
return { return {
id: "upower", id: "upower",
@@ -137,6 +142,10 @@ RowLayout {
objectName: "audioWidget" objectName: "audioWidget"
} }
NetworkWidget {
objectName: "networkWidget"
}
UPowerWidget { UPowerWidget {
height: parent.height height: parent.height
objectName: "upowerWidget" objectName: "upowerWidget"
+24
View File
@@ -0,0 +1,24 @@
import QtQuick
import QtQuick.Layouts
import Quickshell.Io
import Quickshell.Services.Pipewire
import qs.Daemons
import qs.Modules
import qs.Config
import qs.Components
RowLayout {
id: root
// property color barColor: DynamicColors.palette.m3primary
property color textColor: DynamicColors.palette.m3onSurface
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
animate: true
color: root.textColor // Network.connected ? root.textColor : DynamicColors.palette.m3error
fill: 1
font.pointSize: Appearance.font.size.larger
text: "android_wifi_4_bar"
}
}
+32 -30
View File
@@ -9,7 +9,7 @@ pkg_check_modules(Cava IMPORTED_TARGET libcava QUIET)
pkg_check_modules(GLIB REQUIRED glib-2.0 gobject-2.0 gio-2.0) pkg_check_modules(GLIB REQUIRED glib-2.0 gobject-2.0 gio-2.0)
if(NOT Cava_FOUND) if(NOT Cava_FOUND)
pkg_check_modules(Cava IMPORTED_TARGET cava REQUIRED) pkg_check_modules(Cava IMPORTED_TARGET cava REQUIRED)
endif() endif()
if(NOT TARGET Sensors::Sensors) if(NOT TARGET Sensors::Sensors)
@@ -24,48 +24,50 @@ set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml")
qt_standard_project_setup(REQUIRES 6.9) qt_standard_project_setup(REQUIRES 6.9)
function(qml_module arg_TARGET) function(qml_module arg_TARGET)
cmake_parse_arguments(PARSE_ARGV 1 arg "" "URI" "SOURCES;LIBRARIES") cmake_parse_arguments(PARSE_ARGV 1 arg "" "URI" "SOURCES;LIBRARIES")
qt_add_qml_module(${arg_TARGET} qt_add_qml_module(${arg_TARGET}
URI ${arg_URI} URI ${arg_URI}
VERSION 1.0 VERSION 1.0
SOURCES ${arg_SOURCES} SOURCES ${arg_SOURCES}
) )
qt_query_qml_module(${arg_TARGET} qt_query_qml_module(${arg_TARGET}
URI module_uri URI module_uri
VERSION module_version VERSION module_version
PLUGIN_TARGET module_plugin_target PLUGIN_TARGET module_plugin_target
TARGET_PATH module_target_path TARGET_PATH module_target_path
QMLDIR module_qmldir QMLDIR module_qmldir
TYPEINFO module_typeinfo TYPEINFO module_typeinfo
) )
set(module_dir "${INSTALL_QMLDIR}/${module_target_path}") set(module_dir "${INSTALL_QMLDIR}/${module_target_path}")
install(TARGETS ${arg_TARGET} LIBRARY DESTINATION "${module_dir}" RUNTIME DESTINATION "${module_dir}") install(TARGETS ${arg_TARGET} LIBRARY DESTINATION "${module_dir}" RUNTIME DESTINATION "${module_dir}")
install(TARGETS "${module_plugin_target}" LIBRARY DESTINATION "${module_dir}" RUNTIME DESTINATION "${module_dir}") install(TARGETS "${module_plugin_target}" LIBRARY DESTINATION "${module_dir}" RUNTIME DESTINATION "${module_dir}")
install(FILES "${module_qmldir}" DESTINATION "${module_dir}") install(FILES "${module_qmldir}" DESTINATION "${module_dir}")
install(FILES "${module_typeinfo}" DESTINATION "${module_dir}") install(FILES "${module_typeinfo}" DESTINATION "${module_dir}")
target_link_libraries(${arg_TARGET} PRIVATE Qt::Core Qt::Qml ${arg_LIBRARIES}) target_link_libraries(${arg_TARGET} PRIVATE Qt::Core Qt::Qml ${arg_LIBRARIES})
endfunction() endfunction()
qml_module(ZShell qml_module(ZShell
URI ZShell URI ZShell
SOURCES SOURCES
writefile.hpp writefile.cpp writefile.hpp writefile.cpp
appdb.hpp appdb.cpp appdb.hpp appdb.cpp
imageanalyser.hpp imageanalyser.cpp imageanalyser.hpp imageanalyser.cpp
requests.hpp requests.cpp requests.hpp requests.cpp
toaster.hpp toaster.cpp toaster.hpp toaster.cpp
qalculator.hpp qalculator.cpp qalculator.hpp qalculator.cpp
zutils.hpp zutils.cpp zutils.hpp zutils.cpp
LIBRARIES LIBRARIES
Qt::Gui Qt::Gui
Qt::Quick Qt::Quick
Qt::Concurrent Qt::Concurrent
Qt::Sql Qt::Sql
Qt::DBus Qt::DBus
PkgConfig::Qalculate PkgConfig::Qalculate
) )
target_compile_definitions(ZShell PRIVATE ZSHELL_VERSION="${VERSION}")
add_subdirectory(Models) add_subdirectory(Models)
add_subdirectory(Internal) add_subdirectory(Internal)
add_subdirectory(Services) add_subdirectory(Services)
+14
View File
@@ -3,9 +3,11 @@
#include <QtConcurrent/qtconcurrentrun.h> #include <QtConcurrent/qtconcurrentrun.h>
#include <QtQuick/qquickitemgrabresult.h> #include <QtQuick/qquickitemgrabresult.h>
#include <QtQuick/qquickwindow.h> #include <QtQuick/qquickwindow.h>
#include <qcontainerfwd.h>
#include <qdir.h> #include <qdir.h>
#include <qfileinfo.h> #include <qfileinfo.h>
#include <qfuturewatcher.h> #include <qfuturewatcher.h>
#include <qjsprimitivevalue.h>
#include <qloggingcategory.h> #include <qloggingcategory.h>
#include <qqmlengine.h> #include <qqmlengine.h>
@@ -142,4 +144,16 @@ qreal ZUtils::clamp(qreal value, qreal min, qreal max) {
return qBound(min, value, max); return qBound(min, value, max);
} }
#ifndef ZSHELL_VERSION
#define ZSHELL_VERSION ""
#endif
QString ZUtils::version() const {
return QStringLiteral(ZSHELL_VERSION);
}
QString ZUtils::qtVersion() const {
return QStringLiteral(QT_VERSION_STR);
}
} // namespace ZShell } // namespace ZShell
+4
View File
@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <QtQuick/qquickitem.h> #include <QtQuick/qquickitem.h>
#include <qcontainerfwd.h>
#include <qobject.h> #include <qobject.h>
#include <qqmlintegration.h> #include <qqmlintegration.h>
@@ -26,6 +27,9 @@ Q_INVOKABLE static bool deleteFile(const QUrl& path);
Q_INVOKABLE static QString toLocalFile(const QUrl& url); Q_INVOKABLE static QString toLocalFile(const QUrl& url);
Q_INVOKABLE static qreal clamp(qreal value, qreal min, qreal max); Q_INVOKABLE static qreal clamp(qreal value, qreal min, qreal max);
[[nodiscard]] QString version() const;
[[nodiscard]] QString qtVersion() const;
}; };
} // namespace ZShell } // namespace ZShell
+43
View File
@@ -0,0 +1,43 @@
FROM archlinux:latest
RUN pacman -Syu --noconfirm
# Build toolchain
RUN pacman -S --noconfirm \
base-devel \
cmake \
ninja \
clang \
lld \
nodejs \
git
# Qt6
RUN pacman -S --noconfirm \
qt6-base \
qt6-declarative \
qt6-shadertools \
qt6-5compat \
qt6-canvaspainter
# Project-specific dependencies
RUN pacman -S --noconfirm \
libqalculate \
pipewire \
aubio \
cava \
lm_sensors \
glib2
# AUR: libcava (provides development headers for cava)
RUN pacman -S --needed --noconfirm sudo && \
useradd -m builder && \
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
su builder -c " \
git clone https://aur.archlinux.org/libcava.git /tmp/libcava && \
cd /tmp/libcava && \
makepkg -si --noconfirm \
" && \
rm -rf /tmp/libcava && \
userdel -r builder && \
sed -i '/^builder/d' /etc/sudoers