controlcenter: fonts performance fix (virtual listview)

This commit is contained in:
ATMDA 2025-11-15 21:43:09 -05:00
parent 420a19bf31
commit 7d839be3e5

View file

@ -540,64 +540,65 @@ RowLayout {
font.weight: 500 font.weight: 500
} }
ColumnLayout { StyledListView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: Math.min(contentHeight, 300)
clip: true
spacing: Appearance.spacing.small / 2 spacing: Appearance.spacing.small / 2
model: Qt.fontFamilies()
Repeater { delegate: StyledRect {
model: Qt.fontFamilies() required property string modelData
required property int index
delegate: StyledRect { width: ListView.view.width
required property string modelData
Layout.fillWidth: true readonly property bool isCurrent: modelData === rootPane.fontFamilyMaterial
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0)
radius: Appearance.rounding.normal
border.width: isCurrent ? 1 : 0
border.color: Colours.palette.m3primary
readonly property bool isCurrent: modelData === rootPane.fontFamilyMaterial StateLayer {
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) function onClicked(): void {
radius: Appearance.rounding.normal rootPane.fontFamilyMaterial = modelData;
border.width: isCurrent ? 1 : 0 rootPane.saveConfig();
border.color: Colours.palette.m3primary
StateLayer {
function onClicked(): void {
rootPane.fontFamilyMaterial = modelData;
rootPane.saveConfig();
}
} }
RowLayout {
id: fontFamilyMaterialRow
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Appearance.padding.normal
spacing: Appearance.spacing.normal
StyledText {
text: modelData
font.pointSize: Appearance.font.size.normal
}
Item {
Layout.fillWidth: true
}
Loader {
active: isCurrent
asynchronous: true
sourceComponent: MaterialIcon {
text: "check"
color: Colours.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
}
}
}
implicitHeight: fontFamilyMaterialRow.implicitHeight + Appearance.padding.normal * 2
} }
RowLayout {
id: fontFamilyMaterialRow
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Appearance.padding.normal
spacing: Appearance.spacing.normal
StyledText {
text: modelData
font.pointSize: Appearance.font.size.normal
}
Item {
Layout.fillWidth: true
}
Loader {
active: isCurrent
asynchronous: true
sourceComponent: MaterialIcon {
text: "check"
color: Colours.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
}
}
}
implicitHeight: fontFamilyMaterialRow.implicitHeight + Appearance.padding.normal * 2
} }
} }
@ -608,64 +609,65 @@ RowLayout {
font.weight: 500 font.weight: 500
} }
ColumnLayout { StyledListView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: Math.min(contentHeight, 300)
clip: true
spacing: Appearance.spacing.small / 2 spacing: Appearance.spacing.small / 2
model: Qt.fontFamilies()
Repeater { delegate: StyledRect {
model: Qt.fontFamilies() required property string modelData
required property int index
delegate: StyledRect { width: ListView.view.width
required property string modelData
Layout.fillWidth: true readonly property bool isCurrent: modelData === rootPane.fontFamilyMono
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0)
radius: Appearance.rounding.normal
border.width: isCurrent ? 1 : 0
border.color: Colours.palette.m3primary
readonly property bool isCurrent: modelData === rootPane.fontFamilyMono StateLayer {
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) function onClicked(): void {
radius: Appearance.rounding.normal rootPane.fontFamilyMono = modelData;
border.width: isCurrent ? 1 : 0 rootPane.saveConfig();
border.color: Colours.palette.m3primary
StateLayer {
function onClicked(): void {
rootPane.fontFamilyMono = modelData;
rootPane.saveConfig();
}
} }
RowLayout {
id: fontFamilyMonoRow
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Appearance.padding.normal
spacing: Appearance.spacing.normal
StyledText {
text: modelData
font.pointSize: Appearance.font.size.normal
}
Item {
Layout.fillWidth: true
}
Loader {
active: isCurrent
asynchronous: true
sourceComponent: MaterialIcon {
text: "check"
color: Colours.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
}
}
}
implicitHeight: fontFamilyMonoRow.implicitHeight + Appearance.padding.normal * 2
} }
RowLayout {
id: fontFamilyMonoRow
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Appearance.padding.normal
spacing: Appearance.spacing.normal
StyledText {
text: modelData
font.pointSize: Appearance.font.size.normal
}
Item {
Layout.fillWidth: true
}
Loader {
active: isCurrent
asynchronous: true
sourceComponent: MaterialIcon {
text: "check"
color: Colours.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
}
}
}
implicitHeight: fontFamilyMonoRow.implicitHeight + Appearance.padding.normal * 2
} }
} }
@ -676,64 +678,65 @@ RowLayout {
font.weight: 500 font.weight: 500
} }
ColumnLayout { StyledListView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: Math.min(contentHeight, 300)
clip: true
spacing: Appearance.spacing.small / 2 spacing: Appearance.spacing.small / 2
model: Qt.fontFamilies()
Repeater { delegate: StyledRect {
model: Qt.fontFamilies() required property string modelData
required property int index
delegate: StyledRect { width: ListView.view.width
required property string modelData
Layout.fillWidth: true readonly property bool isCurrent: modelData === rootPane.fontFamilySans
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0)
radius: Appearance.rounding.normal
border.width: isCurrent ? 1 : 0
border.color: Colours.palette.m3primary
readonly property bool isCurrent: modelData === rootPane.fontFamilySans StateLayer {
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) function onClicked(): void {
radius: Appearance.rounding.normal rootPane.fontFamilySans = modelData;
border.width: isCurrent ? 1 : 0 rootPane.saveConfig();
border.color: Colours.palette.m3primary
StateLayer {
function onClicked(): void {
rootPane.fontFamilySans = modelData;
rootPane.saveConfig();
}
} }
RowLayout {
id: fontFamilySansRow
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Appearance.padding.normal
spacing: Appearance.spacing.normal
StyledText {
text: modelData
font.pointSize: Appearance.font.size.normal
}
Item {
Layout.fillWidth: true
}
Loader {
active: isCurrent
asynchronous: true
sourceComponent: MaterialIcon {
text: "check"
color: Colours.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
}
}
}
implicitHeight: fontFamilySansRow.implicitHeight + Appearance.padding.normal * 2
} }
RowLayout {
id: fontFamilySansRow
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Appearance.padding.normal
spacing: Appearance.spacing.normal
StyledText {
text: modelData
font.pointSize: Appearance.font.size.normal
}
Item {
Layout.fillWidth: true
}
Loader {
active: isCurrent
asynchronous: true
sourceComponent: MaterialIcon {
text: "check"
color: Colours.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
}
}
}
implicitHeight: fontFamilySansRow.implicitHeight + Appearance.padding.normal * 2
} }
} }
@ -1874,211 +1877,210 @@ RowLayout {
color: Colours.palette.m3onSurfaceVariant color: Colours.palette.m3onSurfaceVariant
} }
GridLayout { GridView {
id: wallpaperGrid
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Appearance.spacing.large Layout.topMargin: Appearance.spacing.large
Layout.preferredHeight: Math.min(600, Math.ceil(count / Math.floor(width / cellWidth)) * cellHeight)
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
columns: Math.max(2, Math.floor(parent.width / 200)) cellWidth: 200 + Appearance.spacing.normal
rowSpacing: Appearance.spacing.normal cellHeight: 140 + Appearance.spacing.normal
columnSpacing: Appearance.spacing.normal
// Center the grid content model: Wallpapers.list
Layout.maximumWidth: { clip: true
const cols = columns;
const itemWidth = 200; // Enable caching for better performance
const spacing = columnSpacing; cacheBuffer: cellHeight * 2
return cols * itemWidth + (cols - 1) * spacing;
StyledScrollBar.vertical: StyledScrollBar {
flickable: wallpaperGrid
} }
Repeater { delegate: Item {
model: Wallpapers.list required property var modelData
delegate: Item { width: 200
required property var modelData height: 140
Layout.preferredWidth: 200 // Center in cell
Layout.preferredHeight: 140 x: (wallpaperGrid.cellWidth - width) / 2
Layout.minimumWidth: 200 y: (wallpaperGrid.cellHeight - height) / 2
Layout.minimumHeight: 140
Layout.maximumWidth: 200
Layout.maximumHeight: 140
readonly property bool isCurrent: modelData.path === Wallpapers.actualCurrent readonly property bool isCurrent: modelData.path === Wallpapers.actualCurrent
StateLayer { StateLayer {
radius: Appearance.rounding.normal radius: Appearance.rounding.normal
function onClicked(): void { function onClicked(): void {
Wallpapers.setWallpaper(modelData.path); Wallpapers.setWallpaper(modelData.path);
}
} }
}
StyledClippingRect { StyledClippingRect {
id: image id: image
anchors.fill: parent
color: Colours.tPalette.m3surfaceContainer
radius: Appearance.rounding.normal
CachingImage {
id: cachingImage
path: modelData.path
anchors.fill: parent anchors.fill: parent
color: Colours.tPalette.m3surfaceContainer cache: true
radius: Appearance.rounding.normal visible: opacity > 0
CachingImage { // Show when ready
id: cachingImage opacity: status === Image.Ready ? 1 : 0
path: modelData.path Behavior on opacity {
anchors.fill: parent
cache: true
visible: opacity > 0
// Show when ready
opacity: status === Image.Ready ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 1000
easing.type: Easing.OutQuad
}
}
}
// Fallback image for when caching fails
Image {
id: fallbackImage
anchors.fill: parent
source: fallbackTimer.triggered && cachingImage.status !== Image.Ready ? modelData.path : ""
asynchronous: true
fillMode: Image.PreserveAspectCrop
cache: true
visible: opacity > 0
opacity: status === Image.Ready && cachingImage.status !== Image.Ready ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 1000
easing.type: Easing.OutQuad
}
}
}
// Timer to trigger fallback only if caching hasn't loaded
Timer {
id: fallbackTimer
property bool triggered: false
interval: 800
running: cachingImage.status === Image.Loading || cachingImage.status === Image.Null
onTriggered: triggered = true
}
}
// Border overlay that doesn't affect image size
Rectangle {
anchors.fill: parent
color: "transparent"
radius: Appearance.rounding.normal
border.width: isCurrent ? 2 : 0
border.color: Colours.palette.m3primary
Behavior on border.width {
NumberAnimation { NumberAnimation {
duration: 150 duration: 1000
easing.type: Easing.OutQuad easing.type: Easing.OutQuad
} }
} }
}
MaterialIcon { // Fallback image for when caching fails
anchors.right: parent.right Image {
anchors.top: parent.top id: fallbackImage
anchors.margins: Appearance.padding.small
visible: isCurrent anchors.fill: parent
text: "check_circle" source: fallbackTimer.triggered && cachingImage.status !== Image.Ready ? modelData.path : ""
color: Colours.palette.m3primary asynchronous: true
font.pointSize: Appearance.font.size.large fillMode: Image.PreserveAspectCrop
} cache: true
visible: opacity > 0
// Gradient overlay for filename with rounded bottom corners opacity: status === Image.Ready && cachingImage.status !== Image.Ready ? 1 : 0
Rectangle {
id: filenameOverlay
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
implicitHeight: filenameText.implicitHeight + Appearance.padding.normal * 2
radius: Appearance.rounding.normal
gradient: Gradient {
GradientStop {
position: 0.0
color: Qt.rgba(0, 0, 0, 0)
}
GradientStop {
position: 0.3
color: Qt.rgba(0, 0, 0, 0.3)
}
GradientStop {
position: 0.7
color: Qt.rgba(0, 0, 0, 0.75)
}
GradientStop {
position: 1.0
color: Qt.rgba(0, 0, 0, 0.85)
}
}
}
opacity: 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: 1000 duration: 1000
easing.type: Easing.OutCubic easing.type: Easing.OutQuad
} }
} }
Component.onCompleted: {
opacity = 1;
}
} }
StyledText { // Timer to trigger fallback only if caching hasn't loaded
id: filenameText Timer {
id: fallbackTimer
property bool triggered: false
interval: 800
running: cachingImage.status === Image.Loading || cachingImage.status === Image.Null
onTriggered: triggered = true
}
}
// Border overlay that doesn't affect image size
Rectangle {
anchors.fill: parent
color: "transparent"
radius: Appearance.rounding.normal
border.width: isCurrent ? 2 : 0
border.color: Colours.palette.m3primary
Behavior on border.width {
NumberAnimation {
duration: 150
easing.type: Easing.OutQuad
}
}
MaterialIcon {
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Appearance.padding.small
visible: isCurrent
text: "check_circle"
color: Colours.palette.m3primary
font.pointSize: Appearance.font.size.large
}
// Gradient overlay for filename with rounded bottom corners
Rectangle {
id: filenameOverlay
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
anchors.bottomMargin: Appearance.padding.normal
readonly property string fileName: { implicitHeight: filenameText.implicitHeight + Appearance.padding.normal * 2
const path = modelData.relativePath || "";
const parts = path.split("/");
return parts.length > 0 ? parts[parts.length - 1] : path;
}
text: fileName radius: Appearance.rounding.normal
font.pointSize: Appearance.font.size.smaller
font.weight: 500
color: isCurrent ? Colours.palette.m3primary : "#FFFFFF"
elide: Text.ElideMiddle
maximumLineCount: 1
opacity: 0 gradient: Gradient {
GradientStop {
Behavior on opacity { position: 0.0
NumberAnimation { color: Qt.rgba(0, 0, 0, 0)
duration: 1000 }
easing.type: Easing.OutCubic GradientStop {
position: 0.3
color: Qt.rgba(0, 0, 0, 0.3)
}
GradientStop {
position: 0.7
color: Qt.rgba(0, 0, 0, 0.75)
}
GradientStop {
position: 1.0
color: Qt.rgba(0, 0, 0, 0.85)
} }
} }
}
Component.onCompleted: { opacity: 0
opacity = 1;
Behavior on opacity {
NumberAnimation {
duration: 1000
easing.type: Easing.OutCubic
} }
} }
Component.onCompleted: {
opacity = 1;
}
}
StyledText {
id: filenameText
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
anchors.bottomMargin: Appearance.padding.normal
readonly property string fileName: {
const path = modelData.relativePath || "";
const parts = path.split("/");
return parts.length > 0 ? parts[parts.length - 1] : path;
}
text: fileName
font.pointSize: Appearance.font.size.smaller
font.weight: 500
color: isCurrent ? Colours.palette.m3primary : "#FFFFFF"
elide: Text.ElideMiddle
maximumLineCount: 1
opacity: 0
Behavior on opacity {
NumberAnimation {
duration: 1000
easing.type: Easing.OutCubic
}
}
Component.onCompleted: {
opacity = 1;
}
} }
} }
} }