1/*************************************************************************** 2** 3** Copyright (C) 2017 The Qt Company Ltd. 4** Contact: https://www.qt.io/licensing/ 5** 6** This file is part of the examples of the QtBluetooth module of the Qt Toolkit. 7** 8** $QT_BEGIN_LICENSE:BSD$ 9** Commercial License Usage 10** Licensees holding valid commercial Qt licenses may use this file in 11** accordance with the commercial license agreement provided with the 12** Software or, alternatively, in accordance with the terms contained in 13** a written agreement between you and The Qt Company. For licensing terms 14** and conditions see https://www.qt.io/terms-conditions. For further 15** information use the contact form at https://www.qt.io/contact-us. 16** 17** BSD License Usage 18** Alternatively, you may use this file under the terms of the BSD license 19** as follows: 20** 21** "Redistribution and use in source and binary forms, with or without 22** modification, are permitted provided that the following conditions are 23** met: 24** * Redistributions of source code must retain the above copyright 25** notice, this list of conditions and the following disclaimer. 26** * Redistributions in binary form must reproduce the above copyright 27** notice, this list of conditions and the following disclaimer in 28** the documentation and/or other materials provided with the 29** distribution. 30** * Neither the name of The Qt Company Ltd nor the names of its 31** contributors may be used to endorse or promote products derived 32** from this software without specific prior written permission. 33** 34** 35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 46** 47** $QT_END_LICENSE$ 48** 49****************************************************************************/ 50 51import QtQuick 2.5 52 53GamePage { 54 id: measurePage 55 56 errorMessage: deviceHandler.error 57 infoMessage: deviceHandler.info 58 59 property real __timeCounter: 0; 60 property real __maxTimeCount: 60 61 property string relaxText: qsTr("Relax!\nWhen you are ready, press Start. You have %1s time to increase heartrate so much as possible.\nGood luck!").arg(__maxTimeCount) 62 63 function close() 64 { 65 deviceHandler.stopMeasurement(); 66 deviceHandler.disconnectService(); 67 app.prevPage(); 68 } 69 70 function start() 71 { 72 if (!deviceHandler.measuring) { 73 __timeCounter = 0; 74 deviceHandler.startMeasurement() 75 } 76 } 77 78 function stop() 79 { 80 if (deviceHandler.measuring) { 81 deviceHandler.stopMeasurement() 82 } 83 84 app.showPage("Stats.qml") 85 } 86 87 Timer { 88 id: measureTimer 89 interval: 1000 90 running: deviceHandler.measuring 91 repeat: true 92 onTriggered: { 93 __timeCounter++; 94 if (__timeCounter >= __maxTimeCount) 95 measurePage.stop() 96 } 97 } 98 99 Column { 100 anchors.centerIn: parent 101 spacing: GameSettings.fieldHeight * 0.5 102 103 Rectangle { 104 id: circle 105 anchors.horizontalCenter: parent.horizontalCenter 106 width: Math.min(measurePage.width, measurePage.height-GameSettings.fieldHeight*4) - 2*GameSettings.fieldMargin 107 height: width 108 radius: width*0.5 109 color: GameSettings.viewColor 110 111 Text { 112 id: hintText 113 anchors.centerIn: parent 114 anchors.verticalCenterOffset: -parent.height*0.1 115 horizontalAlignment: Text.AlignHCenter 116 verticalAlignment: Text.AlignVCenter 117 width: parent.width * 0.8 118 height: parent.height * 0.6 119 wrapMode: Text.WordWrap 120 text: measurePage.relaxText 121 visible: !deviceHandler.measuring 122 color: GameSettings.textColor 123 fontSizeMode: Text.Fit 124 minimumPixelSize: 10 125 font.pixelSize: GameSettings.mediumFontSize 126 } 127 128 Text { 129 id: text 130 anchors.centerIn: parent 131 anchors.verticalCenterOffset: -parent.height*0.15 132 font.pixelSize: parent.width * 0.45 133 text: deviceHandler.hr 134 visible: deviceHandler.measuring 135 color: GameSettings.textColor 136 } 137 138 Item { 139 id: minMaxContainer 140 anchors.horizontalCenter: parent.horizontalCenter 141 width: parent.width*0.7 142 height: parent.height * 0.15 143 anchors.bottom: parent.bottom 144 anchors.bottomMargin: parent.height*0.16 145 visible: deviceHandler.measuring 146 147 Text { 148 anchors.left: parent.left 149 anchors.verticalCenter: parent.verticalCenter 150 text: deviceHandler.minHR 151 color: GameSettings.textColor 152 font.pixelSize: GameSettings.hugeFontSize 153 154 Text { 155 anchors.left: parent.left 156 anchors.bottom: parent.top 157 font.pixelSize: parent.font.pixelSize*0.8 158 color: parent.color 159 text: "MIN" 160 } 161 } 162 163 Text { 164 anchors.right: parent.right 165 anchors.verticalCenter: parent.verticalCenter 166 text: deviceHandler.maxHR 167 color: GameSettings.textColor 168 font.pixelSize: GameSettings.hugeFontSize 169 170 Text { 171 anchors.right: parent.right 172 anchors.bottom: parent.top 173 font.pixelSize: parent.font.pixelSize*0.8 174 color: parent.color 175 text: "MAX" 176 } 177 } 178 } 179 180 Image { 181 id: heart 182 anchors.horizontalCenter: minMaxContainer.horizontalCenter 183 anchors.verticalCenter: minMaxContainer.bottom 184 width: parent.width * 0.2 185 height: width 186 source: "images/heart.png" 187 smooth: true 188 antialiasing: true 189 190 SequentialAnimation{ 191 id: heartAnim 192 running: deviceHandler.alive 193 loops: Animation.Infinite 194 alwaysRunToEnd: true 195 PropertyAnimation { target: heart; property: "scale"; to: 1.2; duration: 500; easing.type: Easing.InQuad } 196 PropertyAnimation { target: heart; property: "scale"; to: 1.0; duration: 500; easing.type: Easing.OutQuad } 197 } 198 } 199 } 200 201 Rectangle { 202 id: timeSlider 203 color: GameSettings.viewColor 204 anchors.horizontalCenter: parent.horizontalCenter 205 width: circle.width 206 height: GameSettings.fieldHeight 207 radius: GameSettings.buttonRadius 208 209 Rectangle { 210 height: parent.height 211 radius: parent.radius 212 color: GameSettings.sliderColor 213 width: Math.min(1.0,__timeCounter / __maxTimeCount) * parent.width 214 } 215 216 Text { 217 anchors.centerIn: parent 218 color: "gray" 219 text: (__maxTimeCount - __timeCounter).toFixed(0) + " s" 220 font.pixelSize: GameSettings.bigFontSize 221 } 222 } 223 } 224 225 GameButton { 226 id: startButton 227 anchors.horizontalCenter: parent.horizontalCenter 228 anchors.bottom: parent.bottom 229 anchors.bottomMargin: GameSettings.fieldMargin 230 width: circle.width 231 height: GameSettings.fieldHeight 232 enabled: !deviceHandler.measuring 233 radius: GameSettings.buttonRadius 234 235 onClicked: start() 236 237 Text { 238 anchors.centerIn: parent 239 font.pixelSize: GameSettings.tinyFontSize 240 text: qsTr("START") 241 color: startButton.enabled ? GameSettings.textColor : GameSettings.disabledTextColor 242 } 243 } 244} 245