Simplified view code

This commit is contained in:
Digital Artifex
2026-06-23 21:02:17 -04:00
parent 5a150c29f9
commit 6d32ed6bce
8 changed files with 452 additions and 372 deletions
+111 -259
View File
@@ -8,66 +8,33 @@ import KomplexHub.Controls
import KomplexHub.Kero
import KomplexHubPlugin
Item {
Item
{
readonly property bool searchable: false
property int resultsPerRow: (homePageRoot.width - (64 + Constants.largeMargin)) / (resultWidth + Constants.largeMargin) + 1
property int resultWidth: 256
property int resultHeight: 256
property int resultHeight: 245
clip: true
id: homePageRoot
NewestPacksModel
{
id: newestPacksModel
id: packsModel
resultsPerPage: homePageRoot.resultsPerRow
onStateChanged: () =>
{
if(state == NewestPacksModel.Loading)
{
console.log("Newest packs loading")
}
else if(state == NewestPacksModel.Idle)
{
console.log("Newest packs finished")
}
}
}
FeaturedImagesModel
{
id: featuredImagesModel
id: imagesModel
resultsPerPage: homePageRoot.resultsPerRow
onStateChanged: () =>
{
if(state == FeaturedImagesModel.Loading)
{
console.log("Featured Images loading")
}
else if(state == FeaturedImagesModel.Idle)
{
console.log("Featured Images finished")
}
}
}
FeaturedVideosModel
{
id: featuredVideosModel
id: videosModel
resultsPerPage: homePageRoot.resultsPerRow
onStateChanged: () =>
{
if(state == FeaturedVideosModel.Loading)
{
console.log("Featured Videos loading")
}
else if(state == FeaturedVideosModel.Idle)
{
console.log("Featured Videos finished")
}
}
}
Rectangle
@@ -75,59 +42,34 @@ Item {
anchors.fill: parent
color: palette.base
ScrollView
ColumnLayout
{
id: newPacksView
id: resultsLayout
anchors.fill: parent
anchors.margins: Constants.largeMargin
ColumnLayout
{
width: newPacksView.width
ColumnLayout
{
width: parent.width
height: 420
anchors.margins: Constants.mediumMargin
Text
{
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: 50
color: palette.text
font.pixelSize: Constants.h2Font.pixelSize
font.bold: true
text: qsTr("Newest Wallpaper Packs")
verticalAlignment: Qt.AlignVCenter
}
RowLayout
HorizontalPaginator
{
id: packsPaginator
Layout.fillWidth: true
Layout.preferredHeight: 256
Layout.preferredHeight: 245
Layout.alignment: Qt.AlignTop
Rectangle
model: packsModel
delegate: ItemDelegate
{
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
clip: true
Row
{
clip: true
spacing: Constants.mediumMargin
anchors.top: parent.top
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.right: newPacksMoreButton.left
anchors.leftMargin: Constants.largeMargin
anchors.rightMargin: Constants.largeMargin
Repeater
{
model: newestPacksModel
delegate: Item {
width: resultWidth
height: resultHeight
@@ -137,6 +79,7 @@ Item {
required property string uuid
required property string thumbnail
required property string authorId
required property int index
SearchResultItem
{
@@ -146,92 +89,39 @@ Item {
description: parent.description
thumbnail: parent.thumbnail
uuid: parent.uuid
}
}
}
selected: parent.highlighted
}
Rectangle
MouseArea
{
id: newestGradientMap
anchors.top: parent.top
anchors.right: newPacksMoreButton.left
height: resultHeight
width: resultWidth / 4
gradient: Gradient
{
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: "transparent" }
GradientStop { position: 1.0; color: palette.light }
}
opacity: 0.5
}
SquareButton
{
id: newPacksMoreButton
anchors.top: parent.top
anchors.right: parent.right
height: resultHeight
width: 64
icon.source: "qrc:/images/icons/icons8-forward.svg"
icon.height: 24
icon.width: 24
anchors.fill: parent
onClicked: () => packsPaginator.currentIndex = index
}
}
}
}
Item {
height: Constants.largeMargin
}
ColumnLayout
{
width: parent.width
height: 420
Text
{
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: 50
color: palette.text
font.pixelSize: Constants.h2Font.pixelSize
font.bold: true
text: qsTr("Featured Images")
verticalAlignment: Qt.AlignVCenter
}
RowLayout
HorizontalPaginator
{
id: imagesPaginator
Layout.fillWidth: true
Layout.preferredHeight: 256
Layout.preferredHeight: 245
Layout.alignment: Qt.AlignTop
Rectangle
{
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
clip: true
Row
{
clip: true
spacing: Constants.mediumMargin
anchors.top: parent.top
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.right: featuredImagesMoreButton.left
anchors.leftMargin: Constants.largeMargin
anchors.rightMargin: Constants.largeMargin
Repeater
{
model: featuredImagesModel
delegate: Item
model: imagesModel
delegate: ItemDelegate
{
width: resultWidth
height: resultHeight
@@ -249,93 +139,40 @@ Item {
description: parent.description
thumbnail: parent.thumbnail
uuid: parent.uuid
pexels: true
}
}
}
selected: parent.highlighted
}
Rectangle
MouseArea
{
anchors.top: parent.top
anchors.right: featuredImagesMoreButton.left
height: resultHeight
width: resultWidth / 4
gradient: Gradient
{
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: "transparent" }
GradientStop { position: 1.0; color: palette.light }
}
opacity: 0.5
}
SquareButton
{
id: featuredImagesMoreButton
anchors.top: parent.top
anchors.right: parent.right
height: resultHeight
width: 64
icon.source: "qrc:/images/icons/icons8-forward.svg"
icon.height: 24
icon.width: 24
anchors.fill: parent
onClicked: () => imagesPaginator.currentIndex = index
}
}
}
}
Item {
height: Constants.largeMargin
}
ColumnLayout
{
width: parent.width
height: 420
Text
{
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: 50
color: palette.text
font.pixelSize: Constants.h2Font.pixelSize
font.bold: true
text: qsTr("Featured Videos")
text: qsTr("Popular Videos")
verticalAlignment: Qt.AlignVCenter
}
RowLayout
HorizontalPaginator
{
id: videosPaginator
Layout.fillWidth: true
Layout.preferredHeight: 256
Layout.preferredHeight: 245
Layout.alignment: Qt.AlignTop
Rectangle
model: videosModel
delegate: ItemDelegate
{
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
clip: true
Row
{
clip: true
spacing: Constants.mediumMargin
anchors.top: parent.top
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.right: featuredVideosMoreButton.left
anchors.leftMargin: Constants.largeMargin
anchors.rightMargin: Constants.largeMargin
Repeater
{
model: featuredVideosModel
delegate: Item {
width: resultWidth
height: resultHeight
@@ -352,52 +189,27 @@ Item {
thumbnail: parent.thumbnail
uuid: parent.uuid
pexels: true
}
}
}
selected: parent.highlighted
}
Rectangle
MouseArea
{
anchors.top: parent.top
anchors.right: featuredVideosMoreButton.left
height: resultHeight
width: resultWidth / 4
gradient: Gradient
{
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: "transparent" }
GradientStop { position: 1.0; color: palette.light }
anchors.fill: parent
onClicked: () => videosPaginator.currentIndex = index
}
}
opacity: 0.5
}
SquareButton
{
id: featuredVideosMoreButton
anchors.top: parent.top
anchors.right: parent.right
height: resultHeight
width: 64
icon.source: "qrc:/images/icons/icons8-forward.svg"
icon.height: 24
icon.width: 24
}
}
}
}
}
/* spacer */
Item { Layout.fillHeight: true }
}
}
Component.onCompleted: () =>
{
featuredImagesModel.nextPage()
featuredVideosModel.nextPage()
newestPacksModel.nextPage()
imagesModel.nextPage()
videosModel.nextPage()
packsModel.nextPage()
}
KeroLoadingAnimation
@@ -405,26 +217,66 @@ Item {
id: loadingAnimation
anchors.fill: parent
OpacityAnimator on opacity {
duration: 150
}
visible: opacity > 0
opacity: 0
opacity: 1
}
states: [
State {
name: "loading"
when: newestPacksModel.state == NewestPacksModel.Loading ||
featuredImagesModel.state == FeaturedImagesModel.Loading ||
featuredVideosModel.state == FeaturedVideosModel.Loading;
when: packsModel.state === NewestPacksModel.Loading ||
imagesModel.state === FeaturedImagesModel.Loading ||
videosModel.state === FeaturedVideosModel.Loading;
PropertyChanges {
PropertyChanges
{
target: loadingAnimation
opacity: 1
}
PropertyChanges
{
target: resultsLayout
opacity: 0
}
},
State {
name: "idle"
when: packsModel.state !== NewestPacksModel.Loading &&
imagesModel.state !== FeaturedImagesModel.Loading &&
videosModel.state !== FeaturedVideosModel.Loading;
PropertyChanges
{
target: loadingAnimation
opacity: 0
}
PropertyChanges
{
target: resultsLayout
opacity: 1
}
}
]
transitions: [
Transition
{
from: "loading"
to: "idle"
NumberAnimation
{
target: loadingOverlay
duration: 250
property: "opacity";
}
NumberAnimation
{
target: resultsLayout
duration: 250
property: "opacity";
}
}
]
}
+13 -1
View File
@@ -28,15 +28,19 @@ Item
model: searchModel
loading: model.state === ImageSearchModel.Loading
delegate: Item
delegate: ItemDelegate
{
id: resultDelegate
width: 256
height: 245
required property string author
required property string description
required property string uuid
required property string thumbnail
required property string authorId
required property int index
SearchResultItem
{
@@ -45,6 +49,14 @@ Item
description: parent.description
thumbnail: parent.thumbnail
uuid: parent.uuid
selected: resultDelegate.highlighted
}
MouseArea
{
anchors.fill: parent
onClicked: paginator.currentIndex = index
}
}
}
+15 -3
View File
@@ -12,7 +12,7 @@ Item
property string query
readonly property bool searchable: paginator.searchable
VideoSearchModel
PackSearchModel
{
id: searchModel
query: rootItem.query
@@ -24,12 +24,16 @@ Item
id: paginator
anchors.fill: parent
model: searchModel
loading: model.state === VideoSearchModel.Loading
loading: model.state === PackSearchModel.Loading
delegate: Item
delegate: ItemDelegate
{
id: resultDelegate
width: 256
height: 245
required property string name
required property string author
required property string description
required property string uuid
@@ -43,6 +47,14 @@ Item
description: parent.description
thumbnail: parent.thumbnail
uuid: parent.uuid
selected: resultDelegate.highlighted
}
MouseArea
{
anchors.fill: parent
onClicked: paginator.currentIndex = index
}
}
}
+13 -1
View File
@@ -28,15 +28,19 @@ Item
model: searchModel
loading: model.state === VideoSearchModel.Loading
delegate: Item
delegate: ItemDelegate
{
id: resultDelegate
width: 256
height: 245
required property string author
required property string description
required property string uuid
required property string thumbnail
required property string authorId
required property int index
SearchResultItem
{
@@ -45,6 +49,14 @@ Item
description: parent.description
thumbnail: parent.thumbnail
uuid: parent.uuid
selected: resultDelegate.highlighted
}
MouseArea
{
anchors.fill: parent
onClicked: paginator.currentIndex = index
}
}
}
+1
View File
@@ -16,5 +16,6 @@ qt6_add_qml_module(KomplexHubModule_Controls
"SearchResultList.qml"
QML_FILES PaginationBox.qml
QML_FILES PaginatorGrid.qml
QML_FILES HorizontalPaginator.qml
)
@@ -0,0 +1,169 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import KomplexHub
import KomplexHub.Controls
import KomplexHub.Kero
import KomplexHubPlugin
Item
{
readonly property bool searchable: false
property int resultsPerRow: (resultsContainer.width - (Constants.largeMargin * 2)) / (resultWidth + Constants.mediumMargin)
property int rows: ((resultsContainer.height - (Constants.largeMargin * 2)) / (resultHeight + Constants.mediumMargin))
property int resultsPerPage: resultsPerRow * rows
property int emptyWidth: (resultsContainer.width - (Constants.largeMargin * 2)) - (resultsPerRow * (resultWidth + Constants.mediumMargin))
property int resultWidth: 256
property int resultHeight: 245
property bool loading: false
property alias currentItem: resultsView.currentItem
property alias currentIndex: resultsView.currentIndex
property var model
property Component delegate
id: rootItem
Item
{
id: resultsContainer
anchors.fill: parent
RowLayout
{
anchors.fill: parent
Component
{
id: highlight
Rectangle
{
width: 256
height: 245
color: palette.accent
radius: 5
// x: resultsView.currentItem.x
// y: resultsView.currentItem.y
Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } }
Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } }
}
}
ListView
{
id: resultsView
Layout.fillHeight: true
Layout.fillWidth: true
spacing: Constants.mediumMargin
orientation: ListView.Horizontal
model: rootItem.model
delegate: rootItem.delegate
highlight: Rectangle { color: palette.accent; radius: 5 }
highlightFollowsCurrentItem: true
focus: true
add: Transition
{
NumberAnimation
{
properties: "x"
from: resultsContainer.width
duration: 250
}
NumberAnimation
{
properties: "opacity,scale"
to: 1.0
duration: 500
}
}
move: Transition
{
NumberAnimation
{
properties: "x,y"
duration: 250
}
}
displaced: Transition
{
NumberAnimation
{
properties: "x,y"
duration: 250
}
}
populate: Transition
{
NumberAnimation
{
properties: "opacity,scale"
to: 1.0
duration: 500
}
}
remove: Transition
{
NumberAnimation
{
properties: "x"
to: 0
duration: 250
}
NumberAnimation
{
properties: "opacity"
to: 0
duration: 250
}
}
}
Item
{
Layout.fillHeight: true
Layout.preferredWidth: 128
Rectangle
{
id: gradientMap
anchors.top: parent.top
anchors.right: moreButton.left
height: resultHeight
width: resultWidth / 4
gradient: Gradient
{
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: "transparent" }
GradientStop { position: 1.0; color: palette.light }
}
opacity: 0.5
}
SquareButton
{
id: moreButton
anchors.top: parent.top
anchors.right: parent.right
height: resultHeight
width: 64
icon.source: "qrc:/images/icons/icons8-forward.svg"
icon.height: 24
icon.width: 24
}
}
}
}
}
+32 -1
View File
@@ -19,6 +19,9 @@ Item
property int resultHeight: 245
property bool loading: false
property alias currentItem: resultsView.currentItem
property alias currentIndex: resultsView.currentIndex
property var model
property Component delegate
@@ -78,6 +81,22 @@ Item
Layout.maximumWidth: emptyWidth / 2
}
Component
{
id: highlight
Rectangle
{
width: view.cellWidth
height: view.cellHeight
color: palette.accent
radius: 5
x: view.currentItem.x
y: view.currentItem.y
Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } }
Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } }
}
}
GridView
{
id: resultsView
@@ -86,10 +105,12 @@ Item
cellWidth: 256 + Constants.mediumMargin
cellHeight: 245 + Constants.mediumMargin
focus: true
model: rootItem.model
delegate: rootItem.delegate
highlight: Rectangle { color: palette.accent; radius: 5 }
highlightFollowsCurrentItem: true
focus: true
add: Transition
{
@@ -116,6 +137,15 @@ Item
}
}
displaced: Transition
{
NumberAnimation
{
properties: "x,y"
duration: 250
}
}
populate: Transition
{
NumberAnimation
@@ -146,6 +176,7 @@ Item
PaginationBox
{
id: buttonBoxLayout
height: 35
anchors.left: parent.left
+2 -11
View File
@@ -119,7 +119,8 @@ Item {
}
}
MouseArea {
MouseArea
{
property string lastState
id: mouseArea
@@ -155,16 +156,6 @@ Item {
}
}
onSelectedChanged: () => {
if(selected) {
searchResultItemRoot.triggered()
searchResultItemRoot.state = "selected"
}
else {
searchResultItemRoot.state = ""
}
}
states: [
State {
name: "hovered"