Add Home and Phone settings
This commit is contained in:
+215
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
state_home="$(mktemp -d /tmp/panama-home-phone-settings-state.XXXXXX)"
|
||||
source_config_path="$repo_dir/config/dot/quickshell"
|
||||
config_path="$state_home/quickshell"
|
||||
test_bin="$state_home/bin"
|
||||
shell_log="$state_home/quickshell.log"
|
||||
flatpak_log="$state_home/flatpak.log"
|
||||
|
||||
cleanup_bootstrap() {
|
||||
rm -rf "$state_home"
|
||||
}
|
||||
trap cleanup_bootstrap EXIT
|
||||
|
||||
mkdir -p "$test_bin"
|
||||
cp -a "$source_config_path" "$config_path"
|
||||
: >"$flatpak_log"
|
||||
|
||||
cat >"$config_path/scripts/panama-home-assistant" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
case "${1:-}" in
|
||||
catalog)
|
||||
printf '%s\n' '{"ok":false,"error":"test-helper"}'
|
||||
;;
|
||||
toggle|brightness)
|
||||
printf '%s\n' '{"ok":true}'
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$config_path/scripts/panama-home-assistant"
|
||||
|
||||
cat >"$test_bin/hyprctl" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${1:-}" == "-j" && "${2:-}" == "monitors" ]]; then
|
||||
printf '%s\n' '[{"focused":true,"name":"TEST-1","description":"Home and Phone contract","width":1920,"height":1080,"refreshRate":60,"scale":1,"currentFormat":"XRGB8888","colorManagementPreset":"srgb","vrr":false}]'
|
||||
exit 0
|
||||
fi
|
||||
if [[ "${1:-}" == "keyword" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
exec /usr/sbin/hyprctl "$@"
|
||||
EOF
|
||||
chmod +x "$test_bin/hyprctl"
|
||||
|
||||
cat >"$test_bin/flatpak" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
printf '%s\n' "$*" >>"$PANAMA_FLATPAK_LOG"
|
||||
if [[ "${1:-}" == "info" && "${2:-}" == "app.bluebubbles.BlueBubbles" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
exit 97
|
||||
EOF
|
||||
chmod +x "$test_bin/flatpak"
|
||||
|
||||
fail() {
|
||||
printf 'home phone settings contract: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
local needle="$1"
|
||||
local file="$2"
|
||||
rg -Fq "$needle" "$file" || fail "$file is missing: $needle"
|
||||
}
|
||||
|
||||
home_page="$repo_dir/config/dot/quickshell/modules/settings/HomePhonePage.qml"
|
||||
favorite_card="$repo_dir/config/dot/quickshell/modules/settings/HomeFavoriteCard.qml"
|
||||
available_row="$repo_dir/config/dot/quickshell/modules/settings/AvailableLightRow.qml"
|
||||
system_settings="$repo_dir/config/dot/quickshell/services/SystemSettings.qml"
|
||||
|
||||
[[ -f "$home_page" ]] || fail 'HomePhonePage.qml is missing'
|
||||
[[ -f "$favorite_card" ]] || fail 'HomeFavoriteCard.qml is missing'
|
||||
[[ -f "$available_row" ]] || fail 'AvailableLightRow.qml is missing'
|
||||
assert_contains 'text: "Home & Phone"' "$home_page"
|
||||
assert_contains 'text: "Choose what appears in Control Center and keep phone continuity close at hand."' "$home_page"
|
||||
assert_contains 'Connected · ' "$home_page"
|
||||
assert_contains 'Last update unavailable · showing saved controls' "$home_page"
|
||||
assert_contains 'Authentication required' "$home_page"
|
||||
assert_contains 'Home Assistant is not configured' "$home_page"
|
||||
assert_contains 'HomePreferences.setAlias' "$home_page"
|
||||
assert_contains 'HomePreferences.move' "$home_page"
|
||||
assert_contains 'HomePreferences.remove' "$home_page"
|
||||
assert_contains 'HomePreferences.add' "$home_page"
|
||||
assert_contains 'HomePreferences.retrySave' "$home_page"
|
||||
assert_contains 'Choose lights below to build your Control Center shelf.' "$home_page"
|
||||
assert_contains 'All discovered lights are already selected' "$home_page"
|
||||
assert_contains 'No lights match that search' "$home_page"
|
||||
assert_contains 'Opens BlueBubbles' "$home_page"
|
||||
[[ "$(rg -Fc 'required property var modelData' "$home_page")" -ge 2 ]] \
|
||||
|| fail 'HomePhonePage.qml does not bind both reusable delegates to modelData'
|
||||
if rg -Fq 'index: model.index' "$home_page"; then
|
||||
fail 'HomePhonePage.qml reads an undefined model.index instead of the delegate index'
|
||||
fi
|
||||
if rg -qi 'token|bearer|api/states' "$home_page"; then
|
||||
fail 'HomePhonePage.qml crosses the credential or REST privacy boundary'
|
||||
fi
|
||||
assert_contains 'signal aliasCommitted(string id, string alias)' "$favorite_card"
|
||||
assert_contains 'signal removeRequested(string id)' "$favorite_card"
|
||||
assert_contains 'signal moveRequested(string id, int targetIndex)' "$favorite_card"
|
||||
assert_contains 'DragHandler {' "$favorite_card"
|
||||
assert_contains 'onEditingFinished:' "$favorite_card"
|
||||
assert_contains 'text: "Control Center"' "$favorite_card"
|
||||
assert_contains 'activeFocusOnTab: true' "$favorite_card"
|
||||
assert_contains 'signal addRequested(string id)' "$available_row"
|
||||
assert_contains 'activeFocusOnTab: true' "$available_row"
|
||||
assert_contains 'readonly property bool bluebubblesAvailable: root.bluebubblesDetected' "$system_settings"
|
||||
assert_contains 'command: ["flatpak", "info", "app.bluebubbles.BlueBubbles"]' "$system_settings"
|
||||
assert_contains '"bluebubbles": ["flatpak", "run", "app.bluebubbles.BlueBubbles"]' "$system_settings"
|
||||
|
||||
qs_for_test() {
|
||||
PATH="$test_bin:$PATH" QS_CONFIG_PATH="$config_path" XDG_STATE_HOME="$state_home" \
|
||||
PANAMA_FLATPAK_LOG="$flatpak_log" qs -p "$config_path" "$@"
|
||||
}
|
||||
|
||||
stop_test_shell() {
|
||||
qs_for_test kill >/dev/null 2>&1 || true
|
||||
for _ in $(seq 1 80); do
|
||||
if ! qs_for_test list 2>/dev/null | rg '^Instance ' >/dev/null \
|
||||
&& ! qs_for_test ipc show >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
qs_for_test ipc call settings close >/dev/null 2>&1 || true
|
||||
if stop_test_shell; then
|
||||
rm -rf "$state_home"
|
||||
else
|
||||
printf 'home phone settings contract: branch shell did not stop; retained %s\n' \
|
||||
"$state_home" >&2
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
start_test_shell() {
|
||||
stop_test_shell || fail 'pre-existing branch shell did not stop cleanly'
|
||||
for _attempt in 1 2; do
|
||||
qs_for_test --daemonize >"$shell_log" 2>&1
|
||||
for _ in $(seq 1 80); do
|
||||
if qs_for_test ipc show 2>/dev/null | rg '^target settings-system$' >/dev/null; then
|
||||
return
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
stop_test_shell || fail 'failed branch-shell attempt did not stop cleanly'
|
||||
done
|
||||
sed -n '1,240p' "$shell_log" >&2
|
||||
fail 'isolated branch shell did not start'
|
||||
}
|
||||
|
||||
start_test_shell
|
||||
qs_for_test ipc call home-assistant fixture ready >/dev/null
|
||||
qs_for_test ipc call settings page home-phone >/dev/null
|
||||
|
||||
status='{}'
|
||||
for _ in $(seq 1 40); do
|
||||
status="$(qs_for_test ipc call settings status | jq -c .)"
|
||||
if jq -e '.page == "home-phone" and .discoveredCount == 7 and .selectedCount == 7' \
|
||||
<<<"$status" >/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
jq -e '.open == true and .page == "home-phone" and .discoveredCount == 7 and .selectedCount == 7' \
|
||||
<<<"$status" >/dev/null || fail "Home & Phone diagnostics are incomplete: $status"
|
||||
|
||||
system_status="$(qs_for_test ipc call settings-system status | jq -c .)"
|
||||
jq -e '.bluebubblesAvailable == true' <<<"$system_status" >/dev/null \
|
||||
|| fail "BlueBubbles availability was not exposed: $system_status"
|
||||
|
||||
shell_pid="$(qs_for_test list | awk '/Process ID:/ { print $3; exit }')"
|
||||
[[ "$shell_pid" =~ ^[0-9]+$ ]] || fail 'could not identify the branch shell process'
|
||||
for _ in $(seq 1 40); do
|
||||
if /usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \
|
||||
'[.[] | select(.pid == $pid and .title == "Panama Settings" and .floating == false)] | length == 1' >/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
/usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \
|
||||
'[.[] | select(.pid == $pid and .title == "Panama Settings" and .floating == false)] | length == 1' >/dev/null \
|
||||
|| fail 'the branch shell did not own exactly one tiled Panama Settings client'
|
||||
|
||||
if [[ -n "${PANAMA_TEST_SCREENSHOT_PATH:-}" ]]; then
|
||||
geometry="$(/usr/sbin/hyprctl -j clients | jq -r --argjson pid "$shell_pid" \
|
||||
'.[] | select(.pid == $pid and .title == "Panama Settings") | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')"
|
||||
[[ -n "$geometry" ]] || fail 'could not resolve the Settings client geometry'
|
||||
grim -g "$geometry" "$PANAMA_TEST_SCREENSHOT_PATH"
|
||||
fi
|
||||
|
||||
rg -Fxq 'info app.bluebubbles.BlueBubbles' "$flatpak_log" \
|
||||
|| fail 'the fixed BlueBubbles availability probe did not run'
|
||||
if rg -q '^run ' "$flatpak_log"; then
|
||||
fail 'the contract started BlueBubbles'
|
||||
fi
|
||||
if find "$state_home" -name panama-home.json -print -quit | rg -q .; then
|
||||
fail 'the read-only fixture route wrote Home preferences'
|
||||
fi
|
||||
|
||||
trap - EXIT
|
||||
cleanup
|
||||
[[ ! -e "$state_home" ]] || fail 'temporary Home & Phone state was not removed after shell exit'
|
||||
printf 'home phone settings contract: PASS\n'
|
||||
@@ -2,34 +2,135 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
state_home="$(mktemp -d /tmp/panama-settings-pages-state.XXXXXX)"
|
||||
source_config_path="$repo_dir/config/dot/quickshell"
|
||||
config_path="$state_home/quickshell"
|
||||
test_bin="$state_home/bin"
|
||||
shell_log="$state_home/quickshell.log"
|
||||
|
||||
cleanup_bootstrap() {
|
||||
rm -rf "$state_home"
|
||||
}
|
||||
trap cleanup_bootstrap EXIT
|
||||
|
||||
mkdir -p "$test_bin"
|
||||
cp -a "$source_config_path" "$config_path"
|
||||
|
||||
cat >"$config_path/scripts/panama-home-assistant" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
case "${1:-}" in
|
||||
catalog)
|
||||
printf '%s\n' '{"ok":false,"error":"test-helper"}'
|
||||
;;
|
||||
toggle|brightness)
|
||||
printf '%s\n' '{"ok":true}'
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$config_path/scripts/panama-home-assistant"
|
||||
|
||||
cat >"$test_bin/hyprctl" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${1:-}" == "-j" && "${2:-}" == "monitors" ]]; then
|
||||
printf '%s\n' '[{"focused":true,"name":"TEST-1","description":"Settings contract","width":1920,"height":1080,"refreshRate":60,"scale":1,"currentFormat":"XRGB8888","colorManagementPreset":"srgb","vrr":false}]'
|
||||
exit 0
|
||||
fi
|
||||
if [[ "${1:-}" == "keyword" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
exec /usr/sbin/hyprctl "$@"
|
||||
EOF
|
||||
chmod +x "$test_bin/hyprctl"
|
||||
|
||||
cat >"$test_bin/flatpak" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${1:-}" == "info" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 97
|
||||
EOF
|
||||
chmod +x "$test_bin/flatpak"
|
||||
|
||||
fail() {
|
||||
printf 'settings pages contract: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
qs_for_test() {
|
||||
PATH="$test_bin:$PATH" QS_CONFIG_PATH="$config_path" XDG_STATE_HOME="$state_home" \
|
||||
qs -p "$config_path" "$@"
|
||||
}
|
||||
|
||||
stop_test_shell() {
|
||||
qs_for_test kill >/dev/null 2>&1 || true
|
||||
for _ in $(seq 1 80); do
|
||||
if ! qs_for_test list 2>/dev/null | rg '^Instance ' >/dev/null \
|
||||
&& ! qs_for_test ipc show >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
qs ipc call settings close >/dev/null 2>&1 || true
|
||||
qs_for_test ipc call settings close >/dev/null 2>&1 || true
|
||||
if stop_test_shell; then
|
||||
rm -rf "$state_home"
|
||||
else
|
||||
printf 'settings pages contract: branch shell did not stop; retained %s\n' \
|
||||
"$state_home" >&2
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
pages=(home appearance displays connectivity desktop sound notifications screen-intelligence shortcuts services about)
|
||||
start_test_shell() {
|
||||
stop_test_shell || fail 'pre-existing branch shell did not stop cleanly'
|
||||
for _attempt in 1 2; do
|
||||
qs_for_test --daemonize >"$shell_log" 2>&1
|
||||
for _ in $(seq 1 80); do
|
||||
if qs_for_test ipc show 2>/dev/null | rg '^target settings$' >/dev/null; then
|
||||
return
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
stop_test_shell || fail 'failed branch-shell attempt did not stop cleanly'
|
||||
done
|
||||
sed -n '1,200p' "$shell_log" >&2
|
||||
fail 'isolated branch shell did not start'
|
||||
}
|
||||
|
||||
start_test_shell
|
||||
qs_for_test ipc call home-assistant fixture ready >/dev/null
|
||||
shell_pid="$(qs_for_test list | awk '/Process ID:/ { print $3; exit }')"
|
||||
[[ "$shell_pid" =~ ^[0-9]+$ ]] || fail 'could not identify the branch shell process'
|
||||
|
||||
pages=(home appearance displays connectivity home-phone desktop sound notifications screen-intelligence shortcuts services about)
|
||||
for page in "${pages[@]}"; do
|
||||
qs ipc call settings page "$page" >/dev/null
|
||||
qs_for_test ipc call settings page "$page" >/dev/null
|
||||
for _ in $(seq 1 20); do
|
||||
[[ "$(qs ipc call settings status | jq -r .page)" == "$page" ]] && break
|
||||
[[ "$(qs_for_test ipc call settings status | jq -r .page)" == "$page" ]] && break
|
||||
sleep 0.1
|
||||
done
|
||||
[[ "$(qs ipc call settings status | jq -r .page)" == "$page" ]] || fail "$page did not route"
|
||||
hyprctl -j clients | jq -e '[.[] | select(.title == "Panama Settings")] | length == 1' >/dev/null \
|
||||
|| fail "$page created a missing or duplicate Settings window"
|
||||
[[ "$(qs_for_test ipc call settings status | jq -r .page)" == "$page" ]] || fail "$page did not route"
|
||||
/usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \
|
||||
'[.[] | select(.pid == $pid and .title == "Panama Settings" and .floating == false)] | length == 1' >/dev/null \
|
||||
|| fail "$page created a missing, floating, or duplicate Settings window"
|
||||
done
|
||||
|
||||
qs ipc call settings page '__unsupported__' >/dev/null
|
||||
[[ "$(qs ipc call settings status | jq -r .page)" == "home" ]] || fail 'unsupported page did not fall back to Home'
|
||||
qs_for_test ipc call settings page '__unsupported__' >/dev/null
|
||||
[[ "$(qs_for_test ipc call settings status | jq -r .page)" == "home" ]] || fail 'unsupported page did not fall back to Home'
|
||||
|
||||
hyprctl -j binds | jq -e '.[] | select(.description == "Panama Settings" and .key == "I" and .modmask == 64)' >/dev/null \
|
||||
/usr/sbin/hyprctl -j binds | jq -e '.[] | select(.description == "Panama Settings" and .key == "I" and .modmask == 64)' >/dev/null \
|
||||
|| fail 'Super+I is not registered as Panama Settings'
|
||||
hyprctl -j binds | jq -e '.[] | select(.description == "Screen Intelligence" and .key == "S" and .modmask == 65)' >/dev/null \
|
||||
/usr/sbin/hyprctl -j binds | jq -e '.[] | select(.description == "Screen Intelligence" and .key == "S" and .modmask == 65)' >/dev/null \
|
||||
|| fail 'Super+Shift+S is not registered as Screen Intelligence'
|
||||
|
||||
desktop_file="$HOME/.local/share/applications/panama-settings.desktop"
|
||||
@@ -44,4 +145,5 @@ desktop-file-validate "$intelligence_desktop_file" >/dev/null || fail 'Screen In
|
||||
|
||||
trap - EXIT
|
||||
cleanup
|
||||
[[ ! -e "$state_home" ]] || fail 'temporary Settings state was not removed after shell exit'
|
||||
printf 'settings pages contract: PASS\n'
|
||||
|
||||
Reference in New Issue
Block a user