diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-05-08 08:03:13 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-05-19 10:27:18 +0000 |
commit | 271efe6dc3dce20df7222d2be3b4f36fd88a835d (patch) | |
tree | 75eb4e951e81bfe546e18cb760038a1572076715 | |
parent | 7e7d452edde2aba1df4f481bc8ab8df9f219a307 (diff) |
Bluetooth/Heartrate game example: Update QML files
Adapt to recent changes in the example.
Done-with: Ivan Solovev <ivan.solovev@qt.io>
Task-number: PYSIDE-2206
Task-number: QTBUG-111972
Change-Id: I6ca56d05615cfc8ca7327e3af4eee89d591f5dd9
Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
(cherry picked from commit 7256d15ee0514629bde0b60843628288a4ba6a50)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
15 files changed, 251 insertions, 207 deletions
diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/App.qml b/examples/bluetooth/heartrate_game/HeartRateGame/App.qml index 1eb532021..db6aa7145 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/App.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/App.qml @@ -2,82 +2,98 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick +import QtQuick.Layouts +import HeartRateGame Item { id: app - anchors.fill: parent - opacity: 0.0 - Behavior on opacity { NumberAnimation { duration: 500 } } - - property var lastPages: [] - property int __currentIndex: 0 + required property ConnectionHandler connectionHandler + required property DeviceFinder deviceFinder + required property DeviceHandler deviceHandler - function init() - { - opacity = 1.0 - showPage("Connect.qml") - } + anchors.fill: parent + opacity: 0.0 - function prevPage() - { - lastPages.pop() - pageLoader.setSource(lastPages[lastPages.length-1]) - __currentIndex = lastPages.length-1; + Behavior on opacity { + NumberAnimation { + duration: 500 + } } - function showPage(name) - { - lastPages.push(name) - pageLoader.setSource(name) - __currentIndex = lastPages.length-1; - } + property int __currentIndex: 0 TitleBar { id: titleBar - currentIndex: __currentIndex + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + currentIndex: app.__currentIndex onTitleClicked: (index) => { - if (index < __currentIndex) - pageLoader.item.close() + if (index < app.__currentIndex) + app.__currentIndex = index } } - Loader { - id: pageLoader + StackLayout { + id: pageStack anchors.left: parent.left anchors.right: parent.right anchors.top: titleBar.bottom anchors.bottom: parent.bottom + currentIndex: app.__currentIndex - onStatusChanged: { - if (status === Loader.Ready) - { - pageLoader.item.init(); - pageLoader.item.forceActiveFocus() - } + Connect { + connectionHandler: app.connectionHandler + deviceFinder: app.deviceFinder + deviceHandler: app.deviceHandler + + onShowMeasurePage: app.__currentIndex = 1 + } + Measure { + id: measurePage + deviceHandler: app.deviceHandler + + onShowStatsPage: app.__currentIndex = 2 + } + Stats { + deviceHandler: app.deviceHandler + } + + onCurrentIndexChanged: { + if (currentIndex === 0) + measurePage.close() } } + BluetoothAlarmDialog { + id: btAlarmDialog + anchors.fill: parent + visible: !app.connectionHandler.alive || permissionError + permissionError: !app.connectionHandler.hasPermission + } + Keys.onReleased: (event) => { switch (event.key) { case Qt.Key_Escape: - case Qt.Key_Back: { - if (__currentIndex > 0) { - pageLoader.item.close() + case Qt.Key_Back: + { + if (app.__currentIndex > 0) { + app.__currentIndex = app.__currentIndex - 1 event.accepted = true } else { Qt.quit() } - break; + break } - default: break; + default: + break } } - BluetoothAlarmDialog { - id: btAlarmDialog - anchors.fill: parent - visible: !connectionHandler.alive + Component.onCompleted: { + forceActiveFocus() + app.opacity = 1.0 } } diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/BluetoothAlarmDialog.qml b/examples/bluetooth/heartrate_game/HeartRateGame/BluetoothAlarmDialog.qml index 0be61e4f8..3687b1331 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/BluetoothAlarmDialog.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/BluetoothAlarmDialog.qml @@ -5,6 +5,9 @@ import QtQuick Item { id: root + + property bool permissionError: false + anchors.fill: parent Rectangle { @@ -51,7 +54,9 @@ Item { wrapMode: Text.WordWrap font.pixelSize: GameSettings.mediumFontSize color: GameSettings.textColor - text: qsTr("This application cannot be used without Bluetooth. Please switch Bluetooth ON to continue.") + text: root.permissionError + ? qsTr("Bluetooth permissions are not granted. Please grant the permissions in the system settings.") + : qsTr("This application cannot be used without Bluetooth. Please switch Bluetooth ON to continue.") } GameButton { diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/Connect.qml b/examples/bluetooth/heartrate_game/HeartRateGame/Connect.qml index abcfb4ce9..ca8ef2923 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/Connect.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/Connect.qml @@ -1,10 +1,18 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +pragma ComponentBehavior: Bound import QtQuick -import "." +import HeartRateGame GamePage { + id: connectPage + + required property ConnectionHandler connectionHandler + required property DeviceFinder deviceFinder + required property DeviceHandler deviceHandler + + signal showMeasurePage errorMessage: deviceFinder.error infoMessage: deviceFinder.info @@ -12,17 +20,16 @@ GamePage { Rectangle { id: viewContainer anchors.top: parent.top - anchors.bottom: - // only BlueZ platform has address type selection - connectionHandler.requiresAddressType ? addressTypeButton.top : searchButton.top - anchors.topMargin: GameSettings.fieldMargin + messageHeight + // only BlueZ platform has address type selection + anchors.bottom: connectPage.connectionHandler.requiresAddressType ? addressTypeButton.top + : searchButton.top + anchors.topMargin: GameSettings.fieldMargin + connectPage.messageHeight anchors.bottomMargin: GameSettings.fieldMargin anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - GameSettings.fieldMargin*2 + width: parent.width - GameSettings.fieldMargin * 2 color: GameSettings.viewColor radius: GameSettings.buttonRadius - Text { id: title width: parent.width @@ -34,40 +41,43 @@ GamePage { text: qsTr("FOUND DEVICES") BottomLine { - height: 1; + height: 1 width: parent.width color: "#898989" } } - ListView { id: devices anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: title.bottom - model: deviceFinder.devices + model: connectPage.deviceFinder.devices clip: true delegate: Rectangle { id: box - height:GameSettings.fieldHeight * 1.2 + + required property int index + required property var modelData + + height: GameSettings.fieldHeight * 1.2 width: devices.width color: index % 2 === 0 ? GameSettings.delegate1Color : GameSettings.delegate2Color MouseArea { - anchors.fill: parent + anchors.fill: parent onClicked: { - deviceFinder.connectToService(modelData.deviceAddress); - app.showPage("Measure.qml") + connectPage.deviceFinder.connectToService(box.modelData.deviceAddress) + connectPage.showMeasurePage() } } Text { id: device font.pixelSize: GameSettings.smallFontSize - text: modelData.deviceName + text: box.modelData.deviceName anchors.top: parent.top anchors.topMargin: parent.height * 0.1 anchors.leftMargin: parent.height * 0.1 @@ -78,7 +88,7 @@ GamePage { Text { id: deviceAddress font.pixelSize: GameSettings.smallFontSize - text: modelData.deviceAddress + text: box.modelData.deviceAddress anchors.bottom: parent.bottom anchors.bottomMargin: parent.height * 0.1 anchors.rightMargin: parent.height * 0.1 @@ -93,23 +103,31 @@ GamePage { id: addressTypeButton anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: searchButton.top - anchors.bottomMargin: GameSettings.fieldMargin*0.5 + anchors.bottomMargin: GameSettings.fieldMargin * 0.5 width: viewContainer.width height: GameSettings.fieldHeight - visible: connectionHandler.requiresAddressType // only required on BlueZ + visible: connectPage.connectionHandler.requiresAddressType // only required on BlueZ state: "public" - onClicked: state == "public" ? state = "random" : state = "public" + onClicked: state === "public" ? state = "random" : state = "public" states: [ State { name: "public" - PropertyChanges { target: addressTypeText; text: qsTr("Public Address") } - PropertyChanges { target: deviceHandler; addressType: AddressType.PUBLIC_ADDRESS } + PropertyChanges { + addressTypeText.text: qsTr("Public Address") + } + PropertyChanges { + connectPage.deviceHandler.addressType: DeviceHandler.PUBLIC_ADDRESS + } }, State { name: "random" - PropertyChanges { target: addressTypeText; text: qsTr("Random Address") } - PropertyChanges { target: deviceHandler; addressType: AddressType.RANDOM_ADDRESS } + PropertyChanges { + addressTypeText.text: qsTr("Random Address") + } + PropertyChanges { + connectPage.deviceHandler.addressType: DeviceHandler.RANDOM_ADDRESS + } } ] @@ -128,8 +146,8 @@ GamePage { anchors.bottomMargin: GameSettings.fieldMargin width: viewContainer.width height: GameSettings.fieldHeight - enabled: !deviceFinder.scanning - onClicked: deviceFinder.startSearch() + enabled: !connectPage.deviceFinder.scanning + onClicked: connectPage.deviceFinder.startSearch() Text { anchors.centerIn: parent diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/GameButton.qml b/examples/bluetooth/heartrate_game/HeartRateGame/GameButton.qml index 3ce9d66fd..8e8760102 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/GameButton.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/GameButton.qml @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick -import "." Rectangle { id: button @@ -14,10 +13,9 @@ Rectangle { property color pressedColor: GameSettings.buttonPressedColor property color disabledColor: GameSettings.disabledButtonColor - signal clicked() + signal clicked - function checkColor() - { + function checkColor() { if (!button.enabled) { button.color = disabledColor } else { @@ -31,10 +29,10 @@ Rectangle { MouseArea { id: mouseArea anchors.fill: parent - onPressed: checkColor() - onReleased: checkColor() + onPressed: button.checkColor() + onReleased: button.checkColor() onClicked: { - checkColor() + button.checkColor() button.clicked() } } diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/GamePage.qml b/examples/bluetooth/heartrate_game/HeartRateGame/GamePage.qml index 25a5bb3d1..249f94186 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/GamePage.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/GamePage.qml @@ -2,10 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick -import "." Item { - anchors.fill: parent + id: page property string errorMessage: "" property string infoMessage: "" @@ -13,23 +12,14 @@ Item { property bool hasError: errorMessage != "" property bool hasInfo: infoMessage != "" - function init() - { - } - - function close() - { - app.prevPage() - } - Rectangle { id: msg anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right height: GameSettings.fieldHeight - color: hasError ? GameSettings.errorColor : GameSettings.infoColor - visible: hasError || hasInfo + color: page.hasError ? GameSettings.errorColor : GameSettings.infoColor + visible: page.hasError || page.hasInfo Text { id: error @@ -40,7 +30,7 @@ Item { font.pixelSize: GameSettings.smallFontSize fontSizeMode: Text.Fit color: GameSettings.textColor - text: hasError ? errorMessage : infoMessage + text: page.hasError ? page.errorMessage : page.infoMessage } } } diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/GameSettings.qml b/examples/bluetooth/heartrate_game/HeartRateGame/GameSettings.qml index f265b73c3..0fe854609 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/GameSettings.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/GameSettings.qml @@ -41,14 +41,11 @@ Item { property real buttonRadius: buttonHeight * 0.1 // Some help functions - function widthForHeight(h, ss) - { - return h/ss.height * ss.width; + function widthForHeight(h, ss) { + return h / ss.height * ss.width } - function heightForWidth(w, ss) - { - return w/ss.width * ss.height; + function heightForWidth(w, ss) { + return w / ss.width * ss.height } - } diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/Main.qml b/examples/bluetooth/heartrate_game/HeartRateGame/Main.qml index 50b7d3fbb..e26f9b004 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/Main.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/Main.qml @@ -1,9 +1,10 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +pragma ComponentBehavior: Bound import QtQuick import QtQuick.Window -import "." +import HeartRateGame Window { id: wroot @@ -15,48 +16,56 @@ Window { required property ConnectionHandler connectionHandler required property DeviceFinder deviceFinder - required property AddressType deviceHandler + required property DeviceHandler deviceHandler Component.onCompleted: { - GameSettings.wWidth = Qt.binding(function() {return width}) - GameSettings.wHeight = Qt.binding(function() {return height}) + GameSettings.wWidth = Qt.binding(function () { + return width + }) + GameSettings.wHeight = Qt.binding(function () { + return height + }) } Loader { id: splashLoader anchors.fill: parent - source: "SplashScreen.qml" asynchronous: false visible: true - onStatusChanged: { - if (status === Loader.Ready) { - appLoader.setSource("App.qml"); + sourceComponent: SplashScreen { + appIsReady: appLoader.status === Loader.Ready + onReadyChanged: { + if (ready) { + appLoader.visible = true + splashLoader.visible = false + splashLoader.active = false + } } } - } - Connections { - target: splashLoader.item - function onReadyToGo() { - appLoader.visible = true - appLoader.item.init() - splashLoader.visible = false - splashLoader.setSource("") - appLoader.item.forceActiveFocus(); + onStatusChanged: { + if (status === Loader.Ready) + appLoader.active = true } } Loader { id: appLoader anchors.fill: parent - visible: false + active: false asynchronous: true + visible: false + + sourceComponent: App { + connectionHandler: wroot.connectionHandler + deviceFinder: wroot.deviceFinder + deviceHandler: wroot.deviceHandler + } + onStatusChanged: { - if (status === Loader.Ready) - splashLoader.item.appReady() if (status === Loader.Error) - splashLoader.item.errorInLoadingApp(); + Qt.quit() } } } diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/Measure.qml b/examples/bluetooth/heartrate_game/HeartRateGame/Measure.qml index c434d5114..48e84e762 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/Measure.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/Measure.qml @@ -2,49 +2,49 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick +import HeartRateGame GamePage { id: measurePage + required property DeviceHandler deviceHandler + errorMessage: deviceHandler.error infoMessage: deviceHandler.info - property real __timeCounter: 0; + property real __timeCounter: 0 property real __maxTimeCount: 60 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) - function close() - { - deviceHandler.stopMeasurement(); - deviceHandler.disconnectService(); - app.prevPage(); + signal showStatsPage + + function close() { + deviceHandler.stopMeasurement() + deviceHandler.disconnectService() } - function start() - { + function start() { if (!deviceHandler.measuring) { - __timeCounter = 0; + __timeCounter = 0 deviceHandler.startMeasurement() } } - function stop() - { - if (deviceHandler.measuring) { + function stop() { + if (deviceHandler.measuring) deviceHandler.stopMeasurement() - } - app.showPage("Stats.qml") + measurePage.showStatsPage() } Timer { id: measureTimer interval: 1000 - running: deviceHandler.measuring + running: measurePage.deviceHandler.measuring repeat: true onTriggered: { - __timeCounter++; - if (__timeCounter >= __maxTimeCount) + measurePage.__timeCounter++ + if (measurePage.__timeCounter >= measurePage.__maxTimeCount) measurePage.stop() } } @@ -56,22 +56,23 @@ GamePage { Rectangle { id: circle anchors.horizontalCenter: parent.horizontalCenter - width: Math.min(measurePage.width, measurePage.height-GameSettings.fieldHeight*4) - 2*GameSettings.fieldMargin + width: Math.min(measurePage.width, measurePage.height - GameSettings.fieldHeight * 4) + - 2 * GameSettings.fieldMargin height: width - radius: width*0.5 + radius: width * 0.5 color: GameSettings.viewColor Text { id: hintText anchors.centerIn: parent - anchors.verticalCenterOffset: -parent.height*0.1 + anchors.verticalCenterOffset: -parent.height * 0.1 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter width: parent.width * 0.8 height: parent.height * 0.6 wrapMode: Text.WordWrap text: measurePage.relaxText - visible: !deviceHandler.measuring + visible: !measurePage.deviceHandler.measuring color: GameSettings.textColor fontSizeMode: Text.Fit minimumPixelSize: 10 @@ -81,33 +82,33 @@ GamePage { Text { id: text anchors.centerIn: parent - anchors.verticalCenterOffset: -parent.height*0.15 + anchors.verticalCenterOffset: -parent.height * 0.15 font.pixelSize: parent.width * 0.45 - text: deviceHandler.hr - visible: deviceHandler.measuring + text: measurePage.deviceHandler.hr + visible: measurePage.deviceHandler.measuring color: GameSettings.textColor } Item { id: minMaxContainer anchors.horizontalCenter: parent.horizontalCenter - width: parent.width*0.7 + width: parent.width * 0.7 height: parent.height * 0.15 anchors.bottom: parent.bottom - anchors.bottomMargin: parent.height*0.16 - visible: deviceHandler.measuring + anchors.bottomMargin: parent.height * 0.16 + visible: measurePage.deviceHandler.measuring Text { anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter - text: deviceHandler.minHR + text: measurePage.deviceHandler.minHR color: GameSettings.textColor font.pixelSize: GameSettings.hugeFontSize Text { anchors.left: parent.left anchors.bottom: parent.top - font.pixelSize: parent.font.pixelSize*0.8 + font.pixelSize: parent.font.pixelSize * 0.8 color: parent.color text: "MIN" } @@ -116,14 +117,14 @@ GamePage { Text { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - text: deviceHandler.maxHR + text: measurePage.deviceHandler.maxHR color: GameSettings.textColor font.pixelSize: GameSettings.hugeFontSize Text { anchors.right: parent.right anchors.bottom: parent.top - font.pixelSize: parent.font.pixelSize*0.8 + font.pixelSize: parent.font.pixelSize * 0.8 color: parent.color text: "MAX" } @@ -140,13 +141,25 @@ GamePage { smooth: true antialiasing: true - SequentialAnimation{ + SequentialAnimation { id: heartAnim - running: deviceHandler.alive + running: measurePage.deviceHandler.alive loops: Animation.Infinite alwaysRunToEnd: true - PropertyAnimation { target: heart; property: "scale"; to: 1.2; duration: 500; easing.type: Easing.InQuad } - PropertyAnimation { target: heart; property: "scale"; to: 1.0; duration: 500; easing.type: Easing.OutQuad } + PropertyAnimation { + target: heart + property: "scale" + to: 1.2 + duration: 500 + easing.type: Easing.InQuad + } + PropertyAnimation { + target: heart + property: "scale" + to: 1.0 + duration: 500 + easing.type: Easing.OutQuad + } } } } @@ -163,13 +176,15 @@ GamePage { height: parent.height radius: parent.radius color: GameSettings.sliderColor - width: Math.min(1.0,__timeCounter / __maxTimeCount) * parent.width + width: Math.min( + 1.0, + measurePage.__timeCounter / measurePage.__maxTimeCount) * parent.width } Text { anchors.centerIn: parent color: "gray" - text: (__maxTimeCount - __timeCounter).toFixed(0) + " s" + text: (measurePage.__maxTimeCount - measurePage.__timeCounter).toFixed(0) + " s" font.pixelSize: GameSettings.bigFontSize } } @@ -182,10 +197,10 @@ GamePage { anchors.bottomMargin: GameSettings.fieldMargin width: circle.width height: GameSettings.fieldHeight - enabled: !deviceHandler.measuring + enabled: !measurePage.deviceHandler.measuring radius: GameSettings.buttonRadius - onClicked: start() + onClicked: measurePage.start() Text { anchors.centerIn: parent diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/SplashScreen.qml b/examples/bluetooth/heartrate_game/HeartRateGame/SplashScreen.qml index 23f71f08f..2f9ac1b3f 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/SplashScreen.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/SplashScreen.qml @@ -2,33 +2,20 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick -import "." +import HeartRateGame Item { id: root - anchors.fill: parent property bool appIsReady: false property bool splashIsReady: false - property bool ready: appIsReady && splashIsReady - onReadyChanged: if (ready) readyToGo(); - signal readyToGo() - - function appReady() - { - appIsReady = true - } - - function errorInLoadingApp() - { - Qt.quit() - } + anchors.fill: parent Image { anchors.centerIn: parent - width: Math.min(parent.height, parent.width)*0.6 + width: Math.min(parent.height, parent.width) * 0.6 height: GameSettings.heightForWidth(width, sourceSize) source: "images/logo.png" } diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/Stats.qml b/examples/bluetooth/heartrate_game/HeartRateGame/Stats.qml index b818e85e4..22cdd5365 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/Stats.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/Stats.qml @@ -2,8 +2,12 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick +import HeartRateGame GamePage { + id: statsPage + + required property DeviceHandler deviceHandler Column { anchors.centerIn: parent @@ -18,9 +22,9 @@ GamePage { Text { anchors.horizontalCenter: parent.horizontalCenter - font.pixelSize: GameSettings.giganticFontSize*3 + font.pixelSize: GameSettings.giganticFontSize * 3 color: GameSettings.textColor - text: (deviceHandler.maxHR - deviceHandler.minHR).toFixed(0) + text: (statsPage.deviceHandler.maxHR - statsPage.deviceHandler.minHR).toFixed(0) } Item { @@ -30,23 +34,22 @@ GamePage { StatsLabel { title: qsTr("MIN") - value: deviceHandler.minHR.toFixed(0) + value: statsPage.deviceHandler.minHR.toFixed(0) } StatsLabel { title: qsTr("MAX") - value: deviceHandler.maxHR.toFixed(0) + value: statsPage.deviceHandler.maxHR.toFixed(0) } StatsLabel { title: qsTr("AVG") - value: deviceHandler.average.toFixed(1) + value: statsPage.deviceHandler.average.toFixed(1) } - StatsLabel { title: qsTr("CALORIES") - value: deviceHandler.calories.toFixed(3) + value: statsPage.deviceHandler.calories.toFixed(3) } } } diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/StatsLabel.qml b/examples/bluetooth/heartrate_game/HeartRateGame/StatsLabel.qml index cd5cda5be..0ea4249a7 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/StatsLabel.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/StatsLabel.qml @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick -import "." Item { height: GameSettings.fieldHeight diff --git a/examples/bluetooth/heartrate_game/HeartRateGame/TitleBar.qml b/examples/bluetooth/heartrate_game/HeartRateGame/TitleBar.qml index b7de77c4b..016a44358 100644 --- a/examples/bluetooth/heartrate_game/HeartRateGame/TitleBar.qml +++ b/examples/bluetooth/heartrate_game/HeartRateGame/TitleBar.qml @@ -1,50 +1,54 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +pragma ComponentBehavior: Bound import QtQuick -Rectangle { +Rectangle { id: titleBar - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - height: GameSettings.fieldHeight - color: GameSettings.viewColor property var __titles: ["CONNECT", "MEASURE", "STATS"] property int currentIndex: 0 signal titleClicked(int index) + height: GameSettings.fieldHeight + color: GameSettings.viewColor + Repeater { model: 3 Text { + id: caption + required property int index width: titleBar.width / 3 height: titleBar.height x: index * width horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter - text: __titles[index] + text: titleBar.__titles[index] font.pixelSize: GameSettings.tinyFontSize - color: titleBar.currentIndex === index ? GameSettings.textColor : GameSettings.disabledTextColor + color: titleBar.currentIndex === index ? GameSettings.textColor + : GameSettings.disabledTextColor MouseArea { anchors.fill: parent - onClicked: titleClicked(index) + onClicked: titleBar.titleClicked(caption.index) } } } - Item { anchors.bottom: parent.bottom width: parent.width / 3 height: parent.height - x: currentIndex * width + x: titleBar.currentIndex * width - BottomLine{} + BottomLine {} - Behavior on x { NumberAnimation { duration: 200 } } + Behavior on x { + NumberAnimation { + duration: 200 + } + } } - } diff --git a/examples/bluetooth/heartrate_game/connectionhandler.py b/examples/bluetooth/heartrate_game/connectionhandler.py index e8734153e..4cce58723 100644 --- a/examples/bluetooth/heartrate_game/connectionhandler.py +++ b/examples/bluetooth/heartrate_game/connectionhandler.py @@ -46,6 +46,10 @@ class ConnectionHandler(QObject): def address(self): return self.m_localDevice.address().toString() + @Property(bool, notify=deviceChanged) + def hasPermission(self): + return True + @Slot(QBluetoothLocalDevice.HostMode) def hostModeChanged(self, mode): self.deviceChanged.emit() diff --git a/examples/bluetooth/heartrate_game/devicehandler.py b/examples/bluetooth/heartrate_game/devicehandler.py index aa8f96b16..85d160c4d 100644 --- a/examples/bluetooth/heartrate_game/devicehandler.py +++ b/examples/bluetooth/heartrate_game/devicehandler.py @@ -10,7 +10,7 @@ from PySide6.QtBluetooth import (QLowEnergyCharacteristic, QLowEnergyDescriptor, QLowEnergyService, QBluetoothUuid) -from PySide6.QtQml import QmlNamedElement, QmlUncreatable +from PySide6.QtQml import QmlElement from PySide6.QtCore import (QByteArray, QDateTime, QRandomGenerator, QTimer, Property, Signal, Slot, QEnum) @@ -24,8 +24,7 @@ QML_IMPORT_NAME = "HeartRateGame" QML_IMPORT_MAJOR_VERSION = 1 -@QmlNamedElement("AddressType") -@QmlUncreatable("Enum is not a type") +@QmlElement class DeviceHandler(BluetoothBaseClass): @QEnum @@ -113,13 +112,13 @@ class DeviceHandler(BluetoothBaseClass): # Make connections #! [Connect-Signals-1] - self.m_control = QLowEnergyController.createCentral(self.m_currentDevice.getDevice(), self) + self.m_control = QLowEnergyController.createCentral(self.m_currentDevice.device(), self) #! [Connect-Signals-1] self.m_control.setRemoteAddressType(self.m_addressType) #! [Connect-Signals-2] - m_control.serviceDiscovered.connect(self.serviceDiscovered) - m_control.discoveryFinished.connect(self.serviceScanDone) + self.m_control.serviceDiscovered.connect(self.serviceDiscovered) + self.m_control.discoveryFinished.connect(self.serviceScanDone) self.m_control.errorOccurred.connect(self.controllerErrorOccurred) self.m_control.connected.connect(self.controllerConnected) @@ -183,14 +182,14 @@ class DeviceHandler(BluetoothBaseClass): @Slot(QLowEnergyService.ServiceState) def serviceStateChanged(self, switch): if switch == QLowEnergyService.RemoteServiceDiscovering: - self.setInfo(tr("Discovering services...")) + self.info = "Discovering services..." elif switch == QLowEnergyService.RemoteServiceDiscovered: - self.setInfo(tr("Service discovered.")) - hrChar = m_service.characteristic(QBluetoothUuid(QBluetoothUuid.CharacteristicType.HeartRateMeasurement)) + self.info = "Service discovered." + hrChar = self.m_service.characteristic(QBluetoothUuid(QBluetoothUuid.CharacteristicType.HeartRateMeasurement)) if hrChar.isValid(): self.m_notificationDesc = hrChar.descriptor(QBluetoothUuid.DescriptorType.ClientCharacteristicConfiguration) if self.m_notificationDesc.isValid(): - self.m_service.writeDescriptor(m_notificationDesc, + self.m_service.writeDescriptor(self.m_notificationDesc, QByteArray.fromHex(b"0100")) else: self.error = "HR Data not found." @@ -209,9 +208,9 @@ class DeviceHandler(BluetoothBaseClass): # Heart Rate hrvalue = 0 if flags & 0x1: # HR 16 bit little endian? otherwise 8 bit - hrvalue = struct.unpack("<H", data[1:3]) + hrvalue = struct.unpack("<H", data[1:3])[0] else: - hrvalue = struct.unpack("B", data[1:2]) + hrvalue = struct.unpack("B", data[1:2])[0] self.addMeasurement(hrvalue) diff --git a/examples/bluetooth/heartrate_game/heartrate_global.py b/examples/bluetooth/heartrate_game/heartrate_global.py index ada5d5cb1..b4c29bf4b 100644 --- a/examples/bluetooth/heartrate_game/heartrate_global.py +++ b/examples/bluetooth/heartrate_game/heartrate_global.py @@ -4,7 +4,7 @@ import sys -_simulator = sys.platform == "win32" +_simulator = False def simulator(): |