reverse penny drop (#5399)
* reverse penny drop * id key * removed unused file
This commit is contained in:
committed by
GitHub Enterprise
parent
3b4fb0e4e9
commit
60dc080f04
@@ -23,10 +23,12 @@ kapt {
|
||||
}
|
||||
|
||||
|
||||
|
||||
def VERSION_CODE = 295
|
||||
def VERSION_NAME = "3.3.2"
|
||||
|
||||
|
||||
|
||||
android {
|
||||
namespace 'com.naviapp'
|
||||
compileSdk 32
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.navi.amc.common.adapter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.navi.amc.R
|
||||
import com.navi.amc.common.model.PennyDropOption
|
||||
import com.navi.amc.databinding.PennyDropOptionBinding
|
||||
import com.navi.amc.utils.ColorUtils
|
||||
import com.navi.amc.utils.orFalse
|
||||
import com.navi.base.utils.isValidIndex
|
||||
import com.navi.design.utils.*
|
||||
|
||||
class PennyDropOptionsAdapter(
|
||||
private val items: List<PennyDropOption>,
|
||||
val listener: ((PennyDropOption) -> Unit)? = null
|
||||
) : RecyclerView.Adapter<PennyDropOptionsViewHolder>() {
|
||||
var lastCheckedPosition = -1
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PennyDropOptionsViewHolder {
|
||||
return PennyDropOptionsViewHolder(
|
||||
DataBindingUtil.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
R.layout.penny_drop_option,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return items.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PennyDropOptionsViewHolder, position: Int) {
|
||||
if (!isValidIndex(position, itemCount)) return
|
||||
val itemData = items[position]
|
||||
holder.binding.apply {
|
||||
title.setSpannableString(itemData.title)
|
||||
subtitle.setSpannableString(itemData.subTitle)
|
||||
root.background =
|
||||
ColorUtils.getDarkGreyBorder8StrokeDrawable(holder.binding.root.context)
|
||||
label.isVisible = itemData.label?.let {
|
||||
label.setSpannableString(it.title)
|
||||
label.background = getNaviDrawable(
|
||||
radii = CornerRadius(
|
||||
leftBottom = dpToPx(4),
|
||||
rightTop = dpToPx(8)
|
||||
), backgroundColor = it.bgColor.parseColorSafe()
|
||||
)
|
||||
true
|
||||
} ?: run {
|
||||
false
|
||||
}
|
||||
if (lastCheckedPosition == -1 && itemData.isSelected.orFalse()) {
|
||||
lastCheckedPosition = position
|
||||
listener?.invoke(itemData)
|
||||
}
|
||||
radio.isChecked = (lastCheckedPosition == position)
|
||||
if (radio.isChecked || itemData.toShowNote.orFalse()) {
|
||||
note.setSpannableString(itemData.note?.title)
|
||||
note.background = getNaviDrawable(
|
||||
radii = CornerRadius(
|
||||
leftBottom = dpToPx(8),
|
||||
rightBottom = dpToPx(8)
|
||||
), backgroundColor = itemData.note?.bgColor.parseColorSafe()
|
||||
)
|
||||
} else {
|
||||
note.isVisible = false
|
||||
}
|
||||
radio.setOnClickListener {
|
||||
val tempLastCheckedPosition = lastCheckedPosition
|
||||
lastCheckedPosition = position
|
||||
notifyItemChanged(tempLastCheckedPosition)
|
||||
notifyItemChanged(lastCheckedPosition)
|
||||
listener?.invoke(itemData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PennyDropOptionsViewHolder(val binding: PennyDropOptionBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
@@ -0,0 +1,244 @@
|
||||
package com.navi.amc.common.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import com.navi.amc.R
|
||||
import com.navi.amc.common.activity.CheckerActivity
|
||||
import com.navi.amc.common.adapter.PennyDropOptionsAdapter
|
||||
import com.navi.amc.common.model.AdditionalDataAsyncResponse
|
||||
import com.navi.amc.common.model.NextCtaResponse
|
||||
import com.navi.amc.common.viewmodel.PennyDropOptionsViewModel
|
||||
import com.navi.amc.databinding.PennyDropOptionsLayoutBinding
|
||||
import com.navi.amc.utils.AmcAnalytics.BANK_VERIFICATION_OPTIONS
|
||||
import com.navi.amc.utils.AmcAnalytics.CHANGE_BANK
|
||||
import com.navi.amc.utils.AmcAnalytics.PENNY_DROP_OPTIONS
|
||||
import com.navi.amc.utils.Constant.RPD
|
||||
import com.navi.amc.utils.Constant.TOKEN
|
||||
import com.navi.amc.utils.Constant.UPILINK
|
||||
import com.navi.amc.utils.orValue
|
||||
import com.navi.base.model.ActionData
|
||||
import com.navi.base.model.CtaData
|
||||
import com.navi.common.firebasedb.FirebaseStatusType
|
||||
import com.navi.common.listeners.FragmentInterchangeListener
|
||||
import com.navi.common.listeners.HeaderInteractionListener
|
||||
import com.navi.common.model.RequestConfig
|
||||
import com.navi.common.utils.ApiPollScheduler
|
||||
import com.navi.common.utils.log
|
||||
import com.navi.common.utils.observeNonNull
|
||||
import com.navi.design.textview.model.NaviSpan
|
||||
import com.navi.design.textview.model.TextWithStyle
|
||||
import com.navi.design.utils.parseColorSafe
|
||||
import com.navi.design.utils.setSpannableString
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PennyDropOptionsFragment() : AmcBaseFragment() {
|
||||
|
||||
private lateinit var binding: PennyDropOptionsLayoutBinding
|
||||
private val viewModel by viewModels<PennyDropOptionsViewModel>()
|
||||
private lateinit var adapter: PennyDropOptionsAdapter
|
||||
private var apiPollScheduler: ApiPollScheduler? = null
|
||||
|
||||
override val screenName: String
|
||||
get() = BANK_VERIFICATION_OPTIONS
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
headerInteractionListener = context as? HeaderInteractionListener
|
||||
fragmentInterchangeListener = context as? FragmentInterchangeListener
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding =
|
||||
DataBindingUtil.inflate(inflater, R.layout.penny_drop_options_layout, container, false)
|
||||
sendInitEvent()
|
||||
initError(viewModel, showNewDesignSystemFragment = true, buttonListener = {
|
||||
when(it){
|
||||
CHANGE_BANK -> {
|
||||
fragmentInterchangeListener?.navigateToNextScreen(actionData = ActionData(url = "bank_details"))
|
||||
}
|
||||
else ->{
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
initObservers()
|
||||
fetchData()
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private fun sendInitEvent(){
|
||||
sendEvent(PENNY_DROP_OPTIONS)
|
||||
}
|
||||
|
||||
private fun initObservers() {
|
||||
viewModel.asyncResponse.observeNonNull(viewLifecycleOwner){
|
||||
if (it != null) {
|
||||
onPollingResponse(it)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.requestConfig.observeNonNull(viewLifecycleOwner){
|
||||
hideLoader()
|
||||
apiPollInit(it?.requestConfig)
|
||||
}
|
||||
viewModel.rpdPaymentDetails.observeNonNull(viewLifecycleOwner){
|
||||
it?.methodDetails?.get(UPILINK)?.let{
|
||||
upiIntent(it)
|
||||
}
|
||||
it?.tokenDetails?.requestId?.let{
|
||||
viewModel.requestId = it
|
||||
}
|
||||
}
|
||||
viewModel.tokenExpire.observeNonNull(viewLifecycleOwner){
|
||||
activity?.finish()
|
||||
}
|
||||
viewModel.pennyDropOptionsData.observeNonNull(viewLifecycleOwner) { data ->
|
||||
hideLoader()
|
||||
data?.header?.let {
|
||||
headerInteractionListener?.setProperties(it)
|
||||
}
|
||||
data?.content?.let {
|
||||
binding.title.setSpannableString(it.title)
|
||||
binding.subtitle.setSpannableString(it.subTitle)
|
||||
}
|
||||
data?.content?.items?.let { items ->
|
||||
adapter = PennyDropOptionsAdapter(
|
||||
items = items
|
||||
) {
|
||||
viewModel.paymentMethod = it
|
||||
}
|
||||
val itemDecorator = DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
|
||||
context?.let {
|
||||
ContextCompat.getDrawable(it, R.drawable.empty_space_divider)?.let { drawable ->
|
||||
itemDecorator.setDrawable(drawable)
|
||||
}
|
||||
}
|
||||
binding.options.addItemDecoration(itemDecorator)
|
||||
binding.options.adapter = adapter
|
||||
}
|
||||
data?.footer?.let {
|
||||
val termsText = it.title?.text + it.name?.text
|
||||
val style: MutableList<NaviSpan> = ArrayList()
|
||||
it.name?.style?.let { it1 -> style.addAll(it1) }
|
||||
it.title?.style?.let { it1 -> style.addAll(it1) }
|
||||
binding.terms.setSpannableString(TextWithStyle(text = termsText, style = style))
|
||||
binding.footer.btn.apply {
|
||||
text = it.nextCta?.title
|
||||
setTextColor(it.nextCta?.titleColor.parseColorSafe())
|
||||
setOnClickListener {
|
||||
if (viewModel.paymentMethod?.id.orEmpty() == RPD)
|
||||
arguments?.getString(TOKEN)
|
||||
?.let { it -> viewModel.fetchInitPaymentMethodDetails(token = it, methodId = RPD) }
|
||||
else {
|
||||
val action = viewModel.paymentMethod?.actionData
|
||||
fragmentInterchangeListener?.navigateToNextScreen(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val method = data?.content?.autoSelectMethod
|
||||
val list = data?.content?.items
|
||||
if (method.isNullOrEmpty().not()) {
|
||||
val item = list?.singleOrNull { it.id == method }
|
||||
if (item?.id.orEmpty() == RPD)
|
||||
arguments?.getString(TOKEN)
|
||||
?.let { it -> viewModel.fetchInitPaymentMethodDetails(token = it, methodId = RPD) }
|
||||
else {
|
||||
activity?.supportFragmentManager?.popBackStack()
|
||||
fragmentInterchangeListener?.navigateToNextScreen(actionData = item?.actionData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun apiPollInit(
|
||||
requestConfig : RequestConfig?
|
||||
) {
|
||||
apiPollScheduler =
|
||||
ApiPollScheduler(
|
||||
initialDelay =
|
||||
requestConfig?.initialDelay.orValue(0).toLong(),
|
||||
numberOfRetry = requestConfig
|
||||
?.numOfRetries
|
||||
.orValue(CheckerActivity.DEFAULT_RETRY_COUNT),
|
||||
pollInterval =
|
||||
requestConfig
|
||||
?.interval
|
||||
.orValue(ApiPollScheduler.API_POLL_REPEAT_PERIOD_SECONDS.toInt())
|
||||
.toLong(),
|
||||
doOnTimeout = { activity?.runOnUiThread { apiPollScheduler?.stopApiPoll()
|
||||
} }
|
||||
) {
|
||||
showLoader()
|
||||
viewModel.checkApiPollStatus()
|
||||
}
|
||||
apiPollScheduler?.scheduleApiPoll()
|
||||
}
|
||||
|
||||
private fun upiIntent(link: String) {
|
||||
try {
|
||||
val intent = Intent().apply {
|
||||
setAction(Intent.ACTION_VIEW)
|
||||
setData(Uri.parse(link))
|
||||
}
|
||||
startActivityForResult(intent, REQUEST_CODE)
|
||||
} catch (ex: Exception) {
|
||||
ex.log()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onPollingResponse(additonalData: AdditionalDataAsyncResponse<NextCtaResponse?>) {
|
||||
when {
|
||||
TextUtils.equals(additonalData.status, FirebaseStatusType.SUCCESS) -> {
|
||||
hideLoader()
|
||||
apiPollScheduler?.stopApiPoll()
|
||||
fragmentInterchangeListener?.navigateToNextScreen(additonalData.data?.nextCTA)
|
||||
}
|
||||
TextUtils.equals(additonalData.status, FirebaseStatusType.FAILURE) -> {
|
||||
hideLoader()
|
||||
apiPollScheduler?.stopApiPoll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
showLoader()
|
||||
viewModel.getRequestConfig()
|
||||
arguments?.getString(TOKEN)?.let{
|
||||
viewModel.postPaymentSignal(it, RPD)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchData() {
|
||||
showLoader()
|
||||
arguments?.getString(TOKEN)?.let{
|
||||
viewModel.fetchData(it)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REQUEST_CODE = 5001
|
||||
fun newInstance(bundle: Bundle): PennyDropOptionsFragment {
|
||||
return PennyDropOptionsFragment().apply {
|
||||
arguments = bundle
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.navi.amc.common.fragment
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.navi.amc.R
|
||||
import com.navi.amc.common.listener.FooterInteractionListener
|
||||
import com.navi.amc.common.view.ShimmerNoteView
|
||||
import com.navi.amc.common.viewmodel.RpdSuccessViewModel
|
||||
import com.navi.amc.databinding.KeyValueItemLayoutBinding
|
||||
import com.navi.amc.databinding.RpdSuccessLayoutBinding
|
||||
import com.navi.amc.utils.AmcAnalytics.RPD_SUCCESS_SCREEN
|
||||
import com.navi.amc.utils.Constant.CHANGE_BANK
|
||||
import com.navi.amc.utils.Constant.CONFIRMED
|
||||
import com.navi.amc.utils.SubPageStatusType.RPD_SUCCESS
|
||||
import com.navi.base.model.ActionData
|
||||
import com.navi.common.listeners.FragmentInterchangeListener
|
||||
import com.navi.common.listeners.HeaderInteractionListener
|
||||
import com.navi.common.utils.observeNonNull
|
||||
import com.navi.design.utils.dpToPxInInt
|
||||
import com.navi.design.utils.setSpannableString
|
||||
import com.navi.naviwidgets.extensions.showWhenDataIsAvailable
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class RpdSuccessFragment() : AmcBaseFragment(), FooterInteractionListener {
|
||||
private lateinit var binding: RpdSuccessLayoutBinding
|
||||
private val viewModel by viewModels<RpdSuccessViewModel>()
|
||||
|
||||
override val screenName: String
|
||||
get() = RPD_SUCCESS
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
headerInteractionListener = context as HeaderInteractionListener?
|
||||
fragmentInterchangeListener = context as FragmentInterchangeListener?
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = DataBindingUtil.inflate(inflater, R.layout.rpd_success_layout, container, false)
|
||||
sendInitEvent()
|
||||
initError(viewModel, showNewDesignSystemFragment = true)
|
||||
initObservers()
|
||||
fetchData()
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private fun fetchData() {
|
||||
showLoader()
|
||||
viewModel.fetchData()
|
||||
}
|
||||
|
||||
private fun sendInitEvent(){
|
||||
sendEvent(RPD_SUCCESS_SCREEN)
|
||||
}
|
||||
|
||||
private fun initObservers() {
|
||||
viewModel.rpdSuccessData.observeNonNull(viewLifecycleOwner) {
|
||||
hideLoader()
|
||||
it.header?.let {
|
||||
headerInteractionListener?.setProperties(it)
|
||||
headerInteractionListener?.hideDivider()
|
||||
}
|
||||
it.content?.let {
|
||||
binding.icon.showWhenDataIsAvailable(it.iconCode)
|
||||
binding.title.setSpannableString(it.title)
|
||||
binding.subtitle.setSpannableString(it.subtitle)
|
||||
binding.container.removeAllViews()
|
||||
it.detailsData?.items?.forEach { data ->
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val view = inflater.inflate(
|
||||
R.layout.key_value_item_layout,
|
||||
binding.container,
|
||||
false
|
||||
)
|
||||
view.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
val childBinding = DataBindingUtil.bind<KeyValueItemLayoutBinding>(view)
|
||||
childBinding?.key?.setSpannableString(data.key)
|
||||
childBinding?.value?.setSpannableString(data.value)
|
||||
binding.container.addView(view)
|
||||
}
|
||||
val view = View(context)
|
||||
view.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
dpToPxInInt(24)
|
||||
)
|
||||
binding.container.addView(view)
|
||||
it.detailsData?.note?.let { note ->
|
||||
val view = context?.let { it -> ShimmerNoteView(it) }
|
||||
view?.setProperties(note)
|
||||
binding.container.addView(view)
|
||||
}
|
||||
it.detailsData?.dataSafeWidget?.let {
|
||||
binding.dataSafe.data = it
|
||||
}
|
||||
val space = View(context)
|
||||
space.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
dpToPxInInt(16)
|
||||
)
|
||||
binding.container.addView(space)
|
||||
}
|
||||
it.footer?.let {
|
||||
binding.footer.setProperties(it, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(bundle: Bundle): RpdSuccessFragment {
|
||||
return RpdSuccessFragment().apply {
|
||||
arguments = bundle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFooterBackPress(actionData: ActionData?) {
|
||||
viewModel.postStatus(CHANGE_BANK)
|
||||
fragmentInterchangeListener?.navigateToNextScreen(actionData)
|
||||
}
|
||||
|
||||
override fun onFooterNextPress(actionData: ActionData?, skipValidation: Boolean?) {
|
||||
viewModel.postStatus(CONFIRMED)
|
||||
fragmentInterchangeListener?.navigateToNextScreen(actionData)
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class Footer(
|
||||
@SerializedName("customerName") var name: TextWithStyle? = null,
|
||||
@SerializedName("title") var title: TextWithStyle? = null,
|
||||
@SerializedName("nextCta") var nextCta: ActionData? = null,
|
||||
@SerializedName("backCta") var backCta: ActionData? = null,
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.navi.amc.common.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.navi.amc.kyc.model.Note
|
||||
import com.navi.base.model.ActionData
|
||||
import com.navi.common.model.Header
|
||||
import com.navi.common.model.LabelData
|
||||
import com.navi.design.textview.model.TextWithStyle
|
||||
|
||||
data class PennyDropOptionsScreenData(
|
||||
@SerializedName("header")
|
||||
val header: Header? = null,
|
||||
@SerializedName("content")
|
||||
val content: PennyDropOptionsContent? = null,
|
||||
@SerializedName("footer")
|
||||
val footer: Footer? = null
|
||||
)
|
||||
|
||||
data class PennyDropOptionsContent(
|
||||
@SerializedName("title")
|
||||
val title: TextWithStyle? = null,
|
||||
@SerializedName("subTitle")
|
||||
val subTitle: TextWithStyle? = null,
|
||||
@SerializedName("items")
|
||||
val items: List<PennyDropOption>? = null,
|
||||
@SerializedName("autoSelectMethod")
|
||||
val autoSelectMethod: String? = null
|
||||
)
|
||||
|
||||
data class PennyDropOption(
|
||||
@SerializedName("label")
|
||||
val label: LabelData? = null,
|
||||
@SerializedName("title")
|
||||
val title: TextWithStyle? = null,
|
||||
@SerializedName("isSelected")
|
||||
val isSelected: Boolean? = null,
|
||||
@SerializedName("id")
|
||||
val id: String? = null,
|
||||
@SerializedName("subTitle")
|
||||
val subTitle: TextWithStyle? = null,
|
||||
@SerializedName("toShowNote")
|
||||
val toShowNote: Boolean? = null,
|
||||
@SerializedName("note")
|
||||
val note: Note? = null,
|
||||
@SerializedName("actionData")
|
||||
val actionData : ActionData ?= null
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.navi.amc.common.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class RpdPaymentDetails(
|
||||
@SerializedName("tokenDetails")
|
||||
val tokenDetails: TokenDetails? = null,
|
||||
@SerializedName("methodDetails")
|
||||
val methodDetails: Map<String, String>? = null
|
||||
)
|
||||
|
||||
data class TokenDetails(
|
||||
@SerializedName("requestId")
|
||||
val requestId: String? = null
|
||||
)
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.navi.amc.common.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.navi.amc.kyc.model.Note
|
||||
import com.navi.common.model.Header
|
||||
import com.navi.design.textview.model.TextWithStyle
|
||||
import com.navi.naviwidgets.models.response.DataSafeWidget
|
||||
|
||||
data class RpdSuccessScreenData(
|
||||
@SerializedName("header")
|
||||
val header: Header? = null,
|
||||
@SerializedName("content")
|
||||
val content: RpdSuccessContentData? = null,
|
||||
@SerializedName("footer")
|
||||
val footer: Footer? = null
|
||||
)
|
||||
|
||||
data class RpdSuccessContentData(
|
||||
@SerializedName("iconCode")
|
||||
val iconCode: String? = null,
|
||||
@SerializedName("title")
|
||||
val title: TextWithStyle? = null,
|
||||
@SerializedName("subTitle")
|
||||
val subtitle: TextWithStyle? = null,
|
||||
@SerializedName("details")
|
||||
val detailsData: DetailsData? =null
|
||||
)
|
||||
|
||||
data class DetailsData(
|
||||
@SerializedName("items")
|
||||
val items: List<KeyValueData>? = null,
|
||||
@SerializedName("note")
|
||||
val note: Note? = null,
|
||||
@SerializedName("dataSafeWidget")
|
||||
val dataSafeWidget: DataSafeWidget? = null
|
||||
)
|
||||
|
||||
data class KeyValueData(
|
||||
@SerializedName("key")
|
||||
val key: TextWithStyle? = null,
|
||||
@SerializedName("value")
|
||||
val value: TextWithStyle? = null
|
||||
)
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.navi.amc.common.repo
|
||||
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.navi.amc.common.model.PennyDropOptionsScreenData
|
||||
import com.navi.amc.network.retrofit.RetrofitService
|
||||
import com.navi.amc.utils.Constant.PAYMENTS
|
||||
import com.navi.amc.utils.mockApiResponse
|
||||
import com.navi.common.network.models.RepoResult
|
||||
import com.navi.common.network.retrofit.ResponseCallback
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class PennyDropOptionsRepository @Inject constructor(private val retrofitService: RetrofitService) :
|
||||
ResponseCallback() {
|
||||
|
||||
/*suspend fun fetchPennyDropOptions(
|
||||
token: String,
|
||||
xTarget: String = PAYMENTS
|
||||
): RepoResult<PennyDropOptionsScreenData> {
|
||||
val type = object : TypeToken<PennyDropOptionsScreenData>() {}.type
|
||||
return mockApiResponse(type, "penny_drop")
|
||||
}*/
|
||||
|
||||
|
||||
suspend fun fetchPennyDropOptions(
|
||||
token: String,
|
||||
xTarget: String = PAYMENTS
|
||||
) = apiResponseCallback(retrofitService.fetchPennyDropOptions(token, xTarget))
|
||||
|
||||
/*suspend fun fetchInitPaymentMethodDetails(
|
||||
token:String,
|
||||
xTarget: String = PAYMENTS
|
||||
) :RepoResult<>{
|
||||
val type = object : TypeToken<PennyDropOptionsScreenData>() {}.type
|
||||
return mockApiResponse(type, "penny_drop")
|
||||
}*/
|
||||
suspend fun fetchInitPaymentMethodDetails(
|
||||
methodId: String,
|
||||
token: String,
|
||||
xTarget: String = PAYMENTS
|
||||
) = apiResponseCallback(retrofitService.fetchInitPaymentMethodDetails(methodId, token, xTarget))
|
||||
|
||||
suspend fun postSignal(token: String, method: String, xTarget: String = PAYMENTS) =
|
||||
retrofitService.postPaymentStatus(token, method, xTarget)
|
||||
|
||||
suspend fun getRequestConfig(requestId: String?) =
|
||||
apiResponseCallback(retrofitService.fetchRequestConfig(requestId))
|
||||
|
||||
suspend fun checkApiPollStatus(requestId: String?) = apiResponseCallback(retrofitService.checkApiPollStatus(requestId))
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.navi.amc.common.repo
|
||||
|
||||
import com.navi.amc.network.retrofit.RetrofitService
|
||||
import com.navi.common.network.retrofit.ResponseCallback
|
||||
import javax.inject.Inject
|
||||
|
||||
class RpdSuccessRepository @Inject constructor(private val retrofitService: RetrofitService) :
|
||||
ResponseCallback() {
|
||||
|
||||
/*suspend fun fetchRpdSuccess() : RepoResult<RpdSuccessScreenData> {
|
||||
val type = object : TypeToken<RpdSuccessScreenData>() {}.type
|
||||
return mockApiResponse(type, "penny_success")
|
||||
}*/
|
||||
|
||||
suspend fun fetchRpdSuccess() = apiResponseCallback(retrofitService.fetchRpdConfirmDetails())
|
||||
|
||||
suspend fun postStatus(status : String) = apiResponseCallback(retrofitService.postStatus(status))
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.navi.amc.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.navi.amc.R
|
||||
import com.navi.amc.databinding.ShimmerNoteViewBinding
|
||||
import com.navi.amc.kyc.model.Note
|
||||
import com.navi.base.utils.orFalse
|
||||
import com.navi.design.utils.*
|
||||
import com.navi.naviwidgets.utils.REWARDS_TOOLTIP_ANIMATION_DELAY
|
||||
|
||||
class ShimmerNoteView(context: Context, attributes: AttributeSet? = null) :
|
||||
ConstraintLayout(context, attributes) {
|
||||
private var binding: ShimmerNoteViewBinding
|
||||
|
||||
init {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
layoutParams = LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
binding = DataBindingUtil.inflate(inflater, R.layout.shimmer_note_view, this, true)
|
||||
}
|
||||
|
||||
fun setProperties(data: Note) {
|
||||
binding.title.setSpannableString(data.title)
|
||||
if (data.toShowShimmer.orFalse()) {
|
||||
binding.shimmer.isVisible = true
|
||||
binding.root.post {
|
||||
moveViewWithDistance(
|
||||
binding.shimmer,
|
||||
binding.root.width,
|
||||
REWARDS_TOOLTIP_ANIMATION_DELAY
|
||||
)
|
||||
}
|
||||
}
|
||||
binding.root.background = getNaviDrawable(
|
||||
cornerRadius = dpToPxInInt(8),
|
||||
backgroundColor = data.bgColor.parseColorSafe()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.navi.amc.common.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.navi.amc.common.model.*
|
||||
import com.navi.amc.common.repo.PennyDropOptionsRepository
|
||||
import com.navi.amc.utils.Constant.INVALID_TOKEN
|
||||
import com.navi.common.model.UploadDataAsyncResponse
|
||||
import com.navi.common.network.models.RepoResult
|
||||
import com.navi.common.viewmodel.BaseVM
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class PennyDropOptionsViewModel @Inject constructor(private val repository: PennyDropOptionsRepository) :
|
||||
BaseVM() {
|
||||
|
||||
var requestId: String? = null
|
||||
|
||||
private val _pennyDropOptionsData = MutableLiveData<PennyDropOptionsScreenData?>()
|
||||
val pennyDropOptionsData: LiveData<PennyDropOptionsScreenData?>
|
||||
get() = _pennyDropOptionsData
|
||||
|
||||
private val _rpdPaymentDetails = MutableLiveData<RpdPaymentDetails?>()
|
||||
val rpdPaymentDetails: LiveData<RpdPaymentDetails?>
|
||||
get() = _rpdPaymentDetails
|
||||
|
||||
private val _tokenExpire = MutableLiveData<Boolean>()
|
||||
val tokenExpire: LiveData<Boolean>
|
||||
get() = _tokenExpire
|
||||
|
||||
private val _requestConfig = MutableLiveData<UploadDataAsyncResponse?>()
|
||||
val requestConfig: LiveData<UploadDataAsyncResponse?>
|
||||
get() = _requestConfig
|
||||
|
||||
private val _asyncResponse = MutableLiveData<AdditionalDataAsyncResponse<NextCtaResponse?>?>()
|
||||
val asyncResponse: LiveData<AdditionalDataAsyncResponse<NextCtaResponse?>?>
|
||||
get() = _asyncResponse
|
||||
|
||||
var paymentMethod: PennyDropOption? = null
|
||||
|
||||
|
||||
fun fetchData(token: String) {
|
||||
viewModelScope.launch {
|
||||
val response = repository.fetchPennyDropOptions(token = token)
|
||||
if (response.error == null && response.errors.isNullOrEmpty())
|
||||
_pennyDropOptionsData.value = response.data
|
||||
else {
|
||||
if (response.errors?.singleOrNull { it.code == INVALID_TOKEN } != null) {
|
||||
_tokenExpire.value = true
|
||||
} else {
|
||||
setErrorData(response.errors, response.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchInitPaymentMethodDetails(token: String, methodId: String) {
|
||||
viewModelScope.launch {
|
||||
val response =
|
||||
repository.fetchInitPaymentMethodDetails(token = token, methodId = methodId)
|
||||
if (response.error == null && response.errors.isNullOrEmpty()) {
|
||||
_rpdPaymentDetails.value = response.data
|
||||
} else {
|
||||
setErrorData(response.errors, response.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun postPaymentSignal(token: String, method: String) {
|
||||
viewModelScope.launch {
|
||||
repository.postSignal(token, method)
|
||||
}
|
||||
}
|
||||
|
||||
fun getRequestConfig() {
|
||||
viewModelScope.launch {
|
||||
val response = repository.getRequestConfig(requestId)
|
||||
if (response.error == null && response.errors.isNullOrEmpty()) {
|
||||
_requestConfig.value = response.data
|
||||
} else {
|
||||
setErrorData(response.errors, response.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkApiPollStatus() {
|
||||
viewModelScope.launch {
|
||||
val response = repository.checkApiPollStatus(requestId)
|
||||
if (response.error == null && response.errors.isNullOrEmpty()) {
|
||||
_asyncResponse.value = response.data
|
||||
} else {
|
||||
setErrorData(response.errors, response.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.navi.amc.common.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.navi.amc.common.model.RpdSuccessScreenData
|
||||
import com.navi.amc.common.repo.RpdSuccessRepository
|
||||
import com.navi.common.constants.API_SUCCESS_CODE
|
||||
import com.navi.common.viewmodel.BaseVM
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class RpdSuccessViewModel @Inject constructor(private val repository: RpdSuccessRepository) :
|
||||
BaseVM() {
|
||||
|
||||
private val _rpdSuccessData = MutableLiveData<RpdSuccessScreenData>()
|
||||
val rpdSuccessData: LiveData<RpdSuccessScreenData>
|
||||
get() = _rpdSuccessData
|
||||
|
||||
private val _success = MutableLiveData<Boolean>()
|
||||
val success: LiveData<Boolean>
|
||||
get() = _success
|
||||
|
||||
fun fetchData() {
|
||||
viewModelScope.launch {
|
||||
val response = repository.fetchRpdSuccess()
|
||||
if (response.error == null && response.errors.isNullOrEmpty()) {
|
||||
_rpdSuccessData.value = response.data!!
|
||||
} else {
|
||||
setErrorData(response.errors, response.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun postStatus(status : String){
|
||||
viewModelScope.launch{
|
||||
val response = repository.postStatus(status)
|
||||
if(response.statusCode == API_SUCCESS_CODE){
|
||||
_success.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,6 @@
|
||||
|
||||
package com.navi.amc.fundbuy.fragments
|
||||
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.navi.amc.kyc.model.BankDetailsResponse
|
||||
import com.navi.amc.kyc.viewmodel.BankDetailsVM
|
||||
import com.navi.amc.utils.*
|
||||
import com.navi.base.model.ActionData
|
||||
import com.navi.base.model.LineItem
|
||||
import com.navi.base.model.NaviClickAction
|
||||
import com.navi.base.model.NaviWidgetClickWithActionData
|
||||
import com.navi.common.listeners.FragmentInterchangeListener
|
||||
|
||||
@@ -34,4 +34,5 @@ data class Note(
|
||||
@SerializedName("bgColor") val bgColor: String? = null,
|
||||
@SerializedName("iconCode") val iconCode: String? = null,
|
||||
@SerializedName("title") val title: TextWithStyle? = null,
|
||||
@SerializedName("toShowShimmer") val toShowShimmer: Boolean? = null
|
||||
) : Parcelable
|
||||
|
||||
@@ -33,6 +33,27 @@ class NaviHttpClient(networkInfo: NetworkInfo, private val context: Context) :
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
okHttpClientBuilder.addInterceptor {
|
||||
|
||||
val oldRequest = it.request()
|
||||
val newRequest = oldRequest.newBuilder()
|
||||
val newHeaders = oldRequest.headers.newBuilder()
|
||||
|
||||
val multiMap = oldRequest.headers.toMultimap()
|
||||
|
||||
for (pair in multiMap) {
|
||||
if (pair.value.size > 1) {
|
||||
newHeaders.removeAll(pair.key)
|
||||
newHeaders.add(pair.key, pair.value.first())
|
||||
}
|
||||
}
|
||||
|
||||
newRequest.headers(newHeaders.build())
|
||||
it.proceed(newRequest.build())
|
||||
}
|
||||
|
||||
return okHttpClientBuilder
|
||||
}
|
||||
|
||||
|
||||
@@ -368,4 +368,36 @@ interface RetrofitService {
|
||||
|
||||
@GET("/fund/fund-details-nfo")
|
||||
suspend fun fetchNfoDetails(@Query("isin") isin: String): Response<GenericResponse<NfoDetailsScreenData>>
|
||||
|
||||
@GET("/payment-method")
|
||||
suspend fun fetchPennyDropOptions(
|
||||
@Header("X-Payments-SDK-Token") token: String,
|
||||
@Header("X-Target") header: String
|
||||
): Response<GenericResponse<PennyDropOptionsScreenData>>
|
||||
|
||||
@GET("/payment-method/details/{methodId}")
|
||||
suspend fun fetchInitPaymentMethodDetails(
|
||||
@Path("methodId") methodId: String,
|
||||
@Header("X-Payments-SDK-Token") token: String,
|
||||
@Header("X-Target") header: String
|
||||
): Response<GenericResponse<RpdPaymentDetails>>
|
||||
|
||||
@POST("payment-method/signal/{method}")
|
||||
suspend fun postPaymentStatus(
|
||||
@Header("X-Payments-SDK-Token") token: String,
|
||||
@Path("method") method: String,
|
||||
@Header("X-Target") xTarget: String
|
||||
): Response<Any>
|
||||
|
||||
@GET("/kyc/rpd-confirm-page")
|
||||
suspend fun fetchRpdConfirmDetails(): Response<GenericResponse<RpdSuccessScreenData>>
|
||||
|
||||
@GET("/requests/{requestId}/request-details-config")
|
||||
suspend fun fetchRequestConfig(@Path("requestId") requestId: String?): Response<GenericResponse<UploadDataAsyncResponse>>
|
||||
|
||||
@GET("/requests/{requestId}")
|
||||
suspend fun checkApiPollStatus(@Path("requestId") requestId: String?): Response<GenericResponse<AdditionalDataAsyncResponse<NextCtaResponse?>?>>
|
||||
|
||||
@POST("/kyc/rpd/bank-status/{status}")
|
||||
suspend fun postStatus(@Path("status") status : String):Response<GenericResponse<Any>>
|
||||
}
|
||||
|
||||
@@ -156,6 +156,10 @@ object AmcAnalytics {
|
||||
const val COARSE_LOCATION_PERMISSION_ALLOWED = "amc_btn_permission_coarse_location_allow"
|
||||
const val COARSE_LOCATION_PERMISSION_DENIED = "amc_btn_permission_coarse_location_deny"
|
||||
const val NFO_SCREEN = "nfoScreen"
|
||||
const val BANK_VERIFICATION_OPTIONS = "bank_verification_options"
|
||||
const val PENNY_DROP_OPTIONS = "amc_init_kyc_bank_verify"
|
||||
const val CHANGE_BANK = "changeBank"
|
||||
const val RPD_SUCCESS_SCREEN = "amc_init_kyc_bank_verify_success"
|
||||
|
||||
const val AMC_INIT_SIMPLIFIED_LUMPSUM = "amc_init_simplified_lumpsum"
|
||||
const val AMC_INIT_SIMPLIFIED_SIP = "amc_init_simplified_sip"
|
||||
|
||||
@@ -81,6 +81,13 @@ object Constant {
|
||||
const val DOWNLOADING = "Downloading"
|
||||
const val V2 ="v2"
|
||||
const val PACKAGE = "package:"
|
||||
const val TOKEN = "token"
|
||||
const val PAYMENTS = "PAYMENTS"
|
||||
const val RPD = "RPD"
|
||||
const val UPILINK= "upiLink"
|
||||
const val INVALID_TOKEN = "INVALID_TOKEN"
|
||||
const val CHANGE_BANK = "CHANGE_BANK"
|
||||
const val CONFIRMED = "CONFIRMED"
|
||||
const val BUSINESS_VERTICAL_AMC = "AMC"
|
||||
const val UPI = "UPI"
|
||||
}
|
||||
|
||||
@@ -197,6 +197,8 @@ fun getFragment(screen: String, bundle: Bundle): Fragment? {
|
||||
SubPageStatusType.SIP_DETAILS_MODIFY -> ModifySipDetailsFragment.newInstance(bundle)
|
||||
SubPageStatusType.SIP_MODIFICATION -> SipModifyFragment.newInstance(bundle)
|
||||
SubPageStatusType.NFO_DETAILS -> NfoDetailsFragment.newInstance(bundle)
|
||||
SubPageStatusType.BANK_ADDITION_OPTIONS -> PennyDropOptionsFragment.newInstance(bundle)
|
||||
SubPageStatusType.RPD_SUCCESS -> RpdSuccessFragment.newInstance(bundle)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,4 +53,6 @@ object SubPageStatusType {
|
||||
const val AMC_COMMON_BOTTOMSHEET = "AMC_COMMON_BOTTOMSHEET"
|
||||
const val BANNER_HORIZONTAL_BOTTOMSHEET = "BANNER_HORIZONTAL_BOTTOMSHEET"
|
||||
const val NFO_DETAILS = "nfo_details"
|
||||
const val BANK_ADDITION_OPTIONS = "bank_addition_options"
|
||||
const val RPD_SUCCESS = "rpd_success"
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
layout="@layout/amc_fund_list_reward"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dp_8"/>
|
||||
android:layout_marginBottom="@dimen/dp_8" />
|
||||
|
||||
<com.navi.amc.fundbuy.views.AmcHeaderView
|
||||
android:id="@+id/header"
|
||||
|
||||
35
navi-amc/src/main/res/layout/key_value_item_layout.xml
Normal file
35
navi-amc/src/main/res/layout/key_value_item_layout.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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">
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/key"
|
||||
android:layout_width="@dimen/dp_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_16"
|
||||
android:gravity="start"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/value"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:text="Bank name"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/value"
|
||||
android:layout_width="@dimen/dp_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_16"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:text="HDFC"
|
||||
android:gravity="end"
|
||||
app:layout_constraintStart_toEndOf="@id/key"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
75
navi-amc/src/main/res/layout/penny_drop_option.xml
Normal file
75
navi-amc/src/main/res/layout/penny_drop_option.xml
Normal file
@@ -0,0 +1,75 @@
|
||||
<?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">
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:letterSpacing="0.16"
|
||||
android:paddingStart="@dimen/dp_8"
|
||||
android:paddingTop="@dimen/dp_2"
|
||||
android:paddingEnd="@dimen/dp_8"
|
||||
android:paddingBottom="@dimen/dp_2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="RECOMMENDED" />
|
||||
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_16"
|
||||
android:layout_marginTop="@dimen/dp_16"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Via UPI" />
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_16"
|
||||
android:layout_marginTop="@dimen/dp_4"
|
||||
android:layout_marginBottom="@dimen/dp_16"
|
||||
app:layout_constraintBottom_toTopOf="@id/note"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
tools:text="Deposit ₹1 via Gpay, Phonepe etc." />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dp_16"
|
||||
android:button="@drawable/radio_selector"
|
||||
app:layout_constraintBottom_toTopOf="@id/note"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/note"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_1"
|
||||
android:layout_marginEnd="@dimen/dp_1"
|
||||
android:layout_marginBottom="@dimen/dp_1"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/dp_16"
|
||||
android:paddingTop="@dimen/dp_8"
|
||||
android:paddingEnd="@dimen/dp_16"
|
||||
android:paddingBottom="@dimen/dp_8"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/subtitle"
|
||||
tools:text="Amount will be refunded within 24-48 hours" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
69
navi-amc/src/main/res/layout/penny_drop_options_layout.xml
Normal file
69
navi-amc/src/main/res/layout/penny_drop_options_layout.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<?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="match_parent">
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="@dimen/dp_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_16"
|
||||
android:layout_marginTop="@dimen/dp_8"
|
||||
android:layout_marginEnd="@dimen/dp_16"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Bank Verification" />
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="@dimen/dp_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_16"
|
||||
android:layout_marginTop="@dimen/dp_4"
|
||||
android:layout_marginEnd="@dimen/dp_16"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
tools:text="Choose options to verify your bank details" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/options"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_0"
|
||||
android:layout_marginStart="@dimen/dp_16"
|
||||
android:layout_marginTop="@dimen/dp_26"
|
||||
android:layout_marginEnd="@dimen/dp_16"
|
||||
android:orientation="vertical"
|
||||
android:visibility="visible"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toTopOf="@id/terms"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/subtitle" />
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/terms"
|
||||
android:layout_width="@dimen/dp_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_16"
|
||||
android:layout_marginEnd="@dimen/dp_16"
|
||||
app:layout_constraintBottom_toTopOf="@id/footer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<include
|
||||
android:id="@+id/footer"
|
||||
layout="@layout/footer_btn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_96"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
92
navi-amc/src/main/res/layout/rpd_success_layout.xml
Normal file
92
navi-amc/src/main/res/layout/rpd_success_layout.xml
Normal file
@@ -0,0 +1,92 @@
|
||||
<?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="match_parent">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_0"
|
||||
app:layout_constraintBottom_toTopOf="@id/footer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/dp_100">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="@dimen/dp_60"
|
||||
android:layout_height="@dimen/dp_60"
|
||||
android:layout_marginTop="@dimen/dp_32"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_30"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/icon"
|
||||
tools:text="Verification successful" />
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_8"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
tools:text="Please confirm your bank details to proceed." />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="@dimen/dp_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_16"
|
||||
android:layout_marginTop="@dimen/dp_24"
|
||||
android:layout_marginEnd="@dimen/dp_16"
|
||||
android:layout_marginBottom="@dimen/dp_2"
|
||||
app:cardCornerRadius="@dimen/dp_8"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/subtitle">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_16"
|
||||
android:layout_marginTop="@dimen/dp_24"
|
||||
android:layout_marginEnd="@dimen/dp_16"
|
||||
android:orientation="vertical" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<include
|
||||
android:id="@+id/data_safe"
|
||||
layout="@layout/data_safe_layout"
|
||||
app:layout_constraintBottom_toTopOf="@id/footer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.navi.amc.common.view.FooterView
|
||||
android:id="@+id/footer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
32
navi-amc/src/main/res/layout/shimmer_note_view.xml
Normal file
32
navi-amc/src/main/res/layout/shimmer_note_view.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?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">
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="@dimen/dp_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/dp_16"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Note: Please use ONLY this account for all future transactions to avoid payment failures." />
|
||||
|
||||
<com.navi.design.customview.ParallelogramView
|
||||
android:id="@+id/shimmer"
|
||||
android:layout_width="@dimen/dp_32"
|
||||
android:layout_height="@dimen/dp_0"
|
||||
android:layout_gravity="start"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tilt_direction="forward" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
@@ -37,7 +37,8 @@ interface ApiCallListener {
|
||||
showFullScreenError: Boolean = false,
|
||||
container: Int? = null,
|
||||
showNewDesignSystemFragment: Boolean = false,
|
||||
actionErrorV2Enabled: Boolean = false
|
||||
actionErrorV2Enabled: Boolean = false,
|
||||
buttonListener: ((String) -> Unit)? = null
|
||||
)
|
||||
|
||||
fun onWarning(
|
||||
|
||||
@@ -170,7 +170,8 @@ abstract class BaseActivity :
|
||||
showFullScreenError: Boolean = false,
|
||||
container: Int? = null,
|
||||
showNewDesignSystemFragment: Boolean = false,
|
||||
actionErrorV2Enabled: Boolean = false
|
||||
actionErrorV2Enabled: Boolean = false,
|
||||
buttonListener: ((String) -> Unit)? = null
|
||||
) {
|
||||
if (viewModel.errorResponse.hasActiveObservers()) return
|
||||
viewModel.errorResponse.observeNonNull(this) { response ->
|
||||
@@ -218,8 +219,9 @@ abstract class BaseActivity :
|
||||
sourceScreenName = eventTrackingScreenName
|
||||
?: getCurrentFragmentScreenName(),
|
||||
secondaryAction = actions?.getOrNull(1)?.first,
|
||||
moduleName = getCurrentModuleName()
|
||||
)
|
||||
moduleName = getCurrentModuleName(),
|
||||
buttonListener = buttonListener
|
||||
)
|
||||
ft.add(errorFragment, NewActionErrorFragment.TAG)
|
||||
ft.commitAllowingStateLoss()
|
||||
} else {
|
||||
@@ -442,7 +444,8 @@ abstract class BaseActivity :
|
||||
showFullScreenError: Boolean,
|
||||
container: Int?,
|
||||
showNewDesignSystemFragment: Boolean,
|
||||
actionErrorV2Enabled: Boolean
|
||||
actionErrorV2Enabled: Boolean,
|
||||
buttonListener: ((String) -> Unit)?
|
||||
) {
|
||||
initError(
|
||||
viewModel,
|
||||
@@ -453,7 +456,8 @@ abstract class BaseActivity :
|
||||
showFullScreenError,
|
||||
container,
|
||||
showNewDesignSystemFragment,
|
||||
actionErrorV2Enabled
|
||||
actionErrorV2Enabled,
|
||||
buttonListener
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,8 @@ abstract class BaseFragment : Fragment() {
|
||||
showFullScreenError: Boolean = false,
|
||||
container: Int? = null,
|
||||
showNewDesignSystemFragment: Boolean = false,
|
||||
actionErrorV2Enabled: Boolean = false
|
||||
actionErrorV2Enabled: Boolean = false ,
|
||||
buttonListener: ((String) -> Unit)? = null
|
||||
) {
|
||||
apiCallListener?.onError(
|
||||
viewModel,
|
||||
@@ -87,7 +88,8 @@ abstract class BaseFragment : Fragment() {
|
||||
showFullScreenError,
|
||||
container,
|
||||
showNewDesignSystemFragment,
|
||||
actionErrorV2Enabled
|
||||
actionErrorV2Enabled,
|
||||
buttonListener
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ class NewActionErrorFragment : BaseBottomSheet() {
|
||||
private var cancelableDialog: Boolean = true
|
||||
private var error: GenericErrorResponse? = null
|
||||
private val analyticsTracker = CommonNaviAnalytics.naviAnalytics.ErrorBottomSheet()
|
||||
private var buttonListener: ((String) -> Unit)? = null
|
||||
|
||||
override fun setContainerView(viewStub: ViewStub) {
|
||||
viewStub.layoutResource = R.layout.new_action_error_fragment
|
||||
@@ -108,12 +109,18 @@ class NewActionErrorFragment : BaseBottomSheet() {
|
||||
view.tag = error?.code
|
||||
action?.let { action?.onClick(view) }
|
||||
?: kotlin.run { openErrorCta(error?.actions?.firstOrNull()) }
|
||||
error?.actions?.getOrNull(0)?.url?.let {
|
||||
buttonListener?.invoke(it)
|
||||
}
|
||||
dismissDialog()
|
||||
}
|
||||
if (error?.actions?.size.orZero() > 1) {
|
||||
binding.secondaryAbv.visibility = View.VISIBLE
|
||||
binding.secondaryAbv.setOnClickListener { view ->
|
||||
view.tag = error?.code
|
||||
error?.actions?.getOrNull(1)?.url?.let{
|
||||
buttonListener?.invoke(it)
|
||||
}
|
||||
secondaryAction?.let { secondaryAction?.onClick(view) }
|
||||
?: kotlin.run { openErrorCta(error?.actions?.getOrNull(1)) }
|
||||
dismissDialog()
|
||||
@@ -205,11 +212,13 @@ class NewActionErrorFragment : BaseBottomSheet() {
|
||||
cancelable: Boolean = true,
|
||||
sourceScreenName: String?,
|
||||
secondaryAction: View.OnClickListener? = null,
|
||||
moduleName: String? = null
|
||||
moduleName: String? = null,
|
||||
buttonListener: ((String) -> Unit)? = null
|
||||
) =
|
||||
NewActionErrorFragment().apply {
|
||||
this.action = action
|
||||
this.secondaryAction = secondaryAction
|
||||
this.buttonListener = buttonListener
|
||||
arguments =
|
||||
Bundle().apply {
|
||||
error?.let { putParcelable(ERROR_DATA, it) }
|
||||
|
||||
Reference in New Issue
Block a user