Address Bar Component

The address bar component is a building block that you can use in order to allow a user to provide booking details (pickup, destination and pickup date). It utilises the address screen and automatically broadcast the booking details to other components.

401

On this page, we are going to show you how you can add the address bar component to your screen, how you can initialise and prepopulate the pickup and/or destination addresses. We also going to show you how you can receive the state updates from the component.

Before we start ensure you have configured the UI SDK.

📘

Inputs and outputs

The address bar accepts a JourneyInfo object so you can deeplink booking details so the user does not have to enter booking details twice.

The address bar updates the booking status which is accessible throughout the UISDK

iOS

Firstly create an instance of the address bar in your view or view controller and then add it as a subview while laying out constraints. Once the address bar is set, it will work out of the box providing the SDK is authenticated.

private lazy var addressBar: AddressBarView = {
        let addressBar = KarhooUI.components.addressBar(journeyInfo: nil)
        addressBar.translatesAutoresizingMaskIntoConstraints = false
        return addressBar
    }()

When a user selects an address or date the BookingStatus is updated for any listener to observe.

// register your class as an observer
KarhooBookingStatus.shared.addObserver(self)

extension YourController: BookingDetailsObserver {

    func bookingStateChanged(details: BookingDetails?) {
        // new details selected
    }
}

Android

The address bar component is developed as a custom view which you can add to your layout

<com.karhoo.uisdk.screen.booking.address.addressbar.AddressBarView
        android:id="@+id/address_bar_widget"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

In order to interact with the component and provide the inputs and get the outputs from the component, you require to have an instance of BookingStatusStateViewModel in your Activity or Fragment and use the watchBookingStatusState to initialise the component. The example shown below is for a Fragment.

//Instantiate BookingStatusStateViewModel
private val bookingStatusStateViewModel: BookingStatusStateViewModel by lazy {
    ViewModelProvider(this).get(BookingStatusStateViewModel::class.java)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // Setup the Address Bar component
    address_bar_widget.watchBookingStatusState(
        this.requireActivity(),
        bookingStatusStateViewModel
    )
    //Set up the observers for the actions e.g. clicking on pickup or drop off
    //and outputs i.e. the selected pickup and drop off locations
    bookingStatusStateViewModel.viewActions().observe(owner, bindToAddressBarWidgetActions())
    bookingStatusStateViewModel.viewStates().observe(owner, bindToAddressBarOutputs())
}

Actions

The component relies on the parent Activity or Fragment to launch the required Activity and pass the result back to the component. You need to subscribe an observer in your Activity/Fragment to the bookingStatusStateViewModel.viewActions()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  // ...
  bookingStatusStateViewModel.viewActions().observe(owner, bindToAddressBarWidgetActions())
}

//Copy this as is as this gets the action from the Address Component and opens the Activity that
//enables the pickup/drop off address to be selected
private fun bindToAddressBarWidgetActions(): Observer<in AddressBarViewContract.AddressBarActions> {
    return Observer { actions ->
        when (actions) {
            is AddressBarViewContract.AddressBarActions.ShowAddressActivity ->
                startActivityForResult(actions.intent, actions.addressCode)
        }
    }
}

Once you have received the results in the immediate parent (Activity or Fragment) of the component, you can use onActivityResult of the AddressBar component to handle the result.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (resultCode == AppCompatActivity.RESULT_OK && data != null) {
        when (requestCode) {
            AddressCodes.PICKUP -> address_bar_widget.onActivityResult(
                requestCode,
                resultCode,
                data
            )
            AddressCodes.DESTINATION -> address_bar_widget.onActivityResult(
                requestCode,
                resultCode,
                data
            )
        }
    }
    super.onActivityResult(requestCode, resultCode, data)
}

If you're using the component in the Fragment, first you will need to forward the result from your Activity to the fragment so you can pass the results back to the component.

//Handle the result in the Fragment
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    for (fragment in supportFragmentManager.fragments) {
        fragment.onActivityResult(requestCode, resultCode, data)
    }
}

States

If you are interested to get the updated BookingStatus in order to use the pickup and destination outputs from the Address Component for display or passed on to another component, you need to subscribe an observer in your Activity/Fragment to the bookingStatusStateViewModel.viewStates()

Observe and handle the results from the Address Component in your Fragment/Activity

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  // ...
  bookingStatusStateViewModel.viewStates().observe(owner, bindToAddressBarOutputs())
}

//Get the updated BookingStatus to use the pickup and destination outputs from
//the Address Component for display or passed on to another component
private fun bindToAddressBarOutputs(): Observer<BookingStatus> {
    return Observer { bookingStatus ->
        bookingStatus?.let {
            //Use the pickup address set in the componenent e.g.
            it.pickup?.let { pickup ->
                selected_pickup?.text = pickup.displayAddress
            } ?: run {
                selected_pickup?.text = ""
            }

            //Use the drop off address set in the componenent e.g.
            it.destination?.let { dropoff ->
                selected_drop_off?.text = dropoff.displayAddress
            } ?: run {
                selected_drop_off?.text = ""
            }
        }
    }
}