/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import QtQuick 2.0 import QtWebKit 3.0 import QtQuick.XmlListModel 2.0 import "qrc:/shared" as Shared Rectangle { id: container width: 1024 height: 768 property string initialUrl: "https://www.flickr.com/explore/interesting/7days/?" Rectangle { id: thumbnailContainer color: "black" anchors.bottom: container.bottom width: container.width height: 100 gradient: Gradient { GradientStop { position: 0.0; color: "gray" } GradientStop { position: 0.33; color: "black" } } Text { id: info color: "white" anchors.horizontalCenter: thumbnailContainer.horizontalCenter text: webView.title } ListView { id: listView orientation: "Horizontal" anchors { topMargin: 20 fill: parent } model: model delegate: Component { Image { source: thumbnail MouseArea { anchors.fill: parent onClicked: webView.url = link + "/lightbox" } } } focus: true spacing: 10 leftMargin: 10 rightMargin: 35 visible: model.status == XmlListModel.Ready } Rectangle { id: updateInfo property real distance: -(listView.contentWidth - listView.contentX - thumbnailContainer.width) property real threshold: Math.max(2.5 * listView.height, thumbnailContainer.width - listView.contentWidth + 2 * listView.height) property bool triggerUpdate: false opacity: 0.8 x: thumbnailContainer.width - distance width: listView.height color: "transparent" anchors { top: thumbnailContainer.top bottom: thumbnailContainer.bottom } Timer { interval: 200; running: updateInfo.state == "update"; repeat: false onTriggered: { model.reload(); updateInfo.triggerUpdate = false; } } states: [ State { name: "pull" when: updateInfo.distance <= updateInfo.threshold && listView.dragging PropertyChanges { target: message; text: "Pull\nto\nupdate" } }, State { name: "release" when: updateInfo.distance > updateInfo.threshold && listView.dragging PropertyChanges { target: message; text: "Release\nto\nupdate" } }, State { name: "update" when: updateInfo.triggerUpdate && listView.atXEnd && !listView.dragging PropertyChanges { target: message; text: "Updating" } } ] onStateChanged: { if (state == "release") triggerUpdate = true if (state == "pull") triggerUpdate = false } Rectangle { id: icon width: 30 color: "transparent" anchors { topMargin: 10 top: parent.top bottom: parent.bottom left: parent.left } Image { source: "qrc:/shared/images/arrow.png" width: 30 height: 30 visible: updateInfo.state != "update" rotation: updateInfo.state == "release" ? 180 : 0 Behavior on rotation { NumberAnimation { duration: 100} } SequentialAnimation on x { running: listView.atXEnd && !listView.dragging loops: Animation.Infinite PropertyAnimation { to: 5; duration: 250 } PropertyAnimation { to: 0; duration: 250 } } anchors { verticalCenter: parent.verticalCenter } } } Text { id: message horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.family: "Monospace" color: "white" anchors { top: parent.top bottom: parent.bottom right: parent.right left: icon.right } } } Shared.LoadIndicator { anchors.fill: parent color: "black" running: !listView.visible && model.status != XmlListModel.Error } } Rectangle { id: content width: container.width color: "black" anchors { top: container.top bottom: thumbnailContainer.top } WebView { id: webView anchors.fill: parent opacity: 0 url: container.initialUrl Behavior on opacity { NumberAnimation { duration: 200 } } onLoadingChanged: { switch (loadRequest.status) { case WebView.LoadSucceededStatus: opacity = 1 break default: opacity = 0 break } } onNavigationRequested: { switch (request.navigationType) { case WebView.LinkClickedNavigation: case WebView.FormSubmittedNavigation: case WebView.BackForwardNavigation: case WebView.ReloadNavigation: case WebView.FormResubmittedNavigation: case WebView.OtherNavigation: if (/^(https|http):\/\/(www\.flickr\.com|login\.yahoo\.com)/.test(request.url)) { request.action = WebView.AcceptRequest return } } // Disallow navigating outside of flickr.com request.action = WebView.IgnoreRequest } } Shared.LoadIndicator { anchors.fill: parent imageSource: "qrc:/images/flickr.png" running: webView.loading } } XmlListModel { id: model namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";" source: "http://api.flickr.com/services/feeds/photos_public.gne?format=rss2" query: "/rss/channel/item" XmlRole { name: "thumbnail"; query: "media:thumbnail/@url/string()" } XmlRole { name: "thumbnailHeight"; query: "media:thumbnail/@height/number()" } XmlRole { name: "content"; query: "media:content/@url/string()" } XmlRole { name: "link"; query: "link/string()" } } }