From 05d598ffcfc36f94e60f54e69637a5d1a55c7c66 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 21 Oct 2024 14:06:48 +0200 Subject: [PATCH 01/18] first raw version --- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 24 ++++++- .../wahookickrsnapbike/wahookickrsnapbike.h | 67 ++++++++++++++++++- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index caa489acc..312fa3285 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -192,10 +192,16 @@ void wahookickrsnapbike::update() { } QThread::msleep(700); + QByteArray d = setWheelCircumference(gearsToWheelDiameter(gears())); + uint8_t e[20]; + setGears(1); + memcpy(e, d.constData(), d.length()); + writeCharacteristic(e, d.length(), "setWheelCircumference", false, true); + // required to the SS2K only one time Resistance = 0; emit resistanceRead(Resistance.value()); - initRequest = false; + initRequest = false; } else if (bluetoothDevice.isValid() && m_control->state() == QLowEnergyController::DiscoveredState //&& // gattCommunicationChannelService && @@ -259,7 +265,10 @@ void wahookickrsnapbike::update() { memcpy(b, a.constData(), a.length()); writeCharacteristic(b, a.length(), "setResistance", false, true); } else if (virtualBike && virtualBike->ftmsDeviceConnected() && lastGearValue != gears()) { - inclinationChanged(lastGrade, lastGrade); + QByteArray a = setWheelCircumference(gearsToWheelDiameter(gears())); + uint8_t b[20]; + memcpy(b, a.constData(), a.length()); + writeCharacteristic(b, a.length(), "setWheelCircumference", false, true); } lastGearValue = gears(); requestResistance = -1; @@ -280,6 +289,16 @@ void wahookickrsnapbike::update() { } } +double wahookickrsnapbike::gearsToWheelDiameter(double gear) { + GearTable table; + if(gear < 1) gear = 1; + else if(gear > 12) gear = 12; + double original_ratio = crankset / rear_cog_size; + GearTable::GearInfo g = table.getGear((int)gear); + double current_ratio = g.crankset / g.rearCog; + return (wheel_size / current_ratio) * original_ratio; +} + void wahookickrsnapbike::serviceDiscovered(const QBluetoothUuid &gatt) { emit debug(QStringLiteral("serviceDiscovered ") + gatt.toString()); } @@ -823,7 +842,6 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) { emit debug(QStringLiteral("writing inclination ") + QString::number(grade)); QSettings settings; double g = grade; - g += gears(); QByteArray a = setSimGrade(g); uint8_t b[20]; memcpy(b, a.constData(), a.length()); diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h index 97357ff85..8ece29240 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h @@ -56,7 +56,7 @@ class wahookickrsnapbike : public bike { _setWheelCircumference = 72, }; - private: + private: QByteArray unlockCommand(); QByteArray setResistanceMode(double resistance); QByteArray setStandardMode(uint8_t level); @@ -109,6 +109,71 @@ class wahookickrsnapbike : public bike { resistance_t lastForcedResistance = -1; + // cranks & co. + double crankset = 40; + double rear_cog_size = 14; + double wheel_size = 2230; // mm 700x44 + double gearsToWheelDiameter(double gear); + + class GearTable { + public: + struct GearInfo { + int gear; + int crankset; + int rearCog; + }; + + GearTable() { + gears = { + {1, 38, 44}, + {2, 38, 38}, + {3, 38, 32}, + {4, 38, 28}, + {5, 38, 24}, + {6, 38, 21}, + {7, 38, 19}, + {8, 38, 17}, + {9, 38, 15}, + {10, 38, 13}, + {11, 38, 11}, + {12, 38, 10} + }; + } + + void addGear(int gear, int crankset, int rearCog) { + gears.push_back({gear, crankset, rearCog}); + } + + void removeGear(int gear) { + gears.erase(std::remove_if(gears.begin(), gears.end(), + [gear](const GearInfo& info) { return info.gear == gear; }), + gears.end()); + } + + void printTable() const { + qDebug() << "| Gear | Crankset | Rear Cog |\n"; + qDebug() << "|------|----------|----------|\n"; + for (const auto& gear : gears) { + qDebug() << "| " << gear.gear << " | " << gear.crankset + << " | " << gear.rearCog << " |\n"; + } + } + + GearInfo getGear(int gearNumber) const { + auto it = std::find_if(gears.begin(), gears.end(), + [gearNumber](const GearInfo& info) { return info.gear == gearNumber; }); + + if (it != gears.end()) { + return *it; + } + return GearInfo(); + } + + private: + std::vector gears; + }; + + #ifdef Q_OS_IOS lockscreen *h = 0; #endif From cc7757bfcd17a68989f48bc5a3ce4ac0d7cfc6f1 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 22 Oct 2024 15:38:44 +0200 Subject: [PATCH 02/18] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index bf820d444..54e5bc1c7 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4068,7 +4068,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 911; + CURRENT_PROJECT_VERSION = 912; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4259,7 +4259,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 911; + CURRENT_PROJECT_VERSION = 912; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4486,7 +4486,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 911; + CURRENT_PROJECT_VERSION = 912; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4582,7 +4582,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 911; + CURRENT_PROJECT_VERSION = 912; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4674,7 +4674,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 911; + CURRENT_PROJECT_VERSION = 912; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4788,7 +4788,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 911; + CURRENT_PROJECT_VERSION = 912; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 2d1364497ea9e94c5c4b127dcdffc20db0fc8813 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 22 Oct 2024 15:40:04 +0200 Subject: [PATCH 03/18] Update virtualbike_zwift.swift --- src/ios/virtualbike_zwift.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ios/virtualbike_zwift.swift b/src/ios/virtualbike_zwift.swift index aec05a16c..06308b98d 100644 --- a/src/ios/virtualbike_zwift.swift +++ b/src/ios/virtualbike_zwift.swift @@ -529,10 +529,10 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate { LastFTMSMessageReceived = Data([0x05, power[0], power[1]]) var response: [UInt8] = [ 0x03, 0x08, 0x82, 0x01, 0x10, 0x22, 0x18, 0x10, 0x20, 0x00, 0x28, 0x98, 0x52, 0x30, 0x86, 0xed, 0x01 ] - response[2] = self.CurrentWatt + response[2] = UInt8(self.CurrentWatt) var responseData = Data(bytes: &response, count: 17) - updateQueue.append((ZwiftPlayReadUUID, responseData)) + updateQueue.append((ZwiftPlayReadCharacteristic, responseData)) } } From d712621b7bb5b57045a59fa8f29e93f05c97899c Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 23 Oct 2024 11:47:05 +0200 Subject: [PATCH 04/18] fixing formula --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ .../wahookickrsnapbike/wahookickrsnapbike.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 55a423971..22c586b9f 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4068,7 +4068,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 913; + CURRENT_PROJECT_VERSION = 914; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4259,7 +4259,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 913; + CURRENT_PROJECT_VERSION = 914; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4486,7 +4486,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 913; + CURRENT_PROJECT_VERSION = 914; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4582,7 +4582,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 913; + CURRENT_PROJECT_VERSION = 914; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4674,7 +4674,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 913; + CURRENT_PROJECT_VERSION = 914; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4788,7 +4788,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 913; + CURRENT_PROJECT_VERSION = 914; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 312fa3285..87833babf 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -296,7 +296,7 @@ double wahookickrsnapbike::gearsToWheelDiameter(double gear) { double original_ratio = crankset / rear_cog_size; GearTable::GearInfo g = table.getGear((int)gear); double current_ratio = g.crankset / g.rearCog; - return (wheel_size / current_ratio) * original_ratio; + return (wheel_size / original_ratio) * current_ratio; } void wahookickrsnapbike::serviceDiscovered(const QBluetoothUuid &gatt) { From 89808ae65b5df49932747fb48b7f12b0a05be0e1 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 24 Oct 2024 11:15:51 +0200 Subject: [PATCH 05/18] fixing casting to double --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ .../wahookickrsnapbike/wahookickrsnapbike.cpp | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 555e53f4f..6110153f4 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4068,7 +4068,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 915; + CURRENT_PROJECT_VERSION = 916; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4259,7 +4259,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 915; + CURRENT_PROJECT_VERSION = 916; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4486,7 +4486,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 915; + CURRENT_PROJECT_VERSION = 916; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4582,7 +4582,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 915; + CURRENT_PROJECT_VERSION = 916; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4674,7 +4674,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 915; + CURRENT_PROJECT_VERSION = 916; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4788,7 +4788,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 915; + CURRENT_PROJECT_VERSION = 916; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 87833babf..b8946eec4 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -293,10 +293,10 @@ double wahookickrsnapbike::gearsToWheelDiameter(double gear) { GearTable table; if(gear < 1) gear = 1; else if(gear > 12) gear = 12; - double original_ratio = crankset / rear_cog_size; + double original_ratio = ((double)crankset) / ((double)rear_cog_size); GearTable::GearInfo g = table.getGear((int)gear); - double current_ratio = g.crankset / g.rearCog; - return (wheel_size / original_ratio) * current_ratio; + double current_ratio = ((double)g.crankset / (double)g.rearCog); + return (((double)wheel_size) / original_ratio) * ((double)current_ratio); } void wahookickrsnapbike::serviceDiscovered(const QBluetoothUuid &gatt) { From ed1599ca8e96259a5a1e12d19fe226a12c2e3c2f Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 24 Oct 2024 15:08:25 +0200 Subject: [PATCH 06/18] need to center the values in the table --- src/gears.qml | 527 ++++++++++++++++++ src/qml.qrc | 1 + ...ettings-treadmill-inclination-override.qml | 2 +- src/settings.qml | 10 +- 4 files changed, 538 insertions(+), 2 deletions(-) create mode 100644 src/gears.qml diff --git a/src/gears.qml b/src/gears.qml new file mode 100644 index 000000000..67b6103c2 --- /dev/null +++ b/src/gears.qml @@ -0,0 +1,527 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.15 +import QtQuick.Controls.Material 2.0 +import Qt.labs.settings 1.0 + +ScrollView { + contentWidth: -1 + focus: true + anchors.horizontalCenter: parent.horizontalCenter + anchors.fill: parent + id: gearSettingsWindow + visible: true + clip: true + + // Properties to store the selected values + property int selectedCranksetSize: 38 + property int selectedCogSize: 44 + property string selectedWheelSize: "700 x 18C" + property real selectedCircumference: 2070 + property int initialWheelSizeIndex: 0 // indice per "700 x 18C" + + // Add these connections to your root item (ScrollView) + Connections { + target: gearSettingsWindow + function onGearConfigurationChanged() { + gearTable.updateGearListModel() + } + } + + // Initial gear data + property var gearRows: [ + { gear: 1, crankset: 38, cog: 44, active: true }, + { gear: 2, crankset: 38, cog: 38, active: true }, + { gear: 3, crankset: 38, cog: 32, active: true }, + { gear: 4, crankset: 38, cog: 28, active: true }, + { gear: 5, crankset: 38, cog: 24, active: true }, + { gear: 6, crankset: 38, cog: 21, active: true }, + { gear: 7, crankset: 38, cog: 19, active: true }, + { gear: 8, crankset: 38, cog: 17, active: true }, + { gear: 9, crankset: 38, cog: 15, active: true }, + { gear: 10, crankset: 38, cog: 13, active: true }, + { gear: 11, crankset: 38, cog: 11, active: true }, + { gear: 12, crankset: 38, cog: 10, active: true } + ] + + // Initialize components + Component.onCompleted: { + wheelSizeCombo.currentIndex = initialWheelSizeIndex + } + + function clearGearsFromIndex(startIndex) { + for (let i = startIndex; i < gearRows.length; i++) { + gearRows[i].active = false + } + // Force update + var temp = gearRows + gearRows = [] + gearRows = temp + gearConfigurationChanged(gearRows) + } + + function initializeGearRows() { + gearRows = [ + { gear: 1, crankset: 38, cog: 44, active: true }, + { gear: 2, crankset: 38, cog: 38, active: true }, + { gear: 3, crankset: 38, cog: 32, active: true }, + { gear: 4, crankset: 38, cog: 28, active: true }, + { gear: 5, crankset: 38, cog: 24, active: true }, + { gear: 6, crankset: 38, cog: 21, active: true }, + { gear: 7, crankset: 38, cog: 19, active: true }, + { gear: 8, crankset: 38, cog: 17, active: true }, + { gear: 9, crankset: 38, cog: 15, active: true }, + { gear: 10, crankset: 38, cog: 13, active: true }, + { gear: 11, crankset: 38, cog: 11, active: true }, + { gear: 12, crankset: 38, cog: 10, active: true } + ] + // Force update + var temp = gearRows + gearRows = [] + gearRows = temp + } + + // Signals to notify when values change + signal settingsChanged(int crankset, int cog, string wheelSize, real circumference) + signal gearConfigurationChanged(var gearRows) + + ColumnLayout { + anchors.fill: parent + anchors.margins: 20 + spacing: 20 + + // Crankset Size + GroupBox { + title: "Crankset Size (tooth count)" + Layout.fillWidth: true + + SpinBox { + from: 1 + to: 60 + value: selectedCranksetSize + onValueChanged: { + selectedCranksetSize = value + gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + selectedWheelSize, selectedCircumference) + } + } + } + + // Cog Size + GroupBox { + title: "Cog Size (tooth count)" + Layout.fillWidth: true + + SpinBox { + from: 1 + to: 50 + value: selectedCogSize + onValueChanged: { + selectedCogSize = value + gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + selectedWheelSize, selectedCircumference) + } + } + } + + // Wheel Size + GroupBox { + title: "Wheel Size" + Layout.fillWidth: true + + ComboBox { + id: wheelSizeCombo + width: parent.width + currentIndex: initialWheelSizeIndex + textRole: "text" + model: ListModel { + id: wheelSizes + ListElement { text: "700 x 18C"; circumference: 2070 } + ListElement { text: "700 x 19C"; circumference: 2080 } + ListElement { text: "700 x 20C"; circumference: 2086 } + ListElement { text: "700 x 23C"; circumference: 2096 } + ListElement { text: "700 x 25C"; circumference: 2109 } + ListElement { text: "700 x 28C"; circumference: 2127 } + ListElement { text: "700 x 30C"; circumference: 2140 } + ListElement { text: "700 x 32C"; circumference: 2152 } + ListElement { text: "700 x 35C"; circumference: 2171 } + ListElement { text: "700 x 38C"; circumference: 2190 } + ListElement { text: "700 x 40C"; circumference: 2203 } + ListElement { text: "700 x 44C"; circumference: 2230 } + ListElement { text: "700 x 45C"; circumference: 2234 } + ListElement { text: "700 x 47C"; circumference: 2247 } + ListElement { text: "700 x 50C"; circumference: 2265 } + ListElement { text: "650 x 20C"; circumference: 1938 } + ListElement { text: "650 x 23C"; circumference: 1944 } + ListElement { text: "650 x 35A"; circumference: 2090 } + ListElement { text: "650 x 38B"; circumference: 2105 } + ListElement { text: "650 x 38A"; circumference: 2125 } + ListElement { text: "12\" x 1.75\""; circumference: 935 } + ListElement { text: "12\" x 1.95\""; circumference: 940 } + ListElement { text: "14\" x 1.50\""; circumference: 1020 } + ListElement { text: "14\" x 1.75\""; circumference: 1055 } + ListElement { text: "16\" x 1.50\""; circumference: 1185 } + ListElement { text: "16\" x 1.75\""; circumference: 1195 } + ListElement { text: "16\" x 2.00\""; circumference: 1245 } + ListElement { text: "16\" x 1-1/8\""; circumference: 1290 } + ListElement { text: "16\" x 1-3/8\""; circumference: 1300 } + ListElement { text: "18\" x 1.50\""; circumference: 1340 } + ListElement { text: "18\" x 1.75\""; circumference: 1350 } + ListElement { text: "20\" x 1.25\""; circumference: 1450 } + ListElement { text: "20\" x 1.35\""; circumference: 1460 } + ListElement { text: "20\" x 1.50\""; circumference: 1490 } + ListElement { text: "20\" x 1.75\""; circumference: 1515 } + ListElement { text: "20\" x 1.95\""; circumference: 1565 } + ListElement { text: "20\" x 1-1/8\""; circumference: 1545 } + ListElement { text: "20\" x 1-3/8\""; circumference: 1615 } + ListElement { text: "22\" x 1-3/8\""; circumference: 1770 } + ListElement { text: "22\" x 1-1/2\""; circumference: 1785 } + ListElement { text: "24\" x 3/4\" Tubular"; circumference: 1785 } + ListElement { text: "24\" x 1\""; circumference: 1753 } + ListElement { text: "24\" x 1-1/8\""; circumference: 1795 } + ListElement { text: "24\" x 1-1/4\""; circumference: 1905 } + ListElement { text: "24\" x 1.75\""; circumference: 1890 } + ListElement { text: "24\" x 2.00\""; circumference: 1925 } + ListElement { text: "24\" x 2.125\""; circumference: 1965 } + ListElement { text: "26\" x 7/8\" Tubular"; circumference: 1920 } + ListElement { text: "26\" x 1.25\""; circumference: 1950 } + ListElement { text: "26\" x 1.40\""; circumference: 2005 } + ListElement { text: "26\" x 1.50\""; circumference: 2010 } + ListElement { text: "26\" x 1.75\""; circumference: 2023 } + ListElement { text: "26\" x 1.95\""; circumference: 2050 } + ListElement { text: "26\" x 2.00\""; circumference: 2055 } + ListElement { text: "26\" x 2.10\""; circumference: 2068 } + ListElement { text: "26\" x 2.125\""; circumference: 2070 } + ListElement { text: "26\" x 2.35\""; circumference: 2083 } + ListElement { text: "26\" x 3.00\""; circumference: 2170 } + ListElement { text: "26\" x 1-1.0\""; circumference: 1913 } + ListElement { text: "26\" x 1\""; circumference: 1952 } + ListElement { text: "26\" x 1-1/8\""; circumference: 1970 } + ListElement { text: "26\" x 1-3/8\""; circumference: 2068 } + ListElement { text: "26\" x 1-1/2\""; circumference: 2100 } + ListElement { text: "27\" x 1\""; circumference: 2145 } + ListElement { text: "27\" x 1-1/8\""; circumference: 2155 } + ListElement { text: "27\" x 1-1/4\""; circumference: 2161 } + ListElement { text: "27\" x 1-3/8\""; circumference: 2169 } + ListElement { text: "27.5\" / 650B x 1.50\""; circumference: 2079 } + ListElement { text: "27.5\" / 650B x 1.95\""; circumference: 2090 } + ListElement { text: "27.5\" / 650B x 2.10\""; circumference: 2148 } + ListElement { text: "27.5\" / 650B x 2.25\""; circumference: 2182 } + ListElement { text: "27.5\" / 650B x 2.3\""; circumference: 2199 } + ListElement { text: "27.5\" / 650B x 2.35\""; circumference: 2207 } + ListElement { text: "27.5\" / 650B x 2.4\""; circumference: 2213 } + ListElement { text: "27.5\" / 650B x 2.5\""; circumference: 2231 } + ListElement { text: "27.5\" / 650B x 2.6\""; circumference: 2247 } + ListElement { text: "27.5\" / 650B x 2.8\""; circumference: 2279 } + ListElement { text: "29\" x 2.1\""; circumference: 2286 } + ListElement { text: "29\" x 2.2\""; circumference: 2302 } + ListElement { text: "29\" x 2.25\""; circumference: 2310 } + ListElement { text: "29\" x 2.3\""; circumference: 2326 } + ListElement { text: "29\" x 2.35\""; circumference: 2326 } + ListElement { text: "29\" x 2.4\""; circumference: 2333 } + ListElement { text: "29\" x 2.5\""; circumference: 2350 } + ListElement { text: "29\" x 2.6\""; circumference: 2366 } + } + onCurrentIndexChanged: { + if (currentIndex >= 0) { + selectedWheelSize = model.get(currentIndex).text + selectedCircumference = model.get(currentIndex).circumference + gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + selectedWheelSize, selectedCircumference) + } + } + } + } + + // Gear Table GroupBox + GroupBox { + title: "Gear Table" + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredHeight: parent.height + + ColumnLayout { + anchors.fill: parent + spacing: 10 + + // Buttons (same as before) + RowLayout { + Layout.fillWidth: true + Layout.preferredHeight: 40 + spacing: 10 + + Button { + text: "Clear Selected Gear and Following" + Layout.fillWidth: true + Layout.preferredHeight: 40 + onClicked: { + if (gearTable.currentRow >= 0) { + clearGearsFromIndex(gearTable.currentRow) + } + } + } + + Button { + text: "Reset All Gears" + Layout.fillWidth: true + Layout.preferredHeight: 40 + onClicked: initializeGearRows() + } + } + + // Table Header (same as before) + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 40 + color: "#f0f0f0" + border.width: 1 + border.color: "#cccccc" + + Row { + anchors.fill: parent + + Rectangle { + width: parent.width / 3 + height: parent.height + border.width: 1 + border.color: "#cccccc" + color: "transparent" + + Text { + anchors.centerIn: parent + text: "Gear" + font.bold: true + color: "black" + } + } + + Rectangle { + width: parent.width / 3 + height: parent.height + border.width: 1 + border.color: "#cccccc" + color: "transparent" + + Text { + anchors.centerIn: parent + text: "Crankset" + font.bold: true + color: "black" + } + } + + Rectangle { + width: parent.width / 3 + height: parent.height + border.width: 1 + border.color: "#cccccc" + color: "transparent" + + Text { + anchors.centerIn: parent + text: "Rear Cog" + font.bold: true + color: "black" + } + } + } + } + + // Table Content + ListView { + id: gearTable + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + property int currentRow: -1 + model: ListModel { + id: gearListModel + } + + Component.onCompleted: { + updateGearListModel() + } + + function updateGearListModel() { + gearListModel.clear() + for (var i = 0; i < gearRows.length; i++) { + if (gearRows[i].active) { + gearListModel.append(gearRows[i]) + } + } + } + + delegate: Rectangle { + width: gearTable.width + height: 40 + color: gearTable.currentRow === index ? "#e0e0e0" : "white" + + MouseArea { + anchors.fill: parent + onClicked: gearTable.currentRow = index + } + + Row { + anchors.fill: parent + + // Gear Number (non-editable) + Rectangle { + width: parent.width / 3 + height: parent.height + border.width: 1 + border.color: "#cccccc" + color: "transparent" + + Text { + anchors.centerIn: parent + text: gear + color: "black" + } + } + + // Crankset (editable) + Rectangle { + width: parent.width / 3 + height: parent.height + border.width: 1 + border.color: "#cccccc" + color: "transparent" + + SpinBox { + id: cranksetSpinBox + anchors.centerIn: parent + width: parent.width * 0.8 + height: 30 + from: 1 + to: 60 + value: crankset + onValueModified: { + gearRows[index].crankset = value + gearConfigurationChanged(gearRows) + } + + // Style the SpinBox + contentItem: TextInput { + z: 2 + text: cranksetSpinBox.textFromValue(cranksetSpinBox.value, cranksetSpinBox.locale) + font: cranksetSpinBox.font + color: "black" + selectionColor: "#21be2b" + selectedTextColor: "#ffffff" + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + } + + up.indicator: Rectangle { + x: parent.width - width + height: parent.height + width: height + color: parent.up.pressed ? "#e4e4e4" : "#f6f6f6" + border.color: "#cccccc" + + Text { + text: "+" + color: "black" + anchors.centerIn: parent + font.pixelSize: 12 + } + } + + down.indicator: Rectangle { + x: 0 + height: parent.height + width: height + color: parent.down.pressed ? "#e4e4e4" : "#f6f6f6" + border.color: "#cccccc" + + Text { + text: "-" + color: "black" + anchors.centerIn: parent + font.pixelSize: 12 + } + } + + background: Rectangle { + color: "white" + border.color: "#cccccc" + } + } + } + + // Rear Cog (editable) + Rectangle { + width: parent.width / 3 + height: parent.height + border.width: 1 + border.color: "#cccccc" + color: "transparent" + + SpinBox { + id: cogSpinBox + anchors.centerIn: parent + width: parent.width * 0.8 + height: 30 + from: 1 + to: 50 + value: cog + onValueModified: { + gearRows[index].cog = value + gearConfigurationChanged(gearRows) + } + + // Style the SpinBox (same as cranksetSpinBox) + contentItem: TextInput { + z: 2 + text: cogSpinBox.textFromValue(cogSpinBox.value, cogSpinBox.locale) + font: cogSpinBox.font + color: "black" + selectionColor: "#21be2b" + selectedTextColor: "#ffffff" + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + } + + up.indicator: Rectangle { + x: parent.width - width + height: parent.height + width: height + color: parent.up.pressed ? "#e4e4e4" : "#f6f6f6" + border.color: "#cccccc" + + Text { + text: "+" + color: "black" + anchors.centerIn: parent + font.pixelSize: 12 + } + } + + down.indicator: Rectangle { + x: 0 + height: parent.height + width: height + color: parent.down.pressed ? "#e4e4e4" : "#f6f6f6" + border.color: "#cccccc" + + Text { + text: "-" + color: "black" + anchors.centerIn: parent + font.pixelSize: 12 + } + } + + background: Rectangle { + color: "white" + border.color: "#cccccc" + } + } + } + } + } + } + } + } + } +} diff --git a/src/qml.qrc b/src/qml.qrc index 75042363d..43f81b742 100644 --- a/src/qml.qrc +++ b/src/qml.qrc @@ -109,5 +109,6 @@ ChartFooterInnerNoJS.qml inner_templates/chartjs/dochartliveheart.js Wizard.qml + gears.qml diff --git a/src/settings-treadmill-inclination-override.qml b/src/settings-treadmill-inclination-override.qml index fc2d75938..3072d3460 100644 --- a/src/settings-treadmill-inclination-override.qml +++ b/src/settings-treadmill-inclination-override.qml @@ -11,7 +11,7 @@ ScrollView { anchors.fill: parent //anchors.bottom: footerSettings.top //anchors.bottomMargin: footerSettings.height + 10 - id: settingsTTLPane + id: settingsInclinationPane Settings { id: settings diff --git a/src/settings.qml b/src/settings.qml index 0b10a071d..7dfe5606c 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -2493,6 +2493,14 @@ import QtQuick.Dialogs 1.0 color: Material.color(Material.Lime) } + NewPageElement { + title: qsTr("Wahoo Options") + indicatRectColor: Material.color(Material.Grey) + textColor: Material.color(Material.Yellow) + color: Material.backgroundColor + accordionContent: "gears.qml" + } + AccordionElement { id: schwinnBikeAccordion title: qsTr("Schwinn Bike Options") @@ -9800,7 +9808,7 @@ import QtQuick.Dialogs 1.0 Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.fillWidth: true color: Material.color(Material.Lime) - } + } } } From 0f149448b34be7c3b6bf9300d249f6f69f4e4a4e Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 25 Oct 2024 16:28:33 +0200 Subject: [PATCH 07/18] Update gears.qml --- src/gears.qml | 196 +++++++++++++++----------------------------------- 1 file changed, 57 insertions(+), 139 deletions(-) diff --git a/src/gears.qml b/src/gears.qml index 67b6103c2..d000d8fe2 100644 --- a/src/gears.qml +++ b/src/gears.qml @@ -18,9 +18,8 @@ ScrollView { property int selectedCogSize: 44 property string selectedWheelSize: "700 x 18C" property real selectedCircumference: 2070 - property int initialWheelSizeIndex: 0 // indice per "700 x 18C" + property int initialWheelSizeIndex: 0 - // Add these connections to your root item (ScrollView) Connections { target: gearSettingsWindow function onGearConfigurationChanged() { @@ -44,20 +43,18 @@ ScrollView { { gear: 12, crankset: 38, cog: 10, active: true } ] - // Initialize components Component.onCompleted: { wheelSizeCombo.currentIndex = initialWheelSizeIndex } function clearGearsFromIndex(startIndex) { - for (let i = startIndex; i < gearRows.length; i++) { - gearRows[i].active = false - } - // Force update - var temp = gearRows - gearRows = [] - gearRows = temp - gearConfigurationChanged(gearRows) + for (let i = startIndex; i < gearRows.length; i++) { + gearRows[i].active = false + } + var temp = gearRows + gearRows = [] + gearRows = temp + gearConfigurationChanged(gearRows) } function initializeGearRows() { @@ -75,13 +72,11 @@ ScrollView { { gear: 11, crankset: 38, cog: 11, active: true }, { gear: 12, crankset: 38, cog: 10, active: true } ] - // Force update var temp = gearRows gearRows = [] gearRows = temp } - // Signals to notify when values change signal settingsChanged(int crankset, int cog, string wheelSize, real circumference) signal gearConfigurationChanged(var gearRows) @@ -95,14 +90,19 @@ ScrollView { title: "Crankset Size (tooth count)" Layout.fillWidth: true - SpinBox { - from: 1 - to: 60 - value: selectedCranksetSize - onValueChanged: { - selectedCranksetSize = value - gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, - selectedWheelSize, selectedCircumference) + TextEdit { + text: selectedCranksetSize.toString() + width: parent.width + height: 30 + verticalAlignment: TextEdit.AlignVCenter + selectByMouse: true + onTextChanged: { + var value = parseInt(text) + if (!isNaN(value) && value >= 1 && value <= 60) { + selectedCranksetSize = value + gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + selectedWheelSize, selectedCircumference) + } } } } @@ -112,14 +112,19 @@ ScrollView { title: "Cog Size (tooth count)" Layout.fillWidth: true - SpinBox { - from: 1 - to: 50 - value: selectedCogSize - onValueChanged: { - selectedCogSize = value - gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, - selectedWheelSize, selectedCircumference) + TextEdit { + text: selectedCogSize.toString() + width: parent.width + height: 30 + verticalAlignment: TextEdit.AlignVCenter + selectByMouse: true + onTextChanged: { + var value = parseInt(text) + if (!isNaN(value) && value >= 1 && value <= 50) { + selectedCogSize = value + gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + selectedWheelSize, selectedCircumference) + } } } } @@ -221,6 +226,7 @@ ScrollView { ListElement { text: "29\" x 2.4\""; circumference: 2333 } ListElement { text: "29\" x 2.5\""; circumference: 2350 } ListElement { text: "29\" x 2.6\""; circumference: 2366 } + } onCurrentIndexChanged: { if (currentIndex >= 0) { @@ -244,7 +250,7 @@ ScrollView { anchors.fill: parent spacing: 10 - // Buttons (same as before) + // Buttons RowLayout { Layout.fillWidth: true Layout.preferredHeight: 40 @@ -269,7 +275,7 @@ ScrollView { } } - // Table Header (same as before) + // Table Header Rectangle { Layout.fillWidth: true Layout.preferredHeight: 40 @@ -387,65 +393,21 @@ ScrollView { border.color: "#cccccc" color: "transparent" - SpinBox { - id: cranksetSpinBox + TextEdit { anchors.centerIn: parent width: parent.width * 0.8 height: 30 - from: 1 - to: 60 - value: crankset - onValueModified: { - gearRows[index].crankset = value - gearConfigurationChanged(gearRows) - } - - // Style the SpinBox - contentItem: TextInput { - z: 2 - text: cranksetSpinBox.textFromValue(cranksetSpinBox.value, cranksetSpinBox.locale) - font: cranksetSpinBox.font - color: "black" - selectionColor: "#21be2b" - selectedTextColor: "#ffffff" - horizontalAlignment: Qt.AlignHCenter - verticalAlignment: Qt.AlignVCenter - } - - up.indicator: Rectangle { - x: parent.width - width - height: parent.height - width: height - color: parent.up.pressed ? "#e4e4e4" : "#f6f6f6" - border.color: "#cccccc" - - Text { - text: "+" - color: "black" - anchors.centerIn: parent - font.pixelSize: 12 - } - } - - down.indicator: Rectangle { - x: 0 - height: parent.height - width: height - color: parent.down.pressed ? "#e4e4e4" : "#f6f6f6" - border.color: "#cccccc" - - Text { - text: "-" - color: "black" - anchors.centerIn: parent - font.pixelSize: 12 + text: crankset.toString() + verticalAlignment: TextEdit.AlignVCenter + horizontalAlignment: TextEdit.AlignHCenter + selectByMouse: true + onTextChanged: { + var value = parseInt(text) + if (!isNaN(value) && value >= 1 && value <= 60) { + gearRows[index].crankset = value + gearConfigurationChanged(gearRows) } } - - background: Rectangle { - color: "white" - border.color: "#cccccc" - } } } @@ -457,65 +419,21 @@ ScrollView { border.color: "#cccccc" color: "transparent" - SpinBox { - id: cogSpinBox + TextEdit { anchors.centerIn: parent width: parent.width * 0.8 height: 30 - from: 1 - to: 50 - value: cog - onValueModified: { - gearRows[index].cog = value - gearConfigurationChanged(gearRows) - } - - // Style the SpinBox (same as cranksetSpinBox) - contentItem: TextInput { - z: 2 - text: cogSpinBox.textFromValue(cogSpinBox.value, cogSpinBox.locale) - font: cogSpinBox.font - color: "black" - selectionColor: "#21be2b" - selectedTextColor: "#ffffff" - horizontalAlignment: Qt.AlignHCenter - verticalAlignment: Qt.AlignVCenter - } - - up.indicator: Rectangle { - x: parent.width - width - height: parent.height - width: height - color: parent.up.pressed ? "#e4e4e4" : "#f6f6f6" - border.color: "#cccccc" - - Text { - text: "+" - color: "black" - anchors.centerIn: parent - font.pixelSize: 12 - } - } - - down.indicator: Rectangle { - x: 0 - height: parent.height - width: height - color: parent.down.pressed ? "#e4e4e4" : "#f6f6f6" - border.color: "#cccccc" - - Text { - text: "-" - color: "black" - anchors.centerIn: parent - font.pixelSize: 12 + text: cog.toString() + verticalAlignment: TextEdit.AlignVCenter + horizontalAlignment: TextEdit.AlignHCenter + selectByMouse: true + onTextChanged: { + var value = parseInt(text) + if (!isNaN(value) && value >= 1 && value <= 50) { + gearRows[index].cog = value + gearConfigurationChanged(gearRows) } } - - background: Rectangle { - color: "white" - border.color: "#cccccc" - } } } } From 527396eafca8480ae46e95b21322374b0cb515ba Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 28 Oct 2024 09:18:54 +0100 Subject: [PATCH 08/18] Revert "Update gears.qml" This reverts commit 0f149448b34be7c3b6bf9300d249f6f69f4e4a4e. --- src/gears.qml | 196 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 139 insertions(+), 57 deletions(-) diff --git a/src/gears.qml b/src/gears.qml index d000d8fe2..67b6103c2 100644 --- a/src/gears.qml +++ b/src/gears.qml @@ -18,8 +18,9 @@ ScrollView { property int selectedCogSize: 44 property string selectedWheelSize: "700 x 18C" property real selectedCircumference: 2070 - property int initialWheelSizeIndex: 0 + property int initialWheelSizeIndex: 0 // indice per "700 x 18C" + // Add these connections to your root item (ScrollView) Connections { target: gearSettingsWindow function onGearConfigurationChanged() { @@ -43,18 +44,20 @@ ScrollView { { gear: 12, crankset: 38, cog: 10, active: true } ] + // Initialize components Component.onCompleted: { wheelSizeCombo.currentIndex = initialWheelSizeIndex } function clearGearsFromIndex(startIndex) { - for (let i = startIndex; i < gearRows.length; i++) { - gearRows[i].active = false - } - var temp = gearRows - gearRows = [] - gearRows = temp - gearConfigurationChanged(gearRows) + for (let i = startIndex; i < gearRows.length; i++) { + gearRows[i].active = false + } + // Force update + var temp = gearRows + gearRows = [] + gearRows = temp + gearConfigurationChanged(gearRows) } function initializeGearRows() { @@ -72,11 +75,13 @@ ScrollView { { gear: 11, crankset: 38, cog: 11, active: true }, { gear: 12, crankset: 38, cog: 10, active: true } ] + // Force update var temp = gearRows gearRows = [] gearRows = temp } + // Signals to notify when values change signal settingsChanged(int crankset, int cog, string wheelSize, real circumference) signal gearConfigurationChanged(var gearRows) @@ -90,19 +95,14 @@ ScrollView { title: "Crankset Size (tooth count)" Layout.fillWidth: true - TextEdit { - text: selectedCranksetSize.toString() - width: parent.width - height: 30 - verticalAlignment: TextEdit.AlignVCenter - selectByMouse: true - onTextChanged: { - var value = parseInt(text) - if (!isNaN(value) && value >= 1 && value <= 60) { - selectedCranksetSize = value - gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, - selectedWheelSize, selectedCircumference) - } + SpinBox { + from: 1 + to: 60 + value: selectedCranksetSize + onValueChanged: { + selectedCranksetSize = value + gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + selectedWheelSize, selectedCircumference) } } } @@ -112,19 +112,14 @@ ScrollView { title: "Cog Size (tooth count)" Layout.fillWidth: true - TextEdit { - text: selectedCogSize.toString() - width: parent.width - height: 30 - verticalAlignment: TextEdit.AlignVCenter - selectByMouse: true - onTextChanged: { - var value = parseInt(text) - if (!isNaN(value) && value >= 1 && value <= 50) { - selectedCogSize = value - gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, - selectedWheelSize, selectedCircumference) - } + SpinBox { + from: 1 + to: 50 + value: selectedCogSize + onValueChanged: { + selectedCogSize = value + gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + selectedWheelSize, selectedCircumference) } } } @@ -226,7 +221,6 @@ ScrollView { ListElement { text: "29\" x 2.4\""; circumference: 2333 } ListElement { text: "29\" x 2.5\""; circumference: 2350 } ListElement { text: "29\" x 2.6\""; circumference: 2366 } - } onCurrentIndexChanged: { if (currentIndex >= 0) { @@ -250,7 +244,7 @@ ScrollView { anchors.fill: parent spacing: 10 - // Buttons + // Buttons (same as before) RowLayout { Layout.fillWidth: true Layout.preferredHeight: 40 @@ -275,7 +269,7 @@ ScrollView { } } - // Table Header + // Table Header (same as before) Rectangle { Layout.fillWidth: true Layout.preferredHeight: 40 @@ -393,21 +387,65 @@ ScrollView { border.color: "#cccccc" color: "transparent" - TextEdit { + SpinBox { + id: cranksetSpinBox anchors.centerIn: parent width: parent.width * 0.8 height: 30 - text: crankset.toString() - verticalAlignment: TextEdit.AlignVCenter - horizontalAlignment: TextEdit.AlignHCenter - selectByMouse: true - onTextChanged: { - var value = parseInt(text) - if (!isNaN(value) && value >= 1 && value <= 60) { - gearRows[index].crankset = value - gearConfigurationChanged(gearRows) + from: 1 + to: 60 + value: crankset + onValueModified: { + gearRows[index].crankset = value + gearConfigurationChanged(gearRows) + } + + // Style the SpinBox + contentItem: TextInput { + z: 2 + text: cranksetSpinBox.textFromValue(cranksetSpinBox.value, cranksetSpinBox.locale) + font: cranksetSpinBox.font + color: "black" + selectionColor: "#21be2b" + selectedTextColor: "#ffffff" + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + } + + up.indicator: Rectangle { + x: parent.width - width + height: parent.height + width: height + color: parent.up.pressed ? "#e4e4e4" : "#f6f6f6" + border.color: "#cccccc" + + Text { + text: "+" + color: "black" + anchors.centerIn: parent + font.pixelSize: 12 + } + } + + down.indicator: Rectangle { + x: 0 + height: parent.height + width: height + color: parent.down.pressed ? "#e4e4e4" : "#f6f6f6" + border.color: "#cccccc" + + Text { + text: "-" + color: "black" + anchors.centerIn: parent + font.pixelSize: 12 } } + + background: Rectangle { + color: "white" + border.color: "#cccccc" + } } } @@ -419,21 +457,65 @@ ScrollView { border.color: "#cccccc" color: "transparent" - TextEdit { + SpinBox { + id: cogSpinBox anchors.centerIn: parent width: parent.width * 0.8 height: 30 - text: cog.toString() - verticalAlignment: TextEdit.AlignVCenter - horizontalAlignment: TextEdit.AlignHCenter - selectByMouse: true - onTextChanged: { - var value = parseInt(text) - if (!isNaN(value) && value >= 1 && value <= 50) { - gearRows[index].cog = value - gearConfigurationChanged(gearRows) + from: 1 + to: 50 + value: cog + onValueModified: { + gearRows[index].cog = value + gearConfigurationChanged(gearRows) + } + + // Style the SpinBox (same as cranksetSpinBox) + contentItem: TextInput { + z: 2 + text: cogSpinBox.textFromValue(cogSpinBox.value, cogSpinBox.locale) + font: cogSpinBox.font + color: "black" + selectionColor: "#21be2b" + selectedTextColor: "#ffffff" + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + } + + up.indicator: Rectangle { + x: parent.width - width + height: parent.height + width: height + color: parent.up.pressed ? "#e4e4e4" : "#f6f6f6" + border.color: "#cccccc" + + Text { + text: "+" + color: "black" + anchors.centerIn: parent + font.pixelSize: 12 + } + } + + down.indicator: Rectangle { + x: 0 + height: parent.height + width: height + color: parent.down.pressed ? "#e4e4e4" : "#f6f6f6" + border.color: "#cccccc" + + Text { + text: "-" + color: "black" + anchors.centerIn: parent + font.pixelSize: 12 } } + + background: Rectangle { + color: "white" + border.color: "#cccccc" + } } } } From 74c37f562427dea268eb39bb5d58ca813c8fcdbe Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 28 Oct 2024 09:46:58 +0100 Subject: [PATCH 09/18] Update gears.qml --- src/gears.qml | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/gears.qml b/src/gears.qml index 67b6103c2..1fe290d65 100644 --- a/src/gears.qml +++ b/src/gears.qml @@ -49,6 +49,34 @@ ScrollView { wheelSizeCombo.currentIndex = initialWheelSizeIndex } + function addNewGear() { + // Find the first inactive gear or add at the end + let newGearIndex = gearRows.findIndex(row => !row.active); + if (newGearIndex === -1) { + newGearIndex = gearRows.length; + } + + // Create new gear with default values + const newGear = { + gear: newGearIndex + 1, + crankset: selectedCranksetSize, + cog: selectedCogSize, + active: true + }; + + if (newGearIndex < gearRows.length) { + gearRows[newGearIndex] = newGear; + } else { + gearRows.push(newGear); + } + + // Force update + var temp = gearRows; + gearRows = []; + gearRows = temp; + gearConfigurationChanged(gearRows); + } + function clearGearsFromIndex(startIndex) { for (let i = startIndex; i < gearRows.length; i++) { gearRows[i].active = false @@ -244,12 +272,19 @@ ScrollView { anchors.fill: parent spacing: 10 - // Buttons (same as before) + // Updated Buttons Row RowLayout { Layout.fillWidth: true Layout.preferredHeight: 40 spacing: 10 + Button { + text: "Add Gear" + Layout.fillWidth: true + Layout.preferredHeight: 40 + onClicked: addNewGear() + } + Button { text: "Clear Selected Gear and Following" Layout.fillWidth: true From f85f7434995712799d3f05fbd788198600b04fa0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 28 Oct 2024 11:11:05 +0100 Subject: [PATCH 10/18] i need to save the first 3 static objects and use it in the wahoo module --- src/gears.qml | 76 +++++++++++++++++++++++++++++++++++++----------- src/settings.qml | 7 +++++ 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/gears.qml b/src/gears.qml index 1fe290d65..3dbcc3c35 100644 --- a/src/gears.qml +++ b/src/gears.qml @@ -13,14 +13,61 @@ ScrollView { visible: true clip: true - // Properties to store the selected values - property int selectedCranksetSize: 38 - property int selectedCogSize: 44 - property string selectedWheelSize: "700 x 18C" - property real selectedCircumference: 2070 - property int initialWheelSizeIndex: 0 // indice per "700 x 18C" - - // Add these connections to your root item (ScrollView) + // Properties + Settings { + id: settings + property string gear_configuration: "1|38|44|true\n2|38|38|true\n3|38|32|true\n4|38|28|true\n5|38|24|true\n6|38|21|true\n7|38|19|true\n8|38|17|true\n9|38|15|true\n10|38|13|true\n11|38|11|true\n12|38|10|true" + property int gear_crankset_size: 38 + property int gear_cog_size: 44 + property string gear_wheel_size: "700 x 18C" + property real gear_circumference: 2070 + } + + property int selectedCranksetSize: settings.gear_crankset_size + property int selectedCogSize: settings.gear_cog_size + property string selectedWheelSize: settings.gear_wheel_size + property real selectedCircumference: settings.gear_circumference + property int initialWheelSizeIndex: 0 + + Component.onCompleted: { + if (settings.gear_configuration) { + gearRows = stringToGearRows(settings.gear_configuration) + } + } + + // Funzioni helper per la conversione delle gear + function stringToGearRows(gearString) { + if (!gearString) return [] + + return gearString.split("\n").map(function(row) { + const parts = row.split("|") + return { + gear: parseInt(parts[0]), + crankset: parseInt(parts[1]), + cog: parseInt(parts[2]), + active: parts[3] === "true" + } + }) + } + + function gearRowsToString(gearRows) { + return gearRows.map(function(row) { + return row.gear + "|" + row.crankset + "|" + row.cog + "|" + row.active + }).join("\n") + } + + // Monitora i cambiamenti nelle gear e salva automaticamente + onGearConfigurationChanged: { + settings.gear_configuration = gearRowsToString(gearRows) + } + + onSettingsChanged: { + settings.gear_crankset_size = crankset + settings.gear_cog_size = cog + settings.gear_wheel_size = wheelSize + settings.gear_circumference = circumference + } + Connections { target: gearSettingsWindow function onGearConfigurationChanged() { @@ -44,11 +91,6 @@ ScrollView { { gear: 12, crankset: 38, cog: 10, active: true } ] - // Initialize components - Component.onCompleted: { - wheelSizeCombo.currentIndex = initialWheelSizeIndex - } - function addNewGear() { // Find the first inactive gear or add at the end let newGearIndex = gearRows.findIndex(row => !row.active); @@ -128,8 +170,8 @@ ScrollView { to: 60 value: selectedCranksetSize onValueChanged: { - selectedCranksetSize = value - gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + selectedCranksetSize = value + settingsChanged(selectedCranksetSize, selectedCogSize, selectedWheelSize, selectedCircumference) } } @@ -146,7 +188,7 @@ ScrollView { value: selectedCogSize onValueChanged: { selectedCogSize = value - gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + settingsChanged(selectedCranksetSize, selectedCogSize, selectedWheelSize, selectedCircumference) } } @@ -254,7 +296,7 @@ ScrollView { if (currentIndex >= 0) { selectedWheelSize = model.get(currentIndex).text selectedCircumference = model.get(currentIndex).circumference - gearSettingsWindow.settingsChanged(selectedCranksetSize, selectedCogSize, + settingsChanged(selectedCranksetSize, selectedCogSize, selectedWheelSize, selectedCircumference) } } diff --git a/src/settings.qml b/src/settings.qml index 7dfe5606c..7d16e5c8c 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -987,6 +987,13 @@ import QtQuick.Dialogs 1.0 // from version 2.18.1 property bool zwift_play_emulator: false + + // from version 2.18.2 + property string gear_configuration: "1|38|44|true\n2|38|38|true\n3|38|32|true\n4|38|28|true\n5|38|24|true\n6|38|21|true\n7|38|19|true\n8|38|17|true\n9|38|15|true\n10|38|13|true\n11|38|11|true\n12|38|10|true" + property int gear_crankset_size: 38 + property int gear_cog_size: 44 + property string gear_wheel_size: "700 x 18C" + property real gear_circumference: 2070 } function paddingZeros(text, limit) { From 6fac9770bea68b0972567037b4b27e28a5da8c15 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 28 Oct 2024 15:09:13 +0100 Subject: [PATCH 11/18] qml finally saves the settings correctly --- src/gears.qml | 241 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 218 insertions(+), 23 deletions(-) diff --git a/src/gears.qml b/src/gears.qml index 3dbcc3c35..a16ed97d0 100644 --- a/src/gears.qml +++ b/src/gears.qml @@ -27,15 +27,38 @@ ScrollView { property int selectedCogSize: settings.gear_cog_size property string selectedWheelSize: settings.gear_wheel_size property real selectedCircumference: settings.gear_circumference - property int initialWheelSizeIndex: 0 + property bool inited: false + + property int initialWheelSizeIndex: { + // Trova l'indice corretto basato sul valore salvato + for (let i = 0; i < wheelSizes.count; i++) { + if (wheelSizes.get(i).text === settings.gear_wheel_size) { + return i; + } + } + return 0; // default se non trovato + } Component.onCompleted: { if (settings.gear_configuration) { gearRows = stringToGearRows(settings.gear_configuration) } + console.log("Component.onCompleted " + settings.gear_crankset_size + " " + settings.gear_cog_size + " " + settings.gear_wheel_size + " " + settings.gear_circumference) + wheelSizeCombo.currentIndex = initialWheelSizeIndex + selectedCranksetSize = settings.gear_crankset_size + selectedCogSize = settings.gear_cog_size + inited = true + } + + function updateSettings() { + if(!inited) + return; + settings.gear_crankset_size = selectedCranksetSize + settings.gear_cog_size = selectedCogSize + settings.gear_wheel_size = selectedWheelSize + settings.gear_circumference = selectedCircumference } - // Funzioni helper per la conversione delle gear function stringToGearRows(gearString) { if (!gearString) return [] @@ -62,10 +85,8 @@ ScrollView { } onSettingsChanged: { - settings.gear_crankset_size = crankset - settings.gear_cog_size = cog - settings.gear_wheel_size = wheelSize - settings.gear_circumference = circumference + console.log("onSettingsChanged") + updateSettings() } Connections { @@ -75,6 +96,150 @@ ScrollView { } } + function loadGearProfile(profileName) { + if (profileName in gearProfiles) { + const profile = gearProfiles[profileName] + + // Create new array with copied objects + var newGears = [] + for (var i = 0; i < profile.gears.length; i++) { + newGears.push({ + gear: profile.gears[i].gear, + crankset: profile.gears[i].crankset, + cog: profile.gears[i].cog, + active: profile.gears[i].active + }) + } + + gearRows = newGears + + // Update the first crankset size + if (gearRows.length > 0) { + selectedCranksetSize = gearRows[0].crankset + selectedCogSize = gearRows[0].cog + } + + // Force update + var temp = gearRows + gearRows = [] + gearRows = temp + gearConfigurationChanged(gearRows) + } + } + + property var gearProfiles: { + "Time Trial": { + name: "Time Trial (52/36, 10 - 28)", + gears: [ + { gear: 1, crankset: 36, cog: 28, active: true }, + { gear: 2, crankset: 36, cog: 24, active: true }, + { gear: 3, crankset: 36, cog: 21, active: true }, + { gear: 4, crankset: 36, cog: 19, active: true }, + { gear: 5, crankset: 36, cog: 18, active: true }, + { gear: 6, crankset: 36, cog: 17, active: true }, + { gear: 7, crankset: 36, cog: 16, active: true }, + { gear: 8, crankset: 36, cog: 15, active: true }, + { gear: 9, crankset: 36, cog: 14, active: true }, + { gear: 10, crankset: 52, cog: 19, active: true }, + { gear: 11, crankset: 52, cog: 18, active: true }, + { gear: 12, crankset: 52, cog: 17, active: true }, + { gear: 13, crankset: 52, cog: 16, active: true }, + { gear: 14, crankset: 52, cog: 15, active: true }, + { gear: 15, crankset: 52, cog: 14, active: true }, + { gear: 16, crankset: 52, cog: 13, active: true }, + { gear: 17, crankset: 52, cog: 12, active: true }, + { gear: 18, crankset: 52, cog: 11, active: true }, + { gear: 19, crankset: 52, cog: 10, active: true } + ] + }, + "Rolling Hills": { + name: "Rolling Hills (46/33, 10 - 33)", + gears: [ + { gear: 1, crankset: 33, cog: 33, active: true }, + { gear: 2, crankset: 33, cog: 28, active: true }, + { gear: 3, crankset: 33, cog: 24, active: true }, + { gear: 4, crankset: 33, cog: 21, active: true }, + { gear: 5, crankset: 33, cog: 19, active: true }, + { gear: 6, crankset: 33, cog: 17, active: true }, + { gear: 7, crankset: 33, cog: 15, active: true }, + { gear: 8, crankset: 46, cog: 19, active: true }, + { gear: 9, crankset: 46, cog: 17, active: true }, + { gear: 10, crankset: 46, cog: 15, active: true }, + { gear: 11, crankset: 46, cog: 14, active: true }, + { gear: 12, crankset: 46, cog: 13, active: true }, + { gear: 13, crankset: 46, cog: 12, active: true }, + { gear: 14, crankset: 46, cog: 11, active: true }, + { gear: 15, crankset: 46, cog: 10, active: true } + ] + }, + "Alpine": { + name: "Alpine (43/30, 10 - 36)", + gears: [ + { gear: 1, crankset: 30, cog: 36, active: true }, + { gear: 2, crankset: 30, cog: 32, active: true }, + { gear: 3, crankset: 30, cog: 28, active: true }, + { gear: 4, crankset: 30, cog: 24, active: true }, + { gear: 5, crankset: 30, cog: 21, active: true }, + { gear: 6, crankset: 30, cog: 19, active: true }, + { gear: 7, crankset: 30, cog: 17, active: true }, + { gear: 8, crankset: 30, cog: 15, active: true }, + { gear: 9, crankset: 43, cog: 19, active: true }, + { gear: 10, crankset: 43, cog: 17, active: true }, + { gear: 11, crankset: 43, cog: 15, active: true }, + { gear: 12, crankset: 43, cog: 13, active: true }, + { gear: 13, crankset: 43, cog: 12, active: true }, + { gear: 14, crankset: 43, cog: 11, active: true }, + { gear: 15, crankset: 43, cog: 10, active: true } + ] + }, + "Reality Bender": { + name: "Reality Bender (24 even spaced)", + gears: [ + { gear: 1, crankset: 30, cog: 40, active: true }, + { gear: 2, crankset: 30, cog: 36, active: true }, + { gear: 3, crankset: 30, cog: 33, active: true }, + { gear: 4, crankset: 30, cog: 30, active: true }, + { gear: 5, crankset: 30, cog: 27, active: true }, + { gear: 6, crankset: 34, cog: 28, active: true }, + { gear: 7, crankset: 34, cog: 26, active: true }, + { gear: 8, crankset: 34, cog: 24, active: true }, + { gear: 9, crankset: 34, cog: 22, active: true }, + { gear: 10, crankset: 44, cog: 26, active: true }, + { gear: 11, crankset: 44, cog: 24, active: true }, + { gear: 12, crankset: 44, cog: 22, active: true }, + { gear: 13, crankset: 44, cog: 20, active: true }, + { gear: 14, crankset: 44, cog: 18, active: true }, + { gear: 15, crankset: 56, cog: 21, active: true }, + { gear: 16, crankset: 56, cog: 19, active: true }, + { gear: 17, crankset: 58, cog: 18, active: true }, + { gear: 18, crankset: 60, cog: 17, active: true }, + { gear: 19, crankset: 62, cog: 16, active: true }, + { gear: 20, crankset: 63, cog: 15, active: true }, + { gear: 21, crankset: 64, cog: 14, active: true }, + { gear: 22, crankset: 66, cog: 13, active: true }, + { gear: 23, crankset: 67, cog: 12, active: true } + ] + }, + "Explorer": { + name: "Explorer (40, 10 - 46)", + gears: [ + { gear: 1, crankset: 40, cog: 46, active: true }, + { gear: 2, crankset: 40, cog: 38, active: true }, + { gear: 3, crankset: 40, cog: 32, active: true }, + { gear: 4, crankset: 40, cog: 28, active: true }, + { gear: 5, crankset: 40, cog: 24, active: true }, + { gear: 6, crankset: 40, cog: 21, active: true }, + { gear: 7, crankset: 40, cog: 19, active: true }, + { gear: 8, crankset: 40, cog: 17, active: true }, + { gear: 9, crankset: 40, cog: 15, active: true }, + { gear: 10, crankset: 40, cog: 13, active: true }, + { gear: 11, crankset: 40, cog: 12, active: true }, + { gear: 12, crankset: 40, cog: 11, active: true }, + { gear: 13, crankset: 40, cog: 10, active: true } + ] + } + } + // Initial gear data property var gearRows: [ { gear: 1, crankset: 38, cog: 44, active: true }, @@ -152,7 +317,7 @@ ScrollView { } // Signals to notify when values change - signal settingsChanged(int crankset, int cog, string wheelSize, real circumference) + signal settingsChanged() signal gearConfigurationChanged(var gearRows) ColumnLayout { @@ -160,6 +325,36 @@ ScrollView { anchors.margins: 20 spacing: 20 + GroupBox { + title: "Preset Gear Profiles" + Layout.fillWidth: true + + ComboBox { + id: profileCombo + width: parent.width + textRole: "text" + displayText: currentIndex < 0 ? "Select a profile..." : model.get(currentIndex).text + model: ListModel { + id: profileModel + } + + Component.onCompleted: { + for (var key in gearProfiles) { + profileModel.append({ + text: gearProfiles[key].name, + value: key + }) + } + } + + onCurrentIndexChanged: { + if (currentIndex >= 0) { + loadGearProfile(profileModel.get(currentIndex).value) + } + } + } + } + // Crankset Size GroupBox { title: "Crankset Size (tooth count)" @@ -171,8 +366,8 @@ ScrollView { value: selectedCranksetSize onValueChanged: { selectedCranksetSize = value - settingsChanged(selectedCranksetSize, selectedCogSize, - selectedWheelSize, selectedCircumference) + console.log("Crankset Size changed"); + settingsChanged() } } } @@ -188,8 +383,8 @@ ScrollView { value: selectedCogSize onValueChanged: { selectedCogSize = value - settingsChanged(selectedCranksetSize, selectedCogSize, - selectedWheelSize, selectedCircumference) + console.log("Cog Size changed"); + settingsChanged() } } } @@ -200,12 +395,12 @@ ScrollView { Layout.fillWidth: true ComboBox { - id: wheelSizeCombo - width: parent.width - currentIndex: initialWheelSizeIndex - textRole: "text" - model: ListModel { - id: wheelSizes + id: wheelSizeCombo + width: parent.width + currentIndex: initialWheelSizeIndex + textRole: "text" + model: ListModel { + id: wheelSizes ListElement { text: "700 x 18C"; circumference: 2070 } ListElement { text: "700 x 19C"; circumference: 2080 } ListElement { text: "700 x 20C"; circumference: 2086 } @@ -294,12 +489,12 @@ ScrollView { } onCurrentIndexChanged: { if (currentIndex >= 0) { - selectedWheelSize = model.get(currentIndex).text - selectedCircumference = model.get(currentIndex).circumference - settingsChanged(selectedCranksetSize, selectedCogSize, - selectedWheelSize, selectedCircumference) - } - } + selectedWheelSize = model.get(currentIndex).text + selectedCircumference = model.get(currentIndex).circumference + console.log("wheelSizeCombo changed"); + settingsChanged() + } + } } } From 2f2989f90dfe00df9dca65d99280735a5c5124a0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 28 Oct 2024 15:40:00 +0100 Subject: [PATCH 12/18] completed? --- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 7 ++- .../wahookickrsnapbike/wahookickrsnapbike.h | 60 ++++++++++++------- src/qzsettings.cpp | 14 ++++- src/qzsettings.h | 15 +++++ 4 files changed, 71 insertions(+), 25 deletions(-) diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index b8946eec4..394c48914 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -290,13 +290,14 @@ void wahookickrsnapbike::update() { } double wahookickrsnapbike::gearsToWheelDiameter(double gear) { + QSettings settings; GearTable table; if(gear < 1) gear = 1; - else if(gear > 12) gear = 12; - double original_ratio = ((double)crankset) / ((double)rear_cog_size); + else if(gear > table.maxGears) gear = table.maxGears; + double original_ratio = ((double)settings.value(QZSettings::gear_crankset_size, QZSettings::default_gear_crankset_size).toDouble()) / ((double)settings.value(QZSettings::gear_cog_size, QZSettings::default_gear_cog_size).toDouble()); GearTable::GearInfo g = table.getGear((int)gear); double current_ratio = ((double)g.crankset / (double)g.rearCog); - return (((double)wheel_size) / original_ratio) * ((double)current_ratio); + return (((double)settings.value(QZSettings::gear_wheel_size, QZSettings::default_gear_wheel_size).toDouble()) / original_ratio) * ((double)current_ratio); } void wahookickrsnapbike::serviceDiscovered(const QBluetoothUuid &gatt) { diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h index 8ece29240..9d8c3cc99 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h @@ -107,37 +107,51 @@ class wahookickrsnapbike : public bike { volatile int notificationSubscribed = 0; - resistance_t lastForcedResistance = -1; + resistance_t lastForcedResistance = -1; - // cranks & co. - double crankset = 40; - double rear_cog_size = 14; - double wheel_size = 2230; // mm 700x44 double gearsToWheelDiameter(double gear); class GearTable { public: + + int maxGears = 12; + struct GearInfo { int gear; int crankset; int rearCog; }; - GearTable() { - gears = { - {1, 38, 44}, - {2, 38, 38}, - {3, 38, 32}, - {4, 38, 28}, - {5, 38, 24}, - {6, 38, 21}, - {7, 38, 19}, - {8, 38, 17}, - {9, 38, 15}, - {10, 38, 13}, - {11, 38, 11}, - {12, 38, 10} - }; + void loadGearSettings() { + QSettings settings; + + QString gearConfig = settings.value("gear_configuration").toString(); + if (gearConfig.isEmpty()) { + + gearConfig = "1|38|44|true\n2|38|38|true\n3|38|32|true\n4|38|28|true\n" + "5|38|24|true\n6|38|21|true\n7|38|19|true\n8|38|17|true\n" + "9|38|15|true\n10|38|13|true\n11|38|11|true\n12|38|10|true"; + } + + gears.clear(); + maxGears = 0; + + // Parsa la configurazione + QStringList rows = gearConfig.split('\n'); + for (const QString& row : rows) { + QStringList parts = row.split('|'); + if (parts.size() >= 4 && (parts[3] == "true")) { + GearInfo config; + config.gear = parts[0].toInt(); + config.crankset = parts[1].toInt(); + config.rearCog = parts[2].toInt(); + + gears.push_back(config); + maxGears = qMax(maxGears, config.gear); + } + } + + printTable(); } void addGear(int gear, int crankset, int rearCog) { @@ -169,9 +183,13 @@ class wahookickrsnapbike : public bike { return GearInfo(); } + GearTable() { + loadGearSettings(); + } + private: std::vector gears; - }; + }; #ifdef Q_OS_IOS diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index ac0433131..f4b33957e 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -769,8 +769,15 @@ const QString QZSettings::default_peloton_date_format = QStringLiteral("MM/dd/yy const QString QZSettings::force_resistance_instead_inclination = QStringLiteral("force_resistance_instead_inclination"); const QString QZSettings::proform_treadmill_575i = QStringLiteral("proform_treadmill_575i"); const QString QZSettings::zwift_play_emulator = QStringLiteral("zwift_play_emulator"); +const QString QZSettings::gear_configuration = QStringLiteral("gear_configuration"); +const QString QZSettings::default_gear_configuration = QStringLiteral("1|38|44|true\n2|38|38|true\n3|38|32|true\n4|38|28|true\n5|38|24|true\n6|38|21|true\n7|38|19|true\n8|38|17|true\n9|38|15|true\n10|38|13|true\n11|38|11|true\n12|38|10|true"); +const QString QZSettings::gear_crankset_size = QStringLiteral("gear_crankset_size"); +const QString QZSettings::gear_cog_size = QStringLiteral("gear_cog_size"); +const QString QZSettings::gear_wheel_size = QStringLiteral("gear_wheel_size"); +const QString QZSettings::default_gear_wheel_size = QStringLiteral("700 x 18C"); +const QString QZSettings::gear_circumference = QStringLiteral("gear_circumference"); -const uint32_t allSettingsCount = 651; +const uint32_t allSettingsCount = 656; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1428,6 +1435,11 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::force_resistance_instead_inclination, QZSettings::default_force_resistance_instead_inclination}, {QZSettings::proform_treadmill_575i, QZSettings::default_proform_treadmill_575i}, {QZSettings::zwift_play_emulator, QZSettings::default_zwift_play_emulator}, + {QZSettings::gear_configuration, QZSettings::default_gear_configuration}, + {QZSettings::gear_crankset_size, QZSettings::default_gear_crankset_size}, + {QZSettings::gear_cog_size, QZSettings::default_gear_cog_size}, + {QZSettings::gear_wheel_size, QZSettings::default_gear_wheel_size}, + {QZSettings::gear_circumference, QZSettings::default_gear_circumference}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index 8fdb021ed..e0b40e3ab 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2153,6 +2153,21 @@ class QZSettings { static const QString zwift_play_emulator; static constexpr bool default_zwift_play_emulator = false; + static const QString gear_configuration; + static const QString default_gear_configuration; + + static const QString gear_crankset_size; + static constexpr int default_gear_crankset_size = 38; + + static const QString gear_cog_size; + static constexpr int default_gear_cog_size = 44; + + static const QString gear_wheel_size; + static const QString default_gear_wheel_size; + + static const QString gear_circumference; + static constexpr double default_gear_circumference = 2070.0; + /** * @brief Write the QSettings values using the constants from this namespace. * @param showDefaults Optionally indicates if the default should be shown with the key. From 379cf8d7de3a658e8b21513aa3dc0471478ecf24 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 29 Oct 2024 08:02:08 +0100 Subject: [PATCH 13/18] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 26250a8bb..4bea73964 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4068,7 +4068,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 919; + CURRENT_PROJECT_VERSION = 920; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4259,7 +4259,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 919; + CURRENT_PROJECT_VERSION = 920; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4486,7 +4486,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 919; + CURRENT_PROJECT_VERSION = 920; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4582,7 +4582,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 919; + CURRENT_PROJECT_VERSION = 920; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4674,7 +4674,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 919; + CURRENT_PROJECT_VERSION = 920; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4788,7 +4788,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 919; + CURRENT_PROJECT_VERSION = 920; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 64b9ec9d72685afc1d08a56f07dc5d108f2f4756 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 29 Oct 2024 08:17:38 +0100 Subject: [PATCH 14/18] fixing gear conversion --- src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp | 4 +++- src/devices/wahookickrsnapbike/wahookickrsnapbike.h | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 394c48914..92f21ace5 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -31,6 +31,8 @@ wahookickrsnapbike::wahookickrsnapbike(bool noWriteResistance, bool noHeartServi initDone = false; connect(refresh, &QTimer::timeout, this, &wahookickrsnapbike::update); refresh->start(200ms); + GearTable g; + g.printTable(); } bool wahookickrsnapbike::writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log, @@ -297,7 +299,7 @@ double wahookickrsnapbike::gearsToWheelDiameter(double gear) { double original_ratio = ((double)settings.value(QZSettings::gear_crankset_size, QZSettings::default_gear_crankset_size).toDouble()) / ((double)settings.value(QZSettings::gear_cog_size, QZSettings::default_gear_cog_size).toDouble()); GearTable::GearInfo g = table.getGear((int)gear); double current_ratio = ((double)g.crankset / (double)g.rearCog); - return (((double)settings.value(QZSettings::gear_wheel_size, QZSettings::default_gear_wheel_size).toDouble()) / original_ratio) * ((double)current_ratio); + return (((double)settings.value(QZSettings::gear_circumference, QZSettings::default_gear_circumference).toDouble()) / original_ratio) * ((double)current_ratio); } void wahookickrsnapbike::serviceDiscovered(const QBluetoothUuid &gatt) { diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h index 9d8c3cc99..27fac2416 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h @@ -150,8 +150,6 @@ class wahookickrsnapbike : public bike { maxGears = qMax(maxGears, config.gear); } } - - printTable(); } void addGear(int gear, int crankset, int rearCog) { From d7c3a84adb456b7fbee32bba24c60b72e4cc6d28 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 29 Oct 2024 08:21:59 +0100 Subject: [PATCH 15/18] adding max and minGears --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/bike.cpp | 8 ++++++++ src/devices/bike.h | 2 ++ .../wahookickrsnapbike/wahookickrsnapbike.cpp | 9 +++++++++ src/devices/wahookickrsnapbike/wahookickrsnapbike.h | 2 ++ 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 4bea73964..93a6fc936 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4068,7 +4068,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 920; + CURRENT_PROJECT_VERSION = 921; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4259,7 +4259,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 920; + CURRENT_PROJECT_VERSION = 921; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4486,7 +4486,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 920; + CURRENT_PROJECT_VERSION = 921; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4582,7 +4582,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 920; + CURRENT_PROJECT_VERSION = 921; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4674,7 +4674,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 920; + CURRENT_PROJECT_VERSION = 921; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4788,7 +4788,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 920; + CURRENT_PROJECT_VERSION = 921; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index b64d715d5..597bf2151 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -106,6 +106,14 @@ void bike::setGears(double gears) { qDebug() << "new gear value ignored because of gears_zwift_ratio setting!"; return; } + if(gears > maxGears()) { + qDebug() << "new gear value ignored because of maxGears" << maxGears(); + return; + } + if(gears < minGears()) { + qDebug() << "new gear value ignored because of minGears" << minGears(); + return; + } m_gears = gears; if(homeform::singleton()) { homeform::singleton()->updateGearsValue(); diff --git a/src/devices/bike.h b/src/devices/bike.h index c296a9138..f075bd784 100644 --- a/src/devices/bike.h +++ b/src/devices/bike.h @@ -23,6 +23,8 @@ class bike : public bluetoothdevice { double currentCrankRevolutions() override; uint16_t lastCrankEventTime() override; bool connected() override; + virtual double maxGears() { return 9999.0; } + virtual double minGears() { return -9999.0; } virtual uint16_t watts(); virtual resistance_t pelotonToBikeResistance(int pelotonResistance); virtual resistance_t resistanceFromPowerRequest(uint16_t power); diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 92f21ace5..16f116434 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -854,3 +854,12 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) { bool wahookickrsnapbike::inclinationAvailableByHardware() { return KICKR_BIKE; } + +double wahookickrsnapbike::maxGears() { + GearTable g; + return g.maxGears; +} + +double wahookickrsnapbike::minGears() { + return 1; +} diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h index 27fac2416..b77f8322f 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h @@ -42,6 +42,8 @@ class wahookickrsnapbike : public bike { bool connected() override; resistance_t maxResistance() override { return 100; } bool inclinationAvailableByHardware() override; + double maxGears() override; + double minGears() override; enum OperationCode : uint8_t { _unlock = 32, From a7b8e6323526961868f272132e38bd844258bd05 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 29 Oct 2024 08:50:33 +0100 Subject: [PATCH 16/18] fixing UI and settings --- src/gears.qml | 136 +++++++++++++++++++++++++++-------------------- src/qzsettings.h | 4 +- src/settings.qml | 4 +- 3 files changed, 81 insertions(+), 63 deletions(-) diff --git a/src/gears.qml b/src/gears.qml index a16ed97d0..6f1d6ea0f 100644 --- a/src/gears.qml +++ b/src/gears.qml @@ -17,8 +17,8 @@ ScrollView { Settings { id: settings property string gear_configuration: "1|38|44|true\n2|38|38|true\n3|38|32|true\n4|38|28|true\n5|38|24|true\n6|38|21|true\n7|38|19|true\n8|38|17|true\n9|38|15|true\n10|38|13|true\n11|38|11|true\n12|38|10|true" - property int gear_crankset_size: 38 - property int gear_cog_size: 44 + property int gear_crankset_size: 42 + property int gear_cog_size: 14 property string gear_wheel_size: "700 x 18C" property real gear_circumference: 2070 } @@ -113,12 +113,6 @@ ScrollView { gearRows = newGears - // Update the first crankset size - if (gearRows.length > 0) { - selectedCranksetSize = gearRows[0].crankset - selectedCogSize = gearRows[0].cog - } - // Force update var temp = gearRows gearRows = [] @@ -324,74 +318,62 @@ ScrollView { anchors.fill: parent anchors.margins: 20 spacing: 20 - - GroupBox { - title: "Preset Gear Profiles" - Layout.fillWidth: true - - ComboBox { - id: profileCombo - width: parent.width - textRole: "text" - displayText: currentIndex < 0 ? "Select a profile..." : model.get(currentIndex).text - model: ListModel { - id: profileModel - } - - Component.onCompleted: { - for (var key in gearProfiles) { - profileModel.append({ - text: gearProfiles[key].name, - value: key - }) - } - } - - onCurrentIndexChanged: { - if (currentIndex >= 0) { - loadGearProfile(profileModel.get(currentIndex).value) - } - } - } - } + id: chainringColumn // Crankset Size GroupBox { - title: "Crankset Size (tooth count)" + title: "Chainring Size" Layout.fillWidth: true - SpinBox { - from: 1 - to: 60 - value: selectedCranksetSize - onValueChanged: { - selectedCranksetSize = value - console.log("Crankset Size changed"); - settingsChanged() + ColumnLayout { + Label { + text: "Tooth count of your chainring on the bike you are currently riding on your trainer - enter 42 for Zwift Ride" + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.maximumWidth: chainringColumn.width - 20 + } + + SpinBox { + from: 1 + to: 60 + value: selectedCranksetSize + onValueChanged: { + selectedCranksetSize = value + console.log("Crankset Size changed"); + settingsChanged() + } } } } // Cog Size GroupBox { - title: "Cog Size (tooth count)" + title: "Cog Size" Layout.fillWidth: true - SpinBox { - from: 1 - to: 50 - value: selectedCogSize - onValueChanged: { - selectedCogSize = value - console.log("Cog Size changed"); - settingsChanged() + ColumnLayout { + Label { + text: "Tooth count of your rear cog on your trainer - enter 14 if you have the Zwift Cog" + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.maximumWidth: chainringColumn.width - 20 + } + SpinBox { + from: 1 + to: 50 + value: selectedCogSize + onValueChanged: { + selectedCogSize = value + console.log("Cog Size changed"); + settingsChanged() + } } } } // Wheel Size GroupBox { - title: "Wheel Size" + title: "Virtual Wheel Size" Layout.fillWidth: true ComboBox { @@ -498,9 +480,40 @@ ScrollView { } } + GroupBox { + title: "Preset Gear Profiles" + Layout.fillWidth: true + + ComboBox { + id: profileCombo + width: parent.width + textRole: "text" + displayText: currentIndex < 0 ? "Select a profile..." : model.get(currentIndex).text + model: ListModel { + id: profileModel + } + + Component.onCompleted: { + for (var key in gearProfiles) { + profileModel.append({ + text: gearProfiles[key].name, + value: key + }) + } + } + + onCurrentIndexChanged: { + if (currentIndex >= 0) { + loadGearProfile(profileModel.get(currentIndex).value) + } + } + } + } + + // Gear Table GroupBox GroupBox { - title: "Gear Table" + title: "Virtual Gear Table" Layout.fillWidth: true Layout.fillHeight: true Layout.preferredHeight: parent.height @@ -576,7 +589,7 @@ ScrollView { Text { anchors.centerIn: parent - text: "Crankset" + text: "Chainring" font.bold: true color: "black" } @@ -610,6 +623,11 @@ ScrollView { id: gearListModel } + ScrollBar.vertical: ScrollBar { + policy: ScrollBar.AlwaysOff + } + + Component.onCompleted: { updateGearListModel() } diff --git a/src/qzsettings.h b/src/qzsettings.h index e0b40e3ab..eb2ebf1b1 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2157,10 +2157,10 @@ class QZSettings { static const QString default_gear_configuration; static const QString gear_crankset_size; - static constexpr int default_gear_crankset_size = 38; + static constexpr int default_gear_crankset_size = 42; static const QString gear_cog_size; - static constexpr int default_gear_cog_size = 44; + static constexpr int default_gear_cog_size = 14; static const QString gear_wheel_size; static const QString default_gear_wheel_size; diff --git a/src/settings.qml b/src/settings.qml index 7d16e5c8c..6a872938e 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -990,8 +990,8 @@ import QtQuick.Dialogs 1.0 // from version 2.18.2 property string gear_configuration: "1|38|44|true\n2|38|38|true\n3|38|32|true\n4|38|28|true\n5|38|24|true\n6|38|21|true\n7|38|19|true\n8|38|17|true\n9|38|15|true\n10|38|13|true\n11|38|11|true\n12|38|10|true" - property int gear_crankset_size: 38 - property int gear_cog_size: 44 + property int gear_crankset_size: 42 + property int gear_cog_size: 14 property string gear_wheel_size: "700 x 18C" property real gear_circumference: 2070 } From 82a6afe6b6ab5432771ba959ce460d4326dfea43 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 29 Oct 2024 12:28:13 +0100 Subject: [PATCH 17/18] kickr core to wahookickr class --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/bluetooth.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 93a6fc936..fa6126769 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4068,7 +4068,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 921; + CURRENT_PROJECT_VERSION = 922; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4259,7 +4259,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 921; + CURRENT_PROJECT_VERSION = 922; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4486,7 +4486,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 921; + CURRENT_PROJECT_VERSION = 922; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4582,7 +4582,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 921; + CURRENT_PROJECT_VERSION = 922; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4674,7 +4674,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 921; + CURRENT_PROJECT_VERSION = 922; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4788,7 +4788,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 921; + CURRENT_PROJECT_VERSION = 922; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 4690b16b8..f1472dad4 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1511,7 +1511,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith(ftmsAccessoryName.toUpper()) && settings.value(QZSettings::ss2k_peloton, QZSettings::default_ss2k_peloton) .toBool()) || // ss2k on a peloton bike - ((b.name().toUpper().startsWith("KICKR CORE")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || (b.name().toUpper().startsWith("MERACH-MR667-")) || (b.name().toUpper().startsWith("DS60-")) || (b.name().toUpper().startsWith("BIKE-")) || @@ -1562,6 +1561,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { this->signalBluetoothDeviceConnected(ftmsBike); } else if ((b.name().toUpper().startsWith("KICKR SNAP") || b.name().toUpper().startsWith("KICKR BIKE") || b.name().toUpper().startsWith("KICKR ROLLR") || + b.name().toUpper().startsWith("KICKR CORE") || (b.name().toUpper().startsWith("HAMMER ") && saris_trainer) || (b.name().toUpper().startsWith("WAHOO KICKR"))) && !wahooKickrSnapBike && !ftmsBike && filter) { From 9cc02dede925eb33b4b9462ffbe1d4e542b433b7 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 30 Oct 2024 15:57:31 +0100 Subject: [PATCH 18/18] ftms wheel circumference for gears --- src/devices/ftmsbike/ftmsbike.cpp | 29 +++-- src/devices/ftmsbike/ftmsbike.h | 2 + .../wahookickrsnapbike/wahookickrsnapbike.cpp | 19 +-- .../wahookickrsnapbike/wahookickrsnapbike.h | 82 +----------- src/qdomyos-zwift.pri | 1 + src/wheelcircumference.h | 120 ++++++++++++++++++ 6 files changed, 148 insertions(+), 105 deletions(-) create mode 100644 src/wheelcircumference.h diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index a118cb1f9..58f85b776 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -35,6 +35,8 @@ ftmsbike::ftmsbike(bool noWriteResistance, bool noHeartService, int8_t bikeResis initDone = false; connect(refresh, &QTimer::timeout, this, &ftmsbike::update); refresh->start(settings.value(QZSettings::poll_device_time, QZSettings::default_poll_device_time).toInt()); + wheelCircumference::GearTable g; + g.printTable(); } void ftmsbike::writeCharacteristicZwiftPlay(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log, @@ -170,6 +172,18 @@ void ftmsbike::zwiftPlayInit() { } } +void ftmsbike::setWheelDiameter(double diameter) { + uint8_t write[] = {FTMS_SET_WHEEL_CIRCUMFERENCE, 0x00, 0x00}; + + diameter = diameter * 10.0; + + write[1] = ((uint16_t)diameter) & 0xFF; + write[2] = ((uint16_t)diameter) >> 8; + + writeCharacteristic(write, sizeof(write), QStringLiteral("setWheelCircumference ") + QString::number(diameter)); +} + + void ftmsbike::forcePower(int16_t requestPower) { if(resistance_lvl_mode) { forceResistance(resistanceFromPowerRequest(requestPower)); @@ -285,14 +299,16 @@ void ftmsbike::update() { if (((virtualBike && !virtualBike->ftmsDeviceConnected()) || !virtualBike) && (requestPower == 0 || requestPower == -1)) { init(); - forceResistance(requestResistance + (gears() * 5)); + if(requestResistance != - 1) + forceResistance(requestResistance + (gears() * 5)); + else + setWheelDiameter(wheelCircumference::gearsToWheelDiameter(gears())); } } requestResistance = -1; } if((virtualBike && virtualBike->ftmsDeviceConnected()) && lastGearValue != gears() && lastRawRequestedInclinationValue != -100 && lastPacketFromFTMS.length() >= 7) { - qDebug() << "injecting fake ftms frame in order to send the new gear value ASAP" << lastPacketFromFTMS.toHex(' '); - ftmsCharacteristicChanged(QLowEnergyCharacteristic(), lastPacketFromFTMS); + setWheelDiameter(wheelCircumference::gearsToWheelDiameter(gears())); } QSettings settings; @@ -1065,13 +1081,8 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact lastPacketFromFTMS.append(b.at(i)); qDebug() << "lastPacketFromFTMS" << lastPacketFromFTMS.toHex(' '); int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8)); - if (gears() != 0) { - slope += (gears() * 50); - } b[3] = slope & 0xFF; - b[4] = slope >> 8; - - qDebug() << "applying gears mod" << gears() << slope; + b[4] = slope >> 8; /*} else if(b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && zwiftPlayService != nullptr && gears_zwift_ratio) { int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8)); uint8_t gear2[] = {0x04, 0x22, 0x02, 0x10, 0x00}; diff --git a/src/devices/ftmsbike/ftmsbike.h b/src/devices/ftmsbike/ftmsbike.h index fe21e284b..fa4fd4e06 100644 --- a/src/devices/ftmsbike/ftmsbike.h +++ b/src/devices/ftmsbike/ftmsbike.h @@ -26,6 +26,7 @@ #include #include +#include "wheelcircumference.h" #include "devices/bike.h" #ifdef Q_OS_IOS @@ -85,6 +86,7 @@ class ftmsbike : public bike { void init(); void forceResistance(resistance_t requestResistance); void forcePower(int16_t requestPower); + void setWheelDiameter(double diameter); uint16_t wattsFromResistance(double resistance); QTimer *refresh; diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 16f116434..f15abc55c 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -31,7 +31,7 @@ wahookickrsnapbike::wahookickrsnapbike(bool noWriteResistance, bool noHeartServi initDone = false; connect(refresh, &QTimer::timeout, this, &wahookickrsnapbike::update); refresh->start(200ms); - GearTable g; + wheelCircumference::GearTable g; g.printTable(); } @@ -194,7 +194,7 @@ void wahookickrsnapbike::update() { } QThread::msleep(700); - QByteArray d = setWheelCircumference(gearsToWheelDiameter(gears())); + QByteArray d = setWheelCircumference(wheelCircumference::gearsToWheelDiameter(gears())); uint8_t e[20]; setGears(1); memcpy(e, d.constData(), d.length()); @@ -267,7 +267,7 @@ void wahookickrsnapbike::update() { memcpy(b, a.constData(), a.length()); writeCharacteristic(b, a.length(), "setResistance", false, true); } else if (virtualBike && virtualBike->ftmsDeviceConnected() && lastGearValue != gears()) { - QByteArray a = setWheelCircumference(gearsToWheelDiameter(gears())); + QByteArray a = setWheelCircumference(wheelCircumference::gearsToWheelDiameter(gears())); uint8_t b[20]; memcpy(b, a.constData(), a.length()); writeCharacteristic(b, a.length(), "setWheelCircumference", false, true); @@ -291,17 +291,6 @@ void wahookickrsnapbike::update() { } } -double wahookickrsnapbike::gearsToWheelDiameter(double gear) { - QSettings settings; - GearTable table; - if(gear < 1) gear = 1; - else if(gear > table.maxGears) gear = table.maxGears; - double original_ratio = ((double)settings.value(QZSettings::gear_crankset_size, QZSettings::default_gear_crankset_size).toDouble()) / ((double)settings.value(QZSettings::gear_cog_size, QZSettings::default_gear_cog_size).toDouble()); - GearTable::GearInfo g = table.getGear((int)gear); - double current_ratio = ((double)g.crankset / (double)g.rearCog); - return (((double)settings.value(QZSettings::gear_circumference, QZSettings::default_gear_circumference).toDouble()) / original_ratio) * ((double)current_ratio); -} - void wahookickrsnapbike::serviceDiscovered(const QBluetoothUuid &gatt) { emit debug(QStringLiteral("serviceDiscovered ") + gatt.toString()); } @@ -856,7 +845,7 @@ bool wahookickrsnapbike::inclinationAvailableByHardware() { } double wahookickrsnapbike::maxGears() { - GearTable g; + wheelCircumference::GearTable g; return g.maxGears; } diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h index b77f8322f..16522fa4c 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h @@ -26,6 +26,7 @@ #include #include +#include "wheelcircumference.h" #include "devices/bike.h" #include "virtualdevices/virtualbike.h" @@ -111,87 +112,6 @@ class wahookickrsnapbike : public bike { resistance_t lastForcedResistance = -1; - double gearsToWheelDiameter(double gear); - - class GearTable { - public: - - int maxGears = 12; - - struct GearInfo { - int gear; - int crankset; - int rearCog; - }; - - void loadGearSettings() { - QSettings settings; - - QString gearConfig = settings.value("gear_configuration").toString(); - if (gearConfig.isEmpty()) { - - gearConfig = "1|38|44|true\n2|38|38|true\n3|38|32|true\n4|38|28|true\n" - "5|38|24|true\n6|38|21|true\n7|38|19|true\n8|38|17|true\n" - "9|38|15|true\n10|38|13|true\n11|38|11|true\n12|38|10|true"; - } - - gears.clear(); - maxGears = 0; - - // Parsa la configurazione - QStringList rows = gearConfig.split('\n'); - for (const QString& row : rows) { - QStringList parts = row.split('|'); - if (parts.size() >= 4 && (parts[3] == "true")) { - GearInfo config; - config.gear = parts[0].toInt(); - config.crankset = parts[1].toInt(); - config.rearCog = parts[2].toInt(); - - gears.push_back(config); - maxGears = qMax(maxGears, config.gear); - } - } - } - - void addGear(int gear, int crankset, int rearCog) { - gears.push_back({gear, crankset, rearCog}); - } - - void removeGear(int gear) { - gears.erase(std::remove_if(gears.begin(), gears.end(), - [gear](const GearInfo& info) { return info.gear == gear; }), - gears.end()); - } - - void printTable() const { - qDebug() << "| Gear | Crankset | Rear Cog |\n"; - qDebug() << "|------|----------|----------|\n"; - for (const auto& gear : gears) { - qDebug() << "| " << gear.gear << " | " << gear.crankset - << " | " << gear.rearCog << " |\n"; - } - } - - GearInfo getGear(int gearNumber) const { - auto it = std::find_if(gears.begin(), gears.end(), - [gearNumber](const GearInfo& info) { return info.gear == gearNumber; }); - - if (it != gears.end()) { - return *it; - } - return GearInfo(); - } - - GearTable() { - loadGearSettings(); - } - - private: - std::vector gears; - }; - - #ifdef Q_OS_IOS lockscreen *h = 0; #endif diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index fa8d97c41..47108ef8a 100644 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -313,6 +313,7 @@ HEADERS += \ $$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.h \ $$PWD/ergtable.h \ $$PWD/treadmillErgTable.h \ + $$PWD/wheelcircumference.h \ QTelnet.h \ devices/bkoolbike/bkoolbike.h \ devices/csaferower/csafe.h \ diff --git a/src/wheelcircumference.h b/src/wheelcircumference.h new file mode 100644 index 000000000..a43c4d4e0 --- /dev/null +++ b/src/wheelcircumference.h @@ -0,0 +1,120 @@ +#ifndef WHEELCIRCUMFERENCE_H +#define WHEELCIRCUMFERENCE_H + +#include + +#ifndef Q_OS_ANDROID +#include +#else +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "qzsettings.h" + +class wheelCircumference : public QObject { + + Q_OBJECT + + public: + static double gearsToWheelDiameter(double gear) { + QSettings settings; + GearTable table; + if(gear < 1) gear = 1; + else if(gear > table.maxGears) gear = table.maxGears; + double original_ratio = ((double)settings.value(QZSettings::gear_crankset_size, QZSettings::default_gear_crankset_size).toDouble()) / ((double)settings.value(QZSettings::gear_cog_size, QZSettings::default_gear_cog_size).toDouble()); + GearTable::GearInfo g = table.getGear((int)gear); + double current_ratio = ((double)g.crankset / (double)g.rearCog); + return (((double)settings.value(QZSettings::gear_circumference, QZSettings::default_gear_circumference).toDouble()) / original_ratio) * ((double)current_ratio); + } + + + class GearTable { + public: + + int maxGears = 12; + + struct GearInfo { + int gear; + int crankset; + int rearCog; + }; + + void loadGearSettings() { + QSettings settings; + + QString gearConfig = settings.value("gear_configuration").toString(); + if (gearConfig.isEmpty()) { + + gearConfig = "1|38|44|true\n2|38|38|true\n3|38|32|true\n4|38|28|true\n" + "5|38|24|true\n6|38|21|true\n7|38|19|true\n8|38|17|true\n" + "9|38|15|true\n10|38|13|true\n11|38|11|true\n12|38|10|true"; + } + + gears.clear(); + maxGears = 0; + + // Parsa la configurazione + QStringList rows = gearConfig.split('\n'); + for (const QString& row : rows) { + QStringList parts = row.split('|'); + if (parts.size() >= 4 && (parts[3] == "true")) { + GearInfo config; + config.gear = parts[0].toInt(); + config.crankset = parts[1].toInt(); + config.rearCog = parts[2].toInt(); + + gears.push_back(config); + maxGears = qMax(maxGears, config.gear); + } + } + } + + void addGear(int gear, int crankset, int rearCog) { + gears.push_back({gear, crankset, rearCog}); + } + + void removeGear(int gear) { + gears.erase(std::remove_if(gears.begin(), gears.end(), + [gear](const GearInfo& info) { return info.gear == gear; }), + gears.end()); + } + + void printTable() const { + qDebug() << "| Gear | Crankset | Rear Cog |\n"; + qDebug() << "|------|----------|----------|\n"; + for (const auto& gear : gears) { + qDebug() << "| " << gear.gear << " | " << gear.crankset + << " | " << gear.rearCog << " |\n"; + } + } + + GearInfo getGear(int gearNumber) const { + auto it = std::find_if(gears.begin(), gears.end(), + [gearNumber](const GearInfo& info) { return info.gear == gearNumber; }); + + if (it != gears.end()) { + return *it; + } + return GearInfo(); + } + + GearTable() { + loadGearSettings(); + } + + private: + std::vector gears; + }; +}; + +#endif // WHEELCIRCUMFERENCE_H