Files
Panama/config/dot/quickshell/modules/settings/HomePhonePage.qml
T

289 lines
10 KiB
QML

import QtQuick
import qs.config
import qs.services
SettingsPage {
id: root
objectName: "home-phone-page"
title: "Home & Phone"
lede: "Choose what appears in Control Center and keep phone continuity close at hand."
property string lightQuery: searchInput.text.trim().toLowerCase()
readonly property var availableLights: HomeAssistant.catalog.filter(entity => {
if (HomeAssistant.selectedEntities.some(selected => selected.id === entity.id))
return false;
const haystack = (entity.sourceName + " " + entity.id).toLowerCase();
return root.lightQuery === "" || haystack.includes(root.lightQuery);
})
readonly property string availableEmptyText: root.availableLights.length > 0
? ""
: (root.lightQuery !== ""
? "No lights match that search"
: (HomeAssistant.catalog.length === 0
? "No lights discovered"
: "All discovered lights are already selected"))
readonly property var pageDiagnostics: ({
availableLightIds: root.availableLights.map(entity => entity.id),
availableEmptyText: root.availableEmptyText,
homeStatus: root.homeStatus()
})
function homeStatus(): string {
if (HomeAssistant.lastError === "authentication-required")
return "Authentication required";
if (HomeAssistant.lastError === "not-configured")
return "Home Assistant is not configured";
if (HomeAssistant.phase === "ready")
return `Connected · ${HomeAssistant.discoveredCount} lights discovered`;
if (HomeAssistant.phase === "degraded")
return "Last update unavailable · showing saved controls";
if (HomeAssistant.phase === "loading")
return "Connecting to Home Assistant";
return "Home Assistant is unavailable";
}
SettingsCard {
title: "Home Assistant"
subtitle: root.homeStatus()
SettingRow {
label: "Light catalog"
detail: "Panama reads light state through the Home Assistant helper."
divider: false
controlWidth: 176
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 8
SettingsButton {
id: refreshButton
text: "Refresh"
activeFocusOnTab: true
border.width: activeFocus ? 2 : 1
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08)
onClicked: HomeAssistant.refresh()
Keys.onReturnPressed: HomeAssistant.refresh()
Keys.onSpacePressed: HomeAssistant.refresh()
}
SettingsButton {
id: openHomeButton
text: "Open"
activeFocusOnTab: true
border.width: activeFocus ? 2 : 1
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08)
onClicked: HomeAssistant.open()
Keys.onReturnPressed: HomeAssistant.open()
Keys.onSpacePressed: HomeAssistant.open()
}
}
}
}
SettingsCard {
title: "Control Center lights"
subtitle: HomeAssistant.selectedEntities.length === 0
? "Select the lights that belong on your shelf."
: `${Math.min(4, HomeAssistant.selectedEntities.length)} in Control Center · ${HomeAssistant.selectedEntities.length} selected`
Text {
width: parent.width
visible: HomeAssistant.selectedEntities.length === 0
text: "Choose lights below to build your Control Center shelf."
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
wrapMode: Text.WordWrap
topPadding: 3
bottomPadding: 13
}
GridView {
id: favoritesGrid
width: parent.width
height: Math.ceil(count / 2) * cellHeight
visible: count > 0
interactive: false
clip: false
cellWidth: width / 2
cellHeight: 116
model: HomeAssistant.selectedEntities
delegate: HomeFavoriteCard {
required property var modelData
width: GridView.view.cellWidth - 6
height: 108
favorite: ({
id: modelData.id,
alias: modelData.name === modelData.sourceName ? "" : modelData.name
})
sourceName: modelData.sourceName
featured: index < 4
canMoveEarlier: index > 0
canMoveLater: index < favoritesGrid.count - 1
onAliasCommitted: (id, alias) => HomePreferences.setAlias(id, alias)
onMoveRequested: (id, targetIndex) => HomePreferences.move(id, targetIndex)
onRemoveRequested: id => HomePreferences.remove(id)
}
}
Rectangle {
width: parent.width
height: 46
visible: HomePreferences.saveError !== ""
radius: 9
color: Theme.alpha(Theme.warn, 0.09)
border.width: 1
border.color: Theme.alpha(Theme.warn, 0.24)
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.right: retryButton.left
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: HomePreferences.saveError
color: Theme.warn
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
elide: Text.ElideRight
}
SettingsButton {
id: retryButton
anchors.right: parent.right
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
text: "Retry"
activeFocusOnTab: true
border.width: activeFocus ? 2 : 1
border.color: activeFocus ? Theme.warn : Theme.alpha(Theme.fg, 0.08)
onClicked: HomePreferences.retrySave()
Keys.onReturnPressed: HomePreferences.retrySave()
Keys.onSpacePressed: HomePreferences.retrySave()
}
}
}
SettingsCard {
title: "Available lights"
subtitle: "Search the Home Assistant catalog by source name or entity ID."
Rectangle {
width: parent.width
height: 38
radius: 10
color: Theme.alpha(Theme.fg, searchInput.activeFocus ? 0.08 : 0.05)
border.width: searchInput.activeFocus ? 2 : 1
border.color: searchInput.activeFocus
? Theme.alpha(Theme.accent, 0.72)
: Theme.alpha(Theme.fg, 0.065)
Text {
anchors.left: parent.left
anchors.leftMargin: 11
anchors.verticalCenter: parent.verticalCenter
text: "\u{F0349}"
color: Theme.fgDim
font.family: Theme.fontMono
font.pixelSize: 14
}
TextInput {
id: searchInput
anchors.left: parent.left
anchors.leftMargin: 36
anchors.right: parent.right
anchors.rightMargin: 11
anchors.verticalCenter: parent.verticalCenter
activeFocusOnTab: true
color: Theme.fg
selectionColor: Theme.accent
selectedTextColor: Theme.bgDark
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
clip: true
Text {
anchors.fill: parent
visible: searchInput.text === "" && !searchInput.activeFocus
text: "Search available lights"
color: Theme.fgMuted
font: searchInput.font
verticalAlignment: Text.AlignVCenter
}
}
}
Column {
width: parent.width
visible: root.availableLights.length > 0
Repeater {
model: root.availableLights
AvailableLightRow {
required property var modelData
width: parent.width
entity: modelData
onAddRequested: id => HomePreferences.add(id)
}
}
}
Text {
width: parent.width
visible: root.availableLights.length === 0
text: root.availableEmptyText
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
topPadding: 18
bottomPadding: 10
}
}
SettingsCard {
title: "Phone continuity"
subtitle: "Keep the Messages handoff independent from phone connectivity."
SettingRow {
label: "Messages"
detail: "Opens BlueBubbles"
divider: false
controlWidth: 204
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 12
Text {
anchors.verticalCenter: parent.verticalCenter
text: SystemSettings.bluebubblesAvailable ? "Installed" : "Unavailable"
color: SystemSettings.bluebubblesAvailable ? Theme.ok : Theme.fgMuted
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
}
SettingsButton {
id: openBlueBubblesButton
text: "Open"
enabled: SystemSettings.bluebubblesAvailable
activeFocusOnTab: enabled
border.width: activeFocus ? 2 : 1
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08)
onClicked: SystemSettings.openApplication("bluebubbles")
Keys.onReturnPressed: if (enabled) SystemSettings.openApplication("bluebubbles")
Keys.onSpacePressed: if (enabled) SystemSettings.openApplication("bluebubbles")
}
}
}
}
}