Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
push:
pull_request:

jobs:
lint-qml:
name: QML lint & type check
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install Qt 6 and xvfb
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
qt6-declarative-dev-tools \
qml-qt6 \
qml6-module-qtquick \
qml6-module-qtquick-controls \
qml6-module-qtquick-layouts \
qml6-module-qtquick-window \
qml6-module-qtquick-templates \
xvfb

- name: Run QML checks
run: ./scripts/lint-qml.sh
Binary file added assets/background.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions components/LoginForm.qml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Item {
color: root.textColor
font.pointSize: root.fontSize + 8
font.weight: Font.Light
font.family: root.fontFamily || undefined
font.family: root.fontFamily
renderType: Text.NativeRendering
}

Expand All @@ -59,7 +59,7 @@ Item {
placeholderText: "Username"
text: root.defaultUsername
font.pointSize: root.fontSize
font.family: root.fontFamily || undefined
font.family: root.fontFamily

color: root.textColor
placeholderTextColor: Qt.rgba(1, 1, 1, 0.5)
Expand All @@ -86,7 +86,7 @@ Item {
placeholderText: "Password"
echoMode: TextInput.Password
font.pointSize: root.fontSize
font.family: root.fontFamily || undefined
font.family: root.fontFamily

color: root.textColor
placeholderTextColor: Qt.rgba(1, 1, 1, 0.5)
Expand Down Expand Up @@ -122,7 +122,7 @@ Item {
height: 44
text: "Log In"
font.pointSize: root.fontSize
font.family: root.fontFamily || undefined
font.family: root.fontFamily

contentItem: Text {
text: loginButton.text
Expand Down
2 changes: 1 addition & 1 deletion components/SessionSelector.qml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Item {
textRole: "name"

font.pointSize: root.fontSize
font.family: root.fontFamily || undefined
font.family: root.fontFamily

contentItem: Text {
leftPadding: 10
Expand Down
9 changes: 8 additions & 1 deletion preview/Preview.qml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Window {

QtObject {
id: mockConfig
// Set to "" to use the solid fallback color, or provide a path
// to an image (e.g. drop your own into assets/background.jpg).
property string background: Qt.resolvedUrl("../assets/background.jpg")
property string type: "image"
property string color: "#1a1a2e"
Expand Down Expand Up @@ -121,9 +123,14 @@ Window {
Image {
id: backgroundImage
anchors.fill: parent
source: mockConfig.background
source: mockConfig.background || ""
fillMode: Image.PreserveAspectCrop
asynchronous: true
onStatusChanged: {
if (status === Image.Error && source != "")
console.log("Background image not found — using fallback color. " +
"Drop an image into assets/background.jpg or update theme.conf.")
}
}

Rectangle {
Expand Down
110 changes: 110 additions & 0 deletions scripts/lint-qml.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash
#
# lint-qml.sh - Static analysis and runtime type-error check for QML files.
#
# Runs qmllint (static) on all QML source files, then launches the preview
# under xvfb for a few seconds to catch runtime type-assignment warnings.
#
# Usage: ./scripts/lint-qml.sh
#
# Exit codes:
# 0 All checks passed
# 1 qmllint found issues or runtime errors detected

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

cd "$PROJECT_DIR"

# ── Locate Qt 6 tools ────────────────────────────────────────────
# Binary names and paths vary across distros:
# Arch: qmllint, qml6 (on PATH)
# Ubuntu: qmllint, qml (in /usr/lib/qt6/bin)
for candidate in /usr/lib/qt6/bin /usr/lib64/qt6/bin; do
[[ -d "$candidate" ]] && export PATH="$candidate:$PATH"
done

find_tool() {
for name in "$@"; do
if command -v "$name" &>/dev/null; then
echo "$name"
return
fi
done
echo ""
}

QMLLINT=$(find_tool qmllint qmllint6)
QML_RUNTIME=$(find_tool qml6 qml)

FAILED=0

# ── Static analysis with qmllint ──────────────────────────────────
echo "=== qmllint: static analysis ==="

if [[ -z "$QMLLINT" ]]; then
echo "SKIP: qmllint not found."
else
QML_FILES=$(find . -name '*.qml' -not -path './.git/*')
echo "Checking: $QML_FILES"
echo ""

# qmllint emits warnings for SDDM context properties (sddm, config,
# userModel, etc.) that only exist at runtime. These are expected and
# unavoidable. We capture the output and only fail on actual errors
# (syntax errors, unknown components from our own code), not warnings
# about unqualified/unresolved access to SDDM injected globals.
LINT_OUTPUT=$($QMLLINT $QML_FILES 2>&1) || true
if echo "$LINT_OUTPUT" | grep -qiE '^Error:'; then
echo "$LINT_OUTPUT"
echo "FAIL: qmllint found errors."
FAILED=1
else
echo "PASS: qmllint clean (warnings only)."
fi
fi
echo ""

# ── Runtime type-error check ──────────────────────────────────────
echo "=== Runtime: checking for type errors ==="

if [[ -z "$QML_RUNTIME" ]]; then
echo "SKIP: qml runtime not found (tried qml6, qml)."
echo ""
exit $FAILED
fi

# Use the Basic style to avoid Breeze/Plasma-specific errors that only
# occur outside a full Plasma session (e.g. T.Overlay in ComboBox).
export QT_QUICK_CONTROLS_STYLE=Basic

STDERR_LOG=$(mktemp)
trap 'rm -f "$STDERR_LOG"' EXIT

# Run preview for 3 seconds under a virtual framebuffer, capture stderr.
if command -v xvfb-run &>/dev/null; then
timeout 3 xvfb-run -a "$QML_RUNTIME" preview/Preview.qml 2>"$STDERR_LOG" || true
elif [ -n "${DISPLAY:-}" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then
timeout 3 "$QML_RUNTIME" preview/Preview.qml 2>"$STDERR_LOG" || true
else
echo "SKIP: no display and xvfb-run not available."
echo ""
exit $FAILED
fi

# Filter for errors we care about (type assignment, ReferenceError, TypeError).
if grep -E 'Unable to assign|ReferenceError|TypeError' "$STDERR_LOG" \
| grep -v 'Cannot open:' \
| grep -q .; then
echo "FAIL: runtime type errors detected:"
grep -E 'Unable to assign|ReferenceError|TypeError' "$STDERR_LOG" \
| grep -v 'Cannot open:'
FAILED=1
else
echo "PASS: no runtime type errors."
fi
echo ""

exit $FAILED
21 changes: 20 additions & 1 deletion scripts/preview.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

ENTR_PID=""

cleanup() {
trap - SIGINT SIGTERM # prevent re-entry
[[ -n "$ENTR_PID" ]] && kill "$ENTR_PID" 2>/dev/null && wait "$ENTR_PID" 2>/dev/null
echo ""
echo "Preview stopped."
exit 0
}
trap cleanup SIGINT SIGTERM

# Force the Basic Qt Quick Controls style so the standalone preview doesn't
# load Breeze, which depends on Plasma-specific overlay types that are
# unavailable outside a full Plasma session.
export QT_QUICK_CONTROLS_STYLE=Basic

echo "=== KDE Lockscreen Builder — Live Preview ==="
echo "Project: $PROJECT_DIR"
echo "Press Ctrl+C to stop"
Expand All @@ -22,5 +38,8 @@ cd "$PROJECT_DIR"

while true; do
find . \( -name '*.qml' -o -name '*.conf' -o -name '*.jpg' -o -name '*.png' -o -name '*.svg' \) \
| entr -d -r qml6 preview/Preview.qml
| entr -d -r qml6 preview/Preview.qml &
ENTR_PID=$!
wait "$ENTR_PID" || true
ENTR_PID=""
done