swift-sdk icon indicating copy to clipboard operation
swift-sdk copied to clipboard

InAppDisplayer: We need a way to set the `topViewController`

Open luizperes opened this issue 9 months ago • 0 comments

Problem Imagine we have the following hierarchy:

  • ViewController Parent A
    • View Controller Child B, which would get pushed from the parent A

If we invoke InAppManager.show(message:consume:callback:) from parent A and the user navigates to child B while the InAppDisplayer is building the Iterable message, then we have a state where InAppDisplayer.getViewController() will return child B as the topViewController, which is the correct ViewController, however, the circumstances for every app change and showing a modal would bring a bad UX to the app.

Right now, once we fire an InAppManager.show(message:consume:callback:), it could literally show in any screen, considering limited resources of possible devices, especially when we support emerging markets.

Expected behaviour I believe that the expected behaviour would be (1) to have the Iterable modal only displaying on the View Controller that fired it or (2) for us to have a way to set the target view controller externally, such as:

  • Approach (1):
// InAppManager.Swift
func show(message: IterableInAppMessage, consume: Bool = true, callback: ITBURLCallback? = nil) {
    ITBInfo()
    
    // get top view controller before any async operation happen
    
    let topViewController = InAppDisplayer.getTopViewController
    DispatchQueue.main.async {[weak self] in
        self?.showInternal(message: message, consume: consume, callback: callback, topViewController: topViewController)

    }
}
  • Approach (2):
// Let the user decide which view controller is the target one

@objc public protocol IterableInAppManagerProtocol {
...
/// - parameter message: The message to show.
    @objc(showMessage:) func show(message: IterableInAppMessage)
    
    /// - parameter message: The message to show.
    /// - parameter consume: Set to true to consume the event from the server queue if the message is shown. This should be default.
    /// - parameter callback: block of code to execute once the user clicks on a link or button in the in-app notification.
    ///   Note that this callback is called in addition to calling `IterableCustomActionDelegate` or `IterableUrlDelegate` on the button action.
    @objc(showMessage:consume:callbackBlock:) func show(message: IterableInAppMessage, consume: Bool, callback: ITBURLCallback?)

    /// - parameter message: The message to show.
    /// - parameter consume: Set to true to consume the event from the server queue if the message is shown. This should be default.
    /// - parameter targetViewController: The View Controller that will display the in-app notification.
    /// - parameter callback: block of code to execute once the user clicks on a link or button in the in-app notification.
    ///   Note that this callback is called in addition to calling `IterableCustomActionDelegate` or `IterableUrlDelegate` on the button action.
    @objc(showMessage:consume:targetViewController:callbackBlock:) func show(message: IterableInAppMessage, consume: Bool, targetViewController: UIViewController?, callback: ITBURLCallback?)
}

Final Thought My team really hopes that in the future Iterable will allow us to have more flexibility in that part of the library as the solution of my team right now is a workaround and could be broken depending on how the library is updated in the future. Cheers.

luizperes avatar Nov 02 '23 20:11 luizperes