Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,55 @@ The ProForm 995i implementation serves as the reference example:
- Test device detection thoroughly using the existing test infrastructure
- Consider platform differences when adding new features

## Updating Version Numbers

When releasing a new version of QDomyos-Zwift, you must update the version number in **3 files**:

### 1. Android Manifest
**File**: `src/android/AndroidManifest.xml`

Update both `versionName` and `versionCode`:
```xml
<manifest ... android:versionName="X.XX.XX" android:versionCode="XXXX" ...>
```

- `versionName`: The human-readable version (e.g., "2.20.26")
- `versionCode`: Integer build number that must be incremented (e.g., 1274)

### 2. Main QML File
**File**: `src/main.qml`

Update the version text displayed in the UI (around line 938):
```qml
ItemDelegate {
text: "version X.XX.XX"
width: parent.width
}
```

### 3. Qt Project Include File
**File**: `src/qdomyos-zwift.pri`

Update the VERSION variable (around line 1011):
```pri
VERSION = X.XX.XX
```

### Version Numbering Convention

- **Major.Minor.Patch** format (e.g., 2.20.26)
- **Build number** must always increment, never reuse
- Update all 3 files together to keep versions synchronized

### iOS Version (Optional)

iOS version is managed through Xcode project variables:
- `MARKETING_VERSION` in project.pbxproj (corresponds to versionName)
- `CURRENT_PROJECT_VERSION` in project.pbxproj (corresponds to versionCode)

These are typically updated via Xcode IDE rather than manually editing files.

## Additional Memories

- When adding a new setting in QML (setting-tiles.qml), you must:
* Add the property at the END of the properties list
* Add the property at the END of the properties list
2 changes: 1 addition & 1 deletion src/android/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionName="2.20.25" android:versionCode="1273" android:installLocation="auto">
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionName="2.20.26" android:versionCode="1274" android:installLocation="auto">
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
Expand Down
1 change: 1 addition & 0 deletions src/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ dependencies {
implementation 'com.jakewharton.timber:timber:5.0.1'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.60'
implementation 'org.bouncycastle:bcprov-jdk15on:1.60'
implementation("com.garmin.connectiq:ciq-companion-app-sdk:2.2.0@aar")
}

import org.apache.tools.ant.taskdefs.condition.Os
Expand Down
Binary file removed src/android/libs/ciq-companion-app-sdk-2.0.3.aar
Binary file not shown.
69 changes: 55 additions & 14 deletions src/android/src/IQMessageReceiverWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,73 @@ public IQMessageReceiverWrapper(BroadcastReceiver receiver) {

@Override
public void onReceive(Context context, Intent intent) {
QLog.d(TAG, "onReceive intent " + intent.getAction());
if ("com.garmin.android.connectiq.SEND_MESSAGE_STATUS".equals(intent.getAction())) {
replaceIQDeviceById(intent, "com.garmin.android.connectiq.EXTRA_REMOTE_DEVICE");
} else if ("com.garmin.android.connectiq.OPEN_APPLICATION".equals(intent.getAction())) {
replaceIQDeviceById(intent, "com.garmin.android.connectiq.EXTRA_OPEN_APPLICATION_DEVICE");
} else if ("com.garmin.android.connectiq.DEVICE_STATUS".equals(intent.getAction())) {
replaceIQDeviceById(intent, "com.garmin.android.connectiq.EXTRA_REMOTE_DEVICE");
}

try {
QLog.d(TAG, "=== GARMIN INTENT DEBUG START ===");
QLog.d(TAG, "Action: " + intent.getAction());

// Log all extras in the intent
if (intent.getExtras() != null) {
QLog.d(TAG, "Extras bundle: " + intent.getExtras());
try {
for (String key : intent.getExtras().keySet()) {
Object value = intent.getExtras().get(key);
QLog.d(TAG, " Extra[" + key + "] = " + value + " (type: " + (value != null ? value.getClass().getName() : "null") + ")");
}
} catch (Exception e) {
QLog.e(TAG, "Error iterating extras: " + e.toString());
}
} else {
QLog.d(TAG, "No extras in intent");
}

// Process known actions
if ("com.garmin.android.connectiq.SEND_MESSAGE_STATUS".equals(intent.getAction())) {
QLog.d(TAG, "Processing SEND_MESSAGE_STATUS");
replaceIQDeviceById(intent, "com.garmin.android.connectiq.EXTRA_REMOTE_DEVICE");
} else if ("com.garmin.android.connectiq.OPEN_APPLICATION".equals(intent.getAction())) {
QLog.d(TAG, "Processing OPEN_APPLICATION");
replaceIQDeviceById(intent, "com.garmin.android.connectiq.EXTRA_OPEN_APPLICATION_DEVICE");
} else if ("com.garmin.android.connectiq.DEVICE_STATUS".equals(intent.getAction())) {
QLog.d(TAG, "Processing DEVICE_STATUS");
replaceIQDeviceById(intent, "com.garmin.android.connectiq.EXTRA_REMOTE_DEVICE");
} else if ("com.garmin.android.connectiq.INCOMING_MESSAGE".equals(intent.getAction())) {
QLog.d(TAG, "Processing INCOMING_MESSAGE");
replaceIQDeviceById(intent, "com.garmin.android.connectiq.EXTRA_REMOTE_DEVICE");
} else {
QLog.d(TAG, "Unknown action, no processing");
}

QLog.d(TAG, "Calling wrapped receiver.onReceive()");
receiver.onReceive(context, intent);
QLog.d(TAG, "=== GARMIN INTENT DEBUG END (success) ===");

} catch (Exception e) {
QLog.d(TAG, "Exception in Garmin message receiver: " + e.toString());
QLog.e(TAG, "=== EXCEPTION in wrapper (BEFORE or DURING receiver call) ===");
QLog.e(TAG, "Exception type: " + e.getClass().getName());
QLog.e(TAG, "Exception message: " + e.getMessage());
QLog.e(TAG, "Stack trace:", e);
QLog.e(TAG, "=== GARMIN INTENT DEBUG END (error) ===");
}
}

private static void replaceIQDeviceById(Intent intent, String extraName) {
try {
QLog.d(TAG, " Attempting to get Parcelable for extra: " + extraName);
IQDevice device = intent.getParcelableExtra(extraName);
if (device != null) {
// Logger.logDebug("Replacing " + device.describeContents() + " " + device.getFriendlyName() + " by " + device.getDeviceIdentifier() );
intent.putExtra(extraName, device.getDeviceIdentifier());
QLog.d(TAG, " Found IQDevice: " + device.getFriendlyName() + " (ID: " + device.getDeviceIdentifier() + ")");
long deviceId = device.getDeviceIdentifier();
intent.putExtra(extraName, deviceId);
QLog.d(TAG, " Replaced IQDevice with Long ID: " + deviceId);
} else {
QLog.d(TAG, " Extra '" + extraName + "' is null or not an IQDevice");
}
} catch (ClassCastException e) {
QLog.d(TAG, e.toString());
// It's already a long, i.e. on the simulator.
QLog.d(TAG, " ClassCastException for '" + extraName + "': " + e.toString());
QLog.d(TAG, " (Extra is already a Long, probably on simulator)");
} catch (Exception e) {
QLog.e(TAG, " Unexpected exception in replaceIQDeviceById: " + e.toString());
QLog.e(TAG, " Stack trace:", e);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,7 @@ ApplicationWindow {
}

ItemDelegate {
text: "version 2.20.25"
text: "version 2.20.26"
width: parent.width
}

Expand Down
2 changes: 1 addition & 1 deletion src/qdomyos-zwift.pri
Original file line number Diff line number Diff line change
Expand Up @@ -1008,4 +1008,4 @@ INCLUDEPATH += purchasing/inapp

WINRT_MANIFEST = AppxManifest.xml

VERSION = 2.20.25
VERSION = 2.20.26
Loading