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 KomplexHub.Kero
import KomplexHubPlugin import KomplexHubPlugin
Item { Item
{
readonly property bool searchable: false readonly property bool searchable: false
property int resultsPerRow: (homePageRoot.width - (64 + Constants.largeMargin)) / (resultWidth + Constants.largeMargin) + 1 property int resultsPerRow: (homePageRoot.width - (64 + Constants.largeMargin)) / (resultWidth + Constants.largeMargin) + 1
property int resultWidth: 256 property int resultWidth: 256
property int resultHeight: 256 property int resultHeight: 245
clip: true
id: homePageRoot id: homePageRoot
NewestPacksModel NewestPacksModel
{ {
id: newestPacksModel id: packsModel
resultsPerPage: homePageRoot.resultsPerRow resultsPerPage: homePageRoot.resultsPerRow
onStateChanged: () =>
{
if(state == NewestPacksModel.Loading)
{
console.log("Newest packs loading")
}
else if(state == NewestPacksModel.Idle)
{
console.log("Newest packs finished")
}
}
} }
FeaturedImagesModel FeaturedImagesModel
{ {
id: featuredImagesModel id: imagesModel
resultsPerPage: homePageRoot.resultsPerRow resultsPerPage: homePageRoot.resultsPerRow
onStateChanged: () =>
{
if(state == FeaturedImagesModel.Loading)
{
console.log("Featured Images loading")
}
else if(state == FeaturedImagesModel.Idle)
{
console.log("Featured Images finished")
}
}
} }
FeaturedVideosModel FeaturedVideosModel
{ {
id: featuredVideosModel id: videosModel
resultsPerPage: homePageRoot.resultsPerRow resultsPerPage: homePageRoot.resultsPerRow
onStateChanged: () =>
{
if(state == FeaturedVideosModel.Loading)
{
console.log("Featured Videos loading")
}
else if(state == FeaturedVideosModel.Idle)
{
console.log("Featured Videos finished")
}
}
} }
Rectangle Rectangle
@@ -75,59 +42,34 @@ Item {
anchors.fill: parent anchors.fill: parent
color: palette.base color: palette.base
ScrollView ColumnLayout
{ {
id: newPacksView id: resultsLayout
anchors.fill: parent anchors.fill: parent
anchors.margins: Constants.largeMargin anchors.margins: Constants.mediumMargin
ColumnLayout
{
width: newPacksView.width
ColumnLayout
{
width: parent.width
height: 420
Text Text
{ {
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: 50
color: palette.text color: palette.text
font.pixelSize: Constants.h2Font.pixelSize font.pixelSize: Constants.h2Font.pixelSize
font.bold: true font.bold: true
text: qsTr("Newest Wallpaper Packs") text: qsTr("Newest Wallpaper Packs")
verticalAlignment: Qt.AlignVCenter
} }
RowLayout HorizontalPaginator
{ {
id: packsPaginator
Layout.fillWidth: true 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 width: resultWidth
height: resultHeight height: resultHeight
@@ -137,6 +79,7 @@ Item {
required property string uuid required property string uuid
required property string thumbnail required property string thumbnail
required property string authorId required property string authorId
required property int index
SearchResultItem SearchResultItem
{ {
@@ -146,92 +89,39 @@ Item {
description: parent.description description: parent.description
thumbnail: parent.thumbnail thumbnail: parent.thumbnail
uuid: parent.uuid uuid: parent.uuid
}
} selected: parent.highlighted
}
} }
Rectangle MouseArea
{ {
id: newestGradientMap anchors.fill: parent
anchors.top: parent.top onClicked: () => packsPaginator.currentIndex = index
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
} }
} }
} }
}
Item {
height: Constants.largeMargin
}
ColumnLayout
{
width: parent.width
height: 420
Text Text
{ {
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: 50
color: palette.text color: palette.text
font.pixelSize: Constants.h2Font.pixelSize font.pixelSize: Constants.h2Font.pixelSize
font.bold: true font.bold: true
text: qsTr("Featured Images") text: qsTr("Featured Images")
verticalAlignment: Qt.AlignVCenter
} }
RowLayout HorizontalPaginator
{ {
id: imagesPaginator
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 256 Layout.preferredHeight: 245
Layout.alignment: Qt.AlignTop
Rectangle model: imagesModel
{ 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: featuredImagesMoreButton.left
anchors.leftMargin: Constants.largeMargin
anchors.rightMargin: Constants.largeMargin
Repeater
{
model: featuredImagesModel
delegate: Item
{ {
width: resultWidth width: resultWidth
height: resultHeight height: resultHeight
@@ -249,93 +139,40 @@ Item {
description: parent.description description: parent.description
thumbnail: parent.thumbnail thumbnail: parent.thumbnail
uuid: parent.uuid uuid: parent.uuid
pexels: true pexels: true
} selected: parent.highlighted
}
}
} }
Rectangle MouseArea
{ {
anchors.top: parent.top anchors.fill: parent
anchors.right: featuredImagesMoreButton.left onClicked: () => imagesPaginator.currentIndex = index
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
} }
} }
} }
}
Item {
height: Constants.largeMargin
}
ColumnLayout
{
width: parent.width
height: 420
Text Text
{ {
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: 50
color: palette.text color: palette.text
font.pixelSize: Constants.h2Font.pixelSize font.pixelSize: Constants.h2Font.pixelSize
font.bold: true font.bold: true
text: qsTr("Featured Videos") text: qsTr("Popular Videos")
verticalAlignment: Qt.AlignVCenter
} }
RowLayout HorizontalPaginator
{ {
id: videosPaginator
Layout.fillWidth: true 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 width: resultWidth
height: resultHeight height: resultHeight
@@ -352,52 +189,27 @@ Item {
thumbnail: parent.thumbnail thumbnail: parent.thumbnail
uuid: parent.uuid uuid: parent.uuid
pexels: true pexels: true
} selected: parent.highlighted
}
}
} }
Rectangle MouseArea
{ {
anchors.top: parent.top anchors.fill: parent
anchors.right: featuredVideosMoreButton.left onClicked: () => videosPaginator.currentIndex = index
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 /* spacer */
{ Item { Layout.fillHeight: true }
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
}
}
}
}
}
} }
} }
Component.onCompleted: () => Component.onCompleted: () =>
{ {
featuredImagesModel.nextPage() imagesModel.nextPage()
featuredVideosModel.nextPage() videosModel.nextPage()
newestPacksModel.nextPage() packsModel.nextPage()
} }
KeroLoadingAnimation KeroLoadingAnimation
@@ -405,26 +217,66 @@ Item {
id: loadingAnimation id: loadingAnimation
anchors.fill: parent anchors.fill: parent
OpacityAnimator on opacity {
duration: 150
}
visible: opacity > 0 visible: opacity > 0
opacity: 0 opacity: 1
} }
states: [ states: [
State { State {
name: "loading" name: "loading"
when: newestPacksModel.state == NewestPacksModel.Loading || when: packsModel.state === NewestPacksModel.Loading ||
featuredImagesModel.state == FeaturedImagesModel.Loading || imagesModel.state === FeaturedImagesModel.Loading ||
featuredVideosModel.state == FeaturedVideosModel.Loading; videosModel.state === FeaturedVideosModel.Loading;
PropertyChanges { PropertyChanges
{
target: loadingAnimation target: loadingAnimation
opacity: 1 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 model: searchModel
loading: model.state === ImageSearchModel.Loading loading: model.state === ImageSearchModel.Loading
delegate: Item delegate: ItemDelegate
{ {
id: resultDelegate
width: 256 width: 256
height: 245 height: 245
required property string author required property string author
required property string description required property string description
required property string uuid required property string uuid
required property string thumbnail required property string thumbnail
required property string authorId required property string authorId
required property int index
SearchResultItem SearchResultItem
{ {
@@ -45,6 +49,14 @@ Item
description: parent.description description: parent.description
thumbnail: parent.thumbnail thumbnail: parent.thumbnail
uuid: parent.uuid 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 property string query
readonly property bool searchable: paginator.searchable readonly property bool searchable: paginator.searchable
VideoSearchModel PackSearchModel
{ {
id: searchModel id: searchModel
query: rootItem.query query: rootItem.query
@@ -24,12 +24,16 @@ Item
id: paginator id: paginator
anchors.fill: parent anchors.fill: parent
model: searchModel model: searchModel
loading: model.state === VideoSearchModel.Loading loading: model.state === PackSearchModel.Loading
delegate: Item delegate: ItemDelegate
{ {
id: resultDelegate
width: 256 width: 256
height: 245 height: 245
required property string name
required property string author required property string author
required property string description required property string description
required property string uuid required property string uuid
@@ -43,6 +47,14 @@ Item
description: parent.description description: parent.description
thumbnail: parent.thumbnail thumbnail: parent.thumbnail
uuid: parent.uuid 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 model: searchModel
loading: model.state === VideoSearchModel.Loading loading: model.state === VideoSearchModel.Loading
delegate: Item delegate: ItemDelegate
{ {
id: resultDelegate
width: 256 width: 256
height: 245 height: 245
required property string author required property string author
required property string description required property string description
required property string uuid required property string uuid
required property string thumbnail required property string thumbnail
required property string authorId required property string authorId
required property int index
SearchResultItem SearchResultItem
{ {
@@ -45,6 +49,14 @@ Item
description: parent.description description: parent.description
thumbnail: parent.thumbnail thumbnail: parent.thumbnail
uuid: parent.uuid 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" "SearchResultList.qml"
QML_FILES PaginationBox.qml QML_FILES PaginationBox.qml
QML_FILES PaginatorGrid.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 int resultHeight: 245
property bool loading: false property bool loading: false
property alias currentItem: resultsView.currentItem
property alias currentIndex: resultsView.currentIndex
property var model property var model
property Component delegate property Component delegate
@@ -78,6 +81,22 @@ Item
Layout.maximumWidth: emptyWidth / 2 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 GridView
{ {
id: resultsView id: resultsView
@@ -86,10 +105,12 @@ Item
cellWidth: 256 + Constants.mediumMargin cellWidth: 256 + Constants.mediumMargin
cellHeight: 245 + Constants.mediumMargin cellHeight: 245 + Constants.mediumMargin
focus: true
model: rootItem.model model: rootItem.model
delegate: rootItem.delegate delegate: rootItem.delegate
highlight: Rectangle { color: palette.accent; radius: 5 }
highlightFollowsCurrentItem: true
focus: true
add: Transition add: Transition
{ {
@@ -116,6 +137,15 @@ Item
} }
} }
displaced: Transition
{
NumberAnimation
{
properties: "x,y"
duration: 250
}
}
populate: Transition populate: Transition
{ {
NumberAnimation NumberAnimation
@@ -146,6 +176,7 @@ Item
PaginationBox PaginationBox
{ {
id: buttonBoxLayout
height: 35 height: 35
anchors.left: parent.left anchors.left: parent.left
+2 -11
View File
@@ -119,7 +119,8 @@ Item {
} }
} }
MouseArea { MouseArea
{
property string lastState property string lastState
id: mouseArea id: mouseArea
@@ -155,16 +156,6 @@ Item {
} }
} }
onSelectedChanged: () => {
if(selected) {
searchResultItemRoot.triggered()
searchResultItemRoot.state = "selected"
}
else {
searchResultItemRoot.state = ""
}
}
states: [ states: [
State { State {
name: "hovered" name: "hovered"