Require textFormat declaration for all Text elements.
This commit is contained in:
@@ -138,6 +138,7 @@ BorderSurface {
|
|||||||
radius: 0
|
radius: 0
|
||||||
}
|
}
|
||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.tooltipText
|
text: root.tooltipText
|
||||||
color: root.tooltipForeground
|
color: root.tooltipForeground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -158,6 +159,7 @@ BorderSurface {
|
|||||||
spacing: Style.spacing.controlGap
|
spacing: Style.spacing.controlGap
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.iconText !== ""
|
visible: root.iconText !== ""
|
||||||
text: root.iconText
|
text: root.iconText
|
||||||
color: root.selected ? root._selectedColor : root.foreground
|
color: root.selected ? root._selectedColor : root.foreground
|
||||||
@@ -177,6 +179,7 @@ BorderSurface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.text !== ""
|
visible: root.text !== ""
|
||||||
text: root.text
|
text: root.text
|
||||||
color: root.selected ? root._selectedColor : root.foreground
|
color: root.selected ? root._selectedColor : root.foreground
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: messageText
|
id: messageText
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
@@ -105,6 +106,7 @@ Item {
|
|||||||
radius: 0
|
radius: 0
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: modelData
|
text: modelData
|
||||||
color: destructive ? (selected ? Color.urgent : root.foreground) : (selected ? root.selectedText : root.foreground)
|
color: destructive ? (selected ? Color.urgent : root.foreground) : (selected ? root.selectedText : root.foreground)
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ Item {
|
|||||||
spacing: Style.spacing.labelGap
|
spacing: Style.spacing.labelGap
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.showLabel && root.label !== ""
|
visible: root.showLabel && root.label !== ""
|
||||||
text: root.label
|
text: root.label
|
||||||
color: Qt.darker(root.foreground, 1.4)
|
color: Qt.darker(root.foreground, 1.4)
|
||||||
@@ -110,6 +111,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: chevron.left
|
anchors.right: chevron.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -214,6 +216,7 @@ Item {
|
|||||||
: "transparent"
|
: "transparent"
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ Item {
|
|||||||
spacing: Style.spacing.labelGap
|
spacing: Style.spacing.labelGap
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.showLabel && root.label !== ""
|
visible: root.showLabel && root.label !== ""
|
||||||
text: root.label
|
text: root.label
|
||||||
color: Qt.darker(root.foreground, 1.4)
|
color: Qt.darker(root.foreground, 1.4)
|
||||||
@@ -298,6 +299,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: chevron.left
|
anchors.right: chevron.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -451,6 +453,7 @@ Item {
|
|||||||
: Border.controlSpec("normal", root.foreground, root.accent)
|
: Border.controlSpec("normal", root.foreground, root.accent)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: root.loadingOptions ? "" : ""
|
text: root.loadingOptions ? "" : ""
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
@@ -486,6 +489,7 @@ Item {
|
|||||||
height: popup.height - searchHeader.height - Style.spacing.xxs - 1
|
height: popup.height - searchHeader.height - Style.spacing.xxs - 1
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: resultList.count === 0
|
visible: resultList.count === 0
|
||||||
text: root.loadingOptions ? "Loading…" : (root.optionsError !== "" ? root.optionsError : root.emptyText)
|
text: root.loadingOptions ? "Loading…" : (root.optionsError !== "" ? root.optionsError : root.emptyText)
|
||||||
@@ -581,6 +585,7 @@ Item {
|
|||||||
spacing: Style.spacing.xxs
|
spacing: Style.spacing.xxs
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: modelData.label
|
text: modelData.label
|
||||||
color: index === resultList.currentIndex ? Style.hoverStateColor(root.foreground, root.accent) : root.foreground
|
color: index === resultList.currentIndex ? Style.hoverStateColor(root.foreground, root.accent) : root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -589,6 +594,7 @@ Item {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: text !== ""
|
visible: text !== ""
|
||||||
text: modelData.description
|
text: modelData.description
|
||||||
color: Qt.darker(root.foreground, 1.5)
|
color: Qt.darker(root.foreground, 1.5)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ Column {
|
|||||||
spacing: Style.spacing.md
|
spacing: Style.spacing.md
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.label !== ""
|
visible: root.label !== ""
|
||||||
text: root.label
|
text: root.label
|
||||||
color: Qt.darker(root.foreground, 1.4)
|
color: Qt.darker(root.foreground, 1.4)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: glyph
|
id: glyph
|
||||||
|
textFormat: Text.PlainText
|
||||||
// Keep the shared line box and baseline intact. Correcting only the
|
// Keep the shared line box and baseline intact. Correcting only the
|
||||||
// horizontal painted bounds avoids per-glyph vertical drift.
|
// horizontal painted bounds avoids per-glyph vertical drift.
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ BorderSurface {
|
|||||||
Behavior on color { ColorAnimation { duration: 60 } }
|
Behavior on color { ColorAnimation { duration: 60 } }
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: root.iconText
|
text: root.iconText
|
||||||
color: root.enabled
|
color: root.enabled
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ Item {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.title !== ""
|
visible: root.title !== ""
|
||||||
text: root.title
|
text: root.title
|
||||||
width: Math.min(implicitWidth, Math.max(0, parent.width - (detailPill.visible ? detailPill.implicitWidth + Style.space(8) : 0)))
|
width: Math.min(implicitWidth, Math.max(0, parent.width - (detailPill.visible ? detailPill.implicitWidth + Style.space(8) : 0)))
|
||||||
@@ -75,6 +76,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: detailText
|
id: detailText
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: root.detail
|
text: root.detail
|
||||||
color: root.dim
|
color: root.dim
|
||||||
@@ -87,6 +89,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: metaText
|
id: metaText
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: root.meta.toUpperCase()
|
text: root.meta.toUpperCase()
|
||||||
visible: text !== ""
|
visible: text !== ""
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ Text {
|
|||||||
property string fontFamily: Style.font.family
|
property string fontFamily: Style.font.family
|
||||||
property real fontSize: Style.font.caption
|
property real fontSize: Style.font.caption
|
||||||
|
|
||||||
|
// Callers bind `text` from outside this file, so the default has to be set
|
||||||
|
// here. AutoText would let a section title that happens to carry a device or
|
||||||
|
// network name promote itself to rich text.
|
||||||
|
textFormat: Text.PlainText
|
||||||
color: Qt.darker(foreground, 1.4)
|
color: Qt.darker(foreground, 1.4)
|
||||||
font.family: fontFamily
|
font.family: fontFamily
|
||||||
font.pixelSize: fontSize
|
font.pixelSize: fontSize
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ ToolTip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.text
|
text: root.text
|
||||||
color: root.panelForeground
|
color: root.panelForeground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ Item {
|
|||||||
spacing: Style.spacing.labelGap
|
spacing: Style.spacing.labelGap
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.showLabel && root.label !== ""
|
visible: root.showLabel && root.label !== ""
|
||||||
text: root.label
|
text: root.label
|
||||||
color: Qt.darker(root.foreground, 1.4)
|
color: Qt.darker(root.foreground, 1.4)
|
||||||
@@ -132,6 +133,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: chevron.left
|
anchors.right: chevron.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -246,6 +248,7 @@ Item {
|
|||||||
height: popup.height - searchHeader.height - Style.spacing.xxs - 1
|
height: popup.height - searchHeader.height - Style.spacing.xxs - 1
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: resultList.count === 0
|
visible: resultList.count === 0
|
||||||
text: root.emptyText
|
text: root.emptyText
|
||||||
@@ -313,6 +316,7 @@ Item {
|
|||||||
spacing: Style.spacing.xxs
|
spacing: Style.spacing.xxs
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.optionLabel(modelData)
|
text: root.optionLabel(modelData)
|
||||||
color: index === resultList.currentIndex ? Style.hoverStateColor(root.foreground, root.accent) : root.foreground
|
color: index === resultList.currentIndex ? Style.hoverStateColor(root.foreground, root.accent) : root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -321,6 +325,7 @@ Item {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: text !== ""
|
visible: text !== ""
|
||||||
text: root.optionDescription(modelData)
|
text: root.optionDescription(modelData)
|
||||||
color: Qt.darker(root.foreground, 1.5)
|
color: Qt.darker(root.foreground, 1.5)
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ PanelWindow {
|
|||||||
spacing: Style.space(16)
|
spacing: Style.space(16)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.title !== ""
|
visible: root.title !== ""
|
||||||
text: root.title.toUpperCase()
|
text: root.title.toUpperCase()
|
||||||
color: root.onScrimDim
|
color: root.onScrimDim
|
||||||
@@ -182,6 +183,7 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.failed
|
visible: root.failed
|
||||||
text: root.error
|
text: root.error
|
||||||
color: root.onScrimUrgent
|
color: root.onScrimUrgent
|
||||||
@@ -368,6 +370,7 @@ PanelWindow {
|
|||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
// Both branches go through the locale: a reading is a measurement, so
|
// Both branches go through the locale: a reading is a measurement, so
|
||||||
// its separators follow the system's number conventions rather than the
|
// its separators follow the system's number conventions rather than the
|
||||||
@@ -383,6 +386,7 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: root.unit
|
text: root.unit
|
||||||
color: root.onScrimDim
|
color: root.onScrimDim
|
||||||
@@ -394,6 +398,7 @@ PanelWindow {
|
|||||||
// The 90° gap at the bottom of the scale is where a cluster prints its
|
// The 90° gap at the bottom of the scale is where a cluster prints its
|
||||||
// unit; here it names the direction.
|
// unit; here it names the direction.
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
text: dial.label
|
text: dial.label
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ BorderSurface {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.label
|
text: root.label
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -79,6 +80,7 @@ BorderSurface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.description !== ""
|
visible: root.description !== ""
|
||||||
text: root.description
|
text: root.description
|
||||||
color: Qt.darker(root.foreground, 1.5)
|
color: Qt.darker(root.foreground, 1.5)
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: label
|
id: label
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.labelVisible
|
visible: root.labelVisible
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: root.text
|
text: root.text
|
||||||
|
|||||||
@@ -434,6 +434,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: heroMarkImage.status !== Image.Ready
|
visible: heroMarkImage.status !== Image.Ready
|
||||||
text: button.text
|
text: button.text
|
||||||
@@ -504,6 +505,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: statusText
|
id: statusText
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -558,6 +560,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: balanceValue
|
id: balanceValue
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.balance ? root.formatMoney(root.balance.remaining, root.balance.currency) : ""
|
text: root.balance ? root.formatMoney(root.balance.remaining, root.balance.currency) : ""
|
||||||
color: root.balanceAlarming ? root.urgent : root.foreground
|
color: root.balanceAlarming ? root.urgent : root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -575,6 +578,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: text !== ""
|
visible: text !== ""
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: root.balanceDetailText(root.balance)
|
text: root.balanceDetailText(root.balance)
|
||||||
@@ -680,6 +684,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: text !== ""
|
visible: text !== ""
|
||||||
width: parent.width
|
width: parent.width
|
||||||
topPadding: Style.space(2)
|
topPadding: Style.space(2)
|
||||||
@@ -710,6 +715,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: limitLabel
|
id: limitLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
// A model-scoped window is titled after its model, and those names run
|
// A model-scoped window is titled after its model, and those names run
|
||||||
// long enough to reach the percentage, so the title gives way first.
|
// long enough to reach the percentage, so the title gives way first.
|
||||||
text: limitRow.window ? limitRow.window.title : ""
|
text: limitRow.window ? limitRow.window.title : ""
|
||||||
@@ -725,6 +731,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: limitValue
|
id: limitValue
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: limitRow.window && limitRow.window.percent >= 0
|
text: limitRow.window && limitRow.window.percent >= 0
|
||||||
? Math.round(limitRow.window.percent * 100) + "%"
|
? Math.round(limitRow.window.percent * 100) + "%"
|
||||||
: "—"
|
: "—"
|
||||||
@@ -744,6 +751,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: resetText
|
id: resetText
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: {
|
text: {
|
||||||
var remainingMs = root.resetMsFor(limitRow.window)
|
var remainingMs = root.resetMsFor(limitRow.window)
|
||||||
@@ -798,6 +806,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: dayLabel
|
id: dayLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.dayLabel(dayRow.day ? dayRow.day.date : "", dayRow.today)
|
text: root.dayLabel(dayRow.day ? dayRow.day.date : "", dayRow.today)
|
||||||
color: dayRow.today ? root.foreground : root.dim
|
color: dayRow.today ? root.foreground : root.dim
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -835,6 +844,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: dayValue
|
id: dayValue
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: usage.formatTokenCount(dayRow.day ? Number(dayRow.day.messageCount || 0) : 0)
|
text: usage.formatTokenCount(dayRow.day ? Number(dayRow.day.messageCount || 0) : 0)
|
||||||
color: dayRow.today ? root.foreground : root.dim
|
color: dayRow.today ? root.foreground : root.dim
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -890,6 +900,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: modelName
|
id: modelName
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: modelRow.row ? modelRow.row.name : ""
|
text: modelRow.row ? modelRow.row.name : ""
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -904,6 +915,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: modelTokens
|
id: modelTokens
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: modelRow.row ? usage.formatTokenCount(modelRow.row.total) : ""
|
text: modelRow.row ? usage.formatTokenCount(modelRow.row.total) : ""
|
||||||
color: root.dim
|
color: root.dim
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
|
|||||||
@@ -1090,6 +1090,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: tooltipLabel
|
id: tooltipLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: root.tooltipText
|
text: root.tooltipText
|
||||||
color: Color.tooltip.text
|
color: Color.tooltip.text
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ BarWidget {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: labelText
|
id: labelText
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|||||||
@@ -467,6 +467,7 @@ BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: rowIcon.right
|
anchors.left: rowIcon.right
|
||||||
anchors.leftMargin: Style.space(10)
|
anchors.leftMargin: Style.space(10)
|
||||||
@@ -577,6 +578,7 @@ BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: Style.space(28)
|
anchors.leftMargin: Style.space(28)
|
||||||
@@ -681,6 +683,7 @@ BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: !menuRow.modelData.isSeparator && menuRow.modelData.buttonType !== QsMenuButtonType.None
|
visible: !menuRow.modelData.isSeparator && menuRow.modelData.buttonType !== QsMenuButtonType.None
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -709,6 +712,7 @@ BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: !menuRow.modelData.isSeparator
|
visible: !menuRow.modelData.isSeparator
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|||||||
@@ -432,6 +432,7 @@ Item {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -500,6 +501,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width - (parent.parent.previewImage.length > 0 ? parent.height + parent.spacing : 0)
|
width: parent.width - (parent.parent.previewImage.length > 0 ? parent.height + parent.spacing : 0)
|
||||||
height: parent.height
|
height: parent.height
|
||||||
text: parent.parent.previewText
|
text: parent.parent.previewText
|
||||||
@@ -546,6 +548,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: parent.activeRow && !parent.activeRow.previewImage
|
visible: parent.activeRow && !parent.activeRow.previewImage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: root.contentMargin
|
anchors.leftMargin: root.contentMargin
|
||||||
@@ -593,6 +596,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.history.length === 0 ? "Clipboard is empty" : "No matches for “" + root.filterText + "”"
|
text: root.history.length === 0 ? "Clipboard is empty" : "No matches for “" + root.filterText + "”"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
|
|||||||
@@ -519,12 +519,14 @@ Item {
|
|||||||
width: Style.space(140)
|
width: Style.space(140)
|
||||||
spacing: Style.space(1)
|
spacing: Style.space(1)
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: "Style.font." + modelData.key
|
text: "Style.font." + modelData.key
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
font.pixelSize: Style.font.bodySmall
|
font.pixelSize: Style.font.bodySmall
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: modelData.size + " px"
|
text: modelData.size + " px"
|
||||||
color: Qt.darker(root.foreground, 1.5)
|
color: Qt.darker(root.foreground, 1.5)
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -534,6 +536,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: sampleText
|
id: sampleText
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: metaCol.right
|
anchors.left: metaCol.right
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -574,6 +577,7 @@ Item {
|
|||||||
font.pixelSize: Style.font.bodySmall
|
font.pixelSize: Style.font.bodySmall
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Style.font.family
|
text: Style.font.family
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -587,6 +591,7 @@ Item {
|
|||||||
font.pixelSize: Style.font.bodySmall
|
font.pixelSize: Style.font.bodySmall
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Style.font.resolvedFamily
|
text: Style.font.resolvedFamily
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -600,6 +605,7 @@ Item {
|
|||||||
font.pixelSize: Style.font.bodySmall
|
font.pixelSize: Style.font.bodySmall
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Style.font.baseSize + " px"
|
text: Style.font.baseSize + " px"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -613,6 +619,7 @@ Item {
|
|||||||
font.pixelSize: Style.font.bodySmall
|
font.pixelSize: Style.font.bodySmall
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Style.bar.sizeHorizontal + " px"
|
text: Style.bar.sizeHorizontal + " px"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -626,6 +633,7 @@ Item {
|
|||||||
font.pixelSize: Style.font.bodySmall
|
font.pixelSize: Style.font.bodySmall
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Style.bar.sizeVertical + " px"
|
text: Style.bar.sizeVertical + " px"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -639,6 +647,7 @@ Item {
|
|||||||
font.pixelSize: Style.font.bodySmall
|
font.pixelSize: Style.font.bodySmall
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Style.spacing.scale.toFixed(2)
|
text: Style.spacing.scale.toFixed(2)
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -652,6 +661,7 @@ Item {
|
|||||||
font.pixelSize: Style.font.bodySmall
|
font.pixelSize: Style.font.bodySmall
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Style.spacing.panelPadding + " px"
|
text: Style.spacing.panelPadding + " px"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -818,6 +828,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: csLabel
|
id: csLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -1273,6 +1284,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Math.round((demoSlider.dragging ? demoSlider.liveValue : sliderRow.demoVolume) * 100) + "%"
|
text: Math.round((demoSlider.dragging ? demoSlider.liveValue : sliderRow.demoVolume) * 100) + "%"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
|
|||||||
@@ -247,6 +247,7 @@ Item {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -284,6 +285,7 @@ Item {
|
|||||||
color: hasCursor ? root.selectedBackground : "transparent"
|
color: hasCursor ? root.selectedBackground : "transparent"
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: parent.emoji
|
text: parent.emoji
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
font.pixelSize: Style.font.display
|
font.pixelSize: Style.font.display
|
||||||
@@ -326,6 +328,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: "No matches for “" + root.filterText + "”"
|
text: "No matches for “" + root.filterText + "”"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
|
|||||||
@@ -545,6 +545,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: selectedLabel
|
id: selectedLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.showLabels
|
visible: root.showLabels
|
||||||
anchors.top: carousel.bottom
|
anchors.top: carousel.bottom
|
||||||
anchors.topMargin: Style.space(16)
|
anchors.topMargin: Style.space(16)
|
||||||
@@ -561,6 +562,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.filterable && root.filterText
|
visible: root.filterable && root.filterText
|
||||||
anchors.top: selectedLabel.bottom
|
anchors.top: selectedLabel.bottom
|
||||||
anchors.topMargin: Style.space(8)
|
anchors.topMargin: Style.space(8)
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.fill: passwordInput
|
anchors.fill: passwordInput
|
||||||
text: root.authenticatingPassword ? "Checking…" : (root.failureMessage.length > 0 ? root.failureMessage : root.placeholderText)
|
text: root.authenticatingPassword ? "Checking…" : (root.failureMessage.length > 0 ? root.failureMessage : root.placeholderText)
|
||||||
visible: passwordInput.text.length === 0
|
visible: passwordInput.text.length === 0
|
||||||
|
|||||||
@@ -1199,6 +1199,7 @@ Item {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -1287,6 +1288,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: iconText
|
id: iconText
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: row.hasIcon && !row.isApp
|
visible: row.hasIcon && !row.isApp
|
||||||
text: row.icon
|
text: row.icon
|
||||||
color: row.hasCursor ? root.selectedText : root.foreground
|
color: row.hasCursor ? root.selectedText : root.foreground
|
||||||
@@ -1328,6 +1330,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: labelText
|
id: labelText
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: row.label
|
text: row.label
|
||||||
color: row.hasCursor ? root.selectedText : root.foreground
|
color: row.hasCursor ? root.selectedText : root.foreground
|
||||||
@@ -1338,6 +1341,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: row.detail
|
text: row.detail
|
||||||
visible: (root.filterText || row.kind === "dmenu") && row.detail.length > 0
|
visible: (root.filterText || row.kind === "dmenu") && row.detail.length > 0
|
||||||
@@ -1358,6 +1362,7 @@ Item {
|
|||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: false
|
visible: false
|
||||||
text: row.childCount
|
text: row.childCount
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
@@ -1368,6 +1373,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: row.kind === "menu" || row.kind === "link" ? "›" : ""
|
text: row.kind === "menu" || row.kind === "link" ? "›" : ""
|
||||||
color: row.hasCursor ? root.selectedText : root.foreground
|
color: row.hasCursor ? root.selectedText : root.foreground
|
||||||
opacity: row.kind === "menu" || row.kind === "link" ? 0.36 : 0
|
opacity: row.kind === "menu" || row.kind === "link" ? 0.36 : 0
|
||||||
@@ -1452,6 +1458,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.filterText ? "No matches for “" + root.filterText + "”" : "Nothing here yet"
|
text: root.filterText ? "No matches for “" + root.filterText + "”" : "Nothing here yet"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
|
|||||||
@@ -5,8 +5,34 @@ function isChromiumDerived(app, appIcon) {
|
|||||||
source.indexOf("opera") >= 0
|
source.indexOf("opera") >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The body renders as StyledText so notifications can use the markup the
|
||||||
|
// body-markup capability advertises (see Service.qml). StyledText honours
|
||||||
|
// <img src>, and a remote src makes the shell issue an unauthenticated GET
|
||||||
|
// with no user action, so image tags go before the renderer sees them.
|
||||||
|
//
|
||||||
|
// One replace() pass is not enough. String.replace scans left to right once,
|
||||||
|
// so a payload spliced inside the literal "<img" prefix reassembles into a
|
||||||
|
// live tag out of the surviving halves:
|
||||||
|
//
|
||||||
|
// <im<img src="http://a/decoy.png">g src="http://a/beacon.png">
|
||||||
|
// -> <img src="http://a/beacon.png">
|
||||||
|
//
|
||||||
|
// Repeat to a fixed point. Each pass can only shorten the string, so this
|
||||||
|
// terminates.
|
||||||
|
function stripImageTags(text) {
|
||||||
|
var current = text
|
||||||
|
var previous
|
||||||
|
do {
|
||||||
|
previous = current
|
||||||
|
// The `$` alternative catches a tag left unterminated at the end of the
|
||||||
|
// string, which the renderer closes for itself.
|
||||||
|
current = current.replace(/<img[^>]*(?:>|$)/gi, "")
|
||||||
|
} while (current !== previous)
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
function sanitizeBody(body, app, appIcon) {
|
function sanitizeBody(body, app, appIcon) {
|
||||||
var text = String(body || "").replace(/<img[^>]*>/gi, "")
|
var text = stripImageTags(String(body || ""))
|
||||||
if (!isChromiumDerived(app, appIcon)) return text
|
if (!isChromiumDerived(app, appIcon)) return text
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ BorderSurface {
|
|||||||
// Glyph fallback (Nerd Font character) when no image icon is
|
// Glyph fallback (Nerd Font character) when no image icon is
|
||||||
// available. Used by omarchy-notification-send's `-g` flag.
|
// available. Used by omarchy-notification-send's `-g` flag.
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: root.hasGlyph && smallIconImage.status !== Image.Ready
|
visible: root.hasGlyph && smallIconImage.status !== Image.Ready
|
||||||
text: root.glyph
|
text: root.glyph
|
||||||
@@ -143,6 +144,7 @@ BorderSurface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
visible: root.compactGlyph
|
visible: root.compactGlyph
|
||||||
text: root.glyph
|
text: root.glyph
|
||||||
@@ -159,6 +161,11 @@ BorderSurface {
|
|||||||
spacing: Style.space(2)
|
spacing: Style.space(2)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
// The spec defines the summary as a single line of plain text, so
|
||||||
|
// AutoText could only ever promote a hostile string to rich text.
|
||||||
|
// The body below is StyledText on purpose — see Service.qml's
|
||||||
|
// bodyMarkupSupported — and is stripped in NotificationLogic.
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: root.summary.length > 0
|
visible: root.summary.length > 0
|
||||||
text: root.summary
|
text: root.summary
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ Item {
|
|||||||
width: root.iconWidth
|
width: root.iconWidth
|
||||||
height: parent.height
|
height: parent.height
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
// Sit the glyph's ink flush in the column, centered when the
|
// Sit the glyph's ink flush in the column, centered when the
|
||||||
// column is wider than this particular glyph.
|
// column is wider than this particular glyph.
|
||||||
x: Math.round((root.iconWidth - root.iconInkWidth) / 2 - iconMetrics.tightBoundingRect.x)
|
x: Math.round((root.iconWidth - root.iconInkWidth) / 2 - iconMetrics.tightBoundingRect.x)
|
||||||
@@ -186,6 +187,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.message !== ""
|
visible: root.message !== ""
|
||||||
width: root.hasProgress ? root.valueWidth : root.messageWidth
|
width: root.hasProgress ? root.valueWidth : root.messageWidth
|
||||||
// The readout hugs the card edge so a short percentage doesn't leave
|
// The readout hugs the card edge so a short percentage doesn't leave
|
||||||
|
|||||||
@@ -711,6 +711,7 @@ Panel {
|
|||||||
// Status only — the switch owns muting, mouse and keyboard alike.
|
// Status only — the switch owns muting, mouse and keyboard alike.
|
||||||
Text {
|
Text {
|
||||||
id: heroIcon
|
id: heroIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.outputIcon()
|
text: root.outputIcon()
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -761,6 +762,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroLabel
|
id: heroLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.outputVolumeName(
|
text: root.outputVolumeName(
|
||||||
outputSlider.dragging ? outputSlider.liveValue : root.outputVolume,
|
outputSlider.dragging ? outputSlider.liveValue : root.outputVolume,
|
||||||
root.outputMuted
|
root.outputMuted
|
||||||
@@ -800,6 +802,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: outputPercent
|
id: outputPercent
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Math.round((outputSlider.dragging ? outputSlider.liveValue : root.outputVolume) * 100) + "%"
|
text: Math.round((outputSlider.dragging ? outputSlider.liveValue : root.outputVolume) * 100) + "%"
|
||||||
color: Qt.darker(root.bar.foreground, 1.4)
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -886,6 +889,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: microphonePercent
|
id: microphonePercent
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Math.round((inputSlider.dragging ? inputSlider.liveValue : root.inputVolume) * 100) + "%"
|
text: Math.round((inputSlider.dragging ? inputSlider.liveValue : root.inputVolume) * 100) + "%"
|
||||||
color: Qt.darker(root.bar.foreground, 1.4)
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1030,6 +1034,7 @@ Panel {
|
|||||||
spacing: Style.space(8)
|
spacing: Style.space(8)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.sinkGlyph(sinkRow.node)
|
text: root.sinkGlyph(sinkRow.node)
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1040,6 +1045,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.nodeLabel(sinkRow.node)
|
text: root.nodeLabel(sinkRow.node)
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1089,6 +1095,7 @@ Panel {
|
|||||||
spacing: Style.space(8)
|
spacing: Style.space(8)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.sourceGlyph(sourceRow.node)
|
text: root.sourceGlyph(sourceRow.node)
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1099,6 +1106,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.nodeLabel(sourceRow.node)
|
text: root.nodeLabel(sourceRow.node)
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1159,6 +1167,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: streamMuteIcon
|
id: streamMuteIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: streamRow.streamMuted ? "" : ""
|
text: streamRow.streamMuted ? "" : ""
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1179,6 +1188,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.streamLabel(streamRow.node)
|
text: root.streamLabel(streamRow.node)
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1191,6 +1201,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: streamPct
|
id: streamPct
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Math.round(streamRow.streamVolume * 100) + "%"
|
text: Math.round(streamRow.streamVolume * 100) + "%"
|
||||||
color: Qt.darker(root.bar.foreground, 1.5)
|
color: Qt.darker(root.bar.foreground, 1.5)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
|
|||||||
@@ -698,6 +698,7 @@ Panel {
|
|||||||
// Status only — the switch owns toggling, mouse and keyboard alike.
|
// Status only — the switch owns toggling, mouse and keyboard alike.
|
||||||
Text {
|
Text {
|
||||||
id: heroIcon
|
id: heroIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: root.icon
|
text: root.icon
|
||||||
@@ -748,6 +749,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroStatus
|
id: heroStatus
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.heroStatusText.toUpperCase()
|
text: root.heroStatusText.toUpperCase()
|
||||||
color: Qt.darker(root.bar.foreground, 1.4)
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -863,6 +865,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.connectedDevices.length === 0 && root.scrollRows.length === 0
|
visible: root.connectedDevices.length === 0 && root.scrollRows.length === 0
|
||||||
text: !root.adapter ? "No Bluetooth adapter"
|
text: !root.adapter ? "No Bluetooth adapter"
|
||||||
: !root.adapter.enabled ? "Turn Bluetooth on to scan"
|
: !root.adapter.enabled ? "Turn Bluetooth on to scan"
|
||||||
@@ -971,6 +974,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: deviceIcon
|
id: deviceIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: row.isConnected ? "" : ""
|
text: row.isConnected ? "" : ""
|
||||||
color: row.statusColor
|
color: row.statusColor
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -989,6 +993,7 @@ Panel {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.deviceLabel(row.dev) || "Device"
|
text: root.deviceLabel(row.dev) || "Device"
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -997,6 +1002,7 @@ Panel {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: row.statusText !== ""
|
visible: row.statusText !== ""
|
||||||
text: row.statusText
|
text: row.statusText
|
||||||
color: row.statusColor
|
color: row.statusColor
|
||||||
|
|||||||
@@ -311,6 +311,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroDate
|
id: heroDate
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: Qt.formatDate(root.today, "MMMM d")
|
text: Qt.formatDate(root.today, "MMMM d")
|
||||||
color: heroMouse.containsMouse
|
color: heroMouse.containsMouse
|
||||||
@@ -413,6 +414,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: yearLabel
|
id: yearLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: !root.editingLife
|
visible: !root.editingLife
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -425,6 +427,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: yearPercent
|
id: yearPercent
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: !root.editingLife
|
visible: !root.editingLife
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -485,6 +488,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: lifePercent
|
id: lifePercent
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: root.lifeDonePercent + "%"
|
text: root.lifeDonePercent + "%"
|
||||||
@@ -608,6 +612,7 @@ Panel {
|
|||||||
model: root.weekdays
|
model: root.weekdays
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
required property var modelData
|
required property var modelData
|
||||||
width: root.cellWidth
|
width: root.cellWidth
|
||||||
height: Style.space(16)
|
height: Style.space(16)
|
||||||
@@ -631,6 +636,7 @@ Panel {
|
|||||||
spacing: root.cellSpacing
|
spacing: root.cellSpacing
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: root.weekColumnWidth
|
width: root.weekColumnWidth
|
||||||
height: root.cellHeight
|
height: root.cellHeight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
@@ -662,6 +668,7 @@ Panel {
|
|||||||
border.color: Style.normalBorderFor(root.contentForeground, Color.accent)
|
border.color: Style.normalBorderFor(root.contentForeground, Color.accent)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: modelData.day
|
text: modelData.day
|
||||||
color: modelData.inMonth
|
color: modelData.inMonth
|
||||||
@@ -707,6 +714,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: monthLabel
|
id: monthLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
// Fixed width so the chevrons hold still between a
|
// Fixed width so the chevrons hold still between a
|
||||||
|
|||||||
@@ -281,6 +281,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: dropbox.actionStatus !== "" || dropbox.lastError !== ""
|
visible: dropbox.actionStatus !== "" || dropbox.lastError !== ""
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: dropbox.actionStatus !== "" ? dropbox.actionStatus : dropbox.lastError
|
text: dropbox.actionStatus !== "" ? dropbox.actionStatus : dropbox.lastError
|
||||||
@@ -421,6 +422,7 @@ Panel {
|
|||||||
spacing: Style.space(1)
|
spacing: Style.space(1)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: dropbox.installed ? "Login to Dropbox" : "Dropbox CLI is not installed"
|
text: dropbox.installed ? "Login to Dropbox" : "Dropbox CLI is not installed"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
@@ -430,6 +432,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: dropbox.installed ? "Start the authentication flow" : "Install Dropbox from the service menu"
|
text: dropbox.installed ? "Start the authentication flow" : "Install Dropbox from the service menu"
|
||||||
color: root.dim
|
color: root.dim
|
||||||
@@ -478,6 +481,7 @@ Panel {
|
|||||||
spacing: Style.space(8)
|
spacing: Style.space(8)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Model.fileGlyph(fileRow.fileName)
|
text: Model.fileGlyph(fileRow.fileName)
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -491,6 +495,7 @@ Panel {
|
|||||||
spacing: Style.space(1)
|
spacing: Style.space(1)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: fileRow.fileName
|
text: fileRow.fileName
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
@@ -500,6 +505,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: Model.fileMeta(fileRow.file)
|
text: Model.fileMeta(fileRow.file)
|
||||||
color: root.dim
|
color: root.dim
|
||||||
|
|||||||
@@ -531,6 +531,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroIcon
|
id: heroIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.displays.length > 1 ? "" : ""
|
text: root.displays.length > 1 ? "" : ""
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -559,6 +560,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroLabel
|
id: heroLabel
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: {
|
text: {
|
||||||
if (root.brightnessAvailable) {
|
if (root.brightnessAvailable) {
|
||||||
return root.brightnessName(brightnessSlider.dragging ? brightnessSlider.liveValue : root.brightnessPercent).toUpperCase()
|
return root.brightnessName(brightnessSlider.dragging ? brightnessSlider.liveValue : root.brightnessPercent).toUpperCase()
|
||||||
@@ -602,6 +604,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: brightnessPercent
|
id: brightnessPercent
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: Math.round(brightnessSlider.dragging ? brightnessSlider.liveValue : root.brightnessPercent) + "%"
|
text: Math.round(brightnessSlider.dragging ? brightnessSlider.liveValue : root.brightnessPercent) + "%"
|
||||||
color: Qt.darker(root.bar.foreground, 1.4)
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -674,6 +677,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: textSizePx
|
id: textSizePx
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: (textSizeSlider.dragging
|
text: (textSizeSlider.dragging
|
||||||
? root.textSizeStops[Math.round(textSizeSlider.liveValue)]
|
? root.textSizeStops[Math.round(textSizeSlider.liveValue)]
|
||||||
: root.displayedTextPx()) + "px"
|
: root.displayedTextPx()) + "px"
|
||||||
@@ -747,6 +751,7 @@ Panel {
|
|||||||
// focused one.
|
// focused one.
|
||||||
Text {
|
Text {
|
||||||
id: scaleMonitor
|
id: scaleMonitor
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.focusedMonitor
|
text: root.focusedMonitor
|
||||||
// Only worth naming when more than one display is in play.
|
// Only worth naming when more than one display is in play.
|
||||||
visible: root.focusedMonitor !== "" && root.enabledDisplayCount > 1
|
visible: root.focusedMonitor !== "" && root.enabledDisplayCount > 1
|
||||||
@@ -887,6 +892,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: monitorRow.display.name + (monitorRow.display.focused ? " · focused" : "")
|
text: monitorRow.display.name + (monitorRow.display.focused ? " · focused" : "")
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -897,6 +903,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: monitorRow.display.enabled ? "" : ""
|
text: monitorRow.display.enabled ? "" : ""
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
|
|||||||
@@ -1090,6 +1090,7 @@ Panel {
|
|||||||
// Status only — the switch owns toggling, mouse and keyboard alike.
|
// Status only — the switch owns toggling, mouse and keyboard alike.
|
||||||
Text {
|
Text {
|
||||||
id: heroIcon
|
id: heroIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.icon
|
text: root.icon
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1170,6 +1171,7 @@ Panel {
|
|||||||
// rather than in a pill, which crowded the on/off switch.
|
// rather than in a pill, which crowded the on/off switch.
|
||||||
Text {
|
Text {
|
||||||
id: heroSsid
|
id: heroSsid
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
readonly property string title: {
|
readonly property string title: {
|
||||||
@@ -1189,6 +1191,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroMeta
|
id: heroMeta
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: {
|
text: {
|
||||||
if (root.info.type === "wifi") {
|
if (root.info.type === "wifi") {
|
||||||
@@ -1711,6 +1714,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: networkIcon
|
id: networkIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: row.net ? root.wifiIconFor(row.net.signal) : ""
|
text: row.net ? root.wifiIconFor(row.net.signal) : ""
|
||||||
color: row.statusColor
|
color: row.statusColor
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1732,6 +1736,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: lockIndicator
|
id: lockIndicator
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: row.requiresCredentials || row.forgetVisible
|
visible: row.requiresCredentials || row.forgetVisible
|
||||||
width: parent.width
|
width: parent.width
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -1779,6 +1784,7 @@ Panel {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: row.net ? (row.net.ssid || "Hidden") : ""
|
text: row.net ? (row.net.ssid || "Hidden") : ""
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -1787,6 +1793,7 @@ Panel {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
// Signal strength is conveyed by the wifi-bars icon and the
|
// Signal strength is conveyed by the wifi-bars icon and the
|
||||||
// right-edge glyph/buttons carry protection or forget affordances,
|
// right-edge glyph/buttons carry protection or forget affordances,
|
||||||
// so the second line only carries action status (Connecting…,
|
// so the second line only carries action status (Connecting…,
|
||||||
@@ -1893,6 +1900,7 @@ Panel {
|
|||||||
radius: Style.cornerRadius
|
radius: Style.cornerRadius
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|||||||
@@ -325,6 +325,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroIcon
|
id: heroIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.batteryIcon()
|
text: root.batteryIcon()
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -356,6 +357,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroStatus
|
id: heroStatus
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.heroStatusText.toUpperCase()
|
text: root.heroStatusText.toUpperCase()
|
||||||
color: Qt.darker(root.bar.foreground, 1.4)
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -369,6 +371,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroPercent
|
id: heroPercent
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.batteryInfo.percentage || "—"
|
text: root.batteryInfo.percentage || "—"
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
|
|||||||
@@ -498,6 +498,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: tailscale.actionStatus !== "" || tailscale.lastError !== ""
|
visible: tailscale.actionStatus !== "" || tailscale.lastError !== ""
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: tailscale.actionStatus !== "" ? tailscale.actionStatus : tailscale.lastError
|
text: tailscale.actionStatus !== "" ? tailscale.actionStatus : tailscale.lastError
|
||||||
@@ -841,6 +842,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: accountRow.accountText
|
text: accountRow.accountText
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -933,6 +935,7 @@ Panel {
|
|||||||
spacing: Style.space(8)
|
spacing: Style.space(8)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: tailscale.osIcon(peer ? peer.OS : "")
|
text: tailscale.osIcon(peer ? peer.OS : "")
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -946,6 +949,7 @@ Panel {
|
|||||||
spacing: Style.space(1)
|
spacing: Style.space(1)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: peerRow.peerName
|
text: peerRow.peerName
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
@@ -955,6 +959,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: {
|
text: {
|
||||||
var parts = []
|
var parts = []
|
||||||
@@ -1087,6 +1092,7 @@ Panel {
|
|||||||
spacing: Style.space(10)
|
spacing: Style.space(10)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: copyChoice.label
|
text: copyChoice.label
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
@@ -1134,6 +1140,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: exitNodeGlyph
|
id: exitNodeGlyph
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: exitNodeRow.addMullvad ? "+" : (peer && peer.Mullvad === true ? "" : "")
|
text: exitNodeRow.addMullvad ? "+" : (peer && peer.Mullvad === true ? "" : "")
|
||||||
color: exitNodeRow.activeExitNode || exitNodeRow.settingExitNode || exitNodeRow.addMullvad ? root.foreground : root.dim
|
color: exitNodeRow.activeExitNode || exitNodeRow.settingExitNode || exitNodeRow.addMullvad ? root.foreground : root.dim
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -1154,6 +1161,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: exitNodeRow.peerName
|
text: exitNodeRow.peerName
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -1224,6 +1232,7 @@ Panel {
|
|||||||
spacing: Style.space(1)
|
spacing: Style.space(1)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: regionRow.regionName
|
text: regionRow.regionName
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
@@ -1234,6 +1243,7 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: regionRow.regionDetail
|
text: regionRow.regionDetail
|
||||||
visible: text !== ""
|
visible: text !== ""
|
||||||
|
|||||||
@@ -531,6 +531,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: heroIcon
|
id: heroIcon
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.verticalCenterOffset: 5
|
anchors.verticalCenterOffset: 5
|
||||||
text: root.label || "—"
|
text: root.label || "—"
|
||||||
@@ -547,6 +548,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: tempBig
|
id: tempBig
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.reportTempNum || "—"
|
text: root.reportTempNum || "—"
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -556,6 +558,7 @@ Panel {
|
|||||||
font.bold: true
|
font.bold: true
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.current ? root.tempUnit : ""
|
text: root.current ? root.tempUnit : ""
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -593,6 +596,7 @@ Panel {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: (root.reportLocation || "").toUpperCase()
|
text: (root.reportLocation || "").toUpperCase()
|
||||||
color: Qt.darker(root.bar.foreground, 1.4)
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -643,6 +647,7 @@ Panel {
|
|||||||
color: !root.savingLocation && clearLocationArea.containsMouse ? Style.hoverFillFor(root.bar.foreground, Color.accent) : "transparent"
|
color: !root.savingLocation && clearLocationArea.containsMouse ? Style.hoverFillFor(root.bar.foreground, Color.accent) : "transparent"
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: root.savingLocation ? "" : "✕"
|
text: root.savingLocation ? "" : "✕"
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -683,6 +688,7 @@ Panel {
|
|||||||
font.letterSpacing: 1
|
font.letterSpacing: 1
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.reportFeels
|
text: root.reportFeels
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -700,6 +706,7 @@ Panel {
|
|||||||
font.letterSpacing: 1
|
font.letterSpacing: 1
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.reportWind
|
text: root.reportWind
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -717,6 +724,7 @@ Panel {
|
|||||||
font.letterSpacing: 1
|
font.letterSpacing: 1
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.reportHumidity
|
text: root.reportHumidity
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -752,12 +760,14 @@ Panel {
|
|||||||
spacing: Style.space(8)
|
spacing: Style.space(8)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: modelData.name
|
text: modelData.name
|
||||||
color: index === root.suggestionIndex ? Style.hoverStateColor(root.bar.foreground, Color.accent) : root.bar.foreground
|
color: index === root.suggestionIndex ? Style.hoverStateColor(root.bar.foreground, Color.accent) : root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
font.pixelSize: Style.font.body
|
font.pixelSize: Style.font.body
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: text !== ""
|
visible: text !== ""
|
||||||
text: modelData.description
|
text: modelData.description
|
||||||
color: Qt.darker(root.bar.foreground, 1.5)
|
color: Qt.darker(root.bar.foreground, 1.5)
|
||||||
@@ -817,6 +827,7 @@ Panel {
|
|||||||
spacing: Style.space(10)
|
spacing: Style.space(10)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: root.dayIcon(modelData)
|
text: root.dayIcon(modelData)
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
@@ -829,6 +840,7 @@ Panel {
|
|||||||
spacing: Style.space(2)
|
spacing: Style.space(2)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.dayName(modelData.date).toUpperCase()
|
text: root.dayName(modelData.date).toUpperCase()
|
||||||
color: Qt.darker(root.bar.foreground, 1.4)
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -840,12 +852,14 @@ Panel {
|
|||||||
spacing: Style.space(6)
|
spacing: Style.space(6)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.bareTempForDay(modelData, "max")
|
text: root.bareTempForDay(modelData, "max")
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
font.pixelSize: Style.font.body
|
font.pixelSize: Style.font.body
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.bareTempForDay(modelData, "min")
|
text: root.bareTempForDay(modelData, "min")
|
||||||
color: Qt.darker(root.bar.foreground, 1.5)
|
color: Qt.darker(root.bar.foreground, 1.5)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
|
|||||||
@@ -257,6 +257,7 @@ Item {
|
|||||||
spacing: Style.space(16)
|
spacing: Style.space(16)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: (root.ssid || "Wi-Fi").toUpperCase()
|
text: (root.ssid || "Wi-Fi").toUpperCase()
|
||||||
color: root.onScrimDim
|
color: root.onScrimDim
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
@@ -318,6 +319,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.error !== ""
|
visible: root.error !== ""
|
||||||
text: root.error
|
text: root.error
|
||||||
color: root.onScrimUrgent
|
color: root.onScrimUrgent
|
||||||
@@ -340,6 +342,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
visible: root.showingQr && root.secured
|
visible: root.showingQr && root.secured
|
||||||
text: root.passwordError !== "" ? root.passwordError
|
text: root.passwordError !== "" ? root.passwordError
|
||||||
: root.passwordVisible ? root.password
|
: root.passwordVisible ? root.password
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -374,6 +375,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: justificationText
|
id: justificationText
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: Style.space(12)
|
anchors.leftMargin: Style.space(12)
|
||||||
anchors.rightMargin: Style.space(12)
|
anchors.rightMargin: Style.space(12)
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ Item {
|
|||||||
anchors.leftMargin: card.contentLeftInset
|
anchors.leftMargin: card.contentLeftInset
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ BarWidget {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: glyph
|
id: glyph
|
||||||
|
textFormat: Text.PlainText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: root.playIcon
|
text: root.playIcon
|
||||||
color: activePlayer && activePlayer.isPlaying ? root.bar.barForeground : Qt.darker(root.bar.barForeground, 1.5)
|
color: activePlayer && activePlayer.isPlaying ? root.bar.barForeground : Qt.darker(root.bar.barForeground, 1.5)
|
||||||
@@ -53,6 +54,7 @@ BarWidget {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: labelText
|
id: labelText
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.title + (root.artist ? " · " + root.artist : "")
|
text: root.title + (root.artist ? " · " + root.artist : "")
|
||||||
color: root.bar.barForeground
|
color: root.bar.barForeground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -148,6 +150,7 @@ BarWidget {
|
|||||||
width: parent.width - Style.space(74)
|
width: parent.width - Style.space(74)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.title || "Nothing playing"
|
text: root.title || "Nothing playing"
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -158,6 +161,7 @@ BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.artist
|
text: root.artist
|
||||||
color: Qt.darker(root.bar.foreground, 1.3)
|
color: Qt.darker(root.bar.foreground, 1.3)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -168,6 +172,7 @@ BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: root.activePlayer && root.activePlayer.trackAlbum ? root.activePlayer.trackAlbum : ""
|
text: root.activePlayer && root.activePlayer.trackAlbum ? root.activePlayer.trackAlbum : ""
|
||||||
color: Qt.darker(root.bar.foreground, 1.6)
|
color: Qt.darker(root.bar.foreground, 1.6)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -255,6 +260,7 @@ BarWidget {
|
|||||||
spacing: Style.space(8)
|
spacing: Style.space(8)
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: sourceRow.player && sourceRow.player.isPlaying ? "" : ""
|
text: sourceRow.player && sourceRow.player.isPlaying ? "" : ""
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -270,6 +276,7 @@ BarWidget {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: sourceRow.sourceTitle
|
text: sourceRow.sourceTitle
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
@@ -280,6 +287,7 @@ BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
textFormat: Text.PlainText
|
||||||
text: sourceRow.sourceDetail
|
text: sourceRow.sourceDetail
|
||||||
color: Qt.darker(root.bar.foreground, 1.5)
|
color: Qt.darker(root.bar.foreground, 1.5)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
|
|||||||
@@ -18,6 +18,40 @@ assertEqual(
|
|||||||
'notifications strip inline image tags'
|
'notifications strip inline image tags'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The body renders as StyledText, which fetches <img src> over the network, so
|
||||||
|
// the strip has to survive a payload built to outlive one replace() pass. A
|
||||||
|
// single left-to-right pass consumes the inner tag and lets the outer halves
|
||||||
|
// close up into a live tag: <im + g src="..."> .
|
||||||
|
assertEqual(
|
||||||
|
notifications.sanitizeBody('<im<img src="http://host/decoy.png">g src="http://host/beacon.png">', 'Slack', ''),
|
||||||
|
'',
|
||||||
|
'notifications strip image tags that reassemble after one substitution'
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEqual(
|
||||||
|
notifications.sanitizeBody('<im<im<img src=a>g src=b>g src="http://host/deep.png">', 'Slack', ''),
|
||||||
|
'',
|
||||||
|
'notifications strip nested image tags to a fixed point'
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEqual(
|
||||||
|
notifications.sanitizeBody('trailing <img src="http://host/z.png"', 'Slack', ''),
|
||||||
|
'trailing ',
|
||||||
|
'notifications strip an unterminated image tag the renderer would close itself'
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEqual(
|
||||||
|
notifications.sanitizeBody('<IMG SRC="http://host/u.png">shout', 'Slack', ''),
|
||||||
|
'shout',
|
||||||
|
'notifications strip image tags regardless of case'
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEqual(
|
||||||
|
notifications.sanitizeBody('<b>bold</b> and <a href="http://host">link</a>', 'Slack', ''),
|
||||||
|
'<b>bold</b> and <a href="http://host">link</a>',
|
||||||
|
'notifications keep the body markup the body-markup capability advertises'
|
||||||
|
)
|
||||||
|
|
||||||
assertEqual(
|
assertEqual(
|
||||||
notifications.sanitizeBody('<a href="https://example.com">example.com</a> Message body', 'Chromium', ''),
|
notifications.sanitizeBody('<a href="https://example.com">example.com</a> Message body', 'Chromium', ''),
|
||||||
'Message body',
|
'Message body',
|
||||||
|
|||||||
Executable
+144
@@ -0,0 +1,144 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# A QML Text element with no textFormat uses Text.AutoText. Qt then runs
|
||||||
|
# mightBeRichText() over the string and promotes it to Text.RichText when it
|
||||||
|
# looks like markup, and RichText fetches <img src="http://..."> through
|
||||||
|
# QQuickPixmap. Any string that reaches such an element from outside the shell
|
||||||
|
# — a notification summary, an MPRIS track title, a window title, an SSID, a
|
||||||
|
# Bluetooth device name, clipboard content, a weather API response — can
|
||||||
|
# therefore make the shell issue an unauthenticated outbound GET with no user
|
||||||
|
# interaction.
|
||||||
|
#
|
||||||
|
# The promotion needs only that the attacker contribute the first `<` in the
|
||||||
|
# string, on the first line. A fixed label in front of the value does not
|
||||||
|
# protect it, and neither does .toUpperCase(), because the parser lowercases
|
||||||
|
# the tag before looking it up.
|
||||||
|
#
|
||||||
|
# So require an explicit textFormat on every Text whose text: binding is not a
|
||||||
|
# bare string literal. A literal carries no external data, so AutoText has
|
||||||
|
# nothing to promote; this test is what catches the edit that later turns such
|
||||||
|
# a literal into an expression.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||||
|
|
||||||
|
require_command python3
|
||||||
|
|
||||||
|
violations=$(ROOT="$ROOT" python3 <<'PY'
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
OPEN_ELEMENT = re.compile(r'(?:^|[:\s])([A-Z][A-Za-z0-9_.]*)\s*\{\s*$')
|
||||||
|
PROP = re.compile(r'^\s*([A-Za-z_][A-Za-z0-9_.]*)\s*:')
|
||||||
|
STRING_LITERAL = re.compile(r'"(?:[^"\\]|\\.)*"|\'(?:[^\'\\]|\\.)*\'')
|
||||||
|
PROPERTY_DECL = re.compile(r'^\s*(?:readonly\s+)?property\b')
|
||||||
|
ROOT_TEXT = re.compile(r'^Text\s*\{\s*$')
|
||||||
|
|
||||||
|
|
||||||
|
def strip_noise(line, keep_strings=False):
|
||||||
|
out = []
|
||||||
|
i = 0
|
||||||
|
quote = None
|
||||||
|
while i < len(line):
|
||||||
|
c = line[i]
|
||||||
|
if quote:
|
||||||
|
if keep_strings:
|
||||||
|
out.append(c)
|
||||||
|
if c == '\\':
|
||||||
|
if keep_strings and i + 1 < len(line):
|
||||||
|
out.append(line[i + 1])
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
if c == quote:
|
||||||
|
quote = None
|
||||||
|
if not keep_strings:
|
||||||
|
out.append('S')
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if c in '"\'':
|
||||||
|
quote = c
|
||||||
|
if keep_strings:
|
||||||
|
out.append(c)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if c == '/' and i + 1 < len(line) and line[i + 1] == '/':
|
||||||
|
break
|
||||||
|
out.append(c)
|
||||||
|
i += 1
|
||||||
|
return ''.join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def is_pure_literal(expr):
|
||||||
|
residue = STRING_LITERAL.sub('', expr)
|
||||||
|
residue = re.sub(r'[\s+]', '', residue)
|
||||||
|
return residue == '' and STRING_LITERAL.search(expr) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def blocks(lines):
|
||||||
|
stack = []
|
||||||
|
done = []
|
||||||
|
depth = 0
|
||||||
|
for idx, raw in enumerate(lines):
|
||||||
|
code = strip_noise(raw)
|
||||||
|
opened = OPEN_ELEMENT.search(code)
|
||||||
|
prop = PROP.match(code)
|
||||||
|
if (prop and stack and stack[-1]['depth'] == depth
|
||||||
|
and not opened and not PROPERTY_DECL.match(code)):
|
||||||
|
stack[-1]['props'].setdefault(prop.group(1), idx)
|
||||||
|
n_open = code.count('{')
|
||||||
|
n_close = code.count('}')
|
||||||
|
if opened and n_open > 0:
|
||||||
|
depth += 1
|
||||||
|
stack.append({'name': opened.group(1), 'depth': depth,
|
||||||
|
'props': {}, 'start': idx})
|
||||||
|
depth += n_open - 1 - n_close
|
||||||
|
else:
|
||||||
|
depth += n_open - n_close
|
||||||
|
while stack and depth < stack[-1]['depth']:
|
||||||
|
done.append(stack.pop())
|
||||||
|
done.extend(stack)
|
||||||
|
return done
|
||||||
|
|
||||||
|
|
||||||
|
root = Path(os.environ['ROOT'])
|
||||||
|
found = []
|
||||||
|
for path in sorted((root / 'shell').rglob('*.qml')):
|
||||||
|
lines = path.read_text().splitlines()
|
||||||
|
rel = path.relative_to(root)
|
||||||
|
|
||||||
|
# A component whose root element is a Text takes its binding from callers,
|
||||||
|
# so the default has to be declared in the component itself.
|
||||||
|
if lines and any(ROOT_TEXT.match(l) for l in lines[:40]):
|
||||||
|
if not any(re.match(r'\s*textFormat\s*:', l) for l in lines):
|
||||||
|
found.append(f'{rel}: root Text element declares no textFormat')
|
||||||
|
|
||||||
|
for b in blocks(lines):
|
||||||
|
if b['name'] != 'Text' or 'textFormat' in b['props']:
|
||||||
|
continue
|
||||||
|
if 'text' not in b['props']:
|
||||||
|
continue
|
||||||
|
tline = b['props']['text']
|
||||||
|
expr = strip_noise(lines[tline], keep_strings=True).split(':', 1)[1]
|
||||||
|
if is_pure_literal(expr):
|
||||||
|
continue
|
||||||
|
found.append(f'{rel}:{tline + 1}: text binding without textFormat')
|
||||||
|
|
||||||
|
for line in found:
|
||||||
|
print(line)
|
||||||
|
PY
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ -n $violations ]]; then
|
||||||
|
count=$(printf '%s\n' "$violations" | wc -l)
|
||||||
|
fail "every Text with a dynamic text binding declares textFormat" \
|
||||||
|
"$violations
|
||||||
|
|
||||||
|
$count Text element(s) rely on Text.AutoText for a non-literal binding.
|
||||||
|
Add an explicit textFormat. Text.PlainText is right for anything that renders
|
||||||
|
data from outside the shell; use Text.StyledText only where markup is a
|
||||||
|
deliberate, documented feature, and strip <img> before it reaches the renderer."
|
||||||
|
fi
|
||||||
|
|
||||||
|
pass "every Text with a dynamic text binding declares textFormat"
|
||||||
Reference in New Issue
Block a user