/* * Copyright 2015 Luca Beltrame * * 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 . */ 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 } } } } }