General update
This commit is contained in:
@@ -18,6 +18,7 @@ qt6_add_qml_module(KomplexHubContent
|
||||
"pages/UserProfilePage.qml"
|
||||
"pages/WallpaperSettingsPage.qml"
|
||||
QML_FILES pages/VideoSearchPage.qml
|
||||
QML_FILES views/ImageView.qml
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -317,21 +317,19 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
KeroBuildingAnimation {
|
||||
KeroBuildingAnimation
|
||||
{
|
||||
id: buildingOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
}
|
||||
|
||||
KeroLoadingAnimation {
|
||||
KeroLoadingAnimation
|
||||
{
|
||||
id: loadingAnimation
|
||||
anchors.fill: parent
|
||||
|
||||
// OpacityAnimator on opacity {
|
||||
// duration: 150
|
||||
// }
|
||||
|
||||
visible: opacity > 0
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Effects
|
||||
@@ -20,18 +20,54 @@ Item {
|
||||
{
|
||||
id: newestPacksModel
|
||||
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
|
||||
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
|
||||
resultsPerPage: homePageRoot.resultsPerRow
|
||||
|
||||
onStateChanged: () =>
|
||||
{
|
||||
if(state == FeaturedVideosModel.Loading)
|
||||
{
|
||||
console.log("Featured Videos loading")
|
||||
}
|
||||
else if(state == FeaturedVideosModel.Idle)
|
||||
{
|
||||
console.log("Featured Videos finished")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle
|
||||
@@ -210,10 +246,11 @@ Item {
|
||||
{
|
||||
anchors.fill: parent
|
||||
title: parent.author
|
||||
author: qsTr("Pexels Images")
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
|
||||
pexels: true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,10 +349,9 @@ Item {
|
||||
{
|
||||
anchors.fill: parent
|
||||
title: parent.author
|
||||
author: parent.author
|
||||
description: "Video provided by Pexels"
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
pexels: true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,6 +393,13 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: () =>
|
||||
{
|
||||
featuredImagesModel.nextPage()
|
||||
featuredVideosModel.nextPage()
|
||||
newestPacksModel.nextPage()
|
||||
}
|
||||
|
||||
KeroLoadingAnimation
|
||||
{
|
||||
id: loadingAnimation
|
||||
|
||||
@@ -9,217 +9,43 @@ import KomplexHubPlugin
|
||||
|
||||
Item
|
||||
{
|
||||
property string query
|
||||
readonly property bool searchable: true
|
||||
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
|
||||
id: rootItem
|
||||
|
||||
id: imageSearchPageRoot
|
||||
property string query
|
||||
readonly property bool searchable: paginator.searchable
|
||||
|
||||
ImageSearchModel
|
||||
{
|
||||
id: searchModel
|
||||
query: imageSearchPageRoot.query
|
||||
resultsPerPage: imageSearchPageRoot.resultsPerPage
|
||||
query: rootItem.query
|
||||
resultsPerPage: paginator.resultsPerPage
|
||||
}
|
||||
|
||||
Rectangle
|
||||
PaginatorGrid
|
||||
{
|
||||
id: paginator
|
||||
anchors.fill: parent
|
||||
color: palette.base
|
||||
model: searchModel
|
||||
loading: model.state === ImageSearchModel.Loading
|
||||
|
||||
Rectangle
|
||||
delegate: Item
|
||||
{
|
||||
id: resultsContainer
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: buttonBoxLayout.top
|
||||
width: 256
|
||||
height: 245
|
||||
required property string author
|
||||
required property string description
|
||||
required property string uuid
|
||||
required property string thumbnail
|
||||
required property string authorId
|
||||
|
||||
color: "transparent"
|
||||
|
||||
ScrollView
|
||||
SearchResultItem
|
||||
{
|
||||
id: resultsView
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Constants.largeMargin
|
||||
|
||||
Item
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: emptyWidth / 2
|
||||
Layout.maximumWidth: emptyWidth / 2
|
||||
}
|
||||
|
||||
GridLayout
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
columns: imageSearchPageRoot.resultsPerRow
|
||||
columnSpacing: Constants.mediumMargin
|
||||
rowSpacing: Constants.mediumMargin
|
||||
|
||||
Repeater
|
||||
{
|
||||
model: searchModel
|
||||
|
||||
delegate: Item
|
||||
{
|
||||
width: 256
|
||||
height: 245
|
||||
required property string author
|
||||
required property string description
|
||||
required property string uuid
|
||||
required property string thumbnail
|
||||
required property string authorId
|
||||
|
||||
SearchResultItem
|
||||
{
|
||||
anchors.fill: parent
|
||||
title: parent.author
|
||||
author: qsTr("Pexels Images")
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout
|
||||
{
|
||||
id: buttonBoxLayout
|
||||
height: 35
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: Constants.largeMargin
|
||||
|
||||
SquareButton
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 128
|
||||
|
||||
icon.source: "qrc:/images/icons/icons8-back.svg"
|
||||
icon.height: 16
|
||||
icon.width: 16
|
||||
text: qsTr("Previous")
|
||||
enabled: searchModel.hasPreviousPage
|
||||
|
||||
onTriggered: () => searchModel.previousPage()
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
SquareButton
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 128
|
||||
|
||||
icon.source: "qrc:/images/icons/icons8-next.svg"
|
||||
icon.height: 16
|
||||
icon.width: 16
|
||||
text: qsTr("Next")
|
||||
enabled: searchModel.hasNextPage
|
||||
|
||||
onTriggered: () => searchModel.nextPage()
|
||||
title: parent.author
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeroErrorAvatar
|
||||
{
|
||||
id: errorOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
KeroNoResultsAvatar
|
||||
{
|
||||
id: noResultsOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
KeroLoadingAnimation
|
||||
{
|
||||
id: loadingOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
states: [
|
||||
State
|
||||
{
|
||||
name: "loading"
|
||||
when: searchModel.state == ImageSearchModel.Loading
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: loadingOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges
|
||||
{
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
}
|
||||
},
|
||||
State
|
||||
{
|
||||
name: "empty"
|
||||
when: searchModel.totalResults === 0
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: noResultsOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges
|
||||
{
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
}
|
||||
PropertyChanges
|
||||
{
|
||||
target: buttonBoxLayout
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
State
|
||||
{
|
||||
name: "error"
|
||||
when: searchModel.state == ImageSearchModel.Error
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: errorOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges
|
||||
{
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,76 +3,47 @@ import QtQuick.Controls
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
|
||||
Item {
|
||||
id: imageSearchPageRoot
|
||||
Item
|
||||
{
|
||||
id: rootItem
|
||||
|
||||
SearchResultList {
|
||||
id: searchResultList
|
||||
anchors.fill: parent
|
||||
color: palette.base
|
||||
property string query
|
||||
readonly property bool searchable: paginator.searchable
|
||||
|
||||
VideoSearchModel
|
||||
{
|
||||
id: searchModel
|
||||
query: rootItem.query
|
||||
resultsPerPage: paginator.resultsPerPage
|
||||
}
|
||||
|
||||
KeroErrorAvatar {
|
||||
id: errorOverlay
|
||||
|
||||
PaginatorGrid
|
||||
{
|
||||
id: paginator
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
model: searchModel
|
||||
loading: model.state === VideoSearchModel.Loading
|
||||
|
||||
KeroNoResultsAvatar {
|
||||
id: noResultsOverlay
|
||||
delegate: Item
|
||||
{
|
||||
width: 256
|
||||
height: 245
|
||||
required property string author
|
||||
required property string description
|
||||
required property string uuid
|
||||
required property string thumbnail
|
||||
required property string authorId
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
KeroLoadingAnimation {
|
||||
id: loadingOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "loading"
|
||||
when: searchResultList.state === "loading"
|
||||
|
||||
PropertyChanges {
|
||||
target: loadingOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "empty"
|
||||
when: searchResultList.state === "empty"
|
||||
|
||||
PropertyChanges {
|
||||
target: noResultsOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "error"
|
||||
when: searchResultList.state === "error"
|
||||
|
||||
PropertyChanges {
|
||||
target: errorOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
SearchResultItem
|
||||
{
|
||||
anchors.fill: parent
|
||||
title: parent.author
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,217 +9,43 @@ import KomplexHubPlugin
|
||||
|
||||
Item
|
||||
{
|
||||
property string query
|
||||
readonly property bool searchable: true
|
||||
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
|
||||
id: rootItem
|
||||
|
||||
id: videoSearchPageRoot
|
||||
property string query
|
||||
readonly property bool searchable: paginator.searchable
|
||||
|
||||
VideoSearchModel
|
||||
{
|
||||
id: searchModel
|
||||
query: videoSearchPageRoot.query
|
||||
resultsPerPage: videoSearchPageRoot.resultsPerPage
|
||||
query: rootItem.query
|
||||
resultsPerPage: paginator.resultsPerPage
|
||||
}
|
||||
|
||||
Rectangle
|
||||
PaginatorGrid
|
||||
{
|
||||
id: paginator
|
||||
anchors.fill: parent
|
||||
color: palette.base
|
||||
model: searchModel
|
||||
loading: model.state === VideoSearchModel.Loading
|
||||
|
||||
Rectangle
|
||||
delegate: Item
|
||||
{
|
||||
id: resultsContainer
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: buttonBoxLayout.top
|
||||
width: 256
|
||||
height: 245
|
||||
required property string author
|
||||
required property string description
|
||||
required property string uuid
|
||||
required property string thumbnail
|
||||
required property string authorId
|
||||
|
||||
color: "transparent"
|
||||
|
||||
ScrollView
|
||||
SearchResultItem
|
||||
{
|
||||
id: resultsView
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Constants.largeMargin
|
||||
|
||||
Item
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: emptyWidth / 2
|
||||
Layout.maximumWidth: emptyWidth / 2
|
||||
}
|
||||
|
||||
GridLayout
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
columns: videoSearchPageRoot.resultsPerRow
|
||||
columnSpacing: Constants.mediumMargin
|
||||
rowSpacing: Constants.mediumMargin
|
||||
|
||||
Repeater
|
||||
{
|
||||
model: searchModel
|
||||
|
||||
delegate: Item {
|
||||
width: resultWidth
|
||||
height: resultHeight
|
||||
|
||||
required property string uuid
|
||||
required property string author
|
||||
required property string authorId
|
||||
required property string authorUrl
|
||||
required property string thumbnail
|
||||
|
||||
SearchResultItem
|
||||
{
|
||||
anchors.fill: parent
|
||||
title: parent.author
|
||||
author: parent.author
|
||||
description: "Video provided by Pexels"
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout
|
||||
{
|
||||
id: buttonBoxLayout
|
||||
height: 35
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: Constants.largeMargin
|
||||
|
||||
SquareButton
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 128
|
||||
|
||||
icon.source: "qrc:/images/icons/icons8-back.svg"
|
||||
icon.height: 16
|
||||
icon.width: 16
|
||||
text: qsTr("Previous")
|
||||
enabled: searchModel.hasPreviousPage
|
||||
|
||||
onTriggered: () => searchModel.previousPage()
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
SquareButton
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 128
|
||||
|
||||
icon.source: "qrc:/images/icons/icons8-next.svg"
|
||||
icon.height: 16
|
||||
icon.width: 16
|
||||
text: qsTr("Next")
|
||||
enabled: searchModel.hasNextPage
|
||||
|
||||
onTriggered: () => searchModel.nextPage()
|
||||
title: parent.author
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeroErrorAvatar
|
||||
{
|
||||
id: errorOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
KeroNoResultsAvatar
|
||||
{
|
||||
id: noResultsOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
KeroLoadingAnimation
|
||||
{
|
||||
id: loadingOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
states: [
|
||||
State
|
||||
{
|
||||
name: "loading"
|
||||
when: searchModel.state == VideoSearchModel.Loading
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: loadingOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges
|
||||
{
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
}
|
||||
},
|
||||
State
|
||||
{
|
||||
name: "empty"
|
||||
when: searchModel.totalResults === 0
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: noResultsOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges
|
||||
{
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
}
|
||||
PropertyChanges
|
||||
{
|
||||
target: buttonBoxLayout
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
State
|
||||
{
|
||||
name: "error"
|
||||
when: searchModel.state == VideoSearchModel.Error
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: errorOverlay
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges
|
||||
{
|
||||
target: resultsView
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Effects
|
||||
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
|
||||
Item
|
||||
{
|
||||
property string uuid
|
||||
property string author
|
||||
property string authorUrl
|
||||
property string description
|
||||
property string thumbnail
|
||||
property string portrait
|
||||
property string landscape
|
||||
property string small
|
||||
property string original
|
||||
property string medium
|
||||
property string large
|
||||
property string extraLarge
|
||||
property string portraitSize
|
||||
property string landscapeSize
|
||||
property string smallSize
|
||||
property string originalSize
|
||||
property string mediumSize
|
||||
property string largeSize
|
||||
property string extraLargeSize
|
||||
|
||||
property int imageHeight
|
||||
property int imageWidth
|
||||
|
||||
id: rootItem
|
||||
|
||||
Rectangle
|
||||
{
|
||||
anchors.fill: parent
|
||||
color: palette.base
|
||||
|
||||
ColumnLayout
|
||||
{
|
||||
anchors.fill: parent
|
||||
anchors.margins: Constants.largeMargin
|
||||
spacing: Constants.largeMargin
|
||||
|
||||
RowLayout
|
||||
{
|
||||
Layout.fillWidth: true
|
||||
|
||||
/** Spacer **/
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
Image
|
||||
{
|
||||
width: imageWidth
|
||||
height: imageHeight
|
||||
transform: Image.PreserveAspectFit
|
||||
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
||||
}
|
||||
|
||||
/** Spacer **/
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
|
||||
Text
|
||||
{
|
||||
id: titleText
|
||||
text: rootItem.author
|
||||
|
||||
font.bold: true
|
||||
font.pixelSize: Constants.h3Font.pixelSize
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text
|
||||
{
|
||||
id: descriptionText
|
||||
text: rootItem.description
|
||||
|
||||
font.pointSize: Constants.h4Font.pixelSize
|
||||
}
|
||||
|
||||
Image
|
||||
{
|
||||
width: 64
|
||||
height: 64
|
||||
transform: Image.PreserveAspectFit
|
||||
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
||||
|
||||
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user