Files
Panama/config/dot/quickshell/modules/settings/SettingsCard.qml
T
Gabriel Brown 495fb9b41b Give each online account its provider's icon
Four accounts distinguished only by a line of small grey text are four rows that
have to be read rather than recognised. GOA already knows what each one is.

It hands back a serialised GThemedIcon -- ". GThemedIcon goa-account-google
goa-account goa …" -- a preference-ordered fallback chain. The helper passes the
whole chain on rather than resolving it, because which of those names exists is
a property of the icon theme in use and not something a python script talking to
D-Bus should be deciding.

The page walks the chain and takes the first name the active theme actually has.
Both simpler readings were wrong and looked right: taking the first name blindly
assumes it resolves, and taking the last as a fallback assumes the most generic
name is the most likely to exist. On Adwaita the tails of these very chains --
"mail", "goa-symbolic" -- do not exist at all, so a miss would have drawn
nothing. Checked by asking Quickshell.iconPath directly, which returns empty for
a name the theme lacks; the fallback is avatar-default-symbolic, which is
present.

SettingsCard grew an optional icon for this. It is empty by default and the
header lays out exactly as before when unset, so no other card moves.

Last-sync is not here because there is nothing to show: GOA exposes no
sync-related property at all, on any of these accounts. Better to say so than to
invent a timestamp from when the page last refreshed.

Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
2026-08-20 13:28:05 -04:00

88 lines
2.6 KiB
QML

import QtQuick
import qs.config
import qs.widgets
Rectangle {
id: root
default property alias contentData: body.data
property string title: ""
property string subtitle: ""
// An optional themed icon beside the title, for cards that represent a
// specific thing rather than a topic -- an online account is one of four
// that otherwise differ only by a line of small grey text. Empty by
// default, and when empty the header lays out exactly as it did before.
property string icon: ""
property string iconFallback: "dialog-information-symbolic"
width: parent ? parent.width : 680
implicitHeight: body.implicitHeight + 30
radius: Theme.cardRadius + 2
color: Theme.alpha(Theme.bgPanel, 0.72)
border.width: 1
border.color: Theme.alpha(Theme.fg, 0.07)
PrismEdge {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
inset: root.radius
opacity: 0.36
}
Column {
id: body
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 15
spacing: 0
Row {
width: parent.width
visible: root.title !== ""
spacing: root.icon === "" ? 0 : 10
ThemedIcon {
anchors.verticalCenter: parent.verticalCenter
visible: root.icon !== ""
width: root.icon === "" ? 0 : 22
icon: root.icon
iconFallback: root.iconFallback
size: 22
}
Text {
anchors.verticalCenter: parent.verticalCenter
width: parent.width - (root.icon === "" ? 0 : 32)
text: root.title
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
elide: Text.ElideRight
}
}
// The title's bottom padding lived on the title Text; it moves here so
// the Row above can centre an icon against it without the padding
// pushing the icon off-centre.
Item {
width: 1
height: root.title === "" ? 0 : (root.subtitle === "" ? 10 : 3)
}
Text {
width: parent.width
visible: root.subtitle !== ""
text: root.subtitle
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
wrapMode: Text.WordWrap
bottomPadding: 12
}
}
}