Feature/feedback on get loan journey (#868)

* started ...

* feedback continue..

* api intgration

* feedback success added, api submit
This commit is contained in:
Satish Prasad
2020-06-20 13:54:56 +05:30
committed by GitHub Enterprise
parent 97573e6288
commit 2350a025d3
24 changed files with 714 additions and 46 deletions

View File

@@ -19,7 +19,7 @@
<application
android:name=".app.NaviApplication"
android:allowBackup="true"
android:allowBackup="false"
android:fullBackupContent="@xml/backup_descriptor"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@@ -28,7 +28,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:replace="android:fullBackupContent">
tools:replace="android:allowBackup,android:fullBackupContent">
<activity
android:name=".registration.SplashActivity"
android:screenOrientation="portrait"

View File

@@ -464,6 +464,7 @@ class NaviAnalytics private constructor() {
const val SYSTEM_UNDER_MAINTENANCE_SCREEN = "system_under_maintenance_screen"
const val MORATORIUM_BOTTOM_SHEET = "moratorium_bottomsheet"
const val RATING_SCREEN = "rating_screen"
const val FEEDBACK_SCREEN = "feedback_screen"
const val TRUE = "true"
const val FALSE = "false"

View File

@@ -19,7 +19,7 @@ import android.widget.TextView
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.ViewModelProvider
import com.naviapp.R
import com.naviapp.analytics.FcmAnalyticsUtil
import com.naviapp.analytics.NaviAnalytics
@@ -28,6 +28,8 @@ import com.naviapp.appupdate.activities.UpdateAppActivity
import com.naviapp.appupdate.viewmodel.UpdateAppVM
import com.naviapp.common.listeners.ActivityFinishListener
import com.naviapp.common.listeners.ApiCallListener
import com.naviapp.common.listeners.FeedbackListener
import com.naviapp.common.listeners.FetchFeedbackListener
import com.naviapp.common.navigator.ErrorNavigator
import com.naviapp.common.navigator.ScreenNavigator
import com.naviapp.errors.fragments.ActionErrorFragment
@@ -36,27 +38,34 @@ import com.naviapp.errors.utils.getExitResponse
import com.naviapp.errors.utils.getTimeOutErrorData
import com.naviapp.firebasedb.FirebaseDataHelper
import com.naviapp.loader.NaviLoader
import com.naviapp.models.FeedbackOption
import com.naviapp.models.FeedbackPageType
import com.naviapp.models.FeedbackResponse
import com.naviapp.models.FeedbackSubmitData
import com.naviapp.network.models.GenericErrorResponse
import com.naviapp.network.models.GenericWarningResponse
import com.naviapp.utils.hideKeyboard
import com.naviapp.utils.log
import com.naviapp.utils.observeNonNull
import com.naviapp.utils.observeNullable
import com.naviapp.utils.orTrue
import com.naviapp.utils.*
abstract class BaseActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListener,
ApiCallListener, ActivityFinishListener {
ApiCallListener, ActivityFinishListener, FetchFeedbackListener {
private var toolbar: Toolbar? = null
private var toolbarHeading: TextView? = null
private var loader: NaviLoader? = null
val appUpgradeVM by lazy { ViewModelProviders.of(this).get(UpdateAppVM::class.java) }
val appUpgradeVM by lazy { ViewModelProvider(this).get(UpdateAppVM::class.java) }
val errorNavigator by lazy { ErrorNavigator() }
var isActivityActive: Boolean = false
private var feedbackData: FeedbackResponse? = null
private var feedbackScreenName: String? = null
var feedbackListener: FeedbackListener? = null
private val feedbackVM by lazy { ViewModelProvider(this).get(FeedbackVM::class.java) }
private var feedbackSubmitted: Boolean = false
override fun setContentView(@LayoutRes layoutResID: Int) {
super.setContentView(layoutResID)
initError(appUpgradeVM)
@@ -64,10 +73,13 @@ abstract class BaseActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListen
initUi()
if (screenName.isNotBlank())
NaviTrackEvent.startScreen(screenName)
initFeedbackListener()
}
private fun initObservers() {
appUpdateObserver()
feedbackObserver()
}
fun initError(viewModel: BaseVM, actions: List<Pair<View.OnClickListener, String>>? = null) {
@@ -135,10 +147,16 @@ abstract class BaseActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListen
override fun onBackPressed() {
if (isTaskRoot) {
val appExitWarning = getExitResponse()
openWarningDialog(appExitWarning, null, View.OnClickListener {
if (!feedbackSubmitted && feedbackData != null && feedbackData?.collect.orFalse() && feedbackScreenName != null && feedbackListener != null) {
feedbackListener?.showFeedbackScreen(feedbackScreenName, data = feedbackData)
} else if (feedbackSubmitted) {
super.onBackPressed()
})
} else {
val appExitWarning = getExitResponse()
openWarningDialog(appExitWarning, null, View.OnClickListener {
super.onBackPressed()
})
}
} else {
super.onBackPressed()
}
@@ -192,6 +210,12 @@ abstract class BaseActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListen
}
}
private fun feedbackObserver() {
feedbackVM.feedbackResponse.observeNonNull(this) {
feedbackData = it
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
when (requestCode) {
@@ -317,6 +341,53 @@ abstract class BaseActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListen
errorNavigator.showErrorScreen(this, errorData, actions)
}
private fun initFeedbackListener() {
feedbackVM.deInit()
feedbackSubmitted = false
feedbackData = null
feedbackScreenName = null
feedbackListener = null
feedbackListener = object : FeedbackListener {
override fun showFeedbackScreen(screen: String?, data: FeedbackResponse?) {
if (isDead()) return
if (data != null && screen != null) {
try {
val feedbackDialog =
FeedbackFragment.getInstance(screen, data)
val ft = this@BaseActivity.supportFragmentManager.beginTransaction()
ft.add(feedbackDialog, FeedbackFragment.TAG)
ft.commitAllowingStateLoss()
} catch (e: Exception) {
e.log()
onBackPressed()
}
} else {
onBackPressed()
}
}
}
}
override fun onFeedbackSubmitted(pageCode: String) {
feedbackSubmitted = true
onBackPressed()
}
override fun onFetchFeedbackOption(screen: String) {
initFeedbackListener()
feedbackScreenName = screen
feedbackVM.fetchFeedOptions(screen)
}
override fun onFeedbackCancel(screen: String) {
}
override fun onInvalidData(screen: String) {
feedbackSubmitted = true
onBackPressed()
}
open fun isDead(): Boolean {
return isFinishing || isDestroyed
}

View File

@@ -13,6 +13,7 @@ import androidx.fragment.app.Fragment
import com.naviapp.analytics.NaviTrackEvent
import com.naviapp.common.listeners.ActivityFinishListener
import com.naviapp.common.listeners.ApiCallListener
import com.naviapp.common.listeners.FetchFeedbackListener
import com.naviapp.common.navigator.ErrorNavigator
import com.naviapp.errors.utils.getTimeOutErrorData
import com.naviapp.firebasedb.FirebaseDataHelper
@@ -23,6 +24,7 @@ abstract class BaseFragment : Fragment() {
private var apiCallListener: ApiCallListener? = null
var activityFinishListener: ActivityFinishListener? = null
var fetchFeedbackListener: FetchFeedbackListener? = null
val errorNavigator by lazy { ErrorNavigator() }
@@ -103,6 +105,7 @@ abstract class BaseFragment : Fragment() {
super.onAttach(context)
apiCallListener = context as? ApiCallListener
activityFinishListener = context as? ActivityFinishListener
fetchFeedbackListener = context as? FetchFeedbackListener
}
protected abstract val screenName: String

View File

@@ -35,14 +35,15 @@ import timber.log.Timber
import java.net.ConnectException
import java.net.SocketTimeoutException
abstract class BaseVM : ViewModel() {
abstract class BaseVM(isExceptionNeedToShow: Boolean = true) : ViewModel() {
val errorMessage = MutableLiveData<ErrorMessage>()
val errorResponse = MutableLiveData<Triple<GenericErrorResponse, String?, Boolean>>()
val warningResponse = MutableLiveData<Pair<GenericWarningResponse, String?>>()
lateinit var coroutineScope: CoroutineScope
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
updateErrorMessage(handleException(exception))
if (isExceptionNeedToShow)
updateErrorMessage(handleException(exception))
}
init {

View File

@@ -0,0 +1,203 @@
/*
* *
* * Copyright (c) 2020 . All rights reserved @Navi
*
*/
package com.naviapp.common
import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewStub
import android.widget.RadioButton
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.naviapp.R
import com.naviapp.analytics.NaviAnalytics
import com.naviapp.common.customview.BaseBottomSheet
import com.naviapp.common.listeners.FetchFeedbackListener
import com.naviapp.databinding.FeedbackFragmentBinding
import com.naviapp.databinding.FeedbackRowItemBinding
import com.naviapp.models.FeedbackOption
import com.naviapp.models.FeedbackResponse
import com.naviapp.models.FeedbackSubmitData
import com.naviapp.utils.fadeOut
import com.naviapp.utils.isDead
import com.naviapp.utils.log
import com.naviapp.utils.setEaseInAnimation
class FeedbackFragment : BaseBottomSheet(), View.OnClickListener {
private lateinit var binding: FeedbackFragmentBinding
private var listener: FetchFeedbackListener? = null
private var screen: String? = null
private var selectedCode: String? = null
private var prevSelectedCode: String? = null
private var isOptionSelected: Boolean = false
private var feedbackOptionList: ArrayList<FeedbackOption>? = null
private val feedbackVM by lazy { ViewModelProvider(this).get(FeedbackVM::class.java) }
override fun setContainerView(viewStub: ViewStub) {
viewStub.layoutResource = R.layout.feedback_fragment
binding = DataBindingUtil.getBinding(viewStub.inflate())!!
getData()
initUi()
}
private fun getData() {
arguments?.apply {
handleUi(this.getParcelable(FEEDBACK_DATA))
screen = this.getString(FEEDBACK_PAGE).orEmpty()
}
}
private fun initUi() {
binding.feedbackDetailLay.closeAbv.setProperties(
getString(R.string.close),
R.color.title_color_one
)
binding.feedbackDetailLay.closeAbv.setViewBg(bgColor = R.color.gray)
binding.feedbackDetailLay.submitAbv.setProperties(
getString(R.string.submit),
R.color.white
)
submitButtonState()
binding.feedbackDetailLay.closeAbv.setOnClickListener(this)
binding.feedbackDetailLay.submitAbv.setOnClickListener(this)
}
private fun handleUi(data: FeedbackResponse?) {
data?.let {
it.feedbackOptionList?.let { options ->
feedbackOptionList = options
options.forEach { feedback ->
if (feedback.desc.isNullOrBlank().not())
addFeedbackItem(feedback)
}
} ?: run {
listener?.onInvalidData(screen.orEmpty())
dismiss()
}
} ?: run {
listener?.onInvalidData(screen.orEmpty())
dismiss()
}
}
private fun addFeedbackItem(option: FeedbackOption) {
context?.apply {
val inflater = this.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val feedbackOption = FeedbackRowItemBinding.inflate(inflater, null, true)
feedbackOption.data = option.desc
feedbackOption.feedbackRb.tag = option.code.orEmpty()
feedbackOption.feedbackRb.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked && prevSelectedCode != option.code) {
if (!isOptionSelected) {
isOptionSelected = true
submitButtonState()
}
prevSelectedCode = selectedCode
selectedCode = option.code
handleCheckClick()
}
}
binding.feedbackDetailLay.feedbackRg.addView(feedbackOption.root)
}
}
private fun handleCheckClick() {
try {
feedbackOptionList?.let {
it.forEach { option ->
if (selectedCode != option.code) {
val view =
binding.feedbackDetailLay.feedbackRg.findViewWithTag<RadioButton>(option.code)
view?.apply {
view.isChecked = false
}
}
}
}
} catch (e: Exception) {
e.log()
}
}
override fun onClick(v: View?) {
when (v?.id) {
binding.feedbackDetailLay.closeAbv.id -> {
listener?.onFeedbackCancel(screen.orEmpty())
dismiss()
}
binding.feedbackDetailLay.submitAbv.id -> {
onSubmitFeedback()
}
}
}
private fun submitButtonState() {
if (isOptionSelected) {
binding.feedbackDetailLay.submitAbv.setViewBg(bgColor = R.color.active_button_color)
}
}
private fun onSubmitFeedback() {
if (isOptionSelected) {
val comment = binding.feedbackDetailLay.commentEt.text?.toString().orEmpty()
val data = FeedbackSubmitData(
selectedCode.orEmpty(),
arrayListOf(selectedCode.orEmpty()),
comment
)
feedbackVM.submitFeed(data)
showFeedbackSuccessView()
}
}
private fun showFeedbackSuccessView() {
activity?.let {
if (isDead(it)) return
binding.feedbackDetailLay.root.visibility = View.GONE
binding.feedbackSubmittedLay.feedbackSuccessLay.visibility = View.VISIBLE
setEaseInAnimation(
binding.feedbackSubmittedLay.root,
binding.feedbackSubmittedLay.statusIv
)
Handler().postDelayed({
if (isDead(it)) return@postDelayed
listener?.onFeedbackSubmitted(screen.orEmpty())
dismiss()
}, 1000L)
}
}
override fun onAttach(context: Context) {
super.onAttach(context)
listener = context as? FetchFeedbackListener
}
override val screenName: String
get() = NaviAnalytics.FEEDBACK_SCREEN
companion object {
private const val FEEDBACK_DATA = "FEEDBACK_DATA"
private const val FEEDBACK_PAGE = "FEEDBACK_PAGE"
const val TAG = "FEEDBACK_SCREEN"
fun getInstance(page: String, data: FeedbackResponse) = FeedbackFragment().apply {
arguments = Bundle().apply {
this.putParcelable(FEEDBACK_DATA, data)
this.putString(FEEDBACK_PAGE, page)
}
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* *
* * Copyright (c) 2020 . All rights reserved @Navi
*
*/
package com.naviapp.common
import com.naviapp.models.FeedbackSubmitData
import com.naviapp.network.retrofit.ResponseCallback
import com.naviapp.utils.retrofitService
class FeedbackRepository : ResponseCallback() {
suspend fun fetchFeedbackOptions(pageCode: String) =
apiResponseCallback(retrofitService().fetchFeedbackOptions(pageCode))
suspend fun postFeedback(data: FeedbackSubmitData) =
apiResponseCallback(retrofitService().submitUserFeedback(data))
}

View File

@@ -0,0 +1,55 @@
/*
* *
* * Copyright (c) 2020 . All rights reserved @Navi
*
*/
package com.naviapp.common
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.naviapp.models.FeedbackResponse
import com.naviapp.models.FeedbackSubmitData
import com.naviapp.utils.orFalse
import kotlinx.coroutines.launch
class FeedbackVM : BaseVM(false) {
private val repository by lazy { FeedbackRepository() }
private val _feedbackResponse = MutableLiveData<FeedbackResponse>()
val feedbackResponse: LiveData<FeedbackResponse>
get() = _feedbackResponse
private val _submitFeedbackResponse = MutableLiveData<Boolean>()
val submitFeedbackResponse: LiveData<Boolean>
get() = _submitFeedbackResponse
fun fetchFeedOptions(page: String) {
coroutineScope.launch {
val response = repository.fetchFeedbackOptions(page)
if (response.error == null) {
_feedbackResponse.value = response.data
} else {
_feedbackResponse.value = null
}
}
}
fun submitFeed(data: FeedbackSubmitData) {
coroutineScope.launch {
val response = repository.postFeedback(data)
if (response.error == null) {
_submitFeedbackResponse.value = response.data?.success.orFalse()
} else {
_submitFeedbackResponse.value = false
}
}
}
fun deInit() {
_submitFeedbackResponse.value = null
_feedbackResponse.value = null
}
}

View File

@@ -0,0 +1,15 @@
/*
* *
* * Copyright (c) 2020 . All rights reserved @Navi
*
*/
package com.naviapp.common.listeners
import com.naviapp.models.FeedbackResponse
interface FeedbackListener {
fun showFeedbackScreen(screen: String?, data: FeedbackResponse?)
}

View File

@@ -0,0 +1,20 @@
/*
* *
* * Copyright (c) 2020 . All rights reserved @Navi
*
*/
package com.naviapp.common.listeners
import com.naviapp.models.FeedbackSubmitData
interface FetchFeedbackListener {
fun onFetchFeedbackOption(screen: String)
fun onFeedbackSubmitted(screen: String)
fun onFeedbackCancel(screen: String)
fun onInvalidData(screen: String)
}

View File

@@ -12,6 +12,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.naviapp.R
import com.naviapp.analytics.NaviAnalytics
@@ -24,6 +25,8 @@ import com.naviapp.getloan.activities.GetLoanActivity.Companion.BANK_DETAILS_AUT
import com.naviapp.getloan.bankdetails.adapters.BankAdapter
import com.naviapp.getloan.bankdetails.listeners.FindIfscListener
import com.naviapp.getloan.bankdetails.viewmodels.BankDetailsVM
import com.naviapp.getloan.kyc.viewmodels.KycVM
import com.naviapp.models.FeedbackPageType
import com.naviapp.models.request.BankDetail
import com.naviapp.models.response.Bank
import com.naviapp.models.response.DisbursementDetailsResponse
@@ -45,9 +48,8 @@ import com.naviapp.utils.toast
class BankDetailsFragment : BaseFragment(), View.OnClickListener, FindIfscListener,
View.OnKeyListener, View.OnFocusChangeListener, BankAdapter.OnSelectBankListener {
private lateinit var binding: BankDetailsFragmentBinding
private val viewModel by lazy {
ViewModelProviders.of(this).get(BankDetailsVM::class.java)
}
private val viewModel by lazy { ViewModelProvider(this).get(BankDetailsVM::class.java) }
private var bankNamesWithCodes: List<Bank> = emptyList()
private var listener: FragmentInteractionListener? = null
private val naviAnalyticsEventTracker = NaviAnalytics.naviAnalytics.BankDetails()
@@ -63,6 +65,7 @@ class BankDetailsFragment : BaseFragment(), View.OnClickListener, FindIfscListen
initUi()
initListeners()
observeBankNames()
fetchFeedbackListener?.onFetchFeedbackOption(FeedbackPageType.BANK_DETAILS_PAGE)
return binding.root
}

View File

@@ -7,6 +7,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.naviapp.R
import com.naviapp.analytics.NaviAnalytics
@@ -29,11 +30,13 @@ import com.naviapp.getloan.activities.GetLoanActivity
import com.naviapp.getloan.activities.GetLoanActivity.Companion.LOAN_AGREEMENT_SCREEN
import com.naviapp.getloan.bankdetails.fragments.BankDetailsFragment.Companion.DISBURSEMENT_DETAILS
import com.naviapp.getloan.bankdetails.fragments.BankDetailsFragment.Companion.EDIT_ACCOUNT
import com.naviapp.getloan.bankdetails.viewmodels.BankDetailsVM
import com.naviapp.getloan.bankdetailsautodebit.viewmodels.BankDetailsAutoDebitVM
import com.naviapp.getloan.bankdetailsautodebit.viewmodels.EnachSharedVM
import com.naviapp.getloan.helpers.EnachHelper
import com.naviapp.getloan.helpers.EnachStub
import com.naviapp.manager.UserManager
import com.naviapp.models.FeedbackPageType
import com.naviapp.models.response.DisbursementDetailsResponse
import com.naviapp.network.ApiErrorTagType
import com.naviapp.sharedpref.PreferenceManager
@@ -43,9 +46,8 @@ import com.naviapp.utils.Constants.SHOULD_SET_PROGRESS
class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener {
private lateinit var binding: BankDetailsAutoDebitFragmentBinding
private var listener: FragmentInteractionListener? = null
private val viewModel by lazy {
ViewModelProviders.of(this).get(BankDetailsAutoDebitVM::class.java)
}
private val viewModel by lazy { ViewModelProvider(this).get(BankDetailsAutoDebitVM::class.java) }
private var apiPollScheduler: ApiPollScheduler? = null
private var firebaseHelper: FirebaseDataHelper? = null
private var firebaseDataReceiveListener: FirebaseDataReceiveListener? = null
@@ -61,6 +63,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener {
initError()
initUi()
initListeners()
fetchFeedbackListener?.onFetchFeedbackOption(FeedbackPageType.AUTO_DEBIT_PAGE)
return binding.root
}

View File

@@ -41,6 +41,7 @@ import com.naviapp.getloan.kyc.models.AadhaarVerificationData
import com.naviapp.getloan.kyc.utils.getKycDocuments
import com.naviapp.getloan.kyc.viewmodels.KycSharedVM
import com.naviapp.getloan.kyc.viewmodels.KycVM
import com.naviapp.models.FeedbackPageType
import com.naviapp.models.RedirectPageStatus
import com.naviapp.models.UiStatusValue
import com.naviapp.models.request.Address
@@ -88,6 +89,7 @@ class KycFragment : BaseFragment(), RadioGroup.OnCheckedChangeListener, View.OnC
initListeners()
initObservers()
initData()
fetchFeedbackListener?.onFetchFeedbackOption(FeedbackPageType.KYC_PAGE)
return binding.root
}

View File

@@ -6,6 +6,7 @@ import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.naviapp.R
import com.naviapp.analytics.NaviAnalytics
@@ -19,7 +20,9 @@ import com.naviapp.firebasedb.FirebaseResponse
import com.naviapp.firebasedb.FirebaseStatusType
import com.naviapp.firebasedb.LOAN_AGREEMENT_CREATE
import com.naviapp.firebasedb.LOAN_AGREEMENT_SIGN
import com.naviapp.getloan.bankdetailsautodebit.viewmodels.BankDetailsAutoDebitVM
import com.naviapp.getloan.loanagreement.viewmodels.LoanAgreementVM
import com.naviapp.models.FeedbackPageType
import com.naviapp.network.ApiErrorTagType
import com.naviapp.sharedpref.PreferenceManager
import com.naviapp.utils.LOAN_APPLICATION_ID
@@ -28,9 +31,8 @@ import com.naviapp.utils.observeNonNull
class LoanAgreementFragment : BaseFragment(), View.OnClickListener {
private lateinit var binding: LoanAgreementFragmentBinding
private var apiPollScheduler: ApiPollScheduler? = null
private val loanAgreementVM by lazy {
ViewModelProviders.of(this).get(LoanAgreementVM::class.java)
}
private val loanAgreementVM by lazy { ViewModelProvider(this).get(LoanAgreementVM::class.java) }
private var listener: FragmentInteractionListener? = null
private var firebaseDataReceiveListener: FirebaseDataReceiveListener? = null
private var firebaseDataHelper: FirebaseDataHelper? = null
@@ -45,6 +47,7 @@ class LoanAgreementFragment : BaseFragment(), View.OnClickListener {
initError(loanAgreementVM)
initObservers()
initUi()
fetchFeedbackListener?.onFetchFeedbackOption(FeedbackPageType.LOAN_AGREEMENT_PAGE)
return binding.root
}

View File

@@ -27,11 +27,7 @@ import com.naviapp.getloan.common.FormSliderView
import com.naviapp.getloan.loandetails.listeners.LoanDetailsListener
import com.naviapp.getloan.loandetails.viewmodels.LoanDetailsVM
import com.naviapp.getloan.moratorium.MoratoriumConsentFragment
import com.naviapp.models.LoanFeeDetails
import com.naviapp.models.LoanSummary
import com.naviapp.models.Money
import com.naviapp.models.Offer
import com.naviapp.models.Tenure
import com.naviapp.models.*
import com.naviapp.network.ApiErrorTagType
import com.naviapp.sharedpref.PreferenceManager
import com.naviapp.useridentification.activities.LoanEligibilityLoaderActivity.Companion.OFFER
@@ -57,6 +53,7 @@ class LoanDetailsFragment : BaseFragment(), View.OnClickListener, LoanDetailsLis
private var isProgressSetToLoanDetails = false
private val naviAnalyticsEventTracker = NaviAnalytics.naviAnalytics.LoanDetails()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@@ -71,6 +68,7 @@ class LoanDetailsFragment : BaseFragment(), View.OnClickListener, LoanDetailsLis
showLoader()
loanDetailsVM.fetchLoanProducts()
}
fetchFeedbackListener?.onFetchFeedbackOption(FeedbackPageType.LOAN_OFFER_PAGE)
return binding.root
}

View File

@@ -0,0 +1,39 @@
/*
* *
* * Copyright (c) 2020 . All rights reserved @Navi
*
*/
package com.naviapp.models
import androidx.annotation.StringDef
object FeedbackPageType {
const val PERMISSIONS_PAGE = "PERMISSIONS_PAGE"
const val OTP_PAGE = "OTP_PAGE"
const val BASIC_DETAILS_PAGE = "BASIC_DETAILS_PAGE"
const val WORK_DETAILS_PAGE = "WORK_DETAILS_PAGE"
const val PAN_DETAILS_PAGE = "PAN_DETAILS_PAGE"
const val LOAN_OFFER_PAGE = "LOAN_OFFER_PAGE"
const val KYC_PAGE = "PERMISSIONS_PAGE"
const val BANK_DETAILS_PAGE = "BANK_DETAILS_PAGE"
const val AUTO_DEBIT_PAGE = "AUTO_DEBIT_PAGE"
const val LOAN_AGREEMENT_PAGE = "LOAN_AGREEMENT_PAGE"
@StringDef(
PERMISSIONS_PAGE,
OTP_PAGE,
BASIC_DETAILS_PAGE,
WORK_DETAILS_PAGE,
PAN_DETAILS_PAGE,
LOAN_OFFER_PAGE,
KYC_PAGE,
BANK_DETAILS_PAGE,
AUTO_DEBIT_PAGE,
LOAN_AGREEMENT_PAGE
)
@Retention(AnnotationRetention.SOURCE)
annotation class FeedbackPageTypeDef
}

View File

@@ -0,0 +1,23 @@
/*
* *
* * Copyright (c) 2020 . All rights reserved @Navi
*
*/
package com.naviapp.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize
@Parcelize
data class FeedbackResponse(
@SerializedName("collect") val collect: Boolean? = null,
@SerializedName("feedbackCategories") val feedbackOptionList: ArrayList<FeedbackOption>? = null
) : Parcelable
@Parcelize
data class FeedbackOption(
@SerializedName("code") val code: String? = null,
@SerializedName("description") val desc: String? = null
) : Parcelable

View File

@@ -0,0 +1,15 @@
/*
* *
* * Copyright (c) 2020 . All rights reserved @Navi
*
*/
package com.naviapp.models
import com.google.gson.annotations.SerializedName
data class FeedbackSubmitData(
@SerializedName("pageCode") val collect: String? = null,
@SerializedName("feedbackCodes") val feedbackCodesList: ArrayList<String>? = null,
@SerializedName("comments") val comments: String? = null
)

View File

@@ -11,23 +11,7 @@ import com.naviapp.getloan.bankdetails.models.BankBranch
import com.naviapp.getloan.kyc.models.AadhaarDetailsResponse
import com.naviapp.getloan.kyc.models.AadhaarVerificationData
import com.naviapp.getloan.kyc.models.KycStatus
import com.naviapp.models.ApplicationSummary
import com.naviapp.models.CustomerSupport
import com.naviapp.models.LoanFeeDetails
import com.naviapp.models.LoanSummary
import com.naviapp.models.LoginSettings
import com.naviapp.models.Offer
import com.naviapp.models.OfferResponse
import com.naviapp.models.RatingData
import com.naviapp.models.RedirectPageStatus
import com.naviapp.models.UserCallLog
import com.naviapp.models.UserContact
import com.naviapp.models.UserDataWrapper
import com.naviapp.models.UserDetail
import com.naviapp.models.UserInstalledApp
import com.naviapp.models.UserLocation
import com.naviapp.models.UserProfile
import com.naviapp.models.UserSms
import com.naviapp.models.*
import com.naviapp.models.request.*
import com.naviapp.models.response.AdditionalDataAsyncResponse
import com.naviapp.models.response.AppUpgradeResponse
@@ -406,4 +390,12 @@ interface RetrofitService {
@GET("customer-service/customers/selfie-settings")
suspend fun fetchSelfieSettings(): Response<GenericResponse<SelfieSetting>>
@GET("customer-service/customers/me/feedback")
suspend fun fetchFeedbackOptions(
@Query("pageCode") pageCode: String
): Response<GenericResponse<FeedbackResponse>>
@POST("customer-service/customers/me/feedback")
suspend fun submitUserFeedback(@Body request: FeedbackSubmitData): Response<GenericResponse<SuccessResponse>>
}

View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ /**
~ * Copyright (c) 2020 . All rights reserved @Navi
~ */
-->
<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"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingBottom="@dimen/layout_dp_20">
<TextView
android:id="@+id/title_tv"
style="@style/TitleFontStyle2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_dp_30"
android:layout_marginTop="@dimen/layout_dp_10"
android:text="@string/feedback_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/subtitle_tv"
style="@style/AgreementFontStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_dp_30"
android:layout_marginTop="@dimen/layout_dp_24"
android:text="@string/feedback_subtitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_tv" />
<LinearLayout
android:id="@+id/feedback_rg"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_dp_30"
android:layout_marginTop="@dimen/layout_dp_12"
android:layout_marginEnd="@dimen/layout_dp_30"
android:letterSpacing="0.03"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/subtitle_tv" />
<EditText
android:id="@+id/comment_et"
style="@style/EditTextStyle"
android:layout_width="0dp"
android:layout_height="@dimen/layout_dp_120"
android:layout_marginStart="@dimen/layout_dp_30"
android:layout_marginTop="@dimen/layout_dp_24"
android:layout_marginEnd="@dimen/layout_dp_30"
android:background="@drawable/bg_rounded_rect_with_gray_border"
android:ellipsize="end"
android:focusable="true"
android:gravity="top|start"
android:hint="@string/feedback_submit_hint"
android:imeOptions="actionDone"
android:minHeight="@dimen/layout_dp_120"
android:padding="@dimen/layout_dp_12"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/feedback_rg" />
<com.naviapp.common.customview.ActionButtonView
android:id="@+id/close_abv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_dp_30"
android:layout_marginTop="@dimen/layout_dp_16"
android:layout_marginEnd="@dimen/layout_dp_30"
app:layout_constraintEnd_toStartOf="@+id/submit_abv"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/comment_et" />
<com.naviapp.common.customview.ActionButtonView
android:id="@+id/submit_abv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_dp_30"
android:layout_marginTop="@dimen/layout_dp_16"
android:layout_marginEnd="@dimen/layout_dp_30"
android:layout_marginBottom="@dimen/layout_dp_20"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/close_abv"
app:layout_constraintTop_toBottomOf="@+id/comment_et" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ /**
~ * Copyright (c) 2020 . All rights reserved @Navi
~ */
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<include
android:id="@+id/feedback_detail_lay"
layout="@layout/feedback_detail_lay"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<include
android:id="@+id/feedback_submitted_lay"
layout="@layout/feedback_submitted_lay" />
</FrameLayout>
</layout>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ /**
~ * Copyright (c) 2020 . All rights reserved @Navi
~ */
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="data"
type="String" />
</data>
<RadioButton
android:id="@+id/feedback_rb"
style="@style/AgreementTwoFontStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/red"
android:text="@{data}"
android:textColor="@drawable/radiobutton_selector"
tools:text="I will complete the process later" />
</layout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ /**
~ * Copyright (c) 2020 . All rights reserved @Navi
~ */
-->
<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">
<LinearLayout
android:id="@+id/feedback_success_lay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/layout_dp_48"
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:id="@+id/status_iv"
android:layout_width="@dimen/layout_dp_48"
android:layout_height="@dimen/layout_dp_48"
android:layout_marginTop="@dimen/layout_dp_48"
android:adjustViewBounds="true"
android:backgroundTint="@color/green"
app:srcCompat="@drawable/ic_tick_svg" />
<TextView
android:id="@+id/title_tv"
style="@style/TextDescMediumFontStyle2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_dp_20"
android:text="@string/done"
tools:text="Done" />
<TextView
android:id="@+id/description_tv"
style="@style/ParagraphThreeFontStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_dp_10"
android:gravity="center"
android:text="@string/feedback_submitted_desc" />
</LinearLayout>
</layout>

View File

@@ -400,5 +400,10 @@
<string name="faceCaptureActivity">Processing</string>
<string name="selfie_permission_error">Please give camera permissions from phone settings</string>
<string name="feedback_submit_hint">Leave a feedback…(optional)</string>
<string name="feedback_title">You are leaving!</string>
<string name="feedback_subtitle">What went wrong?</string>
<string name="close">Close</string>
<string name="feedback_submitted_desc">Thank you for sharing the \nfeedback with us.</string>
</resources>