Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: do not show modal message if change screens and page rule enabled #731

Merged
merged 7 commits into from
Jun 17, 2024

Conversation

levibostian
Copy link
Contributor

@levibostian levibostian commented May 31, 2024

Part of: https://linear.app/customerio/issue/MBL-355/ios-fix-in-app-message-displayed-on-wrong-page

When a customer sets a page rule on a Modal in-app message, they expect that the Modal is only shown on that 1 screen. The problem is there is a chance that a Modal will be displayed over another screen because rendering of in-app messages takes some time and a user can navigate to another screen in that time. This change dismisses a modal if the page changes.

Testing:

  • QA testing. The test cases are identical to all of the automated integration tests I wrote.
  • Wrote automated integration tests. As the number of unique QA test cases increased more then I anticipated, the more I felt manual QA testing this change is unsustainable in the long-term. With this change, I believe the existing QA test suite we have today for modal tests will cover all we need into the future after this gets merged.

Note to reviewers, if you're wondering why I went with the solution that I did, see this comment. TL;DR, there are 2 ways to solve this problem. I tried both ways and the solution I ended up using handles all test cases while the other does not.

@levibostian levibostian self-assigned this May 31, 2024
Copy link

github-actions bot commented May 31, 2024

Sample app builds 📱

Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request.


  • CocoaPods-FCM: levi/inapp-strict-pagerules (1718637376)
  • APN-UIKit: levi/inapp-strict-pagerules (1718637377)

@levibostian levibostian changed the title WIP dismiss message if change screen. feat: do not show modal message if change screens and page rule enabled May 31, 2024
@levibostian levibostian requested a review from a team May 31, 2024 20:08
Copy link

github-actions bot commented May 31, 2024

SDK binary size reports 📊

SDK binary size of this PR
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  17.0%   143Ki  17.0%   143Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/autogenerated/AutoMockable.generated.swift
   4.2%  35.0Ki   4.2%  35.0Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/autogenerated/AutoMockable.generated.swift
   4.1%  34.7Ki   4.1%  34.7Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventBusHandler.swift
   2.7%  22.8Ki   2.7%  22.8Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Migration/autogenerated/AutoMockable.generated.swift
   2.7%  22.7Ki   2.7%  22.7Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/DataPipelineImplementation.swift
   2.7%  22.5Ki   2.7%  22.5Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/autogenerated/AutoMockable.generated.swift
   2.5%  20.9Ki   2.5%  20.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/QueueStorage.swift
   2.3%  19.0Ki   2.3%  19.0Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushFCM/autogenerated/AutoMockable.generated.swift
   2.2%  18.9Ki   2.2%  18.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/autogenerated/AutoMockable.generated.swift
   2.2%  18.6Ki   2.2%  18.6Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/Event.swift
   2.1%  18.0Ki   2.1%  18.0Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/AnyEncodable.swift
   2.1%  17.5Ki   2.1%  17.5Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/MessageManager.swift
   1.8%  15.2Ki   1.8%  15.2Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Type/PushNotification.swift
   1.7%  14.7Ki   1.7%  14.7Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Gist.swift
   1.7%  14.6Ki   1.7%  14.6Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventMemoryStorage.swift
   1.6%  13.8Ki   1.6%  13.8Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/autogenerated/AutoDependencyInjection.generated.swift
   1.6%  13.5Ki   1.6%  13.5Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventStorage.swift
   1.5%  12.9Ki   1.5%  12.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/TrackDeliveryEventRequestBody.swift
   1.5%  12.3Ki   1.5%  12.3Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/MessageQueueManager.swift
   1.4%  11.8Ki   1.4%  11.8Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/DataPipeline.swift
   1.2%  10.3Ki   1.2%  10.3Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/PushEventHandlerProxy.swift
   1.1%  9.65Ki   1.1%  9.65Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/JsonAdapter.swift
   1.1%  9.50Ki   1.1%  9.50Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/CustomerIOInstance.swift
   1.0%  8.63Ki   1.0%  8.63Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/URLComponents.swift
   1.0%  8.61Ki   1.0%  8.61Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/AutoTrackingScreenViews.swift
   1.0%  8.53Ki   1.0%  8.53Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/UserNotificationsFramework/Wrappers.swift
   1.0%  8.22Ki   1.0%  8.22Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Migration/DataPipelineMigrationAssistant.swift
   0.9%  7.92Ki   0.9%  7.92Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushHttpClient.swift
   0.9%  7.77Ki   0.9%  7.77Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Queue.swift
   0.9%  7.26Ki   0.9%  7.26Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineWeb.swift
   0.8%  7.06Ki   0.8%  7.06Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTaskMetadata.swift
   0.8%  6.84Ki   0.8%  6.84Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Store/PushHistory.swift
   0.8%  6.46Ki   0.8%  6.46Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/MessagingInAppImplementation.swift
   0.8%  6.41Ki   0.8%  6.41Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/ModalViewManager.swift
   0.7%  6.14Ki   0.7%  6.14Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Log.swift
   0.7%  5.70Ki   0.7%  5.70Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Migration/TrackEventMigrationType.swift
   0.7%  5.64Ki   0.7%  5.64Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTask.swift
   0.6%  5.39Ki   0.6%  5.39Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/autogenerated/AutoDependencyInjection.generated.swift
   0.6%  5.16Ki   0.6%  5.16Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Response/ErrorMessageResponse.swift
   0.6%  5.15Ki   0.6%  5.15Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/KeyValueStorage.swift
   0.6%  4.86Ki   0.6%  4.86Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/GistQueueNetwork.swift
   0.6%  4.71Ki   0.6%  4.71Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Config/MessagingPushConfigBuilder.swift
   0.5%  4.49Ki   0.5%  4.49Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/DataPipelinePublishedEvents.swift
   0.5%  4.44Ki   0.5%  4.44Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/MetricRequest.swift
   0.5%  4.43Ki   0.5%  4.43Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventBus.swift
   0.5%  4.40Ki   0.5%  4.40Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/DeviceContexualAttributes.swift
   0.5%  4.40Ki   0.5%  4.40Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/Models/Message.swift
   0.5%  4.22Ki   0.5%  4.22Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/FileStorage.swift
   0.5%  4.22Ki   0.5%  4.22Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/iOSPushEventListener.swift
   0.5%  3.79Ki   0.5%  3.79Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/QueueManager.swift
   0.4%  3.79Ki   0.4%  3.79Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineWebConfiguration.swift
   0.4%  3.75Ki   0.4%  3.75Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Module/ModuleTopLevelObject.swift
   0.4%  3.71Ki   0.4%  3.71Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Views/GistModalViewController.swift
   0.4%  3.70Ki   0.4%  3.70Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/HttpRequestRunner.swift
   0.4%  3.55Ki   0.4%  3.55Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/MessagingPush.swift
   0.4%  3.37Ki   0.4%  3.37Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/StringExtensions.swift
   0.4%  3.34Ki   0.4%  3.34Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Config/MessagingInAppConfigBuilder.swift
   0.4%  3.32Ki   0.4%  3.32Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Atomic.swift
   0.4%  3.22Ki   0.4%  3.22Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/MessagingPush+RichPush.swift
   0.4%  3.10Ki   0.4%  3.10Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/StringAnyEncodable.swift
   0.4%  3.06Ki   0.4%  3.06Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/DIManager.swift
   0.4%  3.02Ki   0.4%  3.02Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineEventHandler.swift
   0.4%  2.98Ki   0.4%  2.98Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/Context.swift
   0.4%  2.98Ki   0.4%  2.98Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/BaseNetwork.swift
   0.3%  2.89Ki   0.3%  2.89Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/DeviceInfo.swift
   0.3%  2.88Ki   0.3%  2.88Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Task Data/DeletePushNotificationQueueTaskData.swift
   0.3%  2.84Ki   0.3%  2.84Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Task Data/IdentifyProfileQueueTaskData.swift
   0.3%  2.84Ki   0.3%  2.84Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Task Data/TrackEventQueueTaskData.swift
   0.3%  2.65Ki   0.3%  2.65Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/HttpRequestParams.swift
   0.3%  2.64Ki   0.3%  2.64Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/ManualPushHandling+UserNotifications.swift
   0.3%  2.58Ki   0.3%  2.58Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Task Data/RegisterPushNotificationQueueTaskData.swift
   0.3%  2.55Ki   0.3%  2.55Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/HttpRequestError.swift
   0.3%  2.52Ki   0.3%  2.52Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Util/DeviceAttributesProvider.swift
   0.3%  2.34Ki   0.3%  2.34Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushRequestHandler.swift
   0.3%  2.30Ki   0.3%  2.30Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/MessagingPushAPN.swift
   0.3%  2.29Ki   0.3%  2.29Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Config/SDKConfigBuilder.swift
   0.3%  2.25Ki   0.3%  2.25Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/MessagingPushImplementation.swift
   0.3%  2.23Ki   0.3%  2.23Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/UserNotificationsFramework/UserNotificationsFrameworkAdapter.swift
   0.3%  2.20Ki   0.3%  2.20Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushFCM/MessagingPushFCM.swift
   0.2%  2.09Ki   0.2%  2.09Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTaskRunResults.swift
   0.2%  1.95Ki   0.2%  1.95Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/LockManager.swift
   0.2%  1.80Ki   0.2%  1.80Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/MessagingPush+APN.swift
   0.2%  1.77Ki   0.2%  1.77Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushDeliveryTracker.swift
   0.2%  1.71Ki   0.2%  1.71Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/autogenerated/AutoDependencyInjection.generated.swift
   0.2%  1.66Ki   0.2%  1.66Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Models/UserQueueResponse.swift
   0.2%  1.65Ki   0.2%  1.65Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushFCM/MessagingPush+FCM.swift
   0.2%  1.62Ki   0.2%  1.62Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/DateExtensions.swift
   0.2%  1.57Ki   0.2%  1.57Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Views/GistView.swift
   0.2%  1.49Ki   0.2%  1.49Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/PushMetric.swift
   0.2%  1.48Ki   0.2%  1.48Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Provider/InAppProvider.swift
   0.2%  1.46Ki   0.2%  1.46Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/MessagingInApp.swift
   0.2%  1.42Ki   0.2%  1.42Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/CIOApiEndpoint.swift
   0.2%  1.42Ki   0.2%  1.42Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/autogenerated/AutoMockable.generated.swift
   0.2%  1.37Ki   0.2%  1.37Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/PushClickHandler.swift
   0.2%  1.34Ki   0.2%  1.34Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Store/SdkConfig.swift
   0.2%  1.34Ki   0.2%  1.34Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushRequest.swift
   0.2%  1.32Ki   0.2%  1.32Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/InAppMetric.swift
   0.2%  1.30Ki   0.2%  1.30Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Mocks.swift
   0.1%  1.24Ki   0.1%  1.24Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/UIKitWrapper.swift
   0.1%  1.24Ki   0.1%  1.24Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/ThreadUtil.swift
   0.1%  1.22Ki   0.1%  1.22Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/DictionaryExtension.swift
   0.1%  1.21Ki   0.1%  1.21Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Store/GlobalDataStore.swift
   0.1%  1.18Ki   0.1%  1.18Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/KeyValueStorageKey.swift
   0.1%  1.14Ki   0.1%  1.14Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Config/DataPipelineConfigOptions.swift
   0.1%  1.12Ki   0.1%  1.12Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/DeviceExtension.swift
   0.1%  1.12Ki   0.1%  1.12Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Type/Region.swift
   0.1%  1.04Ki   0.1%  1.04Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushFCM/MessagingPushFCM+PushConfigs.swift
   0.1%  1.02Ki   0.1%  1.02Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/DIGraphShared.swift
   0.1%  1.02Ki   0.1%  1.02Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineRoute.swift
   0.1%    1024   0.1%    1024    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/AnyEncodable.swift
   0.1%     936   0.1%     936    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/UserAgentUtil.swift
   0.1%     936   0.1%     936    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/MessagingPushAPN+PushConfigs.swift
   0.1%     908   0.1%     908    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Utilities/HTTPMethod.swift
   0.1%     880   0.1%     880    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTaskType.swift
   0.1%     872   0.1%     872    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/EmptyRequestBody.swift
   0.1%     832   0.1%     832    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/CustomerIO+Events.swift
   0.1%     832   0.1%     832    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Util/DeepLinkUtil.swift
   0.1%     820   0.1%     820    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/ArrayExtensions.swift
   0.1%     792   0.1%     792    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Endpoints/Utilities/GistNetworkRequest.swift
   0.1%     772   0.1%     772    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/Logger.swift
   0.1%     764   0.1%     764    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Type/InAppMessage.swift
   0.1%     752   0.1%     752    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/Environment.swift
   0.1%     748   0.1%     748    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/LogManager.swift
   0.1%     652   0.1%     652    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Type/CustomerIOParsedPushPayload.swift
   0.1%     624   0.1%     624    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Utilities/ElapsedTimer.swift
   0.1%     612   0.1%     612    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/CustomerIO.swift
   0.1%     600   0.1%     600    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/DownloadFileType.swift
   0.1%     576   0.1%     576    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/UIKitExtensions.swift
   0.1%     572   0.1%     572    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Config/MessagingPushConfigOptions.swift
   0.1%     568   0.1%     568    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Endpoints/QueueEndpoint.swift
   0.1%     508   0.1%     508    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Endpoints/Utilities/GistNetworkRequestError.swift
   0.1%     504   0.1%     504    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Store/ProfileStore.swift
   0.1%     496   0.1%     496    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueStatus.swift
   0.1%     484   0.1%     484    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/CustomerIO+Segment.swift
   0.1%     484   0.1%     484    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/RouteManager.swift
   0.1%     480   0.1%     480    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/RingBuffer.swift
   0.1%     480   0.1%     480    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/Encodable.swift
   0.1%     468   0.1%     468    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Endpoints/LogEndpoint.swift
   0.0%     380   0.0%     380    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Config/MessagingInAppConfigOptions.swift
   0.0%     332   0.0%     332    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Extensions/GistExtensions.swift
   0.0%     248   0.0%     248    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/Logger.swift
   0.0%     236   0.0%     236    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Util/NotificationCenterWrapper.swift
   0.0%     228   0.0%     228    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/NetworkSettings.swift
   0.0%     204   0.0%     204    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Lock.swift
   0.0%     196   0.0%     196    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/DeviceMetricsGrabber.swift
   0.0%     192   0.0%     192    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/AutomaticPushClickHandling.swift
   0.0%     164   0.0%     164    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Store/QueueInventoryMemoryStore.swift
   0.0%     128   0.0%     128    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Timer.swift
   0.0%     120   0.0%     120    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/DataExtensions.swift
   0.0%     116   0.0%     116    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/CustomerIODestination.swift
   0.0%      76   0.0%      76    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/UserManager.swift
   0.0%      68   0.0%      68    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/SingleScheduleTimer.swift
   0.0%      64   0.0%      64    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/DateUtil.swift
   0.0%      52   0.0%      52    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Version.swift
   0.0%      48   0.0%      48    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineWebProvider.swift
   0.0%      36   0.0%      36    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Time.swift
   0.0%      20   0.0%      20    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Deprecated/CustomerIO+Tracking.swift
   0.0%       8   0.0%       8    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/ErrorExtension.swift
 100.0%   842Ki 100.0%   842Ki    TOTAL
Filtering enabled (source_filter); omitted file = 2.52Mi, vm = 2.58Mi of entries

SDK binary size diff report between this PR and the main branch
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  +7.3%   +1024  +7.3%   +1024    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Gist.swift
   +27%    +972   +27%    +972    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/Models/Message.swift
  +5.2%    +904  +5.2%    +904    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/AnyEncodable.swift
  +3.3%    +732  +3.3%    +732    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/autogenerated/AutoMockable.generated.swift
  +2.2%    +392  +2.2%    +392    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/MessageManager.swift
   +24%    +200   +24%    +200    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineRoute.swift
  +2.2%    +160  +2.2%    +160    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineWeb.swift
  +2.2%    +140  +2.2%    +140    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/MessagingInAppImplementation.swift
  +6.2%     +88  +6.2%     +88    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Provider/InAppProvider.swift
  +2.3%     +84  +2.3%     +84    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Views/GistModalViewController.swift
  +1.2%     +76  +1.2%     +76    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/ModalViewManager.swift
  +4.4%     +72  +4.4%     +72    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Models/UserQueueResponse.swift
  +0.7%     +64  +0.7%     +64    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/AutoTrackingScreenViews.swift
  [NEW]     +48  [NEW]     +48    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineWebProvider.swift
  -7.9% -1.05Ki  -7.9% -1.05Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/MessageQueueManager.swift
  +0.5% +3.79Ki  +0.5% +3.79Ki    TOTAL
Filtering enabled (source_filter); omitted file = 2.52Mi, vm = 2.58Mi of entries

Copy link

codecov bot commented May 31, 2024

Codecov Report

Attention: Patch coverage is 95.00000% with 5 lines in your changes missing coverage. Please review.

Project coverage is 61.30%. Comparing base (c1f69c1) to head (2919692).
Report is 5 commits behind head on main.

Files Patch % Lines
...agingInApp/Gist/Managers/MessageQueueManager.swift 90.47% 2 Missing ⚠️
Sources/MessagingInApp/Gist/Gist.swift 95.45% 1 Missing ⚠️
.../MessagingInApp/Gist/Managers/MessageManager.swift 93.75% 1 Missing ⚠️
...essagingInApp/Gist/Managers/ModalViewManager.swift 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #731      +/-   ##
==========================================
+ Coverage   56.95%   61.30%   +4.34%     
==========================================
  Files         139      140       +1     
  Lines        3880     3962      +82     
==========================================
+ Hits         2210     2429     +219     
+ Misses       1670     1533     -137     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@Shahroz16 Shahroz16 left a comment

Choose a reason for hiding this comment

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

Before I look into the changes thoroughly, wanted to check on something. I believe the changes (which could be great to have) are out of scope for this.

Why couldn't we just check the route on MessageManager.routeLoaded and if it was changed, then we dismiss and return? something like what Android is doing?

I am okay to changes made to make make the classes testable, but changes to changing route and other areas is expanding scope to test and verify

@Shahroz16 Shahroz16 self-requested a review June 3, 2024 16:50
Part of: https://linear.app/customerio/issue/MBL-355/ios-fix-in-app-message-displayed-on-wrong-page

When a customer sets a page rule on a Modal in-app message, they expect that the Modal is only shown on that 1 screen. The problem is there is a chance that a Modal will be displayed over another screen because rendering of in-app messages takes some time and a user can navigate to another screen in that time. This change dismisses a modal if the page changes.

Testing:
* QA testing. The test cases are identical to all of the automated integration tests I wrote.
* Wrote automated integration tests. As the number of unique QA test cases increased more then I anticipated, the more I felt manual QA testing this change is unsustainable in the long-term. With this change, I believe the existing QA test suite we have today for modal tests will cover all we need into the future after this gets merged.

Note to reviewers, if you're wondering why I went with the solution that I did, see this [comment](https://linear.app/customerio/issue/MBL-353/android-fix-in-app-message-displayed-on-wrong-page#comment-99f1512d). TL;DR, there are 2 ways to solve this problem. I tried both ways and the solution I ended up using handles all test cases while the other does not.
@levibostian levibostian force-pushed the levi/inapp-strict-pagerules branch from ca93d92 to 2db44f9 Compare June 3, 2024 19:36
@levibostian levibostian marked this pull request as ready for review June 3, 2024 19:40
Comment on lines 153 to 162
if messageManagerToCancel.isShowingMessage {
// The modal is already visible, don't cancel it.
// This can prevent an infinite loop scenario:
// * page rule changed and that triggers showing a Modal
// * Modal message is displayed on screen
// * Modal being displayed triggers an auto screenview tracking event. This triggers a SDK page route change
// * Request to cancel modal message
// * Back to the foreground screen that originally triggered showing a Modal message...repeat...
return
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code gets removed in another PR in stack #732

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code originally existed to prevent an infinite loop but it does not handle test case explained in this PR description.

@@ -60,6 +68,16 @@ class MessageManager: EngineWebDelegate {
}
}

func cancelShowingMessage() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should be making these methods synchronized, cancel loadModalMessage since we relying on them for route logic. Could be considered out of scope because previously we were also just relying on messageLoaded but I think since we are relying on it for multiple actions, the chance of hitting race condition are gonna increase.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do agree, better threading support in the in-app SDK is needed. I also agree this is out-of-scope because I don't think there is a quick win for MessageManager, for example, synchronized when the rest of the module could also be improved.

I think bigger module-wide refactors could be a more productive approach to this problem. I also think that swift concurrency could solve this problem really well.

Do you disagree and think there is a quick win here? Is it a blocker?

Copy link
Contributor

Choose a reason for hiding this comment

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

It could definitely increase the scope, happy for it be a follow up 👍

Comment on lines +43 to +47
guard let modalViewManager = modalViewManager else {
return false
}

return modalViewManager.isShowingMessage
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
guard let modalViewManager = modalViewManager else {
return false
}
return modalViewManager.isShowingMessage
return messageLoaded

Copy link
Contributor

Choose a reason for hiding this comment

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

why not just return the value of messageLoaded from here? is there a case where
they can have different values?

Copy link
Contributor Author

@levibostian levibostian Jun 7, 2024

Choose a reason for hiding this comment

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

messageLoaded is true when an in-app message is showing on the screen and when the in-app message is rendering but not yet on the screen. modalViewManager.isShowingMessage is true only when the message is already rendered and is displayed on screen.

This function is meant to tell you if the message is showing, so it's already been rendered and it's on the screen.

Copy link
Contributor

Choose a reason for hiding this comment

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

messageLoaded is true when an in-app message is showing on the screen and when the in-app message is rendering but not yet on the screen

but looking into this method, it is where we are setting messageLoaded as true and also where modalViewManager is being initialized and view is being set, so modalViewManager.isShowingMessage is also going to be true here.

So, both are being done at the same point and rendering is also done, we are just view here?

    func routeLoaded(route: String) {
        Logger.instance.info(message: "Message loaded with route: \(route)")

        currentRoute = route
        if route == currentMessage.messageId, !messageLoaded {
            messageLoaded = true
            if isMessageEmbed {
                delegate?.messageShown(message: currentMessage)
            } else {
                if UIApplication.shared.applicationState == .active {
                    loadModalMessage()
                } else {
                    Gist.shared.removeMessageManager(instanceId: currentMessage.instanceId)
                }
            }
        }
    }

Copy link
Contributor Author

@levibostian levibostian Jun 13, 2024

Choose a reason for hiding this comment

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

I worked on improvements to the test suite today, including isShowingMessage. These improvements go beyond the scope of this PR, so I'll be opening another PR for this improvement.

The intention of isShowingMessage remains the same - determine if a message is loaded and is shown (animations complete).

var viewController: GistModalViewController!
var position: MessagePosition
var isShowingMessage: Bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

just a note: if we do end up going with messageLoaded, need to remove it

import SharedTests
import XCTest

class MessagingInAppIntegrationTest: IntegrationTest {
Copy link
Contributor

Choose a reason for hiding this comment

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

Great addition !! few tests that i think can us here

  • Multiple messages in queue with page rules
  • Test for Navigating Back to Initial Screen After Dismissal

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you elaborate more on the steps in these tests? I'm having a hard time understanding what these have to do with this ticket? I think you're mentioning tests that are good to have that is outside the scope of these changes?

If you could give scenarios that are in scope, I am happy to write these tests in this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

The use case here is, if a customer has already sent multiple in-app messages with different page rules, so when we fetch messages we are going to get the list of messages in queue already. We need to verify, if we change route before rendering what message is being displayed then according to page rule.

The second test, talks about, Being on a page then moving before its rendered and then coming back to the same page.

Copy link
Contributor Author

@levibostian levibostian Jun 11, 2024

Choose a reason for hiding this comment

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

The second test, talks about, Being on a page then moving before its rendered and then coming back to the same page.

Test test_givenUserOnScreenDuringFetch_givenUserNavigatedToDifferentScreenWhileMessageLoading_expectShowModalMessageAfterGoBack should be covering that one.

if a customer has already sent multiple in-app messages with different page rules, so when we fetch messages we are going to get the list of messages in queue already. We need to verify, if we change route before rendering what message is being displayed then according to page rule.

I'll add this test and push it up. I created tests involving multiple messages in another PR.

return
}

guard currentMessage.gistProperties.routeRule != nil else {
Copy link
Contributor

Choose a reason for hiding this comment

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

we also need to check regex as well? incase route rule is not nil and reges still matches we don't need to cancel message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At first, I thought that a regex check was overkill because the logic in setCurrentRoute detects when the route changes which would mean that the user navigated to a different screen and as long as a message has a page rule attached, we could assume that the new screen would not match the modal's page rule.

However, you helped me realize that you can use wildcards in page rules. So, there is indeed a chance that you change the screen and it does match the page rule of the message.

I'll fix this in another PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

PR created #740

Copy link
Contributor

@Shahroz16 Shahroz16 left a comment

Choose a reason for hiding this comment

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

no more blockers, once follow up PRs are ready for review and merged, we can push this 👍

@@ -60,6 +68,16 @@ class MessageManager: EngineWebDelegate {
}
}

func cancelShowingMessage() {
Copy link
Contributor

Choose a reason for hiding this comment

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

It could definitely increase the scope, happy for it be a follow up 👍

@levibostian levibostian merged commit cb1d014 into main Jun 17, 2024
11 checks passed
@levibostian levibostian deleted the levi/inapp-strict-pagerules branch June 17, 2024 18:36
github-actions bot pushed a commit that referenced this pull request Jun 17, 2024
## [3.3.0](3.2.3...3.3.0) (2024-06-17)

### Features

* do not show modal message if change screens and page rule enabled ([#731](#731)) ([cb1d014](cb1d014))
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.

2 participants