diff --git a/.gitignore b/.gitignore index 03b025c175..581c4f22ef 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,6 @@ vcs.xml digio-kyc-1.0.13/build digio-esign-v2.8.0/build truecallersdk-2.6.1-releasePartner/build -neoeyed-sdk-release-3.3.0/build/ +neoeyed-sdk-release-3.3.1/build/ finoramic-android-sdk/build finoramic-androidx-sdk/build/ diff --git a/Dockerfile b/Dockerfile index 8588ac875f..f0cfec4a3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,11 +37,7 @@ RUN echo ${RELEASE_STORE_FILE} | base64 -d >> app/navi-release-key.jks RUN bash -c " \ if [ $FLAVOR = E2ETEST ] ; then \ - - ./gradlew clean :app:testDevDebugUnitTest --tests com.naviapp.CustomerDataCleanup; EX1=\"\$?\";\ - ./gradlew clean :app:testDevDebugUnitTest --tests com.naviapp.BrowserStackInit -PtestType=\"e2e\" executeE2ETests; EX2=\"\$?\";\ - ./gradlew clean :app:testDevDebugUnitTest --tests com.naviapp.MockDataCleanup ; EX3=\"\$?\";\ - if [ $EX1 == 0 ] && [ $EX2 == 0 ] && [ $EX3 == 0 ]; then exit 0; else exit 1; fi; \ + ./gradlew clean :app:testDevDebugUnitTest --tests com.naviapp.CustomerDataCleanup -PtestType=\"e2e\" executeE2ETests; \ \ elif [ $FLAVOR = DEV ] ; then \ ./gradlew clean \ diff --git a/app/build.gradle b/app/build.gradle index f09fc10985..1988c2e817 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,7 +20,7 @@ kapt { correctErrorTypes true } -def VERSION_NAME = "2.0.4" +def VERSION_NAME = "2.0.5" android { compileSdkVersion 29 diff --git a/app/libs/neoeyed-sdk-release-3.3.1.aar b/app/libs/neoeyed-sdk-release-3.3.1.aar new file mode 100644 index 0000000000..39ec2ec568 Binary files /dev/null and b/app/libs/neoeyed-sdk-release-3.3.1.aar differ diff --git a/app/src/androidTestDev/java/com/naviapp/homeLoan/BalanceTransferTest.kt b/app/src/androidTestDev/java/com/naviapp/homeLoan/BalanceTransferTest.kt index 6962c29cea..b241dffb0d 100644 --- a/app/src/androidTestDev/java/com/naviapp/homeLoan/BalanceTransferTest.kt +++ b/app/src/androidTestDev/java/com/naviapp/homeLoan/BalanceTransferTest.kt @@ -3,7 +3,6 @@ package com.naviapp.homeLoan import androidx.test.ext.junit.rules.ActivityScenarioRule import com.naviapp.E2ETest import com.naviapp.TestBase -import com.naviapp.Utilities import com.naviapp.controllers.Controller import com.naviapp.controllers.dashboard.DashboardController import com.naviapp.controllers.homeloan.* @@ -23,7 +22,7 @@ class BalanceTransferTest: TestBase() { @Rule @JvmField val tutorialActivity = ActivityScenarioRule(SplashActivity::class.java) - val homeLoanType: String = "Transfer Existing Home Loan" + val homeLoanType: String = "Loan Against Property" @Test fun getBalanceTransfer(){ @@ -33,7 +32,7 @@ class BalanceTransferTest: TestBase() { val browserStack: BrowserStack = JsonParser.getData(this.javaClass.getResourceAsStream("/PhoneNumber.json")) - val phoneNumber = browserStack.e2e.phoneNumberBalanceTransfer + val phoneNumber = "6666625528" val basicDetails = newLoanDetails.homeLoanBasicDetails val balanceTransferDetails = newLoanDetails.balanceTransferDetails val homeLoanWorkDetails = newLoanDetails.homeLoanWorkDetails @@ -44,6 +43,7 @@ class BalanceTransferTest: TestBase() { Controller.on() .getStarted() + .loginOrSignup() .enterPhoneNumberAndOtp(phoneNumber) .clickVerifyOtp() .tapPersonalHomeLoanCard() diff --git a/app/src/androidTestDev/java/com/naviapp/homeLoan/HomeLoanTest.kt b/app/src/androidTestDev/java/com/naviapp/homeLoan/HomeLoanTest.kt index cdb7e3ac1a..c9f5abce9f 100644 --- a/app/src/androidTestDev/java/com/naviapp/homeLoan/HomeLoanTest.kt +++ b/app/src/androidTestDev/java/com/naviapp/homeLoan/HomeLoanTest.kt @@ -22,7 +22,7 @@ class HomeLoanTest : TestBase() { @Rule @JvmField val tutorialActivity = ActivityScenarioRule(SplashActivity::class.java) - val homeLoanType: String = "New Home Loan" + val homeLoanType: String = "Home Loan" @Test fun getNewHomeLoan() { @@ -32,7 +32,7 @@ class HomeLoanTest : TestBase() { val browserStack: BrowserStack = JsonParser.getData(this.javaClass.getResourceAsStream("/PhoneNumber.json")) - val phoneNumber = browserStack.e2e.phoneNumberHomeLoan + val phoneNumber = "6666625527" val basicDetails = newLoanDetails.homeLoanBasicDetails val propertyDetails = newLoanDetails.propertyDetails val homeLoanWorkDetails = newLoanDetails.homeLoanWorkDetails @@ -43,6 +43,7 @@ class HomeLoanTest : TestBase() { Controller.on() .getStarted() + .loginOrSignup() .enterPhoneNumberAndOtp(phoneNumber) .clickVerifyOtp() .tapPersonalHomeLoanCard() diff --git a/app/src/androidTestDev/java/com/naviapp/mockTests/NsdlMockTests.kt b/app/src/androidTestDev/java/com/naviapp/mockTests/NsdlMockTests.kt index 79586fa4aa..8a123fd95d 100644 --- a/app/src/androidTestDev/java/com/naviapp/mockTests/NsdlMockTests.kt +++ b/app/src/androidTestDev/java/com/naviapp/mockTests/NsdlMockTests.kt @@ -1,7 +1,6 @@ package com.naviapp.mockTests import androidx.test.ext.junit.rules.ActivityScenarioRule -import com.naviapp.E2ETest import com.naviapp.TestBase import com.naviapp.controllers.Controller import com.naviapp.controllers.dashboard.DashboardController @@ -21,7 +20,7 @@ import com.naviapp.utilities.RandomGenerator import org.junit.Rule import org.junit.Test -@E2ETest + class NsdlMockTests:TestBase() { @Rule @JvmField diff --git a/app/src/androidTestDev/java/com/naviapp/mockTests/PanMockTests.kt b/app/src/androidTestDev/java/com/naviapp/mockTests/PanMockTests.kt index a222eaea71..d0154d520e 100644 --- a/app/src/androidTestDev/java/com/naviapp/mockTests/PanMockTests.kt +++ b/app/src/androidTestDev/java/com/naviapp/mockTests/PanMockTests.kt @@ -1,7 +1,6 @@ package com.naviapp.mockTests import androidx.test.ext.junit.rules.ActivityScenarioRule -import com.naviapp.E2ETest import com.naviapp.TestBase import com.naviapp.controllers.Controller import com.naviapp.controllers.dashboard.DashboardController @@ -21,7 +20,7 @@ import com.naviapp.utilities.RandomGenerator import org.junit.Rule import org.junit.Test -@E2ETest + class PanMockTests: TestBase() { @Rule diff --git a/app/src/androidTestDev/java/com/naviapp/newPersonalLoan/NewLoanTest.kt b/app/src/androidTestDev/java/com/naviapp/newPersonalLoan/NewLoanTest.kt index a7f2a835a7..e57405b3fa 100644 --- a/app/src/androidTestDev/java/com/naviapp/newPersonalLoan/NewLoanTest.kt +++ b/app/src/androidTestDev/java/com/naviapp/newPersonalLoan/NewLoanTest.kt @@ -3,10 +3,12 @@ package com.naviapp.newPersonalLoan import androidx.test.ext.junit.rules.ActivityScenarioRule import com.naviapp.E2ETest import com.naviapp.TestBase -import com.naviapp.Utilities import com.naviapp.controllers.Controller import com.naviapp.controllers.dashboard.DashboardController import com.naviapp.controllers.eligibility.EligibilityController +import com.naviapp.controllers.loanApplication.BankAccountController +import com.naviapp.controllers.loanApplication.KycController +import com.naviapp.controllers.loanApplication.LoanAgreementController import com.naviapp.controllers.loanApplication.LoanDetailsController import com.naviapp.controllers.permission.PermissionController import com.naviapp.controllers.registration.RegistrationController @@ -15,7 +17,10 @@ import com.naviapp.controllers.useridentification.PanController import com.naviapp.controllers.useridentification.ProfileController import com.naviapp.controllers.useridentification.QuestionnaireController import com.naviapp.controllers.useridentification.WorkController -import com.naviapp.entities.* +import com.naviapp.entities.BankDetails +import com.naviapp.entities.BrowserStack +import com.naviapp.entities.DashboardEmiCalendar +import com.naviapp.entities.NewLoanDetails import com.naviapp.filehandler.JsonParser import com.naviapp.registration.SplashActivity import com.naviapp.utilities.DateUtils @@ -36,8 +41,8 @@ class NewLoanTest : TestBase() { val browserStack: BrowserStack = JsonParser.getData(this.javaClass.getResourceAsStream("/PhoneNumber.json")) - private val phoneNumberNewLoan = browserStack.e2e.phoneNumberNewLoan - private val phoneNumberForeclosureLoan = browserStack.e2e.phoneNumberForeclosureLoan + private val phoneNumberNewLoan = "6666625525" + private val phoneNumberForeclosureLoan = "6666625526" @Test @@ -54,6 +59,7 @@ class NewLoanTest : TestBase() { Controller.on() .getStarted() + .loginOrSignup() .enterPhoneNumberAndOtp(phoneNumberNewLoan) .clickVerifyOtp() .tapPersonalLoanCard() @@ -72,14 +78,17 @@ class NewLoanTest : TestBase() { .setMinEmiAmount() Controller.on() .clickNext() - .bankStatement() - .captureSelfie() - .completeEKyc() - .completeAddress() - .clickNext() + .bankStatement() .enterBankDetails(bankDetails) .clickConfirm() .setUpMandate() + .captureSelfie() + .completeEKyc() + .clickNext() + .completeAddress() + .clickNext() + .addressVerification() + .clickNext() .clickGetLoan() .waitForDisbursement() .verifyOnThisActivity() @@ -129,6 +138,7 @@ class NewLoanTest : TestBase() { Controller.on() .getStarted() + .loginOrSignup() .enterPhoneNumberAndOtp(phoneNumberForeclosureLoan) .clickVerifyOtp() .tapPersonalLoanCard() @@ -147,14 +157,17 @@ class NewLoanTest : TestBase() { .setMinEmiAmount() Controller.on() .clickNext() - .bankStatement() - .captureSelfie() - .completeEKyc() - .completeAddress() - .clickNext() + .bankStatement() .enterBankDetails(bankDetails) .clickConfirm() .setUpMandate() + .captureSelfie() + .completeEKyc() + .clickNext() + .completeAddress() + .clickNext() + .addressVerification() + .clickNext() .clickGetLoan() .waitForDisbursement() .verifyActivity() diff --git a/app/src/androidTestDev/resources/NewLoanDetails.json b/app/src/androidTestDev/resources/NewLoanDetails.json index 25fdbf6756..d5b110c7bc 100644 --- a/app/src/androidTestDev/resources/NewLoanDetails.json +++ b/app/src/androidTestDev/resources/NewLoanDetails.json @@ -38,13 +38,13 @@ "propertyDetails": { "city": "Bengaluru", "finaliseProperty": "No", - "propertyType": "Fully Constructed – Apartment", + "propertyType": "Fully Constructed - Individual House", "purchaseValue": "100000", "loanAmount": "100000" }, "balanceTransferDetails": { "city": "Bengaluru", - "propertyType": "Fully Constructed – Apartment", + "propertyType": "Fully Constructed - Individual House", "loanTaken": "1000000", "loanTakenMonth": "07", "loanTakenYear": "2018", diff --git a/app/src/androidTestLibrary/java/com/naviapp/controllers/homeloan/PropertyController.kt b/app/src/androidTestLibrary/java/com/naviapp/controllers/homeloan/PropertyController.kt index 4eeaeb9cbb..474d03f228 100644 --- a/app/src/androidTestLibrary/java/com/naviapp/controllers/homeloan/PropertyController.kt +++ b/app/src/androidTestLibrary/java/com/naviapp/controllers/homeloan/PropertyController.kt @@ -4,7 +4,6 @@ import androidx.test.espresso.Espresso.closeSoftKeyboard import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.* import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers.* import com.naviapp.R import com.naviapp.constants.ErrorText @@ -12,9 +11,9 @@ import com.naviapp.constants.WaitTimeOut import com.naviapp.controllers.Controller import com.naviapp.entities.PropertyDetails import com.naviapp.extensions.sleepFor -import com.naviapp.extensions.withIndex import com.naviapp.extensions.waitFor import com.naviapp.extensions.waitTillLoadingCompletes +import com.naviapp.extensions.withIndex import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.containsString @@ -96,9 +95,9 @@ class PropertyController : Controller() { onView(isRoot()).perform(waitFor(propertyTypeMatcher)) onView(propertyTypeMatcher).perform(click()); - val propertyTypeMatcher = withText(propertyType) - onView(isRoot()).perform(waitFor(propertyTypeMatcher)) - onView(propertyTypeMatcher).perform(click()) + val propertyTypeTextMatcher = withText(propertyType) + onView(isRoot()).perform(waitFor(propertyTypeTextMatcher)) + onView(propertyTypeTextMatcher).perform(click()) return this } diff --git a/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/BankAccountController.kt b/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/BankAccountController.kt index 5ebba9f8a4..06b56b4f1c 100644 --- a/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/BankAccountController.kt +++ b/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/BankAccountController.kt @@ -3,33 +3,28 @@ package com.naviapp.controllers.loanApplication import android.util.Log import android.view.View import androidx.test.espresso.Espresso -import androidx.test.espresso.Espresso.onData import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.* -import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.RootMatchers.isPlatformPopup import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.web.assertion.WebViewAssertions.webMatches import androidx.test.espresso.web.sugar.Web.onWebView -import androidx.test.espresso.web.webdriver.DriverAtoms.findElement -import androidx.test.espresso.web.webdriver.DriverAtoms.getText -import androidx.test.espresso.web.webdriver.DriverAtoms.webClick +import androidx.test.espresso.web.webdriver.DriverAtoms.* import androidx.test.espresso.web.webdriver.Locator import com.naviapp.R import com.naviapp.constants.ErrorText import com.naviapp.constants.StringType import com.naviapp.constants.WaitTimeOut import com.naviapp.controllers.Controller -import com.naviapp.dashboard.adapter.NewHomeBaseViewHolder import com.naviapp.entities.BankDetails -import com.naviapp.extensions.* +import com.naviapp.extensions.sleepFor +import com.naviapp.extensions.waitFor +import com.naviapp.extensions.waitTillLoadingCompletes +import com.naviapp.extensions.waitUntilNotShown import com.naviapp.utilities.RandomGenerator import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.Matcher import org.hamcrest.Matchers @@ -181,7 +176,7 @@ class BankAccountController : Controller() { return this } - fun setUpMandate(): LoanAgreementController { + fun setUpMandate(): KycController { /* onView(isRoot()).perform(waitTillLoadingCompletes()) onView(isRoot()).perform(waitFor(setUpAutoDebitButtonMatcher))*/ onView(isRoot()).perform(waitFor(setUpAutoDebitButtonMatcher, WaitTimeOut.Loader)) @@ -195,7 +190,7 @@ class BankAccountController : Controller() { .reset() Log.i(TAG, "Auto setup EMI done") sleepFor(WaitTimeOut.Invisibility) - return LoanAgreementController() + return KycController() } fun setUpMandateFailure(): LoanAgreementController { diff --git a/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/KycController.kt b/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/KycController.kt index d245e6578d..0149f297c1 100644 --- a/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/KycController.kt +++ b/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/KycController.kt @@ -8,7 +8,6 @@ import android.util.Log import android.view.View import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView -import androidx.test.InstrumentationRegistry.getTargetContext import androidx.test.espresso.Espresso.onView import androidx.test.espresso.UiController import androidx.test.espresso.ViewAction @@ -26,10 +25,8 @@ import com.naviapp.controllers.Controller import com.naviapp.controllers.loanApplication.KycController.MyViewAction.clickChildViewWithId import com.naviapp.extensions.waitFor import com.naviapp.extensions.waitTillLoadingCompletes -import com.naviapp.extensions.withIndex import com.naviapp.manager.PermissionsManager import org.hamcrest.Matcher -import org.hamcrest.Matchers import org.hamcrest.Matchers.allOf import org.junit.Rule import timber.log.Timber @@ -42,12 +39,13 @@ class KycController : Controller() { val requiredKycPermissionManager: GrantPermissionRule = GrantPermissionRule.grant(*PermissionsManager.requiredPermission) - private val nextButtonMatcher = withText("Next") + val nextButtonMatcher = withText("Next") private val uploadSelfieButtonMatcher = withId(R.id.image_iv) private val kycButtonMatcher = withId(R.id.state_cv) private val confirmButtonMatcher = allOf(withId(R.id.action_tv), withText("Confirm")) private val yesRadioButtonMatcher = withId(R.id.yes_rb) private val noRadioButtonMatcher = withId(R.id.no_rb) + private val noButton = withId(R.id.no_rb) val otp = allOf(withId(R.id.action_btn_cv), isDisplayed()) val addressData = allOf(withId(R.id.image_iv), isDisplayed()) private val addressLine1 = withId(R.id.current_address_line1) @@ -195,11 +193,17 @@ class KycController : Controller() { return this } - fun clickNext(waitUntilLoaderDisappears: Boolean = true): BankAccountController { + inline fun clickNext(waitUntilLoaderDisappears: Boolean = true): T { onView(isRoot()).perform(waitFor(nextButtonMatcher)) onView(nextButtonMatcher).perform(click()) if (waitUntilLoaderDisappears) onView(isRoot()).perform(waitTillLoadingCompletes()) - return BankAccountController() + return T::class.java.getConstructor().newInstance() + } + + fun addressVerification(): KycController{ + onView(isRoot()).perform(waitTillLoadingCompletes()) + onView(noButton).perform(click()) + return KycController() } } \ No newline at end of file diff --git a/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/LoanDetailsController.kt b/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/LoanDetailsController.kt index df286f27a1..b75066f6ee 100644 --- a/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/LoanDetailsController.kt +++ b/app/src/androidTestLibrary/java/com/naviapp/controllers/loanApplication/LoanDetailsController.kt @@ -8,25 +8,18 @@ import androidx.core.widget.NestedScrollView import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.Espresso import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions -import androidx.test.espresso.assertion.ViewAssertions -import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.UiController import androidx.test.espresso.ViewAction import androidx.test.espresso.action.ScrollToAction -import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.scrollTo import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers.* -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.uiautomator.UiDevice -import androidx.test.uiautomator.UiSelector import com.naviapp.R import com.naviapp.constants.ErrorText import com.naviapp.constants.StringType -import com.naviapp.constants.WaitTimeOut import com.naviapp.controllers.Controller -import com.naviapp.controllers.useridentification.WorkController -import com.naviapp.controllers.registration.RegistrationController import com.naviapp.entities.EmiCalendar import com.naviapp.entities.LoanAmountDetails import com.naviapp.extensions.* @@ -423,13 +416,13 @@ class LoanDetailsController : Controller() { } - fun bankStatement(waitForLoader: Boolean = true): KycController { + inline fun bankStatement(waitForLoader: Boolean = true):T{ val submitApplicationMatcher = allOf(withId(R.id.action_tv), withText("Skip")) onView(isRoot()).perform(waitFor(submitApplicationMatcher)) onView(submitApplicationMatcher).perform(click()) if (waitForLoader) onView(isRoot()).perform(waitTillLoadingCompletes()) - return KycController() + return T::class.java.getConstructor().newInstance() } } \ No newline at end of file diff --git a/app/src/androidTestLibrary/java/com/naviapp/controllers/registration/RegistrationController.kt b/app/src/androidTestLibrary/java/com/naviapp/controllers/registration/RegistrationController.kt index fbe990eda8..e313281d33 100644 --- a/app/src/androidTestLibrary/java/com/naviapp/controllers/registration/RegistrationController.kt +++ b/app/src/androidTestLibrary/java/com/naviapp/controllers/registration/RegistrationController.kt @@ -1,29 +1,21 @@ package com.naviapp.controllers.registration import android.util.Log -import androidx.test.espresso.Espresso.closeSoftKeyboard -import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.NoActivityResumedException -import androidx.test.espresso.action.ViewActions.* -import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.RootMatchers.isDialog -import androidx.test.espresso.matcher.ViewMatchers.* -import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation -import androidx.test.uiautomator.UiDevice -import androidx.test.uiautomator.UiObjectNotFoundException -import androidx.test.uiautomator.UiSelector -import com.naviapp.R -import com.naviapp.constants.ErrorText -import com.naviapp.constants.WaitTimeOut -import com.naviapp.controllers.Controller -import com.naviapp.controllers.useridentification.ProfileController -import com.naviapp.extensions.* -import com.naviapp.utils.logi -import org.hamcrest.Matchers.allOf -import org.hamcrest.Matchers.containsString import android.view.View import android.view.ViewGroup +import androidx.test.espresso.Espresso.closeSoftKeyboard +import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import com.naviapp.R +import com.naviapp.controllers.Controller +import com.naviapp.extensions.getText +import com.naviapp.extensions.waitFor +import com.naviapp.extensions.waitTillLoadingCompletes +import com.naviapp.utils.logi import org.hamcrest.Description import org.hamcrest.Matcher import org.hamcrest.Matchers.* @@ -45,6 +37,7 @@ class RegistrationController : Controller() { private val nextButton = withId(R.id.action_tv) private val editButton = withId(R.id.edit_number_tv) private val whatsApp = withId(R.id.whatsapp_consent_tv) + private val loginOrSignupMatcher = withText(containsString("Login / Signup")) val TAG:String = this.javaClass.simpleName; @@ -246,4 +239,10 @@ class RegistrationController : Controller() { } } + + fun loginOrSignup(): RegistrationController{ + onView(isRoot()).perform(waitFor(loginOrSignupMatcher)) + onView(loginOrSignupMatcher).perform(click()) + return this + } } diff --git a/app/src/androidTestLibrary/java/com/naviapp/controllers/useridentification/PanController.kt b/app/src/androidTestLibrary/java/com/naviapp/controllers/useridentification/PanController.kt index 45b94bc956..716f6c21c7 100644 --- a/app/src/androidTestLibrary/java/com/naviapp/controllers/useridentification/PanController.kt +++ b/app/src/androidTestLibrary/java/com/naviapp/controllers/useridentification/PanController.kt @@ -4,20 +4,13 @@ import android.util.Log import android.view.View import androidx.test.espresso.Espresso.closeSoftKeyboard import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.* import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.ViewMatchers.hasErrorText -import androidx.test.espresso.matcher.ViewMatchers.isNotChecked -import androidx.test.espresso.matcher.ViewMatchers.isRoot -import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.espresso.matcher.ViewMatchers.* import com.naviapp.R -import com.naviapp.constants.ErrorText import com.naviapp.constants.StringType import com.naviapp.controllers.Controller import com.naviapp.entities.PanDetails -import com.naviapp.entities.ProfileDetails import com.naviapp.extensions.waitFor import com.naviapp.extensions.waitTillLoadingCompletes import com.naviapp.utilities.RandomGenerator @@ -49,7 +42,7 @@ class PanController : Controller() { fun enterPan(panNumber: String? = null): PanController { verifyOnThisActivity() onView(panFieldMatcher).perform( - replaceText( + typeText( panNumber ?: RandomGenerator.getRandomPanNumber() ) ) @@ -76,9 +69,10 @@ class PanController : Controller() { } fun enterAge(ageDay: String, ageMonth: String, ageYear: String): PanController { - onView(ageDayMatcher).perform(replaceText(ageDay)) - onView(ageMonthMatcher).perform(replaceText(ageMonth)) - onView(ageYearMatcher).perform(replaceText(ageYear)) + onView(ageDayMatcher).perform(typeText(ageDay)) + onView(ageMonthMatcher).perform(typeText(ageMonth)) + onView(ageYearMatcher).perform(typeText(ageYear)) + closeSoftKeyboard() Log.i(TAG, "Age entered on profile page") return this } @@ -93,7 +87,7 @@ class PanController : Controller() { } inline fun submitApplication(waitForLoader: Boolean = true): T { - val submitApplicationMatcher = allOf(withId(R.id.action_tv), withText("Submit Application")) + val submitApplicationMatcher = allOf(withId(R.id.action_tv), withText("Next")) onView(isRoot()).perform(waitFor(submitApplicationMatcher)) onView(submitApplicationMatcher).perform(click()) if (waitForLoader) diff --git a/app/src/main/java/com/naviapp/analytics/utils/NaviAnalytics.kt b/app/src/main/java/com/naviapp/analytics/utils/NaviAnalytics.kt index bbbb8bf5c0..00f6b4d668 100644 --- a/app/src/main/java/com/naviapp/analytics/utils/NaviAnalytics.kt +++ b/app/src/main/java/com/naviapp/analytics/utils/NaviAnalytics.kt @@ -248,8 +248,11 @@ class NaviAnalytics private constructor() { fun onCheckBoxClicked() = NaviTrackEvent.trackEvent("bank_details_checkbox") - fun onSetupAutoDebitClicked() = - NaviTrackEvent.trackEvent("setup_autodebit_button_tap") + fun onSetupAutoDebitClicked(type: String?) = + NaviTrackEvent.trackEvent( + "setup_autodebit_button_tap", + mapOf(Pair("type", type.orEmpty())) + ) fun onAccountNumberEdit() = NaviTrackEvent.trackEvent("account_number_edit") @@ -1569,6 +1572,10 @@ class NaviAnalytics private constructor() { } } + inner class EnachTutorial { + fun onPageSelected(pageName: String) = NaviTrackEvent.trackEvent(pageName) + } + companion object { const val SPLASH = "splash" const val PERMISSIONS_SCREEN = "permission" diff --git a/app/src/main/java/com/naviapp/common/BaseActivity.kt b/app/src/main/java/com/naviapp/common/BaseActivity.kt index f7fb90a6d7..683bf64f1a 100644 --- a/app/src/main/java/com/naviapp/common/BaseActivity.kt +++ b/app/src/main/java/com/naviapp/common/BaseActivity.kt @@ -599,7 +599,7 @@ abstract class BaseActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListen val uxCamUtil = UxcamUtil.instance uxCamUtil.init(BuildConfig.UXCAM_KEY) val externalUserId = PreferenceManager.getStringPreference(USER_EXTERNAL_ID) - if (externalUserId.isNullOrBlank()) + if (externalUserId.isNullOrBlank().not()) uxCamUtil.setCustomerId(externalUserId.orEmpty()) val name = UserManager.getName() val phone = UserManager.getPhoneNumber() diff --git a/app/src/main/java/com/naviapp/common/adapter/RadioRvAdapter.kt b/app/src/main/java/com/naviapp/common/adapter/RadioRvAdapter.kt new file mode 100644 index 0000000000..317f7f059d --- /dev/null +++ b/app/src/main/java/com/naviapp/common/adapter/RadioRvAdapter.kt @@ -0,0 +1,70 @@ +package com.naviapp.common.adapter + +import android.annotation.SuppressLint +import android.view.ViewGroup +import androidx.lifecycle.MutableLiveData +import androidx.recyclerview.widget.RecyclerView +import com.naviapp.R +import com.naviapp.common.customview.RadioCustomView +import com.naviapp.models.response.RadioButtonResponse +import com.naviapp.utils.orFalse +import kotlinx.android.synthetic.main.view_radio_button.view.* + +class RadioRvAdapter( + private val radioViewList: List, + private val selectedLabelLiveData: MutableLiveData +) : RecyclerView.Adapter() { + init { + setInitialSelectedPosition() + } + + private fun setInitialSelectedPosition() { + selectedLabelLiveData.value = radioViewList.firstOrNull() + radioViewList.forEach { + if (it.checked.orFalse()) selectedLabelLiveData.value = it + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RadioRvViewHolder { + return RadioRvViewHolder( + RadioCustomView(context = parent.context) + ) + } + + @SuppressLint("NotifyDataSetChanged") + override fun onBindViewHolder(holder: RadioRvViewHolder, position: Int) { + val radioViewData = radioViewList[position] + holder.setData(radioViewData) + holder.view.radio_btn.setOnClickListener { + if (radioViewData.checked.orFalse()) return@setOnClickListener + clearRadioButtonAndSetNewSelection(position) + selectedLabelLiveData.value = radioViewData + notifyDataSetChanged() + } + } + + private fun clearRadioButtonAndSetNewSelection(position: Int) { + radioViewList.forEachIndexed { index, radioButtonData -> + radioButtonData.checked = index == position + } + } + + override fun getItemCount(): Int { + return radioViewList.size + } + +} + +class RadioRvViewHolder(val view: RadioCustomView) : RecyclerView.ViewHolder(view) { + + fun setData(radioButtonResponse: RadioButtonResponse) { + view.setProperties( + radioButtonResponse.radioButtonText, + radioButtonResponse.iconCode, + radioButtonResponse.description, + radioButtonResponse.checked, + radioButtonResponse.enabled, + R.drawable.radio_custom_view_selector + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/common/customview/DobEditText.kt b/app/src/main/java/com/naviapp/common/customview/DobEditText.kt index 53c5b8c255..51290caef7 100644 --- a/app/src/main/java/com/naviapp/common/customview/DobEditText.kt +++ b/app/src/main/java/com/naviapp/common/customview/DobEditText.kt @@ -56,6 +56,7 @@ class DobEditText(context: Context, attrs: AttributeSet) : RelativeLayout(contex } fun setText(dob: String) { + if(dob.isBlank()) return dob.split(DELIMITER).forEachIndexed { index, data -> if (index == 0 && data.length == YEAR_LENGTH) binding.yearEt.setText(data) if (index == 1 && data.length == MONTH_LENGTH) binding.monthEt.setText(data) diff --git a/app/src/main/java/com/naviapp/common/customview/RadioCustomView.kt b/app/src/main/java/com/naviapp/common/customview/RadioCustomView.kt new file mode 100644 index 0000000000..04210d04fe --- /dev/null +++ b/app/src/main/java/com/naviapp/common/customview/RadioCustomView.kt @@ -0,0 +1,35 @@ +package com.naviapp.common.customview + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.databinding.DataBindingUtil +import com.naviapp.R +import com.naviapp.databinding.ViewRadioIconCustomBinding +import com.naviapp.models.RadioCustomViewBindingData + +class RadioCustomView(context: Context, attrs: AttributeSet? = null) : + ConstraintLayout(context, attrs) { + private val binding: ViewRadioIconCustomBinding + + init { + val inflater = LayoutInflater.from(context) + binding = DataBindingUtil.inflate(inflater, R.layout.view_radio_icon_custom, this, true) + } + + fun setProperties( + radioButtonText: String?, + iconCode: String? = null, + description: String? = null, + checked: Boolean? = null, + enabled: Boolean? = null, + selectorRadioButton: Int? = R.drawable.radiobutton_selector, + styleDescription: Int? = R.style.TextDescExtraSmallFontStyleOne + ) { + binding.data = RadioCustomViewBindingData( + radioButtonText, iconCode, description, selectorRadioButton, styleDescription, + checked ?: false, enabled ?: false + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/common/customview/RadioRecyclerView.kt b/app/src/main/java/com/naviapp/common/customview/RadioRecyclerView.kt new file mode 100644 index 0000000000..2ae79c17ac --- /dev/null +++ b/app/src/main/java/com/naviapp/common/customview/RadioRecyclerView.kt @@ -0,0 +1,34 @@ +package com.naviapp.common.customview + +import android.content.Context +import android.util.AttributeSet +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.naviapp.common.adapter.RadioRvAdapter +import com.naviapp.common.decorator.LeftMarginItemDecoration +import com.naviapp.common.decorator.TopMarginItemDecoration +import com.naviapp.models.response.RadioButtonResponse + +class RadioRecyclerView(context: Context, attrs: AttributeSet? = null) : + RecyclerView(context, attrs) { + + private val _selectedLabelLiveData = MutableLiveData() + val selectedLabelLiveData: LiveData get() = _selectedLabelLiveData + fun setProperties( + radioViewList: List, + orientation: Int = VERTICAL, + gap: Float + ) { + layoutManager = LinearLayoutManager(context, orientation, false) + val itemDecoration = if (orientation == HORIZONTAL) { + LeftMarginItemDecoration(gap) + } else { + TopMarginItemDecoration(gap) + } + addItemDecoration(itemDecoration) + adapter = RadioRvAdapter(radioViewList, _selectedLabelLiveData) + } +} + diff --git a/app/src/main/java/com/naviapp/common/fragment/OtpBottomSheet.kt b/app/src/main/java/com/naviapp/common/fragment/OtpBottomSheet.kt index 65ba862e2f..32a0e1b44a 100644 --- a/app/src/main/java/com/naviapp/common/fragment/OtpBottomSheet.kt +++ b/app/src/main/java/com/naviapp/common/fragment/OtpBottomSheet.kt @@ -57,7 +57,9 @@ class OtpBottomSheet : BaseBottomSheet(), View.OnClickListener { private fun initError() { initError(viewModel) otpSharedViewModel?.let { - initError(it) + if (!it.errorResponse.hasActiveObservers()) { + initError(it) + } } } @@ -157,10 +159,8 @@ class OtpBottomSheet : BaseBottomSheet(), View.OnClickListener { } ApiErrorTagType.MAX_OTP_ATTEMPTS -> { analyticsEventTracker.onOtpMaxAttempts() - binding.errorMsgOtpTv.text = resources.getString(R.string.otp_max_attempt) binding.verifyOtpBtn.setState(false) - binding.resendOtpTv.visibility = View.INVISIBLE - binding.countdownTimerTv.visibility = View.INVISIBLE + safelyDismissDialog() } ApiErrorTagType.SOMETHING_WENT_WRONG -> { binding.errorMsgOtpTv.text = resources.getString(R.string.something_went_wrong) @@ -229,7 +229,6 @@ class OtpBottomSheet : BaseBottomSheet(), View.OnClickListener { ) } NaviAnalytics.OTP_EPFO -> { - startCountDownTimerForApiTimeout(API_TIMEOUT) otpSharedViewModel?.verifyOtpForEPFO( OtpRequest( otp = binding.otpBoxLayout.getText(), @@ -261,23 +260,10 @@ class OtpBottomSheet : BaseBottomSheet(), View.OnClickListener { } } - private fun startCountDownTimerForApiTimeout(apiTimeoutInSeconds: Int) { - if (timer != null) { - timer?.cancel() - } - timer = object : CountDownTimer( - apiTimeoutInSeconds * Constants.MILLISECONDS_PER_SECOND.toLong(), - Constants.MILLISECONDS_PER_SECOND.toLong() - ) { - override fun onTick(millisUntilFinished: Long) { - - } - - override fun onFinish() { - safelyDismissDialog() - otpSharedViewModel?.setApiTimeout(false) - } - }.start() + override fun onDestroy() { + super.onDestroy() + viewModel.resetData() + otpSharedViewModel?.resetData() } override val screenName: String @@ -290,7 +276,6 @@ class OtpBottomSheet : BaseBottomSheet(), View.OnClickListener { const val KEY_OTP_TOKEN = "KEY_OTP_TOKEN" const val KEY_OTP_SIZE = "KEY_OTP_SIZE" const val KEY_COMPANY_NAME = "KEY_COMPANY_NAME" - const val API_TIMEOUT = 10 fun newInstance(bundle: Bundle): OtpBottomSheet { return OtpBottomSheet().apply { arguments = bundle diff --git a/app/src/main/java/com/naviapp/common/repository/OtpRepository.kt b/app/src/main/java/com/naviapp/common/repository/OtpRepository.kt index ba87dd92b5..23c02b80d3 100644 --- a/app/src/main/java/com/naviapp/common/repository/OtpRepository.kt +++ b/app/src/main/java/com/naviapp/common/repository/OtpRepository.kt @@ -4,7 +4,6 @@ import com.naviapp.models.request.OtpRequest import com.naviapp.models.request.SendOtpForDisbursementRequest import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService -import com.naviapp.utils.longRunningRetrofitService class OtpRepository : ResponseCallback() { suspend fun sendOtp(sendOtpForDisbursementRequest: SendOtpForDisbursementRequest) = @@ -17,5 +16,5 @@ class OtpRepository : ResponseCallback() { apiResponseCallback(retrofitService().verifyOtpForDisbursement(otpRequest)) suspend fun verifyOtpForEPFO(otpRequest: OtpRequest) = - apiResponseCallback(longRunningRetrofitService().verifyOtpForEPFO(otpRequest)) + apiResponseCallback(retrofitService().verifyOtpForEPFO(otpRequest)) } \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/common/viewmodel/OtpSharedViewModel.kt b/app/src/main/java/com/naviapp/common/viewmodel/OtpSharedViewModel.kt index 37f686d92e..0e4ed3970d 100644 --- a/app/src/main/java/com/naviapp/common/viewmodel/OtpSharedViewModel.kt +++ b/app/src/main/java/com/naviapp/common/viewmodel/OtpSharedViewModel.kt @@ -44,8 +44,10 @@ class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository() ApiConstants.API_WRONG_OTP -> _errorVerifyOtp.value = ApiErrorTagType.OTP_WRONG ApiConstants.API_EXPIRED_OTP -> _errorVerifyOtp.value = ApiErrorTagType.OTP_EXPIRED - ApiConstants.API_TOO_MANY_REQUESTS -> _errorVerifyOtp.value = - ApiErrorTagType.MAX_OTP_ATTEMPTS + ApiConstants.API_TOO_MANY_REQUESTS -> { + _errorVerifyOtp.value = ApiErrorTagType.MAX_OTP_ATTEMPTS + setErrorData(response.errors, response.error) + } else -> { _errorVerifyOtp.value = ApiErrorTagType.SOMETHING_WENT_WRONG setErrorData(response.errors, response.error) @@ -64,8 +66,10 @@ class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository() ApiConstants.API_WRONG_OTP -> _errorVerifyOtp.value = ApiErrorTagType.OTP_WRONG ApiConstants.API_EXPIRED_OTP -> _errorVerifyOtp.value = ApiErrorTagType.OTP_EXPIRED - ApiConstants.API_TOO_MANY_REQUESTS -> _errorVerifyOtp.value = - ApiErrorTagType.MAX_OTP_ATTEMPTS + ApiConstants.API_TOO_MANY_REQUESTS -> { + _errorVerifyOtp.value = ApiErrorTagType.MAX_OTP_ATTEMPTS + setErrorData(response.errors, response.error) + } else -> { _errorVerifyOtp.value = ApiErrorTagType.SOMETHING_WENT_WRONG setErrorData(response.errors, response.error) @@ -79,5 +83,6 @@ class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository() _apiTimeout.value = null _errorVerifyOtp.value = null _verifyOtpResponse.value = null + errorResponse.value = null } } \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/common/viewmodel/OtpViewModel.kt b/app/src/main/java/com/naviapp/common/viewmodel/OtpViewModel.kt index 71af6f99ba..65315934d5 100644 --- a/app/src/main/java/com/naviapp/common/viewmodel/OtpViewModel.kt +++ b/app/src/main/java/com/naviapp/common/viewmodel/OtpViewModel.kt @@ -34,4 +34,9 @@ class OtpViewModel(private val repository: OtpRepository = OtpRepository()) : Ba } } } + + fun resetData() { + _sendOtpResponse.value = null + errorResponse.value = null + } } \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/errors/fragments/ActionErrorFragment.kt b/app/src/main/java/com/naviapp/errors/fragments/ActionErrorFragment.kt index 480f3d0467..db5141beaf 100644 --- a/app/src/main/java/com/naviapp/errors/fragments/ActionErrorFragment.kt +++ b/app/src/main/java/com/naviapp/errors/fragments/ActionErrorFragment.kt @@ -91,6 +91,7 @@ class ActionErrorFragment : BaseBottomSheet() { BANK_ERROR_ICON -> R.drawable.ic_bank_error_svg PROFILE_ERROR_ICON -> R.drawable.ic_profile_error_svg OTP_ON_CALL_ERROR_ICON -> R.drawable.ic_otp_call_error_svg + INVALID_PAN -> R.drawable.ic_pan_error else -> R.drawable.ic_error_circle_svg } } @@ -110,6 +111,7 @@ class ActionErrorFragment : BaseBottomSheet() { const val USER_ON_HOLD_ERROR_ICON = "USER_ON_HOLD_ERROR_ICON" const val NAVI_ICON = "NAVI_ICON" const val OTP_ON_CALL_ERROR_ICON = "OTP_ON_CALL_ERROR_ICON" + const val INVALID_PAN = "INVALID_PAN" private const val ERROR_DATA = "ERROR_DATA" private const val DIALOG_CANCELABLE = "DIALOG_CANCELABLE" diff --git a/app/src/main/java/com/naviapp/models/RadioCustomViewBindingData.kt b/app/src/main/java/com/naviapp/models/RadioCustomViewBindingData.kt new file mode 100644 index 0000000000..bcc3826374 --- /dev/null +++ b/app/src/main/java/com/naviapp/models/RadioCustomViewBindingData.kt @@ -0,0 +1,11 @@ +package com.naviapp.models + +data class RadioCustomViewBindingData( + val radioButtonText: String? = null, + val iconCode: String? = null, + val description: String? = null, + val selectorRadioButton: Int?, + val styleDescription: Int?, + var checked: Boolean = false, + val enabled: Boolean +) diff --git a/app/src/main/java/com/naviapp/models/request/AutoPayOptionData.kt b/app/src/main/java/com/naviapp/models/request/AutoPayOptionData.kt new file mode 100644 index 0000000000..25f6dd808c --- /dev/null +++ b/app/src/main/java/com/naviapp/models/request/AutoPayOptionData.kt @@ -0,0 +1,8 @@ +package com.naviapp.models.request + +import com.google.gson.annotations.SerializedName + +data class AutoPayOptionData( + @SerializedName("autoPayOption") + val autoPayOptionId: String? = null +) diff --git a/app/src/main/java/com/naviapp/models/request/KycRequest.kt b/app/src/main/java/com/naviapp/models/request/KycRequest.kt index a3c415764b..3c501b8a23 100644 --- a/app/src/main/java/com/naviapp/models/request/KycRequest.kt +++ b/app/src/main/java/com/naviapp/models/request/KycRequest.kt @@ -3,13 +3,8 @@ package com.naviapp.models.request import com.google.gson.annotations.SerializedName data class KycRequest( - @SerializedName("address") val address: Address?, - @SerializedName("parentDetails") val parentDetails: ParentDetails? = null -) - -data class ParentDetails( - @SerializedName("fatherName") val fatherName: String? = null, - @SerializedName("motherName") val motherName: String? = null + @SerializedName("address") val address: Address? = null, + @SerializedName("parentDetails") val textField: HashMap? = null ) data class Address( diff --git a/app/src/main/java/com/naviapp/models/response/DisbursementDetailsResponse.kt b/app/src/main/java/com/naviapp/models/response/DisbursementDetailsResponse.kt index 97df996db8..d37ed6a2fc 100644 --- a/app/src/main/java/com/naviapp/models/response/DisbursementDetailsResponse.kt +++ b/app/src/main/java/com/naviapp/models/response/DisbursementDetailsResponse.kt @@ -11,17 +11,26 @@ data class DisbursementDetailsResponse( @SerializedName("header") val header: Header? = null, @SerializedName("content") val disbursementDetails: DisbursementDetails? = null, @SerializedName("footer") val footer: Footer? = null -): Parcelable +) : Parcelable @Parcelize data class DisbursementDetails( - @SerializedName("netLoanAmount") val netLoanAmount: Amount?, - @SerializedName("emi") val emiAmount: Amount?, - @SerializedName("firstDueDate") val firstDueDate: String?, - @SerializedName("bankDetails") var bankDetails: BankDetail?, - @SerializedName("customerName") val customerName: String?, - @SerializedName("autoDebitStatus") val autoDebitStatus: String?, - @SerializedName("email") val email: String?, - @SerializedName("addBankAccountEnable") val addBankAccountEnable: Boolean?, - @SerializedName("editBankRetriesLeft") val editBankRetriesLeft: Int? = null + @SerializedName("netLoanAmount") val netLoanAmount: Amount? = null, + @SerializedName("emi") val emiAmount: Amount? = null, + @SerializedName("firstDueDate") val firstDueDate: String? = null, + @SerializedName("bankDetails") var bankDetails: BankDetail? = null, + @SerializedName("customerName") val customerName: String? = null, + @SerializedName("autoDebitStatus") var autoDebitStatus: String? = null, + @SerializedName("email") val email: String? = null, + @SerializedName("addBankAccountEnable") val addBankAccountEnable: Boolean? = null, + @SerializedName("editBankRetriesLeft") val editBankRetriesLeft: Int? = null, + @SerializedName("autoPayOptions") val autoPayOptions: List? = null, ) : Parcelable + +enum class AutoPayStatus { + WAITING, + SUCCESS, + PENDING, + AADHAR_PENDING, + FAILURE +} diff --git a/app/src/main/java/com/naviapp/models/response/EnachWidgetResponse.kt b/app/src/main/java/com/naviapp/models/response/EnachWidgetResponse.kt new file mode 100644 index 0000000000..5f10633ee4 --- /dev/null +++ b/app/src/main/java/com/naviapp/models/response/EnachWidgetResponse.kt @@ -0,0 +1,12 @@ +package com.naviapp.models.response + +import com.google.gson.annotations.SerializedName + +data class EnachWidgetResponse( + @SerializedName("headerWidget") + val headerWidget: List? = null, + @SerializedName("contentWidget") + val contentWidget: List>? = null, + @SerializedName("footerWidget") + val footerWidget: List? = null +) diff --git a/app/src/main/java/com/naviapp/models/response/KycDetailsResponse.kt b/app/src/main/java/com/naviapp/models/response/KycDetailsResponse.kt index 19f2112f09..41bbe59f19 100644 --- a/app/src/main/java/com/naviapp/models/response/KycDetailsResponse.kt +++ b/app/src/main/java/com/naviapp/models/response/KycDetailsResponse.kt @@ -22,6 +22,7 @@ data class KycItem( @SerializedName("status") val status: String?, @SerializedName("currentAddress") val currentAddress: CurrentAddress?, @SerializedName("uri") val uri: String?, + @SerializedName("jsonKey") val jsonKey: String? = null, @SerializedName("showOtpOption") val showOtpOption: Boolean?, @SerializedName("isEditable") val isEditable: Boolean? = null, @SerializedName("additionalData") val additionalData: KycItemAdditionalData? = null diff --git a/app/src/main/java/com/naviapp/models/response/RadioButtonResponse.kt b/app/src/main/java/com/naviapp/models/response/RadioButtonResponse.kt new file mode 100644 index 0000000000..741c078306 --- /dev/null +++ b/app/src/main/java/com/naviapp/models/response/RadioButtonResponse.kt @@ -0,0 +1,15 @@ +package com.naviapp.models.response + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class RadioButtonResponse( + @SerializedName("id") val id: String? = null, + @SerializedName("title") val radioButtonText: String? = null, + @SerializedName("description") val description: String? = null, + @SerializedName("iconCode") val iconCode: String? = null, + @SerializedName("enabled") val enabled: Boolean? = null, + @SerializedName("checked") var checked: Boolean? = null +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/models/response/WidgetGenericResponse.kt b/app/src/main/java/com/naviapp/models/response/WidgetGenericResponse.kt index adb682902e..0491303926 100644 --- a/app/src/main/java/com/naviapp/models/response/WidgetGenericResponse.kt +++ b/app/src/main/java/com/naviapp/models/response/WidgetGenericResponse.kt @@ -1,5 +1,6 @@ package com.naviapp.models.response +import android.os.Parcelable import com.google.gson.annotations.SerializedName import com.navi.common.model.CtaData import kotlinx.android.parcel.Parcelize @@ -22,11 +23,13 @@ abstract class WidgetConfig( val status: String? = null ) +@Parcelize data class GenericWidgetConfig( @SerializedName("body") val widgetBody: GenericWidgetBody? = null -) : WidgetConfig() +) : WidgetConfig(), Parcelable +@Parcelize open class GenericWidgetBody( @SerializedName("title") val title: String? = null, @@ -42,7 +45,7 @@ open class GenericWidgetBody( val cta: CtaData? = null, @SerializedName("documentUrl") val documentUrl: String? = null -) +) : Parcelable @Parcelize data class GenericWidgetItem( diff --git a/app/src/main/java/com/naviapp/network/ApiErrorTagType.kt b/app/src/main/java/com/naviapp/network/ApiErrorTagType.kt index d10d84ec24..421a351913 100644 --- a/app/src/main/java/com/naviapp/network/ApiErrorTagType.kt +++ b/app/src/main/java/com/naviapp/network/ApiErrorTagType.kt @@ -64,6 +64,7 @@ object ApiErrorTagType { const val VIDEO_KYC_ERROR = "VIDEO_KYC_ERROR" const val OTP_WRONG = "OTP_WRONG" const val SOMETHING_WENT_WRONG = "SOMETHING_WENT_WRONG" + const val INVALID_PAN_DETAILS = "INVALID_PAN_DETAILS" @StringDef( SELFIE_UPLOAD, @@ -103,7 +104,8 @@ object ApiErrorTagType { NO_INTERNET_ERROR, SELFIE_SETTING_API_ERROR, OVD_UPLOAD_ERROR, - PG_REPAYMENT_STATUS_DETAIL_API_ERROR + PG_REPAYMENT_STATUS_DETAIL_API_ERROR, + INVALID_PAN_DETAILS ) @Retention(AnnotationRetention.SOURCE) annotation class ApiErrorTagTypeDef diff --git a/app/src/main/java/com/naviapp/network/models/Action.kt b/app/src/main/java/com/naviapp/network/models/Action.kt index 4a3e7f155a..e0fc4c3424 100644 --- a/app/src/main/java/com/naviapp/network/models/Action.kt +++ b/app/src/main/java/com/naviapp/network/models/Action.kt @@ -1,12 +1,11 @@ package com.naviapp.network.models import android.os.Parcelable -import android.view.View import com.google.gson.annotations.SerializedName import kotlinx.android.parcel.Parcelize -import kotlinx.android.parcel.RawValue @Parcelize data class Action( - @SerializedName("title") val title: String? + @SerializedName("title") val title: String?, + @SerializedName("subPage") val subPage: String? = null ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/network/retrofit/LongRunningRetrofitProvider.kt b/app/src/main/java/com/naviapp/network/retrofit/LongRunningRetrofitProvider.kt deleted file mode 100644 index 721cc46f1b..0000000000 --- a/app/src/main/java/com/naviapp/network/retrofit/LongRunningRetrofitProvider.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * * - * * Copyright (c) 2019 . All rights reserved @Navi - * - */ - -package com.naviapp.network.retrofit - -import com.naviapp.app.NaviApplication -import com.naviapp.network.ApiConstants.API_CONNECT_TIMEOUT_VALUE_120 -import com.naviapp.network.util.createRetrofitClient -import com.naviapp.network.util.getNetworkInfo -import retrofit2.Retrofit - -/* -* This is for long running apis which having large timeout -* //TODO Get rid of this after we do DI for personal loan -* */ -class LongRunningRetrofitProvider private constructor() { - val services: RetrofitService = defaultRetrofitClient.create(RetrofitService::class.java) - - private object Holder { - val INSTANCE = LongRunningRetrofitProvider() - } - - companion object { - val instance: LongRunningRetrofitProvider by lazy { Holder.INSTANCE } - val defaultRetrofitClient: Retrofit = - createRetrofitClient( - NaviHttpClient( - getNetworkInfo(API_CONNECT_TIMEOUT_VALUE_120), - NaviApplication.instance.applicationContext - ).httpClientBuilder - ) - } -} diff --git a/app/src/main/java/com/naviapp/network/retrofit/RetrofitService.kt b/app/src/main/java/com/naviapp/network/retrofit/RetrofitService.kt index d52f839150..6759d583f5 100644 --- a/app/src/main/java/com/naviapp/network/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/naviapp/network/retrofit/RetrofitService.kt @@ -241,7 +241,10 @@ interface RetrofitService { suspend fun fetchMendateData(@Path("requestId") requestId: String): Response>> @POST("/loan-applications/{loanApplicationId}/auto-debit-registration") - suspend fun fetchMendateRequestId(@Path("loanApplicationId") loanApplicationId: String): Response> + suspend fun fetchMendateRequestId( + @Path("loanApplicationId") loanApplicationId: String, + @Body autoPayOptionData: AutoPayOptionData + ): Response> //Company Names @GET("/master-data/fetch-companies") @@ -342,8 +345,8 @@ interface RetrofitService { @GET("/attach/details/insurance") suspend fun fetchInsuranceDetails(): Response> - @GET("/loan-applications/{loanApplicationId}/auto-debit-instructions ") - suspend fun fetchEnachDetails(@Path("loanApplicationId") loanApplicationId: String): Response> + @GET("/loan-applications/{loanApplicationId}/v2/auto-debit-instructions") + suspend fun fetchEnachDetails(@Path("loanApplicationId") loanApplicationId: String): Response> @POST("/loan-origination-manager/fetch-installments") suspend fun fetchEmiDetails(@Body loanFeeDetailsRequest: LoanFeeDetailsRequest): Response> diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/fragments/BankDetailsFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/fragments/BankDetailsFragment.kt index 900632b2d6..4f79d367f0 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/fragments/BankDetailsFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/fragments/BankDetailsFragment.kt @@ -14,28 +14,28 @@ import android.widget.Toast import androidx.core.widget.addTextChangedListener import androidx.lifecycle.ViewModelProvider import com.navi.analytics.uxcam.UxcamUtil +import com.navi.common.model.CtaData +import com.navi.common.sharedpref.PreferenceManager import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.fragment.BaseFragment import com.naviapp.dashboard.listeners.FragmentInteractionListener import com.naviapp.databinding.BankDetailsFragmentBinding -import com.naviapp.personalloan.getloan.activities.BankAccountVerificationLoaderActivity -import com.naviapp.personalloan.getloan.activities.GetLoanActivity.Companion.IS_FOR_SECOND_LOAN_JOURNEY -import com.naviapp.personalloan.getloan.bankdetails.listeners.FindIfscListener -import com.naviapp.personalloan.getloan.bankdetails.listeners.OnSelectBankListener -import com.naviapp.personalloan.getloan.bankdetails.viewmodels.BankDetailsVM import com.naviapp.homeloan.common.listener.CheckBoxClickListener import com.naviapp.homeloan.common.listener.FooterInteractionListener import com.naviapp.homeloan.common.listener.HeaderInteractionListener -import com.navi.common.model.CtaData import com.naviapp.models.FeedbackPageType import com.naviapp.models.request.BankDetail import com.naviapp.models.response.* import com.naviapp.network.ApiErrorTagType.FETCH_BANKS_ERROR import com.naviapp.network.ApiErrorTagType.FETCH_DISBURSEMENT_DETAILS_ERROR import com.naviapp.network.ApiErrorTagType.FETCH_LOAN_BASIC_DETAILS_ERROR +import com.naviapp.personalloan.getloan.activities.BankAccountVerificationLoaderActivity import com.naviapp.personalloan.getloan.activities.GetLoanActivity -import com.navi.common.sharedpref.PreferenceManager +import com.naviapp.personalloan.getloan.activities.GetLoanActivity.Companion.IS_FOR_SECOND_LOAN_JOURNEY +import com.naviapp.personalloan.getloan.bankdetails.listeners.FindIfscListener +import com.naviapp.personalloan.getloan.bankdetails.listeners.OnSelectBankListener +import com.naviapp.personalloan.getloan.bankdetails.viewmodels.BankDetailsVM import com.naviapp.utils.* import com.naviapp.utils.Constants.BANK_ACCOUNT_NUMBER import com.naviapp.utils.Constants.BANK_IFSC @@ -172,6 +172,7 @@ class BankDetailsFragment : BaseFragment(), View.OnClickListener, FindIfscListen private fun initObservers() { viewModel.loanBasicDetails.observeNonNull(this) { + loanApplicationId = it.loanApplicationId if (!it.loanApplicationId.isNullOrEmpty()) { showLoader() viewModel.fetchDisbursementDetails(it.loanApplicationId) diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/repositories/BankDetailsAutoDebitRepository.kt b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/repositories/BankDetailsAutoDebitRepository.kt index 4981bd5a5d..b940a9c7ce 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/repositories/BankDetailsAutoDebitRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/repositories/BankDetailsAutoDebitRepository.kt @@ -1,6 +1,7 @@ package com.naviapp.personalloan.getloan.bankdetailsautodebit.repositories import com.naviapp.models.EnachData +import com.naviapp.models.request.AutoPayOptionData import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService @@ -8,8 +9,16 @@ class BankDetailsAutoDebitRepository : ResponseCallback() { suspend fun fetchDisbursementDetails(loanApplicationId: String) = apiResponseCallback(retrofitService().fetchDisbursementDetails(loanApplicationId)) - suspend fun fetchMandateRequestId(loanApplicationId: String) = - apiResponseCallback(retrofitService().fetchMendateRequestId(loanApplicationId)) + suspend fun fetchMandateRequestId( + loanApplicationId: String, + autoPayOptionData: AutoPayOptionData + ) = + apiResponseCallback( + retrofitService().fetchMendateRequestId( + loanApplicationId, + autoPayOptionData + ) + ) suspend fun fetchEnachStatus(requestId: String) = apiResponseCallback(retrofitService().fetchAsyncRequestData(requestId)) diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/activities/EnachTutorialActivity.kt b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/activities/EnachTutorialActivity.kt index 1bc1b0cc18..07ceb92ab5 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/activities/EnachTutorialActivity.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/activities/EnachTutorialActivity.kt @@ -3,19 +3,20 @@ package com.naviapp.personalloan.getloan.bankdetailsautodebit.view.activities import android.os.Bundle import android.view.View import androidx.databinding.DataBindingUtil -import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider +import com.navi.common.sharedpref.PreferenceManager import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.BaseActivity -import com.naviapp.common.decorator.TopMarginItemDecoration +import com.naviapp.common.adapter.BaseVPA import com.naviapp.databinding.EnachTutorialActivityBinding -import com.naviapp.personalloan.getloan.bankdetailsautodebit.adapter.EnachDetailsAdapter -import com.naviapp.personalloan.getloan.bankdetailsautodebit.viewmodels.BankDetailsAutoDebitVM +import com.naviapp.models.response.EnachWidgetResponse import com.naviapp.models.response.GenericWidgetConfig -import com.navi.common.sharedpref.PreferenceManager +import com.naviapp.personalloan.getloan.bankdetailsautodebit.view.fragments.EnachFragment +import com.naviapp.personalloan.getloan.bankdetailsautodebit.viewmodels.BankDetailsAutoDebitVM import com.naviapp.utils.Constants import com.naviapp.utils.LOAN_APPLICATION_ID +import com.naviapp.utils.onPageSelected class EnachTutorialActivity : BaseActivity(), View.OnClickListener { private lateinit var binding: EnachTutorialActivityBinding @@ -31,7 +32,6 @@ class EnachTutorialActivity : BaseActivity(), View.OnClickListener { binding = DataBindingUtil.setContentView(this, R.layout.enach_tutorial_activity) super.setContentView(binding.root) initError(viewModel) - initUI() initListener() setUpObservers() val loanType = intent.getStringExtra(KEY_LOAN_TYPE) @@ -47,44 +47,48 @@ class EnachTutorialActivity : BaseActivity(), View.OnClickListener { } private fun setUpObservers() { - viewModel.enachDetails.observe(this, Observer { widgetGenericResponse -> + viewModel.enachDetails.observe(this, { widgetGenericResponse -> hideLoader() widgetGenericResponse?.let { - it.contentWidget?.let { contentWidgetList -> - @Suppress("UNCHECKED_CAST") - binding.contentRv.adapter = - EnachDetailsAdapter(contentWidgetList as List) - } - it.footerWidget?.let { listFooter -> - if (!listFooter.isNullOrEmpty()) { - (listFooter[0] as GenericWidgetConfig).widgetBody?.title?.let { title -> - binding.setupAutoDebitBtn.setProperties( - title, - iconId = R.drawable.ic_arrow_right_svg - ) - } - } - } + setupView(it) } }) } - private fun initListener() { - binding.backIv.setOnClickListener(this) - binding.setupAutoDebitBtn.setOnClickListener(this) + private fun setupView(enachWidgetResponse: EnachWidgetResponse) { + val headerWidgetList: List? = + enachWidgetResponse.headerWidget + val contentWidgetListForAllScreens: List>? = + enachWidgetResponse.contentWidget + val footerWidgetList: List? = + enachWidgetResponse.footerWidget + val adapter = BaseVPA(supportFragmentManager) + contentWidgetListForAllScreens?.forEachIndexed { index, contentWidgetList -> + adapter.addFragment( + EnachFragment.newInstance( + footerWidgetList?.getOrNull(index)?.widgetId, + contentWidgetList, + footerWidgetList?.getOrNull(index)?.widgetBody?.title + ), + headerWidgetList?.getOrNull(index)?.widgetBody?.title.orEmpty() + ) + } + binding.enachViewPager.adapter = adapter + binding.enachViewPager.offscreenPageLimit = 2 + binding.enachTabLayout.setupWithViewPager(binding.enachViewPager) + binding.enachViewPager.onPageSelected { position -> + NaviAnalytics.naviAnalytics.EnachTutorial() + .onPageSelected(headerWidgetList?.getOrNull(position)?.widgetBody?.title.orEmpty()) + } } - private fun initUI() { - binding.contentRv.addItemDecoration(TopMarginItemDecoration(resources.getDimension(R.dimen.layout_dp_40))) + private fun initListener() { + binding.sectionHeading.backIv.setOnClickListener(this) } override fun onClick(v: View?) { when (v?.id) { - binding.backIv.id -> finish() - binding.setupAutoDebitBtn.id -> { - setResult(RESULT_OK) - finish() - } + binding.sectionHeading.backIv.id -> finish() } } diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/fragments/BankDetailsAutoDebitFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/fragments/BankDetailsAutoDebitFragment.kt index 8594fbd199..332b86d9b9 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/fragments/BankDetailsAutoDebitFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/fragments/BankDetailsAutoDebitFragment.kt @@ -9,9 +9,10 @@ import android.os.Handler import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModelProvider import com.navi.analytics.uxcam.UxcamUtil +import com.navi.common.model.CtaData +import com.navi.common.sharedpref.PreferenceManager import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.ApiPollScheduler @@ -26,6 +27,16 @@ import com.naviapp.firebasedb.FirebaseStatusType.PENDING import com.naviapp.firebasedb.FirebaseStatusType.SUCCESS import com.naviapp.homeloan.common.listener.FooterInteractionListener import com.naviapp.homeloan.common.listener.HeaderInteractionListener +import com.naviapp.manager.UserManager +import com.naviapp.models.FeedbackPageType +import com.naviapp.models.request.AutoPayOptionData +import com.naviapp.models.response.AdditionalDataAsyncResponse +import com.naviapp.models.response.AutoPayStatus +import com.naviapp.models.response.EnachMandateDetailsResponse +import com.naviapp.network.ApiErrorTagType +import com.naviapp.network.models.Action +import com.naviapp.network.models.GenericWarningResponse +import com.naviapp.payment.models.ProviderType import com.naviapp.personalloan.getloan.activities.GetLoanActivity import com.naviapp.personalloan.getloan.bankdetails.fragments.BankDetailsFragment.Companion.DISBURSEMENT_DETAILS import com.naviapp.personalloan.getloan.bankdetails.fragments.BankDetailsFragment.Companion.EDIT_ACCOUNT @@ -35,30 +46,18 @@ import com.naviapp.personalloan.getloan.bankdetailsautodebit.viewmodels.EnachSha import com.naviapp.personalloan.getloan.common.listener.EnachListener import com.naviapp.personalloan.getloan.helpers.EnachHelper import com.naviapp.personalloan.getloan.helpers.EnachStub -import com.naviapp.manager.UserManager -import com.navi.common.model.CtaData -import com.naviapp.models.FeedbackPageType -import com.naviapp.models.response.AdditionalDataAsyncResponse -import com.naviapp.models.response.DisbursementDetails -import com.naviapp.models.response.EnachMandateDetailsResponse -import com.naviapp.network.ApiErrorTagType -import com.naviapp.network.models.Action -import com.naviapp.network.models.GenericWarningResponse -import com.naviapp.payment.models.ProviderType -import com.navi.common.sharedpref.PreferenceManager import com.naviapp.utils.* +import com.naviapp.utils.Constants.MANDATE_TYPE class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, FooterInteractionListener { private lateinit var binding: BankDetailsAutoDebitFragmentBinding private var listener: FragmentInteractionListener? = null 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 private val naviAnalyticsEventTracker = NaviAnalytics.naviAnalytics.BankDetails() - private var editAccountMaxRetry = 0 private var enachListener: EnachListener? = null private var loanApplicationId: String? = null @@ -73,7 +72,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { binding = BankDetailsAutoDebitFragmentBinding.inflate(inflater, container, false) initError() initUi() @@ -158,6 +157,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, private fun observeLoanBasicDetails() { viewModel.loanBasicDetails.observeNonNull(this) { basicDetails -> basicDetails.loanApplicationId?.let { + loanApplicationId = it showLoader() PreferenceManager.setStringPreference(LOAN_APPLICATION_ID, it) viewModel.fetchDisbursementDetails(it) @@ -231,12 +231,12 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } private fun observeDisbursementDetails() { - viewModel.disbursementDetails.observeNonNull(this) { disbursementDetailsResponse -> + viewModel.disbursementDetails.observeNullable(this) { disbursementDetailsResponse -> hideLoader() headerInteractionListener?.setProperties( - disbursementDetailsResponse.header?.title, - disbursementDetailsResponse.header?.subtitle, - disbursementDetailsResponse.header?.progress + disbursementDetailsResponse?.header?.title, + disbursementDetailsResponse?.header?.subtitle, + disbursementDetailsResponse?.header?.progress ) binding.footerView.setProperties( disbursementDetailsResponse?.footer?.backCta, @@ -246,32 +246,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, ), this ) - disbursementDetailsResponse?.disbursementDetails?.let { disbursementDetails -> - setBankDetails( - disbursementDetails.bankDetails?.bankName, - disbursementDetails.bankDetails?.accountNumber - ) - binding.bankDetailsTv.text = getString( - R.string.loan_transfer_info, - disbursementDetails.netLoanAmount?.value?.formatCurrency() - ?: getString(R.string.loan_amount) - ) - binding.autoDebitLayout.detailTv.text = getString( - R.string.enach_first_installment_info, - disbursementDetails.emiAmount?.value?.formatCurrency(), - disbursementDetails.firstDueDate - ) - editAccountMaxRetry = disbursementDetails.editBankRetriesLeft.orZero() - editBtnHandling(disbursementDetails) - disbursementDetails.autoDebitStatus?.let { setAutoDebitState(it, true) } - showAutoDebitLayout() - } - } - } - - private fun editBtnHandling(disbursementDetail: DisbursementDetails) { - if (disbursementDetail.editBankRetriesLeft.orZero() <= 0 || disbursementDetail.autoDebitStatus == SUCCESS) { - binding.editAccountTv.visibility = View.GONE + binding.viewModel = viewModel } } @@ -350,7 +325,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, when (status) { SUCCESS -> { firebaseHelper?.clear() - binding.editAccountTv.visibility = View.GONE + binding.changeBankTv.visibility = View.GONE gotoGetLoan() } FAILURE -> { @@ -396,7 +371,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, showTimeoutErrorScreen( firebaseHelper, apiPollScheduler, - View.OnClickListener { setupAutoDebit() }, + { setupAutoDebit() }, errorTag ) firebaseHelper = null @@ -434,7 +409,12 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, apiPollScheduler = ApiPollScheduler( numberOfRetry = NUMBER_OF_RETRY_MANDATE_STATUS, doOnTimeout = { - activity?.runOnUiThread { handleResponse(WAITING, MANDATE_COMPLETE) } + activity?.runOnUiThread { + handleResponse( + AutoPayStatus.WAITING.name, + MANDATE_COMPLETE + ) + } } ) { viewModel.fetchEnachStatus(requestId) @@ -456,66 +436,16 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, private fun setAutoDebitState(autoDebitStatus: String, isPageLoad: Boolean = false) { if (autoDebitStatus == SUCCESS) naviAnalyticsEventTracker.onAutoDebitSuccessScreen() else if (autoDebitStatus == FAILURE) naviAnalyticsEventTracker.onAutoDebitFailureScreen() - binding.autoDebitLayout.statusTv.visibility = - if (autoDebitStatus == PENDING) View.GONE else View.VISIBLE + viewModel.setAutoDebitState(autoDebitStatus) + binding.notifyChange() binding.footerView.visibility = - if (autoDebitStatus == SUCCESS || autoDebitStatus == WAITING) View.GONE else View.VISIBLE - binding.autoDebitLayout.howToSetupTv.visibility = - if (autoDebitStatus == SUCCESS || autoDebitStatus == WAITING) View.GONE else View.VISIBLE - binding.autoDebitLayout.statusTv.text = getString( - when (autoDebitStatus) { - SUCCESS -> R.string.auto_debit_success - WAITING -> R.string.auto_debit_pending - else -> R.string.auto_debit_failed - } - ) - - if (autoDebitStatus == WAITING) { - binding.autoDebitLayout.autoDebitTv.text = getString(R.string.auto_debit_pending_title) - binding.autoDebitLayout.detailTv.text = getString(R.string.auto_debit_pending_status) - } else { - binding.autoDebitLayout.autoDebitTv.text = - getString(R.string.setup_auto_debit_for_emi_s) - } - - context?.let { context -> - binding.autoDebitLayout.statusTv.setTextColor( - ContextCompat.getColor( - context, - when (autoDebitStatus) { - SUCCESS -> R.color.green - FAILURE -> R.color.red - else -> R.color.title_color_one - } - ) - ) - binding.autoDebitLayout.statusTv.setCompoundDrawablesWithIntrinsicBounds( - ContextCompat.getDrawable( - context, - when (autoDebitStatus) { - SUCCESS -> R.drawable.ic_tick_svg - FAILURE -> R.drawable.ic_alert_svg - else -> R.drawable.ic_pending_svg - } - ), - null, null, null - ) - } - - if (editAccountMaxRetry > 0 && autoDebitStatus == FAILURE) { - if (binding.editAccountTv.visibility != View.VISIBLE) - binding.editAccountTv.visibility = View.VISIBLE - } - if (isPageLoad && autoDebitStatus == SUCCESS) showNextBtn() + if (autoDebitStatus == SUCCESS || autoDebitStatus == AutoPayStatus.WAITING.name) View.GONE else View.VISIBLE + if (isPageLoad && autoDebitStatus == SUCCESS) binding.footerView.visibility = View.VISIBLE } private fun initUi() { - val isForSecondLoanJourney = - arguments?.getBoolean(GetLoanActivity.IS_FOR_SECOND_LOAN_JOURNEY).orFalse() - binding.bankDisclaimerView.bankDisclaimerCv.visibility = - if (isForSecondLoanJourney) View.GONE else View.VISIBLE - - UxcamUtil.instance.occludeSensitiveView(binding.accountNumberTv) + binding.footerInteractionListener = this + UxcamUtil.instance.occludeSensitiveView(binding.bankAccountNumberTv) initObservers() val id = loanApplicationId if (!id.isNullOrEmpty()) { @@ -526,49 +456,37 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } } - private fun showAutoDebitLayout() { - if (binding.autoDebitLayout.root.visibility == View.VISIBLE) return - Handler().postDelayed({ - binding.autoDebitLayout.root.visibility = View.VISIBLE - binding.divider.visibility = View.VISIBLE - binding.verifiedBadge.visibility = View.VISIBLE - setEaseInAnimation(binding.autoDebitLayout.root, binding.divider, binding.verifiedBadge) - }, AUTO_DEBIT_LAYOUT_DELAY) - } - - private fun setBankDetails(bankName: String?, accountNumber: String?) { - ifLet(bankName, accountNumber) { (bankName, accountNumber) -> - binding.bankNameTv.text = bankName - binding.accountNumberTv.text = accountNumber - } - } - private fun initListeners() { - binding.autoDebitLayout.howToSetupTv.setOnClickListener(this) - binding.editAccountTv.setOnClickListener(this) + binding.selectManadateView.howToSetupTv.setOnClickListener(this) + binding.changeBankTv.setOnClickListener(this) } - private fun setupAutoDebit() { + private fun setupAutoDebit(autoPayTypeId: String? = binding.selectManadateView.mandateOptionsRv.selectedLabelLiveData.value?.id) { if (!isAdded && activity?.isFinishing.orTrue()) return - showLoader() - naviAnalyticsEventTracker.onSetupAutoDebitClicked() + naviAnalyticsEventTracker.onSetupAutoDebitClicked(autoPayTypeId) val id = loanApplicationId if (!id.isNullOrEmpty()) { - viewModel.fetchMandateRequestId(id) + showLoader() + viewModel.fetchMandateRequestId(id, AutoPayOptionData(autoPayOptionId = autoPayTypeId)) } } override fun onClick(view: View?) { when (view?.id) { R.id.how_to_setup_tv -> navigateToEnachTutorial() - R.id.edit_account_tv -> handleEditAccountClick() + R.id.change_bank_tv -> handleEditAccountClick() } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - if (requestCode != ENACH_TUTORIAL_SETUP_AUTO_DEBIT || resultCode != RESULT_OK) return - setupAutoDebit() + if (resultCode == RESULT_OK) { + when (requestCode) { + ENACH_TUTORIAL_SETUP_AUTO_DEBIT -> { + setupAutoDebit(arguments?.getString(MANDATE_TYPE)) + } + } + } } private fun navigateToEnachTutorial() { @@ -617,15 +535,6 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, }) } - private fun showNextBtn() { - binding.footerView.visibility = View.VISIBLE - binding.footerView.setProperties( - viewModel.disbursementDetails.value?.footer?.backCta, - viewModel.disbursementDetails.value?.footer?.nextCta, - this - ) - } - override fun onAttach(context: Context) { super.onAttach(context) listener = context as? FragmentInteractionListener @@ -650,9 +559,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } override fun onFooterNextPress(ctaData: CtaData?, skipValidation: Boolean?) { - if (ctaData?.url == Constants.SETUP_AUTO_DEBIT) { - setupAutoDebit() - } else { + if (viewModel.isAutoPaySuccess()) { ctaData?.url?.let { listener?.navigateTo( it, Bundle().apply { @@ -660,6 +567,8 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } ) } + } else { + setupAutoDebit() } } @@ -668,11 +577,9 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, companion object { const val TAG = "BANK_DETAILS_AUTO_DEBIT_FRAGMENT" - private const val AUTO_DEBIT_LAYOUT_DELAY = 500L private const val DELAY_AFTER_ENACH_SUCCESS = 4000L private const val NUMBER_OF_RETRY_MANDATE_CREATION = 2 private const val NUMBER_OF_RETRY_MANDATE_STATUS = 6 - private const val WAITING = "WAITING" private const val EDIT_BANK_CONFIRM_DELAY = 200L private const val ENACH_TUTORIAL_SETUP_AUTO_DEBIT = 100 private const val EMANDATE_CANCEL_CODE = 0 diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/fragments/EnachFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/fragments/EnachFragment.kt new file mode 100644 index 0000000000..5f2e01bb56 --- /dev/null +++ b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/view/fragments/EnachFragment.kt @@ -0,0 +1,82 @@ +package com.naviapp.personalloan.getloan.bankdetailsautodebit.view.fragments + +import android.app.Activity.RESULT_OK +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.naviapp.R +import com.naviapp.common.decorator.TopMarginItemDecoration +import com.naviapp.common.fragment.BaseFragment +import com.naviapp.databinding.FragmentEnachBinding +import com.naviapp.models.response.GenericWidgetConfig +import com.naviapp.personalloan.getloan.bankdetailsautodebit.adapter.EnachDetailsAdapter +import com.naviapp.utils.Constants.EMPTY +import java.util.* + +class EnachFragment : BaseFragment() { + private lateinit var binding: FragmentEnachBinding + + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentEnachBinding.inflate(inflater, container, false) + initUi() + return binding.root + } + + private fun initUi() { + arguments?.getParcelableArrayList(CONTENT_DATA)?.let { + binding.contentRv.adapter = EnachDetailsAdapter( + it + ) + binding.contentRv.addItemDecoration(TopMarginItemDecoration(resources.getDimension(R.dimen.layout_dp_40))) + } + arguments?.getString(FOOTER_TITLE)?.let { + binding.setupAutoDebitBtn.visibility = View.VISIBLE + binding.footerDivider.visibility = View.VISIBLE + binding.setupAutoDebitBtn.setProperties( + it, + iconId = R.drawable.ic_arrow_right_svg + ) + } ?: run { + binding.setupAutoDebitBtn.visibility = View.GONE + binding.footerDivider.visibility = View.GONE + } + + binding.setupAutoDebitBtn.setOnClickListener { + val intent = Intent() + intent.putExtra(MANDATE_TYPE, arguments?.getString(MANDATE_TYPE)) + activity?.setResult(RESULT_OK, intent) + activity?.finish() + } + } + + companion object { + const val TAG = "EnachFragment" + private const val CONTENT_DATA = "content_data" + private const val MANDATE_TYPE = "mandate_type" + private const val FOOTER_TITLE = "footer_title" + fun newInstance( + mandateType: String?, + contentWidgetList: List, + footerTitle: String? + ) = EnachFragment().apply { + val args = Bundle() + args.putParcelableArrayList( + CONTENT_DATA, + contentWidgetList as? ArrayList + ) + args.putString(MANDATE_TYPE, mandateType) + args.putString(FOOTER_TITLE, footerTitle) + arguments = args + } + } + + override val screenName: String + get() = EMPTY +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/viewmodels/BankDetailsAutoDebitVM.kt b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/viewmodels/BankDetailsAutoDebitVM.kt index 7477cf5c06..d166efa107 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/viewmodels/BankDetailsAutoDebitVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetailsautodebit/viewmodels/BankDetailsAutoDebitVM.kt @@ -3,17 +3,22 @@ package com.naviapp.personalloan.getloan.bankdetailsautodebit.viewmodels import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.naviapp.common.viewmodel.BaseVM -import com.naviapp.personalloan.getloan.bankdetailsautodebit.repositories.BankDetailsAutoDebitRepository import com.naviapp.models.EnachData +import com.naviapp.models.request.AutoPayOptionData import com.naviapp.models.response.* import com.naviapp.network.ApiErrorTagType import com.naviapp.network.models.GenericErrorResponse +import com.naviapp.personalloan.getloan.bankdetailsautodebit.repositories.BankDetailsAutoDebitRepository +import com.naviapp.utils.formatCurrency +import com.naviapp.utils.orZero import kotlinx.coroutines.launch class BankDetailsAutoDebitVM : BaseVM() { private val repository by lazy { BankDetailsAutoDebitRepository() } - val disbursementDetails = MutableLiveData() + private val _disbursementDetails = MutableLiveData() + val disbursementDetails: LiveData + get() = _disbursementDetails private val _mandateId = MutableLiveData() val mandateId: LiveData @@ -40,15 +45,15 @@ class BankDetailsAutoDebitVM : BaseVM() { val mandateFailure: LiveData get() = _mandateFailure - private val _enachDetails = MutableLiveData() - val enachDetails: LiveData + private val _enachDetails = MutableLiveData() + val enachDetails: LiveData get() = _enachDetails fun fetchDisbursementDetails(loanApplicationId: String) { coroutineScope.launch { val response = repository.fetchDisbursementDetails(loanApplicationId) if (response.error == null) { - disbursementDetails.value = response.data + _disbursementDetails.value = response.data } else { updateErrorMessage( response.error, @@ -59,9 +64,9 @@ class BankDetailsAutoDebitVM : BaseVM() { } } - fun fetchMandateRequestId(loanApplicationId: String) { + fun fetchMandateRequestId(loanApplicationId: String, autoPayOptionData: AutoPayOptionData) { coroutineScope.launch { - val response = repository.fetchMandateRequestId(loanApplicationId) + val response = repository.fetchMandateRequestId(loanApplicationId, autoPayOptionData) if (response.error == null) { _notificationPath.value = response.data?.notificationPath _mandateId.value = response.data @@ -132,4 +137,49 @@ class BankDetailsAutoDebitVM : BaseVM() { } } } + + fun isAutoPaySuccess(): Boolean { + return disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.SUCCESS.name + } + + fun isAutoPayAadharPending(): Boolean { + return disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.AADHAR_PENDING.name + } + + fun isAutoPayPending(): Boolean { + return disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.PENDING.name + } + + fun getBankName(): String? { + return disbursementDetails.value?.disbursementDetails?.bankDetails?.bankName + } + + fun getAccountNumber(): String? { + return disbursementDetails.value?.disbursementDetails?.bankDetails?.accountNumber + } + + fun canChangeBank(): Boolean { + return (disbursementDetails.value?.disbursementDetails?.editBankRetriesLeft.orZero() <= 0 || + disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.SUCCESS.name).not() + } + + fun getAutoPayFooterData(): Footer? { + return disbursementDetails.value?.footer + } + + fun getAutoPayOptions(): List? { + return disbursementDetails.value?.disbursementDetails?.autoPayOptions + } + + fun getEmiAmount(): String? { + return disbursementDetails.value?.disbursementDetails?.emiAmount?.value?.formatCurrency() + } + + fun getEmiStartDate(): String? { + return disbursementDetails.value?.disbursementDetails?.firstDueDate + } + + fun setAutoDebitState(autoDebitStatus: String) { + disbursementDetails.value?.disbursementDetails?.autoDebitStatus = autoDebitStatus + } } \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/helpers/EnachHelper.kt b/app/src/main/java/com/naviapp/personalloan/getloan/helpers/EnachHelper.kt index 9c34b9c264..8709b78182 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/helpers/EnachHelper.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/helpers/EnachHelper.kt @@ -7,10 +7,13 @@ package com.naviapp.personalloan.getloan.helpers import android.app.Activity +import android.text.TextUtils import androidx.appcompat.app.AppCompatActivity import com.digio.`in`.esign2sdk.Digio import com.digio.`in`.esign2sdk.DigioConfig import com.digio.`in`.esign2sdk.DigioEnvironment +import com.naviapp.BuildConfig +import com.naviapp.utils.PROD import com.naviapp.utils.log class EnachHelper { @@ -25,7 +28,9 @@ class EnachHelper { digio = Digio() val digioConfig = DigioConfig() // digioConfig.logo = "url for company logo" //TODO; company logo - digioConfig.environment = DigioEnvironment.PRODUCTION //Stage is sandbox + if (TextUtils.equals(BuildConfig.FLAVOR, PROD)) + digioConfig.environment = DigioEnvironment.PRODUCTION + else digioConfig.environment = DigioEnvironment.SANDBOX try { digio?.init(activity as AppCompatActivity, digioConfig) } catch (e: Exception) { diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/adapter/KycItemsAdapter.kt b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/adapter/KycItemsAdapter.kt index 727a16c72a..71f29b13c2 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/adapter/KycItemsAdapter.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/adapter/KycItemsAdapter.kt @@ -3,6 +3,7 @@ package com.naviapp.personalloan.getloan.kyc.adapter import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.widget.doAfterTextChanged import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.naviapp.R @@ -66,6 +67,15 @@ class KycItemsAdapter( ) ) } + KycItemType.TEXTFIELD.ordinal -> { + TextFieldViewHolder( + ItemTextFieldViewBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } KycItemType.PAN.ordinal -> { PanKycOptionsViewHolder( ItemPanKycViewBinding.inflate( @@ -111,6 +121,9 @@ class KycItemsAdapter( is AddressKycOptionsViewHolder -> { setupAddressView(holder.binding, position) } + is TextFieldViewHolder -> { + setupTextFieldView(holder.binding, position) + } is PanKycOptionsViewHolder -> { setupPanView(holder.binding, position) } @@ -125,6 +138,7 @@ class KycItemsAdapter( KycItemType.SELFIE.name -> KycItemType.SELFIE.ordinal KycItemType.AADHAR.name -> KycItemType.AADHAR.ordinal KycItemType.CURRENT_ADDRESS.name -> KycItemType.CURRENT_ADDRESS.ordinal + KycItemType.TEXTFIELD.name -> KycItemType.TEXTFIELD.ordinal KycItemType.PAN.name -> KycItemType.PAN.ordinal KycItemType.VIDEO_KYC.name -> KycItemType.VIDEO_KYC.ordinal else -> -1 @@ -171,6 +185,20 @@ class KycItemsAdapter( } } + private fun setupTextFieldView(binding: ItemTextFieldViewBinding, position: Int) { + val testFieldKycOption = kycItemList[position] + binding.fathersNameStatusView.setProperties( + (position + 1).toString().plus(DOT), + testFieldKycOption.title + ?: run { binding.root.resources.getString(R.string.father_s_name) } + ) + binding.textFieldEt.hint = testFieldKycOption.subTitle + ?: run { binding.root.resources.getString(R.string.type_here) } + binding.textFieldEt.doAfterTextChanged { + viewModel.setTextFieldData(it?.trim()?.toString()) + } + } + private fun setupAadharView(binding: ItemAadharKycViewBinding, position: Int) { val aadharKycOption = kycItemList[position] binding.idProofStatusView.setProperties( @@ -342,6 +370,9 @@ class AadharKycOptionsViewHolder(val binding: ItemAadharKycViewBinding) : class AddressKycOptionsViewHolder(val binding: ItemAddressKycViewBinding) : KycOptionsBaseViewHolder(binding.root) +class TextFieldViewHolder(val binding: ItemTextFieldViewBinding) : + KycOptionsBaseViewHolder(binding.root) + class PanKycOptionsViewHolder(val binding: ItemPanKycViewBinding) : KycOptionsBaseViewHolder(binding.root) @@ -349,5 +380,5 @@ class VideoKycOptionsViewHolder(val binding: ItemVideoKycViewBinding) : KycOptionsBaseViewHolder(binding.root) enum class KycItemType { - SELFIE, AADHAR, CURRENT_ADDRESS, PAN, VIDEO_KYC + SELFIE, AADHAR, CURRENT_ADDRESS, PAN, VIDEO_KYC, TEXTFIELD } diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/KycFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/KycFragment.kt index 838166bb1d..1acb2b1f4d 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/KycFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/KycFragment.kt @@ -18,6 +18,7 @@ import androidx.lifecycle.ViewModelProvider import co.hyperverge.hypersnapsdk.activities.HVDocsActivity import co.hyperverge.hypersnapsdk.listeners.DocCaptureCompletionHandler import co.hyperverge.hypersnapsdk.objects.HVDocConfig +import com.navi.common.model.CtaData import com.naviapp.BuildConfig import com.naviapp.R import com.naviapp.analytics.neoeyed.viewmodel.NeoEyedVM @@ -41,10 +42,10 @@ import com.naviapp.homeloan.common.listener.HeaderInteractionListener import com.naviapp.manager.PermissionsManager import com.naviapp.manager.PermissionsManager.Companion.CAMERA_PERMISSION import com.naviapp.manager.PermissionsManager.Companion.STORAGE_PERMISSION -import com.navi.common.model.CtaData import com.naviapp.models.FeedbackPageType import com.naviapp.models.KycUiStatusValue import com.naviapp.models.RedirectPageStatus +import com.naviapp.models.request.KycRequest import com.naviapp.models.request.SelfieSetting import com.naviapp.models.request.SelfieUploadRequestData import com.naviapp.models.response.KycAaadharActionType @@ -69,10 +70,12 @@ import com.naviapp.personalloan.getloan.kyc.viewmodels.KycSharedVM import com.naviapp.personalloan.getloan.kyc.viewmodels.KycVM import com.naviapp.utils.* import com.naviapp.utils.Constants.PL_KYC_LOCATION +import kotlinx.android.synthetic.main.transaction_history_fragment.* import java.io.ByteArrayOutputStream import java.io.File import java.io.FileInputStream import java.util.* +import kotlin.collections.HashMap class KycFragment : BaseFragment(), FooterInteractionListener, KycItemsListener { @@ -170,6 +173,34 @@ class KycFragment : BaseFragment(), FooterInteractionListener, observeSupportedPANOvdsUploadAsyncResponse() observeVideoKycData() observeVideoKycUploadAsyncResponse() + observeTextFieldData() + observeTextFieldSubmitResponse() + } + + private fun observeFathersNameSubmitSuccess() { + viewModel.fathersNameSubmitSuccess.observeNonNull(this) { + onFooterNextPress(viewModel.kycDetailsLiveData.value?.footer?.nextCta) + } + } + + private fun observeTextFieldData() { + viewModel.textFieldData.observeNonNull(this) { + enableNextButton(it) + } + } + + private fun observeTextFieldSubmitResponse() { + viewModel.textFieldSubmitAsyncResponse.observeNonNull(this) { data -> + data.requestId?.let { requestId -> + firebaseRequestId = requestId + firebaseInit( + requestId, + UPDATE_KYC_DETAILS, + data.notificationPath.orEmpty() + ) + apiPollInit(requestId, UPDATE_KYC_DETAILS) + } + } } private fun observeVideoKycData() { @@ -297,12 +328,10 @@ class KycFragment : BaseFragment(), FooterInteractionListener, } else { (binding.kycRecyclerView.adapter as? KycItemsAdapter)?.updateData(it) } - } - if (kycDetailsResponse.kycDetails?.kycDetailsComplete.orFalse()) { + + if (!viewModel.isTextFieldPresent() && kycDetailsResponse.kycDetails?.kycDetailsComplete.orFalse()) { binding.footerView.enableNextButton(true) - } else { - binding.footerView.enableNextButton(false) } handleVideoKycDeeplink(kycDetailsResponse.kycDetails?.kycItemList) } @@ -670,7 +699,9 @@ class KycFragment : BaseFragment(), FooterInteractionListener, } UPDATE_KYC_DETAILS -> { if (TextUtils.equals(status, SUCCESS)) { - viewModel.fetchKycDetails() + viewModel.setFathersNameSubmitSuccess(true) + hideLoader() + observeFathersNameSubmitSuccess() } } OVD_UPLOAD -> { @@ -994,6 +1025,14 @@ class KycFragment : BaseFragment(), FooterInteractionListener, } ?: onPANDocumentCaptureError() } + private fun enableNextButton(textField: String) { + if (textField.isNotEmpty()) { + binding.footerView.enableNextButton(true) + } else { + binding.footerView.enableNextButton(false) + } + } + override fun onPause() { super.onPause() permissionDeniedFragment?.dismiss() @@ -1009,20 +1048,21 @@ class KycFragment : BaseFragment(), FooterInteractionListener, override fun onFooterNextPress(ctaData: CtaData?, skipValidation: Boolean?) { locationUpdateListener?.updateLocation(PL_KYC_LOCATION) - var moveToAddressPage = true - viewModel.kycDetailsLiveData.value?.kycDetails?.kycItemList?.forEach { kycItem -> - if (kycItem.type == Constants.CURRENT_ADDRESS && viewModel.kycDetailsLiveData.value?.kycDetails?.kycDetailsComplete.orFalse()) { + if (viewModel.isTextFieldPresent() && viewModel.fathersNameSubmitSuccess.value != true) { + val hashMap = HashMap() + hashMap[viewModel.getJsonKey()] = viewModel.textFieldData.value.toString() + viewModel.updateKycDetails(KycRequest(null, hashMap)) + showLoader() + } else { + if (viewModel.isCurrentAddressFieldPresent()) { viewModel.fetchKycStatus() - moveToAddressPage = false - } - } - - if (moveToAddressPage) { - ctaData?.url?.let { - listener?.navigateTo( - it - ) + } else { + ctaData?.url?.let { + listener?.navigateTo( + it + ) + } } } } @@ -1038,7 +1078,8 @@ class KycFragment : BaseFragment(), FooterInteractionListener, const val VIDEO_KYC_REQUEST_CODE = 103 const val AADHAR_OTP_REQUEST_CODE = 104 const val COMPLETED = "COMPLETED" - private const val CORRESPONDENCE = "CORRESPONDENCE" + const val TEXTFIELD = "TEXTFIELD" + const val CURRENT_ADDRESS = "CURRENT_ADDRESS" private const val HYPERVERGE = "HYPERVERGE" private const val PROVIDER_MOCK = "MOCK" private const val VIDEO_KYC_WEB_VIEW_REQUEST_CODE = 11 diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/viewmodels/KycVM.kt b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/viewmodels/KycVM.kt index 238cf67bfe..0a1d5d45ce 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/viewmodels/KycVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/viewmodels/KycVM.kt @@ -21,8 +21,8 @@ import com.naviapp.network.models.GenericErrorResponse import com.naviapp.payment.models.ProviderType import com.naviapp.personalloan.getloan.common.view.KycPanView import com.naviapp.personalloan.getloan.common.view.StatusIndicatorView -import com.naviapp.personalloan.getloan.kyc.adapter.KycItemType import com.naviapp.personalloan.getloan.kyc.adapter.KycItemsAdapter +import com.naviapp.personalloan.getloan.kyc.fragments.KycFragment import com.naviapp.personalloan.getloan.kyc.models.AadhaarDetailsResponse import com.naviapp.personalloan.getloan.kyc.models.AadhaarVerificationData import com.naviapp.personalloan.getloan.kyc.models.KycInReviewResponse @@ -121,6 +121,18 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() val videoKycAsyncResponse: LiveData get() = _videoKycAsyncResponse + private val _textFieldData = MutableLiveData() + val textFieldData: LiveData + get() = _textFieldData + + private val _textFieldSubmitAsyncResponse = MutableLiveData() + val textFieldSubmitAsyncResponse: LiveData + get() = _textFieldSubmitAsyncResponse + + private val _fathersNameSubmitSuccess = MutableLiveData() + val fathersNameSubmitSuccess: LiveData + get() = _fathersNameSubmitSuccess + fun submitSelfie(bytes: ByteArray, requestData: SelfieUploadRequestData? = null) { var requestBody: RequestBody? = null convertObjectToJsonString(requestData)?.let { @@ -160,6 +172,21 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() } } + fun updateKycDetails(kycRequest: KycRequest) { + coroutineScope.launch { + val response = repository.updateKycDetails(kycRequest) + if (response.error == null && response.errors.isNullOrEmpty()) { + _textFieldSubmitAsyncResponse.value = response.data + } else { + setErrorData( + response.errors, + response.error, + ApiErrorTagType.SUBMIT_KYC_API_ERROR + ) + } + } + } + fun checkApiPollStatus(requestId: String, type: String) { coroutineScope.launch { val response = repository.fetchAsyncRequestData(requestId) @@ -343,6 +370,12 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() _panAadharOvdStatus.value = status } + fun setTextFieldData(name: String?) { + name?.let { + _textFieldData.value = name + } + } + fun isKycItemNotCompleted(type: String, kycItemList: List?): Boolean { kycItemList?.forEach { kycItem -> if (kycItem.type == type && kycItem.status != KycItemsAdapter.COMPLETED) { @@ -352,6 +385,41 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() return false } + fun getJsonKey(): String { + if (isTextFieldPresent()) { + _kycDetails.value?.kycDetails?.kycItemList?.forEach { kycItem -> + if (kycItem.type == KycFragment.TEXTFIELD) { + return kycItem.jsonKey.toString() + } + } + } + return Constants.EMPTY + } + + fun isCurrentAddressFieldPresent(): Boolean { + var isCurrentAddressFieldPresent = false + _kycDetails.value?.kycDetails?.kycItemList?.forEach { kycItem -> + if (kycItem.type == KycFragment.CURRENT_ADDRESS) { + isCurrentAddressFieldPresent = true + } + } + return isCurrentAddressFieldPresent + } + + fun isTextFieldPresent(): Boolean { + var isTextFieldPresent = false + _kycDetails.value?.kycDetails?.kycItemList?.forEach { kycItem -> + if (kycItem.type == KycFragment.TEXTFIELD) { + isTextFieldPresent = true + } + } + return isTextFieldPresent + } + + fun setFathersNameSubmitSuccess(fathersNameSubmitSuccess: Boolean) { + _fathersNameSubmitSuccess.value = fathersNameSubmitSuccess + } + companion object { private const val KYC = "kyc" private const val KYC_FILE_NAME = "kyc.jpg" diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/viewmodels/LoanDetailsVM.kt b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/viewmodels/LoanDetailsVM.kt index e3f19796d3..7a52c8b99d 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/viewmodels/LoanDetailsVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/viewmodels/LoanDetailsVM.kt @@ -3,7 +3,9 @@ package com.naviapp.personalloan.getloan.loandetails.viewmodels import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.navi.common.model.CtaData +import com.navi.common.sharedpref.PreferenceManager import com.naviapp.common.viewmodel.BaseVM +import com.naviapp.firebasedb.FirebaseStatusType import com.naviapp.firebasedb.LOAN_APPLY import com.naviapp.firebasedb.OFFER_GENERATE import com.naviapp.firebasedb.PRE_ELIGIBILITY @@ -13,9 +15,9 @@ import com.naviapp.models.request.LoanFeeDetailsRequest import com.naviapp.models.request.LoanRequest import com.naviapp.models.request.MoratoriumRequest import com.naviapp.models.response.* +import com.naviapp.network.ApiErrorTagType.INVALID_PAN_DETAILS import com.naviapp.network.models.GenericErrorResponse import com.naviapp.personalloan.getloan.loandetails.repositories.LoanDetailsRepository -import com.navi.common.sharedpref.PreferenceManager import com.naviapp.utils.LOAN_APPLICATION_ID import com.naviapp.utils.PRODUCT_CODE import com.naviapp.utils.orFalse @@ -113,6 +115,12 @@ class LoanDetailsVM(private val repository: LoanDetailsRepository = LoanDetailsR val loanDetailsResponse: LiveData get() = _loanDetailsResponse + private var panFailedFromCibilRedirectUrl: String? = null + + private val _generateOfferFailed = MutableLiveData() + val generateOfferFailed: LiveData + get() = _generateOfferFailed + fun fetchLoanProducts() { coroutineScope.launch { val response = repository.fetchLoanProduct() @@ -276,10 +284,29 @@ class LoanDetailsVM(private val repository: LoanDetailsRepository = LoanDetailsR fun fetchLoanRejectionData(requestId: String) { coroutineScope.launch { val response = repository.fetchOfferRejectionData(requestId) - if (response.error == null) { + var errorTag: String? = null + response.errors?.forEach { genericError -> + when (genericError.code) { + INVALID_PAN_DETAILS -> { + _generateOfferFailed.value = FirebaseStatusType.FAILURE + panFailedFromCibilRedirectUrl = genericError.actions?.get(0)?.subPage + errorTag = genericError.code + } + } + } + if (response.error == null && errorTag.isNullOrEmpty()) { _generateOfferError.value = response.errors?.firstOrNull() } else { - updateErrorMessage(response.error) + if (errorTag.isNullOrEmpty()) { + updateErrorMessage(response.error) + } else { + setErrorData( + errors = response.errors, + error = response.error, + tag = errorTag, + cancelable = errorTag == null + ) + } } } } @@ -358,4 +385,6 @@ class LoanDetailsVM(private val repository: LoanDetailsRepository = LoanDetailsR } } } + + fun getPanFailedRedirectUrl() = panFailedFromCibilRedirectUrl } diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/summary/fragments/SummaryFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/summary/fragments/SummaryFragment.kt index fbcaacc08c..a58b524cf5 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/summary/fragments/SummaryFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/summary/fragments/SummaryFragment.kt @@ -387,6 +387,7 @@ class SummaryFragment : BaseFragment(), View.OnClickListener, CtaListener, private fun sendOtp() { eventTracker.onSendOtp() + otpSharedViewModel?.resetData() showLoader() viewModel.sendOtp( SendOtpForDisbursementRequest( @@ -426,4 +427,9 @@ class SummaryFragment : BaseFragment(), View.OnClickListener, CtaListener, } } } + + override fun onDestroy() { + super.onDestroy() + otpSharedViewModel?.resetData() + } } diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/activities/LoanEligibilityLoaderActivity.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/activities/LoanEligibilityLoaderActivity.kt index f4b92b462f..bc954be0dc 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/activities/LoanEligibilityLoaderActivity.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/activities/LoanEligibilityLoaderActivity.kt @@ -6,6 +6,8 @@ import android.text.TextUtils import android.view.View import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProvider +import com.navi.common.model.CtaData +import com.navi.common.sharedpref.PreferenceManager import com.naviapp.R import com.naviapp.analytics.neoeyed.viewmodel.NeoEyedVM import com.naviapp.analytics.utils.NaviAnalytics @@ -25,11 +27,11 @@ import com.naviapp.firebasedb.FirebaseStatusType.FAILURE import com.naviapp.firebasedb.FirebaseStatusType.SUCCESS import com.naviapp.manager.viewmodel.UserDataViewModel import com.naviapp.models.RedirectPageStatus +import com.naviapp.network.ApiErrorTagType import com.naviapp.permission.viewmodel.PermissionViewModel import com.naviapp.personalloan.getloan.activities.GetLoanActivity import com.naviapp.personalloan.getloan.loandetails.viewmodels.LoanDetailsVM import com.naviapp.personalloan.intermediate.activity.IntermediateActivity.Companion.KEY_NEEDS_RESULT -import com.navi.common.sharedpref.PreferenceManager import com.naviapp.utils.* class LoanEligibilityLoaderActivity : BaseActivity(), @@ -56,7 +58,7 @@ class LoanEligibilityLoaderActivity : BaseActivity(), super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.loan_eligibility_loader_activity) super.setContentView(binding.root) - initError(loanDetailsVM) + initError() binding.loader.setProgressCompletedListener(this) sendUserData() sendNeoEyedData() @@ -65,6 +67,17 @@ class LoanEligibilityLoaderActivity : BaseActivity(), initAnimation() } + private fun initError() { + initError( + viewModel = loanDetailsVM, + actions = listOf( + Pair( + handlePanDetailsFailedFromCibil, ApiErrorTagType.INVALID_PAN_DETAILS + ) + ) + ) + } + private fun sendUserData() { userDataViewModel.sendUserData() } @@ -121,6 +134,10 @@ class LoanEligibilityLoaderActivity : BaseActivity(), loanDetailsVM.statusGenerateOffer.observeNullable(this) { it?.let { fetchOfferIdAndStopApiPoll(it) } } + loanDetailsVM.generateOfferFailed.observeNonNull(this) { + binding.loader.pause() + statusHandling(it) + } loanDetailsVM.offerIdResponse.observeNonNull(this) { offerIdResponse -> if (offerIdResponse.details?.inReview.orFalse()) { @@ -409,6 +426,16 @@ class LoanEligibilityLoaderActivity : BaseActivity(), } } + private val handlePanDetailsFailedFromCibil: View.OnClickListener = View.OnClickListener { + loanDetailsVM.getPanFailedRedirectUrl()?.let { url -> + NaviDeepLinkNavigator.navigate( + activity = this, + ctaData = CtaData(url = url), + finish = true + ) + } + } + override val screenName: String get() = LOAN_ELIGIBILITIY_LOADER diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/employmentverification/fragment/EmploymentVerificationFragment.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/employmentverification/fragment/EmploymentVerificationFragment.kt index fdb91040ab..075bb1d417 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/employmentverification/fragment/EmploymentVerificationFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/employmentverification/fragment/EmploymentVerificationFragment.kt @@ -9,6 +9,7 @@ import android.widget.Toast import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider +import com.navi.common.model.CtaData import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.adapter.IconTextAdapter @@ -18,19 +19,14 @@ import com.naviapp.common.decorator.TopMarginItemDecoration import com.naviapp.common.fragment.BaseFragment import com.naviapp.common.fragment.OtpBottomSheet import com.naviapp.common.fragment.SearchFragment -import com.naviapp.common.fragment.TimeoutBottomSheet -import com.naviapp.common.fragment.TimeoutBottomSheet.Companion.SCREEN_TIMEOUT_SEC import com.naviapp.common.viewmodel.OtpSharedViewModel import com.naviapp.common.viewmodel.SearchViewModel import com.naviapp.dashboard.listeners.FragmentInterchangeListener import com.naviapp.databinding.EmploymentVerificationFragmentBinding -import com.naviapp.errors.utils.getApiTimeoutData import com.naviapp.homeloan.common.listener.FooterInteractionListener import com.naviapp.homeloan.common.listener.HeaderInteractionListener -import com.navi.common.model.CtaData import com.naviapp.models.response.EPFODetails import com.naviapp.models.response.SendDisbursementOtpResponse -import com.naviapp.network.ApiConstants.API_CONNECT_TIMEOUT_VALUE_120 import com.naviapp.network.ApiErrorTagType import com.naviapp.personalloan.useridentification.employmentverification.viewmodel.EmploymentVerificationVM import com.naviapp.utils.* @@ -188,25 +184,6 @@ class EmploymentVerificationFragment : BaseFragment(), View.OnClickListener, ) } } - otpSharedViewModel?.apiTimeout?.observeNonNull(this) { - it?.let { - hideLoader() - if (it) { - viewModel.setWarning(getApiTimeoutData(), ApiErrorTagType.EPFO) - } else { - naviAnalyticsEventTracker.onLoaderShown() - val bundle = Bundle() - bundle.putLong( - SCREEN_TIMEOUT_SEC, - viewModel.employmentVerificationResponse.value?.content?.otpVerificationTimeoutInSec.orValue( - API_CONNECT_TIMEOUT_VALUE_120 - ) - ) - val bottomSheet = TimeoutBottomSheet.newInstance(bundle) - safelyShowBottomSheet(bottomSheet, TimeoutBottomSheet.TAG) - } - } - } } private fun handleDisbursementOtpResponse(sendDisbursementOtpResponse: SendDisbursementOtpResponse?) { diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/pan/fragments/PanFragment.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/pan/fragments/PanFragment.kt index 80d1d80700..cb452d51f3 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/pan/fragments/PanFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/pan/fragments/PanFragment.kt @@ -14,6 +14,8 @@ import androidx.core.view.isVisible import androidx.core.widget.addTextChangedListener import androidx.lifecycle.ViewModelProvider import com.navi.analytics.uxcam.UxcamUtil +import com.navi.common.model.CtaData +import com.navi.common.sharedpref.PreferenceManager import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.ApiPollScheduler @@ -27,12 +29,10 @@ import com.naviapp.firebasedb.* import com.naviapp.homeloan.common.listener.CheckBoxClickListener import com.naviapp.homeloan.common.listener.FooterInteractionListener import com.naviapp.homeloan.common.listener.HeaderInteractionListener -import com.navi.common.model.CtaData import com.naviapp.models.UserDetail import com.naviapp.network.ApiErrorTagType import com.naviapp.personalloan.useridentification.pan.viewmodels.PanVM import com.naviapp.personalloan.useridentification.viewmodels.UserIdentificationVM -import com.navi.common.sharedpref.PreferenceManager import com.naviapp.utils.* import com.naviapp.utils.Constants.CURRENT_USER import com.naviapp.utils.Constants.PL_MAX_AGE @@ -89,29 +89,34 @@ class PanFragment : BaseFragment(), FooterInteractionListener, DobEditText.DOBLi } private fun initObservers() { - viewModel.panDataResponse.observeNonNull(this) { data -> + viewModel.panDataResponse.observeNullable(this) { hideLoader() - if (data.content?.isPinCodeEnabled.orTrue().not()) { - binding.pincodeLayout.root.visibility = View.GONE - } - data.content?.panNumber?.let { populateData(data.content) } - data.footer?.nextCta?.let { ctaData -> - binding.footerView.visibility = View.VISIBLE - binding.footerView.setProperties( - data.footer.backCta, - ctaData, - this, - nextButtonIconId = null + it?.let { data -> + if (data.content?.isPinCodeEnabled.orTrue().not()) { + binding.pincodeLayout.root.visibility = View.GONE + } + if(data.content?.dateOfBirth.isNullOrBlank().not()){ + binding.dobLayout.dobEt.setText(data.content?.dateOfBirth.orEmpty()) + } + data.content?.panNumber?.let { populateData(data.content) } + data.footer?.nextCta?.let { ctaData -> + binding.footerView.visibility = View.VISIBLE + binding.footerView.setProperties( + data.footer.backCta, + ctaData, + this, + nextButtonIconId = null + ) + } + if (data.header?.progress == null) { + headerInteractionListener?.hideHeaderProgress() + } + headerInteractionListener?.setProperties( + data.header?.title, + data.header?.subtitle, + data.header?.progress ) } - if (data.header?.progress == null) { - headerInteractionListener?.hideHeaderProgress() - } - headerInteractionListener?.setProperties( - data.header?.title, - data.header?.subtitle, - data.header?.progress - ) } viewModel.uiStatusData.observeNonNull(this) { hideLoader() diff --git a/app/src/main/java/com/naviapp/utils/BindingAdapterUtil.kt b/app/src/main/java/com/naviapp/utils/BindingAdapterUtil.kt index 795cfe6a58..6a8720d56f 100644 --- a/app/src/main/java/com/naviapp/utils/BindingAdapterUtil.kt +++ b/app/src/main/java/com/naviapp/utils/BindingAdapterUtil.kt @@ -9,7 +9,10 @@ import android.graphics.drawable.Drawable import android.view.View import android.widget.AdapterView import android.widget.ImageView +import android.widget.RadioButton import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.core.widget.TextViewCompat import androidx.databinding.BindingAdapter import androidx.recyclerview.widget.RecyclerView import com.navi.common.model.CtaData @@ -283,7 +286,7 @@ object BindingAdapterUtil { ) { greetingCardData?.let { greetingCardView.visibility = View.VISIBLE - greetingCardView.setProperties(it.title, it.iconCode, CtaData(url = "HOME")) + greetingCardView.setProperties(it.title, it.iconCode) } ?: run { greetingCardView.visibility = View.GONE } } @@ -464,6 +467,42 @@ object BindingAdapterUtil { horizontalLabelRecyclerView.setProperties(labelViewResponseList) } + @BindingAdapter("setRadioDataList") + @JvmStatic + fun setRadioDataList( + radioRecyclerView: RadioRecyclerView, + radioButtonList: List? + ) { + if (radioButtonList.isNullOrEmpty()) return + radioRecyclerView.setProperties( + radioButtonList, + gap = radioRecyclerView.resources.getDimension(R.dimen.layout_dp_20) + ) + } + + @BindingAdapter("setStyleToTextView") + @JvmStatic + fun setStyleToTextView( + textView: TextView, + styleId: Int? + ) { + styleId?.let { + TextViewCompat.setTextAppearance(textView, it) + } + } + + @BindingAdapter("setColorStateListToRadioText") + @JvmStatic + fun setColorStateListToRadioText( + radioButton: RadioButton, + colorStateList: Int? + ) { + colorStateList?.let { + radioButton.setTextColor(ContextCompat.getColorStateList(radioButton.context, it)) + } + } + + @BindingAdapter("setActionButtonViewBackGround") @JvmStatic fun setActionButtonViewBackGround( diff --git a/app/src/main/java/com/naviapp/utils/Constants.kt b/app/src/main/java/com/naviapp/utils/Constants.kt index 2842fef77b..6d34a7b567 100644 --- a/app/src/main/java/com/naviapp/utils/Constants.kt +++ b/app/src/main/java/com/naviapp/utils/Constants.kt @@ -132,4 +132,5 @@ object Constants { const val LEGAL_DOC_TYPE_TNC = "tnc" const val LEGAL_DOC_TYPE_PRIVACY_POLICY = "privacy-policy" const val CURRENT_ADDRESS ="CURRENT_ADDRESS" + const val MANDATE_TYPE = "MANDATE_TYPE" } \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/utils/Ext.kt b/app/src/main/java/com/naviapp/utils/Ext.kt index c116200f6b..0f00a03e54 100644 --- a/app/src/main/java/com/naviapp/utils/Ext.kt +++ b/app/src/main/java/com/naviapp/utils/Ext.kt @@ -28,7 +28,6 @@ import com.naviapp.app.NaviApplication import com.naviapp.common.customview.CustomTypefaceSpan import com.naviapp.models.Money import com.naviapp.models.response.StyledTextWithIconCode -import com.naviapp.network.retrofit.LongRunningRetrofitProvider import com.naviapp.network.retrofit.RetrofitProvider import com.naviapp.network.retrofit.RetrofitService import com.naviapp.superapp.NaviSuperAppRetrofitProvider @@ -76,11 +75,6 @@ fun superAppRetrofitService(): RetrofitService { return NaviSuperAppRetrofitProvider.instance.services } -//TOTO we will remove this service in next release and make EPFO otp verify api async call -fun longRunningRetrofitService(): RetrofitService { - return LongRunningRetrofitProvider.instance.services -} - fun Boolean?.orFalse() = this ?: false fun Boolean?.orTrue() = this ?: true diff --git a/app/src/main/java/com/naviapp/utils/IconUtils.kt b/app/src/main/java/com/naviapp/utils/IconUtils.kt index abba6e68b5..e9a25a3c2e 100644 --- a/app/src/main/java/com/naviapp/utils/IconUtils.kt +++ b/app/src/main/java/com/naviapp/utils/IconUtils.kt @@ -60,6 +60,8 @@ object IconUtils { private const val INVESTMENT_ICON = "INVESTMENT_ICON" private const val KYC_IN_PROGRESS_ICON = "KYC_IN_PROGRESS_ICON" private const val VERIFICATION_ERROR_ICON = "VERIFICATION_ERROR_ICON" + private const val LIGHTNING_RECOMMENDED = "LIGHTNING_RECOMMENDED" + private const val LIGHTNING = "LIGHTNING" private const val ICON_AMC_CARD = "ICON_AMC_CARD" private const val EMAIL_GI_ICON = "EMAIL_GI_ICON" private const val GI_HEART_SHIELD_ICON = "GI_HEART_SHIELD_ICON" @@ -188,6 +190,8 @@ object IconUtils { INVESTMENT_ICON -> R.drawable.ic_investment KYC_IN_PROGRESS_ICON -> R.drawable.ic_kyc_in_progress VERIFICATION_ERROR_ICON -> R.drawable.ic_verification_fail + LIGHTNING_RECOMMENDED -> R.drawable.ic_recommended_lightning + LIGHTNING -> R.drawable.ic_lightning ICON_AMC_CARD -> R.drawable.ic_amc_home COIN_HOME_LOAN -> R.drawable.ic_coin_home_loan GI_HEART_SHIELD_ICON -> R.drawable.ic_heart_shield_gi diff --git a/app/src/main/res/drawable/ic_bank_verified.xml b/app/src/main/res/drawable/ic_bank_verified.xml new file mode 100644 index 0000000000..71057a6445 --- /dev/null +++ b/app/src/main/res/drawable/ic_bank_verified.xml @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_green_tick_circle_16.xml b/app/src/main/res/drawable/ic_green_tick_circle_16.xml new file mode 100644 index 0000000000..418d28b15c --- /dev/null +++ b/app/src/main/res/drawable/ic_green_tick_circle_16.xml @@ -0,0 +1,15 @@ + + + + diff --git a/app/src/main/res/drawable/ic_lightning.xml b/app/src/main/res/drawable/ic_lightning.xml new file mode 100644 index 0000000000..8bdff70538 --- /dev/null +++ b/app/src/main/res/drawable/ic_lightning.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_pan_error.xml b/app/src/main/res/drawable/ic_pan_error.xml new file mode 100644 index 0000000000..eb0aec46d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_pan_error.xml @@ -0,0 +1,20 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_recommended_lightning.xml b/app/src/main/res/drawable/ic_recommended_lightning.xml new file mode 100644 index 0000000000..c2731607fa --- /dev/null +++ b/app/src/main/res/drawable/ic_recommended_lightning.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/radio_custom_view_selector.xml b/app/src/main/res/drawable/radio_custom_view_selector.xml new file mode 100644 index 0000000000..38b41d8174 --- /dev/null +++ b/app/src/main/res/drawable/radio_custom_view_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/radio_icon_tint_selector.xml b/app/src/main/res/drawable/radio_icon_tint_selector.xml new file mode 100644 index 0000000000..72d9d6f995 --- /dev/null +++ b/app/src/main/res/drawable/radio_icon_tint_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bank_details_auto_debit_fragment.xml b/app/src/main/res/layout/bank_details_auto_debit_fragment.xml index a9c336ee81..636a093ed5 100644 --- a/app/src/main/res/layout/bank_details_auto_debit_fragment.xml +++ b/app/src/main/res/layout/bank_details_auto_debit_fragment.xml @@ -1,145 +1,160 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> - + + + + + + + + + + + + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_above="@+id/footer_view" + android:paddingStart="@dimen/layout_dp_20" + android:paddingTop="@dimen/layout_dp_28" + android:paddingEnd="@dimen/layout_dp_20" + android:paddingBottom="@dimen/layout_dp_20" + app:layout_constraintBottom_toTopOf="@id/footer_view" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:layout_height="wrap_content"> - - - + app:layout_constraintTop_toTopOf="parent"> - + - + - + - + - - - + + app:layout_constraintTop_toBottomOf="@id/auto_pay_view" /> - + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/bank_verified_iv" + app:setNoteText="@{@string/same_bank_account_will_be_used_to_get_loan_to_setup_auto_debit}" /> - + app:layout_constraintStart_toStartOf="parent" + app:setFooterData="@{viewModel.getAutoPayFooterData()}" + app:setFooterInteractionListener="@{footerInteractionListener}" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/enach_tutorial_activity.xml b/app/src/main/res/layout/enach_tutorial_activity.xml index a7f6589a45..b52efbbc4b 100644 --- a/app/src/main/res/layout/enach_tutorial_activity.xml +++ b/app/src/main/res/layout/enach_tutorial_activity.xml @@ -2,50 +2,47 @@ - + android:background="@color/view_background_color_six" + android:orientation="vertical" + android:paddingBottom="10dp"> - - - - - + android:background="@color/view_background_color_six" + app:liftOnScroll="true"> - + - + + + + + - + android:layout_height="match_parent" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> + + diff --git a/app/src/main/res/layout/fragment_enach.xml b/app/src/main/res/layout/fragment_enach.xml new file mode 100644 index 0000000000..0679370216 --- /dev/null +++ b/app/src/main/res/layout/fragment_enach.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_dashboard_gi_active.xml b/app/src/main/res/layout/item_dashboard_gi_active.xml index 6a1c4d43ae..03c98d9f2f 100644 --- a/app/src/main/res/layout/item_dashboard_gi_active.xml +++ b/app/src/main/res/layout/item_dashboard_gi_active.xml @@ -280,9 +280,8 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/container_margin" android:layout_marginTop="@dimen/layout_dp_16" - android:layout_marginBottom="@dimen/layout_dp_16" + android:paddingBottom="@dimen/layout_dp_16" android:textColor="@color/title_color_two" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/autoPayDescription" tools:text="Start Now" /> diff --git a/app/src/main/res/layout/item_text_field_view.xml b/app/src/main/res/layout/item_text_field_view.xml new file mode 100644 index 0000000000..7c2ac2ec36 --- /dev/null +++ b/app/src/main/res/layout/item_text_field_view.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/section_heading_layout.xml b/app/src/main/res/layout/section_heading_layout.xml index f0eefe6e96..c872df8aef 100644 --- a/app/src/main/res/layout/section_heading_layout.xml +++ b/app/src/main/res/layout/section_heading_layout.xml @@ -10,9 +10,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_auto_pay_pending_aadhar.xml b/app/src/main/res/layout/view_auto_pay_pending_aadhar.xml new file mode 100644 index 0000000000..dd708c37fd --- /dev/null +++ b/app/src/main/res/layout/view_auto_pay_pending_aadhar.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_auto_pay_success.xml b/app/src/main/res/layout/view_auto_pay_success.xml new file mode 100644 index 0000000000..c489bacffa --- /dev/null +++ b/app/src/main/res/layout/view_auto_pay_success.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_radio_icon_custom.xml b/app/src/main/res/layout/view_radio_icon_custom.xml new file mode 100644 index 0000000000..a2f193776e --- /dev/null +++ b/app/src/main/res/layout/view_radio_icon_custom.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_select_mandate.xml b/app/src/main/res/layout/view_select_mandate.xml new file mode 100644 index 0000000000..0c88725edb --- /dev/null +++ b/app/src/main/res/layout/view_select_mandate.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/raw/mock.json b/app/src/main/res/raw/mock.json index 1049e998af..7207268dc3 100644 --- a/app/src/main/res/raw/mock.json +++ b/app/src/main/res/raw/mock.json @@ -3332,6 +3332,12 @@ "uri": "https://s3.ap-south-1.amazonaws.com/navi-d5a6c37adb7e06d06401aba47fe07bf3/prod/b6879988-0022-4dd7-94e4-6d80ee735c7f?X-Amz-Security-Token\u003dFwoGZXIvYXdzEBcaDEbeLF6v9%2BBCTd9v9SLKAXnruh6Vz4ubOX%2BQ6BRz6ytEoW6lcFj%2BRsEiMIo1H74UnHxlbJ8Mq0nFAud9djqEK4qy07vZBWnhRfMJZpYWyRBgeVNmfBW6pg7AQKATZXLxi2P9wzWNa67G4uLKBsjPurVrkegpLfy0SdWWaRSPQXFaWf50i6wgvAei18leryu5pkssjb%2FDFMV6mDgzdHzz3c%2BCMi%2Bzzf60QPPJ72S1rMFqhMIVkt2rz8620s2hQfLJjSxBXeswACm0zGJtdWcHrEX1In675oD6UhAotZ%2BXiQYyLShluwKRXHpvGKeqoRieOI5zPBZMM3RjaLeAIW%2BU9b0CRzwoweilmnwyXoySaA%3D%3D\u0026X-Amz-Algorithm\u003dAWS4-HMAC-SHA256\u0026X-Amz-Date\u003d20210825T054733Z\u0026X-Amz-SignedHeaders\u003dhost\u0026X-Amz-Expires\u003d36000\u0026X-Amz-Credential\u003dASIAYKBIIH2NLZHHQ7WK%2F20210825%2Fap-south-1%2Fs3%2Faws4_request\u0026X-Amz-Signature\u003d9254a117ec5ff3e020c9ac1d6c9b052f769c54a05bddd0de5b5520109f525a1c", "showOtpOption": false, "isEditable": false + }, + { + "type" : "TEXTFIELD", + "subtitle" : "Type here", + "title" : "Father's Name", + "jsonKey" : "fatherName" } ], "kycDetailsComplete": true @@ -3738,4 +3744,4 @@ } } } -} \ No newline at end of file +} diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 3c08ac64c7..f0a24456fc 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -95,7 +95,6 @@ 22dp 2dp 36dp - 54dp 56dp 62dp 72dp @@ -181,6 +180,7 @@ 160dp 86dp 5dp + 54dp 2dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4dd2f24067..ac74420b5e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -306,12 +306,13 @@ No Transactions! Transactions related to EMI(s)\nwill show here Please select your primary email - EMI of %1$s will be auto-debited starting %2$s + EMI of %1$s will be auto-paid starting %2$s Auto-debit setup failed. Please retry. Pending Your auto-debit setup is pending confirmation. It may take upto 10 mins. Please wait... Auto-debit setup done + Auto-pay setup done Select valid Bank Kindly reach out to us for any questions\nregarding your loan or the app We will get back to you within 24 hours @@ -430,7 +431,7 @@ Voter ID Capture PAN Capture ID Capture - Same bank account will be used to get loan & to setup auto-debit of EMIs + Same bank account will be used to get loan & to setup auto-pay of EMIs Change Bank? Leave a feedback…(optional) It seems you are leaving! @@ -461,7 +462,7 @@ WhatsApp notifications enabled WhatsApp notifications disabled You are disabling whatsapp notifications. - I accept the loan agreement terms + I accept the loan agreement terms & by proceeding I declare that I am not a politically exposed person Hey, Camera permission is required for selfie Camera permission is required for Aadhaar photo @@ -593,7 +594,7 @@ View Details Policy Terms Insurance - I accept the loan agreement and insurance terms + I accept the loan agreement and insurance terms & by proceeding I declare that I am not a politically exposed person Insurance Premium Chat (Mon-Sat, 10am-6pm) Address Line 1 @@ -672,7 +673,7 @@ PAN Card Photo Please retry the submission PAN Upload Failed - AMIPI2731G + Enter your 10-digit PAN PAN card verification failed. Please retry the submission Select City Select Company @@ -763,4 +764,8 @@ Do you want to change the slot? You can only do this once Change Slot + Your auto-pay setup with Aadhar OTP is signed + Setup auto-pay for EMIs + Your auto-pay setup is pending confirmation. It may take up to 10 mins. + Setup Auto-pay diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 7790d1ec50..5f66ad18d3 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -622,6 +622,11 @@ @color/title_color_one +