TP-00000 | landing page bottom-sheet compose (#6582)

* TP-00000 | landing page bottom-sheet

* TP-00000 | refactoring

* TP-00000 | used naviText & refactoring

* TP-00000 | spotless fix

* TP-00000 | rm extra line

* TP-00000 | cta handling

* TP-00000 | removed extra code

* TP-00000 | removed unused imports

* TP-00000 | removed unused imports
This commit is contained in:
Shaurya Rehan
2023-05-24 18:26:41 +05:30
committed by GitHub Enterprise
parent 84a4061872
commit dcad4d2ed2
9 changed files with 239 additions and 11 deletions

View File

@@ -27,9 +27,13 @@ android {
}
}
buildFeatures {
compose true
dataBinding true
viewBinding true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8

View File

@@ -0,0 +1,161 @@
/*
*
* * Copyright © 2023 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.hl.landingpage.bottomsheet
import android.os.Bundle
import android.view.ViewStub
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Divider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.databinding.DataBindingUtil
import coil.compose.AsyncImage
import com.navi.base.model.CtaData
import com.navi.base.utils.EMPTY
import com.navi.common.ui.fragment.BaseBottomSheet
import com.navi.design.font.FontWeightEnum
import com.navi.design.theme.getFontWeight
import com.navi.design.theme.ttComposeFontFamily
import com.navi.hl.R
import com.navi.hl.common.listeners.HLCommonBottomSheetListener
import com.navi.hl.databinding.BottomSheetHlTitleWithStartAndEndIconBinding
import com.navi.hl.landingpage.model.BottomSheetContent
import com.navi.hl.utils.NaviHLAnalytics
import com.navi.naviwidgets.extensions.NaviText
import com.navi.naviwidgets.models.response.TitleWithStartAndEndIconBottomSheetData
class TitleWithStartAndEndIconBottomSheet : BaseBottomSheet() {
private lateinit var binding: BottomSheetHlTitleWithStartAndEndIconBinding
private var listItems: List<TitleWithStartAndEndIconBottomSheetData> = emptyList()
private var listener: HLCommonBottomSheetListener? = null
override fun setContainerView(viewStub: ViewStub) {
viewStub.layoutResource = R.layout.bottom_sheet_hl_title_with_start_and_end_icon
binding = DataBindingUtil.getBinding(viewStub.inflate())!!
initUI()
}
private fun initUI() {
arguments?.getParcelable<BottomSheetContent>(BOTTOM_SHEET_DATA)?.let { bottomSheetContent ->
bottomSheetContent.content?.let {
listItems = it
}
}
binding.bottomSheetComposeView.setContent {
BottomSheetContent()
}
}
@Composable
fun BottomSheetContent() {
LazyColumn(
modifier = Modifier
.wrapContentHeight()
.padding(16.dp, 0.dp, 16.dp, 8.dp)
) {
items(listItems) { item ->
if (item.showDivider == true)
HorizontalDividerView()
else
TitleWithStartAndEndIconView(item, ::onItemClick)
}
}
}
@Composable
fun TitleWithStartAndEndIconView(
data: TitleWithStartAndEndIconBottomSheetData,
onItemClick: (CtaData) -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(0.dp, 16.dp, 0.dp, 24.dp)
.clickable { onItemClick(data.cta ?: CtaData()) },
verticalAlignment = Alignment.CenterVertically
) {
AsyncImage(
model = data.startIcon?.url,
contentDescription = EMPTY,
modifier = Modifier
.size(
width = (data.startIcon?.iconWidth ?: 24).dp,
height = (data.startIcon?.iconHeight ?: 24).dp
),
fallback = painterResource(id = R.drawable.ic_outlined_home_icon),
placeholder = painterResource(id = R.drawable.ic_outlined_home_icon),
error = painterResource(id = R.drawable.ic_outlined_home_icon),
)
NaviText(textFieldData = data.title, Modifier.padding(start = 12.dp))
Spacer(modifier = Modifier.weight(1f))
AsyncImage(
model = data.endIcon?.url,
contentDescription = EMPTY,
modifier = Modifier
.size(
width = (data.endIcon?.iconWidth ?: 24).dp,
height = (data.endIcon?.iconHeight ?: 24).dp
),
fallback = painterResource(id = R.drawable.ic_outlined_home_icon),
placeholder = painterResource(id = R.drawable.ic_outlined_home_icon),
error = painterResource(id = R.drawable.ic_outlined_home_icon),
)
}
}
@Composable
private fun HorizontalDividerView() {
Divider(
color = Color(0xFFE3E5E5),
thickness = 1.dp,
modifier = Modifier
.fillMaxWidth()
.padding(0.dp, 0.dp, 0.dp, 8.dp)
)
}
private fun onItemClick(ctaData: CtaData) {
listener?.onBsCtaClick(ctaData, TAG)
}
fun setBottomSheetListener(listener: HLCommonBottomSheetListener) {
this.listener = listener
}
override val screenName: String
get() = NaviHLAnalytics.HL_TITLE_WITH_START_AND_END_ICON_BOTTOM_SHEET
companion object {
private const val BOTTOM_SHEET_DATA = "BOTTOM_SHEET_DATA"
const val TAG = "HL_TITLE_WITH_START_AND_END_ICON_BOTTOM_SHEET"
fun getInstance(bottomSheetData: BottomSheetContent) =
TitleWithStartAndEndIconBottomSheet().apply {
val bundle = Bundle().apply {
putParcelable(BOTTOM_SHEET_DATA, bottomSheetData)
}
arguments = bundle
}
}
}

View File

@@ -24,6 +24,7 @@ import com.navi.base.utils.BaseUtils
import com.navi.common.utils.observeNullable
import com.navi.hl.common.customview.HLTopNavigationHeaderInterface
import com.navi.hl.common.listeners.BackListener
import com.navi.hl.common.listeners.HLCommonBottomSheetListener
import com.navi.hl.common.listeners.HLFooterListener
import com.navi.hl.common.ui.activity.Navigator
import com.navi.hl.common.ui.fragment.HomeLoanBaseFragment
@@ -33,13 +34,15 @@ import com.navi.hl.utils.NaviHLAnalytics
import com.navi.hl.utils.slideViewFromBottom
import com.navi.naviwidgets.adapters.NaviAdapter
import com.navi.hl.landingpage.bottomsheet.IconTitleDescriptionInfoCtaBottomSheet
import com.navi.hl.landingpage.bottomsheet.TitleWithStartAndEndIconBottomSheet
import com.navi.naviwidgets.callbacks.WidgetCallback
import com.navi.naviwidgets.models.NaviWidget
import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class HomeLoanLandingPageFragment : HomeLoanBaseFragment(), BackListener, HLFooterListener, WidgetCallback {
class HomeLoanLandingPageFragment : HomeLoanBaseFragment(), BackListener, HLFooterListener,
WidgetCallback, HLCommonBottomSheetListener {
private lateinit var binding: FragmentHlLandingPageBinding
private val hlLandingPageEventTracker =
@@ -147,8 +150,9 @@ class HomeLoanLandingPageFragment : HomeLoanBaseFragment(), BackListener, HLFoot
override fun onClick(naviClickAction: NaviClickAction, widgetId: String?) {
when (naviClickAction) {
is CtaData -> {
navigateTo(naviClickAction, false)
openBottomSheet(naviClickAction)
}
is NaviBenefitsItemClick -> {
hlLandingPageEventTracker.onBenefitsCardClicked(naviClickAction.ctaData)
naviClickAction.ctaData?.url?.let {
@@ -168,6 +172,7 @@ class HomeLoanLandingPageFragment : HomeLoanBaseFragment(), BackListener, HLFoot
}
}
}
is NaviWidgetClickWithCtaData -> {
hlLandingPageEventTracker.onVideoCardClicked(naviClickAction.ctaData)
navigateTo(naviClickAction.ctaData, false)
@@ -175,6 +180,18 @@ class HomeLoanLandingPageFragment : HomeLoanBaseFragment(), BackListener, HLFoot
}
}
private fun openBottomSheet(ctaData: CtaData?) {
viewModel.landingPageResponse.value?.content?.bottomSheetData?.let {
val bottomSheet = TitleWithStartAndEndIconBottomSheet.getInstance(it)
bottomSheet.setBottomSheetListener(this)
if (!isBottomSheetVisible(TitleWithStartAndEndIconBottomSheet.TAG)) {
safelyShowBottomSheet(bottomSheet, TitleWithStartAndEndIconBottomSheet.TAG)
}
} ?: run {
navigateTo(ctaData, false)
}
}
private fun navigateTo(cta: CtaData?, finish: Boolean = true) {
val navigator = activity
if (navigator is Navigator) {
@@ -183,7 +200,11 @@ class HomeLoanLandingPageFragment : HomeLoanBaseFragment(), BackListener, HLFoot
}
override fun onFooterCtaClick(ctaData: CtaData?) {
navigateTo(ctaData, finish = false)
openBottomSheet(ctaData)
}
override fun onBsCtaClick(ctaData: CtaData?, bottomSheetType: String) {
navigateTo(ctaData, false)
}
override val screenName: String

View File

@@ -7,11 +7,14 @@
package com.navi.hl.landingpage.model
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import com.navi.hl.common.models.HLFooter
import com.navi.hl.common.models.HLHeader
import com.navi.naviwidgets.models.NaviWidget
import com.navi.naviwidgets.models.response.TextFieldData
import com.navi.naviwidgets.models.response.TitleWithStartAndEndIconBottomSheetData
import kotlinx.parcelize.Parcelize
data class HLLandingPageResponse(
@SerializedName("header") var header: HLHeader? = null,
@@ -21,5 +24,11 @@ data class HLLandingPageResponse(
data class HLLandingPageContent(
@SerializedName("widgets") val widgets: List<NaviWidget>? = null,
@SerializedName("infoProviderText") val infoProviderText: TextFieldData? = null
@SerializedName("infoProviderText") val infoProviderText: TextFieldData? = null,
@SerializedName("bottomSheetData") val bottomSheetData: BottomSheetContent? = null
)
@Parcelize
data class BottomSheetContent(
@SerializedName("content") val content: List<TitleWithStartAndEndIconBottomSheetData>? = null
) : Parcelable

View File

@@ -18,6 +18,7 @@ class HomeLoanLandingPageRepository
constructor(private val retrofitService: RetrofitService) : ResponseCallback() {
suspend fun fetchLandingPageResponse(): RepoResult<HLLandingPageResponse> {
return apiResponseCallback(retrofitService.fetchHomeLoanLandingPageResponse())
return apiResponseCallback(retrofitService.fetchHomeLoanLandingPageResponse())
}
}

View File

@@ -434,11 +434,14 @@ class NaviHLAnalytics private constructor() {
const val HL_LANDING_PAGE = "HL_Landing_Page"
const val HL_HELP_BOTTOM_SHEET = "New_HL_Help_Bottom_Sheet"
const val HL_LOAN_DETAILS_BOTTOM_SHEET = "New_HL_Loan_Details_Bottom_Sheet"
const val HL_REVIEW_PROPERTY_DETAILS_BOTTOM_SHEET = "New_HL_Review_Property_Details_Bottom_Sheet"
const val HL_REVIEW_PROPERTY_DETAILS_BOTTOM_SHEET =
"New_HL_Review_Property_Details_Bottom_Sheet"
const val HL_ACC_AGGREGATOR_BOTTOM_SHEET = "New_HL_Account_Aggregator_Bottom_Sheet"
const val HL_EMI_PLAN_TAB_SCREEN = "New_HL_Emi_Plan_Tab_Screen"
const val HL_EMI_MONTH_SLIDER_BOTTOM_SHEET = "New_HL_Emi_Month_Slider_Bottom_Sheet"
const val HL_DOWPAYMENT_RANGE_BOTTOM_SHEET = "New_HL_Downpayment_Range_Bottom_Sheet"
const val HL_TITLE_WITH_START_AND_END_ICON_BOTTOM_SHEET =
"New_HL_Title_With_Start_And_End_Icon_Bottom_Sheet"
const val POST_FIX_LANDED = "_Landed"
const val POST_FIX_CLICKED = "_Clicked"

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/bottomSheetComposeView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -71,3 +71,12 @@ data class GenericWidgetTimerConfig(
@SerializedName("insertAt") val insertAt: Int? = null,
@SerializedName("baseString") val baseString: String? = null
): Parcelable
@Parcelize
data class TitleWithStartAndEndIconBottomSheetData(
@SerializedName("startIcon") val startIcon: ImageFieldData? = null,
@SerializedName("title") val title: TextFieldData? = null,
@SerializedName("endIcon") val endIcon: ImageFieldData? = null,
@SerializedName("showDivider") val showDivider: Boolean? = null,
@SerializedName("cta") val cta: CtaData? = null
) : Parcelable

View File

@@ -1,6 +1,6 @@
/*
*
* * Copyright © 2022 by Navi Technologies Limited
* * Copyright © 2022-2023 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
@@ -54,9 +54,9 @@ class ProductIntroWithButtonWidgetLayout @JvmOverloads constructor(
widgetData.productIntroWithButtonWidgetData?.let { productWidgetData ->
binding.tvAction.apply {
setOnClickListener {
widgetCallback.onClick(NaviWidgetClickWithCtaData(
ctaData = productWidgetData.cta
))
productWidgetData.cta?.let {
widgetCallback.onClick(it)
}
}
}
}
@@ -99,4 +99,4 @@ class ProductIntroWithButtonWidgetLayout @JvmOverloads constructor(
private const val DEFAULT_SLIDE_PERIOD_TIME = 2000L
}
}
}