Skip to content

Conversation

@lposen
Copy link
Contributor

@lposen lposen commented Aug 21, 2025

🔹 JIRA Ticket(s) if any

✏️ Description

Restructure RNIterableAPIModule to delegate functionality to RNIterableAPIModuleImpl. This is to minimize duplicate code when splitting the functionality between new architecture and legacy architecture later on.

Testing

Testing Legacy Architecture

  1. Enable Legacy Architecture:

    # Check example/android/gradle.properties
    newArchEnabled=false
  2. Build and run:

    cd example
    cd android && ./gradlew clean && cd ..
    watchman watch-del-all
    yarn start --reset-cache
    
    # In another terminal:
    yarn android
  3. Verify app launches and do a quick click through of various items

Testing New Architecture

  1. Enable new architecture:

    # Edit example/android/gradle.properties
    newArchEnabled=true
  2. Clean and rebuild:

    cd example
    cd android && ./gradlew clean && cd ..
    watchman watch-del-all
    yarn start --reset-cache
    
    # In another terminal:
    yarn android
  3. Verify app launches and do a quick click through of various items

@lposen lposen marked this pull request as ready for review August 21, 2025 22:05
@lposen lposen requested a review from Copilot August 21, 2025 22:05
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR restructures the RNIterableAPIModule to delegate its functionality to a new RNIterableAPIModuleImpl class. This refactoring separates the React Native bridge interface from the core implementation logic, preparing for future architectural changes that will split functionality between new and legacy architectures.

  • Extracts all implementation logic from RNIterableAPIModule into RNIterableAPIModuleImpl
  • Transforms RNIterableAPIModule into a thin wrapper that delegates calls to the implementation
  • Maintains the same public API while enabling code reuse for upcoming architecture splits

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
RNIterableAPIModuleImpl.java New implementation class containing all the core functionality moved from RNIterableAPIModule
RNIterableAPIModule.java Refactored to delegate all method calls to RNIterableAPIModuleImpl instance

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

}

@Override
public void onInboxUpdated() {
Copy link

Copilot AI Aug 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The onInboxUpdated method should not be public as it appears to be a callback method that should only be called internally. This method should have package-private or private visibility.

Suggested change
public void onInboxUpdated() {
void onInboxUpdated() {

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

github-actions bot commented Aug 21, 2025

Lines Statements Branches Functions
Coverage: 38%
37.98% (177/466) 13.04% (24/184) 32.9% (51/155)

@qlty-cloud-legacy
Copy link

11 new issues

Tool Category Rule Count
qlty Structure Function with many parameters (count = 5): initialize2WithApiKey 9
qlty Structure Function with high complexity (count = 5): initializeWithApiKey 2

This is from Qlty Cloud, the successor to Code Climate Quality. Learn more.

// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);
@ReactMethod
public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): initialize2WithApiKey [qlty:function-parameters]

@ReactMethod
public void trackPushOpenWithCampaignId(Integer campaignId, Integer templateId, String messageId, Boolean appAlreadyRunning, ReadableMap dataFields) {
RNIterableInternal.trackPushOpenWithCampaignId(campaignId, templateId, messageId, optSerializedDataFields(dataFields));
public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): trackPushOpenWithCampaignId [qlty:function-parameters]

finalCampaignId,
finalTemplateId
);
public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 6): updateSubscriptions [qlty:function-parameters]

}

IterableApi.getInstance().trackInAppClose(inAppMessage, clickedUrl, closeAction, inAppCloseLocation);
public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 4): trackInAppClose [qlty:function-parameters]

Comment on lines +75 to +102
public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, String version, Promise promise) {
IterableLogger.d(TAG, "initializeWithApiKey: " + apiKey);
IterableConfig.Builder configBuilder = Serialization.getConfigFromReadableMap(configReadableMap);

if (configReadableMap.hasKey("urlHandlerPresent") && configReadableMap.getBoolean("urlHandlerPresent") == true) {
configBuilder.setUrlHandler(this);
}

if (configReadableMap.hasKey("customActionHandlerPresent") && configReadableMap.getBoolean("customActionHandlerPresent") == true) {
configBuilder.setCustomActionHandler(this);
}

if (configReadableMap.hasKey("inAppHandlerPresent") && configReadableMap.getBoolean("inAppHandlerPresent") == true) {
configBuilder.setInAppHandler(this);
}

if (configReadableMap.hasKey("authHandlerPresent") && configReadableMap.getBoolean("authHandlerPresent") == true) {
configBuilder.setAuthHandler(this);
}

IterableApi.initialize(reactContext, apiKey, configBuilder.build());
IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);

// MOB-10421: Figure out what the error cases are and handle them appropriately
// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Function with high complexity (count = 5): initializeWithApiKey [qlty:function-complexity]


2. Function with many parameters (count = 4): initializeWithApiKey [qlty:function-parameters]

Comment on lines 105 to 137
public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) {
IterableLogger.d(TAG, "initialize2WithApiKey: " + apiKey);
IterableConfig.Builder configBuilder = Serialization.getConfigFromReadableMap(configReadableMap);

if (configReadableMap.hasKey("urlHandlerPresent") && configReadableMap.getBoolean("urlHandlerPresent") == true) {
configBuilder.setUrlHandler(this);
}

if (configReadableMap.hasKey("customActionHandlerPresent") && configReadableMap.getBoolean("customActionHandlerPresent") == true) {
configBuilder.setCustomActionHandler(this);
}

if (configReadableMap.hasKey("inAppHandlerPresent") && configReadableMap.getBoolean("inAppHandlerPresent") == true) {
configBuilder.setInAppHandler(this);
}

if (configReadableMap.hasKey("authHandlerPresent") && configReadableMap.getBoolean("authHandlerPresent") == true) {
configBuilder.setAuthHandler(this);
}

// Set the API endpoint override if provided
// if (apiEndPointOverride != null && !apiEndPointOverride.isEmpty()) {
// configBuilder.setApiEndpoint(apiEndPointOverride);
// }

IterableApi.initialize(reactContext, apiKey, configBuilder.build());
IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);

// MOB-10421: Figure out what the error cases are and handle them appropriately
// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Function with high complexity (count = 5): initialize2WithApiKey [qlty:function-complexity]


2. Function with many parameters (count = 5): initialize2WithApiKey [qlty:function-parameters]

IterableApi.getInstance().trackPurchase(total, Serialization.commerceItemsFromReadableArray(items), optSerializedDataFields(dataFields));
}

public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): trackPushOpenWithCampaignId [qlty:function-parameters]

RNIterableInternal.trackPushOpenWithCampaignId((int) campaignId, templateId != null ? templateId.intValue() : null, messageId, optSerializedDataFields(dataFields));
}

public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 6): updateSubscriptions [qlty:function-parameters]

IterableApi.getInstance().trackInAppClick(message, clickedUrl, inAppOpenLocation);
}

public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 4): trackInAppClose [qlty:function-parameters]

// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);
@ReactMethod
public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): initialize2WithApiKey [qlty:function-parameters]

@ReactMethod
public void trackPushOpenWithCampaignId(Integer campaignId, Integer templateId, String messageId, Boolean appAlreadyRunning, ReadableMap dataFields) {
RNIterableInternal.trackPushOpenWithCampaignId(campaignId, templateId, messageId, optSerializedDataFields(dataFields));
public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): trackPushOpenWithCampaignId [qlty:function-parameters]

finalCampaignId,
finalTemplateId
);
public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 6): updateSubscriptions [qlty:function-parameters]

}

IterableApi.getInstance().trackInAppClose(inAppMessage, clickedUrl, closeAction, inAppCloseLocation);
public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 4): trackInAppClose [qlty:function-parameters]

Comment on lines +75 to +102
public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, String version, Promise promise) {
IterableLogger.d(TAG, "initializeWithApiKey: " + apiKey);
IterableConfig.Builder configBuilder = Serialization.getConfigFromReadableMap(configReadableMap);

if (configReadableMap.hasKey("urlHandlerPresent") && configReadableMap.getBoolean("urlHandlerPresent") == true) {
configBuilder.setUrlHandler(this);
}

if (configReadableMap.hasKey("customActionHandlerPresent") && configReadableMap.getBoolean("customActionHandlerPresent") == true) {
configBuilder.setCustomActionHandler(this);
}

if (configReadableMap.hasKey("inAppHandlerPresent") && configReadableMap.getBoolean("inAppHandlerPresent") == true) {
configBuilder.setInAppHandler(this);
}

if (configReadableMap.hasKey("authHandlerPresent") && configReadableMap.getBoolean("authHandlerPresent") == true) {
configBuilder.setAuthHandler(this);
}

IterableApi.initialize(reactContext, apiKey, configBuilder.build());
IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);

// MOB-10421: Figure out what the error cases are and handle them appropriately
// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Function with high complexity (count = 5): initializeWithApiKey [qlty:function-complexity]


2. Function with many parameters (count = 4): initializeWithApiKey [qlty:function-parameters]

Comment on lines +105 to +136
public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) {
IterableLogger.d(TAG, "initialize2WithApiKey: " + apiKey);
IterableConfig.Builder configBuilder = Serialization.getConfigFromReadableMap(configReadableMap);

if (configReadableMap.hasKey("urlHandlerPresent") && configReadableMap.getBoolean("urlHandlerPresent") == true) {
configBuilder.setUrlHandler(this);
}

if (configReadableMap.hasKey("customActionHandlerPresent") && configReadableMap.getBoolean("customActionHandlerPresent") == true) {
configBuilder.setCustomActionHandler(this);
}

if (configReadableMap.hasKey("inAppHandlerPresent") && configReadableMap.getBoolean("inAppHandlerPresent") == true) {
configBuilder.setInAppHandler(this);
}

if (configReadableMap.hasKey("authHandlerPresent") && configReadableMap.getBoolean("authHandlerPresent") == true) {
configBuilder.setAuthHandler(this);
}

// NOTE: There does not seem to be a way to set the API endpoint
// override in the Android SDK. Check with @Ayyanchira and @evantk91 to
// see what the best approach is.

IterableApi.initialize(reactContext, apiKey, configBuilder.build());
IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);

// MOB-10421: Figure out what the error cases are and handle them appropriately
// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Function with high complexity (count = 5): initialize2WithApiKey [qlty:function-complexity]


2. Function with many parameters (count = 5): initialize2WithApiKey [qlty:function-parameters]

IterableApi.getInstance().trackPurchase(total, Serialization.commerceItemsFromReadableArray(items), optSerializedDataFields(dataFields));
}

public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): trackPushOpenWithCampaignId [qlty:function-parameters]

RNIterableInternal.trackPushOpenWithCampaignId((int) campaignId, templateId != null ? templateId.intValue() : null, messageId, optSerializedDataFields(dataFields));
}

public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 6): updateSubscriptions [qlty:function-parameters]

IterableApi.getInstance().trackInAppClick(message, clickedUrl, inAppOpenLocation);
}

public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 4): trackInAppClose [qlty:function-parameters]

// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);
@ReactMethod
public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): initialize2WithApiKey [qlty:function-parameters]

@ReactMethod
public void trackPushOpenWithCampaignId(Integer campaignId, Integer templateId, String messageId, Boolean appAlreadyRunning, ReadableMap dataFields) {
RNIterableInternal.trackPushOpenWithCampaignId(campaignId, templateId, messageId, optSerializedDataFields(dataFields));
public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): trackPushOpenWithCampaignId [qlty:function-parameters]

finalCampaignId,
finalTemplateId
);
public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 6): updateSubscriptions [qlty:function-parameters]

}

IterableApi.getInstance().trackInAppClose(inAppMessage, clickedUrl, closeAction, inAppCloseLocation);
public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 4): trackInAppClose [qlty:function-parameters]

Comment on lines +75 to +102
public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, String version, Promise promise) {
IterableLogger.d(TAG, "initializeWithApiKey: " + apiKey);
IterableConfig.Builder configBuilder = Serialization.getConfigFromReadableMap(configReadableMap);

if (configReadableMap.hasKey("urlHandlerPresent") && configReadableMap.getBoolean("urlHandlerPresent") == true) {
configBuilder.setUrlHandler(this);
}

if (configReadableMap.hasKey("customActionHandlerPresent") && configReadableMap.getBoolean("customActionHandlerPresent") == true) {
configBuilder.setCustomActionHandler(this);
}

if (configReadableMap.hasKey("inAppHandlerPresent") && configReadableMap.getBoolean("inAppHandlerPresent") == true) {
configBuilder.setInAppHandler(this);
}

if (configReadableMap.hasKey("authHandlerPresent") && configReadableMap.getBoolean("authHandlerPresent") == true) {
configBuilder.setAuthHandler(this);
}

IterableApi.initialize(reactContext, apiKey, configBuilder.build());
IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);

// MOB-10421: Figure out what the error cases are and handle them appropriately
// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Function with high complexity (count = 5): initializeWithApiKey [qlty:function-complexity]


2. Function with many parameters (count = 4): initializeWithApiKey [qlty:function-parameters]

Comment on lines +105 to +136
public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) {
IterableLogger.d(TAG, "initialize2WithApiKey: " + apiKey);
IterableConfig.Builder configBuilder = Serialization.getConfigFromReadableMap(configReadableMap);

if (configReadableMap.hasKey("urlHandlerPresent") && configReadableMap.getBoolean("urlHandlerPresent") == true) {
configBuilder.setUrlHandler(this);
}

if (configReadableMap.hasKey("customActionHandlerPresent") && configReadableMap.getBoolean("customActionHandlerPresent") == true) {
configBuilder.setCustomActionHandler(this);
}

if (configReadableMap.hasKey("inAppHandlerPresent") && configReadableMap.getBoolean("inAppHandlerPresent") == true) {
configBuilder.setInAppHandler(this);
}

if (configReadableMap.hasKey("authHandlerPresent") && configReadableMap.getBoolean("authHandlerPresent") == true) {
configBuilder.setAuthHandler(this);
}

// NOTE: There does not seem to be a way to set the API endpoint
// override in the Android SDK. Check with @Ayyanchira and @evantk91 to
// see what the best approach is.

IterableApi.initialize(reactContext, apiKey, configBuilder.build());
IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);

// MOB-10421: Figure out what the error cases are and handle them appropriately
// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Function with high complexity (count = 5): initialize2WithApiKey [qlty:function-complexity]


2. Function with many parameters (count = 5): initialize2WithApiKey [qlty:function-parameters]

IterableApi.getInstance().trackPurchase(total, Serialization.commerceItemsFromReadableArray(items), optSerializedDataFields(dataFields));
}

public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 5): trackPushOpenWithCampaignId [qlty:function-parameters]

RNIterableInternal.trackPushOpenWithCampaignId((int) campaignId, templateId != null ? templateId.intValue() : null, messageId, optSerializedDataFields(dataFields));
}

public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 6): updateSubscriptions [qlty:function-parameters]

IterableApi.getInstance().trackInAppClick(message, clickedUrl, inAppOpenLocation);
}

public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function with many parameters (count = 4): trackInAppClose [qlty:function-parameters]

Copy link
Contributor

@evantk91 evantk91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just skimmed. Let me know if you need a deeper review. Confirmed both legacy and new architecture run successfully.

@lposen lposen merged commit e7eec5d into new-arch/master Sep 3, 2025
5 checks passed
@lposen lposen deleted the new-arch/MOB-11954-extract-rniterableapimodule-so-that-its-major-func branch September 3, 2025 00:17
@lposen lposen mentioned this pull request Oct 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants