Fold thirty-one settings pages into fifteen categories with tabs
The sidebar was a flat scan of thirty-one rows; now it reads like a settings app. Multi-subject categories (Input, Network & Sharing, Applications, Users & Accounts, Privacy & Security, System) carry an Appearance-style tab strip above the page, drawn by the shell so the leaf pages themselves are untouched. The taxonomy lives in one new file, services/SettingsRoutes.qml; the sidebar, the strip, route validation, search breadcrumbs, and both generators derive from it. ShellState.settingsPage still holds leaf ids, so every deep link, IPC call, and search result keeps working — and now lands on the exact tab. Dictation moves out of Sound onto its own page under Input, with a handoff back to Sound for the microphone. The strip scrolls when System's nine tabs outgrow a tiled window. All 161 contracts pass. Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -3,11 +3,19 @@
|
||||
# The Sound page is a first-class PipeWire control surface, not a launcher for
|
||||
# another settings app. This contract keeps the real device plumbing shared
|
||||
# with Quick Settings and verifies the controls that must remain available.
|
||||
#
|
||||
# It also owns the line between Sound and Dictation. Dictation used to be a
|
||||
# card on this page, because it listens through the input device chosen here.
|
||||
# It is an input method, so it now sits under Input with the keyboard -- and
|
||||
# the thing that made the old arrangement legible, that the microphone and the
|
||||
# dictation setup were visibly the same subject, has to survive the move as an
|
||||
# explicit handoff rather than as a second device picker.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
sound_page="$repo_dir/config/dot/quickshell/modules/settings/SoundPage.qml"
|
||||
dictation_page="$repo_dir/config/dot/quickshell/modules/settings/DictationPage.qml"
|
||||
device_list="$repo_dir/config/dot/quickshell/modules/settings/SoundDeviceList.qml"
|
||||
device_row="$repo_dir/config/dot/quickshell/modules/settings/SoundDeviceRow.qml"
|
||||
application_mixer="$repo_dir/config/dot/quickshell/modules/settings/ApplicationMixer.qml"
|
||||
@@ -36,7 +44,7 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
for file in "$sound_page" "$device_list" "$device_row" "$application_mixer" "$application_row" "$balance" "$audio_devices" "$sound_feedback" "$quick_devices"; do
|
||||
for file in "$sound_page" "$dictation_page" "$device_list" "$device_row" "$application_mixer" "$application_row" "$balance" "$audio_devices" "$sound_feedback" "$quick_devices"; do
|
||||
[[ -f "$file" ]] || fail "missing ${file#"$repo_dir/"}"
|
||||
done
|
||||
|
||||
@@ -71,6 +79,35 @@ rg -Fq 'SoundFeedback.setEventSounds(checked)' "$sound_page" || fail 'event soun
|
||||
rg -Fq 'SoundFeedback.setInputFeedback(checked)' "$sound_page" || fail 'input feedback sounds are not controllable'
|
||||
rg -Fq 'org.gnome.desktop.sound' "$sound_feedback" || fail 'sound feedback does not use the desktop sound schema'
|
||||
|
||||
# ── Dictation lives on its own page under Input ──────────────────────────────
|
||||
# One page owns the dictation controls. Two would mean two setup buttons
|
||||
# driving the same one-time install, and whichever one someone found second
|
||||
# would report state it did not cause.
|
||||
! rg -Fq 'Dictation.' "$sound_page" \
|
||||
|| fail 'the Sound page reads Dictation state again -- dictation belongs to DictationPage, and two pages showing the same setup is how one of them goes stale'
|
||||
rg -Fq 'label: "Set up dictation"' "$dictation_page" \
|
||||
|| fail 'DictationPage has no setup action, so the one-time install cannot be started from Settings'
|
||||
rg -Fq 'onTriggered: Dictation.setup()' "$dictation_page" \
|
||||
|| fail 'the dictation setup action does not call the helper that installs both the speech server and the model'
|
||||
rg -Fq 'label: "Speech server"' "$dictation_page" \
|
||||
|| fail 'DictationPage does not report whether the speech server is installed'
|
||||
rg -Fq 'label: "Speech model"' "$dictation_page" \
|
||||
|| fail 'DictationPage does not report whether the speech model is installed'
|
||||
rg -Fq 'Dictation.typingAvailable' "$dictation_page" \
|
||||
|| fail 'DictationPage does not say when wtype is missing, so dictated text would silently go to the clipboard'
|
||||
rg -Fq 'Dictation.lastError' "$dictation_page" \
|
||||
|| fail 'DictationPage never surfaces a setup failure'
|
||||
|
||||
# The microphone is chosen on the Sound page, and dictation listens through it.
|
||||
# Saying so, with a way to get there, is what replaces the two cards having sat
|
||||
# side by side.
|
||||
rg -Fq 'title: "Microphone"' "$dictation_page" \
|
||||
|| fail 'DictationPage does not name the input device it listens through'
|
||||
rg -Fq 'ShellState.openSettings("sound")' "$dictation_page" \
|
||||
|| fail 'DictationPage does not hand off to Sound, so the device it listens through is unreachable from it'
|
||||
! rg -Fq 'SoundDeviceList {' "$dictation_page" \
|
||||
|| fail 'DictationPage grew its own device picker -- there is one input device, and two places to change it disagree'
|
||||
|
||||
# Native bindings are the supported path. Shelling out would race the service
|
||||
# that owns these same objects and regress Quick Settings coherence.
|
||||
if rg -q '\b(Process|pactl|wpctl)\b' "$audio_devices" "$device_list" "$device_row" "$balance"; then
|
||||
|
||||
Reference in New Issue
Block a user