Set Up and Launch Default Components

In the following sections, we will discuss how to set up and launch default IQL components using UIKit.

Introduction to Components

Integrate Home Screen Widgets

Integrate PermissionsErrorCombinedSummaryWidget

Launch Appropriate Components On Notification Taps

Introduction to Components

ZendriveIQLUIKit offers a curated collection of pre-designed components, meticulously crafted to expedite the development workflow. These out-of-the-box elements ensure that developers can seamlessly embed them into applications, delivering both functionality and a cohesive user experience without the need for developing components from scratch.

Types of Components:

  1. Widget Components : These compact, interactive elements in ZendriveIQLUIKit are designed for quick tasks or information snippets. Adaptable in presentation, they can fit various contexts, from pop-ups to overlays.

  2. Full Screen Components: These dominant elements in ZendriveIQLUIKit occupy the entire screen space, offering an in-depth interface for detailed user interactions.

Component Usage

In native ZendriveIQLUIKit, every component can be created by instantiating its class Component as shown in the example.

For instance, if you're keen on constructing an Offer Card widget, you will need to leverage the OfferCardWidget() class to create it.

In case of React Native, the screen components are exposed as classes that needs to be instantiated. The widget components are exposed as React components so they can directly used in the views.

let component = Component()

Set Listener

Each component in ZendriveIQLUIKit requires a listener to receive callbacks based on certain events. To listen to these callbacks, you need to assign a listener using the setListener API. Once a listener is set, you must implement all the methods associated with the listener to handle any callback events. Typically, the listener for a component follows a naming convention such as ComponentNameListener, for example, PermissionErrorCombinedSummaryWidgetListener.

iOS (Swift)

Step 1: Create a Component

class DemoViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Create widget
        let widget = PermissionErrorCombinedSummaryWidget()
        widget.setListener(self) //Set listener for component
        
        // Add widget as a subview
        widget.addTo(parent: self.view)
    // ... additional code ...
    }
}

Step 2: Implementing Listener Methods

extension DemoViewController: PermissionErrorCombinedSummaryWidgetListener {
// Implement Listener methods if any
}
Android (Kotlin)

Step 1: Create a Component

class MyFragment: Fragment() {
    
    var permissionErrorWidget: PermissionErrorCombinedSummaryWidget? = null
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        permissionErrorWidget = PermissionErrorCombinedSummaryWidget()
        
        // set Listener to your component using setListener()
        val listener = PermissionErrorCombinedSummaryWidgetListener()
        permissionErrorWidget?.setListener(listener)
        
        // call other methods and add widget to your view
    }
}

Step 2: Implementing Listener Methods

class MyFragment: Fragment() {
    
    // create listener for PermissionErrorCombinedSummaryWidget
    
    inner class PermissionErrorCombinedSummaryWidgetListener:
        PermissionErrorCombinedSummaryWidget.Listener {
        
        override fun onPermissionErrorCombinedSummaryWidgetViewDetached(){
            // implement action if any when this widget gets detached.
        }
    }
}

Listeners are not applicable in React Native

Set Launcher

Each component in ZendriveIQLUIKit requires a launcher for initiating the subsequent set of components. Therefore, when creating a component, it's essential to assign a launcher to it. This is done by invoking the setLauncher method on the component.

Depending on the platform, various types of launchers are available. Please refer to the platform-specific sections below for detailed information.

iOS

There are three launchers available in iOS as below.

  1. NavigationLauncher: Manages navigation-based component presentations, specifically push and pop operations.

let launcher = NavigationLauncher(/*viewController.navigationController*/)
componet.setLauncher(launcher)
component.launch() // Make Sure you set launcher before calling launch()
  1. ModalViewControllerLauncher: ModalViewControllerLauncher functions similarly to NavigationLauncher with one key distinction: instead of pushing screens onto the navigation stack, it presents them modally. If you pass ModalViewControllerLauncher starting as a launcher for UIKit it employs this launcher as the foundation for subsequent screen presentations.

let launcher = ModalViewControllerLauncher(/*viewController*/)
componet.setLauncher(launcher)
component.launch() // Make Sure you set launcher before calling launch()
  1. BottomSheetLauncher: BottomSheetLauncher is used to launch any widget components as bottom sheets.

let launcher = BottomSheetLauncher(/*viewController*/)
componet.setLauncher(launcher)
component.launch() // Make Sure you set launcher before calling launch()
Android
  • ActivityLauncher: Launchers a component as a new Activity.

val activityLauncher = Launcher.ActivityLauncher(context: this)
screen.setLauncher(activityLauncher)
screen.launch()
  • Fragment Launcher: Launches a component as a fragment in your activity.

val launcher = Launcher.FragmentLauncher(
    fragmentManager = supportFragmentManager,
    containerId = fragmentContainerId
)
screen.setLauncher(launcher)
screen.launch()
  • BottomSheetLauncher: Displays components as bottom sheets.

val launcher = Launcher.ActivityLauncher(this)
widget.setLauncher(launcher)
widget.launchAsBottomSheet()

Setting launchers is not supported in React Native. By default, iOS uses ModalLauncher and Android uses ActivityLauncher.

Add a Widget

After setting the listener and launcher for components, to integrate a widget into your app, you need to add widget components to your app's view hierarchy using the addTo method.

Refer to the code snippets provided below for guidance.

iOS (Swift)
let widget = Widget()
widget.addTo(parent: /*view*/) // Here, 'view' is the UIView to which you want to add the widget.
Android (Kotlin)
val widget = Widget()
widget.addTo(binding.widgetContainer.id, supportFragmentManager)
React Native

Render a widget component:

import { Widgets } from 'react-native-iqluikit';

// Get the widget to render
const { WidgetComponent } = Widgets;
 
 // Other code
 
 return (
    <View>
        <WidgetComponent style={{ /* style preperties here */ }}/>
    </View>
 );
 
   

Launch a Screen

After setting the listener and launcher for components, to integrate a screen into your app, you need to launch a screen using launch method.

Refer to the code snippets provided below for guidance.

iOS(Swift)
let screen = Screen()
let launcher = NavigationLauncher(/*UINavigationController*/)
screen.setLauncher(launcher)
screen.launch()
Android (Kotlin)
val screen = Screen()
val launcher = Launcher.ActivityLauncher(this)
screen.setLauncher(launcher)
screen.launch()
React Native
import { ScreenComponent } from 'react-native-zendrive-iqluikit';

const launchScreen = () => {
  const screenComponent = new ScreenComponent();  
  screenComponent.launch();
}

// Launching a screen on a button click
<Button onClick={() => launchScreen()} />

Set Availability Listener

ZendriveIQLUIKit automatically handles the showing or hiding of widgets based on data availability. However, if you require additional control over layout changes beyond simple show or hide actions, you can utilize the setAvailabilityListener API of WidgetComponent. By passing a listener to this API and implementing the onAvailable and onUnavailable callbacks, you can make more nuanced layout adjustments as needed.

In React Native, onAvailable and onUnAvailable callbacks are available as props to the widgets so some custom logic can be implemented in the application code based on the availability of the view.

iOS (Swift)

Step 1: Create a widget and add it to view hierarchy

class DemoViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Create widget
        let widget = PermissionErrorCombinedSummaryWidget()
        // Add widget as a subview
        widget.addTo(parent: self.view)
        // Set the availability listener to receive callbacks about widget's availability status
        widget?.setAvailabilityListener(self)
    }
    // ... additional code ...
}

Step 2: Implementing Availability Listener Methods

extension DemoViewController: PermissionErrorCombinedSummaryWidgetViewAvailabilityListener {
    // Method called when the widget becomes available
    func onViewAvailable(view: UIView) {
        // Check if the available view is PermissionErrorCombinedSummaryWidget
        if view.isKind(of: BasePermissionErrorCombinedSummaryWidget.self) {
            // Modify Layout as needed when the widget becomes available
        }
    }

    // Method called when the widget becomes unavailable
    func onViewUnavailable(view: UIView) {
        // Check if the unavailable view is PermissionErrorCombinedSummaryWidget
        if view.isKind(of: BasePermissionErrorCombinedSummaryWidget.self) {
            // Modify Layout as needed when the widget becomes unavailable
        }
    }
}
Android (Kotlin)

Step 1: Create a widget and add it to view hierarchy.

class MyFragment: Fragment() {
    
    var permissionErrorWidget: PermissionErrorCombinedSummaryWidget? = null
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    

        // set Availibility Listener to your component 
        // using setAvailibilityListener()
        // ZendriveIQLUiKit hide and show internally.
        // You can listen to this callback to adjust your layout. 
        val listener = PermissionErrorAvailibilityListener()
        permissionErrorWidget?.setAvailibilityListener(listener)
        
        // call other methods and add widget to your view
    }

}

Step 2: Implementing Availability Listener Methods

class MyFragment: Fragment() {

    inner class PermissionErrorAvailibilityListener: 
        AvailabilityListener {
        
        override fun onAvailable() {
            // show your parent container
            binding.permissionErrorCard.makeVisible()
        }

        override fun onUnAvailable() {
            // hide your parent container
            binding.permissionErrorCard.makeGone()
        }

    }
}
React Native

Pass the callbacks as props to the widgets.

const { PermissionErrorCombinedSummaryWidget } = Widgets;

const Home: React.FC = () => {
    return (
        <View style={styles.container}>
            <PermissionErrorCombinedSummaryWidget 
                style={{ /* styles here */ }}
                onAvailable={() => console.log("Error is shown!")}
                onUnAvailable={() => console.log("Error is hidden!")}
            />
        </View>
    )
} 

Integrate Home Screen Widgets

Integrate CombinedProgramSummaryWidget

The CombinedProgramSummaryWidget is designed to be seamlessly integrated into the home screen of the host application. With its dynamic states, this widget adapts its UI to offer timely updates. This will serve as starting point for the user to interact with the program.

The widget transitions between four distinct states, each representing a specific phase of the user's progression:

  1. Eligibility Pending: The user hasn't been activated for participation in the IQL program.

  2. Permissions Pending: Essential permissions for the ZendriveIQLUIKit haven't been granted by the user.

  3. Test Drive In Progress: Upon activation, the user's trip recordings are in progress.

  4. Qualified: The user has fulfilled the necessary criteria and is now eligible for the Offer.

If you wish to launch UIKit screens from a custom UI, based on the program status above, refer to section Launch screens based on program status

iOS (Swift)
class HomeViewController: UIViewController, CombinedProgramSummaryWidgetListener {
    override func viewDidLoad() {
        super.viewDidLoad()
        setupCombinedProgramSummaryWidget()
    }

    func setupCombinedProgramSummaryWidget() {
        let combinedProgramSummaryWidget = CombinedProgramSummaryWidget()
        combinedProgramSummaryWidget.setListener(self)
        let launcher = NavigationLauncher(self.navigationController)
        combinedProgramSummaryWidget.setLauncher(launcher)
        combinedProgramSummaryWidget.addTo(parent: self.view)
        let padding: CGFloat = 16
        NSLayoutConstraint.activate([
            combinedProgramSummaryWidget.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            combinedProgramSummaryWidget.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
            combinedProgramSummaryWidget.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: padding),
            combinedProgramSummaryWidget.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -padding)
        ])
    }
}
Android (Kotlin)
class DemoActivity: AppCompatActivity() {
    
    var iqlEntryWidget: CombinedProgramSummaryWidget? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        iqlEntryWidget = CombinedProgramSummaryWidget()
        val launcher = Launcher.ActivityLauncher(this)
        iqlEntryWidget?.setLauncher(launcher)
        iqlEntryWidget?.setListener(IQLEntryWidgetListener())
        val containerId = binding.iqlEntryWidgetContainer.id
        iqlEntryWidget?.addTo(containerId, supportFragmentManager)
    }
    
    inner class IQLEntryWidgetListener : 
            CombinedProgramSummaryWidget.Listener {
        override fun onCombinedProgramSummaryWidgetViewDetached() {
            iqlEntryWidget = null
        }
    }  
}
React Native
import { Widgets } from 'react-native-zendrive-iqluikit';

const { CombinedProgramSummaryWidget } = Widgets;

const Home: React.FC = () => {
    return (
        <View style={styles.container}>
            <CombinedProgramSummaryWidget style={{ /* styles here */ }} />
        </View>
    )
} 

Integrate PermissionsErrorCombinedSummaryWidget

The PermissionErrorCombinedSummaryWidget within the ZendriveIQLUIKit serves as a proactive notifier for users about any permission errors. Ensuring correct permissions is pivotal for the seamless functionality of the application.

This widget adeptly identifies and manages various permission error states, such as those related to location or notifications. After integration, the application simply subscribes to its availability listener. The ZendriveIQLUIKit subsequently sends callbacks whenever there's a permission error. Internally, the widget modifies its display, allowing the application to intuitively present or hide it based on the presence or absence of permission errors.

iOS (Swift)

Step 1: Create a widget and add it to view hierarchy

class DemoViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Create widget
        let widget = PermissionErrorCombinedSummaryWidget()
        // Add widget as a subview
        widget.addTo(parent: self.view)
        // Set the availability listener to receive callbacks about widget's availability status
        widget.setAvailabilityListener(self)
    }
    // ... additional code ...
}

Step 2: Implementing Availability Listener Methods

extension DemoViewController: AvailabilityListener {
    // Method called when the widget becomes available
    func onAvailable(view: UIView) {
        // Check if the available view is PermissionErrorCombinedSummaryWidget
        if view.isKind(of: BasePermissionErrorCombinedSummaryWidget.self) {
            // Modify Layout as needed when the widget becomes available
        }
    }

    // Method called when the widget becomes unavailable
    func onUnavailable(view: UIView) {
        // Check if the unavailable view is PermissionErrorCombinedSummaryWidget
        if view.isKind(of: BasePermissionErrorCombinedSummaryWidget.self) {
            // Modify Layout as needed when the widget becomes unavailable
        }
    }
}
Android (Kotlin)
class DemoActivity: AppCompatActivity() {

    // Instance of PermissionErrorCombinedSummaryWidget
    var permissionErrorWidget: PermissionErrorCombinedSummaryWidget?
    
     override fun onViewCreated(view: View, savedInstanceState: Bundle?){
        super.onViewCreated(view, savedInstanceState)
        
        val launcher = Launcher.ActivityLauncher(this)
        
        permissionErrorWidget = PermissionErrorCombinedSummaryWidget()
        permissionErrorWidget?.setListener(
            PermissionErrorCombinedSummaryWidgetListener()
        )
        permissionErrorWidget?.setAvailabilityListener(
            PermissionAvailabilityListener()
        )
        permissionErrorWidget?.setLauncher(launcher)
        val containerId = binding.permissionContainer.id
        permissionErrorWidget?.addTo(containerId, supportFragmentManager)
    }
    
    inner class PermissionAvailabilityListener :
        AvailabilityListener.Listener { 
        override fun onAvailable()
        {            
            // show the container
            binding.widgetContainer.makeVisible()
        }
        override fun onUnAvailable()
        {
            // hide the container
            binding.widgetContainer.makeGone()
        }
    }
    
    inner class PermissionErrorCombinedSummaryWidgetListener :
        PermissionErrorCombinedSummaryWidget.Listener { 
        override fun onPermissionErrorCombinedSummaryWidgetViewDetached()
        {
            permissionErrorWidget = null
        }
    }
}
React Native
import { Widgets } from 'react-native-zendrive-iqluikit';

const { PermissionErrorCombinedSummaryWidget } = Widgets;

const Home: React.FC = () => {
    return (
        <View style={styles.container}>
            <PermissionErrorCombinedSummaryWidget 
                style={{ /* styles here */ }}
                onAvailable={() => console.log("Error is shown!")}
                onUnAvailable={() => console.log("Error is hidden!")}
            />
        </View>
    )
} 

Launch Appropriate Components On Notification Taps

Handle Notification Tap

  • iOS: Handle the UNNotificationCenterDelegate didReceive withReponse method

  • Android: Handle using notification’s PendingIntent method.

  • Parse the notification data to identify the type of notification. This depends on the application’s notification data object structure and will vary from application to application.

  • Based on the type of notification, launch the appropriate component from the IQLUIKit. Following are the most common components that get used here:

    • DashboardScreen component:This gets used whenever you need to open the home page of the Zendrive IQL program. This is generally used for most of the program milestone-related notifications.

    • OfferDetailsScreen component: This gets used whenever an offer is available and you need to show the offer to the user.

    • PermissionErrorDetailsWidget component: This gets used whenever an permission error related notification is tapped.

Launch ProgramIntroductionScreen Component

The ProgramIntroductionScreen component provides an introduction to the IQL program.

iOS (Swift)
import UIKit
import ZendriveIQLUIKit

class DemoViewController: UIViewController {

    // ...Other code

    func launchProgramIntroductionScreen() {
        let programIntroductionScreen = ProgramIntroductionScreen()
        let launcher = NavigationLauncher(self.navigationController)
        programIntroductionScreen.setLauncher(launcher)
        programIntroductionScreen.setListener(self)
        programIntroductionScreen.launch()
    }
}

// Extension for ProgramIntroductionScreenListener
extension DemoViewController: ProgramIntroductionScreenListener {
    // Implement listener methods as needed
}
Android (Kotlin)
class DemoActivity: AppCompatActivity() {

    
    var programIntroductionScreen: ProgramIntroductionScreen? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        programIntroductionScreen = ProgramIntroductionScreen()
        val launcher = Launcher.ActivityLauncher(this)
        programIntroductionScreen?.setListener(ProgramIntroductionScreenListener())
        programIntroductionScreen?.setLauncher(launcher)
        programIntroductionScreen?.launch()
    }
    
    inner class ProgramIntroductionScreenListener : ProgramIntroductionScreen.Listener {
    
        override fun onProgramIntroductionScreenViewDetached() {
            programIntroductionScreen = null
        }
        override fun onActivateButtonClicked() {
            // do something when activate button is clicked
        }

    } 
}
React Native
import { ProgramIntroductionScreen } from 'react-native-zendrive-iqluikit';

const Home: React.FC = () => {
    
    React.useEffect(() => {
        const programIntroductionScreen = new ProgramIntroductionScreen();
        programIntroductionScreen.launch();
    }, []);
    
    return (<></>)
}

Launch DashboardScreen Component

The DashboardScreen component holds different widgets which allows users to track their progress in the IQL program using those metrics.

iOS (Swift)
import UIKit
import ZendriveIQLUIKit

class DemoViewController: UIViewController, DashboardScreenListener {

    var dashboardScreen: DashboardScreen?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupDashboardScreen()
    }
    
    func setupDashboardScreen() {
        let dashboardScreen = DashboardScreen()
        let launcher = NavigationLauncher(self.navigationController)
        dashboardScreen.setLauncher(launcher)
        dashboardScreen.setListener(self)
        dashboardScreen.launch()
    }
    
    // Implement DashboardScreenListener methods here
}
Android (Kotlin)
class DemoActivity: AppCompatActivity() {

    
    var dashboardScreen: DashboardScreen? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        dashboardScreen = DashboardScreen()
        val launcher = Launcher.ActivityLauncher(this)
        dashboardScreen?.setLauncher(launcher)
        daashboardScreen?.setListener(DashboardScreenListener())
        dashboardScreen?.launch()
    }
    
    inner class DashboardScreenListener : DashboardScreen.Listener {
        override fun onDashboardDetached() {
            dashboardScreen = null
        }

    } 
}
React Native
import { DashboardScreen } from 'react-native-zendrive-iqluikit';

const Home: React.FC = () => {
    
    React.useEffect(() => {
        const dashboardScreen = new DashboardScreen();
        dashboardScreen.launch();
    }, []);
    
    return (<></>)
}

Launch OfferDetailsScreen Component

When a user gets an offer, the OfferDetailsScreen component helps them to input the information required to obtain a discount quote.

iOS (Swift)
import UIKit
import ZendriveIQLUIKit

class SampleViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setupOfferDetailsScreen()
    }
    
    private func setupOfferDetailsScreen() {    
        let offerDetailsScreen = OfferDetailsScreen()
        let launcher = NavigationLauncher(self.navigationController)
        offerDetailsScreen.setLauncher(launcher)
        offerDetailsScreen.setListener(self)
        offerDetailsScreen.launch()
    }
}

// MARK: - OfferDetailsScreenListener Extension
extension SampleViewController: OfferDetailsScreenListener {
    // Implement methods of OfferDetailsScreenListener if any.
}
Android (Kotlin)
class DemoActivity: AppCompatActivity() {
    
    var offerDetailsScreen: OfferDetailsScreen? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        offerDetailsScreen = OfferDetailsScreen()
        offerDetailsScreen?.setListener(OfferDetailsScreenListener())
        val launcher = Launcher.ActivityLauncher(this)
        offerDetailsScreen?.setLauncher(launcher)
        offerDetailsScreen?.launch(launcher)
    }
    
    inner class OfferDetailsScreenListener : OfferDetailsScreen.Listener {
        override fun onOfferDetailsDetached() {
            offerDetailsScreen = null
        }
    } 
}
React Native
import { OfferDetailsScreen } from 'react-native-zendrive-iqluikit';

const Home: React.FC = () => {
    
    React.useEffect(() => {
        const offerScreen = new OfferDetailsScreen();
        offerScreen.launch();
    }, []);
    
    return (<></>)
}

Launch PermissionErrorDetailsWidget Component

The PermissionErrorDetailsWidget is used to resolve different types of permissions. It navigates the user to the Settings menu in order to provide the required permission to continue with the IQL program.

React Native: Different error types are exposed via ErrorTypes object. These error types, based on the platform are passed as error props to the PermissionErrorDetailsWidget component.

iOS (Swift)
import UIKit
import ZendriveIQLUIKit

class SampleViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setupPermissionErrorDetailsWidget()
    }

    private func setupPermissionErrorDetailsWidget() {
        let permissionErrorDetailsWidget = ZendriveIQLUIKit.viewFactory.createPermissionErrorDetailsWidget()
        permissionErrorDetailsWidget.setError(.locationServicesOff)
        permissionErrorDetailsWidget.setListener(self)

        let launcher = BottomSheetLauncher(self)
        permissionErrorDetailsWidget.setLauncher(launcher: launcher)
        permissionErrorDetailsWidget.launch()
    }
}

// MARK: - PermissionErrorDetailsWidgetListener
extension SampleViewController: PermissionErrorDetailsWidgetListener {
    // Implement methods of PermissionErrorDetailsWidgetListener if any.
}
Android (Kotlin)
class DemoActivity: AppCompatActivity() {
    
    var permissionErrorDetailsWidget: PermissionErrorDetailsWidget? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val error = ZendriveIQLUIKitPermissionError.LOCATION_PERMISSION_DENIED
        
        permissionErrorDetailsWidget = PermissionErrorDetailsWidget()
        val state = PermissionErrorDetailsWidgetViewState(error)
        permissionErrorDetailsWidget?.setState(state)
        permissionErrorDetailsWidget?.setListener(
            PermissionErrorDetailsWidgetListener()
        )    
        val launcher = Launcher.FragmentLauncher(
            fragmentManager = supportFragmentManager,
            containerId = fragmentContainerId
        )
        permissionErrorDetailsWidget?.setLauncher(launcher)
        permissionErrorDetailsWidget?.launchAsBottomSheet()
    }
    
    inner class PermissionErrorDetailsWidgetListener: PermissionErrorDetailsWidget.Listener {
        override fun onPermissionErrorDetailsWidgetViewDetached() {
            permissionErrorDetailsWidget = null
        }
    } 
}
React Native
import { Platform } from 'react-native'; 
import { Widgets, ErrorTypes } from 'react-native-zendrive-iqluikit';

const { PermissionErrorDetailsWidget } = Widgets;

const Home: React.FC = () => {
    return (
        <View style={styles.container}>
            <PermissionErrorDetailsWidget
                error={
                    Platform.OS === 'android' ? 
                    ErrorTypes.android.LOCATION_PERMISSION_DENIED : 
                    ErrorTypes.ios.LOCATION_SERVICES_OFF
                }
                style={{ /* styles here */ }} 
            />
        </View>
    )
} 

PermissionErrorDetailsWidget is currently not supported in React Native

Launch screens based on program status

If you choose not to use the CombinedProgramSummaryWidget and prefer to launch specific screens based on the user's current status, the getProgramStatus API is available for use. This API identifies one of four states defined here. Once you receive the state, you can independently initiate the corresponding screen. Essentially, the getProgramStatus API acts as the initial step for launching the correct screen within . After a screen is launched, UIKit will autonomously manage the transitions to any subsequent screens.

Not applicable for React Native

Refer below code snippets for guidance.

iOS (Swift)
class DemoViewController: UIViewController {
    // ... Other code ...

    // Function to handle user actions within your app
    func onUserAction() {
        let programStatus = ZendriveIQLUIKit.getRepository().getProgramStatus()
        launchIQLScreen(forStatus: programStatus)
    }

    // Launch the appropriate IQL screen based on the user's program status
    func launchIQLScreen(forStatus status: ZendriveIQLUIKitProgramStatus) {
        switch status {
            case .eligibilityPending:
                // Launch Program Introduction screen
                launchProgramIntroductionScreen()
            case .permissionsPending:
                // Launch Permission Capture Screen
                launchPermissionCaptureScreen()
            case .testDriveInProgress:
                // Launch Dashboard Screen
                launchDashboardScreen()
            case .qualified:
                // Launch Offer Detail Screen
                launchOfferDetailScreen()
        }
    }

    // Launch the Program Introduction Screen
    func launchProgramIntroductionScreen() {
        let programIntroductionScreen = ProgramIntroductionScreen()
        let launcher = NavigationLauncher(self.navigationController)
        programIntroductionScreen.setLauncher(launcher)
        programIntroductionScreen.setListener(self)
        programIntroductionScreen.launch()
    }

    // Placeholder functions for launching other screens
    func launchPermissionCaptureScreen() {
        // Implementation for launching Permission Capture Screen
    }

    func launchDashboardScreen() {
        // Implementation for launching Dashboard Screen
    }

    func launchOfferDetailScreen() {
        // Implementation for launching Offer Detail Screen
    }
}

// Extension for ProgramIntroductionScreenListener
extension DemoViewController: ProgramIntroductionScreenListener {
    // Implement listener methods as needed
}
Android (Kotlin)
class DemoActivity: AppCompatActivity() {

    // ... Other code ...

    // Function to handle user actions within your app
    
    var programIntroductionScreen: ProgramIntroductionScreen? = null
    
    fun onUserAction() {
        val programStatus = ZendriveIQLUIKit.zendriveIQLUIKitRepository.getProgramStatus()
        launchIQLScreen(programStatus)
    }
    
    fun launchIQLScreen(programStatus: ZendriveIQLUIKitProgramStatus) {
        when (programStatus) {
            ZendriveIQLUIKitProgramStatus.QUALIFIED -> {
                launchOfferDetailScreen()
            }

            ZendriveIQLUIKitProgramStatus.TEST_DRIVE_IN_PROGRESS -> {
                launchDashboardScreen()
            }

            ZendriveIQLUIKitProgramStatus.ELIGIBILITY_PENDING -> {
                launchProgramIntroductionScreen()
            }

            ZendriveIQLUIKitProgramStatus.PERMISSION_PENDING -> {
                launchPermissionCaptureScreen()
            }
        }
    }
    
    
    fun launchProgramIntroductionScreen() {
        programIntroductionScreen = ProgramIntroductionScreen()
        val launcher = Launcher.ActivityLauncher(this)
        programIntroductionScreen?.setListener(ProgramIntroductionScreenListener())
        programIntroductionScreen?.setLauncher(launcher)
        programIntroductionScreen?.launch()
    }
    
    // Placeholder functions for launching other screens
    fun launchPermissionCaptureScreen() {
        // Implementation for launching Permission Capture Screen
    }

    fun launchDashboardScreen() {
        // Implementation for launching Dashboard Screen
    }

    fun launchOfferDetailScreen() {
        // Implementation for launching Offer Detail Screen
    }
    
    inner class ProgramIntroductionScreenListener : ProgramIntroductionScreen.Listener {
    
        override fun onActivateButtonClicked() {
            // logic
        }

        override fun onProgramIntroductionScreenViewDetached() {
            // detach logic
        }
    }
}

Customising Navigation Bar (iOS Only)

ZendriveIQLUIKit provides a way to customise navigation bar through different approaches

Using UINavigationBar and UINavigationItem

To customize the appearance of the navigation bar for any screen component with the default view, you can set its properties when the screen loads. Follow these steps:

  1. Create a new CustomComponentScreen class by subclassing from ComponentScreen.

  2. In this subclassed CustomComponentScreen, you can modify the UINavigationBar and UINavigationItem properties to customize the navigation bar's appearance.

  3. Return this view from customViewFactory method of that particular screen component.

Example:

Let's say you have a DashboardScreen class for a screen in your iOS app. To customize the navigation bar appearance for this screen, you can do the following:

import ZendriveIQLUIKit

class CustomDashboardScreen: DashboardScreen {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // Call the method to customize the navigation bar
        customizeNavigationBar()
    }
    
    // Method to customize the navigation bar
    func customizeNavigationBar() {
        if let navigationBar = navigationController?.navigationBar {
            // Set background color
            navigationBar.barTintColor = UIColor.red
            
            // Set text color
            navigationBar.tintColor = UIColor.white
            
            // Make it translucent or not
            navigationBar.isTranslucent = false
        }
        
        // Customize the UINavigationItem properties
        navigationItem.title = "Custom Screen" // Set the title
        navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil) // Customize the back button
    }
}

Adding CustomView as subview to UINavigationBar

Add a custom navigation bar view as a subview to the navigation bar and handle any actions associated with the elements within the custom view. Example:

import ZendriveIQLUIKit

class CustomDashboardScreen: DashboardScreen {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Create a custom view
        let customView = UIView()
        customView.backgroundColor = UIColor.clear

        // Add UI elements to your custom view
        let titleLabel = UILabel()
        titleLabel.text = "Custom Title"
        titleLabel.textAlignment = .center
        titleLabel.textColor = UIColor.white
        customView.addSubview(titleLabel)

        // Add a button to the right side of the custom view
        let customButton = UIButton()
        customButton.setTitle("Button", for: .normal)
        customButton.addTarget(self, action: #selector(customButtonTapped), for: .touchUpInside)
        customView.addSubview(customButton)

        // Add custom view to navigation bar
        if let navigationBar = self.navigationController?.navigationBar {
            navigationBar.addSubview(customView)
            customView.translatesAutoresizingMaskIntoConstraints = false

            // Add constraints
            NSLayoutConstraint.activate([
                customView.topAnchor.constraint(equalTo: navigationBar.topAnchor),
                customView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor),
                customView.leadingAnchor.constraint(equalTo: navigationBar.leadingAnchor),
                customView.trailingAnchor.constraint(equalTo: navigationBar.trailingAnchor),
                
                titleLabel.topAnchor.constraint(equalTo: customView.topAnchor),
                titleLabel.leadingAnchor.constraint(equalTo: customView.leadingAnchor),
                titleLabel.trailingAnchor.constraint(equalTo: customButton.leadingAnchor),
                titleLabel.bottomAnchor.constraint(equalTo: customView.bottomAnchor),
                
                customButton.topAnchor.constraint(equalTo: customView.topAnchor),
                customButton.trailingAnchor.constraint(equalTo: customView.trailingAnchor),
                customButton.widthAnchor.constraint(equalToConstant: 50),
                customButton.bottomAnchor.constraint(equalTo: customView.bottomAnchor)
            ])
        }
    }

    // Handle tap on the custom button
    @objc func customButtonTapped() {
        // Perform actions when the custom button is tapped
        print("Custom button tapped!")
    }
}

Using UIKit UI Elements in your application

If you wish to create independent screens in your app that are themed similar to ZendriveIQLUIKit, you can use themed input fields and buttons that are exposed by ZendriveIQLUIKit.

Input Field

  • IQLUIKitPrimaryTextField

  • IQLUIKitSecondaryTextField

iOS

IQLUIKitPrimaryTextField

IQLUIKitPrimaryTextField is a custom text field component part of the UIKit. It extends UITextField and provides additional functionality like floating labels, error messaging, and input validation.

Example Usage

let textField = IQLUIKitPrimaryTextField()
textField.floatingText = "FirstName"
textField.placeholder = "Enter your first name"
textField.validators = [EmailValidator(failureMessage: "failure message"), 
TextLengthValidator(min: 3, max: 20, failureMessage: "failure message")]

IQLUIKitSecondaryTextField

IQLUIKitSecondaryTextField is custom text field component in the UIKit similar to IQLUIKitPrimaryTextField, but with different visual styles and behaviours.

Example Usage

let textField = IQLUIKitSecondaryTextField()
textField.floatingText = "FirstName"
textField.placeholder = "Enter your first name"
textField.validators = [EmailValidator(failureMessage: "failure message"), 
TextLengthValidator(min: 3, max: 20, failureMessage: "failure message")]
Android
  • Usage

<com.zendrive.zendriveiqluikit.ui.customviews.IQLUIKitPrimaryTextField
                android:id="@+id/my_text_primary_field"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/dp16"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
/>

<!-- or Use secondary text field -->

<com.zendrive.zendriveiqluikit.ui.customviews.IQLUIKitSecondaryTextField
        android:id="@+id/my_text_secondary_field"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="@dimen/dp40"
        android:layout_margin="@dimen/dp48"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
/>

Button

  • IQLUIKitPrimaryButton

  • IQLUIKitSecondaryButton

iOS

IQLUIKitPrimaryButton and IQLUIKitSecondaryButton are customizable buttons in the UIKit extended from UIButton

Example Usage

let primaryButton = IQLUIKitPrimaryButton()
primaryButton.setTitle("Primary Button", for: .normal)
primaryButton.setShape(shape: .roundedEdgesRectangle(cornerRadius: 5))
primaryButton.onTap = {
    print("Button tapped")
}

// Secondary Button 
let secondaryButton = IQLUIKitSecondaryButton()
secondaryButton.setTitle("Secondary Button", for: .normal)
secondaryButton.onTap = {
    // Actions to perform on button tap
}
Android
  • Usage

<com.zendrive.zendriveiqluikit.ui.customviews.IQLUIKitPrimaryButton
            android:id="@+id/my_button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="@dimen/dp42"
            android:layout_marginTop="@dimen/dp16"
            android:minHeight="@dimen/dp48"
            android:text="My Button"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
/>

<!-- or Use secondary button -->

<com.zendrive.zendriveiqluikit.ui.customviews.IQLUIKitSecondaryButton
            android:id="@+id/my_button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="@dimen/dp42"
            android:layout_marginTop="@dimen/dp16"
            android:minHeight="@dimen/dp48"
            android:text="My Button"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
/>
  • Button Specific attribute

    • ziuButtonShape can accept rectangular, rectangular

Last updated