danbooru-client/src/qml/danbooruimageview.qml

413 lines
12 KiB
QML

/*
* Copyright 2015 Luca Beltrame <lbeltrame@kde.org>
*
* This file is part of Danbooru Client.
*
* Danbooru Client is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Danbooru Client is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Danbooru Client. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
import QtQuick.Controls.Styles 1.3
import QtQuick.Layouts 1.1
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kcoreaddons 1.0 as KCoreAddons
import org.kde.kio 1.0
import DanbooruClient 1.0
Rectangle {
id: rootObj
objectName: "rootObj"
width: 500
height: 500
property bool poolMode: false;
signal downloadFinished()
signal downloadRequested(url url, var tags)
signal downloadStarted()
signal fileInfo(url name, var tags)
KRun {
id: runner
}
onDownloadFinished: {
grid.opacity = 1
runningIndicator.running = false
if (danbooruModel.rowCount() == 0) {
warnLabel.visible = true
}
}
onDownloadStarted: {
warnLabel.visible = false
grid.opacity = 0.5
runningIndicator.running = true
}
BusyIndicator {
id: runningIndicator
z: 1
width: grid.cellWidth / 2
height: grid.cellHeight / 2
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
running: false
}
Label {
id: warnLabel
z: 1
width: grid.cellWidth / 2
height: grid.cellHeight / 2
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
visible: false
text: "No posts found."
}
Component {
id: highlight
Rectangle {
width: grid.cellWidth; height: grid.cellHeight
color: "lightsteelblue"; radius: 5
}
}
Component {
id: viewDelegate
Item {
width: grid.cellWidth
height: grid.cellHeight
Column {
id: postElement
anchors.fill: parent
QPixmapItem {
id: pixItem
pixmap: thumbPix
anchors.horizontalCenter: parent.horizontalCenter
smooth: true
fillMode: QPixmapItem.PreserveAspectFit
height: grid.cellHeight * 0.75
width: grid.cellWidth * 0.9
MouseArea {
id: mouseArea
anchors.fill: parent
height: parent.height
width: parent.width
//
hoverEnabled: true
onClicked: {
grid.currentIndex = index
rootObj.fileInfo(fileUrl, tags)
}
onDoubleClicked: {
imageOverlay.imageDoubleClicked(sampleUrl, tags)
}
onEntered: {
viewButton.opacity = 1
downloadButton.opacity = 1
}
onExited: {
viewButton.opacity = 0
downloadButton.opacity = 0
}
Button {
id: viewButton
iconName: "view-preview"
visible: opacity > 0
opacity: 0
tooltip: i18n("View in image viewer")
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: (pixItem.height - pixItem.paintedHeight) / 2
anchors.leftMargin: (pixItem.width - pixItem.paintedWidth) / 2
height: pixItem.height * 0.15
width: pixItem.height * 0.15
z: 1
onClicked: {
runner.openUrl(fileUrl)
}
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
}
Button {
id: downloadButton
iconName: "download"
visible: opacity > 0
opacity: 0
tooltip: i18n("Download image")
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.bottomMargin: (pixItem.height - pixItem.paintedHeight) / 2
anchors.leftMargin: (pixItem.width - pixItem.paintedWidth) / 2
height: pixItem.height * 0.15
width: pixItem.height * 0.15
z: 1
onClicked: {
rootObj.downloadRequested(fileUrl, tags)
}
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
}
}
}
Text {
id: sizeText
text: i18n("File size: %1", KCoreAddons.Format.formatByteSize(fileSize))
}
Text {
id: resolutionText
text: i18n("Resolution: %1 x %2", resolution.width, resolution.height)
}
Text {
id: ratingText
text: {
if (rating == DanbooruPost.Safe) {
return i18n("Rating: %1", "Safe")
} else if (rating == DanbooruPost.Questionable) {
return i18n("Rating: %1", "Questionable")
} else if (rating == DanbooruPost.Explicit) {
return i18n("Rating: %1", "Explicit")
}
}
}
}
}
}
ScrollView {
id: scrollView
anchors.fill: parent
GridView {
id: grid
cellWidth: 230
cellHeight: 230
flow: GridView.FlowLeftToRight
anchors.fill: parent
clip: true
highlight: highlight
highlightFollowsCurrentItem: true
snapMode: GridView.SnapToRow
model: danbooruModel
delegate: viewDelegate
focus: true
Component.onCompleted: { currentIndex = -1; forceActiveFocus()}
onAtYEndChanged: {
// Download only if at end, if there are posts, if
// we are not displaying a pool, if the option is set
// and if we're not already downloading something
if (grid.atYEnd && danbooruModel.rowCount() > 0 &&
!rootObj.poolMode &&
infiniteScroll &&
!runningIndicator.running) {
rootObj.downloadStarted()
danbooruService.nextPostPage();
}
}
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 250}
}
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
}
}
Image {
// This handles displaying the medium-resolution image as preview
signal imageDoubleClicked(url url, var tags)
id: imageOverlay
smooth: true
fillMode: QPixmapItem.PreserveAspectFit
height: rootObj.height * 0.9
width: rootObj.width * 0.9
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
visible: width > 0
z: 1
Button {
id: closeButton
anchors.top: parent.top
anchors.right: imageOverlay.right
height: parent.paintedHeight * 0.05
width: parent.paintedHeight * 0.05
anchors.topMargin: (parent.height - parent.paintedHeight) / 2
anchors.leftMargin: (parent.width - parent.paintedWidth) / 2
iconName: "window-close"
visible: false
z: 2
tooltip: i18n("Click to close image preview")
onClicked: {
closeButton.visible = false
// shrinkAnimation.start()
imageOverlay.visible = false
overlayBox.visible = false
overlayText.visible = false
}
}
Rectangle {
id: overlayBox
color:"black"
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.bottomMargin: (parent.height - parent.paintedHeight) / 2
anchors.leftMargin: (parent.width - parent.paintedWidth) / 2
width: imageOverlay.paintedWidth
height: imageOverlay.paintedHeight * 0.05
opacity: 0.8
visible: false
Text {
id: overlayText
anchors.fill: parent
text: "" // FIXME
color: "white"
visible: false
}
}
Keys.onEscapePressed: {
closeButton.visible = false
imageOverlay.visible = false
}
onImageDoubleClicked: {
imageOverlay.visible = true
imageOverlay.source = url
closeButton.visible = true
if (tags.length < 10) {
overlayText.text = i18n("Tags: %1", tags.toString())
} else {
overlayText.text = i18n("Tags: %1", tags.slice(0, 10).join(", "))
}
}
onStatusChanged: {
if (imageOverlay.status == Image.Loading) {
rootObj.downloadStarted()
}
if (imageOverlay.status == Image.Ready) {
rootObj.downloadFinished()
// imageOverlay.visible = true
enlargeAnimation.start()
}
}
PropertyAnimation {
id: enlargeAnimation
target: imageOverlay
properties: "width"
from: 0
to: imageOverlay.paintedWidth
duration: 250
onRunningChanged: {
if (!enlargeAnimation.running) {
overlayBox.visible = true
overlayText.visible = true
if (imageOverlay.paintedWidth / imageOverlay.paintedHeight <= 1.6) {
overlayBox.height = imageOverlay.paintedHeight * 0.03
} else {
overlayBox.height = imageOverlay.paintedHeight * 0.05
}
}
}
}
PropertyAnimation {
id: shrinkAnimation
target: imageOverlay
properties: "width"
from: imageOverlay.paintedWidth
to: 0
duration: 250
onRunningChanged: {
if (!shrinkAnimation.running) {
imageOverlay.visible = false
}
}
}
}
}