diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index bc0e6a19d5..12b7870520 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,6 +1,6 @@ - + + - ## Description of what I changed @@ -9,26 +9,19 @@ ## Issue I worked on - JIRA Issue: https://navihq.atlassian.net/browse/AE-#### ## Type of change I made - - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected, explain why) - [ ] Refactoring / Maintenance (non-breaking change to keep the project healthy) -## QA Requirement for my changes - -- [ ] QA is required for this change (QA Owner: @github-username) -- [ ] QA is not required for this change - ## Checklist: I completed these to help reviewers :) - -- [ ] I am able to build the project locally with my changes -- [ ] My changes generate no new warnings +- [ ] I am able to build the project locally & build check passes - [ ] My code follows the style guidelines of this project & spotless check passes +- [ ] My changes generate no new warnings - [ ] I have performed a self-review of my own code -- [ ] I have made corresponding changes to the documentation - [ ] I understand that **'Squash and merge'** is the preferred merge + + \ No newline at end of file diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index b85e089a44..d543fdc674 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -6,22 +6,24 @@ on: pull_request: branches: [ master, release-*, development ] +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: build: - - runs-on: [ self-hosted ] - + runs-on: [ self-hosted, android ] steps: - - name: Checkout - uses: actions/checkout@v2 - - name: set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: '11' - distribution: 'adopt' - - name: Setup Android SDK - uses: android-actions/setup-android@v2 - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - name: Build Debug with gradle - run: ./gradlew assembleDevDebug --stacktrace + - name: Checkout + uses: actions/checkout@v2 + - name: set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + - name: Setup Android SDK + uses: android-actions/setup-android@v2 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build Debug with gradle + run: ./gradlew assembleDevDebug --stacktrace diff --git a/.github/workflows/android_suggestion.yml b/.github/workflows/android_checkstyle.yml similarity index 75% rename from .github/workflows/android_suggestion.yml rename to .github/workflows/android_checkstyle.yml index 537e481c1b..bc500fbe14 100644 --- a/.github/workflows/android_suggestion.yml +++ b/.github/workflows/android_checkstyle.yml @@ -1,14 +1,16 @@ -name: Android Suggestion CI +name: Android Checkstyle CI on: pull_request: branches: [ development ] +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: spotless: - - runs-on: [ self-hosted ] - + runs-on: [ self-hosted, default ] steps: - name: Checkout uses: actions/checkout@v2 diff --git a/.github/workflows/android_test.yml b/.github/workflows/android_test.yml index 34ec36d204..cdab1ea517 100644 --- a/.github/workflows/android_test.yml +++ b/.github/workflows/android_test.yml @@ -6,22 +6,24 @@ on: pull_request: branches: [ development, master ] +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: - build: - - runs-on: [ self-hosted ] - + test: + runs-on: [ self-hosted, default ] steps: - - name: Checkout - uses: actions/checkout@v2 - - name: set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: '11' - distribution: 'adopt' - - name: Setup Android SDK - uses: android-actions/setup-android@v2 - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - name: Unit Test - run: ./gradlew testDebugUnitTest + - name: Checkout + uses: actions/checkout@v2 + - name: set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + - name: Setup Android SDK + uses: android-actions/setup-android@v2 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Unit Test + run: ./gradlew testDebugUnitTest diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..31bc4a8953 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,20 @@ +name: Mark & Close stale PRs + +on: + workflow_dispatch: + schedule: + - cron: "30 4 * * MON" + +jobs: + stale: + runs-on: [ self-hosted, default ] + steps: + - uses: actions/stale@v5 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + days-before-pr-stale: 70 + stale-pr-label: 'STALE' + stale-pr-message: "This PR hasn't seen activity in last 10 weeks! Should it be merged, closed, or worked on further? If you want to keep it open, post a comment or remove the `STALE` label – otherwise this will be closed in 2 weeks." + days-before-pr-close: 14 + close-pr-label: 'CLOSED BY STALE' + close-pr-message: 'This PR was closed due to 3 months of inactivity. Feel free to reopen it if still relevant.' diff --git a/Dockerfile b/Dockerfile index 60c7583dc5..506d377b8c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,8 @@ ARG XIAOMI_PUSH_APP_KEY ARG YOUTUBE_KEY ENV WORK_DIR="/android/navi" \ - ANDROID_APK_DIR="app/build/outputs/apk" + ANDROID_APK_DIR="app/build/outputs/apk" \ + CI=true COPY . $WORK_DIR WORKDIR $WORK_DIR diff --git a/app/build.gradle b/app/build.gradle index 588ec51dbf..ce1c983e32 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,7 +23,7 @@ kapt { correctErrorTypes true } -def VERSION_NAME = "3.0.5" +def VERSION_NAME = "3.0.6" android { compileSdkVersion 32 @@ -46,7 +46,7 @@ android { applicationId "com.naviapp" minSdkVersion 21 targetSdk 31 - versionCode 276 + versionCode 277 versionName VERSION_NAME multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/androidTestDev/java/com/naviapp/newPersonalLoan/NewLoanNegativeTest.kt b/app/src/androidTestDev/java/com/naviapp/newPersonalLoan/NewLoanNegativeTest.kt index b410aa15fc..40187b12e5 100644 --- a/app/src/androidTestDev/java/com/naviapp/newPersonalLoan/NewLoanNegativeTest.kt +++ b/app/src/androidTestDev/java/com/naviapp/newPersonalLoan/NewLoanNegativeTest.kt @@ -1,36 +1,36 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ -//package com.naviapp.newPersonalLoan +package com.naviapp.newPersonalLoan + +// import androidx.test.ext.junit.rules.ActivityScenarioRule +// 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.LoanDetailsController +// import com.naviapp.controllers.registration.RegistrationController +// import com.naviapp.controllers.tutorial.TutorialController +// import com.naviapp.controllers.useridentification.PanController +// import com.naviapp.controllers.useridentification.ProfileController +// import com.naviapp.controllers.useridentification.WorkController +// import com.naviapp.entities.BankDetails +// import com.naviapp.entities.EmiCalendar +// import com.naviapp.entities.NewLoanDetails +// import com.naviapp.filehandler.JsonParser +// import com.naviapp.registration.SplashActivity +// import com.naviapp.utilities.DateUtils +// import com.naviapp.utilities.RandomGenerator +// import org.joda.time.LocalDate +// import org.junit.Rule +// import org.junit.Test // -//import androidx.test.ext.junit.rules.ActivityScenarioRule -//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.LoanDetailsController -//import com.naviapp.controllers.registration.RegistrationController -//import com.naviapp.controllers.tutorial.TutorialController -//import com.naviapp.controllers.useridentification.PanController -//import com.naviapp.controllers.useridentification.ProfileController -//import com.naviapp.controllers.useridentification.WorkController -//import com.naviapp.entities.BankDetails -//import com.naviapp.entities.EmiCalendar -//import com.naviapp.entities.NewLoanDetails -//import com.naviapp.filehandler.JsonParser -//import com.naviapp.registration.SplashActivity -//import com.naviapp.utilities.DateUtils -//import com.naviapp.utilities.RandomGenerator -//import org.joda.time.LocalDate -//import org.junit.Rule -//import org.junit.Test -// -//class NewLoanNegativeTest : TestBase() { +// class NewLoanNegativeTest : TestBase() { // // @Rule // @JvmField @@ -92,22 +92,27 @@ // .setLoanAmount(loanDetails.loanAmount) // .setMinEmiAmount() // -// val loanDetailsDisplayed = Controller.on().getLoanAmountDetails() +// val loanDetailsDisplayed = +// Controller.on().getLoanAmountDetails() // val emiAmount = "₹ ${loanDetailsDisplayed.emiAmount}" // val tenure = loanDetailsDisplayed.tenure.replace("months", "", true).trim().toInt() // val annualRateOfInterest = loanDetailsDisplayed.annualInterest // // check(loanDetailsDisplayed.loanAmount == loanDetails.loanAmount) -// { "Expected Loan Amount displayed to be: ${loanDetails.loanAmount}:\nBut was:${loanDetailsDisplayed.loanAmount}" } +// { "Expected Loan Amount displayed to be: ${loanDetails.loanAmount}:\nBut +// was:${loanDetailsDisplayed.loanAmount}" } // // check(loanDetailsDisplayed.gst == loanDetails.gst) -// { "Expected Gst displayed to be: ${loanDetails.gst}:\nBut was:${loanDetailsDisplayed.gst}" } +// { "Expected Gst displayed to be: ${loanDetails.gst}:\nBut +// was:${loanDetailsDisplayed.gst}" } // // check(loanDetailsDisplayed.processingFee == loanDetails.processingFee) -// { "Expected Processing Fee displayed to be: ${loanDetails.processingFee}:\nBut was:${loanDetailsDisplayed.processingFee}" } +// { "Expected Processing Fee displayed to be: ${loanDetails.processingFee}:\nBut +// was:${loanDetailsDisplayed.processingFee}" } // // check(loanDetailsDisplayed.netLoanAmount == loanDetails.netLoanAmount) -// { "Expected netLoanAmount displayed to be: ${loanDetails.netLoanAmount}:\nBut was:${loanDetailsDisplayed.netLoanAmount}" } +// { "Expected netLoanAmount displayed to be: ${loanDetails.netLoanAmount}:\nBut +// was:${loanDetailsDisplayed.netLoanAmount}" } // // Controller.on() // .editEMI() @@ -259,4 +264,4 @@ // } // } // -//} \ No newline at end of file +// } diff --git a/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/A2DLoanDetailsPageTests.kt b/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/A2DLoanDetailsPageTests.kt deleted file mode 100644 index 526ad2f2e8..0000000000 --- a/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/A2DLoanDetailsPageTests.kt +++ /dev/null @@ -1,7 +0,0 @@ -/* - * - * * Copyright © 2019 by Navi Technologies Private Limited - * * All rights reserved. Strictly confidential - * - */ - diff --git a/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/HomeScreenTests.kt b/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/HomeScreenTests.kt index 2722131554..e4369cafeb 100644 --- a/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/HomeScreenTests.kt +++ b/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/HomeScreenTests.kt @@ -1,35 +1,35 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ -//package com.naviapp.personalLoanDetailScreens -// -//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.LoanDetailsController -//import com.naviapp.controllers.registration.RegistrationController -//import com.naviapp.controllers.tutorial.TutorialController -//import com.naviapp.controllers.useridentification.PanController -//import com.naviapp.controllers.useridentification.ProfileController -//import com.naviapp.controllers.useridentification.WorkController -//import com.naviapp.entities.BankDetails -//import com.naviapp.entities.NewLoanDetails -//import com.naviapp.filehandler.JsonParser -//import com.naviapp.registration.SplashActivity -//import com.naviapp.utilities.RandomGenerator -//import org.junit.Rule -//import org.junit.Test +package com.naviapp.personalLoanDetailScreens + +// 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.LoanDetailsController +// import com.naviapp.controllers.registration.RegistrationController +// import com.naviapp.controllers.tutorial.TutorialController +// import com.naviapp.controllers.useridentification.PanController +// import com.naviapp.controllers.useridentification.ProfileController +// import com.naviapp.controllers.useridentification.WorkController +// import com.naviapp.entities.BankDetails +// import com.naviapp.entities.NewLoanDetails +// import com.naviapp.filehandler.JsonParser +// import com.naviapp.registration.SplashActivity +// import com.naviapp.utilities.RandomGenerator +// import org.junit.Rule +// import org.junit.Test // // -//class HomeScreenTests : TestBase() { +// class HomeScreenTests : TestBase() { // // @Rule // @JvmField @@ -85,4 +85,4 @@ // .replace("-", "") // .trim().toInt() // } -//} \ No newline at end of file +// } diff --git a/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/MenuScreenTests.kt b/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/MenuScreenTests.kt index ea9093ac6e..0845c8565d 100644 --- a/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/MenuScreenTests.kt +++ b/app/src/androidTestDev/java/com/naviapp/personalLoanDetailScreens/MenuScreenTests.kt @@ -1,37 +1,37 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ -//package com.naviapp.personalLoanDetailScreens -// -//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.LoanDetailsController -//import com.naviapp.controllers.loanApplication.MenuDetailsController -//import com.naviapp.controllers.registration.RegistrationController -//import com.naviapp.controllers.tutorial.TutorialController -//import com.naviapp.controllers.useridentification.PanController -//import com.naviapp.controllers.useridentification.ProfileController -//import com.naviapp.controllers.useridentification.WorkController -//import com.naviapp.entities.BankDetails -//import com.naviapp.entities.NewLoanDetails -//import com.naviapp.filehandler.JsonParser -//import com.naviapp.registration.SplashActivity -//import com.naviapp.utilities.RandomGenerator -//import org.junit.Before -//import org.junit.Rule -//import org.junit.Test +package com.naviapp.personalLoanDetailScreens + +// 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.LoanDetailsController +// import com.naviapp.controllers.loanApplication.MenuDetailsController +// import com.naviapp.controllers.registration.RegistrationController +// import com.naviapp.controllers.tutorial.TutorialController +// import com.naviapp.controllers.useridentification.PanController +// import com.naviapp.controllers.useridentification.ProfileController +// import com.naviapp.controllers.useridentification.WorkController +// import com.naviapp.entities.BankDetails +// import com.naviapp.entities.NewLoanDetails +// import com.naviapp.filehandler.JsonParser +// import com.naviapp.registration.SplashActivity +// import com.naviapp.utilities.RandomGenerator +// import org.junit.Before +// import org.junit.Rule +// import org.junit.Test // // -//class MenuScreenTests : TestBase() { +// class MenuScreenTests : TestBase() { // // @Rule // @JvmField @@ -79,4 +79,4 @@ // .verifyActivity() // .validateMenuScreenDetails() // } -//} \ No newline at end of file +// } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c8af7421b7..18a7f13420 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,4 +1,11 @@ + + @@ -39,7 +46,7 @@ android:usesCleartextTraffic="true" tools:replace="android:theme,android:allowBackup,android:fullBackupContent,android:usesCleartextTraffic"> @@ -275,7 +282,7 @@ android:exported="false" android:screenOrientation="portrait" android:theme="@style/BaseThemeStyle" /> - + - + + + + + + = if ( CHANNEL_GI.equals(source, ignoreCase = true) || - CHANNEL_GI_BRANCH.equals(source, ignoreCase = true) + CHANNEL_GI_BRANCH.equals(source, ignoreCase = true) ) { val skipIdentifier = metaData?.optString(SKIP_IDENTIFIER).orEmpty() if (skipIdentifier == TRUE) { @@ -351,7 +374,8 @@ object DeeplinkManager { fun logOut() { try { Branch.getInstance().logout() - } catch (_: Exception) {} + } catch (_: Exception) { + } } } 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 d4d4f71748..033f2571b2 100644 --- a/app/src/main/java/com/naviapp/analytics/utils/NaviAnalytics.kt +++ b/app/src/main/java/com/naviapp/analytics/utils/NaviAnalytics.kt @@ -19,15 +19,14 @@ import com.navi.base.sharedpref.CommonPrefConstants.USER_EXTERNAL_ID import com.navi.base.sharedpref.PreferenceManager import com.navi.base.utils.BaseUtils import com.navi.base.utils.isNull -import com.navi.common.model.GenericErrorResponse import com.navi.common.network.models.ErrorMessage +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.utils.getKeyValueParams import com.navi.common.utils.log import com.navi.common.utils.orFalse import com.navi.common.utils.orZero import com.naviapp.BuildConfig import com.naviapp.app.NaviApplication -import com.naviapp.models.CardStatus import com.naviapp.models.VideoKycStatusEnum import com.naviapp.models.response.KycItem import com.naviapp.models.response.RadioButtonResponse @@ -1466,6 +1465,14 @@ class NaviAnalytics private constructor() { } } + inner class DigitalGold { + fun onBackButtonClick() { + NaviTrackEvent.trackEventOnClickStream( + "gold_vault_landing_page_back_click" + ) + } + } + inner class LoanEditor { fun onLoanEditorPageLands(offerId: String?, isAutoDebitSetup: Boolean?) { NaviTrackEvent.trackEventOnClickStream( @@ -3693,9 +3700,9 @@ class NaviAnalytics private constructor() { } inner class SmsUpload { - fun onSmsUploadStart(totalPages: Int, pageNumber: Int, size: Int) { + fun onSmsUploadStart(totalPages: Int, pageNumber: Int, size: Int, retryCount: Int = 0) { NaviTrackEvent.trackEventOnClickStream( - "sms_upload_started", + if (retryCount == 0) "sms_upload_started" else "retry_sms_upload_started", mapOf( Pair("totalPages", totalPages.toString()), Pair("pageNumber", pageNumber.toString()), @@ -3704,9 +3711,9 @@ class NaviAnalytics private constructor() { ) } - fun onSmsUploadSuccess(totalPages: Int, pageNumber: Int, size: Int) { + fun onSmsUploadSuccess(totalPages: Int, pageNumber: Int, size: Int, retryCount: Int = 0) { NaviTrackEvent.trackEventOnClickStream( - "sms_upload_success", + if (retryCount == 0) "sms_upload_success" else "retry_sms_upload_success", mapOf( Pair("totalPages", totalPages.toString()), Pair("pageNumber", pageNumber.toString()), @@ -3737,9 +3744,9 @@ class NaviAnalytics private constructor() { ) } - fun smsUploadEndTime(pageNumber: Int) { + fun smsUploadEndTime(pageNumber: Int, retryCount: Int = 0) { NaviTrackEvent.trackEventOnClickStream( - "sms_upload_end_time", + if (retryCount == 0) "sms_upload_end_time" else "retry_sms_upload_end_time", mapOf( Pair("atTimeStamp", System.currentTimeMillis().toString()), Pair("pageNumber", pageNumber.toString()) @@ -4722,7 +4729,7 @@ class NaviAnalytics private constructor() { NaviTrackEvent.trackEvent(clickData?.actionData?.screenName + "_Clicked", map) } - fun onWidgetClickEvent(actionData: ActionData?) { + fun onWidgetClickEvent(actionData: ActionData?, screenName: String? = null) { val map = ConcurrentHashMap() var eventName = actionData?.metaData?.clickedData?.eventName if (eventName.isNullOrEmpty()) { @@ -4732,6 +4739,9 @@ class NaviAnalytics private constructor() { if (userExternalId.isNullOrEmpty().not()) map["user_external_id"] = userExternalId.toString() map["user_logged_in"] = BaseUtils.isUserLoggedIn().toString() + screenName?.let { + map["screen_name"] = screenName + } actionData?.metaData?.clickedData?.parameters?.let { map.putAll(it) } NaviTrackEvent.trackEvent(eventName.orEmpty(), map) } @@ -4850,6 +4860,10 @@ class NaviAnalytics private constructor() { Pair("auto_debit_shown", if (autoDebitShown) TRUE else FALSE) ) ) + + fun onOfferUpgradeCardClicked() { + NaviTrackEvent.trackEventOnClickStream("PL_LoanDetails_OfferUpgradeCard_Clicked") + } } inner class FreshLoanDetailsV2 { @@ -5394,6 +5408,7 @@ class NaviAnalytics private constructor() { const val INFO_BOTTOM_SHEET_V2 = "info_$BOTTOM_SHEET" + "v2" fun faqs(screenName: String) = "${screenName}_FAQS" + const val INTEREST_RESET_SCREEN = "interest_reset_screen" const val PAYMENT_FOOTER_BOTTOM_SHEET = "PAYMENT_FOOTER_BOTTOM_SHEET" const val CUSTOM_PAYMENT_TYPE_SCREEN = "custom_payment_type_screen" const val LOAN_REPAYMENT_TYPE_SCREEN = "loan_repayment_type_screen" @@ -5497,6 +5512,8 @@ class NaviAnalytics private constructor() { const val HL_ADDRESS_DETAILS_SCREEN = "hl_address_details_screen" const val DELAYED_DISBURSEMENT_DETAILS_SCREEN = "delayed_disbursement_details_screen" const val DELAYED_DISBURSEMENT_DETAILS_V2_SCREEN = "delayed_disbursement_details_v2_screen" + const val MFI_REJECTED_FRAGMENT_V2 = "MFI_REJECTED_FRAGMENT_V2" + const val COMMON_REJECTED_FRAGMENT_V2 = "COMMON_REJECTED_FRAGMENT_V2" const val EMI_DATE_SELECT_BOTTOMSHEET = "emi_date_select_bottomsheet" const val PAYMENT_ACTIVITY = "payment_activity" const val CHAT_BANNER_CLICK = "chat_banner_click" @@ -5776,16 +5793,20 @@ class NaviAnalytics private constructor() { const val REWARDS_SUCCESSFUL_DISBURSAL_SCREEN = "Rewards_Successful_Disbursal_Screen" const val REWARDS_DELIGHT_SCREEN = "Rewards_Delight_Screen" const val SELECTABLE_OPTION_BOTTOMSHEET = "selectable_option_bottomsheet" + const val DASHBOARD_INSURANCE_BOTTOMSHEET_DATA = "dashboard_insurance_bottomsheet_data" const val HL_DOCUMENTS_PAGELAND = "HL_Documents_PageLand" const val DIGITAL_GOLD_HOME_SCREEN = "gold_vault_init_landing_page" const val DIGITAL_GOLD_TRANSACTION_SCREEN = "digital_gold_transaction_screen" - const val DIGITAL_GOLD_BUY_SCREEN = "digital_gold_buy_screen" + const val DIGITAL_GOLD_BUY_SCREEN = "gold_vault_init_buy_summary_page" const val DIGITAL_GOLD_SELL_SCREEN = "gold_vault_init_sell_summary_page" const val PAYMENT_CHECK_ACTIVITY = "payment_check_activity" - + const val DIGITAL_GOLD_SELL_UPI_SCREEN = "gold_vault_init_upi_withdrawal_page" const val REWARDS_ANNOUNCEMENT_SCREEN = "rewards_announcement_screen" const val POST_PAYMENT_MESSAGING_SCREEN = "Post_Payment_Messaging_Screen" const val NEW_HL_LANDING_LOADED = "New_HL_Landing_Loaded" + const val NOTIFICATION_RECEIVER_ACTIVITY = "notification_receiver_activity" + const val ELIGIBLE_FOR_BALANCE_TRANSFER = "Eligible for balance transfer" + const val COLENDING_BALANCE_TRANSFER_EVENT = "coLendingBalanceTransferEvent" } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/common/customview/DescExpandableCardView.kt b/app/src/main/java/com/naviapp/common/customview/DescExpandableCardView.kt index 84b9bee087..8233b63f2f 100644 --- a/app/src/main/java/com/naviapp/common/customview/DescExpandableCardView.kt +++ b/app/src/main/java/com/naviapp/common/customview/DescExpandableCardView.kt @@ -13,6 +13,8 @@ import android.view.LayoutInflater import androidx.cardview.widget.CardView import androidx.databinding.DataBindingUtil import com.navi.analytics.utils.NaviTrackEvent +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.extensions.setTextFieldData import com.naviapp.R import com.naviapp.dashboard.loanapplicationdetails.emicalendar.models.DescExpandableItemBinder import com.naviapp.databinding.ExpandableTitleDescViewBinding @@ -22,6 +24,7 @@ class DescExpandableCardView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : CardView(context, attrs) { private var binding: ExpandableTitleDescViewBinding + private var widgetCallback: WidgetCallback? = null init { val inflater = LayoutInflater.from(context) @@ -36,6 +39,12 @@ constructor(context: Context, attrs: AttributeSet? = null) : CardView(context, a binding.apply { emiInstallmentData = descExpandableItemBinder root.tag = ExpandableTag.COLLAPSED + tvTitle.setTextFieldData(descExpandableItemBinder.infoTitle) { + widgetCallback?.onClick(it) + } + tvDescription.setTextFieldData(descExpandableItemBinder.infoDescription) { + widgetCallback?.onClick(it) + } if (descExpandableItemBinder.cardType == MESSAGE_CARD) { collapsibleIcon.visibility = GONE tvDescription.visibility = VISIBLE @@ -62,6 +71,10 @@ constructor(context: Context, attrs: AttributeSet? = null) : CardView(context, a } } + fun setWidgetCallback(widgetCallback: WidgetCallback) { + this.widgetCallback = widgetCallback + } + private fun getIconIdFromIcon(icon: String?): Int? { return when (icon) { ICON_DOWN_ARROW_GREY -> R.drawable.ic_down_arrow_grey_svg diff --git a/app/src/main/java/com/naviapp/common/customview/FooterView.kt b/app/src/main/java/com/naviapp/common/customview/FooterView.kt index 9c4f82d03f..b474397c7f 100644 --- a/app/src/main/java/com/naviapp/common/customview/FooterView.kt +++ b/app/src/main/java/com/naviapp/common/customview/FooterView.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -17,6 +17,8 @@ import androidx.core.view.isVisible import androidx.core.widget.CompoundButtonCompat import androidx.databinding.DataBindingUtil import com.navi.base.model.CtaData +import com.navi.naviwidgets.extensions.setTextFieldData +import com.navi.naviwidgets.models.response.TextFieldData import com.naviapp.R import com.naviapp.common.listeners.CheckBoxClickListener import com.naviapp.common.listeners.FooterInteractionListener @@ -32,6 +34,16 @@ class FooterView(context: Context, attrs: AttributeSet?) : ConstraintLayout(cont binding = DataBindingUtil.inflate(inflater, R.layout.view_common_footer, this, true) } + fun setMessage( + textFieldData: TextFieldData?, + footerInteractionListener: FooterInteractionListener? + ) { + binding.messageTv.apply { + visibility = View.VISIBLE + setTextFieldData(textFieldData) { footerInteractionListener?.onFooterTextPress(it) } + } + } + fun setProperties( backCtaData: CtaData?, nextCtaData: CtaData?, @@ -48,17 +60,12 @@ class FooterView(context: Context, attrs: AttributeSet?) : ConstraintLayout(cont } } nextCtaData?.title?.let { title -> - binding.nextView.setProperties( - title = title, - iconId = nextButtonIconId - ) + binding.nextView.setProperties(title = title, iconId = nextButtonIconId) } - binding.nextView.setOnCustomClickListener({ - footerInteractionListener?.onFooterNextPress( - nextCtaData - ) - }, customClickConfig) - + binding.nextView.setOnCustomClickListener( + { footerInteractionListener?.onFooterNextPress(nextCtaData) }, + customClickConfig + ) } fun toggleCheckBoxView(show: Boolean) { @@ -147,12 +154,7 @@ class FooterView(context: Context, attrs: AttributeSet?) : ConstraintLayout(cont } fun setNextCtaTitle(title: String?, nextButtonIconId: Int? = R.drawable.ic_arrow_right_svg) { - title?.let { - binding.nextView.setProperties( - title = it, - iconId = nextButtonIconId - ) - } + title?.let { binding.nextView.setProperties(title = it, iconId = nextButtonIconId) } } fun getCtaTitle(): String { @@ -163,4 +165,4 @@ class FooterView(context: Context, attrs: AttributeSet?) : ConstraintLayout(cont ENABLED, DISABLED } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/common/fragment/InfoBottomSheetV3.kt b/app/src/main/java/com/naviapp/common/fragment/InfoBottomSheetV3.kt new file mode 100644 index 0000000000..422e8ea5dd --- /dev/null +++ b/app/src/main/java/com/naviapp/common/fragment/InfoBottomSheetV3.kt @@ -0,0 +1,144 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.common.fragment + +import android.content.ActivityNotFoundException +import android.content.Context +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewStub +import androidx.appcompat.widget.AppCompatTextView +import androidx.browser.customtabs.CustomTabsIntent +import androidx.databinding.DataBindingUtil +import com.navi.base.model.CtaType +import com.navi.base.utils.isNotNull +import com.navi.base.utils.isNotNullAndNotEmpty +import com.navi.common.ui.fragment.BaseBottomSheet +import com.navi.common.utils.log +import com.navi.naviwidgets.databinding.LayoutLeftRightTextBinding +import com.navi.naviwidgets.extensions.setLayoutFieldData +import com.navi.naviwidgets.extensions.setTextFieldData +import com.navi.naviwidgets.models.response.BottomSheetInfoV2 +import com.navi.naviwidgets.models.response.BottomSheetInfoV2RowItem +import com.navi.naviwidgets.models.response.TextFieldData +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.databinding.BottomSheetInfoV3Binding +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class InfoBottomSheetV3 : BaseBottomSheet() { + + private lateinit var binding: BottomSheetInfoV3Binding + private var bottomSheetInfo: BottomSheetInfoV2? = null + + override fun setContainerView(viewStub: ViewStub) { + viewStub.layoutResource = R.layout.bottom_sheet_info_v3 + binding = DataBindingUtil.getBinding(viewStub.inflate())!! + initUI() + } + + private fun initUI() { + arguments?.getParcelable(ARG_DATA)?.run { + bottomSheetInfo = this + NaviAnalytics.naviAnalytics.sendAnalyticsEvent(bottomSheetInfo?.analyticsEvent) + binding.title.setTextFieldData(this.title) + context?.let { context -> + this.rowItems?.forEachIndexed { _, paymentOptionContent -> + val childItem = getRowItem(paymentOptionContent, context) + binding.content.addView(childItem, binding.content.childCount) + } + this.descriptions?.forEachIndexed { _, textFieldData -> + val itemView = getDescriptionsItem(textFieldData, context) + itemView.setLineSpacing( + resources.getDimension(com.navi.naviwidgets.R.dimen.dp_1), + 1.0f + ) + itemView.setPadding( + 0, + resources.getDimension(com.navi.naviwidgets.R.dimen.dp_16).toInt(), + 0, + 0 + ) + binding.content.addView(itemView) + } + if (this.rowItems.isNotNull() || this.descriptions.isNotNull()) { + binding.content.visibility = View.VISIBLE + } + } + binding.tvPrimaryAction.setLayoutFieldData(this.footer?.primaryAction) { + safelyDismissDialog() + } + } + } + + private fun getRowItem( + bottomSheetInfoV1RowItem: BottomSheetInfoV2RowItem?, + context: Context + ): View { + val layoutLeftRightTextBinding: LayoutLeftRightTextBinding = + DataBindingUtil.inflate( + LayoutInflater.from(context), + com.navi.naviwidgets.R.layout.layout_left_right_text, + null, + false + ) + layoutLeftRightTextBinding.apply { + leftText.setTextFieldData(bottomSheetInfoV1RowItem?.leftText) + rightText.setTextFieldData(bottomSheetInfoV1RowItem?.rightText) + } + layoutLeftRightTextBinding.rootLayout.setPadding( + 0, + resources.getDimension(com.navi.naviwidgets.R.dimen.dp_16).toInt(), + 0, + 0 + ) + return layoutLeftRightTextBinding.root + } + + private fun getDescriptionsItem( + textFieldData: TextFieldData?, + context: Context + ): AppCompatTextView { + val textView = AppCompatTextView(context) + textView.setTextFieldData(textFieldData) { + if (it.url == CtaType.OPEN_WEB_PAGE.name) { + val lineItem = it.parameters?.firstOrNull { it.key == PARAM_WEB_URL } + lineItem?.run { + if (this.value.isNotNullAndNotEmpty()) { + try { + val customTabsIntent: CustomTabsIntent = + CustomTabsIntent.Builder().build() + customTabsIntent.launchUrl(requireContext(), Uri.parse(this.value)) + safelyDismissDialog() + } catch (e: ActivityNotFoundException) { + e.log() + } + } + } + } + } + return textView + } + + companion object { + const val TAG = "BOTTOM_SHEET_INFO_V3" + const val ARG_DATA = "BottomSheetInfoV1" + const val PARAM_WEB_URL = "WEB_URL" + fun getInstance(bottomSheetInfo: BottomSheetInfoV2) = + InfoBottomSheetV3().apply { + val bundle = Bundle().apply { putParcelable(ARG_DATA, bottomSheetInfo) } + arguments = bundle + } + } + + override val screenName: String + get() = TAG +} diff --git a/app/src/main/java/com/naviapp/common/fragment/PaymentCheckFragment.kt b/app/src/main/java/com/naviapp/common/fragment/PaymentCheckFragment.kt new file mode 100644 index 0000000000..43b1b60a32 --- /dev/null +++ b/app/src/main/java/com/naviapp/common/fragment/PaymentCheckFragment.kt @@ -0,0 +1,98 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.common.fragment + +import android.app.Dialog +import android.os.Bundle +import android.view.View +import com.navi.analytics.utils.NaviTrackEvent +import com.navi.base.model.ActionData +import com.navi.common.extensions.isNotNull +import com.navi.common.ui.dialog.BaseDialogFragment +import com.navi.common.utils.toCtaData +import com.navi.design.utils.spannedText +import com.navi.naviwidgets.extensions.showWhenDataIsAvailable +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.analytics.utils.NaviAnalytics.Companion.PAYMENT_CHECK_ACTIVITY +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.databinding.PaymentCheckFragmentBinding +import com.naviapp.models.PaymentCheckResponse +import com.naviapp.utils.Constants.GOLD + +class PaymentCheckFragment : BaseDialogFragment( + R.layout.payment_check_fragment, + R.style.FullScreenDialogFragment +) { + + private val widgetNaviAnalyticsEventTracker = NaviAnalytics.naviAnalytics.Widget() + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return object : Dialog(requireActivity(), theme) { + override fun onBackPressed() { + arguments?.getParcelable(DATA)?.actionData?.let { + navigateToNextScreen( + it + ) + } + } + } + } + + override fun initUI() { + binding.apply { + val data = arguments?.getParcelable(DATA) + activity?.let { + binding.titleTv.text = data?.title?.text?.spannedText( + context = it, + span = data.title.span + ) + binding.messageTv.text = data?.description?.text?.spannedText( + context = it, + span = data.description.span + ) + } + binding.actionButton.showWhenDataIsAvailable(data?.actionData?.title) + binding.iconIv.showWhenDataIsAvailable(data?.iconCode) + binding.actionButton.setOnClickListener { + data?.actionData?.let { + navigateToNextScreen(it) + } + } + data?.screenName?.let { + NaviTrackEvent.trackEvent(it) + } + } + } + + private fun navigateToNextScreen(actionData: ActionData) { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent(actionData) + if (actionData.isNotNull() && actionData.url?.equals(GOLD) == true) { + activity?.finish() + } + NaviDeepLinkNavigator.navigate( + activity, + actionData.toCtaData(), + finish = true + ) + } + + override fun onClick(p0: View?) {} + + companion object { + const val DATA = "DATA" + const val TAG = "PAYMENT_CHECK_FRAGMENT" + fun newInstance(bundle: Bundle): PaymentCheckFragment { + return PaymentCheckFragment().apply { + arguments = bundle + } + } + } + + override val screenName: String = PAYMENT_CHECK_ACTIVITY +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/common/fragment/PtpErrorFragment.kt b/app/src/main/java/com/naviapp/common/fragment/PtpErrorFragment.kt index 7e5a33cd27..946e2bd30f 100644 --- a/app/src/main/java/com/naviapp/common/fragment/PtpErrorFragment.kt +++ b/app/src/main/java/com/naviapp/common/fragment/PtpErrorFragment.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -12,19 +12,19 @@ import android.os.Bundle import android.view.View import android.view.WindowManager import com.navi.analytics.utils.NaviTrackEvent +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.dialog.BaseDialogFragment import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.dashboard.listeners.FragmentInteractionListener import com.naviapp.databinding.PtpErrorLayoutBinding -import com.navi.common.model.GenericErrorResponse import com.naviapp.utils.IconUtils - -class PtpErrorFragment : BaseDialogFragment( - R.layout.ptp_error_layout, - R.style.FullScreenDialogFragment -) { +class PtpErrorFragment : + BaseDialogFragment( + R.layout.ptp_error_layout, + R.style.FullScreenDialogFragment + ) { var response: GenericErrorResponse? = null @@ -36,9 +36,7 @@ class PtpErrorFragment : BaseDialogFragment( } private fun initListeners() { - binding.closeIv.setOnClickListener { - dismiss() - } + binding.closeIv.setOnClickListener { dismiss() } binding.actionTv.setOnClickListener { response?.actions?.getOrNull(0)?.cta?.analyticsEventName?.let { NaviAnalytics.naviAnalytics.PTP().sendEvent(it) @@ -90,15 +88,12 @@ class PtpErrorFragment : BaseDialogFragment( } } - override fun onClick(p0: View?) { - } - + override fun onClick(p0: View?) {} companion object { const val TAG = "PtpErrorDialog" - fun getInstance(response: GenericErrorResponse?) = PtpErrorFragment().apply { - this.response = response - } + fun getInstance(response: GenericErrorResponse?) = + PtpErrorFragment().apply { this.response = response } } } diff --git a/app/src/main/java/com/naviapp/common/listeners/FooterInteractionListener.kt b/app/src/main/java/com/naviapp/common/listeners/FooterInteractionListener.kt index ae0a47d8b4..9bd804d089 100644 --- a/app/src/main/java/com/naviapp/common/listeners/FooterInteractionListener.kt +++ b/app/src/main/java/com/naviapp/common/listeners/FooterInteractionListener.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -12,4 +12,5 @@ import com.navi.base.model.CtaData interface FooterInteractionListener { fun onFooterBackPress(ctaData: CtaData?) fun onFooterNextPress(ctaData: CtaData?, skipValidation: Boolean? = false) -} \ No newline at end of file + fun onFooterTextPress(ctaData: CtaData?) {} +} diff --git a/app/src/main/java/com/naviapp/common/navigator/NaviDeepLinkNavigator.kt b/app/src/main/java/com/naviapp/common/navigator/NaviDeepLinkNavigator.kt index cc18dfa0e0..c1441b7248 100644 --- a/app/src/main/java/com/naviapp/common/navigator/NaviDeepLinkNavigator.kt +++ b/app/src/main/java/com/naviapp/common/navigator/NaviDeepLinkNavigator.kt @@ -22,6 +22,7 @@ import com.navi.analytics.utils.NaviTrackEvent import com.navi.base.model.CtaData import com.navi.base.sharedpref.CommonPrefConstants.USER_EXTERNAL_ID import com.navi.base.sharedpref.PreferenceManager +import com.navi.base.utils.isNotNullAndNotEmpty import com.navi.chat.models.NaviChatSystemLocalData import com.navi.chat.ui.activities.NaviChatActivity import com.navi.chat.utils.* @@ -54,6 +55,10 @@ import com.naviapp.dashboard.menu.utils.openCallDialScreen import com.naviapp.dashboard.menu.utils.openEmailScreenWithSubjectAndBody import com.naviapp.dashboard.newloan.NewLoanConsentActivity import com.naviapp.dashboard.rating.RatingActivity +import com.naviapp.digitalgold.ui.DigitalGoldBuyActivity +import com.naviapp.digitalgold.ui.DigitalGoldHomeActivity +import com.naviapp.digitalgold.ui.DigitalGoldSellActivity +import com.naviapp.digitalgold.ui.DigitalGoldTransactionActivity import com.naviapp.email.activity.EmailActivity import com.naviapp.errors.activities.ErrorActivity import com.naviapp.home.activity.NewDashboardActivity @@ -67,9 +72,11 @@ import com.naviapp.homeloandigital.pennydrop.ui.HomeLoanPennyDropLoaderActivity import com.naviapp.homeloandigital.posteligibility.activity.HomeLoanPostEligibilityV2Activity import com.naviapp.homeloandigital.slgenerate.ui.HomeLoanSanctionLoaderActivity import com.naviapp.homeloandigital.tracker.ui.activity.HomeLoanTrackerActivity +import com.naviapp.interest_reset.InterestResetActivity import com.naviapp.models.SubPageStatusType import com.naviapp.models.UserDetail import com.naviapp.part_prepayment.PartPrePaymentActivity +import com.naviapp.payment.activities.FeedbackActivity import com.naviapp.payment.activities.NaviPaymentActivity import com.naviapp.permission.activities.PermissionActivity import com.naviapp.personalloan.getloan.activities.* @@ -149,7 +156,8 @@ object NaviDeepLinkNavigator : DeepLinkListener { private const val HOME_SMALL = "home" const val PART_PRE_PAYMENT = "partPrePayment" private const val STATUS_TRACKER = "status_tracker" - const val CUSTOM_PAYMENT = "custom_payment" + private const val CUSTOM_PAYMENT = "custom_payment" + private const val INTEREST_RESET = "interest_reset" const val SEND_EMAIL = "sendEmail" const val HOME_LOAN_ELIGIBILITY_V2 = "homeLoanEligibilityV2" const val HOME_LOAN_POST_ELIGIBILITY_V2 = "homeLoanPostEligibilityV2" @@ -187,6 +195,10 @@ object NaviDeepLinkNavigator : DeepLinkListener { const val DISBURSEMENT_STATUS_V2 = "DISBURSEMENT_STATUS_V2" const val SKIP_MANDATE_V2 = "SKIP_MANDATE_V2" private const val STORY = "story" + private const val GOLD = "gold" + private const val TRANSACTIONS = "transactions" + private const val SELL = "sell" + private const val BUY = "buy" private const val WEB_URL = "webUrl" private const val CUSTOMER_SUPPORT = "CUSTOMER_SUPPORT" const val DOCUMENT_LIST = "documentList" @@ -194,6 +206,7 @@ object NaviDeepLinkNavigator : DeepLinkListener { const val SURVEY = "SURVEY" private const val APP_PLATFORM = "applicationPlatform" private const val VIEW_VIDEO = "view_video" + const val FEEDBACK_SCREEN = "feedback_screen" fun navigate( activity: Activity?, @@ -414,6 +427,12 @@ object NaviDeepLinkNavigator : DeepLinkListener { bundle.putString(LOAN_ACCOUNT_NUMBER, loanAccountNumber) intent = Intent(activity, DocumentListActivity::class.java) } + INTEREST_RESET -> { + intent = Intent(activity, InterestResetActivity::class.java) + } + FEEDBACK_SCREEN -> { + intent = Intent(activity, FeedbackActivity::class.java) + } CHAT_ACTIVITY -> { var shareableLink: String? = null var sourceId: String? = DEFAULT_SOURCE_ID_FOR_PL @@ -595,6 +614,19 @@ object NaviDeepLinkNavigator : DeepLinkListener { APP_PLATFORM -> { intent = Intent(activity, ApplicationPlatformActivity::class.java) } + GOLD -> { + if (secondIdentifier.isNotNullAndNotEmpty()) { + when (secondIdentifier) { + TRANSACTIONS -> intent = + Intent(activity, DigitalGoldTransactionActivity::class.java) + SELL -> intent = + Intent(activity, DigitalGoldSellActivity::class.java) + BUY -> intent = Intent(activity, DigitalGoldBuyActivity::class.java) + } + } else { + intent = Intent(activity, DigitalGoldHomeActivity::class.java) + } + } VIEW_VIDEO -> { var videoId: String? = null ctaData.parameters?.forEach { lineItem -> 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 a63d90d684..90f8a94cbc 100644 --- a/app/src/main/java/com/naviapp/common/repository/OtpRepository.kt +++ b/app/src/main/java/com/naviapp/common/repository/OtpRepository.kt @@ -1,18 +1,18 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.common.repository +import com.navi.common.network.models.RepoResult import com.naviapp.homeloandigital.models.EmailResponse import com.naviapp.homeloandigital.models.OTPVerifyResponse import com.naviapp.models.request.OtpRequest import com.naviapp.models.request.SendOtpForDisbursementRequest import com.naviapp.models.response.SendDisbursementOtpResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService @@ -20,10 +20,11 @@ class OtpRepository : ResponseCallback() { suspend fun sendOtp(sendOtpForDisbursementRequest: SendOtpForDisbursementRequest) = apiResponseCallback(retrofitService().sendOtpForDisbursement(sendOtpForDisbursementRequest)) - suspend fun sendOtpForEPFO() = - apiResponseCallback(retrofitService().sendOtpForEPFO()) + suspend fun sendOtpForEPFO() = apiResponseCallback(retrofitService().sendOtpForEPFO()) - suspend fun sendOtpForHL(queryMap: HashMap): RepoResult = + suspend fun sendOtpForHL( + queryMap: HashMap + ): RepoResult = apiResponseCallback(retrofitService().sendOtpForHL(queryMap)) suspend fun sendOtpForHLEmail( @@ -43,4 +44,4 @@ class OtpRepository : ResponseCallback() { suspend fun fetchAsyncRequestData(requestId: String): RepoResult = apiResponseCallback(retrofitService().fetchAsyncResponse(requestId)) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/common/viewholders/DashboardPolicyBenefitVH.kt b/app/src/main/java/com/naviapp/common/viewholders/DashboardPolicyBenefitVH.kt index 50530e95ca..6a6252def5 100644 --- a/app/src/main/java/com/naviapp/common/viewholders/DashboardPolicyBenefitVH.kt +++ b/app/src/main/java/com/naviapp/common/viewholders/DashboardPolicyBenefitVH.kt @@ -136,7 +136,6 @@ class DashboardPolicyBenefitVH(private val viewBinding: ViewDataBinding) : viewBinding.ivLeftIcon.showWhenDataIsAvailable( policyBenefitData?.statusAttribute?.iconCode ) - } else { viewBinding.benefitErrorLayout.isVisible = false } diff --git a/app/src/main/java/com/naviapp/common/viewholders/RadioBaseViewHolder.kt b/app/src/main/java/com/naviapp/common/viewholders/RadioBaseViewHolder.kt index c031de9fc0..8d4f812f91 100644 --- a/app/src/main/java/com/naviapp/common/viewholders/RadioBaseViewHolder.kt +++ b/app/src/main/java/com/naviapp/common/viewholders/RadioBaseViewHolder.kt @@ -5,7 +5,6 @@ * */ - package com.naviapp.common.viewholders import android.view.View @@ -23,4 +22,3 @@ abstract class RadioBaseViewHolder(view: View) : action: (position: Int) -> Unit ) } - 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 8fc43c1978..ca83692ed4 100644 --- a/app/src/main/java/com/naviapp/common/viewmodel/OtpSharedViewModel.kt +++ b/app/src/main/java/com/naviapp/common/viewmodel/OtpSharedViewModel.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -10,16 +10,16 @@ package com.naviapp.common.viewmodel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.navi.common.extensions.isNull +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.viewmodel.BaseVM import com.naviapp.common.repository.OtpRepository import com.naviapp.homeloandigital.models.OTPVerifyResponse import com.naviapp.models.request.OtpRequest import com.naviapp.models.response.EPFOOtpVerificationStatusResponse import com.naviapp.models.response.SuccessResponse -import com.navi.common.model.UploadDataAsyncResponse import com.naviapp.network.ApiConstants import com.naviapp.network.ApiErrorTagType -import com.navi.common.model.GenericErrorResponse import kotlinx.coroutines.launch class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository()) : BaseVM(false) { @@ -79,8 +79,8 @@ class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository() } else { when (response.error?.statusCode) { ApiConstants.API_WRONG_OTP -> _errorVerifyOtp.value = ApiErrorTagType.OTP_WRONG - ApiConstants.API_EXPIRED_OTP -> _errorVerifyOtp.value = - ApiErrorTagType.OTP_EXPIRED + ApiConstants.API_EXPIRED_OTP -> + _errorVerifyOtp.value = ApiErrorTagType.OTP_EXPIRED ApiConstants.API_TOO_MANY_REQUESTS -> { _errorVerifyOtp.value = ApiErrorTagType.MAX_OTP_ATTEMPTS setErrorData(response.errors, response.error) @@ -101,10 +101,9 @@ class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository() _verifyEpfoOtpAsyncResponse.value = response.data } when (response.statusCode) { - ApiConstants.API_SUCCESS_CODE -> { } + ApiConstants.API_SUCCESS_CODE -> {} ApiConstants.API_WRONG_OTP -> _errorVerifyOtp.value = ApiErrorTagType.OTP_WRONG - ApiConstants.API_EXPIRED_OTP -> _errorVerifyOtp.value = - ApiErrorTagType.OTP_EXPIRED + ApiConstants.API_EXPIRED_OTP -> _errorVerifyOtp.value = ApiErrorTagType.OTP_EXPIRED ApiConstants.API_TOO_MANY_REQUESTS -> { _errorVerifyOtp.value = ApiErrorTagType.MAX_OTP_ATTEMPTS setErrorData(response.errors, response.error) @@ -138,9 +137,10 @@ class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository() ApiConstants.API_SUCCESS_CODE.toString() -> { _hlOtpVerifiedForMail.value = response.data } - ApiConstants.API_WRONG_OTP.toString() -> _errorVerifyOtp.value = ApiErrorTagType.OTP_WRONG - ApiConstants.API_EXPIRED_OTP.toString() -> _errorVerifyOtp.value = - ApiErrorTagType.OTP_EXPIRED + ApiConstants.API_WRONG_OTP.toString() -> + _errorVerifyOtp.value = ApiErrorTagType.OTP_WRONG + ApiConstants.API_EXPIRED_OTP.toString() -> + _errorVerifyOtp.value = ApiErrorTagType.OTP_EXPIRED ApiConstants.API_TOO_MANY_REQUESTS.toString() -> { _errorVerifyOtp.value = ApiErrorTagType.MAX_OTP_ATTEMPTS setErrorData(response.errors, response.error) @@ -160,32 +160,34 @@ class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository() _asyncResponse.value = response.data if (response.data?.details?.statusCode.isNull().not()) { when (response.data?.details?.statusCode) { - ApiConstants.API_SUCCESS_CODE -> { - } + ApiConstants.API_SUCCESS_CODE -> {} ApiConstants.API_WRONG_OTP -> _errorVerifyOtp.value = ApiErrorTagType.OTP_WRONG - ApiConstants.API_EXPIRED_OTP -> _errorVerifyOtp.value = - ApiErrorTagType.OTP_EXPIRED + ApiConstants.API_EXPIRED_OTP -> + _errorVerifyOtp.value = ApiErrorTagType.OTP_EXPIRED ApiConstants.API_TOO_MANY_REQUESTS -> { _errorVerifyOtp.value = ApiErrorTagType.MAX_OTP_ATTEMPTS setErrorData(response.errors, response.error) } else -> { _errorVerifyOtp.value = ApiErrorTagType.SOMETHING_WENT_WRONG - if(!isEpfoErrorCodeHandled(response.errors)) { + if (!isEpfoErrorCodeHandled(response.errors)) { setErrorData(response.errors, response.error) } } } } else if (response.error != null || response.errors.isNullOrEmpty().not()) { - if(!isEpfoErrorCodeHandled(response.errors)) { + if (!isEpfoErrorCodeHandled(response.errors)) { setErrorData(response.errors, response.error) } } } } - private fun isEpfoErrorCodeHandled(errors: List?):Boolean { - if((errors?.getOrNull(0)?.code == ApiErrorTagType.KARZA_FAILURE) || (errors?.getOrNull(0)?.code == ApiErrorTagType.OTP_LIMIT_BREACHED)){ + private fun isEpfoErrorCodeHandled(errors: List?): Boolean { + if ( + (errors?.getOrNull(0)?.code == ApiErrorTagType.KARZA_FAILURE) || + (errors?.getOrNull(0)?.code == ApiErrorTagType.OTP_LIMIT_BREACHED) + ) { _otpFailureCtaEpfo.value = true return true } @@ -208,4 +210,4 @@ class OtpSharedViewModel(private val repository: OtpRepository = OtpRepository() _dataAsyncResponse.value = null _verifyEpfoOtpAsyncResponse.value = null } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/custom_payments/CustomPaymentActivity.kt b/app/src/main/java/com/naviapp/custom_payments/CustomPaymentActivity.kt index 8e9d9d8cba..6f24da4a70 100644 --- a/app/src/main/java/com/naviapp/custom_payments/CustomPaymentActivity.kt +++ b/app/src/main/java/com/naviapp/custom_payments/CustomPaymentActivity.kt @@ -32,6 +32,7 @@ class CustomPaymentActivity : DashboardBaseActivity(), FragmentInterchangeListen override fun onCreate(savedInstanceState: Bundle?) { binding = DataBindingUtil.setContentView(this, R.layout.activity_custom_payment) super.onCreate(savedInstanceState) + initV2Loader() navigateToNextScreen( intent?.extras?.getString(Constants.REDIRECT_STATUS).orEmpty(), intent?.extras ?: Bundle() @@ -58,7 +59,12 @@ class CustomPaymentActivity : DashboardBaseActivity(), FragmentInterchangeListen fragmentTransaction.commit() } } else { - NaviDeepLinkNavigator.navigate(this, CtaData(url = currentScreenTag), true, bundle) + NaviDeepLinkNavigator.navigate( + this, + CtaData(url = currentScreenTag), + bundle = bundle, + finish = true + ) } } @@ -87,10 +93,4 @@ class CustomPaymentActivity : DashboardBaseActivity(), FragmentInterchangeListen } ?: run { finish() } } - - companion object { - const val REPAYMENT_TYPE = "REPAYMENT_TYPE" - const val CURRENCY = "CURRENCY" - const val SYMBOL = "SYMBOL" - } } diff --git a/app/src/main/java/com/naviapp/custom_payments/fragments/CustomPaymentCalendarReviewFragment.kt b/app/src/main/java/com/naviapp/custom_payments/fragments/CustomPaymentCalendarReviewFragment.kt index bebbfec51a..955621f5a5 100644 --- a/app/src/main/java/com/naviapp/custom_payments/fragments/CustomPaymentCalendarReviewFragment.kt +++ b/app/src/main/java/com/naviapp/custom_payments/fragments/CustomPaymentCalendarReviewFragment.kt @@ -28,7 +28,6 @@ import com.naviapp.part_prepayment.PartPrePaymentActivity import com.naviapp.part_prepayment.fragments.PartPrePaymentBaseFragment import com.naviapp.part_prepayment.states.GenericWidgetState import com.naviapp.payment.activities.NaviPaymentActivity -import com.naviapp.payment.fragments.PaymentType import com.naviapp.payment.models.Amount import com.naviapp.utils.LOAN_ACCOUNT_NUMBER import dagger.hilt.android.AndroidEntryPoint @@ -60,7 +59,7 @@ class CustomPaymentCalendarReviewFragment : PartPrePaymentBaseFragment(), Widget override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initError(customPaymentCalendarVM) - initialize(PaymentType.CUSTOM_PAYMENT) + initialize() init() } diff --git a/app/src/main/java/com/naviapp/custom_payments/fragments/ForecloseLoanFragment.kt b/app/src/main/java/com/naviapp/custom_payments/fragments/ForecloseLoanFragment.kt index aba59dd1cd..ea1f222618 100644 --- a/app/src/main/java/com/naviapp/custom_payments/fragments/ForecloseLoanFragment.kt +++ b/app/src/main/java/com/naviapp/custom_payments/fragments/ForecloseLoanFragment.kt @@ -37,6 +37,7 @@ import com.naviapp.part_prepayment.states.GenericWidgetState import com.naviapp.payment.activities.NaviPaymentActivity import com.naviapp.payment.fragments.PaymentType import com.naviapp.payment.models.Amount +import com.naviapp.utils.CLOSURE_TYPE import com.naviapp.utils.LOAN_ACCOUNT_NUMBER import kotlinx.coroutines.launch @@ -80,6 +81,25 @@ class ForecloseLoanFragment : setWidgetState(it) } } + launch { paymentVM.closeLoanResponse.collect { handelCloseLoanWidgetState(it) } } + } + } + + private fun handelCloseLoanWidgetState(viewState: GenericWidgetState) { + when (viewState) { + is GenericWidgetState.Init -> { + showLoader() + } + is GenericWidgetState.Failure -> { + hideLoader() + } + is GenericWidgetState.Update -> { + hideLoader() + viewState.data?.run { + val cta = this.metadata?.get(METADATA_CTA)?.data as? CtaData + cta?.let { onClick(cta) } + } + } } } @@ -101,8 +121,11 @@ class ForecloseLoanFragment : adapter = naviAdapter } repaymentType = - (contentWidget.firstOrNull { x -> x.widgetNameForBaseAdapter == PaymentLabelWidget.WIDGET_NAME } - as? PaymentLabelWidget)?.widgetData?.type + (contentWidget.firstOrNull { x -> + x.widgetNameForBaseAdapter == PaymentLabelWidget.WIDGET_NAME + } as? PaymentLabelWidget) + ?.widgetData + ?.type } termsAndConditionsBottomSheet = this.metadata @@ -174,16 +197,14 @@ class ForecloseLoanFragment : openForecloseLoanBottomSheet(paymentFooterWidget) } else if (naviClickAction.url == CtaType.GO_BACK.name) { activity?.onBackPressed() + } else if (naviClickAction.url == CtaType.FORECLOSE_LOAN.name) { + val loanAccountNumber = + naviClickAction.parameters?.firstOrNull { it.key == LOAN_ACCOUNT_NUMBER }?.value + val closureType = + naviClickAction.parameters?.firstOrNull { it.key == CLOSURE_TYPE }?.value + paymentVM.closeLoan(loanAccountNumber, closureType) } else { - val bundle = Bundle() - naviClickAction.parameters?.forEach { bundle.putString(it.key, it.value) } - val source = arguments?.getString(PartPrePaymentActivity.SOURCE_DATA) - if (source != null) { - bundle.putString(PartPrePaymentActivity.SOURCE_DATA, source) - } - naviClickAction.url?.let { - fragmentInterchangeListener?.navigateToNextScreen(it, bundle) - } + navigateToNextScreen(naviClickAction, fragmentInterchangeListener) } } else if (naviClickAction is ActionData) { val bundle = Bundle() @@ -216,6 +237,7 @@ class ForecloseLoanFragment : const val FORECLOSE_LOAN = "FORECLOSE_LOAN_FRAGMENT" const val METADATA_TERMS_AND_CONDITIONS = "termsAndConditionsBottomSheet" const val METADATA_FORECLOSE_LOAN_DETAILS = "forecloseLoanDetailsBottomSheet" + const val METADATA_CTA = "ctaData" fun getInstance(loanAccountNumber: String) = ForecloseLoanFragment().apply { diff --git a/app/src/main/java/com/naviapp/custom_payments/fragments/LoanRepaymentOptionsFragment.kt b/app/src/main/java/com/naviapp/custom_payments/fragments/LoanRepaymentOptionsFragment.kt index 49ba38dd67..413c387ae8 100644 --- a/app/src/main/java/com/naviapp/custom_payments/fragments/LoanRepaymentOptionsFragment.kt +++ b/app/src/main/java/com/naviapp/custom_payments/fragments/LoanRepaymentOptionsFragment.kt @@ -68,9 +68,7 @@ class LoanRepaymentOptionsFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initError(loanRepaymentTypeVM) - initialize(PaymentType.CUSTOM_PAYMENT) - showLoader() - loanRepaymentTypeVM.fetchData(arguments) + initialize() } override fun onCreateView( @@ -95,20 +93,22 @@ class LoanRepaymentOptionsFragment : private fun init() { viewLifecycleOwner.lifecycleScope.launchWhenStarted { + launch { + showLoader() + loanRepaymentTypeVM.fetchData(arguments) + } launch { loanRepaymentTypeVM.widgetDataResponse.collect { hideLoader() setWidgetState(it) } } - launch { loanRepaymentTypeVM.submitAmountResponse.collect { hideLoader() setSubmitAmountState(it) } } - launch { loanRepaymentTypeVM.paymentInfoResponse.collect { hideLoader() diff --git a/app/src/main/java/com/naviapp/custom_payments/fragments/PaymentFooterBottomSheet.kt b/app/src/main/java/com/naviapp/custom_payments/fragments/PaymentFooterBottomSheet.kt index 8ed732effd..ac4133be37 100644 --- a/app/src/main/java/com/naviapp/custom_payments/fragments/PaymentFooterBottomSheet.kt +++ b/app/src/main/java/com/naviapp/custom_payments/fragments/PaymentFooterBottomSheet.kt @@ -19,6 +19,7 @@ import com.navi.base.model.NaviClickAction import com.navi.common.listeners.FragmentInterchangeListener import com.navi.common.ui.fragment.BaseBottomSheet import com.navi.common.utils.replaceLayout +import com.navi.design.utils.dpToPx import com.navi.naviwidgets.callbacks.WidgetCallback import com.navi.naviwidgets.models.NaviWidget import com.navi.naviwidgets.models.response.PaymentFooterWidget @@ -29,13 +30,13 @@ import com.naviapp.databinding.BottomSheetPaymentFooterBinding import kotlinx.coroutines.launch class PaymentFooterBottomSheet() : BaseBottomSheet(), WidgetCallback { - private var binding: BottomSheetPaymentFooterBinding? = null + private var bottomSheetPaymentFooterBinding: BottomSheetPaymentFooterBinding? = null private var paymentFooterInfo: PaymentFooterWidget? = null private var fragmentInterchangeListener: FragmentInterchangeListener? = null override fun setContainerView(viewStub: ViewStub) { viewStub.layoutResource = R.layout.bottom_sheet_payment_footer - binding = DataBindingUtil.getBinding(viewStub.inflate())!! + bottomSheetPaymentFooterBinding = DataBindingUtil.getBinding(viewStub.inflate())!! init() } @@ -58,9 +59,13 @@ class PaymentFooterBottomSheet() : BaseBottomSheet(), WidgetCallback { private fun init() { fragmentInterchangeListener = context as? FragmentInterchangeListener arguments?.getParcelable(ARG_DATA)?.run { + setPadding(0, dpToPx(8).toInt(), 0, 0) this.widgetData?.showCurvedBackgroundDrawable = true paymentFooterInfo = this - binding?.let { updateContainer(this, it.footerContainer) } + bottomSheetPaymentFooterBinding?.let { + setPadding(0, com.navi.design.utils.dpToPx(8).toInt(), 0, 0) + updateContainer(this, it.footerContainer) + } } } diff --git a/app/src/main/java/com/naviapp/custom_payments/fragments/RepaymentTypeFragment.kt b/app/src/main/java/com/naviapp/custom_payments/fragments/RepaymentTypeFragment.kt index 4a60cdc653..5be9761338 100644 --- a/app/src/main/java/com/naviapp/custom_payments/fragments/RepaymentTypeFragment.kt +++ b/app/src/main/java/com/naviapp/custom_payments/fragments/RepaymentTypeFragment.kt @@ -17,6 +17,7 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.navi.base.model.* +import com.navi.common.utils.CommonNaviAnalytics import com.navi.common.utils.replaceLayout import com.navi.naviwidgets.adapters.NaviInputWidgetAdapter import com.navi.naviwidgets.callbacks.WidgetCallback @@ -25,16 +26,19 @@ import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl import com.navi.naviwidgets.widgets.BaseNaviWidgetLayout import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.analytics.utils.NaviAnalytics.Companion.COLENDING_BALANCE_TRANSFER_EVENT +import com.naviapp.analytics.utils.NaviAnalytics.Companion.ELIGIBLE_FOR_BALANCE_TRANSFER import com.naviapp.custom_payments.view_models.CustomPaymentTypeVM import com.naviapp.databinding.FragmentRepaymentTypeBinding import com.naviapp.part_prepayment.PartPrePaymentActivity import com.naviapp.part_prepayment.fragments.PartPrePaymentBaseFragment import com.naviapp.part_prepayment.states.GenericWidgetState import com.naviapp.payment.activities.NaviPaymentActivity -import com.naviapp.payment.fragments.PaymentType import com.naviapp.payment.models.Amount import com.naviapp.utils.LOAN_ACCOUNT_NUMBER +import com.naviapp.utils.NaviDownloadManager import dagger.hilt.android.AndroidEntryPoint +import java.lang.ref.WeakReference import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch @@ -51,6 +55,8 @@ class RepaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback { widgetCallback = this, factory = ViewHolderFactoryImpl() ) + private var isColendingBalanceTransferEligible = false + private var naviDownloadManager: NaviDownloadManager? = null override fun onCreateView( inflater: LayoutInflater, @@ -64,32 +70,32 @@ class RepaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - showLoader() customPaymentTypeVM.fetchData(arguments) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initError(customPaymentTypeVM) - initialize(PaymentType.CUSTOM_PAYMENT) + initialize() init() } private fun init() { viewLifecycleOwner.lifecycleScope.launchWhenStarted { - launch { - customPaymentTypeVM.widgetDataResponse.collect { - hideLoader() - setWidgetState(it) - } - } + launch { customPaymentTypeVM.widgetDataResponse.collect { setWidgetState(it) } } } } private fun setWidgetState(viewState: GenericWidgetState) { when (viewState) { - is GenericWidgetState.Init -> {} + is GenericWidgetState.Init -> { + showLoader() + } + is GenericWidgetState.Failure -> { + hideLoader() + } is GenericWidgetState.Update -> { + hideLoader() viewState.data?.run { this.header?.getOrNull(0)?.let { updateContainer(it, binding.headerContainer) } this.footer?.getOrNull(0)?.let { @@ -109,6 +115,15 @@ class RepaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback { ?.get(PartPrePaymentActivity.METADATA_ANALYTICS_EVENT) ?.data as? AnalyticsEvent NaviAnalytics.naviAnalytics.sendAnalyticsEvent(analyticsEvent, screenName) + val coLendingBalanceTransferEvent = + this.metadata?.get(COLENDING_BALANCE_TRANSFER_EVENT)?.data + as? AnalyticsEvent + if (coLendingBalanceTransferEvent != null) { + NaviAnalytics.naviAnalytics.sendAnalyticsEvent( + coLendingBalanceTransferEvent + ) + isColendingBalanceTransferEligible = true + } } } } @@ -120,6 +135,25 @@ class RepaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback { if (naviClickAction.url == CtaType.PAYMENT.name) { if (naviAdapter.isValidWidget()) { val type = naviAdapter.getWidgetData().getOrNull(0) + val entry = + naviClickAction.analyticsEventProperties + ?.properties + ?.filter { it.key == CommonNaviAnalytics.OVERRIDE_EVENT } + ?.entries + ?.firstOrNull() + if (entry?.value == CommonNaviAnalytics.TEXT_TRUE) { + NaviAnalytics.naviAnalytics.sendAnalyticsEvent( + analyticsEvent = naviClickAction.analyticsEventProperties, + props = + mutableMapOf( + Pair(NaviAnalytics.SELECTED_OPTION, type.toString()), + Pair( + ELIGIBLE_FOR_BALANCE_TRANSFER, + isColendingBalanceTransferEligible.toString() + ) + ) + ) + } loanAccountNumber = naviClickAction.parameters ?.firstOrNull { it.key == LOAN_ACCOUNT_NUMBER } @@ -138,13 +172,15 @@ class RepaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback { ?.value startPayment( Amount(amountData?.toDoubleOrNull(), currency = currency, symbol = symbol), - partPrePaymentRescheduleType = "CHANGE_EMI" + partPrePaymentRescheduleType = type as? String ) } } else if (naviClickAction.url == CtaType.HELP_BOTTOM_SHEET.name) { openHelpInfo() } else if (naviClickAction.url == CtaType.GO_BACK.name) { activity?.onBackPressed() + } else if (naviClickAction.url == CtaType.DOWNLOAD.name) { + download(naviClickAction, naviClickAction.url) } else { val bundle = Bundle() naviClickAction.parameters?.forEach { bundle.putString(it.key, it.value) } @@ -159,6 +195,19 @@ class RepaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback { } } + private fun download(naviClickAction: CtaData, url: String?): Unit? { + NaviAnalytics.naviAnalytics.sendAnalyticsEvent(naviClickAction.analyticsEventProperties) + if (naviDownloadManager == null) { + naviDownloadManager = NaviDownloadManager(WeakReference(activity)) + } + return naviDownloadManager?.start( + NaviAnalytics.CUSTOM_PAYMENT_TYPE_SCREEN, + naviClickAction.title.toString(), + url.toString(), + "" + ) + } + override fun widgetAnalytics(genericAnalyticsData: GenericAnalyticsData?) { NaviAnalytics.naviAnalytics.sendGenericAnalyticsData(genericAnalyticsData, screenName) } diff --git a/app/src/main/java/com/naviapp/custom_payments/view_models/CustomPaymentCalendarVM.kt b/app/src/main/java/com/naviapp/custom_payments/view_models/CustomPaymentCalendarVM.kt index 9997f7ac92..8bccdd1362 100644 --- a/app/src/main/java/com/naviapp/custom_payments/view_models/CustomPaymentCalendarVM.kt +++ b/app/src/main/java/com/naviapp/custom_payments/view_models/CustomPaymentCalendarVM.kt @@ -9,6 +9,7 @@ package com.naviapp.custom_payments.view_models import android.os.Bundle import com.navi.common.utils.Constants +import com.navi.common.utils.Constants.FLOW_TYPE import com.navi.common.viewmodel.BaseVM import com.naviapp.models.request.CustomPaymentRequest import com.naviapp.part_prepayment.states.GenericWidgetState @@ -33,19 +34,23 @@ constructor(private val paymentRepository: PaymentRepository) : BaseVM() { val loanApplicationId = arguments?.getString(LOAN_ACCOUNT_NUMBER).orEmpty() val amountData = arguments?.getString(NaviPaymentActivity.AMOUNT_DATA) val rescheduleType = arguments?.getString(Constants.RESCHEDULE_TYPE) + val flowType = + arguments?.getString(FLOW_TYPE) + ?: com.naviapp.utils.Constants.FlowType.PART_PRE_PAYMENT.name coroutineScope.launch { val response = paymentRepository.fetchCustomPaymentCalendarWidget( - loanApplicationId, - rescheduleType, - CustomPaymentRequest( - amount = - Amount( - value = amountData?.toDoubleOrNull(), - currency = com.naviapp.utils.Constants.INR - ), - rescheduleType = rescheduleType - ) + loanAccountNumber = loanApplicationId, + customPayRequest = + CustomPaymentRequest( + amount = + Amount( + value = amountData?.toDoubleOrNull(), + currency = com.naviapp.utils.Constants.INR + ), + rescheduleType = rescheduleType + ), + flowType = flowType ) if ( response.error == null && response.errors.isNullOrEmpty() && response.data != null diff --git a/app/src/main/java/com/naviapp/custom_payments/view_models/CustomPaymentTypeVM.kt b/app/src/main/java/com/naviapp/custom_payments/view_models/CustomPaymentTypeVM.kt index 2725cd2720..ad2775831f 100644 --- a/app/src/main/java/com/naviapp/custom_payments/view_models/CustomPaymentTypeVM.kt +++ b/app/src/main/java/com/naviapp/custom_payments/view_models/CustomPaymentTypeVM.kt @@ -35,6 +35,7 @@ class CustomPaymentTypeVM @Inject constructor(private val paymentRepository: Pay val amountData = arguments?.getString(NaviPaymentActivity.AMOUNT_DATA) val source = arguments?.getString(PartPrePaymentActivity.SOURCE_DATA) coroutineScope.launch { + _widgetDataResponse.emit(GenericWidgetState.Loading) val response = paymentRepository.fetchCustomPaymentTypeWidget( loanApplicationId, @@ -49,6 +50,7 @@ class CustomPaymentTypeVM @Inject constructor(private val paymentRepository: Pay ) { _widgetDataResponse.emit(GenericWidgetState.Update(response.data)) } else { + _widgetDataResponse.emit(GenericWidgetState.Failure) setErrorData(response.errors, response.error) } } diff --git a/app/src/main/java/com/naviapp/dashboard/DashboardBaseActivity.kt b/app/src/main/java/com/naviapp/dashboard/DashboardBaseActivity.kt index 634858b24e..87dfb8a5cb 100644 --- a/app/src/main/java/com/naviapp/dashboard/DashboardBaseActivity.kt +++ b/app/src/main/java/com/naviapp/dashboard/DashboardBaseActivity.kt @@ -19,6 +19,7 @@ import com.naviapp.dashboard.viewmodels.DashboardSharedVM import com.naviapp.home.activity.NewDashboardActivity import com.naviapp.models.PgRepaymentData import com.naviapp.models.response.BottomSheetData +import com.naviapp.payment.activities.FeedbackActivity import com.naviapp.payment.activities.NaviPaymentActivity import com.naviapp.payment.activities.NaviPaymentActivity.Companion.ADVANCE_PAY_LABEL import com.naviapp.payment.activities.NaviPaymentActivity.Companion.AMOUNT_DATA @@ -150,11 +151,11 @@ abstract class DashboardBaseActivity : amount: Amount?, paymentType: String? ) { - val intent = Intent(this, PostPaymentMessagingActivity::class.java) + val intent = Intent(this, FeedbackActivity::class.java) if (status == FirebaseStatusType.SUCCESS) { intent.putExtra(PREVIOUS_SCREEN, PreviousScreenNameRequest(Constants.LOAN_CLOSED)) intent.putExtra(LOAN_ACCOUNT_NUMBER, loanAccountNumber) - intent.putExtra(com.naviapp.utils.AMOUNT_DATA, amount?.value) + intent.putExtra(com.naviapp.utils.AMOUNT_DATA, amount?.value?.toString()) } intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK or diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/details/fragments/DetailsFragment.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/details/fragments/DetailsFragment.kt index 2cc78d45d8..5503a30416 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/details/fragments/DetailsFragment.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/details/fragments/DetailsFragment.kt @@ -15,6 +15,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.res.ResourcesCompat import androidx.core.view.isVisible import androidx.lifecycle.ViewModelProvider import com.navi.base.model.AnalyticsEvent @@ -25,6 +26,7 @@ import com.navi.common.extensions.isNotNull import com.navi.common.extensions.isNotNullAndNotEmpty import com.navi.common.extensions.orFalse import com.navi.common.ui.fragment.BaseFragment +import com.navi.design.utils.getNaviDrawable import com.navi.design.utils.isNull import com.navi.insurance.util.disableView import com.navi.naviwidgets.callbacks.WidgetCallback @@ -226,6 +228,18 @@ class DetailsFragment : BaseFragment(), View.OnClickListener, WidgetCallback { ) } + binding.repoRateView.rootLayout.visibility = View.GONE + loanApplicationDetails?.repoRateDetails?.let { + binding.repoRateView.root.visibility = View.VISIBLE + binding.repoRateView.rootLayout.setProperties(it, this, binding.repoRateView) + binding.repoRateView.rootLayout.background = + getNaviDrawable( + cornerRadius = resources.getDimension(R.dimen.dp_10).toInt(), + backgroundColor = + ResourcesCompat.getColor(resources, R.color.grey_alabaster, null) + ) + } + loanApplicationDetails?.documentList?.let { documentList() } } diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/adapters/EmiStatusCalendarAdapter.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/adapters/EmiStatusCalendarAdapter.kt index 113bb50888..08dffdacf1 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/adapters/EmiStatusCalendarAdapter.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/adapters/EmiStatusCalendarAdapter.kt @@ -15,6 +15,7 @@ import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView +import com.navi.naviwidgets.callbacks.WidgetCallback import com.naviapp.R import com.naviapp.dashboard.loanapplicationdetails.emicalendar.models.EmiInstallmentBinder import com.naviapp.dashboard.loanapplicationdetails.emicalendar.models.EmiStatus @@ -23,7 +24,8 @@ import com.naviapp.utils.isValidIndex class EmiStatusCalendarAdapter( private val emiCalendar: MutableList, - private val context: Context? + private val context: Context?, + private val widgetCallback: WidgetCallback? = null ) : RecyclerView.Adapter() { @SuppressLint("NotifyDataSetChanged") @@ -50,6 +52,7 @@ class EmiStatusCalendarAdapter( val emiInstallment = emiCalendar[position] binding.emiInstallment = emiInstallment + binding.widgetCallback = widgetCallback when (emiInstallment.status) { EmiStatus.PAID -> binding.emiStatusPaidView.root.visibility = View.VISIBLE EmiStatus.OVERDUE -> { diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/fragments/EmiStatusCalendarFragment.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/fragments/EmiStatusCalendarFragment.kt index 03fbf2ad40..bde22f2202 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/fragments/EmiStatusCalendarFragment.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/fragments/EmiStatusCalendarFragment.kt @@ -7,33 +7,50 @@ package com.naviapp.dashboard.loanapplicationdetails.emicalendar.fragments +import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.core.widget.NestedScrollView import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.base.model.* +import com.navi.common.listeners.FragmentInterchangeListener import com.navi.common.ui.fragment.BaseFragment +import com.navi.common.utils.observeNonNull import com.navi.common.utils.observeNullable +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.models.response.BottomSheetInfoV2 +import com.navi.naviwidgets.models.response.TextFieldData +import com.navi.naviwidgets.widgets.textdisplay.Margin import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.common.fragment.InfoBottomSheetV3 import com.naviapp.dashboard.loanapplicationdetails.emicalendar.adapters.EmiStatusCalendarAdapter import com.naviapp.dashboard.loanapplicationdetails.emicalendar.models.* +import com.naviapp.dashboard.loanapplicationdetails.emicalendar.states.OnScrollState import com.naviapp.dashboard.loanapplicationdetails.emicalendar.viewmodel.EmiViewModel import com.naviapp.databinding.EmiStatusCalendarFragmentBinding +import com.naviapp.utils.Constants import com.naviapp.utils.Constants.HOME_LOAN_TITLE import com.naviapp.utils.Constants.WIDGET_ID import com.naviapp.utils.LOAN_ACCOUNT_NUMBER import com.naviapp.utils.formatCurrency import com.naviapp.utils.getOrdinal +import com.naviapp.utils.setMargin +import kotlinx.coroutines.launch class EmiStatusCalendarFragment : BaseFragment() { private lateinit var binding: EmiStatusCalendarFragmentBinding private var loanAccountNumber: String? = null private var loanPreClosureData: EmiInstallment? = null private var pageNumber: Int = 0 - private val viewModel by lazy { ViewModelProvider(this).get(EmiViewModel::class.java) } + private val viewModel by lazy { ViewModelProvider(this)[EmiViewModel::class.java] } + private var repoRateBottomSheet: BottomSheetInfoV2? = null + private lateinit var widgetCallback: WidgetCallback override fun onCreateView( inflater: LayoutInflater, @@ -49,16 +66,28 @@ class EmiStatusCalendarFragment : BaseFragment() { } private fun initObservers() { + viewModel.emiCalendarResponse.observeNonNull(viewLifecycleOwner) { emiCalendarResponse -> + (emiCalendarResponse.metadata + ?.get(Constants.MetaDataKey.METADATA_REPO_RATE_BOTTOM_SHEET.value) + ?.data as? BottomSheetInfoV2) + ?.let { repoRateBottomSheet = it } + } viewModel.emis.observeNullable(viewLifecycleOwner) { emiList -> if (binding.emiCalendarRv.adapter == null) { binding.emiCalendarRv.visibility = View.VISIBLE binding.emiCalendarRv.adapter = - EmiStatusCalendarAdapter(getEmiCalendar(emiList, loanPreClosureData), context) + EmiStatusCalendarAdapter( + getEmiCalendar(emiList, loanPreClosureData), + context, + widgetCallback + ) arguments?.getString(WIDGET_ID)?.let { id -> if (HOME_LOAN_TITLE.contains(id, true)) { - binding.emiTitleTv.visibility = View.VISIBLE + if(binding.preEmiTitleTv.isVisible){ + binding.emiTitleTv.visibility = View.VISIBLE + binding.emiTitleTv.text = arguments?.getString(EMI_TITLE) + } binding.emiCalanderNotesTv.visibility = View.VISIBLE - binding.emiTitleTv.text = arguments?.getString(EMI_TITLE) binding.emiCalanderNotesTv.text = arguments?.getString(EMI_CALENDAR_NOTES) } } @@ -85,6 +114,30 @@ class EmiStatusCalendarFragment : BaseFragment() { } } } + + viewLifecycleOwner.lifecycleScope.launchWhenStarted { + launch { + viewModel.showOnScrollLoader.collect { + setOnScrollState(it) + } + } + } + } + + private fun setOnScrollState(onScrollState: OnScrollState) { + when (onScrollState) { + OnScrollState.Init -> {} + OnScrollState.Loading -> { + binding.onScrollDivider.visibility = View.VISIBLE + binding.emiNoteTv.setMargin(Margin(topDp = 8f)) + binding.onScrollLoader.visibility = View.VISIBLE + } + OnScrollState.Failure, OnScrollState.Completed -> { + binding.onScrollDivider.visibility = View.GONE + binding.emiNoteTv.setMargin(Margin(topDp = 20f)) + binding.onScrollLoader.visibility = View.GONE + } + } } private fun fetchEmi(page: Int) { @@ -117,6 +170,41 @@ class EmiStatusCalendarFragment : BaseFragment() { ) } initEmiPagination() + + widgetCallback = + object : WidgetCallback { + override fun onClick(naviClickAction: NaviClickAction) { + if (naviClickAction is CtaData) { + when (naviClickAction.url) { + CtaType.INFO_BOTTOM_SHEET_V3.name -> { + repoRateBottomSheet?.run { + if (!isBottomSheetVisible(InfoBottomSheetV3.TAG)) { + val bottomSheet = InfoBottomSheetV3.getInstance(this) + safelyShowBottomSheet(bottomSheet, InfoBottomSheetV3.TAG) + } + } + } + else -> { + val bundle = Bundle() + naviClickAction.parameters?.forEach { + bundle.putString(it.key, it.value) + } + naviClickAction.url?.let { + fragmentInterchangeListener?.navigateToNextScreen(it, bundle) + } + } + } + } + } + + override fun widgetAnalytics(analyticsEvent: AnalyticsEvent?) { + super.widgetAnalytics(analyticsEvent) + } + + override fun widgetAnalytics(genericAnalyticsData: GenericAnalyticsData?) { + super.widgetAnalytics(genericAnalyticsData) + } + } } private fun initEmiPagination() { @@ -189,8 +277,8 @@ class EmiStatusCalendarFragment : BaseFragment() { private fun getStatusCardDetails(statusDetails: StatusCard): DescExpandableItemBinder { return DescExpandableItemBinder( - statusDetails.title, - statusDetails.description, + TextFieldData(text = statusDetails.title), + TextFieldData(text = statusDetails.description), statusDetails.iconCode, eventName = statusDetails.eventName, cardType = STATUS_CARD @@ -199,13 +287,18 @@ class EmiStatusCalendarFragment : BaseFragment() { private fun getMessageCardDetails(messageCard: MessageCard): DescExpandableItemBinder { return DescExpandableItemBinder( - messageCard.title?.text, - messageCard.description?.text, + messageCard.title, + messageCard.description, messageCard.leftIcon?.iconCode, cardType = MESSAGE_CARD ) } + override fun onAttach(context: Context) { + super.onAttach(context) + fragmentInterchangeListener = context as? FragmentInterchangeListener + } + override val screenName: String get() = NaviAnalytics.EMI_STATUS_CALENDAR_FRAGMENT diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/models/EmiCalendarResponse.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/models/EmiCalendarResponse.kt index fc41939d84..8bd98cfec5 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/models/EmiCalendarResponse.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/models/EmiCalendarResponse.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -8,9 +8,11 @@ package com.naviapp.dashboard.loanapplicationdetails.emicalendar.models import com.google.gson.annotations.SerializedName +import com.navi.naviwidgets.models.ParameterValue data class EmiCalendarResponse( @SerializedName("emiCalendar") val emiCalendar: List? = null, @SerializedName("nextPage") val nextPage: Int? = null, - @SerializedName("lastPage") val lastPage: Boolean? = null + @SerializedName("lastPage") val lastPage: Boolean? = null, + @SerializedName("metadata") var metadata: MutableMap? = null ) diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/models/EmiInstallment.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/models/EmiInstallment.kt index 0a00dd2ebe..1fefcff10e 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/models/EmiInstallment.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/models/EmiInstallment.kt @@ -71,8 +71,8 @@ data class DueDetailBinder( ) data class DescExpandableItemBinder( - val infoTitle: String? = null, - val infoDescription: String? = null, + val infoTitle: TextFieldData? = null, + val infoDescription: TextFieldData? = null, val infoIcon: String? = null, val collapsibleIcon: String? = null, val eventName: String? = null, diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/states/OnScrollState.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/states/OnScrollState.kt new file mode 100644 index 0000000000..2a76107817 --- /dev/null +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/states/OnScrollState.kt @@ -0,0 +1,15 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.dashboard.loanapplicationdetails.emicalendar.states + +sealed class OnScrollState { + object Init : OnScrollState() + object Loading : OnScrollState() + object Failure : OnScrollState() + object Completed : OnScrollState() +} diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/viewmodel/EmiViewModel.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/viewmodel/EmiViewModel.kt index a794bae9fa..851d11e477 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/viewmodel/EmiViewModel.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/emicalendar/viewmodel/EmiViewModel.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -13,6 +13,9 @@ import com.navi.common.viewmodel.BaseVM import com.naviapp.dashboard.loanapplicationdetails.emicalendar.models.EmiCalendarResponse import com.naviapp.dashboard.loanapplicationdetails.emicalendar.models.EmiInstallment import com.naviapp.dashboard.loanapplicationdetails.emicalendar.repo.EmiRepository +import com.naviapp.dashboard.loanapplicationdetails.emicalendar.states.OnScrollState +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch class EmiViewModel(private val repository: EmiRepository = EmiRepository()) : BaseVM() { @@ -21,19 +24,35 @@ class EmiViewModel(private val repository: EmiRepository = EmiRepository()) : Ba get() = _emis private val _emiDetails = MutableLiveData() + val emiCalendarResponse: LiveData + get() = _emiDetails + + private var _showOnScrollLoader = MutableStateFlow(OnScrollState.Init) + val showOnScrollLoader = _showOnScrollLoader.asStateFlow() private var isLoading: Boolean = false fun fetchEmi(accountNumber: String, page: Int, size: Int) { + val isOnScroll = page >= 1 coroutineScope.launch { isLoading = true + if(isOnScroll) { + _showOnScrollLoader.emit(OnScrollState.Loading) + } val response = repository.fetchEmi(accountNumber, page, size) if (response.error == null && response.errors.isNullOrEmpty()) { _emiDetails.value = response.data _emis.value = response.data?.emiCalendar + if(isOnScroll) { + _showOnScrollLoader.emit(OnScrollState.Completed) + } } else { setErrorData(response.errors, response.error) + if(isOnScroll) { + _showOnScrollLoader.emit(OnScrollState.Failure) + } } + isLoading = false } } @@ -45,4 +64,4 @@ class EmiViewModel(private val repository: EmiRepository = EmiRepository()) : Ba fun shouldLoadMore(): Boolean { return isLastPage().not() && isLoading.not() } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/models/LoanApplicationDetails.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/models/LoanApplicationDetails.kt index b955ec7bec..27683a07d7 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/models/LoanApplicationDetails.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/models/LoanApplicationDetails.kt @@ -55,7 +55,8 @@ data class LoanApplicationDetails( val interestCertificateFinancialYears: ArrayList? = null, @SerializedName("enableInstallmentRequest") val enableInstallmentRequest: Boolean? = null, @SerializedName("emiInfo") val emiInfo: AlertInfoWidget? = null, - @SerializedName("documentList") val documentList: DocumentListButton? = null + @SerializedName("documentList") val documentList: DocumentListButton? = null, + @SerializedName("repoRateDetails") val repoRateDetails: RowsWithFooterWidget? = null ) : Parcelable @Parcelize diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/repositories/TrancheDisbursalRepository.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/repositories/TrancheDisbursalRepository.kt index 1fd26d2cfd..ccf58c6c2d 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/repositories/TrancheDisbursalRepository.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/repositories/TrancheDisbursalRepository.kt @@ -7,7 +7,7 @@ package com.naviapp.dashboard.loanapplicationdetails.repositories -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult import com.naviapp.dashboard.loanapplicationdetails.models.RequestInstallmentDetails import com.naviapp.dashboard.loanapplicationdetails.models.RequestInstallmentResponse import com.naviapp.dashboard.loanapplicationdetails.models.TrancheDisbursalResponse diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/tranche_disbursal/RequestInstallmentFragment.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/tranche_disbursal/RequestInstallmentFragment.kt index 8099580316..90fc44ccde 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/tranche_disbursal/RequestInstallmentFragment.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/tranche_disbursal/RequestInstallmentFragment.kt @@ -28,8 +28,8 @@ import com.navi.common.awsupload.FileUploadManager import com.navi.common.awsupload.model.UploadState import com.navi.common.awsupload.model.UploadTask import com.navi.common.model.Action -import com.navi.common.model.AssetDetails -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.AssetDetails +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.activity.BaseActivity import com.navi.common.ui.fragment.ActionErrorFragment import com.navi.common.ui.fragment.BaseFragment @@ -63,7 +63,6 @@ import java.util.* import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch @ExperimentalCoroutinesApi diff --git a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/viewmodels/RequestInstallmentFragmentVM.kt b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/viewmodels/RequestInstallmentFragmentVM.kt index 9674a6d1cd..b8299fcf05 100644 --- a/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/viewmodels/RequestInstallmentFragmentVM.kt +++ b/app/src/main/java/com/naviapp/dashboard/loanapplicationdetails/viewmodels/RequestInstallmentFragmentVM.kt @@ -11,8 +11,8 @@ import android.os.Bundle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.navi.analytics.utils.NaviTrackEvent -import com.navi.common.model.GenericErrorResponse import com.navi.common.network.models.ErrorMessage +import com.navi.common.network.models.GenericErrorResponse import com.naviapp.dashboard.loanapplicationdetails.models.RequestInstallmentDetails import com.naviapp.dashboard.loanapplicationdetails.models.RequestInstallmentResponse import com.naviapp.dashboard.loanapplicationdetails.models.TrancheDisbursalResponse diff --git a/app/src/main/java/com/naviapp/digitalgold/di/DigitalGoldModule.kt b/app/src/main/java/com/naviapp/digitalgold/di/DigitalGoldModule.kt new file mode 100644 index 0000000000..5ff01ea356 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/di/DigitalGoldModule.kt @@ -0,0 +1,47 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.di + +import com.naviapp.digitalgold.repo.DigitalGoldBuyRepo +import com.naviapp.digitalgold.repo.DigitalGoldHomeRepo +import com.naviapp.digitalgold.repo.DigitalGoldSellRepo +import com.naviapp.digitalgold.repo.DigitalGoldTransactionRepo +import com.naviapp.network.di.SuperAppRetroFit +import com.naviapp.network.retrofit.RetrofitService +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent +import dagger.hilt.android.scopes.ViewModelScoped + +@Module +@InstallIn(ViewModelComponent::class) +object DigitalGoldModule { + + @ViewModelScoped + @Provides + fun providesGoldHomeRepo(@SuperAppRetroFit retrofitService: RetrofitService) = + DigitalGoldHomeRepo(retrofitService) + + @ViewModelScoped + @Provides + fun providesGoldSellRepo(@SuperAppRetroFit retrofitService: RetrofitService) = + DigitalGoldSellRepo(retrofitService) + + @ViewModelScoped + @Provides + fun providesGoldBuyRepo(@SuperAppRetroFit retrofitService: RetrofitService) = + DigitalGoldBuyRepo(retrofitService) + + @ViewModelScoped + @Provides + fun providesDigitalGoldTransaction(@SuperAppRetroFit retrofitService: RetrofitService) = + DigitalGoldTransactionRepo(retrofitService) +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/model/DigitalGoldPollingResponse.kt b/app/src/main/java/com/naviapp/digitalgold/model/DigitalGoldPollingResponse.kt new file mode 100644 index 0000000000..a3a58ffbb2 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/model/DigitalGoldPollingResponse.kt @@ -0,0 +1,24 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.model + +import com.google.gson.annotations.SerializedName +import com.naviapp.models.PaymentCheckResponse +import com.naviapp.payment.models.PaymentRequest + +data class DigitalGoldPollingResponse( + @SerializedName("status") + val status: String? = null, + @SerializedName("paymentRequest") + val paymentRequest: PaymentRequest? = null, + @SerializedName("paymentCheckResponse") + val paymentCheckResponse: PaymentCheckResponse? = null, + +) diff --git a/app/src/main/java/com/naviapp/digitalgold/model/DigitalGoldSellUpiRequest.kt b/app/src/main/java/com/naviapp/digitalgold/model/DigitalGoldSellUpiRequest.kt new file mode 100644 index 0000000000..bf752fba70 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/model/DigitalGoldSellUpiRequest.kt @@ -0,0 +1,19 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.model + +import com.google.gson.annotations.SerializedName + +data class DigitalGoldSellUpiRequest( + @SerializedName("exchangeRateId") + val exchangeRateId: String? = null, + @SerializedName("amountInRupees") + val amountInRupees: Double? = null +) diff --git a/app/src/main/java/com/naviapp/digitalgold/model/GoldBuyOrderRequest.kt b/app/src/main/java/com/naviapp/digitalgold/model/GoldBuyOrderRequest.kt new file mode 100644 index 0000000000..cb189fd78a --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/model/GoldBuyOrderRequest.kt @@ -0,0 +1,21 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.model + +import com.google.gson.annotations.SerializedName + +data class GoldBuyOrderRequest( + @SerializedName("amount") + val amount: Double? = null, + @SerializedName("exchangeRateId") + val exchangeRateId: String? = null, + @SerializedName("source") + val source: String? = null +) diff --git a/app/src/main/java/com/naviapp/digitalgold/model/GoldSellOrderRequest.kt b/app/src/main/java/com/naviapp/digitalgold/model/GoldSellOrderRequest.kt new file mode 100644 index 0000000000..49d59f5e72 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/model/GoldSellOrderRequest.kt @@ -0,0 +1,21 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.model + +import com.google.gson.annotations.SerializedName + +data class GoldSellOrderRequest( + @SerializedName("amount") + val amount: Double? = null, + @SerializedName("exchangeRateId") + val exchangeRateId: String? = null, + @SerializedName("upiId") + val upiId: String? = null +) diff --git a/app/src/main/java/com/naviapp/digitalgold/model/GoldSellOrderResponse.kt b/app/src/main/java/com/naviapp/digitalgold/model/GoldSellOrderResponse.kt new file mode 100644 index 0000000000..fc1f5a8f45 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/model/GoldSellOrderResponse.kt @@ -0,0 +1,25 @@ +package com.naviapp.digitalgold.model + +import com.google.gson.annotations.SerializedName +import com.navi.base.model.BottomSheetData +import com.navi.common.model.RequestConfig +import com.naviapp.payment.models.PaymentRequest + +data class GoldSellOrderResponse( + @SerializedName("requestId") + val requestId: String? = null, + @SerializedName("notificationPath") + val notificationPath: String? = null, + @SerializedName("requestConfig") + val requestConfig: RequestConfig? = null, + @SerializedName("bottomSheetData") + val bottomSheetData: BottomSheetData? = null, + @SerializedName("status") + val status: String? = null, + @SerializedName("expired") + val expired: Boolean? = false, + @SerializedName("paymentRequest") + val paymentRequest: PaymentRequest? = null, + @SerializedName("isValidUpiId") + val inValidUpiId: Boolean? = false +) diff --git a/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldBuyRepo.kt b/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldBuyRepo.kt new file mode 100644 index 0000000000..0c7cb41da2 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldBuyRepo.kt @@ -0,0 +1,40 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.repo + +import com.naviapp.digitalgold.model.GoldBuyOrderRequest +import com.naviapp.models.PgRepaymentData +import com.naviapp.models.request.AmountDataRequest +import com.naviapp.network.retrofit.ResponseCallback +import com.naviapp.network.retrofit.RetrofitService +import javax.inject.Inject + +class DigitalGoldBuyRepo @Inject constructor(private val retrofitService: RetrofitService) : + ResponseCallback() { + + + suspend fun fetchDigitalGoldBuyDetails(amount: Double) = + apiResponseCallback(retrofitService.fetchDigitalGoldBuyDetails(AmountDataRequest(amount = amount))) + + suspend fun fetchBuyOrderResponse(goldBuyOrderRequest: GoldBuyOrderRequest) = + apiResponseCallback(retrofitService.getDigitalGoldBuyOrder(goldBuyOrderRequest)) + + suspend fun startSdkCredPolling(requestId: String) = + apiResponseCallback(retrofitService.getDigitalGoldSdkCred(requestId)) + + suspend fun postPaymentData(pgRepaymentData: PgRepaymentData) = + apiResponseCallback(retrofitService.digitalGoldSdkStatus(pgRepaymentData)) + + suspend fun startPaymentPolling(requestId: String) = + apiResponseCallback(retrofitService.digitalGoldPaymentPolling(requestId)) + + suspend fun fetchPaymentPollingUIData(requestId: String) = + apiResponseCallback(retrofitService.digitalGoldPollingUIData(requestId)) +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldHomeRepo.kt b/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldHomeRepo.kt new file mode 100644 index 0000000000..ca74e8b817 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldHomeRepo.kt @@ -0,0 +1,24 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.repo + +import com.naviapp.network.retrofit.ResponseCallback +import com.naviapp.network.retrofit.RetrofitService +import javax.inject.Inject + +class DigitalGoldHomeRepo @Inject constructor(private val superAppRetrofitService: RetrofitService) : + ResponseCallback() { + + suspend fun fetchDigitalGoldHomeDetails() = + apiResponseCallback(superAppRetrofitService.getDigitalGoldHome()) + + suspend fun fetchDigitalGoldHomeDetailsPolling() = + apiResponseCallback(superAppRetrofitService.getDigitalGoldHomePolling()) +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldSellRepo.kt b/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldSellRepo.kt new file mode 100644 index 0000000000..592b8ab9c1 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldSellRepo.kt @@ -0,0 +1,41 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.repo + +import com.naviapp.digitalgold.model.GoldSellOrderRequest +import com.naviapp.network.retrofit.ResponseCallback +import com.naviapp.network.retrofit.RetrofitService +import javax.inject.Inject + +class DigitalGoldSellRepo @Inject constructor(private val superAppRetrofitService: RetrofitService) : + ResponseCallback() { + + suspend fun fetchDigitalGoldSellDetails() = + apiResponseCallback(superAppRetrofitService.getDigitalGoldSellPage()) + + suspend fun fetchSellOrderResponse(goldSellOrderRequest: GoldSellOrderRequest) = + apiResponseCallback(superAppRetrofitService.getDigitalGoldSellOrder(goldSellOrderRequest = goldSellOrderRequest)) + + suspend fun startPaymentPolling(requestId: String) = + apiResponseCallback(superAppRetrofitService.digitalGoldPaymentPolling(requestId = requestId)) + + suspend fun fetchPaymentPollingUIData(requestId: String) = + apiResponseCallback(superAppRetrofitService.digitalGoldPollingUIData(requestId = requestId)) + + suspend fun fetchUpiScreenDetails( + exchangeRateId: String, + amount: Double + ) = apiResponseCallback( + superAppRetrofitService.fetchDigitalGoldSellUpiScreenData( + exchangeRateId = exchangeRateId, + amount = amount + ) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldTransactionRepo.kt b/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldTransactionRepo.kt new file mode 100644 index 0000000000..59abbbb649 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/repo/DigitalGoldTransactionRepo.kt @@ -0,0 +1,22 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.repo + +import com.naviapp.network.retrofit.ResponseCallback +import com.naviapp.network.retrofit.RetrofitService +import javax.inject.Inject + +class DigitalGoldTransactionRepo @Inject constructor(private val retrofitService: RetrofitService) : + ResponseCallback() { + + suspend fun fetchDigitalGoldTransactionDetails() = + apiResponseCallback(retrofitService.fetchDigitalGoldTransactionHistory()) + +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldBuyActivity.kt b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldBuyActivity.kt new file mode 100644 index 0000000000..479c84aa1c --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldBuyActivity.kt @@ -0,0 +1,558 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.ui + +import android.os.Bundle +import android.text.TextUtils +import android.view.View +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.base.model.ActionData +import com.navi.base.model.BottomSheetData +import com.navi.base.model.NaviClickAction +import com.navi.base.model.NaviWidgetClickWithActionData +import com.navi.common.extensions.isNotNull +import com.navi.common.extensions.isNotNullAndNotEmpty +import com.navi.common.firebasedb.* +import com.navi.common.listeners.NewBottomSheetListener +import com.navi.common.model.ModuleNameV2 +import com.navi.common.ui.activity.BaseActivity +import com.navi.common.ui.fragment.NewCommonBottomSheet +import com.navi.common.utils.ApiPollScheduler +import com.navi.common.utils.Constants.REFRESH +import com.navi.common.utils.observeNonNull +import com.navi.common.utils.toCtaData +import com.navi.naviwidgets.actions.PaymentWidgetClickAction +import com.navi.naviwidgets.adapters.NaviAdapter +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.extensions.showWhenDataIsAvailable +import com.navi.naviwidgets.models.ContainerWidget +import com.navi.naviwidgets.models.TextWithTimerWidget +import com.navi.naviwidgets.models.WidgetChangedData +import com.navi.naviwidgets.utils.WIDGET_STATE_CHANGE +import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.analytics.utils.NaviAnalytics.Companion.DIGITAL_GOLD_BUY_SCREEN +import com.naviapp.common.fragment.PaymentCheckFragment +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.databinding.ActivityDigitalGoldBuyBinding +import com.naviapp.digitalgold.model.DigitalGoldPollingResponse +import com.naviapp.digitalgold.model.GoldSellOrderResponse +import com.naviapp.digitalgold.viewmodels.DigitalGoldBuyVM +import com.naviapp.home.model.WidgetResponse +import com.naviapp.models.PaymentCheckResponse +import com.naviapp.models.PgRepaymentData +import com.naviapp.payment.factories.PaymentProviderFactory +import com.naviapp.payment.models.PaymentRequest +import com.naviapp.payment.models.ProviderType +import com.naviapp.payment.razorpay.RazorpayPayment +import com.naviapp.utils.AMOUNT_DATA +import com.naviapp.utils.Constants.APP +import com.naviapp.utils.Constants.BUY_GOLD +import com.naviapp.utils.Constants.COMMON_BOTTOM_SHEET_ID +import com.naviapp.utils.Constants.SHOW_BOTTOM_SHEET +import com.razorpay.PaymentData +import com.razorpay.PaymentResultWithDataListener +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class DigitalGoldBuyActivity : BaseActivity(), WidgetCallback, NewBottomSheetListener, + PaymentResultWithDataListener { + + private lateinit var binding: ActivityDigitalGoldBuyBinding + private val widgetNaviAnalyticsEventTracker = NaviAnalytics.naviAnalytics.Widget() + private val viewModel by lazy { ViewModelProvider(this)[DigitalGoldBuyVM::class.java] } + private lateinit var commonBottomSheet: NewCommonBottomSheet + private val naviAdapter = NaviAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + private val naviFooterAdapter = NaviAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + private var provider: Any? = null + private var firebaseDataReceiveListener: FirebaseDataReceiveListener? = null + private var apiPollScheduler: ApiPollScheduler? = null + private var firebaseDataHelper: FirebaseDataHelper? = null + private var errorTag: String? = null + private val onPollingEnd = { + handleTimeOutError(errorTag.orEmpty()) + } + private val pollingTimeoutClickListener: View.OnClickListener = View.OnClickListener { + fetchDigitalBuyPageDetails() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView( + this, + R.layout.activity_digital_gold_buy + ) + setContentView(binding.root) + initUI() + initObserver() + getPaymentProvider() + initError( + viewModel = viewModel, + dialogDismissClicked = { + fetchDigitalBuyPageDetails() + }, + showFullScreenError = true, + dialogOnBackPressed = { fetchDigitalBuyPageDetails() } + ) + fetchDigitalBuyPageDetails() + } + + private fun initUI() { + binding.apply { + rvGoldItems.apply { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + adapter = naviAdapter + } + rvGoldFooterItems.apply { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + adapter = naviFooterAdapter + } + ivBack.setOnClickListener { + finish() + } + } + } + + private fun initObserver() { + lifecycleScope.launchWhenResumed { + viewModel.digitalGoldBuyWidgets.observeNonNull(this@DigitalGoldBuyActivity) { widgetResponse -> + stopShimmer() + processHeader(widgetResponse) + widgetResponse.contentWidget?.let { listOfWidgets -> + naviAdapter.setData(listOfWidgets) + } + widgetResponse.footerWidget?.let { listOfFooterWidgets -> + naviFooterAdapter.setData(listOfFooterWidgets) + } + } + viewModel.goldBuyOrderResponse.observeNonNull(this@DigitalGoldBuyActivity) { goldBuyOrderResponse -> + handleBuyOrderResponse(goldBuyOrderResponse) + } + viewModel.sdkCredPollingData.observeNonNull(this@DigitalGoldBuyActivity) { pollingData -> + handlePollingData(pollingData.status.orEmpty(), pollingData, true) + } + viewModel.paymentPollingData.observeNonNull(this@DigitalGoldBuyActivity) { pollingData -> + handlePollingData( + pollingData.status.orEmpty(), + pollingData, + sdkCredPollingData = false + ) + } + viewModel.postPaymentStatus.observeNonNull(this@DigitalGoldBuyActivity) { + viewModel.postPaymentData(it) + } + viewModel.postPaymentResponse.observeNonNull(this@DigitalGoldBuyActivity) { + startPolling( + needFirebasePolling = true, + notificationPath = viewModel.goldBuyOrderResponse.value?.notificationPath, + goldSellOrderResponse = viewModel.goldBuyOrderResponse.value, + paymentStatusPolling = true + ) + } + viewModel.digitalGoldPollingUIData.observeNonNull(this@DigitalGoldBuyActivity) { + if (::commonBottomSheet.isInitialized && commonBottomSheet.isNotNull()) { + commonBottomSheet.safelyDismissDialog() + } + navigateToNextScreen(it) + } + } + } + + private fun navigateToNextScreen(paymentCheckResponse: PaymentCheckResponse) { + val bundle = Bundle() + bundle.putParcelable(PaymentCheckFragment.DATA, paymentCheckResponse) + safelyOpenFragment( + PaymentCheckFragment.newInstance(bundle), + PaymentCheckFragment.TAG + ) + } + + private fun getPaymentProvider() { + provider = PaymentProviderFactory.getPaymentProvider(ProviderType.RAZORPAY) + if (provider is RazorpayPayment?) { + (provider as? RazorpayPayment)?.initializeRazorpay(this) + } + } + + private fun processHeader(response: WidgetResponse?) { + response?.header?.let { + it.title?.let { title -> + it.leftIconCode?.let { leftIconCode -> + binding.ivBack.showWhenDataIsAvailable(leftIconCode) + binding.tvTitle.showWhenDataIsAvailable(title) + } + } + binding.clHeaderView.isVisible = true + binding.tvHelp.isVisible = it.enableHelp == true + } + } + + private fun toOpenBottomSheet(url: String?): Boolean { + url?.let { + return url.contains(SHOW_BOTTOM_SHEET, true) + } ?: run { + return false + } + } + + private fun showCommonBottomSheet(bottomSheetData: BottomSheetData) { + try { + if (::commonBottomSheet.isInitialized && commonBottomSheet.isNotNull()) { + commonBottomSheet.safelyDismissDialog() + } + commonBottomSheet = NewCommonBottomSheet.getInstance( + bottomSheetData + ) + commonBottomSheet.setListener(this@DigitalGoldBuyActivity) + safelyShowBottomSheet(commonBottomSheet, NewCommonBottomSheet.TAG) + } catch (e: Exception) { + } + + } + + private fun toShowBottomSheet(action: ActionData?) { + val splitDeepLink = action?.url?.split("/") + when (splitDeepLink?.getOrNull(1)) { + COMMON_BOTTOM_SHEET_ID -> { + action.bottomSheetData?.let { + showCommonBottomSheet(it) + } + } + } + } + + override fun getLifeCycle(): Lifecycle = lifecycle + + override fun onClick(naviClickAction: NaviClickAction) { + when (naviClickAction) { + is NaviWidgetClickWithActionData -> { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent( + naviClickAction.actionData, + screenName + ) + if (toOpenBottomSheet(naviClickAction.actionData?.url)) { + toShowBottomSheet(naviClickAction.actionData) + return + } + naviClickAction.actionData?.let { + NaviDeepLinkNavigator.navigate( + this, + it.toCtaData(), + finish = naviClickAction.isFinish + ) + } + } + is PaymentWidgetClickAction -> { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent( + naviClickAction.actionData, + screenName + ) + if (toOpenBottomSheet(naviClickAction.actionData.url)) { + toShowBottomSheet(naviClickAction.actionData) + return + } else if (naviClickAction.actionData.url.equals(BUY_GOLD)) { + stopTimer() + fetchBuyOrderResponse() + return + } + naviClickAction.actionData.let { + NaviDeepLinkNavigator.navigate( + this, + it.toCtaData() + ) + } + } + } + } + + private fun showShimmer() { + binding.shimmerLayout.startShimmer() + binding.shimmerLayout.isVisible = true + binding.group.isVisible = false + } + + private fun stopShimmer() { + binding.shimmerLayout.stopShimmer() + binding.shimmerLayout.isVisible = false + binding.group.isVisible = true + } + + private fun fetchDigitalBuyPageDetails() { + if (::commonBottomSheet.isInitialized && commonBottomSheet.isNotNull()) { + commonBottomSheet.safelyDismissDialog() + } + showShimmer() + intent?.extras?.let { viewModel.fetchDigitalGoldBuyDetails(it.getDouble(AMOUNT_DATA, 0.0)) } + } + + private fun fetchBuyOrderResponse() { + viewModel.digitalGoldBuyWidgets.value?.extraData?.let { + it.totalAmount?.let { it1 -> + it.exchangeRateId?.let { it2 -> + showLoader() + viewModel.fetchBuyOrderResponse( + amount = it1, + exchangeRateId = it2, + source = APP + ) + } + } + } + } + + private fun handleBuyOrderResponse(goldSellOrderResponse: GoldSellOrderResponse? = null) { + if (goldSellOrderResponse?.expired == false) { + startPolling( + needFirebasePolling = false, + goldSellOrderResponse = goldSellOrderResponse, + paymentStatusPolling = false + ) + } else { + hideLoader() + goldSellOrderResponse?.bottomSheetData?.let { showCommonBottomSheet(it) } + } + + } + + private fun stopTimer() { + naviFooterAdapter.list.forEachIndexed { index, naviBaseAdapterModel -> + if (naviBaseAdapterModel is ContainerWidget) { + val itemsOfContainerWidget = naviBaseAdapterModel.widgetData?.items + var textWithTimerWidget: TextWithTimerWidget? = null + itemsOfContainerWidget?.forEach { item -> + if (item is TextWithTimerWidget) { + textWithTimerWidget = item + item.widgetData?.stopTimer = true + } + } + naviFooterAdapter.notifyItemChanged( + index, + WidgetChangedData(WIDGET_STATE_CHANGE, textWithTimerWidget) + ) + } + } + } + + private fun startRazorpaySdk(paymentRequestData: PaymentRequest? = null) { + paymentRequestData?.let { data -> + if (provider is RazorpayPayment?) { + (provider as? RazorpayPayment)?.startPayment( + data, + this, + paymentRequestData.key.orEmpty() + ) + } + } + } + + private fun startPolling( + needFirebasePolling: Boolean? = true, + notificationPath: String? = null, + goldSellOrderResponse: GoldSellOrderResponse? = null, + paymentStatusPolling: Boolean + ) { + goldSellOrderResponse?.let { + if (needFirebasePolling == true && notificationPath.isNotNullAndNotEmpty()) { + firebaseInit( + requestId = goldSellOrderResponse.requestId.orEmpty(), + type = DIGITAL_GOLD_PAYMENT, + notificationPath = notificationPath.orEmpty() + ) + } + apiPollInit( + requestId = goldSellOrderResponse.requestId.orEmpty(), + type = DIGITAL_GOLD_PAYMENT, + initialDelay = goldSellOrderResponse.requestConfig?.initialDelay?.toLong() + ?: ApiPollScheduler.INITIAL_DELAY_FOR_API_POLL_SECONDS, + pollInterval = goldSellOrderResponse.requestConfig?.interval?.toLong() + ?: ApiPollScheduler.API_POLL_REPEAT_PERIOD_SECONDS, + noOfRetry = goldSellOrderResponse.requestConfig?.numOfRetries + ?: ApiPollScheduler.API_POLL_RETRY_COUNT, + paymentStatusPolling + ) + } + } + + private fun handlePollingData( + status: String, + digitalGoldPollingResponse: DigitalGoldPollingResponse? = null, + sdkCredPollingData: Boolean + ) { + if (TextUtils.equals( + status, + FirebaseStatusType.SUCCESS + ) + || TextUtils.equals( + status, + FirebaseStatusType.FAILURE + ) + ) { + deInitializeFirebaseListener() + apiPollScheduler?.stopApiPoll() + hideLoader() + if (sdkCredPollingData) { + startRazorpaySdk(digitalGoldPollingResponse?.paymentRequest) + } else { + viewModel.fetchPaymentPollingUIData( + requestId = viewModel.goldBuyOrderResponse.value?.requestId.orEmpty() + ) + } + } + } + + private fun firebaseInit( + requestId: String, + type: String, + notificationPath: String + ) { + firebaseDataReceiveListener = object : FirebaseDataReceiveListener { + override fun onDataReceive(firebaseResponse: FirebaseResponse?) { + firebaseResponse?.let { + apiPollScheduler?.stopApiPoll() + handlePollingData(firebaseResponse.status.orEmpty(), sdkCredPollingData = false) + } + } + } + firebaseDataHelper = null + firebaseDataHelper = FirebaseDataHelper() + firebaseDataHelper?.initFirebaseDataReceiver( + lifecycle, + firebaseDataReceiveListener, + type, + requestId, + notificationPath + ) + } + + private fun apiPollInit( + requestId: String, + type: String, + initialDelay: Long, + pollInterval: Long, + noOfRetry: Int, + paymentStatusPolling: Boolean + ) { + errorTag = type + apiPollScheduler = ApiPollScheduler( + initialDelay = initialDelay, + pollInterval = pollInterval, + numberOfRetry = noOfRetry, + doOnTimeout = onPollingEnd + ) { + if (paymentStatusPolling) { + viewModel.startPaymentPolling(requestId = requestId) + } else { + viewModel.startSdkCredPolling(requestId = requestId) + } + + } + apiPollScheduler?.scheduleApiPoll() + } + + private fun handleTimeOutError(errorTag: String) { + hideLoader() + if (::commonBottomSheet.isInitialized && commonBottomSheet.isNotNull()) { + commonBottomSheet.safelyDismissDialog() + } + showTimeoutErrorScreen( + firebaseDataHelper, + apiPollScheduler, + pollingTimeoutClickListener, + errorTag + ) + firebaseDataHelper = null + firebaseDataReceiveListener = null + } + + private fun deInitializeFirebaseListener() { + firebaseDataHelper?.clear() + firebaseDataHelper = null + firebaseDataReceiveListener = null + hideErrorScreen() + } + + override val screenName: String = DIGITAL_GOLD_BUY_SCREEN + override val moduleName: ModuleNameV2 = ModuleNameV2.COMMON + override fun buttonClick(actionData: ActionData?) { + actionData?.let { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent(actionData, screenName) + if (it.url.isNotNullAndNotEmpty()) { + if (toOpenBottomSheet(it.url)) { + toShowBottomSheet(it) + return + } + NaviDeepLinkNavigator.navigate( + this, + it.toCtaData() + ) + } else if (it.action.isNotNullAndNotEmpty()) { + when (it.action) { + REFRESH -> { + showShimmer() + hideLoader() + fetchDigitalBuyPageDetails() + } + } + } + } + } + + override fun onPaymentError(code: Int, description: String?, data: PaymentData?) { + pgRepaymentStatus(description, data, code) + } + + override fun onPaymentSuccess(description: String?, data: PaymentData?) { + pgRepaymentStatus(description, data) + } + + private fun pgRepaymentStatus( + description: String?, + data: PaymentData?, + code: Int? = null + ) { + CoroutineScope(Dispatchers.Main).launch { + showProcessingBottomSheet() + viewModel.setPostPaymentResponseStatus( + PgRepaymentData( + code = code, + description = description, + paymentReferenceId = data?.paymentId, + orderId = data?.orderId, + status = if (code == null) FirebaseStatusType.SUCCESS else FirebaseStatusType.FAILURE, + requestId = viewModel.goldBuyOrderResponse.value?.requestId + ) + ) + } + } + + private fun showProcessingBottomSheet() { + viewModel.digitalGoldBuyWidgets.value?.extraData?.loadingBottomSheet?.let { + showCommonBottomSheet( + it + ) + } + } +} + diff --git a/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldHomeActivity.kt b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldHomeActivity.kt new file mode 100644 index 0000000000..dc25fb8d86 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldHomeActivity.kt @@ -0,0 +1,315 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.ui + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.widget.Toast +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.base.model.ActionData +import com.navi.base.model.GenericAnalyticsData +import com.navi.base.model.NaviClickAction +import com.navi.base.model.NaviWidgetClickWithActionData +import com.navi.base.utils.BaseUtils +import com.navi.base.utils.isNotNull +import com.navi.common.downloader.DownloadUtil +import com.navi.common.listeners.NewBottomSheetListener +import com.navi.common.model.ModuleNameV2 +import com.navi.common.ui.activity.BaseActivity +import com.navi.common.ui.fragment.NewCommonBottomSheet +import com.navi.common.utils.observeNonNull +import com.navi.common.utils.toCtaData +import com.navi.design.utils.isNull +import com.navi.naviwidgets.actions.DownloadClickAction +import com.navi.naviwidgets.adapters.NaviAdapter +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.extensions.showWhenDataIsAvailable +import com.navi.naviwidgets.models.ContainerWidget +import com.navi.naviwidgets.models.GoldConversionWidget +import com.navi.naviwidgets.models.WidgetChangedData +import com.navi.naviwidgets.utils.STORE_DIGITAL_GOLD_AMOUNT +import com.navi.naviwidgets.utils.WIDGET_STATE_CHANGE +import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.analytics.utils.NaviAnalytics.Companion.DIGITAL_GOLD_HOME_SCREEN +import com.naviapp.analytics.utils.NaviAnalytics.Companion.SCREEN_NAME +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.databinding.ActivityDigitalGoldHomeBinding +import com.naviapp.digitalgold.viewmodels.DigitalGoldHomeVM +import com.naviapp.home.analytics.LandingScreenAnalytics +import com.naviapp.home.model.WidgetResponse +import com.naviapp.utils.AMOUNT_DATA +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.net.URI +import java.util.* + +@AndroidEntryPoint +class DigitalGoldHomeActivity : BaseActivity(), WidgetCallback, NewBottomSheetListener { + + private lateinit var binding: ActivityDigitalGoldHomeBinding + private val eventTracker = NaviAnalytics.naviAnalytics.DigitalGold() + private val widgetNaviAnalyticsEventTracker = NaviAnalytics.naviAnalytics.Widget() + private val viewModel by lazy { ViewModelProvider(this)[DigitalGoldHomeVM::class.java] } + private val naviAdapter = NaviAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + private var commonBottomSheet: NewCommonBottomSheet? = null + private var timer: Timer? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView( + this, + R.layout.activity_digital_gold_home + ) + setContentView(binding.root) + initUI() + initObserver() + initError( + viewModel = viewModel, + dialogDismissClicked = { + fetchDigitalHomePageDetails() + }, + showFullScreenError = true + ) + fetchDigitalHomePageDetails() + } + + private fun initUI() { + binding.apply { + rvGoldItems.apply { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + adapter = naviAdapter + } + ivBack.setOnClickListener { + eventTracker.onBackButtonClick() + finish() + } + } + } + + private fun showShimmer() { + binding.shimmerLayout.startShimmer() + binding.shimmerLayout.isVisible = true + binding.rvGoldItems.isVisible = false + binding.cvParent.isVisible = false + } + + private fun stopShimmer() { + binding.shimmerLayout.stopShimmer() + binding.shimmerLayout.isVisible = false + binding.rvGoldItems.isVisible = true + binding.cvParent.isVisible = true + } + + override fun widgetUserData(key: String, value: Any) { + when (key) { + STORE_DIGITAL_GOLD_AMOUNT -> { + viewModel.setActualSellAmount(value.toString().toDouble()) + } + } + } + + + private fun initObserver() { + lifecycleScope.launchWhenResumed { + viewModel.digitalGoldHomeWidgets.observeNonNull(this@DigitalGoldHomeActivity) { widgetResponse -> + stopShimmer() + processHeader(widgetResponse) + widgetResponse.contentWidget?.let { listOfWidgets -> + naviAdapter.setData(listOfWidgets) + } + startTimer() + } + viewModel.pollingData.observeNonNull(this@DigitalGoldHomeActivity) { + handlePollingData(it) + } + } + } + + private fun handlePollingData(response: WidgetResponse) { + response.contentWidget?.let { contentWidget -> + response.extraData?.pricePerMg?.let { + naviAdapter.list.forEachIndexed { index, naviWidget -> + if (naviWidget is ContainerWidget) { + val itemsOfContainerWidget = naviWidget.widgetData?.items + var goldContainerWidget: GoldConversionWidget? = null + itemsOfContainerWidget?.forEach { item -> + if (item is GoldConversionWidget && (item.widgetData?.actualAmount + ?: 0.0) > 0.0 + ) { + goldContainerWidget = item + goldContainerWidget?.widgetData?.pricePerMg = + it + } + } + naviAdapter.notifyItemChanged( + index, + WidgetChangedData(WIDGET_STATE_CHANGE, goldContainerWidget?.widgetData) + ) + } + } + } + + response.extraData?.updateWidgetPosition?.let { listOfPosition -> + CoroutineScope(Dispatchers.IO).launch { + delay(DELAY_TO_UPDATE_POLLING_DATA) + CoroutineScope(Dispatchers.Main).launch { + var updateWidgetIndex = 0 + val updatedWidgets = response.contentWidget + listOfPosition.forEach { index -> + if (index < naviAdapter.list.size && + updatedWidgets?.get(updateWidgetIndex).isNotNull() + ) { + if ( + updatedWidgets?.get(updateWidgetIndex)?.widgetNameForBaseAdapter == + naviAdapter.list[index].widgetNameForBaseAdapter + ) { + updatedWidgets?.get(updateWidgetIndex)?.let { widget -> + naviAdapter.updateItemAtIndexNotifyAll( + index, + widget + ) + } + } + } + updateWidgetIndex++ + } + } + } + } + } + } + + private fun processHeader(response: WidgetResponse?) { + response?.header?.let { + it.title?.let { title -> + it.leftIconCode?.let { leftIconCode -> + binding.ivBack.showWhenDataIsAvailable(leftIconCode) + binding.tvTitle.showWhenDataIsAvailable(title) + } + } + binding.clHeaderView.isVisible = true + binding.tvHelp.isVisible = it.enableHelp == true + } + } + + private fun fetchDigitalHomePageDetails() { + showShimmer() + viewModel.fetchDigitalGoldHomeDetails() + } + + override fun getLifeCycle(): Lifecycle = lifecycle + + override val screenName: String = DIGITAL_GOLD_HOME_SCREEN + + override val moduleName: ModuleNameV2 = ModuleNameV2.COMMON + + override fun buttonClick(actionData: ActionData?) { + commonBottomSheet?.dismiss() + } + + override fun widgetAnalytics(genericAnalyticsData: GenericAnalyticsData?) { + genericAnalyticsData?.let { data -> + val parameters: HashMap = + data.parameters ?: HashMap() + parameters[SCREEN_NAME] = screenName + LandingScreenAnalytics.sendEventsToClickStream( + data.eventName, + parameters + ) + } + } + + override fun onClick(naviClickAction: NaviClickAction) { + when (naviClickAction) { + is NaviWidgetClickWithActionData -> { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent( + naviClickAction.actionData, + screenName + ) + val bundle = Bundle() + bundle.putDouble(AMOUNT_DATA, viewModel.getActualSellAmount()) + naviClickAction.actionData?.let { + NaviDeepLinkNavigator.navigate( + this, + it.toCtaData(), + bundle = bundle, + finish = naviClickAction.isFinish + ) + } + } + is DownloadClickAction -> { + val destination = + BaseUtils.cacheDirUri( + this, + naviClickAction.fileName + ) + Toast.makeText(this, getString(R.string.downloading), Toast.LENGTH_SHORT).show() + DownloadUtil.download( + this, + Uri.parse(naviClickAction.url), + URI.create(destination) + ) + } + } + } + + override fun onResume() { + super.onResume() + startTimer() + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + fetchDigitalHomePageDetails() + } + + private fun startTimer() { + if (timer.isNull()) { + viewModel.digitalGoldHomeWidgets.value?.extraData?.delay?.let { + timer = Timer() + timer?.scheduleAtFixedRate(object : TimerTask() { + override fun run() { + viewModel.startPolling() + } + }, it, it) + } + } + } + + override fun onStop() { + super.onStop() + timer?.cancel() + timer = null + } + + override fun onDestroy() { + super.onDestroy() + timer?.cancel() + timer = null + } + + companion object { + private const val DELAY_TO_UPDATE_POLLING_DATA = 2000L + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellActivity.kt b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellActivity.kt new file mode 100644 index 0000000000..3fb03b5ee4 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellActivity.kt @@ -0,0 +1,535 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.ui + +import android.os.Bundle +import android.text.TextUtils +import android.view.View +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.base.model.ActionData +import com.navi.base.model.BottomSheetData +import com.navi.base.model.NaviClickAction +import com.navi.base.model.GenericAnalyticsData +import com.navi.base.model.NaviWidgetClickWithActionData +import com.navi.common.extensions.isNotNull +import com.navi.common.extensions.isNotNullAndNotEmpty +import com.navi.common.firebasedb.* +import com.navi.common.listeners.NewBottomSheetListener +import com.navi.common.model.ModuleNameV2 +import com.navi.common.ui.activity.BaseActivity +import com.navi.common.ui.fragment.BaseFragment +import com.navi.common.ui.fragment.NewCommonBottomSheet +import com.navi.common.utils.ApiPollScheduler +import com.navi.common.utils.Constants.REFRESH +import com.navi.common.utils.observeNonNull +import com.navi.common.utils.toCtaData +import com.navi.naviwidgets.actions.PaymentWidgetClickAction +import com.navi.naviwidgets.adapters.NaviAdapter +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.extensions.showWhenDataIsAvailable +import com.navi.naviwidgets.models.ContainerWidget +import com.navi.naviwidgets.models.PaymentWidget +import com.navi.naviwidgets.models.TextWithTimerWidget +import com.navi.naviwidgets.models.WidgetChangedData +import com.navi.naviwidgets.utils.WIDGET_STATE_CHANGE +import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.analytics.utils.NaviAnalytics.Companion.DIGITAL_GOLD_SELL_SCREEN +import com.naviapp.common.fragment.PaymentCheckFragment +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.databinding.ActivityDigitalGoldSellBinding +import com.naviapp.digitalgold.model.GoldSellOrderResponse +import com.naviapp.digitalgold.viewmodels.DigitalGoldSellSharedVM +import com.naviapp.digitalgold.viewmodels.DigitalGoldSellVM +import com.naviapp.home.analytics.LandingScreenAnalytics +import com.naviapp.models.PaymentCheckResponse +import com.naviapp.models.response.Header +import com.naviapp.utils.Constants.COMMON_BOTTOM_SHEET_ID +import com.naviapp.utils.Constants.SELL_GOLD +import com.naviapp.utils.Constants.SELL_GOLD_FRAGMENT +import com.naviapp.utils.Constants.SELL_GOLD_UPI_FRAGMENT +import com.naviapp.utils.Constants.SHOW_BOTTOM_SHEET +import com.naviapp.utils.Constants.SUB_REDIRECT +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class DigitalGoldSellActivity : BaseActivity(), WidgetCallback, NewBottomSheetListener { + + private lateinit var binding: ActivityDigitalGoldSellBinding + private val widgetNaviAnalyticsEventTracker = NaviAnalytics.naviAnalytics.Widget() + private val viewModel by lazy { ViewModelProvider(this).get(DigitalGoldSellVM::class.java) } + private val sharedVM by lazy { ViewModelProvider(this).get(DigitalGoldSellSharedVM::class.java) } + private lateinit var commonBottomSheet: NewCommonBottomSheet + private var firebaseDataReceiveListener: FirebaseDataReceiveListener? = null + private var apiPollScheduler: ApiPollScheduler? = null + private var firebaseDataHelper: FirebaseDataHelper? = null + private var errorTag: String? = null + private val onPollingEnd = { + handleTimeOutError(errorTag.orEmpty()) + } + private val naviFooterAdapter = NaviAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + private val pollingTimeoutClickListener: View.OnClickListener = View.OnClickListener { + loadFragment(DigitalGoldSellFragment.TAG) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView( + this, + R.layout.activity_digital_gold_sell + ) + setContentView(binding.root) + initUI() + initObserver() + initError( + viewModel = viewModel, + dialogDismissClicked = { + loadFragment(DigitalGoldSellFragment.TAG) + }, + showFullScreenError = true, + dialogOnBackPressed = { handleBackPress() } + ) + loadFragment(intent.getStringExtra(SUB_REDIRECT) ?: DigitalGoldSellFragment.TAG) + initHeader() + initFooterWidgets() + updateNextButtonStatus() + updatePaymentWidget() + } + + private fun initUI() { + binding.apply { + rvGoldFooterItems.apply { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + adapter = naviFooterAdapter + } + ivBack.setOnClickListener { + handleBackPress() + } + } + } + + private fun initObserver() { + lifecycleScope.launchWhenResumed { + viewModel.goldSellOrderResponse.observeNonNull(this@DigitalGoldSellActivity) { goldSellOrderResponse -> + hideLoader() + handleSellOrderResponse(goldSellOrderResponse) + } + viewModel.pollingData.observeNonNull(this@DigitalGoldSellActivity) { pollingData -> + handlePollingData(pollingData.status.orEmpty()) + } + viewModel.digitalGoldPollingUIData.observeNonNull(this@DigitalGoldSellActivity) { paymentCheckResponse -> + if (::commonBottomSheet.isInitialized && commonBottomSheet.isNotNull()) { + commonBottomSheet.safelyDismissDialog() + } + navigateToNextScreen(paymentCheckResponse) + } + } + } + + private fun loadFragment(screenName: String) { + val fragment = + supportFragmentManager.findFragmentByTag(screenName) ?: getFragment( + screenName + ) + val fragmentTransaction = supportFragmentManager.beginTransaction() + if (!supportFragmentManager.isStateSaved && !supportFragmentManager.isDestroyed) { + fragmentTransaction.replace(R.id.flLoadFragment, fragment, screenName) + fragmentTransaction.commit() + } + } + + private fun initHeader() { + lifecycleScope.launchWhenResumed { + sharedVM.updateHeaders.observeNonNull(this@DigitalGoldSellActivity) { header -> + processHeader(header) + } + } + } + + private fun initFooterWidgets() { + lifecycleScope.launchWhenResumed { + sharedVM.showActivityComponent.observeNonNull(this@DigitalGoldSellActivity) { show -> + binding.rvGoldFooterItems.isVisible = show + binding.clHeaderView.isVisible = show + } + sharedVM.footerWidgets.observeNonNull(this@DigitalGoldSellActivity) { listOfWidgets -> + naviFooterAdapter.setData(listOfWidgets) + } + } + } + + private fun updateNextButtonStatus() { + lifecycleScope.launchWhenResumed { + sharedVM.updateNextButtonStatus.observeNonNull(this@DigitalGoldSellActivity) { paymentData -> + naviFooterAdapter.list.forEachIndexed { index, naviBaseAdapterModel -> + if (naviBaseAdapterModel is ContainerWidget) { + val itemsOfContainerWidget = naviBaseAdapterModel.widgetData?.items + var paymentWidget: PaymentWidget? = null + itemsOfContainerWidget?.forEach { item -> + if (item is PaymentWidget) { + paymentWidget = item + paymentData.totalAmount?.let { + item.widgetData?.totalAmount = + it.toString().toDouble() + } + paymentData.disabled?.let { + item.widgetData?.actionData?.disabled = it + } + } + } + naviFooterAdapter.notifyItemChanged( + index, + WidgetChangedData(WIDGET_STATE_CHANGE, paymentWidget) + ) + } + } + } + } + } + + private fun updatePaymentWidget() { + lifecycleScope.launchWhenResumed { + sharedVM.updatePaymentWidget.observeNonNull(this@DigitalGoldSellActivity) { paymentWidget -> + naviFooterAdapter.list.forEachIndexed { index, naviBaseAdapterModel -> + if (naviBaseAdapterModel is ContainerWidget) { + val itemsOfContainerWidget = naviBaseAdapterModel.widgetData?.items + var currentPaymentWidget: PaymentWidget? = null + itemsOfContainerWidget?.forEach { item -> + if (item is PaymentWidget) { + currentPaymentWidget = item + currentPaymentWidget?.widgetData = paymentWidget.widgetData + } + } + naviFooterAdapter.notifyItemChanged( + index, + WidgetChangedData(WIDGET_STATE_CHANGE, currentPaymentWidget) + ) + } + } + } + } + } + + private fun getFragment(screen: String): Fragment { + return when (screen) { + DigitalGoldSellFragment.TAG -> DigitalGoldSellFragment.getInstance() + + DigitalGoldSellUpiFragment.TAG -> DigitalGoldSellUpiFragment.getInstance() + + else -> DigitalGoldSellFragment.getInstance() + } + } + + override fun getCurrentFragmentScreenName(): String { + return try { + (supportFragmentManager.findFragmentById(R.id.flLoadFragment) as? BaseFragment)?.screenName + ?: screenName + } catch (e: Exception) { + screenName + } + } + + private fun handleBackPress() { + sharedVM.updateHeaders.value?.actionData?.url?.let { + when (it) { + CLOSE -> { + finish() + } + else -> { + loadFragment(sharedVM.updateHeaders.value?.actionData?.url.orEmpty()) + } + } + } ?: run { + finish() + } + } + + private fun fetchSellOrderResponse() { + showLoader() + lifecycleScope.launchWhenResumed { + naviFooterAdapter.list.forEachIndexed { index, naviBaseAdapterModel -> + if (naviBaseAdapterModel is ContainerWidget) { + val itemsOfContainerWidget = naviBaseAdapterModel.widgetData?.items + var textWithTimerWidget: TextWithTimerWidget? = null + itemsOfContainerWidget?.forEach { item -> + if (item is TextWithTimerWidget) { + textWithTimerWidget = item + item.widgetData?.stopTimer = true + } + } + naviFooterAdapter.notifyItemChanged( + index, + WidgetChangedData(WIDGET_STATE_CHANGE, textWithTimerWidget) + ) + } + } + } + viewModel.fetchSellOrderResponse( + amount = sharedVM.getActualSellAmount(), + exchangeRateId = sharedVM.getExchangeRateId(), + upiId = sharedVM.getUpiId() + ) + } + + private fun processHeader(header: Header) { + header.title?.let { title -> + header.leftIconCode?.let { leftIconCode -> + binding.ivBack.showWhenDataIsAvailable(leftIconCode) + binding.tvTitle.showWhenDataIsAvailable(title) + } + } + binding.clHeaderView.isVisible = true + binding.tvHelp.isVisible = header.enableHelp == true + } + + private fun handleSellOrderResponse(goldSellOrderResponse: GoldSellOrderResponse? = null) { + if (goldSellOrderResponse?.expired == false && goldSellOrderResponse.inValidUpiId == false) { + firebaseInit( + requestId = goldSellOrderResponse.requestId.orEmpty(), + type = DIGITAL_GOLD_PAYMENT, + notificationPath = goldSellOrderResponse.notificationPath.orEmpty() + ) + apiPollInit( + requestId = goldSellOrderResponse.requestId.orEmpty(), + type = DIGITAL_GOLD_PAYMENT, + initialDelay = goldSellOrderResponse.requestConfig?.initialDelay?.toLong() + ?: ApiPollScheduler.INITIAL_DELAY_FOR_API_POLL_SECONDS, + pollInterval = goldSellOrderResponse.requestConfig?.interval?.toLong() + ?: ApiPollScheduler.API_POLL_REPEAT_PERIOD_SECONDS, + noOfRetry = goldSellOrderResponse.requestConfig?.numOfRetries + ?: ApiPollScheduler.API_POLL_RETRY_COUNT + ) + } + goldSellOrderResponse?.bottomSheetData?.let { showCommonBottomSheet(it) } + } + + private fun handlePollingData(status: String) { + if (TextUtils.equals(status, FirebaseStatusType.SUCCESS) + || TextUtils.equals(status, FirebaseStatusType.FAILURE) + ) { + deInitializeFirebaseListener() + apiPollScheduler?.stopApiPoll() + viewModel.fetchPaymentPollingUIData( + requestId = viewModel.goldSellOrderResponse.value?.requestId.orEmpty() + ) + } + } + + private fun navigateToNextScreen(paymentCheckResponse: PaymentCheckResponse) { + val bundle = Bundle() + bundle.putParcelable(PaymentCheckFragment.DATA, paymentCheckResponse) + safelyOpenFragment( + PaymentCheckFragment.newInstance(bundle), + PaymentCheckFragment.TAG + ) + } + + private fun firebaseInit( + requestId: String, + type: String, + notificationPath: String + ) { + firebaseDataReceiveListener = object : FirebaseDataReceiveListener { + override fun onDataReceive(firebaseResponse: FirebaseResponse?) { + firebaseResponse?.let { + apiPollScheduler?.stopApiPoll() + handlePollingData(firebaseResponse.status.orEmpty()) + } + } + } + firebaseDataHelper = null + firebaseDataHelper = FirebaseDataHelper() + firebaseDataHelper?.initFirebaseDataReceiver( + lifecycle, + firebaseDataReceiveListener, + type, + requestId, + notificationPath + ) + } + + private fun apiPollInit( + requestId: String, + type: String, + initialDelay: Long, + pollInterval: Long, + noOfRetry: Int + ) { + errorTag = type + apiPollScheduler = ApiPollScheduler( + initialDelay = initialDelay, + pollInterval = pollInterval, + numberOfRetry = noOfRetry, + doOnTimeout = onPollingEnd + ) { + viewModel.startPaymentPolling(requestId = requestId) + } + apiPollScheduler?.scheduleApiPoll() + } + + private fun handleTimeOutError(errorTag: String) { + if (::commonBottomSheet.isInitialized && commonBottomSheet.isNotNull()) { + commonBottomSheet.safelyDismissDialog() + } + showTimeoutErrorScreen( + firebaseDataHelper, + apiPollScheduler, + pollingTimeoutClickListener, + errorTag + ) + firebaseDataHelper = null + firebaseDataReceiveListener = null + } + + private fun deInitializeFirebaseListener() { + firebaseDataHelper?.clear() + firebaseDataHelper = null + firebaseDataReceiveListener = null + hideErrorScreen() + } + + private fun showCommonBottomSheet(bottomSheetData: BottomSheetData) { + if (::commonBottomSheet.isInitialized && commonBottomSheet.isNotNull()) { + commonBottomSheet.safelyDismissDialog() + } + commonBottomSheet = NewCommonBottomSheet.getInstance( + bottomSheetData + ) + commonBottomSheet.setListener(this@DigitalGoldSellActivity) + safelyShowBottomSheet(commonBottomSheet, NewCommonBottomSheet.TAG) + } + + override fun getLifeCycle(): Lifecycle = lifecycle + + override fun onClick(naviClickAction: NaviClickAction) { + when (naviClickAction) { + is NaviWidgetClickWithActionData -> { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent( + naviClickAction.actionData, + screenName + ) + if (toOpenBottomSheet(naviClickAction.actionData?.url)) { + toShowBottomSheet(naviClickAction.actionData) + return + } + naviClickAction.actionData?.let { + NaviDeepLinkNavigator.navigate( + this, + it.toCtaData(), + finish = naviClickAction.isFinish + ) + } + } + is PaymentWidgetClickAction -> { + if (sharedVM.getActualSellAmount() > 0) { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent( + naviClickAction.actionData, + screenName + ) + if (toOpenBottomSheet(naviClickAction.actionData.url)) { + toShowBottomSheet(naviClickAction.actionData) + return + } + when (naviClickAction.actionData.url) { + SELL_GOLD_FRAGMENT, SELL_GOLD_UPI_FRAGMENT -> { + loadFragment(naviClickAction.actionData.url.orEmpty()) + } + else -> { + naviClickAction.actionData.let { + NaviDeepLinkNavigator.navigate( + this, + it.toCtaData() + ) + } + } + } + } + } + } + } + + override fun widgetAnalytics(genericAnalyticsData: GenericAnalyticsData?) { + genericAnalyticsData?.let { data -> + val parameters: HashMap = + data.parameters ?: HashMap() + parameters[NaviAnalytics.SCREEN_NAME] = screenName + LandingScreenAnalytics.sendEventsToClickStream( + data.eventName, + parameters + ) + } + } + + override fun buttonClick(actionData: ActionData?) { + actionData?.let { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent(actionData, screenName) + if (it.url.isNotNullAndNotEmpty()) { + if (toOpenBottomSheet(it.url)) { + toShowBottomSheet(it) + return + } else if (it.url.equals(SELL_GOLD)) { + fetchSellOrderResponse() + return + } + NaviDeepLinkNavigator.navigate( + this, + it.toCtaData() + ) + } else if (it.action.isNotNullAndNotEmpty()) { + when (it.action) { + REFRESH -> { + sharedVM.setRefreshScreen(true) + } + } + } + } + } + + private fun toOpenBottomSheet(url: String?): Boolean { + url?.let { + return url.contains(SHOW_BOTTOM_SHEET, true) + } ?: run { + return false + } + } + + private fun toShowBottomSheet(action: ActionData?) { + val splitDeepLink = action?.url?.split("/") + when (splitDeepLink?.getOrNull(1)) { + COMMON_BOTTOM_SHEET_ID -> { + action.bottomSheetData?.let { + showCommonBottomSheet(it) + } + } + } + } + + override fun onBackPressed() { + handleBackPress() + } + + companion object { + private const val CLOSE = "CLOSE" + } + + override val screenName: String = DIGITAL_GOLD_SELL_SCREEN + override val moduleName: ModuleNameV2 = ModuleNameV2.COMMON +} + diff --git a/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellFragment.kt b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellFragment.kt new file mode 100644 index 0000000000..0c68bed597 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellFragment.kt @@ -0,0 +1,150 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.base.model.NaviClickAction +import com.navi.common.ui.fragment.BaseFragment +import com.navi.common.utils.observeNonNull +import com.navi.naviwidgets.actions.PaymentWidgetClickAction +import com.navi.naviwidgets.adapters.NaviAdapter +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.models.PaymentData +import com.navi.naviwidgets.utils.STORE_DIGITAL_GOLD_AMOUNT +import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.databinding.FragmentDigitalGoldSellBinding +import com.naviapp.digitalgold.viewmodels.DigitalGoldSellSharedVM +import com.naviapp.digitalgold.viewmodels.DigitalGoldSellVM +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class DigitalGoldSellFragment : BaseFragment(), WidgetCallback { + + private lateinit var binding: FragmentDigitalGoldSellBinding + private val viewModel by lazy { ViewModelProvider(this).get(DigitalGoldSellVM::class.java) } + private val sharedVM by lazy { ViewModelProvider(activity!!).get(DigitalGoldSellSharedVM::class.java) } + private val naviAdapter = NaviAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = DataBindingUtil.inflate( + inflater, + R.layout.fragment_digital_gold_sell, + container, + false + ) + initError( + viewModel = viewModel, + dialogDismissClicked = { fetchDigitalSellScreen() }, + showFullScreenError = true, + container = R.id.flLoadFragment, + dialogOnBackPressed = { activity?.onBackPressed() } + ) + initUI() + initObserver() + fetchDigitalSellScreen() + return binding.root + } + + private fun initUI() { + binding.apply { + rvItems.apply { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + adapter = naviAdapter + } + } + } + + private fun initObserver() { + lifecycleScope.launchWhenResumed { + viewModel.digitalGoldSellWidgets.observeNonNull(this@DigitalGoldSellFragment) { widgetResponse -> + binding.rvItems.isVisible = true + sharedVM.setActivityComponent(true) + stopShimmer() + widgetResponse.header?.let { header -> + sharedVM.setHeaders(header) + } + widgetResponse.footerWidget?.let { listOfWidgets -> + sharedVM.setFooterWidgets(listOfWidgets) + } + widgetResponse.contentWidget?.let { listOfWidgets -> + naviAdapter.setData(listOfWidgets) + } + sharedVM.setExchangeRateId(widgetResponse.extraData?.exchangeRateId.orEmpty()) + } + viewModel.errorResponse.observe(viewLifecycleOwner) { + sharedVM.setActivityComponent(false) + stopShimmer() + } + sharedVM.refreshScreen.observeNonNull(this@DigitalGoldSellFragment) { refresh -> + if (refresh) { + fetchDigitalSellScreen() + sharedVM.setRefreshScreen(false) + } + } + } + } + + private fun fetchDigitalSellScreen() { + showShimmer() + viewModel.fetchDigitalGoldSellDetails() + } + + private fun showShimmer() { + binding.shimmerLayout.startShimmer() + binding.shimmerLayout.isVisible = true + binding.rvItems.isVisible = false + sharedVM.setActivityComponent(false) + } + + private fun stopShimmer() { + binding.shimmerLayout.stopShimmer() + binding.shimmerLayout.isVisible = false + } + + override fun getLifeCycle(): Lifecycle = lifecycle + + override fun widgetUserData(key: String, value: Any) { + when (key) { + STORE_DIGITAL_GOLD_AMOUNT -> { + sharedVM.setNextButtonStatus( + PaymentData( + totalAmount = value.toString().toDouble(), + disabled = value.toString().toDouble() == 0.0 + ) + ) + sharedVM.setActualSellAmount(value.toString().toDouble()) + } + } + } + + companion object { + const val TAG = "sellScreen" + fun getInstance() = DigitalGoldSellFragment().apply { } + } + + override val screenName: String = NaviAnalytics.DIGITAL_GOLD_SELL_SCREEN +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellUpiFragment.kt b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellUpiFragment.kt new file mode 100644 index 0000000000..f0306e0d0d --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldSellUpiFragment.kt @@ -0,0 +1,155 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.common.ui.fragment.BaseFragment +import com.navi.common.utils.observeNonNull +import com.navi.naviwidgets.adapters.NaviAdapter +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.models.PaymentData +import com.navi.naviwidgets.models.PaymentWidget +import com.navi.naviwidgets.utils.STORE_DIGITAL_GOLD_SELL_UPI_ID +import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.databinding.FragmentDigitalGoldSellUpiBinding +import com.naviapp.digitalgold.viewmodels.DigitalGoldSellSharedVM +import com.naviapp.digitalgold.viewmodels.DigitalGoldSellVM +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class DigitalGoldSellUpiFragment : BaseFragment(), WidgetCallback { + + private lateinit var binding: FragmentDigitalGoldSellUpiBinding + private val viewModel by lazy { ViewModelProvider(this).get(DigitalGoldSellVM::class.java) } + private val sharedVM by lazy { ViewModelProvider(activity!!).get(DigitalGoldSellSharedVM::class.java) } + private val naviAdapter = NaviAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = DataBindingUtil.inflate( + inflater, + R.layout.fragment_digital_gold_sell_upi, + container, + false + ) + initError( + viewModel = viewModel, + dialogDismissClicked = { fetchDigitalSellUpiScreen() }, + showFullScreenError = true, + container = R.id.flLoadFragment, + dialogOnBackPressed = { activity?.onBackPressed() } + ) + initUI() + initObserver() + fetchDigitalSellUpiScreen() + return binding.root + } + + private fun initUI() { + binding.apply { + rvItems.apply { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + adapter = naviAdapter + } + } + } + + private fun initObserver() { + lifecycleScope.launchWhenResumed { + viewModel.digitalGoldSellUpiWidgets.observeNonNull(this@DigitalGoldSellUpiFragment) { widgetResponse -> + binding.rvItems.isVisible = true + sharedVM.setActivityComponent(true) + stopShimmer() + widgetResponse.header?.let { header -> + sharedVM.setHeaders(header) + } + widgetResponse.footerWidget?.let { listOfWidgets -> + listOfWidgets.forEach { naviWidget -> + if (naviWidget is PaymentWidget) { + sharedVM.setPaymentWidget(naviWidget) + } + } + } + widgetResponse.contentWidget?.let { listOfWidgets -> + naviAdapter.setData(listOfWidgets) + } + } + viewModel.errorResponse.observe(viewLifecycleOwner) { + sharedVM.setActivityComponent(false) + stopShimmer() + } + sharedVM.refreshScreen.observeNonNull(this@DigitalGoldSellUpiFragment) { refresh -> + if (refresh) { + activity?.onBackPressed() + sharedVM.setRefreshScreen(false) + } + } + } + } + + private fun fetchDigitalSellUpiScreen() { + showShimmer() + viewModel.fetchUpiScreenDetails( + exchangeRateId = sharedVM.getExchangeRateId(), + amount = sharedVM.getActualSellAmount() + ) + } + + private fun showShimmer() { + binding.shimmerLayout.startShimmer() + binding.shimmerLayout.isVisible = true + binding.rvItems.isVisible = false + sharedVM.setActivityComponent(false) + } + + private fun stopShimmer() { + binding.shimmerLayout.stopShimmer() + binding.shimmerLayout.isVisible = false + } + + override fun getLifeCycle(): Lifecycle = lifecycle + + override fun widgetUserData(key: String, value: Any) { + when (key) { + STORE_DIGITAL_GOLD_SELL_UPI_ID -> { + sharedVM.setNextButtonStatus( + PaymentData( + disabled = (value.toString() == "") + ) + ) + sharedVM.setUpiId(value.toString()) + } + } + } + + companion object { + const val TAG = "upiScreen" + + fun getInstance() = DigitalGoldSellUpiFragment().apply { } + } + + override val screenName: String = NaviAnalytics.DIGITAL_GOLD_SELL_UPI_SCREEN +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldTransactionActivity.kt b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldTransactionActivity.kt new file mode 100644 index 0000000000..d614cd554b --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/ui/DigitalGoldTransactionActivity.kt @@ -0,0 +1,131 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.ui + +import android.net.Uri +import android.os.Bundle +import android.widget.Toast +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.base.model.NaviClickAction +import com.navi.base.utils.BaseUtils +import com.navi.common.downloader.DownloadUtil +import com.navi.common.model.ModuleNameV2 +import com.navi.common.ui.activity.BaseActivity +import com.navi.common.utils.observeNonNull +import com.navi.naviwidgets.actions.DownloadClickAction +import com.navi.naviwidgets.adapters.NaviAdapter +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.extensions.showWhenDataIsAvailable +import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics.Companion.DIGITAL_GOLD_TRANSACTION_SCREEN +import com.naviapp.databinding.ActivityDigitalGoldTransactionBinding +import com.naviapp.digitalgold.viewmodels.DigitalGoldTransactionVM +import com.naviapp.home.model.WidgetResponse +import dagger.hilt.android.AndroidEntryPoint +import java.net.URI + +@AndroidEntryPoint +class DigitalGoldTransactionActivity : BaseActivity(), WidgetCallback { + + private lateinit var binding: ActivityDigitalGoldTransactionBinding + private val viewModel by lazy { ViewModelProvider(this).get(DigitalGoldTransactionVM::class.java) } + private val naviAdapter = NaviAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView( + this, + R.layout.activity_digital_gold_transaction + ) + setContentView(binding.root) + initUI() + initObserver() + initError( + viewModel = viewModel, + dialogDismissClicked = { + fetchDigitalTransactionPageDetails() + }, + showFullScreenError = true + ) + fetchDigitalTransactionPageDetails() + } + + private fun initUI() { + binding.apply { + rvGoldItems.apply { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + adapter = naviAdapter + } + ivBack.setOnClickListener { + finish() + } + } + } + + private fun initObserver() { + lifecycleScope.launchWhenResumed { + viewModel.digitalGoldTransactionWidgets.observeNonNull(this@DigitalGoldTransactionActivity) { widgetResponse -> + processHeader(widgetResponse) + widgetResponse.contentWidget?.let { listOfWidgets -> + naviAdapter.setData(listOfWidgets) + } + } + } + } + + private fun processHeader(response: WidgetResponse?) { + response?.header?.let { + it.title?.let { title -> + it.leftIconCode?.let { leftIconCode -> + binding.ivBack.showWhenDataIsAvailable(leftIconCode) + binding.tvTitle.showWhenDataIsAvailable(title) + } + } + binding.clHeaderView.isVisible = true + binding.tvHelp.isVisible = it.enableHelp == true + } + } + + private fun fetchDigitalTransactionPageDetails() { + viewModel.fetchDigitalGoldTransactionDetails() + } + + override fun onClick(naviClickAction: NaviClickAction) { + when (naviClickAction) { + is DownloadClickAction -> { + val destination = + BaseUtils.cacheDirUri( + this, + naviClickAction.fileName + ) + Toast.makeText(this, getString(R.string.downloading), Toast.LENGTH_SHORT).show() + DownloadUtil.download( + this, + Uri.parse(naviClickAction.url), + URI.create(destination) + ) + } + } + } + + + override val screenName: String = DIGITAL_GOLD_TRANSACTION_SCREEN + + override val moduleName: ModuleNameV2 = ModuleNameV2.COMMON + +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldBuyVM.kt b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldBuyVM.kt new file mode 100644 index 0000000000..6d883c2cf8 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldBuyVM.kt @@ -0,0 +1,135 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.navi.common.extensions.isNull +import com.navi.common.network.models.RepoResult +import com.navi.common.viewmodel.BaseVM +import com.naviapp.digitalgold.model.DigitalGoldPollingResponse +import com.naviapp.digitalgold.model.GoldBuyOrderRequest +import com.naviapp.digitalgold.model.GoldSellOrderResponse +import com.naviapp.digitalgold.repo.DigitalGoldBuyRepo +import com.naviapp.home.model.WidgetResponse +import com.naviapp.models.PaymentCheckResponse +import com.naviapp.models.PgRepaymentData +import com.naviapp.models.response.SuccessResponse +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DigitalGoldBuyVM @Inject constructor(private val goldBuyRepo: DigitalGoldBuyRepo) : + BaseVM() { + + private val _digitalGoldBuyWidgets = MutableLiveData() + val digitalGoldBuyWidgets: LiveData + get() = _digitalGoldBuyWidgets + private val _goldBuyOrderResponse = MutableLiveData() + val goldBuyOrderResponse: LiveData + get() = _goldBuyOrderResponse + private val _paymentPollingData = MutableLiveData() + val paymentPollingData: LiveData + get() = _paymentPollingData + private val _sdkCredPollingData = MutableLiveData() + val sdkCredPollingData: LiveData + get() = _sdkCredPollingData + private val _digitalGoldPollingUIData = MutableLiveData() + val digitalGoldPollingUIData: LiveData + get() = _digitalGoldPollingUIData + private val _pgRePaymentResponse = MutableLiveData>() + val pgRepaymentResponse: LiveData> + get() = _pgRePaymentResponse + + private val _postPaymentStatus = MutableLiveData() + val postPaymentStatus: LiveData + get() = _postPaymentStatus + private val _postPaymentResponse = MutableLiveData>() + val postPaymentResponse: LiveData> + get() = _postPaymentResponse + + + fun setPostPaymentResponseStatus(data: PgRepaymentData) { + _postPaymentStatus.value = data + } + + fun fetchDigitalGoldBuyDetails(amount: Double) { + coroutineScope.launch { + val response = goldBuyRepo.fetchDigitalGoldBuyDetails(amount) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _digitalGoldBuyWidgets.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun fetchBuyOrderResponse( + amount: Double, + exchangeRateId: String, + source: String + ) { + coroutineScope.launch { + val response = goldBuyRepo.fetchBuyOrderResponse( + GoldBuyOrderRequest( + amount = amount, + exchangeRateId = exchangeRateId, + source = source + ) + ) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _goldBuyOrderResponse.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun startSdkCredPolling(requestId: String) { + coroutineScope.launch { + val response = goldBuyRepo.startSdkCredPolling(requestId = requestId) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _sdkCredPollingData.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun postPaymentData(pgRepaymentData: PgRepaymentData) { + coroutineScope.launch { + val response = goldBuyRepo.postPaymentData(pgRepaymentData) + _postPaymentResponse.value = response + } + } + + fun startPaymentPolling(requestId: String) { + coroutineScope.launch { + val response = goldBuyRepo.startPaymentPolling(requestId = requestId) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _paymentPollingData.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun fetchPaymentPollingUIData(requestId: String) { + coroutineScope.launch { + val response = goldBuyRepo.fetchPaymentPollingUIData(requestId = requestId) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _digitalGoldPollingUIData.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldHomeVM.kt b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldHomeVM.kt new file mode 100644 index 0000000000..a8b66148a0 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldHomeVM.kt @@ -0,0 +1,60 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.navi.common.extensions.isNull +import com.navi.common.viewmodel.BaseVM +import com.naviapp.digitalgold.repo.DigitalGoldHomeRepo +import com.naviapp.home.model.WidgetResponse +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DigitalGoldHomeVM @Inject constructor(private val goldHomeRepo: DigitalGoldHomeRepo) : + BaseVM() { + + private val _digitalGoldHomeWidgets = MutableLiveData() + val digitalGoldHomeWidgets: LiveData + get() = _digitalGoldHomeWidgets + private val _pollingData = MutableLiveData() + val pollingData: LiveData + get() = _pollingData + private var actualSellAmount: Double = 0.0 + + fun setActualSellAmount(actualSellAmount: Double) { + this.actualSellAmount = actualSellAmount + } + + fun getActualSellAmount() = actualSellAmount + fun fetchDigitalGoldHomeDetails() { + coroutineScope.launch { + val response = goldHomeRepo.fetchDigitalGoldHomeDetails() + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _digitalGoldHomeWidgets.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun startPolling() { + coroutineScope.launch { + val response = goldHomeRepo.fetchDigitalGoldHomeDetailsPolling() + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _pollingData.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldSellSharedVM.kt b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldSellSharedVM.kt new file mode 100644 index 0000000000..c19e0e609a --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldSellSharedVM.kt @@ -0,0 +1,93 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.navi.common.viewmodel.BaseVM +import com.navi.naviwidgets.models.NaviWidget +import com.navi.naviwidgets.models.PaymentData +import com.navi.naviwidgets.models.PaymentWidget +import com.naviapp.models.response.Header + +class DigitalGoldSellSharedVM : BaseVM(isExceptionNeedToShow = false) { + + private val _updateHeaders = MutableLiveData
() + val updateHeaders: LiveData
+ get() = _updateHeaders + + private val _footerWidgets = MutableLiveData>() + val footerWidgets: LiveData> + get() = _footerWidgets + + private val _updateNextButtonStatus = MutableLiveData() + val updateNextButtonStatus: LiveData + get() = _updateNextButtonStatus + + private val _refreshScreen = MutableLiveData() + val refreshScreen: LiveData + get() = _refreshScreen + + private val _showActivityComponent = MutableLiveData() + val showActivityComponent: LiveData + get() = _showActivityComponent + + private val _updatePaymentWidget = MutableLiveData() + val updatePaymentWidget: LiveData + get() = _updatePaymentWidget + + private var actualSellAmount: Double = 0.0 + + private var upiId: String = "" + + private var exchangeRateId: String = "" + + fun setActualSellAmount(actualSellAmount: Double) { + this.actualSellAmount = actualSellAmount + } + + fun getActualSellAmount() = actualSellAmount + + fun setUpiId(upiId: String) { + this.upiId = upiId + } + + fun getUpiId() = upiId + + fun setExchangeRateId(exchangeRateId: String) { + this.exchangeRateId = exchangeRateId + } + + fun getExchangeRateId() = exchangeRateId + + fun setHeaders(header: Header) { + _updateHeaders.value = header + } + + fun setFooterWidgets(listOfFooterWidgets: List) { + _footerWidgets.value = listOfFooterWidgets + } + + fun setNextButtonStatus(paymentData: PaymentData) { + _updateNextButtonStatus.value = paymentData + } + + fun setRefreshScreen(refresh: Boolean) { + _refreshScreen.value = refresh + } + + fun setActivityComponent(show: Boolean) { + _showActivityComponent.value = show + } + + fun setPaymentWidget(paymentWidget: PaymentWidget) { + _updatePaymentWidget.value = paymentWidget + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldSellVM.kt b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldSellVM.kt new file mode 100644 index 0000000000..f84deddf37 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldSellVM.kt @@ -0,0 +1,116 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.navi.common.extensions.isNull +import com.navi.common.viewmodel.BaseVM +import com.naviapp.digitalgold.model.DigitalGoldPollingResponse +import com.naviapp.digitalgold.model.GoldSellOrderRequest +import com.naviapp.digitalgold.model.GoldSellOrderResponse +import com.naviapp.digitalgold.repo.DigitalGoldSellRepo +import com.naviapp.home.model.WidgetResponse +import com.naviapp.models.PaymentCheckResponse +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DigitalGoldSellVM @Inject constructor(private val goldSellRepo: DigitalGoldSellRepo) : + BaseVM() { + + private val _digitalGoldSellWidgets = MutableLiveData() + val digitalGoldSellWidgets: LiveData + get() = _digitalGoldSellWidgets + private val _goldSellOrderResponse = MutableLiveData() + val goldSellOrderResponse: LiveData + get() = _goldSellOrderResponse + private val _pollingData = MutableLiveData() + val pollingData: LiveData + get() = _pollingData + private val _digitalGoldPollingUIData = MutableLiveData() + val digitalGoldPollingUIData: LiveData + get() = _digitalGoldPollingUIData + private val _digitalGoldSellUpiWidgets = MutableLiveData() + val digitalGoldSellUpiWidgets: LiveData + get() = _digitalGoldSellUpiWidgets + + fun fetchDigitalGoldSellDetails() { + coroutineScope.launch { + val response = goldSellRepo.fetchDigitalGoldSellDetails() + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _digitalGoldSellWidgets.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun fetchSellOrderResponse( + amount: Double, + exchangeRateId: String, + upiId: String + ) { + coroutineScope.launch { + val response = goldSellRepo.fetchSellOrderResponse( + GoldSellOrderRequest( + amount = amount, + exchangeRateId = exchangeRateId, + upiId = upiId + ) + ) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _goldSellOrderResponse.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun startPaymentPolling(requestId: String) { + coroutineScope.launch { + val response = goldSellRepo.startPaymentPolling(requestId = requestId) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _pollingData.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun fetchPaymentPollingUIData(requestId: String) { + coroutineScope.launch { + val response = goldSellRepo.fetchPaymentPollingUIData(requestId = requestId) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _digitalGoldPollingUIData.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } + + fun fetchUpiScreenDetails( + exchangeRateId: String, + amount: Double + ) { + coroutineScope.launch { + val response = goldSellRepo.fetchUpiScreenDetails( + exchangeRateId = exchangeRateId, + amount = amount + ) + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _digitalGoldSellUpiWidgets.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldTransactionVM.kt b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldTransactionVM.kt new file mode 100644 index 0000000000..2b0f8be655 --- /dev/null +++ b/app/src/main/java/com/naviapp/digitalgold/viewmodels/DigitalGoldTransactionVM.kt @@ -0,0 +1,40 @@ +/* + * + * * + * * * Copyright © 2022 by Navi Technologies Private Limited + * * * All rights reserved. Strictly confidential + * * + * + */ + +package com.naviapp.digitalgold.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.navi.common.extensions.isNull +import com.navi.common.viewmodel.BaseVM +import com.naviapp.digitalgold.repo.DigitalGoldTransactionRepo +import com.naviapp.home.model.WidgetResponse +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DigitalGoldTransactionVM @Inject constructor(private val goldTransactionRepo: DigitalGoldTransactionRepo) : + BaseVM() { + + private val _digitalGoldTransactionWidgets = MutableLiveData() + val digitalGoldTransactionWidgets: LiveData + get() = _digitalGoldTransactionWidgets + + fun fetchDigitalGoldTransactionDetails() { + coroutineScope.launch { + val response = goldTransactionRepo.fetchDigitalGoldTransactionDetails() + if (response.error.isNull() && response.errors.isNullOrEmpty()) { + _digitalGoldTransactionWidgets.value = response.data + } else { + setErrorData(response.errors, response.error) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/errors/activities/ErrorActivity.kt b/app/src/main/java/com/naviapp/errors/activities/ErrorActivity.kt index 28665ff26f..253045e431 100644 --- a/app/src/main/java/com/naviapp/errors/activities/ErrorActivity.kt +++ b/app/src/main/java/com/naviapp/errors/activities/ErrorActivity.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -17,9 +17,9 @@ import androidx.lifecycle.ViewModelProvider import com.navi.analytics.utils.NaviTrackEvent import com.navi.common.extensions.isNotNull import com.navi.common.extensions.isNotNullAndNotEmpty -import com.navi.common.model.GenericErrorResponse import com.navi.common.model.ModuleNameV2 import com.navi.common.model.PreviousScreenNameRequest +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.activity.BaseActivity import com.navi.common.utils.log import com.navi.common.utils.observeNonNull @@ -63,7 +63,9 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { private var isSoftRejectFromHL = false private val viewModel by lazy { ViewModelProvider(this).get(ErrorVM::class.java) } - private val activeLoanDetailsVM by lazy { ViewModelProvider(this).get(ActiveLoanDetailsVM::class.java) } + private val activeLoanDetailsVM by lazy { + ViewModelProvider(this).get(ActiveLoanDetailsVM::class.java) + } private val analyticsEventTracker = NaviAnalytics.naviAnalytics.RatingDetail() private val offerRejectionEventTracker = NaviAnalytics.naviAnalytics.OfferRejection() @@ -87,10 +89,9 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { } isSecondLoanJourney = intent.getBooleanExtra(IS_FOR_SECOND_LOAN_JOURNEY, false) isSoftReject = intent.getStringExtra(IS_SOFT_REJECT) == Constants.TRUE - isHomeLoan = intent.getBooleanExtra(IS_HOME_LOAN, false).orFalse() || intent.getStringExtra( - IS_HOME_LOAN - ) == Constants.TRUE - + isHomeLoan = + intent.getBooleanExtra(IS_HOME_LOAN, false).orFalse() || + intent.getStringExtra(IS_HOME_LOAN) == Constants.TRUE } override fun onSaveInstanceState(outState: Bundle) { @@ -105,20 +106,19 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { val rejectionDate = viewModel.rejectionDetailsData.value?.humanReadableContent?.rejectionDate - if (rejectionDate.isNotNullAndNotEmpty() && - (listOf( - PROFILE_NOT_ELIGIBLE, - PROFILE_NOT_ELIGIBLE_DUE_TO_MFI, - OFFER_INELIGIBLE - ).contains(rejectionCode)) + if ( + rejectionDate.isNotNullAndNotEmpty() && + (listOf(PROFILE_NOT_ELIGIBLE, PROFILE_NOT_ELIGIBLE_DUE_TO_MFI, OFFER_INELIGIBLE) + .contains(rejectionCode)) ) { offerRejectionEventTracker.onOfferRejectionBackButtonClicked(rejectionDate) } - if (rejectionCode == E_HOME_LOAN_OFFER_HARD_REJECT || - rejectionCode == E_HOME_LOAN_OFFER_NO_CO_APPLICANT_REJECTION || - rejectionCode == E_HOME_LOAN_OFFER_CO_APPLICANT_NOT_ELIGIBLE || - rejectionCode == PROFILE_NOT_ELIGIBLE_DUE_TO_MFI + if ( + rejectionCode == E_HOME_LOAN_OFFER_HARD_REJECT || + rejectionCode == E_HOME_LOAN_OFFER_NO_CO_APPLICANT_REJECTION || + rejectionCode == E_HOME_LOAN_OFFER_CO_APPLICANT_NOT_ELIGIBLE || + rejectionCode == PROFILE_NOT_ELIGIBLE_DUE_TO_MFI ) { bundle.putParcelable(Constants.PREVIOUS_SCREEN, PreviousScreenNameRequest(REJECTED)) ScreenNavigator.instance.startActivityWithNoActivityStack( @@ -164,10 +164,8 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { trackSoftRejectEvent(data?.rejectionCode, data?.rejectionCode) isSoftRejectFromHL = data?.cardsData.isNotNull() val fragment = - supportFragmentManager.findFragmentByTag(tag) ?: getFragment( - data?.rejectionCode, - intent.extras - ) + supportFragmentManager.findFragmentByTag(tag) + ?: getFragment(data?.rejectionCode, intent.extras) val bundle = fragment.arguments ?: Bundle() fragment.arguments = bundle.apply { @@ -188,11 +186,12 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { private fun handleRatingUi(isRatingEnabled: Boolean = false) { if (isRatingEnabled) { - val ratingListener = object : RatingChangeListener { - override fun onRatingChange(rating: Float?) { - openRatingScreen(rating) + val ratingListener = + object : RatingChangeListener { + override fun onRatingChange(rating: Float?) { + openRatingScreen(rating) + } } - } binding.ratingViewLay.setBackgroundResource(R.drawable.bg_rounded_rect_with_shadow) binding.ratingViewLay.setListener(ratingListener) binding.ratingViewLay.setData(getString(R.string.rate_us)) @@ -204,13 +203,9 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { private fun openRatingScreen(rating: Float? = null) { analyticsEventTracker.onRatingRejectScreenSelect(rating?.toString().orEmpty()) val b = Bundle() - rating?.apply { - b.putFloat(RatingActivity.RATING_VALUE, this) - } + rating?.apply { b.putFloat(RatingActivity.RATING_VALUE, this) } b.putString(RatingActivity.SCREEN_FROM, RatingActivity.SCREEN_FROM_SOFT_REJECT) - redirectStatusData?.apply { - b.putParcelable(RATING_DATA, this) - } + redirectStatusData?.apply { b.putParcelable(RATING_DATA, this) } ScreenNavigator.instance.startActivity( this, ScreenNavigator.RATING_SCREEN, @@ -250,15 +245,14 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { val tag = getTag(data.first?.rejectReason) trackSoftRejectEvent(data.first?.rejectReason, data.second?.code) val fragment = - supportFragmentManager.findFragmentByTag(tag) ?: getFragment( - data.first?.rejectReason, - intent.extras - ) + supportFragmentManager.findFragmentByTag(tag) + ?: getFragment(data.first?.rejectReason, intent.extras) val bundle = fragment.arguments ?: Bundle() - fragment.arguments = bundle.apply { - putParcelable(ERROR_DATA, data.second) - putBoolean(IS_HOME_LOAN, isHomeLoan) - } + fragment.arguments = + bundle.apply { + putParcelable(ERROR_DATA, data.second) + putBoolean(IS_HOME_LOAN, isHomeLoan) + } supportFragmentManager.beginTransaction().run { replace(R.id.error_container_fl, fragment, tag) commit() @@ -267,24 +261,30 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { private fun getFragment(rejectReason: String?, bundle: Bundle?): Fragment { return when (rejectReason) { - PROFILE_NOT_ELIGIBLE, PROFILE_NOT_ELIGIBLE_DUE_TO_MFI -> ProfileRejectedFragment() + PROFILE_NOT_ELIGIBLE, + PROFILE_NOT_ELIGIBLE_DUE_TO_MFI -> ProfileRejectedFragment() KYC_FAILED -> ErrorFragment() OFFER_INELIGIBLE -> OfferRejectedFragment.newInstance(bundle) LOAN_OFFER_EXPIRED -> OfferExpiredFragment() E_HOME_LOAN_OFFER_HARD_REJECT -> OfferRejectedFragment.newInstance(bundle) E_HOME_LOAN_OFFER_CO_APPLICANT_NOT_ELIGIBLE -> OfferRejectedFragment.newInstance(bundle) E_HOME_LOAN_OFFER_NO_CO_APPLICANT_REJECTION -> OfferRejectedFragment.newInstance(bundle) - else -> ErrorFragment().apply { - val bundle = Bundle() - bundle.putString(ERROR_SCREEN_NAME, NaviAnalytics.SYSTEM_UNDER_MAINTENANCE_SCREEN) - arguments = bundle - } + else -> + ErrorFragment().apply { + val bundle = Bundle() + bundle.putString( + ERROR_SCREEN_NAME, + NaviAnalytics.SYSTEM_UNDER_MAINTENANCE_SCREEN + ) + arguments = bundle + } } } private fun getTag(rejectReason: String?): String { return when (rejectReason) { - PROFILE_NOT_ELIGIBLE, PROFILE_NOT_ELIGIBLE_DUE_TO_MFI -> ProfileRejectedFragment.TAG + PROFILE_NOT_ELIGIBLE, + PROFILE_NOT_ELIGIBLE_DUE_TO_MFI -> ProfileRejectedFragment.TAG KYC_FAILED -> ErrorFragment.TAG OFFER_INELIGIBLE -> OfferRejectedFragment.TAG E_HOME_LOAN_OFFER_HARD_REJECT -> OfferRejectedFragment.TAG @@ -299,27 +299,26 @@ class ErrorActivity : BaseActivity(), View.OnClickListener { val rejectionDate = viewModel.rejectionDetailsData.value?.humanReadableContent?.rejectionDate - if (rejectionDate.isNotNullAndNotEmpty() && - (listOf( - PROFILE_NOT_ELIGIBLE, - PROFILE_NOT_ELIGIBLE_DUE_TO_MFI, - OFFER_INELIGIBLE - ).contains(rejectReason)) + if ( + rejectionDate.isNotNullAndNotEmpty() && + (listOf(PROFILE_NOT_ELIGIBLE, PROFILE_NOT_ELIGIBLE_DUE_TO_MFI, OFFER_INELIGIBLE) + .contains(rejectReason)) ) { offerRejectionEventTracker.onOfferRejectionPageLands(rejectionDate) } - val eventName = when (rejectReason) { - PROFILE_NOT_ELIGIBLE -> NaviAnalytics.PROFILE_SOFT_REJECTED - KYC_FAILED -> NaviAnalytics.KYC_SOFT_REJECTED - OFFER_INELIGIBLE -> NaviAnalytics.OFFER_SOFT_REJECTED - else -> { - when (intent?.extras?.getString(ERROR_TYPE)) { - APPLICATION_ON_HOLD -> NaviAnalytics.LOAN_RCS_SCREEN - else -> null + val eventName = + when (rejectReason) { + PROFILE_NOT_ELIGIBLE -> NaviAnalytics.PROFILE_SOFT_REJECTED + KYC_FAILED -> NaviAnalytics.KYC_SOFT_REJECTED + OFFER_INELIGIBLE -> NaviAnalytics.OFFER_SOFT_REJECTED + else -> { + when (intent?.extras?.getString(ERROR_TYPE)) { + APPLICATION_ON_HOLD -> NaviAnalytics.LOAN_RCS_SCREEN + else -> null + } } } - } eventName?.let { NaviTrackEvent.trackEvent(eventName) } code?.let { NaviAnalytics.naviAnalytics.Errors().startScreen(it) } diff --git a/app/src/main/java/com/naviapp/errors/fragments/ErrorFragment.kt b/app/src/main/java/com/naviapp/errors/fragments/ErrorFragment.kt index e3ee13187f..388d7b0962 100644 --- a/app/src/main/java/com/naviapp/errors/fragments/ErrorFragment.kt +++ b/app/src/main/java/com/naviapp/errors/fragments/ErrorFragment.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -11,26 +11,25 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import com.naviapp.R -import com.naviapp.analytics.utils.NaviAnalytics -import com.navi.common.ui.fragment.BaseFragment -import com.naviapp.common.navigator.NaviDeepLinkNavigator -import com.naviapp.databinding.ErrorFragmentBinding -import com.naviapp.errors.activities.ErrorActivity -import com.naviapp.errors.activities.ErrorActivity.Companion.IS_SOFT_REJECT -import com.naviapp.errors.helper.ErrorHelper -import com.naviapp.models.response.ErrorContent -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.ActionErrorFragment import com.navi.common.ui.fragment.ActionErrorFragment.Companion.DOCUMENT_ERROR_ICON import com.navi.common.ui.fragment.ActionErrorFragment.Companion.NAVI_ICON import com.navi.common.ui.fragment.ActionErrorFragment.Companion.PROFILE_ERROR_ICON import com.navi.common.ui.fragment.ActionErrorFragment.Companion.USER_ERROR_ICON import com.navi.common.ui.fragment.ActionErrorFragment.Companion.USER_ON_HOLD_ERROR_ICON +import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.orFalse +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.databinding.ErrorFragmentBinding +import com.naviapp.errors.activities.ErrorActivity +import com.naviapp.errors.activities.ErrorActivity.Companion.IS_SOFT_REJECT +import com.naviapp.errors.helper.ErrorHelper +import com.naviapp.models.response.ErrorContent import com.naviapp.personalloan.getloan.creditAssignment.models.ImageBannerData -import com.naviapp.utils.* - +import com.naviapp.utils.loadUrlIntoImageView class ErrorFragment : BaseFragment() { @@ -38,7 +37,6 @@ class ErrorFragment : BaseFragment() { private val defaultBannerImageAspectRatio = 2.1918 private val creditAssignmentAnalytics = NaviAnalytics.naviAnalytics.CreditAssignment() - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -59,9 +57,7 @@ class ErrorFragment : BaseFragment() { binding.optionalNoteTv.text = it binding.optionalNoteTv.visibility = View.VISIBLE } - error?.imageCardData?.let { - setCreditAssignmentImageCardData(it) - } + error?.imageCardData?.let { setCreditAssignmentImageCardData(it) } setIcon(error?.iconCode) setOptionIcon(error?.numberOfDays, error?.optionIconCode) } else { @@ -78,8 +74,9 @@ class ErrorFragment : BaseFragment() { private fun setCreditAssignmentImageCardData(imageBannerData: ImageBannerData) { context?.let { context -> - if(!imageBannerData.imageUrl.isNullOrEmpty()) { - binding.bottomImageBanner.layoutParams = ErrorHelper.getBannerParams(imageBannerData, defaultBannerImageAspectRatio) + if (!imageBannerData.imageUrl.isNullOrEmpty()) { + binding.bottomImageBanner.layoutParams = + ErrorHelper.getBannerParams(imageBannerData, defaultBannerImageAspectRatio) loadUrlIntoImageView(context, imageBannerData.imageUrl, binding.bottomImageBanner) creditAssignmentAnalytics.creditAssignmentBannerSeen() diff --git a/app/src/main/java/com/naviapp/errors/fragments/OfferExpiredFragment.kt b/app/src/main/java/com/naviapp/errors/fragments/OfferExpiredFragment.kt index f5af233239..fc09aeed83 100644 --- a/app/src/main/java/com/naviapp/errors/fragments/OfferExpiredFragment.kt +++ b/app/src/main/java/com/naviapp/errors/fragments/OfferExpiredFragment.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -12,8 +12,10 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.navi.analytics.utils.NaviTrackEvent -import com.naviapp.R +import com.navi.common.extensions.orFalse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment +import com.naviapp.R import com.naviapp.common.navigator.ScreenNavigator import com.naviapp.common.navigator.ScreenNavigator.Companion.LOAN_ELIGIBLE_SCREEN import com.naviapp.databinding.OfferExpiredFragmentBinding @@ -21,9 +23,7 @@ import com.naviapp.errors.activities.ErrorActivity import com.naviapp.errors.activities.ErrorActivity.Companion.ERROR_DATA import com.naviapp.errors.activities.ErrorActivity.Companion.IS_SOFT_REJECT import com.naviapp.models.response.ErrorContent -import com.navi.common.model.GenericErrorResponse import com.naviapp.personalloan.useridentification.activities.LoanEligibilityLoaderActivity.Companion.OFFER_EXPIRED_MESSAGE -import com.navi.common.extensions.orFalse class OfferExpiredFragment : BaseFragment(), View.OnClickListener { private lateinit var binding: OfferExpiredFragmentBinding diff --git a/app/src/main/java/com/naviapp/errors/fragments/OfferRejectedFragment.kt b/app/src/main/java/com/naviapp/errors/fragments/OfferRejectedFragment.kt index 8afe11d7dd..496aa9e50f 100644 --- a/app/src/main/java/com/naviapp/errors/fragments/OfferRejectedFragment.kt +++ b/app/src/main/java/com/naviapp/errors/fragments/OfferRejectedFragment.kt @@ -24,7 +24,7 @@ import com.navi.chat.models.NaviChatSystemLocalData import com.navi.chat.ui.activities.NaviChatActivity import com.navi.chat.utils.* import com.navi.common.extensions.isNotNullAndNotEmpty -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.ActionErrorFragment import com.navi.common.ui.fragment.ActionErrorFragment.Companion.DOCUMENT_ERROR_ICON import com.navi.common.ui.fragment.ActionErrorFragment.Companion.USER_ERROR_ICON diff --git a/app/src/main/java/com/naviapp/errors/fragments/ProfileRejectedFragment.kt b/app/src/main/java/com/naviapp/errors/fragments/ProfileRejectedFragment.kt index b1c745edbe..7ac3d6aced 100644 --- a/app/src/main/java/com/naviapp/errors/fragments/ProfileRejectedFragment.kt +++ b/app/src/main/java/com/naviapp/errors/fragments/ProfileRejectedFragment.kt @@ -21,7 +21,7 @@ import com.navi.chat.ui.activities.NaviChatActivity import com.navi.chat.utils.* import com.navi.common.extensions.isNotNullAndNotEmpty import com.navi.common.extensions.orFalse -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.ActionErrorFragment import com.navi.common.ui.fragment.ActionErrorFragment.Companion.DOCUMENT_ERROR_ICON import com.navi.common.ui.fragment.ActionErrorFragment.Companion.MFI_PROFILE_ERROR_ICON diff --git a/app/src/main/java/com/naviapp/errors/viewmodels/ErrorVM.kt b/app/src/main/java/com/naviapp/errors/viewmodels/ErrorVM.kt index 0f3e370ea6..e31a23603e 100644 --- a/app/src/main/java/com/naviapp/errors/viewmodels/ErrorVM.kt +++ b/app/src/main/java/com/naviapp/errors/viewmodels/ErrorVM.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -9,7 +9,7 @@ package com.naviapp.errors.viewmodels import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.viewmodel.BaseVM import com.naviapp.errors.repository.ErrorRepository import com.naviapp.models.RedirectPageStatus @@ -60,7 +60,6 @@ class ErrorVM : BaseVM() { } } - fun fetchHomeLoanRejectionDetails(type: String) { coroutineScope.launch { val response = repository.fetchRejectionDetails(type) @@ -71,4 +70,4 @@ class ErrorVM : BaseVM() { } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/home/activity/NewDashboardActivity.kt b/app/src/main/java/com/naviapp/home/activity/NewDashboardActivity.kt index 1aa80f50b5..d4e203747f 100644 --- a/app/src/main/java/com/naviapp/home/activity/NewDashboardActivity.kt +++ b/app/src/main/java/com/naviapp/home/activity/NewDashboardActivity.kt @@ -653,4 +653,4 @@ class NewDashboardActivity : uxCamTracker.onUxCamDisabled(screenName, journey) } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/home/dashboard/adapter/GridOptionsAdapter.kt b/app/src/main/java/com/naviapp/home/dashboard/adapter/GridOptionsAdapter.kt index f4e68f7672..2664fe5f37 100644 --- a/app/src/main/java/com/naviapp/home/dashboard/adapter/GridOptionsAdapter.kt +++ b/app/src/main/java/com/naviapp/home/dashboard/adapter/GridOptionsAdapter.kt @@ -7,10 +7,15 @@ package com.naviapp.home.dashboard.adapter +import android.content.res.ColorStateList import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.navi.base.model.ActionData +import com.navi.design.utils.parseColorSafe +import com.navi.naviwidgets.extensions.isValidHexColor +import com.navi.naviwidgets.extensions.setTextFieldData import com.navi.naviwidgets.extensions.showWhenDataIsAvailable import com.naviapp.databinding.GridOptionItemBinding import com.naviapp.home.dashboard.models.response.GridOption @@ -30,9 +35,16 @@ class GridOptionsAdapter(val items: List, val onClick: (action: Acti override fun onBindViewHolder(holder: GridOptionsViewHolder, position: Int) { holder.binding.title.text = items[position].text holder.binding.image.showWhenDataIsAvailable(items[position].imageUrl) + + items[position].tagInfo?.let { tagInfoData -> + holder.binding.tagCard.visibility = View.VISIBLE + holder.binding.tagTv.setTextFieldData(tagInfoData.text) + if(isValidHexColor(tagInfoData.backgroundColor)) { + holder.binding.tagCard.backgroundTintList = ColorStateList.valueOf(tagInfoData.backgroundColor.parseColorSafe()) + } + } holder.itemView.setOnClickListener { items[position].actionData?.let { onClick.invoke(it) } - } } diff --git a/app/src/main/java/com/naviapp/home/dashboard/models/response/GridOption.kt b/app/src/main/java/com/naviapp/home/dashboard/models/response/GridOption.kt index d46d58f537..2044fd9526 100644 --- a/app/src/main/java/com/naviapp/home/dashboard/models/response/GridOption.kt +++ b/app/src/main/java/com/naviapp/home/dashboard/models/response/GridOption.kt @@ -7,12 +7,21 @@ package com.naviapp.home.dashboard.models.response +import android.os.Parcelable import com.google.gson.annotations.SerializedName import com.navi.base.model.ActionData +import com.navi.naviwidgets.models.response.TextFieldData +import kotlinx.android.parcel.Parcelize data class GridOption( @SerializedName("text") val text: String? = null, @SerializedName("imageUrl") val imageUrl: String? = null, - @SerializedName("actionData") val actionData: ActionData? = null + @SerializedName("actionData") val actionData: ActionData? = null, + @SerializedName("tagInfo") val tagInfo: TagInfoData? = null ) +@Parcelize +data class TagInfoData( + @SerializedName("infoText") val text: TextFieldData? = null, + @SerializedName("backgroundColor") val backgroundColor: String? = null +) : Parcelable diff --git a/app/src/main/java/com/naviapp/home/dashboard/repo/DashboardContentRepository.kt b/app/src/main/java/com/naviapp/home/dashboard/repo/DashboardContentRepository.kt index 4533278329..cf5f0efca5 100644 --- a/app/src/main/java/com/naviapp/home/dashboard/repo/DashboardContentRepository.kt +++ b/app/src/main/java/com/naviapp/home/dashboard/repo/DashboardContentRepository.kt @@ -7,15 +7,11 @@ package com.naviapp.home.dashboard.repo -import com.google.common.reflect.TypeToken import com.navi.common.model.ModuleName -import com.navi.common.model.RepoResult import com.navi.naviwidgets.models.response.HideCardData -import com.naviapp.home.dashboard.models.response.DashboardContentResponse import com.naviapp.network.di.SuperAppRetroFit import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.network.retrofit.RetrofitService -import com.naviapp.utils.mockApiResponse import javax.inject.Inject class DashboardContentRepository @@ -26,11 +22,6 @@ constructor( suspend fun fetchDashboardContent(product: String) = apiResponseCallback(retrofitService.fetchDashboardContent(product = product)) - suspend fun fetchDashboardContent1(product: String): RepoResult { - val type = object : TypeToken() {}.type - return mockApiResponse(type, "dashboard_data") - } - suspend fun hideStatusCard2(hideCardData: HideCardData) = apiResponseCallback( retrofitService.hideStatusCard2( diff --git a/app/src/main/java/com/naviapp/home/dashboard/repo/R11PaymentRepository.kt b/app/src/main/java/com/naviapp/home/dashboard/repo/R11PaymentRepository.kt index 02f1e73f55..7c1d7ca283 100644 --- a/app/src/main/java/com/naviapp/home/dashboard/repo/R11PaymentRepository.kt +++ b/app/src/main/java/com/naviapp/home/dashboard/repo/R11PaymentRepository.kt @@ -8,7 +8,7 @@ package com.naviapp.home.dashboard.repo import com.navi.common.model.ModuleName -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult import com.naviapp.home.dashboard.models.response.GenerateQuoteResponse import com.naviapp.home.dashboard.models.response.R11PaymentResponse import com.naviapp.network.retrofit.ResponseCallback diff --git a/app/src/main/java/com/naviapp/home/dashboard/ui/DashboardContentInfoBottomSheet.kt b/app/src/main/java/com/naviapp/home/dashboard/ui/DashboardContentInfoBottomSheet.kt new file mode 100644 index 0000000000..dbe47f3d15 --- /dev/null +++ b/app/src/main/java/com/naviapp/home/dashboard/ui/DashboardContentInfoBottomSheet.kt @@ -0,0 +1,86 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.home.dashboard.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewStub +import android.widget.LinearLayout +import androidx.databinding.DataBindingUtil +import com.navi.chat.common.fragment.BaseBottomSheet +import com.navi.naviwidgets.extensions.setTextFieldData +import com.navi.naviwidgets.models.DashBoardContentInfoBottomSheetData +import com.navi.naviwidgets.models.SubListData +import com.navi.naviwidgets.utils.NaviWidgetIconUtils +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics.Companion.DASHBOARD_INSURANCE_BOTTOMSHEET_DATA +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.databinding.DashboardInsuranceBottomsheetBinding +import com.naviapp.databinding.InfoBottomsheetItemBinding + +class DashboardContentInfoBottomSheet : BaseBottomSheet() { + + private lateinit var binding: DashboardInsuranceBottomsheetBinding + private var data: DashBoardContentInfoBottomSheetData? = null + + override fun setContainerView(viewStub: ViewStub) { + viewStub.layoutResource = R.layout.dashboard_insurance_bottomsheet + binding = DataBindingUtil.getBinding(viewStub.inflate())!! + data = arguments?.getParcelable(CONTENT_INFO_BOTTOMSHEET_DATA) + setProperties() + } + + private fun setProperties() { + binding.run { + data?.topLeftIcon?.let { + NaviWidgetIconUtils.getImageFromIconCode(it.iconCode).let { iconCode -> + if (iconCode != -1) { + calendar.setImageResource(iconCode) + } + } + } + data?.title?.let { title.setTextFieldData(it) } + data?.primaryCta?.let { continueBtn.text = it.title } + data?.secondaryCta?.let { skipBtn.text = it.title } + items.setItemsData(data?.items) + skipBtn.setOnClickListener { + safelyDismissDialog() + } + continueBtn.setOnClickListener { + data?.primaryCta?.let { + NaviDeepLinkNavigator.navigate(activity = activity, ctaData = it) + safelyDismissDialog() + } + } + } + } + private fun LinearLayout.setItemsData(items: List?){ + removeAllViews() + items?.forEach { + val inflater = LayoutInflater.from(context) + val view = inflater.inflate(R.layout.info_bottomsheet_item, this, false) + val binding: InfoBottomsheetItemBinding? = DataBindingUtil.bind(view) + binding?.subtitle?.setTextFieldData(it.title) + addView(binding?.root) + } + } + + companion object { + val CONTENT_INFO_BOTTOMSHEET_DATA = "bottomSheetData" + val TAG = DASHBOARD_INSURANCE_BOTTOMSHEET_DATA + + fun getInstance(bundle: Bundle? = Bundle.EMPTY): DashboardContentInfoBottomSheet { + return DashboardContentInfoBottomSheet().apply { + arguments = bundle + } + } + } + + override val screenName: String + get() = DASHBOARD_INSURANCE_BOTTOMSHEET_DATA +} diff --git a/app/src/main/java/com/naviapp/home/dashboard/ui/GridOptionsBottomSheet.kt b/app/src/main/java/com/naviapp/home/dashboard/ui/GridOptionsBottomSheet.kt index 4e73d72d0a..cf93119cf0 100644 --- a/app/src/main/java/com/naviapp/home/dashboard/ui/GridOptionsBottomSheet.kt +++ b/app/src/main/java/com/naviapp/home/dashboard/ui/GridOptionsBottomSheet.kt @@ -59,8 +59,8 @@ class GridOptionsBottomSheet : BaseBottomSheet() { companion object { const val TAG = "GridOptionsBottomSheet" - const val data = "data" - const val error = "error" + const val data = "data" + const val error = "error" fun getInstance(bundle: Bundle): GridOptionsBottomSheet { return GridOptionsBottomSheet().apply { arguments = bundle } } diff --git a/app/src/main/java/com/naviapp/home/dashboard/ui/ProductFragment.kt b/app/src/main/java/com/naviapp/home/dashboard/ui/ProductFragment.kt index 7a875aae4a..081071d8df 100644 --- a/app/src/main/java/com/naviapp/home/dashboard/ui/ProductFragment.kt +++ b/app/src/main/java/com/naviapp/home/dashboard/ui/ProductFragment.kt @@ -31,18 +31,19 @@ import com.navi.common.ui.activity.BaseActivity import com.navi.common.ui.fragment.ActionErrorFragment import com.navi.common.ui.fragment.BaseFragment import com.navi.common.ui.fragment.FullScreenErrorDialog -import com.navi.common.utils.* +import com.navi.common.utils.Constants import com.navi.common.utils.Constants.USER_ID import com.navi.common.utils.Constants.USER_LOGGED_IN +import com.navi.common.utils.log +import com.navi.common.utils.observeNonNull +import com.navi.common.utils.toCtaData import com.navi.common.viewmodel.BaseVM import com.navi.insurance.claim.fragment.ClaimsBottomSheet import com.navi.insurance.common.activity.BenefitWebViewActivity -import com.navi.naviwidgets.actions.ClosedLoansClicked -import com.navi.naviwidgets.actions.InformationWidgetCloseClickAction -import com.navi.naviwidgets.actions.NavigateClickAction -import com.navi.naviwidgets.actions.ShowBottomSheetClicked +import com.navi.naviwidgets.actions.* import com.navi.naviwidgets.adapters.NaviAdapter import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.models.DashBoardContentInfoBottomSheetData import com.navi.naviwidgets.models.NaviWidget import com.navi.naviwidgets.models.response.AdditionalBottomSheetData import com.navi.naviwidgets.utils.getBottomSheetWidgetData @@ -52,6 +53,7 @@ import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.fragment.DashboardPolicyBenefitBottomSheet import com.naviapp.common.fragment.DashboardPolicyPaymentBottomSheet +import com.naviapp.common.fragment.InfoBottomSheetV3 import com.naviapp.common.listeners.DashboardPolicyBenefitBottomSheetListener import com.naviapp.common.navigator.NaviDeepLinkNavigator import com.naviapp.databinding.FragmentProductBinding @@ -66,6 +68,7 @@ import com.naviapp.models.PolicyBenefitData import com.naviapp.models.PolicyBenefitStatus import com.naviapp.utils.Constants.BOTTOMSHEET_SELECT_POLICY import com.naviapp.utils.Constants.GI_CLAIMS_BOTTOMSHEET +import com.naviapp.utils.Constants.GI_INFO_BOTTOMSHEET import com.naviapp.utils.Constants.GRID_OPTION_BOTTOMSHEET import com.naviapp.utils.Constants.KEY_DASHBOARD_TAB_DATA import com.naviapp.utils.Constants.OPD @@ -311,6 +314,11 @@ class ProductFragment : BaseFragment(), WidgetCallback, DashboardPolicyBenefitBo UniversalBottomSheet.getInstance(naviClickAction.genericBottomSheetData) safelyShowBottomSheet(bottomSheet, UniversalBottomSheet.TAG) } + is ShowInfoBottomSheetV3Action -> { + val bottomSheet = + InfoBottomSheetV3.getInstance(naviClickAction.infoBottomSheetInfoV2) + safelyShowBottomSheet(bottomSheet, InfoBottomSheetV3.TAG) + } is ClosedLoansClicked -> { NaviTrackEvent.setStartTs(screenName) startActivity(Intent(context, ClosedLoansActivity::class.java)) @@ -390,6 +398,25 @@ class ProductFragment : BaseFragment(), WidgetCallback, DashboardPolicyBenefitBo val bottomsheet = ClaimsBottomSheet.newInstance(bundle) safelyShowBottomSheet(bottomsheet, ClaimsBottomSheet.TAG) } + GI_INFO_BOTTOMSHEET -> { + val dataString: String? = action.parameters?.getOrNull(0)?.value + val data: DashBoardContentInfoBottomSheetData? = + if (!dataString.isNullOrEmpty()) Gson().fromJson( + dataString, + DashBoardContentInfoBottomSheetData::class.java + ) else null + if (data != null) { + val bundle = + Bundle().apply { + putParcelable( + DashboardContentInfoBottomSheet.CONTENT_INFO_BOTTOMSHEET_DATA, + data + ) + } + val bottomSheet = DashboardContentInfoBottomSheet.getInstance(bundle) + safelyShowBottomSheet(bottomSheet, DashboardContentInfoBottomSheet.TAG) + } + } BOTTOMSHEET_SELECT_POLICY -> { handlePolices(action.parameters?.getOrNull(0)?.value) } @@ -527,4 +554,4 @@ class ProductFragment : BaseFragment(), WidgetCallback, DashboardPolicyBenefitBo NaviDeepLinkNavigator.navigate(activity, ctaData) } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/home/dashboard/viewmodels/R11PaymentBottomSheetVM.kt b/app/src/main/java/com/naviapp/home/dashboard/viewmodels/R11PaymentBottomSheetVM.kt index 525c0abbfa..8ae4e98a06 100644 --- a/app/src/main/java/com/naviapp/home/dashboard/viewmodels/R11PaymentBottomSheetVM.kt +++ b/app/src/main/java/com/naviapp/home/dashboard/viewmodels/R11PaymentBottomSheetVM.kt @@ -11,8 +11,8 @@ import android.os.Bundle import androidx.lifecycle.viewModelScope import com.navi.analytics.utils.NaviTrackEvent import com.navi.common.extensions.isNull -import com.navi.common.model.GenericErrorResponse import com.navi.common.network.models.ErrorMessage +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.viewmodel.BaseVM import com.naviapp.home.dashboard.models.response.GenerateQuoteResponse import com.naviapp.home.dashboard.models.response.R11PaymentResponse diff --git a/app/src/main/java/com/naviapp/home/fragment/HomeFragment.kt b/app/src/main/java/com/naviapp/home/fragment/HomeFragment.kt index bf8cb1db7d..89483bd21f 100644 --- a/app/src/main/java/com/naviapp/home/fragment/HomeFragment.kt +++ b/app/src/main/java/com/naviapp/home/fragment/HomeFragment.kt @@ -36,6 +36,7 @@ import com.navi.common.listeners.DialogCancelListener import com.navi.common.managers.NaviLocationManager import com.navi.common.managers.PermissionsManager import com.navi.common.model.PreviousScreenNameRequest +import com.navi.common.ui.activity.BaseActivity import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* import com.navi.insurance.navigator.NaviInsuranceDeeplinkNavigator @@ -77,6 +78,8 @@ import com.naviapp.nps.viewmodel.NpsVM import com.naviapp.payment.listeners.PaymentInitListener import com.naviapp.payment.viewmodel.PaymentVM import com.naviapp.personalloan.getloan.activities.GetLoanActivity +import com.naviapp.rewards.models.RewardsAnnouncementData +import com.naviapp.rewards.ui.RewardsAnnouncementFragment import com.naviapp.utils.* import com.naviapp.utils.Constants import com.naviapp.utils.Constants.HOME_FEATURE @@ -124,9 +127,8 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di initUI() initListener() initObservers() - viewModel.fetchHomeItems() + fetchHomeItems() fetchHomeFeature() - activity?.run { permissionsManager = PermissionsManager(this) } fetchStories() return binding.root @@ -139,6 +141,32 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di } } + private fun fetchHomeItems() { + if (BaseUtils.isUserLoggedIn().not() && + PreferenceManager.getSecureString(com.navi.common.utils.Constants.OFFER_VALUE) + .isNullOrEmpty().not() + && PreferenceManager.getBooleanPreference(Constants.OFFER_VIEWED).not() + ) { + context?.let { + val density = getDensityName(context = it).orEmpty() + val connectivityType = getNetworkType(context = it) + val queryMap = HashMap() + queryMap[PreferenceManager.getSecureString( + com.navi.common.utils.Constants.OFFER_KEY + ).orEmpty()] = + PreferenceManager.getSecureString( + com.navi.common.utils.Constants.OFFER_VALUE + ).orEmpty() + PreferenceManager.setBooleanPreference(Constants.OFFER_VIEWED, true) + viewModel.fetchHomeItems(queryMap, density, connectivityType) + } ?: kotlin.run { + viewModel.fetchHomeItems() + } + } else { + viewModel.fetchHomeItems() + } + } + private fun fetchStories() { activity?.let { val sharedVM = ViewModelProvider(it).get(DashboardSharedVM::class.java) @@ -249,9 +277,9 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { if ( dy != 0 && - PreferenceManager.getBooleanPreference( - SHOW_SCROLL_FEEDBACK_IN_HOME_SCREEN - ) + PreferenceManager.getBooleanPreference( + SHOW_SCROLL_FEEDBACK_IN_HOME_SCREEN + ) ) { PreferenceManager.setBooleanPreference( SHOW_SCROLL_FEEDBACK_IN_HOME_SCREEN, @@ -264,6 +292,9 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di ) } } + response?.extraData?.rewardsIntroPopup?.let { + readRewardsAnnouncementData(it) + } sendLocationUpdates() binding.ivScrollFeedback.setOnClickListener { stopScrollAnimationAndHideView() @@ -311,8 +342,7 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di npsVM.ratingSubmitResponse.observeNonNull(viewLifecycleOwner) { if (it.response == Constants.SUCCESS) { - viewModel.homeFeatures.value?.survey?.content?.dialogBoxInfo?.let { - dialogBoxResponse -> + viewModel.homeFeatures.value?.survey?.content?.dialogBoxInfo?.let { dialogBoxResponse -> if ( arguments ?.getParcelable(Constants.PREVIOUS_SCREEN) @@ -322,20 +352,20 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di NaviInsuranceDeeplinkNavigator.navigate( activity = activity, ctaData = - CtaData( - url = - giDeeplink( - NaviInsuranceDeeplinkNavigator.DASHBOARD.plus( - Constants.DIVIDER - ) - .plus(NaviInsuranceDeeplinkNavigator.HOME) - ) - ), + CtaData( + url = + giDeeplink( + NaviInsuranceDeeplinkNavigator.DASHBOARD.plus( + Constants.DIVIDER + ) + .plus(NaviInsuranceDeeplinkNavigator.HOME) + ) + ), finish = true, bundle = - Bundle().apply { - putParcelable(NPS_SUBMIT_DIALOG, dialogBoxResponse) - } + Bundle().apply { + putParcelable(NPS_SUBMIT_DIALOG, dialogBoxResponse) + } ) } else { val commonDialogBox = @@ -354,6 +384,17 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di } } + private fun readRewardsAnnouncementData(rewardData: RewardsAnnouncementData) { + val rewardsAnnouncementFragment = RewardsAnnouncementFragment.getInstance( + rewardsAnnouncementData = rewardData, + screenName = screenName + ) + (activity as BaseActivity).safelyOpenFragment( + rewardsAnnouncementFragment, + RewardsAnnouncementFragment.TAG + ) + } + private fun stopScrollAnimationAndHideView() { binding.ivScrollFeedback.clearAnimation() binding.ivScrollFeedback.visibility = GONE @@ -446,13 +487,13 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di Intent.ACTION_DIAL, Uri.parse( "tel:" + - (parameters - ?.filter { it.key == com.navi.common.utils.Constants.PHONE } - ?.getOrNull(0) - ?.value - ?: (FirebaseRemoteConfigHelper.getString( - FirebaseRemoteConfigHelper.HELP_LINE_NUMBER - ))) + (parameters + ?.filter { it.key == com.navi.common.utils.Constants.PHONE } + ?.getOrNull(0) + ?.value + ?: (FirebaseRemoteConfigHelper.getString( + FirebaseRemoteConfigHelper.HELP_LINE_NUMBER + ))) ) ) startActivity(intent) @@ -534,7 +575,7 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di private fun toShowWhatsNewTag() { if ( viewModel.appStoriesData.value?.description.isNotNull() && - !PreferenceManager.getBooleanPreferenceApp(IS_WHATS_NEW_TAG_SHOWN) + !PreferenceManager.getBooleanPreferenceApp(IS_WHATS_NEW_TAG_SHOWN) ) { binding.tagBuilder.apply { root.visibility = View.VISIBLE @@ -563,12 +604,12 @@ class HomeFragment : BaseFragment(), WidgetCallback, PlayStoreActionListener, Di OptionSelectBottomsheet.newInstance( bundle, secondaryListener = - object : OptionSelectorListener { - override fun onItemSelected(cta: ActionData) { - widgetNaviAnalyticsEventTracker.onWidgetClickEvent(cta) - NaviDeepLinkNavigator.navigate(activity, cta.toCtaData()) - } + object : OptionSelectorListener { + override fun onItemSelected(cta: ActionData) { + widgetNaviAnalyticsEventTracker.onWidgetClickEvent(cta) + NaviDeepLinkNavigator.navigate(activity, cta.toCtaData()) } + } ) safelyShowBottomSheet(bottomSheet, OptionSelectBottomsheet.TAG) } diff --git a/app/src/main/java/com/naviapp/home/model/WidgetResponse.kt b/app/src/main/java/com/naviapp/home/model/WidgetResponse.kt index 6e064532ec..c799b4e06a 100644 --- a/app/src/main/java/com/naviapp/home/model/WidgetResponse.kt +++ b/app/src/main/java/com/naviapp/home/model/WidgetResponse.kt @@ -1,16 +1,39 @@ package com.naviapp.home.model import com.google.gson.annotations.SerializedName +import com.navi.base.model.BottomSheetData import com.navi.naviwidgets.models.NaviWidget +import com.naviapp.models.response.Header +import com.naviapp.rewards.models.RewardsAnnouncementData data class WidgetResponse( @SerializedName("contentWidget") var contentWidget: List? = null, @SerializedName("extraData") - val extraData: ExtraDataDetails? = null + val extraData: ExtraDataDetails? = null, + @SerializedName("header") + val header: Header? = null, + @SerializedName("footerWidget") + val footerWidget: List? = null, + @SerializedName("headerWidget") + val headerWidget: List? = null ) data class ExtraDataDetails( @SerializedName("greetingText") - val greetingText: String? = null + val greetingText: String? = null, + @SerializedName("exchangeRateId") + val exchangeRateId: String? = null, + @SerializedName("loadingBottomSheet") + val loadingBottomSheet: BottomSheetData? = null, + @SerializedName("delay") + val delay: Long? = null, + @SerializedName("totalAmount") + val totalAmount: Double? = null, + @SerializedName("pricePerMg") + val pricePerMg: Double? = null, + @SerializedName("rewardsIntroPopup") + val rewardsIntroPopup: RewardsAnnouncementData? = null, + @SerializedName("updateWidgetPosition") + val updateWidgetPosition: List? = null ) \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/home/respository/HomeRepository.kt b/app/src/main/java/com/naviapp/home/respository/HomeRepository.kt index aef071a1ee..f427f80cef 100644 --- a/app/src/main/java/com/naviapp/home/respository/HomeRepository.kt +++ b/app/src/main/java/com/naviapp/home/respository/HomeRepository.kt @@ -7,6 +7,8 @@ package com.naviapp.home.respository +import com.navi.common.network.models.RepoResult +import com.naviapp.home.model.WidgetResponse import com.naviapp.network.di.SuperAppRetroFit import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.network.retrofit.RetrofitService @@ -14,7 +16,22 @@ import javax.inject.Inject class HomeRepository @Inject constructor(@SuperAppRetroFit private val superAppRetrofitService: RetrofitService) : ResponseCallback() { - suspend fun fetchHomeItems() = apiResponseCallback(superAppRetrofitService.fetchHomeItems()) + suspend fun fetchHomeItems( + queryMap: HashMap?, + density: String?, + connectivityType: String? + ): RepoResult { + return if (queryMap.isNullOrEmpty()) + apiResponseCallback(superAppRetrofitService.fetchHomeItems()) + else + apiResponseCallback( + superAppRetrofitService.fetchHomeItems( + queryMap, + density.orEmpty(), + connectivityType.orEmpty() + ) + ) + } suspend fun fetchStories(density: String) = apiResponseCallback(superAppRetrofitService.fetchStories(density)) diff --git a/app/src/main/java/com/naviapp/home/viewmodel/HomeVM.kt b/app/src/main/java/com/naviapp/home/viewmodel/HomeVM.kt index e7651128ce..6f66d22328 100644 --- a/app/src/main/java/com/naviapp/home/viewmodel/HomeVM.kt +++ b/app/src/main/java/com/naviapp/home/viewmodel/HomeVM.kt @@ -34,9 +34,13 @@ class HomeVM @Inject constructor(private val repository: HomeRepository) : val appStoriesData: LiveData get() = _appStoriesData - fun fetchHomeItems() { + fun fetchHomeItems( + queryMap: HashMap? = null, + density: String? = null, + connectivityType: String? = null + ) { coroutineScope.launch { - val response = repository.fetchHomeItems() + val response = repository.fetchHomeItems(queryMap, density, connectivityType) if (response.error == null && response.errors.isNullOrEmpty()) { _homeItems.value = response.data } else { diff --git a/app/src/main/java/com/naviapp/homeloandigital/eligibility/fragment/form/HomeLoanFormFragmentViewModel.kt b/app/src/main/java/com/naviapp/homeloandigital/eligibility/fragment/form/HomeLoanFormFragmentViewModel.kt index 5cda521ae3..23884a6061 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/eligibility/fragment/form/HomeLoanFormFragmentViewModel.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/eligibility/fragment/form/HomeLoanFormFragmentViewModel.kt @@ -1,27 +1,35 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.homeloandigital.eligibility.fragment.form import android.text.TextUtils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.navi.common.viewmodel.BaseVM import com.navi.common.firebasedb.FirebaseStatusType +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.network.models.GenericWarningResponse +import com.navi.common.viewmodel.BaseVM import com.naviapp.homeloandigital.eligibility.fragment.form.repository.HomeLoanFormRepository import com.naviapp.homeloandigital.models.FormResponse import com.naviapp.homeloandigital.models.InputSearchResponse import com.naviapp.models.RedirectPageStatus import com.naviapp.models.response.ProfileDetailsResponse -import com.navi.common.model.UploadDataAsyncResponse import com.naviapp.network.ApiConstants import com.naviapp.network.ApiErrorTagType -import com.navi.common.model.GenericErrorResponse -import com.navi.common.model.GenericWarningResponse import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch import javax.inject.Inject +import kotlinx.coroutines.launch @HiltViewModel -class HomeLoanFormFragmentViewModel @Inject constructor(private val repository: HomeLoanFormRepository) : - BaseVM() { +class HomeLoanFormFragmentViewModel +@Inject +constructor(private val repository: HomeLoanFormRepository) : BaseVM() { private val _formGetResponse = MutableLiveData() val formGetResponse: LiveData get() = _formGetResponse @@ -118,10 +126,7 @@ class HomeLoanFormFragmentViewModel @Inject constructor(private val repository: } } - fun checkUiStatus( - errors: List?, - warning: GenericWarningResponse? - ) { + fun checkUiStatus(errors: List?, warning: GenericWarningResponse?) { coroutineScope.launch { val response = repository.checkUiStatus() if (response.error == null) { @@ -142,4 +147,4 @@ class HomeLoanFormFragmentViewModel @Inject constructor(private val repository: fun getFormPageType(): FormBaseFragment.FormPageType? { return _formPageType.value } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/homeloandigital/eligibility/fragment/panerror/PanErrorFragmentV2.kt b/app/src/main/java/com/naviapp/homeloandigital/eligibility/fragment/panerror/PanErrorFragmentV2.kt index a3ac47291a..f72df236ca 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/eligibility/fragment/panerror/PanErrorFragmentV2.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/eligibility/fragment/panerror/PanErrorFragmentV2.kt @@ -1,3 +1,10 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.homeloandigital.eligibility.fragment.panerror import android.os.Bundle @@ -5,21 +12,21 @@ import android.view.ViewStub import androidx.databinding.DataBindingUtil import com.navi.analytics.utils.NaviTrackEvent import com.navi.base.model.CtaData +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.ui.fragment.BaseBottomSheet import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics -import com.navi.common.ui.fragment.BaseBottomSheet import com.naviapp.databinding.PanNameMismatchLayoutV2Binding import com.naviapp.homeloandigital.common.ui.activity.Navigator import com.naviapp.homeloandigital.eligibility.fragment.panerror.PanOptionViewV2.PanOptionTag -import com.naviapp.homeloandigital.eligibility.fragment.panerror.PanOptionViewV2.PanOptionTag.* -import com.navi.common.model.GenericErrorResponse +import com.naviapp.homeloandigital.eligibility.fragment.panerror.PanOptionViewV2.PanOptionTag.PAN_NAME +import com.naviapp.homeloandigital.eligibility.fragment.panerror.PanOptionViewV2.PanOptionTag.PAN_NUMBER import com.naviapp.personalloan.getloan.common.adapters.InstructionsAdapter class PanErrorFragmentV2 : BaseBottomSheet() { private lateinit var binding: PanNameMismatchLayoutV2Binding private var selectedOption: PanOptionViewV2? = null - override fun setContainerView(viewStub: ViewStub) { viewStub.layoutResource = R.layout.pan_name_mismatch_layout_v2 binding = DataBindingUtil.getBinding(viewStub.inflate())!! @@ -39,30 +46,36 @@ class PanErrorFragmentV2 : BaseBottomSheet() { binding.nameOptionView.setOptionSelected(false) selectedOption = binding.nameOptionView binding.actionButton.setProperties(resources.getString(R.string.continue_text)) - binding.actionButton.setOnClickListener { - onClickActionBtn(selectedOption?.cta) - } + binding.actionButton.setOnClickListener { onClickActionBtn(selectedOption?.cta) } } } private fun GenericErrorResponse.initActions() { - actions?.map { it.title?.split(DELIMITER) }?.let { - if (it.isEmpty()) return@let + actions + ?.map { it.title?.split(DELIMITER) } + ?.let { + if (it.isEmpty()) return@let - it.getOrNull(0)?.apply { - binding.nameOptionView.setProperties(getOrNull(0), getOrNull(1)?.trim(), PAN_NAME, actions?.getOrNull(0)?.cta) - binding.nameOptionView.onClickAction = { - onSelectPanOption(PAN_NAME) + it.getOrNull(0)?.apply { + binding.nameOptionView.setProperties( + getOrNull(0), + getOrNull(1)?.trim(), + PAN_NAME, + actions?.getOrNull(0)?.cta + ) + binding.nameOptionView.onClickAction = { onSelectPanOption(PAN_NAME) } + } + + it.getOrNull(1)?.apply { + binding.panOptionView.setProperties( + getOrNull(0), + getOrNull(1)?.trim(), + PAN_NUMBER, + null + ) + binding.panOptionView.onClickAction = { onSelectPanOption(PAN_NUMBER) } } } - - it.getOrNull(1)?.apply { - binding.panOptionView.setProperties(getOrNull(0), getOrNull(1)?.trim(), PAN_NUMBER, null) - binding.panOptionView.onClickAction = { - onSelectPanOption(PAN_NUMBER) - } - } - } } private fun onClickActionBtn(cta: CtaData?) { @@ -97,10 +110,11 @@ class PanErrorFragmentV2 : BaseBottomSheet() { private const val ERROR_DATA = "ERROR_DATA" private const val DELIMITER = ":" - fun getInstance(error: GenericErrorResponse) = PanErrorFragmentV2().apply { - val bundle = Bundle() - bundle.putParcelable(ERROR_DATA, error) - arguments = bundle - } + fun getInstance(error: GenericErrorResponse) = + PanErrorFragmentV2().apply { + val bundle = Bundle() + bundle.putParcelable(ERROR_DATA, error) + arguments = bundle + } } } diff --git a/app/src/main/java/com/naviapp/homeloandigital/eligibility/repository/HomeLoanPermissionRepository.kt b/app/src/main/java/com/naviapp/homeloandigital/eligibility/repository/HomeLoanPermissionRepository.kt index 5c6217b32b..ccf05ba070 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/eligibility/repository/HomeLoanPermissionRepository.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/eligibility/repository/HomeLoanPermissionRepository.kt @@ -1,3 +1,10 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.homeloandigital.eligibility.repository /* @@ -7,18 +14,19 @@ package com.naviapp.homeloandigital.eligibility.repository * */ +import com.navi.common.network.models.RepoResult import com.naviapp.homeloandigital.models.response.HLPermissionDetailsResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.network.retrofit.RetrofitService import javax.inject.Inject -class HomeLoanPermissionRepository @Inject constructor(private val retrofitService: RetrofitService) : - ResponseCallback() { +class HomeLoanPermissionRepository +@Inject +constructor(private val retrofitService: RetrofitService) : ResponseCallback() { - suspend fun fetchHomeLoanPermissionResponse(queryMap: HashMap): - RepoResult { + suspend fun fetchHomeLoanPermissionResponse( + queryMap: HashMap + ): RepoResult { return apiResponseCallback(retrofitService.fetchHomeLoanPermissionResponse(queryMap)) } - } diff --git a/app/src/main/java/com/naviapp/homeloandigital/ipagenerate/viewmodel/HomeLoanIpaLoaderVM.kt b/app/src/main/java/com/naviapp/homeloandigital/ipagenerate/viewmodel/HomeLoanIpaLoaderVM.kt index b17a513470..1d4c571c0e 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/ipagenerate/viewmodel/HomeLoanIpaLoaderVM.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/ipagenerate/viewmodel/HomeLoanIpaLoaderVM.kt @@ -11,8 +11,8 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.navi.base.model.CtaData -import com.navi.common.model.GenericErrorResponse import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.viewmodel.BaseVM import com.naviapp.homeloandigital.ipagenerate.repo.HomeLoanIpaLoaderRepository import com.naviapp.network.ApiConstants.E_HL_PAN_VERIFICATION_FAILED diff --git a/app/src/main/java/com/naviapp/homeloandigital/models/FormFooter.kt b/app/src/main/java/com/naviapp/homeloandigital/models/FormFooter.kt index c6b9099d54..7e6f6f83a4 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/models/FormFooter.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/models/FormFooter.kt @@ -1,20 +1,27 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.homeloandigital.models import android.os.Parcelable import com.google.gson.annotations.SerializedName import com.navi.base.model.CtaData +import com.navi.naviwidgets.models.response.TextFieldData import kotlinx.android.parcel.Parcelize @Parcelize data class FormFooter( - @SerializedName("footerCheckBox") - val footerCheckBox: FooterCheckBox? = null, - @SerializedName("nextCta") - var nextCta: CtaData? = null, + @SerializedName("footerCheckBox") val footerCheckBox: FooterCheckBox? = null, + @SerializedName("nextCta") var nextCta: CtaData? = null, + @SerializedName("message") val message: TextFieldData? = null ) : Parcelable @Parcelize data class FooterCheckBox( @SerializedName("text") val text: String? = null, @SerializedName("isChecked") val isChecked: Boolean? = null -) : Parcelable \ No newline at end of file +) : Parcelable diff --git a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanDocumentUploadRepository.kt b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanDocumentUploadRepository.kt index bde59f129a..821177b0a8 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanDocumentUploadRepository.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanDocumentUploadRepository.kt @@ -1,33 +1,35 @@ /* * - * * Copyright © 2022 by Navi Technologies Private Limited + * * Copyright © 2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.homeloandigital.posteligibility.repository +import com.navi.common.network.models.RepoResult import com.naviapp.homeloandigital.models.request.HomeLoanDocumentIdRequest import com.naviapp.homeloandigital.models.request.HomeLoanDocumentKeyRequest import com.naviapp.models.response.HomeLoanDocumentPostResponse import com.naviapp.models.response.HomeLoanDocumentUploadResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.network.retrofit.RetrofitService import javax.inject.Inject -class HomeLoanDocumentUploadRepository @Inject constructor(private val retrofitService: RetrofitService) : - ResponseCallback() { +class HomeLoanDocumentUploadRepository +@Inject +constructor(private val retrofitService: RetrofitService) : ResponseCallback() { suspend fun fetchDocumentUploadDetails( documentType: String, loanApplicationId: String, contextKey: String? - ): - RepoResult { + ): RepoResult { return apiResponseCallback( retrofitService.fetchHomeLoanDocumentUploadDetails( - documentType, loanApplicationId, contextKey + documentType, + loanApplicationId, + contextKey ) ) } @@ -39,7 +41,9 @@ class HomeLoanDocumentUploadRepository @Inject constructor(private val retrofitS ): RepoResult { return apiResponseCallback( retrofitService.sendHomeLoanDocumentUploadDetails( - loanApplicationId, homeLoanDocumentKeyRequest, contextKey + loanApplicationId, + homeLoanDocumentKeyRequest, + contextKey ) ) } @@ -51,7 +55,9 @@ class HomeLoanDocumentUploadRepository @Inject constructor(private val retrofitS ): RepoResult { return apiResponseCallback( retrofitService.deleteHomeLoanDocuments( - loanApplicationId, HomeLoanDocumentIdRequest(documentIdList), contextKey + loanApplicationId, + HomeLoanDocumentIdRequest(documentIdList), + contextKey ) ) } @@ -61,10 +67,7 @@ class HomeLoanDocumentUploadRepository @Inject constructor(private val retrofitS contextKey: String? ): RepoResult { return apiResponseCallback( - retrofitService.submitHomeLoanDocuments( - loanApplicationId, - contextKey - ) + retrofitService.submitHomeLoanDocuments(loanApplicationId, contextKey) ) } } diff --git a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanPostEligibilityV2Repository.kt b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanPostEligibilityV2Repository.kt index e68846195d..0c93c35ba6 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanPostEligibilityV2Repository.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanPostEligibilityV2Repository.kt @@ -7,8 +7,8 @@ package com.naviapp.homeloandigital.posteligibility.repository -import com.navi.common.model.RepoResult import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.RepoResult import com.navi.naviwidgets.models.response.esign.DigioStatusUpdateRequestModel import com.naviapp.homeloandigital.common.models.RequestCallbackRequest import com.naviapp.homeloandigital.models.* diff --git a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanPropertyDocumentStatusRepo.kt b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanPropertyDocumentStatusRepo.kt index 7141c8cc33..624f7186d9 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanPropertyDocumentStatusRepo.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/repository/HomeLoanPropertyDocumentStatusRepo.kt @@ -7,7 +7,7 @@ package com.naviapp.homeloandigital.posteligibility.repository -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult import com.naviapp.homeloandigital.models.response.HomeLoanPropertyDocsStatusResponse import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.network.retrofit.RetrofitService diff --git a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/viewmodel/HomeLoanAddressFragmentVM.kt b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/viewmodel/HomeLoanAddressFragmentVM.kt index b638c2117d..53ba983431 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/viewmodel/HomeLoanAddressFragmentVM.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/viewmodel/HomeLoanAddressFragmentVM.kt @@ -1,3 +1,10 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.homeloandigital.posteligibility.viewmodel /* @@ -11,7 +18,9 @@ import android.content.res.Resources import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.navi.common.model.GenericErrorResponse +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.viewmodel.BaseVM import com.navi.naviwidgets.validations.NotEmptyValidation import com.navi.naviwidgets.validations.RegexInputValidation import com.navi.naviwidgets.widgets.TextInputUtil @@ -19,20 +28,19 @@ import com.navi.naviwidgets.widgets.labledtextinput.InputTextWidgetMeta import com.navi.naviwidgets.widgets.labledtextinput.LabeledTextInputWidgetModelV2 import com.navi.naviwidgets.widgets.labledtextinput.TextInputWidgetData import com.naviapp.R -import com.navi.common.viewmodel.BaseVM import com.naviapp.homeloandigital.models.response.HLAddressFieldData import com.naviapp.homeloandigital.models.response.HLKycAddressDetails import com.naviapp.homeloandigital.posteligibility.repository.HomeLoanPostEligibilityV2Repository import com.naviapp.models.response.PinCodeData -import com.navi.common.model.UploadDataAsyncResponse import com.naviapp.network.ApiErrorTagType import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch import javax.inject.Inject +import kotlinx.coroutines.launch @HiltViewModel -class HomeLoanAddressFragmentVM @Inject constructor(private val repository: HomeLoanPostEligibilityV2Repository) : - BaseVM() { +class HomeLoanAddressFragmentVM +@Inject +constructor(private val repository: HomeLoanPostEligibilityV2Repository) : BaseVM() { private val _kycAddressResponse = MutableLiveData() val kycAddressResponse: LiveData @@ -115,24 +123,29 @@ class HomeLoanAddressFragmentVM @Inject constructor(private val repository: Home } fun getLine1Data(resources: Resources, savedText: String?): LabeledTextInputWidgetModelV2 { - val line1WidgetData = TextInputWidgetData().apply { - title = resources.getString(R.string.address_line_one) - inputTextData = - InputTextWidgetMeta( - hint = resources.getString( - R.string.hl_digital_self_employed_address_line1_hint - ), - inputType = TextInputUtil.INPUT_TYPE_TEXT, - maxCharLength = 50, - savedText = savedText.orEmpty() - ) - inputValidationList = listOf( - NotEmptyValidation() - .apply { - errorText = - resources.getString(R.string.hl_digital_self_employed_address_not_empty_message) - }) - } + val line1WidgetData = + TextInputWidgetData().apply { + title = resources.getString(R.string.address_line_one) + inputTextData = + InputTextWidgetMeta( + hint = + resources.getString( + R.string.hl_digital_self_employed_address_line1_hint + ), + inputType = TextInputUtil.INPUT_TYPE_TEXT, + maxCharLength = 50, + savedText = savedText.orEmpty() + ) + inputValidationList = + listOf( + NotEmptyValidation().apply { + errorText = + resources.getString( + R.string.hl_digital_self_employed_address_not_empty_message + ) + } + ) + } return LabeledTextInputWidgetModelV2( widgetId = KycAddressWidgetName.ADDRESS.value, LabeledTextInputWidgetModelV2.WIDGET_NAME, @@ -141,18 +154,20 @@ class HomeLoanAddressFragmentVM @Inject constructor(private val repository: Home } fun getLine2Data(resources: Resources, savedText: String?): LabeledTextInputWidgetModelV2 { - val line2WidgetData = TextInputWidgetData().apply { - title = resources.getString(R.string.address_line_two) - inputTextData = - InputTextWidgetMeta( - hint = resources.getString( - R.string.hl_digital_self_employed_address_line2_hint - ), - inputType = TextInputUtil.INPUT_TYPE_TEXT, - maxCharLength = 50, - savedText = savedText.orEmpty() - ) - } + val line2WidgetData = + TextInputWidgetData().apply { + title = resources.getString(R.string.address_line_two) + inputTextData = + InputTextWidgetMeta( + hint = + resources.getString( + R.string.hl_digital_self_employed_address_line2_hint + ), + inputType = TextInputUtil.INPUT_TYPE_TEXT, + maxCharLength = 50, + savedText = savedText.orEmpty() + ) + } return LabeledTextInputWidgetModelV2( widgetId = KycAddressWidgetName.AREA.value, @@ -162,23 +177,24 @@ class HomeLoanAddressFragmentVM @Inject constructor(private val repository: Home } fun getPinCodeData(resources: Resources, savedText: String?): LabeledTextInputWidgetModelV2 { - val pinCodeWidgetData = TextInputWidgetData().apply { - title = resources.getString(R.string.pincode_criteria) - inputTextData = - InputTextWidgetMeta( - hint = resources.getString(R.string.enter_pincode), - inputType = TextInputUtil.INPUT_TYPE_NUMBER, - maxCharLength = 6, - savedText = savedText.orEmpty() - ) - inputValidationList = listOf( - RegexInputValidation().apply { - regex = "^[1-9][0-9]{5}\$" - errorText = - resources.getString(R.string.please_enter_valid_pincode) - } - ) - } + val pinCodeWidgetData = + TextInputWidgetData().apply { + title = resources.getString(R.string.pincode_criteria) + inputTextData = + InputTextWidgetMeta( + hint = resources.getString(R.string.enter_pincode), + inputType = TextInputUtil.INPUT_TYPE_NUMBER, + maxCharLength = 6, + savedText = savedText.orEmpty() + ) + inputValidationList = + listOf( + RegexInputValidation().apply { + regex = "^[1-9][0-9]{5}\$" + errorText = resources.getString(R.string.please_enter_valid_pincode) + } + ) + } return LabeledTextInputWidgetModelV2( widgetId = KycAddressWidgetName.PINCODE.value, LabeledTextInputWidgetModelV2.WIDGET_NAME, @@ -187,16 +203,17 @@ class HomeLoanAddressFragmentVM @Inject constructor(private val repository: Home } fun getCityData(resources: Resources, savedText: String?): LabeledTextInputWidgetModelV2 { - val cityWidgetData = TextInputWidgetData().apply { - title = resources.getString(R.string.city) - inputTextData = - InputTextWidgetMeta( - hint = resources.getString(R.string.enter_city), - maxCharLength = 30, - savedText = savedText.orEmpty() - ) - inputValidationList = listOf(NotEmptyValidation()) - } + val cityWidgetData = + TextInputWidgetData().apply { + title = resources.getString(R.string.city) + inputTextData = + InputTextWidgetMeta( + hint = resources.getString(R.string.enter_city), + maxCharLength = 30, + savedText = savedText.orEmpty() + ) + inputValidationList = listOf(NotEmptyValidation()) + } return LabeledTextInputWidgetModelV2( widgetId = KycAddressWidgetName.CITY.value, LabeledTextInputWidgetModelV2.WIDGET_NAME, @@ -205,16 +222,17 @@ class HomeLoanAddressFragmentVM @Inject constructor(private val repository: Home } fun getStateData(resources: Resources, savedText: String?): LabeledTextInputWidgetModelV2 { - val stateWidgetData = TextInputWidgetData().apply { - title = resources.getString(R.string.state) - inputTextData = - InputTextWidgetMeta( - hint = resources.getString(R.string.enter_state), - maxCharLength = 30, - savedText = savedText.orEmpty() - ) - inputValidationList = listOf(NotEmptyValidation()) - } + val stateWidgetData = + TextInputWidgetData().apply { + title = resources.getString(R.string.state) + inputTextData = + InputTextWidgetMeta( + hint = resources.getString(R.string.enter_state), + maxCharLength = 30, + savedText = savedText.orEmpty() + ) + inputValidationList = listOf(NotEmptyValidation()) + } return LabeledTextInputWidgetModelV2( widgetId = KycAddressWidgetName.STATE.value, LabeledTextInputWidgetModelV2.WIDGET_NAME, diff --git a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/viewmodel/HomeLoanPostEligibilityV2ActivityVM.kt b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/viewmodel/HomeLoanPostEligibilityV2ActivityVM.kt index 97d6801957..1fcfce0243 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/posteligibility/viewmodel/HomeLoanPostEligibilityV2ActivityVM.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/posteligibility/viewmodel/HomeLoanPostEligibilityV2ActivityVM.kt @@ -1,33 +1,40 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.homeloandigital.posteligibility.viewmodel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.navi.common.firebasedb.AADHAR_VERIFICATION import com.navi.base.model.CtaData -import com.navi.common.model.GenericErrorResponse +import com.navi.common.firebasedb.AADHAR_VERIFICATION +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.utils.orTrue import com.navi.common.viewmodel.BaseVM import com.naviapp.homeloandigital.models.HLAdhaarResponse import com.naviapp.homeloandigital.posteligibility.repository.HomeLoanPostEligibilityV2Repository import com.naviapp.models.RedirectPageStatus import com.naviapp.models.response.SuccessResponse -import com.navi.common.model.UploadDataAsyncResponse -import com.navi.common.utils.orTrue import com.naviapp.network.ApiConstants import com.naviapp.network.ApiErrorTagType import com.naviapp.personalloan.getloan.kyc.models.AadhaarVerificationData import com.naviapp.personalloan.getloan.kyc.repositories.KycRepository import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch import javax.inject.Inject - +import kotlinx.coroutines.launch @HiltViewModel -class HomeLoanPostEligibilityV2ActivityVM @Inject constructor( +class HomeLoanPostEligibilityV2ActivityVM +@Inject +constructor( private val repository: HomeLoanPostEligibilityV2Repository, private val kycRespository: KycRepository, -) : - BaseVM() { +) : BaseVM() { private val _aadharResponse = MutableLiveData() val aadharResponse: LiveData @@ -104,7 +111,11 @@ class HomeLoanPostEligibilityV2ActivityVM @Inject constructor( } } else { _asyncError.value = true - if (type == AADHAR_VERIFICATION && response.errors?.getOrNull(0)?.code == ApiConstants.MAX_ACTION_RETRY_LIMIT_REACHED) { + if ( + type == AADHAR_VERIFICATION && + response.errors?.getOrNull(0)?.code == + ApiConstants.MAX_ACTION_RETRY_LIMIT_REACHED + ) { showSkipBottomSheet(true) } else { _retryVerificationStepResponse.value = true @@ -138,4 +149,4 @@ class HomeLoanPostEligibilityV2ActivityVM @Inject constructor( } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/homeloandigital/tracker/repo/HomeLoanTrackerRepository.kt b/app/src/main/java/com/naviapp/homeloandigital/tracker/repo/HomeLoanTrackerRepository.kt index da2da5a7ee..ef47cfd3ed 100644 --- a/app/src/main/java/com/naviapp/homeloandigital/tracker/repo/HomeLoanTrackerRepository.kt +++ b/app/src/main/java/com/naviapp/homeloandigital/tracker/repo/HomeLoanTrackerRepository.kt @@ -1,6 +1,13 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.homeloandigital.tracker.repo -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult import com.naviapp.homeloandigital.models.AcceptOrRejectUpdatedOfferRequest import com.naviapp.homeloandigital.models.CoApplicantActivationRequest import com.naviapp.homeloandigital.models.CoApplicantVerificationRequest @@ -13,18 +20,18 @@ import javax.inject.Inject class HomeLoanTrackerRepository @Inject constructor(private val retrofitService: RetrofitService) : ResponseCallback() { - suspend fun fetchHomeLoanStatus(queryMap: HashMap): RepoResult = + suspend fun fetchHomeLoanStatus( + queryMap: HashMap + ): RepoResult = apiResponseCallback(retrofitService.fetchHomeLoanTrackerStatus(queryMap)) suspend fun postCoApplicantVerification( coApplicantRequest: CoApplicantVerificationRequest, queryMap: HashMap - ) = apiResponseCallback( - retrofitService.postCoApplicantVerification( - coApplicantRequest, - queryMap + ) = + apiResponseCallback( + retrofitService.postCoApplicantVerification(coApplicantRequest, queryMap) ) - ) suspend fun deleteOrAddCoApplicant( coApplicantRequest: CoApplicantActivationRequest, @@ -34,13 +41,14 @@ class HomeLoanTrackerRepository @Inject constructor(private val retrofitService: suspend fun acceptOrRejectUpdatedOffer( loanApplicationId: String, acceptOrRejectUpdatedOfferRequest: AcceptOrRejectUpdatedOfferRequest - ) = apiResponseCallback( - retrofitService.acceptOrRejectUpdatedOffer( - loanApplicationId, - acceptOrRejectUpdatedOfferRequest + ) = + apiResponseCallback( + retrofitService.acceptOrRejectUpdatedOffer( + loanApplicationId, + acceptOrRejectUpdatedOfferRequest + ) ) - ) suspend fun submitHomeLoanSelectTypeDetails(loanActionType: LoanActionType) = apiResponseCallback(retrofitService.submitHomeLoanSelectTypeDetails(loanActionType)) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/interest_reset/InterestResetActivity.kt b/app/src/main/java/com/naviapp/interest_reset/InterestResetActivity.kt new file mode 100644 index 0000000000..3b736d1a96 --- /dev/null +++ b/app/src/main/java/com/naviapp/interest_reset/InterestResetActivity.kt @@ -0,0 +1,95 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.interest_reset + +import android.os.Bundle +import androidx.databinding.DataBindingUtil +import com.navi.base.model.CtaData +import com.navi.common.listeners.FragmentInterchangeListener +import com.navi.common.model.ModuleNameV2 +import com.navi.common.ui.activity.BaseActivity +import com.navi.common.utils.orElse +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.databinding.ActivityInterestResetBinding +import com.naviapp.models.SubPageStatusType +import com.naviapp.part_prepayment.FragmentMapper +import com.naviapp.utils.Constants +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +class InterestResetActivity : BaseActivity(), FragmentInterchangeListener { + + private lateinit var binding: ActivityInterestResetBinding + + @Inject lateinit var fragmentMapper: FragmentMapper + + override fun onCreate(savedInstanceState: Bundle?) { + binding = DataBindingUtil.setContentView(this, R.layout.activity_interest_reset) + super.onCreate(savedInstanceState) + navigateToNextScreen( + intent + ?.extras + ?.getString(Constants.REDIRECT_STATUS) + .orElse(SubPageStatusType.INTEREST_RESET), + intent?.extras ?: Bundle() + ) + } + + override val screenName: String + get() = NaviAnalytics.CUSTOM_PAYMENT_SCREEN + + override val moduleName: ModuleNameV2 + get() = ModuleNameV2.COMMON + + override fun navigateToNextScreen(currentScreenTag: String, bundle: Bundle) { + val tag = fragmentMapper.getFragmentTagByUrl(currentScreenTag) + val fragment = + supportFragmentManager.findFragmentByTag(tag) + ?: fragmentMapper.getFragmentByUrl(currentScreenTag) + fragment?.apply { arguments = bundle } + if (fragment != null) { + val fragmentTransaction = supportFragmentManager.beginTransaction() + if (!supportFragmentManager.isStateSaved && !supportFragmentManager.isDestroyed) { + fragmentTransaction.addToBackStack(tag) + fragmentTransaction.replace(R.id.fragment_container, fragment, tag) + fragmentTransaction.commit() + } + } else { + NaviDeepLinkNavigator.navigate(this, CtaData(url = currentScreenTag), true) + } + } + + override fun onActivityCompleted() {} + + override fun onBackPressed() { + supportFragmentManager.fragments + .takeIf { it.size > 0 } + ?.let { fragments -> + for (i in (fragments.size - 1) downTo 0) { + val fragment = fragments[i] + val childFragmentManager = fragment.childFragmentManager + if (fragment.isVisible) { + if (childFragmentManager.backStackEntryCount > 0) { + supportFragmentManager.popBackStackImmediate() + return + } + break + } + } + if (supportFragmentManager.backStackEntryCount > 1) { + supportFragmentManager.popBackStackImmediate() + } else { + finish() + } + } + ?: run { finish() } + } +} diff --git a/app/src/main/java/com/naviapp/interest_reset/InterestResetRepository.kt b/app/src/main/java/com/naviapp/interest_reset/InterestResetRepository.kt new file mode 100644 index 0000000000..e0145ec7fa --- /dev/null +++ b/app/src/main/java/com/naviapp/interest_reset/InterestResetRepository.kt @@ -0,0 +1,21 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.interest_reset + +import com.naviapp.network.retrofit.ResponseCallback +import com.naviapp.utils.retrofitService +import javax.inject.Inject + +class InterestResetRepository @Inject constructor() : ResponseCallback() { + + suspend fun setInterestRatePreference(accountNumber: String?, type: String?) = + apiResponseCallback(retrofitService().setInterestRatePreference(accountNumber, type)) + + suspend fun fetchInterestResetWidgets(loanAccountNumber: String?, flow: String?) = + apiResponseCallback(retrofitService().fetchInterestResetWidgets(loanAccountNumber, flow)) +} diff --git a/app/src/main/java/com/naviapp/interest_reset/fragments/InterestResetFragment.kt b/app/src/main/java/com/naviapp/interest_reset/fragments/InterestResetFragment.kt new file mode 100644 index 0000000000..563e864146 --- /dev/null +++ b/app/src/main/java/com/naviapp/interest_reset/fragments/InterestResetFragment.kt @@ -0,0 +1,268 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.interest_reset.fragments + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.base.model.* +import com.navi.common.listeners.FragmentInterchangeListener +import com.navi.common.ui.fragment.BaseFragment +import com.navi.common.utils.CommonNaviAnalytics +import com.navi.common.utils.replaceLayout +import com.navi.naviwidgets.adapters.NaviInputWidgetAdapter +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.models.NaviWidget +import com.navi.naviwidgets.models.response.BottomSheetInfoV2 +import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl +import com.navi.naviwidgets.widgets.BaseNaviWidgetLayout +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.common.fragment.InfoBottomSheetV3 +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.databinding.FragmentInterestResetBinding +import com.naviapp.home.dashboard.ui.DashboardFragment +import com.naviapp.interest_reset.view_models.InterestResetVM +import com.naviapp.part_prepayment.PartPrePaymentActivity +import com.naviapp.part_prepayment.WidgetIdProvider +import com.naviapp.part_prepayment.states.GenericWidgetState +import com.naviapp.personalloan.getloan.common.fragment.CustomerSupportFragment +import com.naviapp.utils.Constants +import com.naviapp.utils.Constants.REDIRECT_STATUS +import com.naviapp.utils.LOAN_ACCOUNT_NUMBER +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class InterestResetFragment : BaseFragment(), WidgetCallback { + + private val interestResetVM by lazy { ViewModelProvider(this)[InterestResetVM::class.java] } + + @Inject lateinit var widgetIdProvider: WidgetIdProvider + private lateinit var binding: FragmentInterestResetBinding + private var footerBinding: ViewDataBinding? = null + private var repoRateBottomSheet: BottomSheetInfoV2? = null + private val naviAdapter = + NaviInputWidgetAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = + DataBindingUtil.inflate(inflater, R.layout.fragment_interest_reset, container, false) + return binding.root + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + interestResetVM.fetchData(arguments) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initError(interestResetVM) + init() + } + + override fun onAttach(context: Context) { + super.onAttach(context) + fragmentInterchangeListener = context as? FragmentInterchangeListener + } + + private fun init() { + viewLifecycleOwner.lifecycleScope.launchWhenStarted { + launch { + interestResetVM.widgetDataResponse.collect { + hideLoader() + setWidgetState(it) + } + } + launch { + interestResetVM.setInterestPreference.collect { + hideLoader() + setInterestPreferenceState(it) + } + } + } + } + + private fun setInterestPreferenceState(viewState: GenericWidgetState) { + when (viewState) { + is GenericWidgetState.Init -> {} + is GenericWidgetState.Update -> { + NaviDeepLinkNavigator.navigate( + activity, + ctaData = + CtaData( + url = HOME_DASHBOARD_URL, + parameters = + listOf( + LineItem(key = REDIRECT_STATUS, value = DashboardFragment.TAG) + ) + ), + finish = true + ) + } + } + } + + private fun setWidgetState(viewState: GenericWidgetState) { + when (viewState) { + is GenericWidgetState.Init -> { + showLoader() + } + is GenericWidgetState.Failure -> { + hideLoader() + } + is GenericWidgetState.Update -> { + hideLoader() + viewState.data?.run { + this.header?.getOrNull(0)?.let { naviWidget -> + updateContainer( + naviWidget, + binding.headerContainer.replaceLayout( + widgetIdProvider.getNaviWidgetLayoutId(naviWidget) + ) + ) + } + this.content?.let { contentWidget -> + binding.recyclerView.apply { + val linearLayoutManager = + LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + layoutManager = linearLayoutManager + naviAdapter.list = contentWidget + adapter = naviAdapter + } + } + this.footer?.getOrNull(0)?.let { naviWidget -> + footerBinding = + updateContainer( + naviWidget, + binding.footerContainer.replaceLayout( + widgetIdProvider.getNaviWidgetLayoutId(naviWidget) + ) + ) + } + + val analyticsEvent = + this.metadata?.get(PartPrePaymentActivity.METADATA_ANALYTICS_EVENT)?.data + as? AnalyticsEvent + NaviAnalytics.naviAnalytics.sendAnalyticsEvent(analyticsEvent, screenName) + + repoRateBottomSheet = + this.metadata + ?.get(Constants.MetaDataKey.METADATA_REPO_RATE_BOTTOM_SHEET.value) + ?.data as? BottomSheetInfoV2 + } + } + } + } + + private fun updateContainer( + naviWidget: NaviWidget, + layoutBinding: ViewDataBinding? + ): ViewDataBinding? { + viewLifecycleOwner.lifecycleScope.launch { + (layoutBinding?.root as? BaseNaviWidgetLayout)?.updateLayout( + layoutBinding, + naviWidget, + this@InterestResetFragment + ) + } + return layoutBinding + } + + override fun onClick(naviClickAction: NaviClickAction) { + if (naviClickAction is CtaData) { + when (naviClickAction.url) { + CtaType.NEXT_PAGE_API.name -> { + if (naviAdapter.isValidWidget()) { + val type = naviAdapter.getWidgetData().getOrNull(0) + val loanAccountNumber = arguments?.getString(LOAN_ACCOUNT_NUMBER) + val entry = + naviClickAction.analyticsEventProperties + ?.properties + ?.filter { it.key == CommonNaviAnalytics.OVERRIDE_EVENT } + ?.entries + ?.firstOrNull() + if (entry?.value == CommonNaviAnalytics.TEXT_TRUE) { + NaviAnalytics.naviAnalytics.sendAnalyticsEvent( + analyticsEvent = naviClickAction.analyticsEventProperties, + props = + mutableMapOf( + Pair(NaviAnalytics.SELECTED_OPTION, type.toString()) + ) + ) + } + + showLoader() + interestResetVM.setInterestRatePreference( + loanAccountNumber, + type.toString() + ) + } + } + CtaType.INFO_BOTTOM_SHEET_V3.name -> { + repoRateBottomSheet?.run { + if (!isBottomSheetVisible(InfoBottomSheetV3.TAG)) { + val bottomSheet = InfoBottomSheetV3.getInstance(this) + safelyShowBottomSheet(bottomSheet, InfoBottomSheetV3.TAG) + } + } + } + CtaType.HELP_BOTTOM_SHEET.name -> { + openHelpInfo() + } + CtaType.GO_BACK.name -> { + activity?.onBackPressed() + } + else -> { + val bundle = Bundle() + naviClickAction.parameters?.forEach { bundle.putString(it.key, it.value) } + naviClickAction.url?.let { + fragmentInterchangeListener?.navigateToNextScreen(it, bundle) + } + } + } + } + } + + private fun openHelpInfo() { + val bottomSheet = CustomerSupportFragment.newInstance(screenName, null) + safelyShowBottomSheet(bottomSheet, CustomerSupportFragment.TAG) + } + + override fun widgetAnalytics(genericAnalyticsData: GenericAnalyticsData?) { + NaviAnalytics.naviAnalytics.sendGenericAnalyticsData(genericAnalyticsData) + } + + override fun widgetAnalytics(analyticsEvent: AnalyticsEvent?) { + NaviAnalytics.naviAnalytics.sendAnalyticsEvent(analyticsEvent) + } + + override val screenName: String + get() = NaviAnalytics.INTEREST_RESET_SCREEN + + companion object { + const val TAG = "INTEREST_RESET_SCREEN" + const val HOME_DASHBOARD_URL = "HOME/DASHBOARD" + } +} diff --git a/app/src/main/java/com/naviapp/interest_reset/view_models/InterestResetVM.kt b/app/src/main/java/com/naviapp/interest_reset/view_models/InterestResetVM.kt new file mode 100644 index 0000000000..e605d10b58 --- /dev/null +++ b/app/src/main/java/com/naviapp/interest_reset/view_models/InterestResetVM.kt @@ -0,0 +1,67 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.interest_reset.view_models + +import android.os.Bundle +import com.navi.common.viewmodel.BaseVM +import com.naviapp.interest_reset.InterestResetRepository +import com.naviapp.part_prepayment.states.GenericWidgetState +import com.naviapp.utils.Constants.PREFERENCE +import com.naviapp.utils.LOAN_ACCOUNT_NUMBER +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch + +@HiltViewModel +class InterestResetVM +@Inject +constructor(private val interestResetRepository: InterestResetRepository) : BaseVM() { + + private var loanAccountNumber: String? = null + + private val _widgetDataResponse = MutableStateFlow(GenericWidgetState.Init) + val widgetDataResponse = _widgetDataResponse.asStateFlow() + + private val _setInterestPreference = + MutableStateFlow(GenericWidgetState.Init) + val setInterestPreference = _setInterestPreference.asStateFlow() + + fun fetchData(arguments: Bundle?) { + loanAccountNumber = arguments?.getString(LOAN_ACCOUNT_NUMBER) + val flow = arguments?.getString(PREFERENCE) + coroutineScope.launch { + _widgetDataResponse.emit(GenericWidgetState.Loading) + val response = + interestResetRepository.fetchInterestResetWidgets(loanAccountNumber, flow) + if ( + response.error == null && response.errors.isNullOrEmpty() && response.data != null + ) { + _widgetDataResponse.emit(GenericWidgetState.Update(response.data)) + } else { + _widgetDataResponse.emit(GenericWidgetState.Failure) + setErrorData(response.errors, response.error) + } + } + } + + fun setInterestRatePreference(loanAccountNumber: String?, type: String?) { + coroutineScope.launch { + val response = + interestResetRepository.setInterestRatePreference(loanAccountNumber, type) + if ( + response.error == null && response.errors.isNullOrEmpty() && response.data != null + ) { + _setInterestPreference.emit(GenericWidgetState.Update(response.data)) + } else { + setErrorData(response.errors, response.error) + } + } + } +} diff --git a/app/src/main/java/com/naviapp/models/DashboardPolicyBenefitData.kt b/app/src/main/java/com/naviapp/models/DashboardPolicyBenefitData.kt index 7ddd979134..a7b0a2cd9a 100644 --- a/app/src/main/java/com/naviapp/models/DashboardPolicyBenefitData.kt +++ b/app/src/main/java/com/naviapp/models/DashboardPolicyBenefitData.kt @@ -1,5 +1,4 @@ /* - * * * * Copyright © 2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential @@ -57,5 +56,4 @@ enum class PolicyBenefitStatus { IN_PROGRESS, GRACE_PERIOD, NOT_APPLICABLE -} - +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/models/EMIUpdatedCalendarResponse.kt b/app/src/main/java/com/naviapp/models/EMIUpdatedCalendarResponse.kt index 00946ca856..8106b67244 100644 --- a/app/src/main/java/com/naviapp/models/EMIUpdatedCalendarResponse.kt +++ b/app/src/main/java/com/naviapp/models/EMIUpdatedCalendarResponse.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022 by Navi Technologies Private Limited + * * Copyright © 2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -8,57 +8,42 @@ package com.naviapp.models import com.google.gson.annotations.SerializedName +import com.navi.common.model.StyledTextWithIconCode +import com.navi.naviwidgets.models.ParameterValue import com.naviapp.homeloandigital.models.FormFooter import com.naviapp.homeloandigital.models.FormHeader -import com.navi.common.model.StyledTextWithIconCode data class EMIUpdatedCalendarResponse( - @SerializedName("header") - val header: FormHeader? = null, - @SerializedName("content") - val content: EMIUpdatedCalendarContent? = null, - @SerializedName("footer") - val footer: FormFooter? = null + @SerializedName("header") val header: FormHeader? = null, + @SerializedName("content") val content: EMIUpdatedCalendarContent? = null, + @SerializedName("footer") val footer: FormFooter? = null, + @SerializedName("metadata") var metadata: MutableMap? ) data class EMIUpdatedCalendarContent( - @SerializedName("header") - val header: String? = null, - @SerializedName("description") - val description: StyledTextWithIconCode? = null, - @SerializedName("updatedCalendar") - val updatedCalendar: ArrayList? = null, + @SerializedName("header") val header: String? = null, + @SerializedName("description") val description: StyledTextWithIconCode? = null, + @SerializedName("updatedCalendar") val updatedCalendar: ArrayList? = null, @SerializedName("calendarVisibilityConfig") val calendarVisibilityConfig: CalendarVisibilityConfig? = null, - @SerializedName("note") - val note: StyledTextWithIconCode? = null + @SerializedName("note") val note: StyledTextWithIconCode? = null ) data class EMIDateContent( - @SerializedName("serialNumber") - val serialNumber: String? = null, - @SerializedName("dueDate") - val dueDate: String? = null, - @SerializedName("emi") - val emi: String? = null, - @SerializedName("emiSplitUp") - val emiSplitUp: ArrayList? = null, - @SerializedName("viewType") - val viewType: Int? = null + @SerializedName("serialNumber") val serialNumber: String? = null, + @SerializedName("dueDate") val dueDate: String? = null, + @SerializedName("emi") val emi: String? = null, + @SerializedName("emiSplitUp") val emiSplitUp: ArrayList? = null, + @SerializedName("viewType") val viewType: Int? = null ) data class EMISplitUp( - @SerializedName("header") - val header: StyledTextWithIconCode? = null, - @SerializedName("amount") - val amount: StyledTextWithIconCode? = null + @SerializedName("header") val header: StyledTextWithIconCode? = null, + @SerializedName("amount") val amount: StyledTextWithIconCode? = null ) data class CalendarVisibilityConfig( - @SerializedName("count") - val count: Int? = null, - @SerializedName("openHeader") - val openHeader: StyledTextWithIconCode? = null, - @SerializedName("closeHeader") - val closeHeader: StyledTextWithIconCode? = null -) \ No newline at end of file + @SerializedName("count") val count: Int? = null, + @SerializedName("openHeader") val openHeader: StyledTextWithIconCode? = null, + @SerializedName("closeHeader") val closeHeader: StyledTextWithIconCode? = null +) diff --git a/app/src/main/java/com/naviapp/models/PaymentCheckResponse.kt b/app/src/main/java/com/naviapp/models/PaymentCheckResponse.kt new file mode 100644 index 0000000000..175faf5e1b --- /dev/null +++ b/app/src/main/java/com/naviapp/models/PaymentCheckResponse.kt @@ -0,0 +1,16 @@ +package com.naviapp.models + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import com.navi.base.model.ActionData +import com.navi.naviwidgets.models.NaviTextComponent +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class PaymentCheckResponse( + @SerializedName("title") val title: NaviTextComponent? = null, + @SerializedName("description") val description: NaviTextComponent? = null, + @SerializedName("iconCode") val iconCode: String? = null, + @SerializedName("actionData") val actionData: ActionData? = null, + @SerializedName("screenName") val screenName: String? = null +) : Parcelable diff --git a/app/src/main/java/com/naviapp/models/PgRepaymentData.kt b/app/src/main/java/com/naviapp/models/PgRepaymentData.kt index b85e834663..77606ff1e4 100644 --- a/app/src/main/java/com/naviapp/models/PgRepaymentData.kt +++ b/app/src/main/java/com/naviapp/models/PgRepaymentData.kt @@ -14,5 +14,6 @@ data class PgRepaymentData( @SerializedName("orderId") val orderId: String? = null, @SerializedName("description") val description: String? = null, @SerializedName("status") val status: String? = null, - @SerializedName("type") val type: String? = null // PaymentType enum + @SerializedName("type") val type: String? = null, // PaymentType enum + @SerializedName("requestId") val requestId: String? = null ) \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/models/SubPageStatusType.kt b/app/src/main/java/com/naviapp/models/SubPageStatusType.kt index ef07099eeb..e92daedc85 100644 --- a/app/src/main/java/com/naviapp/models/SubPageStatusType.kt +++ b/app/src/main/java/com/naviapp/models/SubPageStatusType.kt @@ -60,6 +60,7 @@ object SubPageStatusType { const val DOCUMENT_LIST = "document_list" const val FORECLOSE_LOAN = "foreclose_loan" const val SUCCESS_FRAGMENT = "success_fragment" + const val INTEREST_RESET = "interest_reset_screen" @StringDef( BASIC_DETAILS, @@ -99,7 +100,8 @@ object SubPageStatusType { CUSTOM_PAYMENT_CALENDAR_REVIEW, DOCUMENT_LIST, FORECLOSE_LOAN, - SUCCESS_FRAGMENT + SUCCESS_FRAGMENT, + INTEREST_RESET ) @Retention(AnnotationRetention.SOURCE) annotation class SubPageStatusTypeDef diff --git a/app/src/main/java/com/naviapp/models/request/AmountDataRequest.kt b/app/src/main/java/com/naviapp/models/request/AmountDataRequest.kt new file mode 100644 index 0000000000..7b07a8b866 --- /dev/null +++ b/app/src/main/java/com/naviapp/models/request/AmountDataRequest.kt @@ -0,0 +1,15 @@ +/* + * + * * Copyright © 2019 by Navi Technologies Private Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.models.request + +import com.google.gson.annotations.SerializedName + +data class AmountDataRequest( + @SerializedName("amount") + val amount: Double? = null +) diff --git a/app/src/main/java/com/naviapp/models/request/ForecloseLoanRequest.kt b/app/src/main/java/com/naviapp/models/request/ForecloseLoanRequest.kt new file mode 100644 index 0000000000..9941f92fae --- /dev/null +++ b/app/src/main/java/com/naviapp/models/request/ForecloseLoanRequest.kt @@ -0,0 +1,14 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.models.request + +import com.google.gson.annotations.SerializedName + +data class ForecloseLoanRequest( + @SerializedName("closureType") val closureType: String? = null, +) diff --git a/app/src/main/java/com/naviapp/models/request/ForeclosureSuccessPageRequest.kt b/app/src/main/java/com/naviapp/models/request/ForeclosureSuccessPageRequest.kt index 11e1dcdd26..24b16ce24f 100644 --- a/app/src/main/java/com/naviapp/models/request/ForeclosureSuccessPageRequest.kt +++ b/app/src/main/java/com/naviapp/models/request/ForeclosureSuccessPageRequest.kt @@ -9,14 +9,13 @@ package com.naviapp.models.request import android.os.Parcelable import com.google.gson.annotations.SerializedName -import java.time.LocalDate import kotlinx.android.parcel.Parcelize @Parcelize data class ForeclosureSuccessPageRequest( @SerializedName("foreclosedAmount") val foreclosedAmount: Double?, @SerializedName("refundAmount") val refundAmount: Double?, - @SerializedName("refundDate") val refundDate: LocalDate?, - @SerializedName("disbursementBankReferenceId") val disbursementBankReferenceId: String?, + @SerializedName("refundDate") val refundDate: String?, + @SerializedName("bankAccountNumber") val bankAccountNumber: String?, @SerializedName("isNegativeForeclosure") val isNegativeForeclosure: Boolean? ) : Parcelable diff --git a/app/src/main/java/com/naviapp/models/request/OtpRequest.kt b/app/src/main/java/com/naviapp/models/request/OtpRequest.kt index 7dea2b61f3..a0cf80015c 100644 --- a/app/src/main/java/com/naviapp/models/request/OtpRequest.kt +++ b/app/src/main/java/com/naviapp/models/request/OtpRequest.kt @@ -27,7 +27,8 @@ data class OtpRequest( @SerializedName("source") val source: String? = null, @SerializedName("parameters") var parameters: List? = null, @SerializedName("referenceId") var referenceId: String? = null, - @SerializedName("workEmail") var workEmail: String? = null + @SerializedName("workEmail") var workEmail: String? = null, + @SerializedName("installDeeplinkData") var installDeeplinkData: String? = null, ) data class AppVersionData( 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 e9a3548377..7a3f3415c4 100644 --- a/app/src/main/java/com/naviapp/models/response/DisbursementDetailsResponse.kt +++ b/app/src/main/java/com/naviapp/models/response/DisbursementDetailsResponse.kt @@ -58,7 +58,9 @@ data class DisbursementDetails( val bankDetailsAutoDebitConfig: BankDetailsAutoPayData? = null, @SerializedName("dataSafetyBottomSheet") val dataSafetyBottomSheet: InfoBottomSheetConfig? = null, - @SerializedName("autopaySetupSuccessMessage") val autoPaySuccessMessage: String? = null + @SerializedName("autopaySetupSuccessMessage") val autoPaySuccessMessage: String? = null, + @SerializedName("delayedDisbursementBankCodes") val delayedDisbursementBankCodes: List? = null, + @SerializedName("delayedDisbursementDisclaimerHeader") val delayedDisbursmentDisclaimerHeader: StyledTextWithIconCode? = null ) : Parcelable @Parcelize diff --git a/app/src/main/java/com/naviapp/models/response/EPFODetails.kt b/app/src/main/java/com/naviapp/models/response/EPFODetails.kt index 4698284363..60da81484e 100644 --- a/app/src/main/java/com/naviapp/models/response/EPFODetails.kt +++ b/app/src/main/java/com/naviapp/models/response/EPFODetails.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -8,7 +8,7 @@ package com.naviapp.models.response import com.google.gson.annotations.SerializedName -import com.navi.common.model.GenericWarningResponse +import com.navi.common.network.models.GenericWarningResponse data class EPFODetails( @SerializedName("title") val title: String? = null, @@ -22,8 +22,7 @@ data class EPFODetails( @SerializedName("selectorSection") val selectorSection: SelectorSectionData? = null ) - data class SelectorSectionData( @SerializedName("title") val title: String? = null, @SerializedName("placeHolderTitle") val placeHolderTitle: String? = null -) \ No newline at end of file +) diff --git a/app/src/main/java/com/naviapp/models/response/EPFOOtpVerificationStatusResponse.kt b/app/src/main/java/com/naviapp/models/response/EPFOOtpVerificationStatusResponse.kt index 0ca1f65f3d..ec6a928747 100644 --- a/app/src/main/java/com/naviapp/models/response/EPFOOtpVerificationStatusResponse.kt +++ b/app/src/main/java/com/naviapp/models/response/EPFOOtpVerificationStatusResponse.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -8,7 +8,7 @@ package com.naviapp.models.response import com.google.gson.annotations.SerializedName -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse data class EPFOOtpVerificationStatusResponse( @SerializedName("requestId") val requestId: String? = null, @@ -20,4 +20,4 @@ data class EPFOVerificationDetails( @SerializedName("statusCode") var statusCode: Int? = null, @SerializedName("message") var message: String? = null, @SerializedName("errors") val errors: List? = null -) \ No newline at end of file +) diff --git a/app/src/main/java/com/naviapp/models/response/Header.kt b/app/src/main/java/com/naviapp/models/response/Header.kt index f9983c106b..1a4e770169 100644 --- a/app/src/main/java/com/naviapp/models/response/Header.kt +++ b/app/src/main/java/com/naviapp/models/response/Header.kt @@ -22,6 +22,7 @@ data class Header( @SerializedName("infoCta") val infoCta: CtaData? = null, @SerializedName("enableHelp") val enableHelp: Boolean? = null, @SerializedName("leftIconData") val leftIconData: LeftIconData? = null, + @SerializedName("actionData") val actionData: ActionData? = null ) : Parcelable @Parcelize diff --git a/app/src/main/java/com/naviapp/models/response/HomeLoanPanDetailsResponse.kt b/app/src/main/java/com/naviapp/models/response/HomeLoanPanDetailsResponse.kt deleted file mode 100644 index c5297e6226..0000000000 --- a/app/src/main/java/com/naviapp/models/response/HomeLoanPanDetailsResponse.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * * Copyright © 2019 by Navi Technologies Private Limited - * * All rights reserved. Strictly confidential - * - */ - -package com.naviapp.models.response - -import com.google.gson.annotations.SerializedName -import com.navi.base.model.CtaData - -data class HomeLoanPanDetailsResponse( - @SerializedName("title") val title: String? = null, - @SerializedName("subtitle") val subtitle: String? = null, - @SerializedName("progress") val progress: Int? = null, - @SerializedName("backCta") val backCta: CtaData? = null, - @SerializedName("nextCta") val nextCta: CtaData? = null, - @SerializedName("coApplicantLabelList") val coApplicantLabelList: List?, - @SerializedName("details") val panDetails: HomeLoanPanDetails?, - @SerializedName("loanApplicationDetails") val loanApplicationDetails: LoanApplicationDetails? -) - -data class HomeLoanPanDetails( - @SerializedName("pan") val userPan: String? = null, - @SerializedName("coApplicantPanList") val coApplicantPanList: List? = null -) - -data class CoApplicantLabelDetails( - @SerializedName("label") val label: String? = null, - @SerializedName("referenceId") val referenceId: String? = null -) - -data class LoanApplicationDetails( - @SerializedName("homeLoanActionType") val actionType: String? = null, - @SerializedName("loanApplicationType") val loanApplicationType: String? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/models/response/HomeLoanProfileResponse.kt b/app/src/main/java/com/naviapp/models/response/HomeLoanProfileResponse.kt index 06085159af..eaaa605206 100644 --- a/app/src/main/java/com/naviapp/models/response/HomeLoanProfileResponse.kt +++ b/app/src/main/java/com/naviapp/models/response/HomeLoanProfileResponse.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -8,33 +8,6 @@ package com.naviapp.models.response import com.google.gson.annotations.SerializedName -import com.navi.base.model.CtaData - -data class HomeLoanProfileResponse( - @SerializedName("title") val title: String? = null, - @SerializedName("subtitle") val subtitle: String? = null, - @SerializedName("progress") val progress: Int? = null, - @SerializedName("backCta") val backCta: CtaData? = null, - @SerializedName("nextCta") val nextCta: CtaData? = null, - @SerializedName("relationList") val relationList: List? = null, - @SerializedName("profileDetails") val profileDetails: HomeLoanProfileDetails? = null, - @SerializedName("loanApplicationDetails") val loanApplicationDetails: HomeLoanApplicationDetail? = null, - @SerializedName("minAge") val minAge: Int? = null, - @SerializedName("maxAge") val maxAge: Int? = null -) - -data class HomeLoanApplicationDetail( - @SerializedName("referenceId") val referenceId: String? = null, - @SerializedName("homeLoanActionType") val actionType: String? = null, - @SerializedName("loanApplicationType") val loanApplicationType: String? = null -) - -data class HomeLoanProfileDetails( - @SerializedName("name") val name: String? = null, - @SerializedName("dateOfBirth") val dateOfBirth: String? = null, - @SerializedName("maritalStatus") val maritalStatus: String? = null, - @SerializedName("customerRelations") val coapplicantDetails: List? = null -) data class CoApplicantProfileDetail( @SerializedName("referenceId") val referenceId: String? = null, @@ -43,16 +16,3 @@ data class CoApplicantProfileDetail( @SerializedName("maritalStatus") val maritalStatus: String? = null, @SerializedName("relationship") val coapplicantRelation: String? = null ) - -enum class MaritalStatus { - MARRIED, - SINGLE, - OTHER -} - -enum class Relation(val value: String) { - SPOUSE("Spouse"), - SON_DAUGHTER("Son-Daughter"), - FATHER("Father"), - MOTHER("Mother") -} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/models/response/HomeLoanSanctionResponse.kt b/app/src/main/java/com/naviapp/models/response/HomeLoanSanctionResponse.kt deleted file mode 100644 index 80cdfce2b2..0000000000 --- a/app/src/main/java/com/naviapp/models/response/HomeLoanSanctionResponse.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * * - * * Copyright (c) 2020 . All rights reserved @Navi - * - */ - -package com.naviapp.models.response - -import com.google.gson.annotations.SerializedName -import com.navi.base.model.CtaData -import com.navi.base.model.LineItem - -data class HomeLoanSanctionResponse( - @SerializedName("title") val title: String? = null, - @SerializedName("subtitle") val subtitle: String? = null, - @SerializedName("progress") val progress: Int? = null, - @SerializedName("backCta") val backCta: CtaData? = null, - @SerializedName("nextCta") val nextCta: CtaData? = null, - - @SerializedName("bannerTitle") val bannerTitle: String? = null, - @SerializedName("heading") val heading: String? = null, - @SerializedName("loanDetails") val loanDetails: List? = null, - @SerializedName("loanSanctionLetter") val loanLetterDetail: HomeLoanLetterDetail? = null, - @SerializedName("subItems") val subItems: List? = null, - @SerializedName("subItemHeading") val subItemHeading: String? = null, - @SerializedName("mobileInfo") val mobileInfo: MobileInfo? = null, - @SerializedName("offerAccepted") val offerAccepted: Boolean? = null, - @SerializedName("offerAcceptedInfo") val offerAcceptedInfo: OfferAcceptedInfo? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/models/response/HomeLoanStepsResponse.kt b/app/src/main/java/com/naviapp/models/response/HomeLoanStepsResponse.kt deleted file mode 100644 index f579afe113..0000000000 --- a/app/src/main/java/com/naviapp/models/response/HomeLoanStepsResponse.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * - * * Copyright © 2019 by Navi Technologies Private Limited - * * All rights reserved. Strictly confidential - * - */ - -package com.naviapp.models.response - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import com.navi.base.model.CtaData -import kotlinx.android.parcel.Parcelize - -data class HomeLoanStepsResponse( - @SerializedName("title") val title: String? = null, - @SerializedName("subItems") val steps: List? = null, - @SerializedName("warning") val warningData: HomeLoanStepsWarningData? = null, - @SerializedName("nextCta") val nextCta: CtaData? = null -) - -@Parcelize -data class HomeLoanStepsWarningData( - @SerializedName("title") val title: String? = null, - @SerializedName("message") val message: String? = null, - @SerializedName("icon") val icon: String? = null, - @SerializedName("actions") val actions: List? = null -) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/models/response/HomeLoanTransactionsResponse.kt b/app/src/main/java/com/naviapp/models/response/HomeLoanTransactionsResponse.kt deleted file mode 100644 index 5052c0ca7f..0000000000 --- a/app/src/main/java/com/naviapp/models/response/HomeLoanTransactionsResponse.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * * Copyright © 2019 by Navi Technologies Private Limited - * * All rights reserved. Strictly confidential - * - */ - -package com.naviapp.models.response - -import com.google.gson.annotations.SerializedName -import com.navi.base.model.LineItem - -data class HomeLoanTransactionsResponse( - @SerializedName("transactionType") val transactionType: String? = null, - @SerializedName("otherDetails") val otherDetails: List? = null, - @SerializedName("paymentStatus") val paymentStatus: String? = null, - @SerializedName("paymentStatusLabel") val paymentStatusLabel: String? = null, - @SerializedName("paymentStatusValue") val paymentStatusValue: String? = null, - @SerializedName("amountLabel") val amountLabel: String? = null, - @SerializedName("amountValue") val amountValue: String? = null -) - -enum class HomeLoanTransactionType { - LOAN_TRANSFER, - REFUND -} - -enum class HomeLoanTransactionPaymentStatus { - SUCCESS, - FAILED -} diff --git a/app/src/main/java/com/naviapp/models/response/HomeLoanWorkResponse.kt b/app/src/main/java/com/naviapp/models/response/HomeLoanWorkResponse.kt deleted file mode 100644 index 8b839298d8..0000000000 --- a/app/src/main/java/com/naviapp/models/response/HomeLoanWorkResponse.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * * Copyright © 2019 by Navi Technologies Private Limited - * * All rights reserved. Strictly confidential - * - */ - -package com.naviapp.models.response - -import com.google.gson.annotations.SerializedName -import com.navi.base.model.CtaData -import com.navi.common.model.Money -import com.naviapp.models.request.Address -import com.navi.common.model.GenericWarningResponse - -data class HomeLoanWorkResponse( - @SerializedName("title") val title: String? = null, - @SerializedName("subtitle") val subtitle: String? = null, - @SerializedName("progress") val progress: Int? = null, - @SerializedName("note") val note: String? = null, - @SerializedName("backCta") val backCta: CtaData? = null, - @SerializedName("nextCta") val nextCta: CtaData? = null, - @SerializedName("employmentTypeList") val employmentTypeList: List? = null, - @SerializedName("serviceType") val serviceType: List? = null, - @SerializedName("natureOfEmploymentType") val natureOfEmploymentType: List? = null, - @SerializedName("coapplicants") val coApplicantList: List?, - @SerializedName("workDetails") val workDetails: WorkDetails? = null, - @SerializedName("incomeInfo") val incomeInfo: GenericWarningResponse? = null, - @SerializedName("loanApplicationDetails") val loanApplicationDetails: HomeLoanApplicationDetail? = null, - @SerializedName("workAddress") var workAddress:Address? = null, - @SerializedName("addressMinSize") val addressMinSize:CurrentAddressMinSize? = null -) - -data class CoApplicantWorkDetail( - @SerializedName("label") val label: String?, - @SerializedName("referenceId") val referenceId: String? = null -) - -data class WorkDetails( - @SerializedName("employmentType") val employmentType: SpinnerResponse? = null, - @SerializedName("serviceType") val serviceType: SpinnerCommonResponse? = null, - @SerializedName("natureEmploymentType") val natureEmploymentType: SpinnerCommonResponse? = null, - @SerializedName("monthlyIncome") val monthlyIncome: Money? = null, - @SerializedName("customerRelations") val coapplicantDetails: List? = null, - @SerializedName("workIndustry") val workIndustry: SpinnerCommonResponse? = null -) - -data class CoapplicantData( - @SerializedName("employmentType") val employmentType: SpinnerResponse? = null, - @SerializedName("monthlyIncome") val monthlyIncome: Money? = null, - @SerializedName("serviceType") val serviceType: SpinnerCommonResponse? = null, - @SerializedName("natureEmploymentType") val natureEmploymentType: SpinnerCommonResponse? = null, - @SerializedName("workIndustry") val workIndustry: SpinnerCommonResponse? = null -) - -class SpinnerResponse( - @SerializedName("serviceType") val serviceType: Boolean? = null, - @SerializedName("workIndustry") val workIndustry: Boolean? = null, - id: String, - value: String -) : SpinnerCommonResponse(id = id, value = value) \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/models/response/WorkDetailsContent.kt b/app/src/main/java/com/naviapp/models/response/WorkDetailsContent.kt index 188b8241ca..01ce5220af 100644 --- a/app/src/main/java/com/naviapp/models/response/WorkDetailsContent.kt +++ b/app/src/main/java/com/naviapp/models/response/WorkDetailsContent.kt @@ -8,8 +8,8 @@ package com.naviapp.models.response import com.google.gson.annotations.SerializedName -import com.navi.common.model.GenericWarningResponse import com.navi.common.model.Money +import com.navi.common.network.models.GenericWarningResponse import com.navi.naviwidgets.models.response.ToastWidget import com.naviapp.personalloanrevamp.models.InfoBottomSheetConfig diff --git a/app/src/main/java/com/naviapp/network/retrofit/ResponseCallback.kt b/app/src/main/java/com/naviapp/network/retrofit/ResponseCallback.kt index fc21be5ed3..2507be66a1 100644 --- a/app/src/main/java/com/naviapp/network/retrofit/ResponseCallback.kt +++ b/app/src/main/java/com/naviapp/network/retrofit/ResponseCallback.kt @@ -1,6 +1,7 @@ /* - * * - * * Copyright (c) 2019 . All rights reserved @Navi + * + * * Copyright © 2019-2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential * */ @@ -8,11 +9,11 @@ package com.naviapp.network.retrofit import com.google.gson.Gson import com.google.gson.reflect.TypeToken -import com.navi.common.constants.NO_INTERNET -import com.navi.common.model.GenericResponse -import com.navi.common.model.RepoResult -import com.navi.common.network.models.ErrorMessage import com.navi.base.utils.BaseUtils +import com.navi.common.constants.NO_INTERNET +import com.navi.common.network.models.ErrorMessage +import com.navi.common.network.models.GenericResponse +import com.navi.common.network.models.RepoResult import com.naviapp.R import com.naviapp.app.NaviApplication import com.naviapp.errors.activities.ErrorActivity.Companion.LOAN_OFFER_EXPIRED @@ -29,9 +30,9 @@ import com.naviapp.network.ApiConstants.E_OFFER_EXPIRED import com.naviapp.utils.deleteCacheAndOpenLoginPage import com.naviapp.utils.handleError import com.naviapp.utils.isNetworkAvailable -import retrofit2.Response import java.net.ConnectException import java.net.SocketTimeoutException +import retrofit2.Response abstract class ResponseCallback { @@ -49,71 +50,59 @@ abstract class ResponseCallback { if (it.errors?.firstOrNull()?.code == E_OFFER_EXPIRED) { handleError(it.errors, RedirectPageStatus(rejectReason = LOAN_OFFER_EXPIRED)) } - if (it.statusCode == API_SUCCESS_CODE || it.statusCode == API_SUCCESS_CODE_201 || it.statusCode == API_SUCCESS_CODE_204) { - return RepoResult( - it.data, - null, - it.errors, - it.warning, - it.statusCode - ) + if ( + it.statusCode == API_SUCCESS_CODE || + it.statusCode == API_SUCCESS_CODE_201 || + it.statusCode == API_SUCCESS_CODE_204 + ) { + return RepoResult(it.data, null, it.errors, it.warning, it.statusCode) } else if (it.statusCode == API_ERROR_NO_USER_FOUND) { - //logged out or session expired here + // logged out or session expired here deleteCacheAndOpenLoginPage() } return RepoResult( null, - ErrorMessage( - it.statusCode, - it.message, - it.message - ), + ErrorMessage(it.statusCode, it.message, it.message), it.errors, it.warning, it.statusCode ) - - } ?: run { - - if (response.code() == API_ERROR_NO_USER_FOUND && BaseUtils.isUserLoggedIn()) { - //logged out or session expired here - - deleteCacheAndOpenLoginPage() - return RepoResult() - } else if (response.code() == API_SUCCESS_CODE_204) { - return handleNoResponseBodySuccessResponse(response) - } else { - val gson = Gson() - val type = object : TypeToken>() {}.type - val errorResponse: GenericResponse? = - gson.fromJson(response.errorBody()?.charStream(), type) - if (response.code() == API_ERROR_SYSTEM_UNDER_MAINTENANCE_CODE) { - handleError( - errorResponse?.errors, - RedirectPageStatus(rejectReason = SYSTEM_UNDER_MAINTENANCE) - ) - return RepoResult() - } - return RepoResult( - null, - ErrorMessage(response.code(), response.message(), response.message()), - errorResponse?.errors, - null, - errorResponse?.statusCode - ) - } - } + ?: run { + if (response.code() == API_ERROR_NO_USER_FOUND && BaseUtils.isUserLoggedIn()) { + // logged out or session expired here + + deleteCacheAndOpenLoginPage() + return RepoResult() + } else if (response.code() == API_SUCCESS_CODE_204) { + return handleNoResponseBodySuccessResponse(response) + } else { + val gson = Gson() + val type = object : TypeToken>() {}.type + val errorResponse: GenericResponse? = + gson.fromJson(response.errorBody()?.charStream(), type) + if (response.code() == API_ERROR_SYSTEM_UNDER_MAINTENANCE_CODE) { + handleError( + errorResponse?.errors, + RedirectPageStatus(rejectReason = SYSTEM_UNDER_MAINTENANCE) + ) + return RepoResult() + } + return RepoResult( + null, + ErrorMessage(response.code(), response.message(), response.message()), + errorResponse?.errors, + null, + errorResponse?.statusCode + ) + } + } } - private fun handleNoResponseBodySuccessResponse(response: Response>): RepoResult { - return RepoResult( - null, - null, - null, - null, - response.code() - ) + private fun handleNoResponseBodySuccessResponse( + response: Response> + ): RepoResult { + return RepoResult(null, null, null, null, response.code()) } private fun handleException(e: Exception): RepoResult { 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 2650acee63..7d65088587 100644 --- a/app/src/main/java/com/naviapp/network/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/naviapp/network/retrofit/RetrofitService.kt @@ -10,6 +10,7 @@ package com.naviapp.network.retrofit import com.navi.analytics.model.UserLocation import com.navi.base.model.CtaData import com.navi.common.model.* +import com.navi.common.network.models.GenericResponse import com.navi.common.utils.Constants.HEADER_CONNECTIVITY_TYPE import com.navi.common.utils.Constants.HEADER_DEVICE_DENSITY import com.navi.insurance.models.request.FlagUpdateRequest @@ -21,7 +22,10 @@ import com.naviapp.crosssell.models.CrossSellResponse import com.naviapp.dashboard.loanapplicationdetails.documentlist.models.DocumentData import com.naviapp.dashboard.loanapplicationdetails.emicalendar.models.EmiCalendarResponse import com.naviapp.dashboard.loanapplicationdetails.models.* -import com.naviapp.dashboard.loanapplicationdetails.models.LoanApplicationDetails +import com.naviapp.digitalgold.model.DigitalGoldPollingResponse +import com.naviapp.digitalgold.model.GoldBuyOrderRequest +import com.naviapp.digitalgold.model.GoldSellOrderRequest +import com.naviapp.digitalgold.model.GoldSellOrderResponse import com.naviapp.home.dashboard.models.response.* import com.naviapp.home.model.WidgetResponse import com.naviapp.homeloandigital.common.models.CallAssistanceResponse @@ -40,7 +44,6 @@ import com.naviapp.models.RedirectPageStatus import com.naviapp.models.request.* import com.naviapp.models.response.* import com.naviapp.models.response.Details -import com.naviapp.models.response.WidgetGenericResponse import com.naviapp.part_prepayment.models.PartPrePaymentRequest import com.naviapp.payment.models.* import com.naviapp.personalloan.getloan.bankdetails.models.BankBranch @@ -166,11 +169,11 @@ interface RetrofitService { @GET("/customer-service/customers/me/fetch-current-address-details") suspend fun fetchCurrentAddressDetails(): - Response> + Response> @GET("/customer-service/customers/me/fetch-current-address-details/v2") suspend fun fetchCurrentAddressDetailsV2(): - Response> + Response> @GET("/customer-service/customers/me/fetch-addresses-for-current-reference") suspend fun fetchNoProofAddressList(): Response> @@ -298,7 +301,8 @@ interface RetrofitService { @GET("/customer-service/customers/contact-us") suspend fun fetchCustomerSupportData(): Response> - @GET("/faq") suspend fun fetchFaqs(): Response>> + @GET("/faq") + suspend fun fetchFaqs(): Response>> // Add bank here @POST("/loan-applications/{loanApplicationId}/add-bank-account") @@ -459,7 +463,8 @@ interface RetrofitService { suspend fun fetchProfileDetails(): Response> // Logout - @POST("/auth/v1/logout") suspend fun logout(): Response> + @POST("/auth/v1/logout") + suspend fun logout(): Response> @GET("/login-settings") suspend fun fetchLoginSettings(): Response> @@ -597,9 +602,15 @@ interface RetrofitService { @Body loanFeeDetailsRequest: LoanFeeDetailsRequest ): Response> - @GET("v2/home") suspend fun fetchNewHomeCards(): Response> + @GET("/v2/home") + suspend fun fetchHomeItems( + @QueryMap queryMap: HashMap?, + @Header(HEADER_DEVICE_DENSITY) deviceDensity: String, + @Header(HEADER_CONNECTIVITY_TYPE) connectivityType: String + ): Response> - @GET("/v2/home") suspend fun fetchHomeItems(): Response> + @GET("/v2/home") + suspend fun fetchHomeItems(): Response> @GET("/v1/cards?groupType=STORY") suspend fun fetchStories( @@ -687,7 +698,7 @@ interface RetrofitService { @GET("/customer-service/customers/me/eligibility/work-details") suspend fun fetchEmploymentVerificationData(): - Response> + Response> @GET("/customer-service/customers/me/eligibility/pan-details") suspend fun fetchPanData(): Response> @@ -882,7 +893,7 @@ interface RetrofitService { @GET("/auth-token/v1/refresh") suspend fun refreshFirebaseAuthToken(): - Response> + Response> @POST("/v1/finoramic-upload") suspend fun sendFinoramicData( @@ -961,7 +972,7 @@ interface RetrofitService { @GET("/customer-service/customers/me/fetch-osv-details") suspend fun fetchPhysicalAddressVerificationData(): - Response> + Response> @GET("/customer-service/customers/me/fetch-osv-slot-details") suspend fun fetchOsvData(): Response> @@ -1114,7 +1125,7 @@ interface RetrofitService { @GET("/home-loan/customers/me/journey/v1/home") suspend fun fetchHomeLoanSelectTypeScreenDetails(): - Response> + Response> @GET("/home-loan/customers/me/journey/v1/form?action=CUSTOMIZE_LOAN") suspend fun fetchHomeLoanEmiTenureDetails( @@ -1392,22 +1403,22 @@ interface RetrofitService { suspend fun fetchGstLoginWithCredentialStatus( @Path("requestId") requestId: String ): Response< - GenericResponse>> - > + GenericResponse>> + > @GET("/requests/{requestId}") suspend fun fetchSendOTPForGstVerificationStatus( @Path("requestId") requestId: String ): Response< - GenericResponse>> - > + GenericResponse>> + > @GET("/requests/{requestId}") suspend fun fetchVerifyOTPForGstVerification( @Path("requestId") requestId: String ): Response< - GenericResponse>> - > + GenericResponse>> + > @GET("/customer-service/customers/me/credit-assignment") suspend fun fetchCreditAssignmentDetails(): Response> @@ -1537,7 +1548,7 @@ interface RetrofitService { @GET("/journey-tracker") suspend fun fetchPersonalLoanTrackerResponse(): - Response> + Response> @GET("end-screen-widgets/{screenName}") suspend fun fetchCrossSellDetails( @@ -1690,6 +1701,59 @@ interface RetrofitService { @Path("loan-account-number") loanAccountNumber: String? ): Response> + @GET("/kuber/home/get-home-content") + suspend fun getDigitalGoldHome( + ): Response> + + @GET("/kuber/home/sub-widgets") + suspend fun getDigitalGoldHomePolling( + ): Response> + + @GET("/kuber/order/get-sell-page-content") + suspend fun getDigitalGoldSellPage( + ): Response> + + @POST("/kuber/order/sell") + suspend fun getDigitalGoldSellOrder( + @Body goldSellOrderRequest: GoldSellOrderRequest + ): Response> + + @GET("/kuber/payment/creds") + suspend fun getDigitalGoldSdkCred( + @Query("requestId") requestId: String + ): Response> + + @POST("/kuber/order/buy") + suspend fun getDigitalGoldBuyOrder( + @Body goldBuyOrderRequest: GoldBuyOrderRequest + ): Response> + + @GET("/kuber/order/status/{requestId}") + suspend fun digitalGoldPaymentPolling( + @Path("requestId") requestId: String + ): Response> + + @PATCH("/kuber/sdk-info") + suspend fun digitalGoldSdkStatus( + @Body pgRepaymentData: PgRepaymentData + ): Response> + + @GET("/kuber/order/status/{requestId}/data") + suspend fun digitalGoldPollingUIData( + @Path("requestId") requestId: String + ): Response> + + @GET("/kuber/order/payment-details/get-upi-page-content") + suspend fun fetchDigitalGoldSellUpiScreenData( + @Query("exchangeRateId") exchangeRateId: String, + @Query("amount") amount: Double + ): Response> + + @POST("/kuber/order/buy-summary-page-content") + suspend fun fetchDigitalGoldBuyDetails( + @Body amount: AmountDataRequest + ): Response> + @POST("/loan-accounts/{loan-account-number}/auto-debit-education") suspend fun fetchAutoDebitEducationTrackerWidget( @Path("loan-account-number") loanAccountNumber: String?, @@ -1751,10 +1815,10 @@ interface RetrofitService { @Body customPayRequest: CustomPaymentRequest? ): Response> - @POST("/loan-accounts/{loanAccountNumber}/new-payment/{rescheduleType}/new-emi-calendar") + @POST("/loan-accounts/{loanAccountNumber}/view-emi-calendar") suspend fun fetchCustomPaymentCalendarWidget( @Path("loanAccountNumber") loanAccountNumber: String?, - @Path("rescheduleType") rescheduleType: String?, + @Query("flowType") flowType: String?, @Body customPayRequest: CustomPaymentRequest? ): Response> @@ -1780,4 +1844,25 @@ interface RetrofitService { @Path("applicationId") applicationId: String, @Query("screenId") screenId: String ): Response>> + + @GET("/loan-accounts/{loanAccountNumber}/interest-rate-reset") + suspend fun fetchInterestResetWidgets( + @Path("loanAccountNumber") loanAccountNumber: String?, + @Query("flow") flow: String? + ): Response> + + @GET("/loan-accounts/{loanAccountNumber}/set-interest-rate-preference") + suspend fun setInterestRatePreference( + @Path("loanAccountNumber") loanAccountNumber: String?, + @Query("preference") preference: String? + ): Response> + + @POST("/loan-accounts/{loanAccountNumber}/foreclose-loan") + suspend fun forecloseLoan( + @Path("loanAccountNumber") loanAccountNumber: String?, + @Body forecloseLoanRequest: ForecloseLoanRequest? + ): Response> + + @GET("/kuber/transactions/transaction-history-page-content") + suspend fun fetchDigitalGoldTransactionHistory() : Response> } diff --git a/app/src/main/java/com/naviapp/part_prepayment/FragmentMapper.kt b/app/src/main/java/com/naviapp/part_prepayment/FragmentMapper.kt index b2a2991290..8741e19fe1 100644 --- a/app/src/main/java/com/naviapp/part_prepayment/FragmentMapper.kt +++ b/app/src/main/java/com/naviapp/part_prepayment/FragmentMapper.kt @@ -14,8 +14,10 @@ import com.naviapp.custom_payments.fragments.ForecloseLoanFragment import com.naviapp.custom_payments.fragments.LoanRepaymentOptionsFragment import com.naviapp.custom_payments.fragments.RepaymentTypeFragment import com.naviapp.dashboard.loanapplicationdetails.documentlist.DocumentListFragment +import com.naviapp.interest_reset.fragments.InterestResetFragment import com.naviapp.models.SubPageStatusType.CUSTOM_PAYMENT_CALENDAR_REVIEW import com.naviapp.models.SubPageStatusType.CUSTOM_PAYMENT_TYPE +import com.naviapp.models.SubPageStatusType.INTEREST_RESET import com.naviapp.models.SubPageStatusType.FORECLOSE_LOAN import com.naviapp.models.SubPageStatusType.PART_PRE_PAYMENT_CALENDAR_REVIEW import com.naviapp.models.SubPageStatusType.PART_PRE_PAYMENT_EMI_AMOUNT @@ -44,6 +46,7 @@ class FragmentMapper @Inject constructor() { FORECLOSE_LOAN -> ForecloseLoanFragment() DOCUMENT_LIST -> DocumentListFragment() SUCCESS_FRAGMENT -> SuccessFragment() + INTEREST_RESET -> InterestResetFragment() else -> null } } @@ -60,6 +63,7 @@ class FragmentMapper @Inject constructor() { FORECLOSE_LOAN -> ForecloseLoanFragment.FORECLOSE_LOAN DOCUMENT_LIST -> DocumentListFragment.TAG SUCCESS_FRAGMENT -> SuccessFragment.TAG + INTEREST_RESET -> InterestResetFragment.TAG else -> "" } } diff --git a/app/src/main/java/com/naviapp/part_prepayment/fragments/PartPrePaymentTypeFragment.kt b/app/src/main/java/com/naviapp/part_prepayment/fragments/PartPrePaymentTypeFragment.kt index 6287905b81..0371566ab2 100644 --- a/app/src/main/java/com/naviapp/part_prepayment/fragments/PartPrePaymentTypeFragment.kt +++ b/app/src/main/java/com/naviapp/part_prepayment/fragments/PartPrePaymentTypeFragment.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022 by Navi Technologies Private Limited + * * Copyright © 2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -28,6 +28,8 @@ import com.navi.naviwidgets.viewholder.ViewHolderFactoryImpl import com.navi.naviwidgets.widgets.BaseNaviWidgetLayout import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.analytics.utils.NaviAnalytics.Companion.COLENDING_BALANCE_TRANSFER_EVENT +import com.naviapp.analytics.utils.NaviAnalytics.Companion.ELIGIBLE_FOR_BALANCE_TRANSFER import com.naviapp.databinding.FragmentPartPrePaymentTypeBinding import com.naviapp.part_prepayment.PartPrePaymentActivity import com.naviapp.part_prepayment.states.GenericWidgetState @@ -35,7 +37,9 @@ import com.naviapp.part_prepayment.viewModels.PartPrePaymentTypeVM import com.naviapp.payment.activities.NaviPaymentActivity import com.naviapp.payment.models.Amount import com.naviapp.utils.LOAN_ACCOUNT_NUMBER +import com.naviapp.utils.NaviDownloadManager import dagger.hilt.android.AndroidEntryPoint +import java.lang.ref.WeakReference import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch @@ -43,24 +47,30 @@ import kotlinx.coroutines.launch class PartPrePaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback { private val partPrePaymentTypeVM by lazy { - ViewModelProvider(this).get( - PartPrePaymentTypeVM::class.java - ) + ViewModelProvider(this).get(PartPrePaymentTypeVM::class.java) } private lateinit var binding: FragmentPartPrePaymentTypeBinding private var footerBinding: ViewDataBinding? = null - private val naviAdapter = NaviInputWidgetAdapter( - widgetCallback = this, - factory = ViewHolderFactoryImpl() - ) + private val naviAdapter = + NaviInputWidgetAdapter( + widgetCallback = this, + factory = ViewHolderFactoryImpl() + ) + private var isColendingBalanceTransferEligible = false + private var naviDownloadManager: NaviDownloadManager? = null override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = DataBindingUtil.inflate( - inflater, R.layout.fragment_part_pre_payment_type, container, false - ) + binding = + DataBindingUtil.inflate( + inflater, + R.layout.fragment_part_pre_payment_type, + container, + false + ) return binding.root } @@ -78,45 +88,44 @@ class PartPrePaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback private fun init() { viewLifecycleOwner.lifecycleScope.launchWhenStarted { - launch { - partPrePaymentTypeVM.widgetDataResponse.collect { - setWidgetState(it) - } - } + launch { partPrePaymentTypeVM.widgetDataResponse.collect { setWidgetState(it) } } } } private fun setWidgetState(viewState: GenericWidgetState) { when (viewState) { - is GenericWidgetState.Init -> { - } + is GenericWidgetState.Init -> {} is GenericWidgetState.Update -> { viewState.data?.run { - this.header?.getOrNull(0)?.let { - updateContainer(it, binding.headerContainer) - } + this.header?.getOrNull(0)?.let { updateContainer(it, binding.headerContainer) } this.footer?.getOrNull(0)?.let { updateContainer(it, binding.footerContainer, true) } this.content?.let { contentWidget -> binding.recyclerView.apply { - val linearLayoutManager = LinearLayoutManager( - context, - LinearLayoutManager.VERTICAL, - false - ) + val linearLayoutManager = + LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) layoutManager = linearLayoutManager naviAdapter.list = contentWidget adapter = naviAdapter } - binding.recyclerView.post { - handleActionButtonVisibility() - } + binding.recyclerView.post { handleActionButtonVisibility() } } val analyticsEvent = - this.metadata?.get(PartPrePaymentActivity.METADATA_ANALYTICS_EVENT)?.data as? AnalyticsEvent + this.metadata?.get(PartPrePaymentActivity.METADATA_ANALYTICS_EVENT)?.data + as? AnalyticsEvent NaviAnalytics.naviAnalytics.sendAnalyticsEvent(analyticsEvent, screenName) + + var coLendingBalanceTransferEvent = + this.metadata?.get(COLENDING_BALANCE_TRANSFER_EVENT)?.data + as? AnalyticsEvent + if (coLendingBalanceTransferEvent != null) { + NaviAnalytics.naviAnalytics.sendAnalyticsEvent( + coLendingBalanceTransferEvent + ) + isColendingBalanceTransferEligible = true + } } } } @@ -128,36 +137,46 @@ class PartPrePaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback if (naviAdapter.isValidWidget()) { val type = naviAdapter.getWidgetData().getOrNull(0) val entry = - naviClickAction.analyticsEventProperties?.properties?.filter { it.key == CommonNaviAnalytics.OVERRIDE_EVENT }?.entries?.firstOrNull() + naviClickAction.analyticsEventProperties + ?.properties + ?.filter { it.key == CommonNaviAnalytics.OVERRIDE_EVENT } + ?.entries + ?.firstOrNull() if (entry?.value == CommonNaviAnalytics.TEXT_TRUE) { NaviAnalytics.naviAnalytics.sendAnalyticsEvent( analyticsEvent = naviClickAction.analyticsEventProperties, - props = mutableMapOf( - Pair( - NaviAnalytics.SELECTED_OPTION, - type.toString() + props = + mutableMapOf( + Pair(NaviAnalytics.SELECTED_OPTION, type.toString()), + Pair( + ELIGIBLE_FOR_BALANCE_TRANSFER, + isColendingBalanceTransferEligible.toString() + ) ) - ) ) } loanAccountNumber = - naviClickAction.parameters?.filter { it.key == LOAN_ACCOUNT_NUMBER } - ?.firstOrNull()?.value + naviClickAction.parameters + ?.filter { it.key == LOAN_ACCOUNT_NUMBER } + ?.firstOrNull() + ?.value val amountData = - naviClickAction.parameters?.filter { it.key == NaviPaymentActivity.AMOUNT_DATA } - ?.firstOrNull()?.value + naviClickAction.parameters + ?.filter { it.key == NaviPaymentActivity.AMOUNT_DATA } + ?.firstOrNull() + ?.value val currency = - naviClickAction.parameters?.filter { it.key == PartPrePaymentActivity.CURRENCY } - ?.firstOrNull()?.value + naviClickAction.parameters + ?.filter { it.key == PartPrePaymentActivity.CURRENCY } + ?.firstOrNull() + ?.value val symbol = - naviClickAction.parameters?.filter { it.key == PartPrePaymentActivity.SYMBOL } - ?.firstOrNull()?.value + naviClickAction.parameters + ?.filter { it.key == PartPrePaymentActivity.SYMBOL } + ?.firstOrNull() + ?.value startPayment( - Amount( - amountData?.toDoubleOrNull(), - currency = currency, - symbol = symbol - ), + Amount(amountData?.toDoubleOrNull(), currency = currency, symbol = symbol), partPrePaymentRescheduleType = type as? String ) } @@ -167,19 +186,28 @@ class PartPrePaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback activity?.onBackPressed() } else if (naviClickAction.url == CtaType.VALIDATE_FORM_PAGE.name) { handleActionButtonVisibility() + } else if (naviClickAction.url == CtaType.DOWNLOAD.name) { + NaviAnalytics.naviAnalytics.sendAnalyticsEvent( + naviClickAction.analyticsEventProperties + ) + if (naviDownloadManager == null) { + naviDownloadManager = NaviDownloadManager(WeakReference(activity)) + } + naviDownloadManager?.start( + NaviAnalytics.PART_PRE_PAYMENT_TYPE_SCREEN, + naviClickAction.title.toString(), + naviClickAction.parameters?.getOrNull(0)?.value.toString(), + "" + ) } else { val bundle = Bundle() - naviClickAction.parameters?.forEach { - bundle.putString(it.key, it.value) - } + naviClickAction.parameters?.forEach { bundle.putString(it.key, it.value) } val source = arguments?.getString(PartPrePaymentActivity.SOURCE_DATA) if (source != null) { bundle.putString(PartPrePaymentActivity.SOURCE_DATA, source) } naviClickAction.url?.let { - fragmentInterchangeListener?.navigateToNextScreen( - it, bundle - ) + fragmentInterchangeListener?.navigateToNextScreen(it, bundle) } } } @@ -195,13 +223,9 @@ class PartPrePaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback private fun handleActionButtonVisibility() { if (naviAdapter.isValidWidget()) { - actionButtonProvider.getActionButton(footerBinding)?.let { - enableView(it) - } + actionButtonProvider.getActionButton(footerBinding)?.let { enableView(it) } } else { - actionButtonProvider.getActionButton(footerBinding)?.let { - disableView(it) - } + actionButtonProvider.getActionButton(footerBinding)?.let { disableView(it) } } } @@ -217,7 +241,9 @@ class PartPrePaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback footerBinding = layoutBinding } (layoutBinding?.root as? BaseNaviWidgetLayout)?.updateLayout( - layoutBinding, naviWidget, this@PartPrePaymentTypeFragment + layoutBinding, + naviWidget, + this@PartPrePaymentTypeFragment ) } } @@ -228,5 +254,4 @@ class PartPrePaymentTypeFragment : PartPrePaymentBaseFragment(), WidgetCallback companion object { const val TAG = "PART_PRE_PAYMENT_TYPE" } - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/part_prepayment/states/GenericWidgetState.kt b/app/src/main/java/com/naviapp/part_prepayment/states/GenericWidgetState.kt index 54e0aa459e..8709cc7cfa 100644 --- a/app/src/main/java/com/naviapp/part_prepayment/states/GenericWidgetState.kt +++ b/app/src/main/java/com/naviapp/part_prepayment/states/GenericWidgetState.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022 by Navi Technologies Private Limited + * * Copyright © 2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -11,5 +11,7 @@ import com.navi.naviwidgets.models.response.GenericWidgetResponse sealed class GenericWidgetState { object Init : GenericWidgetState() + object Loading : GenericWidgetState() + object Failure : GenericWidgetState() class Update(val data: GenericWidgetResponse?) : GenericWidgetState() -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/payment/activities/FeedbackActivity.kt b/app/src/main/java/com/naviapp/payment/activities/FeedbackActivity.kt new file mode 100644 index 0000000000..2b2ae867d2 --- /dev/null +++ b/app/src/main/java/com/naviapp/payment/activities/FeedbackActivity.kt @@ -0,0 +1,89 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.payment.activities + +import android.os.Bundle +import androidx.databinding.DataBindingUtil +import com.navi.base.model.CtaData +import com.navi.common.listeners.FragmentInterchangeListener +import com.navi.common.model.ModuleNameV2 +import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics.Companion.POST_PAYMENT_MESSAGING_SCREEN +import com.naviapp.common.navigator.NaviDeepLinkNavigator +import com.naviapp.dashboard.DashboardBaseActivity +import com.naviapp.databinding.ActivityPostPaymentMessagingBinding +import com.naviapp.models.SubPageStatusType.SUCCESS_FRAGMENT +import com.naviapp.part_prepayment.FragmentMapper +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@AndroidEntryPoint +class FeedbackActivity : DashboardBaseActivity(), FragmentInterchangeListener { + private lateinit var binding: ActivityPostPaymentMessagingBinding + @Inject lateinit var fragmentMapper: FragmentMapper + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView(this, R.layout.activity_post_payment_messaging) + navigateToNextScreen(SUCCESS_FRAGMENT, intent?.extras ?: Bundle()) + } + + override val screenName: String + get() = POST_PAYMENT_MESSAGING_SCREEN + + override val moduleName: ModuleNameV2 + get() = ModuleNameV2.COMMON + + @OptIn(ExperimentalCoroutinesApi::class) + override fun navigateToNextScreen(currentScreenTag: String, bundle: Bundle) { + val tag = fragmentMapper.getFragmentTagByUrl(currentScreenTag) + val fragment = + supportFragmentManager.findFragmentByTag(tag) + ?: fragmentMapper.getFragmentByUrl(currentScreenTag) + fragment?.apply { arguments = bundle } + if (fragment != null) { + val fragmentTransaction = supportFragmentManager.beginTransaction() + if (!supportFragmentManager.isStateSaved && !supportFragmentManager.isDestroyed) { + fragmentTransaction.addToBackStack(tag) + fragmentTransaction.replace(R.id.fragment_container, fragment, tag) + fragmentTransaction.commit() + } + } else { + NaviDeepLinkNavigator.navigate( + this, + CtaData(url = currentScreenTag, bundle = bundle), + true + ) + } + } + + override fun onBackPressed() { + supportFragmentManager.fragments + .takeIf { it.size > 0 } + ?.let { fragments -> + for (i in (fragments.size - 1) downTo 0) { + val fragment = fragments[i] + val childFragmentManager = fragment.childFragmentManager + if (fragment.isVisible) { + if (childFragmentManager.backStackEntryCount > 0) { + supportFragmentManager.popBackStackImmediate() + return + } + break + } + } + if (supportFragmentManager.backStackEntryCount > 1) { + supportFragmentManager.popBackStackImmediate() + } else { + finish() + } + } + ?: run { finish() } + } +} diff --git a/app/src/main/java/com/naviapp/payment/fragments/PaymentBaseFragment.kt b/app/src/main/java/com/naviapp/payment/fragments/PaymentBaseFragment.kt index b026d4bf69..736d9d7df2 100644 --- a/app/src/main/java/com/naviapp/payment/fragments/PaymentBaseFragment.kt +++ b/app/src/main/java/com/naviapp/payment/fragments/PaymentBaseFragment.kt @@ -326,6 +326,5 @@ enum class PaymentType { EMI, PRE_LOAN_CLOSURE, PART_PRE_PAYMENT, - CUSTOM_PAYMENT, SCHEDULED_PRE_CLOSURE } diff --git a/app/src/main/java/com/naviapp/payment/fragments/SuccessFragment.kt b/app/src/main/java/com/naviapp/payment/fragments/SuccessFragment.kt index 29b7738eb8..bcd5072e12 100644 --- a/app/src/main/java/com/naviapp/payment/fragments/SuccessFragment.kt +++ b/app/src/main/java/com/naviapp/payment/fragments/SuccessFragment.kt @@ -22,6 +22,11 @@ import com.naviapp.models.request.ForeclosureSuccessPageRequest import com.naviapp.models.response.ImageDetail import com.naviapp.payment.viewmodel.PaymentVM import com.naviapp.utils.AMOUNT_DATA +import com.naviapp.utils.Constants.BANK_ACCOUNT_NUMBER +import com.naviapp.utils.Constants.NEGATIVE_FORECLOSURE +import com.naviapp.utils.Constants.REFUND_AMOUNT +import com.naviapp.utils.Constants.REFUND_DATE +import com.naviapp.utils.Constants.TRUE import com.naviapp.utils.IconUtils import com.naviapp.utils.LOAN_ACCOUNT_NUMBER @@ -37,29 +42,30 @@ class SuccessFragment : BaseFragment() { ): View { super.onCreateView(inflater, container, savedInstanceState) binding = SuccessFragmentBinding.inflate(inflater, container, false) - loanAccountNumber = activity?.intent?.extras?.getString(LOAN_ACCOUNT_NUMBER) - foreclosedAmount = activity?.intent?.extras?.getDouble(AMOUNT_DATA) + loanAccountNumber = arguments?.getString(LOAN_ACCOUNT_NUMBER) + foreclosedAmount = arguments?.getString(AMOUNT_DATA)?.toDoubleOrNull() fetchForeclosureSuccessPage() initObservers() return binding.root } - fun fetchForeclosureSuccessPage() { + + private fun fetchForeclosureSuccessPage() { showLoader() viewModel.fetchForeclosureSuccessPage( loanAccountNumber, ForeclosureSuccessPageRequest( foreclosedAmount = foreclosedAmount, - refundAmount = null, - refundDate = null, - disbursementBankReferenceId = null, - isNegativeForeclosure = false + refundAmount = arguments?.getString(REFUND_AMOUNT)?.toDoubleOrNull(), + refundDate = arguments?.getString(REFUND_DATE), + bankAccountNumber = arguments?.getString(BANK_ACCOUNT_NUMBER), + isNegativeForeclosure = arguments?.getString(NEGATIVE_FORECLOSURE).equals(TRUE) ) ) } fun initObservers() { viewModel.foreclosureSuccessPage.observeNullable(viewLifecycleOwner) { - foreclosureSuccessPage -> + foreclosureSuccessPage -> hideLoader() binding.apply { foreclosureSuccessPage?.paymentMessage?.let { @@ -81,9 +87,11 @@ class SuccessFragment : BaseFragment() { } } } + companion object { const val TAG = "SUCCESS_FRAGMENT" } + override val screenName: String get() = NaviAnalytics.POST_PAYMENT_MESSAGING_SCREEN -} +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/payment/models/ForeclosureSuccessPage.kt b/app/src/main/java/com/naviapp/payment/models/ForeclosureSuccessPage.kt index 248189f10d..68449cf93b 100644 --- a/app/src/main/java/com/naviapp/payment/models/ForeclosureSuccessPage.kt +++ b/app/src/main/java/com/naviapp/payment/models/ForeclosureSuccessPage.kt @@ -16,7 +16,7 @@ import kotlinx.android.parcel.Parcelize @Parcelize data class ForeclosureSuccessPage( - @SerializedName("paymentMessage") val paymentMessage: PaymentMessage?, + @SerializedName("paymentMessage") val paymentMessage: PaymentMessage? = null, @SerializedName("footer") val footer: Footer? ) : Parcelable diff --git a/app/src/main/java/com/naviapp/payment/models/PaymentRequest.kt b/app/src/main/java/com/naviapp/payment/models/PaymentRequest.kt index b5dc3307cc..36354b9ce2 100644 --- a/app/src/main/java/com/naviapp/payment/models/PaymentRequest.kt +++ b/app/src/main/java/com/naviapp/payment/models/PaymentRequest.kt @@ -17,7 +17,8 @@ data class PaymentRequest( @SerializedName("notes") var notes: Notes? = null, @SerializedName("contact") val contact: String? = null, @SerializedName("customer_id") val customerId: String? = null, - @SerializedName("prefill") var prefill: Prefill? = null + @SerializedName("prefill") var prefill: Prefill? = null, + @SerializedName("sdkConfigKey") val key: String? = null, ) data class Notes( diff --git a/app/src/main/java/com/naviapp/payment/repositories/PaymentRepository.kt b/app/src/main/java/com/naviapp/payment/repositories/PaymentRepository.kt index d53ea18122..ca277b89b2 100644 --- a/app/src/main/java/com/naviapp/payment/repositories/PaymentRepository.kt +++ b/app/src/main/java/com/naviapp/payment/repositories/PaymentRepository.kt @@ -7,13 +7,10 @@ package com.naviapp.payment.repositories -import com.navi.common.model.RepoResult import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.RepoResult import com.naviapp.models.PgRepaymentData -import com.naviapp.models.request.AutoDebitEducationRequest -import com.naviapp.models.request.CustomPaymentRequest -import com.naviapp.models.request.ForeclosureSuccessPageRequest -import com.naviapp.models.request.NewPaymentApiRequest +import com.naviapp.models.request.* import com.naviapp.models.response.AsyncRequestData import com.naviapp.models.response.NotificationSettings import com.naviapp.models.response.NotificationSettingsContent @@ -159,16 +156,12 @@ class PaymentRepository @Inject constructor() : ResponseCallback() { suspend fun fetchCustomPaymentCalendarWidget( loanAccountNumber: String?, - rescheduleType: String?, - customPayRequest: CustomPaymentRequest? + customPayRequest: CustomPaymentRequest?, + flowType: String? ) = apiResponseCallback( retrofitService() - .fetchCustomPaymentCalendarWidget( - loanAccountNumber, - rescheduleType, - customPayRequest - ) + .fetchCustomPaymentCalendarWidget(loanAccountNumber, flowType, customPayRequest) ) suspend fun fetchAutoDebitEducationTrackerWidget( @@ -191,4 +184,7 @@ class PaymentRepository @Inject constructor() : ResponseCallback() { retrofitService() .fetchForeclosureSuccessPage(loanAccountNumber, foreclosureSuccessPageRequest) ) + + suspend fun closeLoan(loanAccountNumber: String?, request: ForecloseLoanRequest?) = + apiResponseCallback(retrofitService().forecloseLoan(loanAccountNumber, request)) } diff --git a/app/src/main/java/com/naviapp/payment/viewmodel/PaymentVM.kt b/app/src/main/java/com/naviapp/payment/viewmodel/PaymentVM.kt index 1407fc4ea6..13f4cd3301 100644 --- a/app/src/main/java/com/naviapp/payment/viewmodel/PaymentVM.kt +++ b/app/src/main/java/com/naviapp/payment/viewmodel/PaymentVM.kt @@ -9,15 +9,20 @@ package com.naviapp.payment.viewmodel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import com.navi.base.model.CtaData import com.navi.common.model.UploadDataAsyncResponse import com.navi.common.viewmodel.BaseVM +import com.navi.naviwidgets.models.response.LayoutFieldData +import com.navi.naviwidgets.models.response.TextFieldData import com.naviapp.models.PgRepaymentData import com.naviapp.models.RedirectPageStatus +import com.naviapp.models.request.ForecloseLoanRequest import com.naviapp.models.request.ForeclosureSuccessPageRequest import com.naviapp.models.response.* import com.naviapp.network.ApiErrorTagType import com.naviapp.part_prepayment.states.GenericWidgetState import com.naviapp.payment.models.* +import com.naviapp.payment.models.Footer import com.naviapp.payment.repositories.PaymentRepository import com.naviapp.utils.Constants import com.naviapp.utils.RUPEES_IN_PAISA @@ -92,6 +97,9 @@ class PaymentVM : BaseVM() { val foreclosureSuccessPage: LiveData get() = _foreclosureSuccessPage + private val _closeLoanResponse = MutableStateFlow(GenericWidgetState.Init) + val closeLoanResponse = _closeLoanResponse.asStateFlow() + fun initiatePayment(data: InitiatePaymentRequest) { coroutineScope.launch { val response = repository.initiatePayment(data) @@ -322,7 +330,44 @@ class PaymentVM : BaseVM() { ) { _foreclosureSuccessPage.value = response.data } else { - _foreclosureSuccessPage.value = null + _foreclosureSuccessPage.value = getFailureSuccessPage() + } + } + } + + private fun getFailureSuccessPage() = ForeclosureSuccessPage( + footer = Footer( + primaryAction = LayoutFieldData( + action = TextFieldData( + text = "Go to home", + textColor = "#F5F5F5", + size = 14, + font = "BOLD", + cta = CtaData( + url = "HOME" + ) + ), + gravity = "CENTER", + bgColor = "#ff5732" + ) + ) + ) + + fun closeLoan(loanAccountNumber: String?, closureType: String?) { + coroutineScope.launch { + _closeLoanResponse.emit(GenericWidgetState.Init) + val response = + repository.closeLoan( + loanAccountNumber, + ForecloseLoanRequest(closureType = closureType) + ) + if ( + response.data != null && response.error == null && response.errors.isNullOrEmpty() + ) { + _closeLoanResponse.emit(GenericWidgetState.Update(response.data)) + } else { + _closeLoanResponse.emit(GenericWidgetState.Failure) + setErrorData(response.errors, response.error) } } } diff --git a/app/src/main/java/com/naviapp/personalloan/factory/LoanDetailsV2VHFactoryImpl.kt b/app/src/main/java/com/naviapp/personalloan/factory/LoanDetailsV2VHFactoryImpl.kt index 56207ff746..2b40ea97f8 100644 --- a/app/src/main/java/com/naviapp/personalloan/factory/LoanDetailsV2VHFactoryImpl.kt +++ b/app/src/main/java/com/naviapp/personalloan/factory/LoanDetailsV2VHFactoryImpl.kt @@ -21,6 +21,7 @@ import com.naviapp.personalloanrevamp.common.customview.HeaderDescriptionView import com.naviapp.personalloanrevamp.common.customview.OfferUpgradedCardView import com.naviapp.personalloanrevamp.common.customview.ViewCtaView import com.naviapp.personalloanrevamp.getloanRevamp.customview.BankNameCardView +import com.naviapp.personalloanrevamp.getloanRevamp.customview.OfferUpgradeCardV2View import com.naviapp.personalloanrevamp.getloanRevamp.customview.OfferUpgradeCardView import com.naviapp.personalloanrevamp.getloanRevamp.customview.StyledKeyValueCardView import com.naviapp.personalloanrevamp.getloanRevamp.listeners.LoanDetailsV2WidgetAdapterListener @@ -40,6 +41,8 @@ class LoanDetailsV2VHFactoryImpl : VHFactory() { LoanDetailsV2WidgetType.BANK_NAME_CARD.ordinal LoanDetailsV2WidgetType.OFFER_UPGRADE_CARD.name -> LoanDetailsV2WidgetType.OFFER_UPGRADE_CARD.ordinal + LoanDetailsV2WidgetType.OFFER_UPGRADE_CARD_V2.name -> + LoanDetailsV2WidgetType.OFFER_UPGRADE_CARD_V2.ordinal LoanDetailsV2WidgetType.SLIDER_WITH_TOOLTIP_TITLE.name -> LoanDetailsV2WidgetType.SLIDER_WITH_TOOLTIP_TITLE.ordinal LoanDetailsV2WidgetType.WIDGET_LIST_WITH_RADIO_BUTTON.name -> @@ -74,6 +77,8 @@ class LoanDetailsV2VHFactoryImpl : VHFactory() { BankNameViewHolder(BankNameCardView(parent.context)) LoanDetailsV2WidgetType.OFFER_UPGRADE_CARD.ordinal -> OfferUpgradeViewHolder(OfferUpgradeCardView(parent.context)) + LoanDetailsV2WidgetType.OFFER_UPGRADE_CARD_V2.ordinal -> + OfferUpgradeV2ViewHolder(OfferUpgradeCardV2View(parent.context)) LoanDetailsV2WidgetType.TITLE_WITH_BUTTON.ordinal -> TitleWithButtonViewHolder(TitleWithButtonView(parent.context)) LoanDetailsV2WidgetType.SLIDER_WITH_TOOLTIP_TITLE.ordinal -> @@ -130,6 +135,14 @@ class LoanDetailsV2VHFactoryImpl : VHFactory() { listener as? LoanDetailsV2WidgetAdapterListener ) } + is OfferUpgradeV2ViewHolder -> { + loanDetailsEventTracker.onOfferUpgradeBannerVisible() + loanDetailsEventTracker.onOfferUpgradeCardShown() + holder.view.setProperties( + data as? OfferUpgradeCardV2WidgetConfig, + listener as? LoanDetailsV2WidgetAdapterListener + ) + } is TitleWithButtonViewHolder -> holder.view.setProperties( data as? TitleWithButtonWidgetConfig, @@ -203,6 +216,8 @@ class TitleWithButtonViewHolder(val view: TitleWithButtonView) : LoanDetailsV2Vi class OfferUpgradeViewHolder(val view: OfferUpgradeCardView) : LoanDetailsV2ViewHolder(view) +class OfferUpgradeV2ViewHolder(val view: OfferUpgradeCardV2View) : LoanDetailsV2ViewHolder(view) + class BankNameViewHolder(val view: BankNameCardView) : LoanDetailsV2ViewHolder(view) class StyledKeyValueViewHolder(val view: StyledKeyValueCardView) : LoanDetailsV2ViewHolder(view) diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/fragments/KycAddressFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/fragments/KycAddressFragment.kt index 23127d9c55..ce34238772 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/fragments/KycAddressFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/fragments/KycAddressFragment.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -19,11 +19,11 @@ import android.view.ViewGroup import androidx.core.widget.doAfterTextChanged import androidx.lifecycle.ViewModelProvider import com.navi.analytics.utils.NaviTrackEvent +import com.navi.base.model.CtaData import com.navi.common.firebasedb.* import com.navi.common.listeners.HeaderInteractionListener import com.navi.common.listeners.LocationUpdateListener -import com.navi.base.model.CtaData -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* import com.naviapp.R @@ -50,7 +50,10 @@ import com.naviapp.utils.Constants.HOUSE_NUMBER_MIN_SIZE import com.naviapp.utils.Constants.LOCALITY_MIN_SIZE import com.naviapp.utils.Constants.STREET_MIN_SIZE -class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListener, +class KycAddressFragment : + BaseFragment(), + View.OnClickListener, + View.OnKeyListener, View.OnFocusChangeListener, FooterInteractionListener { private lateinit var binding: FragmentKycAddressBinding @@ -66,7 +69,6 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe private var locationUpdateListener: LocationUpdateListener? = null private val analyticsEventTracker = NaviAnalytics.naviAnalytics.KycAddress() - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -114,20 +116,13 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe viewModel.cityAndStateResponse.observeNullable(viewLifecycleOwner) { hideLoader() context?.let { context -> - hideKeyboard( - context, - binding.addressLayout.currentAddressPincode - ) + hideKeyboard(context, binding.addressLayout.currentAddressPincode) } it?.city?.let { cityName -> it.state?.let { stateName -> binding.addressLayout.currentAddressCity.visibility = View.VISIBLE binding.addressLayout.currentAddressCity.setText( - resources.getString( - R.string.city_state_format, - cityName, - stateName - ) + resources.getString(R.string.city_state_format, cityName, stateName) ) enableNextButton() } @@ -150,7 +145,9 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe KycUiStatusValue.SOFT_REJECT.name -> { gotoSoftReject() } - KycUiStatusValue.IN_REVIEW.name, KycUiStatusValue.OSV_VERIFICATION_IN_PROGRESS.name, KycUiStatusValue.OSV_OPS_VERIFICATION_PENDING.name -> { + KycUiStatusValue.IN_REVIEW.name, + KycUiStatusValue.OSV_VERIFICATION_IN_PROGRESS.name, + KycUiStatusValue.OSV_OPS_VERIFICATION_PENDING.name -> { navigateToKycInReviewScreen() } KycUiStatusValue.OSV_VERIFICATION.name -> { @@ -164,11 +161,14 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe } } - private fun observeNextCta() { viewModel.addressStatusNextCta.observeNullable(this) { saveCorrespondenceAddressResponse -> hideLoader() - if (saveCorrespondenceAddressResponse?.correspondenceAddressDetails?.currentSameAsPermanent == true) { + if ( + saveCorrespondenceAddressResponse + ?.correspondenceAddressDetails + ?.currentSameAsPermanent == true + ) { val address = getAddressFromCurrentAddress(getCurrentAddress(), true) showLoader() viewModel.updateKycDetails(KycRequest(address)) @@ -219,7 +219,8 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe } private fun observeAddressVerificationData() { - viewModel.addressDetailsLiveData.observeNullable(this) { addressVerificationDetailsResponse -> + viewModel.addressDetailsLiveData.observeNullable(this) { addressVerificationDetailsResponse + -> hideLoader() analyticsEventTracker.onCustomerLandsOnCorrespondenceAddressPage(getLoanApplicationId()) headerInteractionListener?.setProperties( @@ -233,12 +234,8 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe this ) addressVerificationDetailsResponse?.content?.addressLabel?.let { - it.title?.let { title -> - binding.subtitleTv.text = title - } - it.iconCode?.let { iconCode -> - IconUtils.updateIcon(iconCode, binding.thumbnailIv) - } + it.title?.let { title -> binding.subtitleTv.text = title } + it.iconCode?.let { iconCode -> IconUtils.updateIcon(iconCode, binding.thumbnailIv) } } addressVerificationDetailsResponse?.content?.note?.let { binding.noteView.setProperties(it.title, it.iconCode) @@ -254,11 +251,7 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe viewModel.kycAddressDetailsSubmitAsyncData.observeNonNull(this) { data -> data.requestId?.let { requestId -> firebaseRequestId = requestId - firebaseInit( - requestId, - UPDATE_KYC_DETAILS, - data.notificationPath.orEmpty() - ) + firebaseInit(requestId, UPDATE_KYC_DETAILS, data.notificationPath.orEmpty()) apiPollInit(requestId, UPDATE_KYC_DETAILS) } } @@ -302,25 +295,29 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe binding.noteView.setProperties(getString(R.string.kyc_address_note)) val pincodeEt = binding.addressLayout.currentAddressPincode pincodeEt.setOnKeyListener(this) - pincodeEt.addTextChangedListener(object : TextWatcher { - override fun afterTextChanged(s: Editable?) { - } + pincodeEt.addTextChangedListener( + object : TextWatcher { + override fun afterTextChanged(s: Editable?) {} - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { - } + override fun beforeTextChanged( + s: CharSequence?, + start: Int, + count: Int, + after: Int + ) {} - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - if (s?.length == Constants.PINCODE_SIZE) { - showLoader() - viewModel.fetchCityAndState(s.toString()) - } else { - binding.addressLayout.currentAddressPincode.error = null - binding.addressLayout.currentAddressCity.setText("") - binding.addressLayout.currentAddressCity.visibility = View.GONE + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + if (s?.length == Constants.PINCODE_SIZE) { + showLoader() + viewModel.fetchCityAndState(s.toString()) + } else { + binding.addressLayout.currentAddressPincode.error = null + binding.addressLayout.currentAddressCity.setText("") + binding.addressLayout.currentAddressCity.visibility = View.GONE + } } } - - }) + ) } private fun setAddressToUI(data: CurrentAddress) { @@ -329,72 +326,84 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe data.locality?.let { binding.addressLayout.currentAddressLine3.setText(it) } data.pinCode?.let { binding.addressLayout.currentAddressPincode.setText(it) } data.city?.let { - binding.addressLayout.currentAddressCity.setText(if (data.state.isNullOrEmpty()) it else it + ", " + data.state) - } ?: kotlin.run { - data.state?.let { - binding.addressLayout.currentAddressCity.setText(it) - } + binding.addressLayout.currentAddressCity.setText( + if (data.state.isNullOrEmpty()) it else it + ", " + data.state + ) } + ?: kotlin.run { + data.state?.let { binding.addressLayout.currentAddressCity.setText(it) } + } } private fun shouldEnableNextButton(showError: Boolean): Boolean { var enable = true val houseNumberMinChars = - viewModel.addressDetailsLiveData.value?.content?.currentAddressMinSize?.houseNumberMinChars.orValue( - HOUSE_NUMBER_MIN_SIZE - ) + viewModel.addressDetailsLiveData.value + ?.content + ?.currentAddressMinSize + ?.houseNumberMinChars + .orValue(HOUSE_NUMBER_MIN_SIZE) val streetMinChars = - viewModel.addressDetailsLiveData.value?.content?.currentAddressMinSize?.streetMinChars.orValue( - STREET_MIN_SIZE - ) + viewModel.addressDetailsLiveData.value + ?.content + ?.currentAddressMinSize + ?.streetMinChars + .orValue(STREET_MIN_SIZE) val localityMinChars = - viewModel.addressDetailsLiveData.value?.content?.currentAddressMinSize?.localityMinChars.orValue( - LOCALITY_MIN_SIZE - ) + viewModel.addressDetailsLiveData.value + ?.content + ?.currentAddressMinSize + ?.localityMinChars + .orValue(LOCALITY_MIN_SIZE) val currentAddressLine1String = binding.addressLayout.currentAddressLine1.text.toString() - if (currentAddressLine1String.length < houseNumberMinChars || currentAddressLine1String.removeSpaces().isEmpty() + if ( + currentAddressLine1String.length < houseNumberMinChars || + currentAddressLine1String.removeSpaces().isEmpty() ) { enable = false if (showError) { binding.addressLayout.currentAddressLine1.setError( - getString(R.string.min_character_length).appendStrings( - " $houseNumberMinChars ", - getString(R.string._char) - ) + getString(R.string.min_character_length) + .appendStrings(" $houseNumberMinChars ", getString(R.string._char)) ) } } val currentAddressLine2String = binding.addressLayout.currentAddressLine2.text.toString() - if (currentAddressLine2String.length < streetMinChars || currentAddressLine2String.removeSpaces().isEmpty() + if ( + currentAddressLine2String.length < streetMinChars || + currentAddressLine2String.removeSpaces().isEmpty() ) { enable = false if (showError) { binding.addressLayout.currentAddressLine2.setError( - getString(R.string.min_character_length).appendStrings( - " $streetMinChars ", - getString(R.string._char) - ) + getString(R.string.min_character_length) + .appendStrings(" $streetMinChars ", getString(R.string._char)) ) } } val currentAddressLine3String = binding.addressLayout.currentAddressLine3.text.toString() - if (currentAddressLine3String.length < localityMinChars || currentAddressLine3String.removeSpaces().isEmpty() + if ( + currentAddressLine3String.length < localityMinChars || + currentAddressLine3String.removeSpaces().isEmpty() ) { enable = false if (showError) { binding.addressLayout.currentAddressLine3.setError( - getString(R.string.min_character_length).appendStrings( - " $localityMinChars ", - getString(R.string._char) - ) + getString(R.string.min_character_length) + .appendStrings(" $localityMinChars ", getString(R.string._char)) ) } } - if (binding.addressLayout.currentAddressPincode.text.toString().length != Constants.PINCODE_SIZE) { + if ( + binding.addressLayout.currentAddressPincode.text.toString().length != + Constants.PINCODE_SIZE + ) { enable = false if (showError) { - binding.addressLayout.currentAddressPincode.setError(getString(R.string.enter_a_valid_pincode)) + binding.addressLayout.currentAddressPincode.setError( + getString(R.string.enter_a_valid_pincode) + ) } } if (binding.addressLayout.currentAddressCity.text.toString().isEmpty()) { @@ -410,23 +419,24 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe private fun confirmAddress() { if (shouldEnableNextButton(true)) { NaviTrackEvent.setStartTs(screenName) - val currentAddress = CurrentAddress( - houseNumber = binding.addressLayout.currentAddressLine1.text.toString(), - street = binding.addressLayout.currentAddressLine2.text.toString(), - locality = binding.addressLayout.currentAddressLine3.text.toString(), - status = KycFragment.COMPLETED, - documentType = uploadedDocumentTypeAndUrl?.first, - documentUrl = uploadedDocumentTypeAndUrl?.second, - pinCode = binding.addressLayout.currentAddressPincode.text.toString(), - city = binding.addressLayout.currentAddressCity.text.toString(), - current = data?.current, - referenceId = data?.referenceId, - state = data?.state, - type = data?.type, - isAddressProofOptional = data?.isAddressProofOptional, - completeAddress = data?.completeAddress, - addressQualityStatus = data?.addressQualityStatus - ) + val currentAddress = + CurrentAddress( + houseNumber = binding.addressLayout.currentAddressLine1.text.toString(), + street = binding.addressLayout.currentAddressLine2.text.toString(), + locality = binding.addressLayout.currentAddressLine3.text.toString(), + status = KycFragment.COMPLETED, + documentType = uploadedDocumentTypeAndUrl?.first, + documentUrl = uploadedDocumentTypeAndUrl?.second, + pinCode = binding.addressLayout.currentAddressPincode.text.toString(), + city = binding.addressLayout.currentAddressCity.text.toString(), + current = data?.current, + referenceId = data?.referenceId, + state = data?.state, + type = data?.type, + isAddressProofOptional = data?.isAddressProofOptional, + completeAddress = data?.completeAddress, + addressQualityStatus = data?.addressQualityStatus + ) submitKycDetails(currentAddress) } } @@ -441,7 +451,7 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe private fun gotoSoftReject(data: Pair? = null) { val bundle = Bundle() - bundle.putString(Constants.WIDGET_ID,Constants.PERSONAL_LOAN) + bundle.putString(Constants.WIDGET_ID, Constants.PERSONAL_LOAN) data?.let { bundle.putParcelable(ErrorActivity.REDIRECT_DATA, it.first) bundle.putParcelable(ErrorActivity.ERROR_DATA, it.second) @@ -460,19 +470,28 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe private fun navigateToNextScreen() { viewModel.kycStatus.value?.footer?.nextCta?.url?.let { val loanApplicationId = - viewModel.kycStatus.value?.footer?.nextCta?.parameters?.firstOrNull { item -> - item.key == Constants.PERSONAL_LOAN_APPLICATION_ID - }?.value - listener?.navigateTo(it, Bundle().apply { - putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) - }) + viewModel.kycStatus.value + ?.footer + ?.nextCta + ?.parameters + ?.firstOrNull { item -> item.key == Constants.PERSONAL_LOAN_APPLICATION_ID } + ?.value + listener?.navigateTo( + it, + Bundle().apply { + putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) + } + ) } } fun getLoanApplicationId(): String? { - return viewModel.kycStatus.value?.footer?.nextCta?.parameters?.firstOrNull { item -> - item.key == Constants.PERSONAL_LOAN_APPLICATION_ID - }?.value + return viewModel.kycStatus.value + ?.footer + ?.nextCta + ?.parameters + ?.firstOrNull { item -> item.key == Constants.PERSONAL_LOAN_APPLICATION_ID } + ?.value } override fun onClick(view: View?) { @@ -485,11 +504,7 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe } override fun onFooterBackPress(ctaData: CtaData?) { - ctaData?.url?.let { - listener?.navigateTo( - it - ) - } + ctaData?.url?.let { listener?.navigateTo(it) } } override fun onFooterNextPress(ctaData: CtaData?, skipValidation: Boolean?) { @@ -500,26 +515,19 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe override fun onFocusChange(v: View?, hasFocus: Boolean) { when (v?.id) { binding.addressLayout.currentAddressLine1.id -> { - if (hasFocus) - analyticsEventTracker.onCurrentAddressHouseSelect() + if (hasFocus) analyticsEventTracker.onCurrentAddressHouseSelect() } binding.addressLayout.currentAddressLine2.id -> { - if (hasFocus) - analyticsEventTracker.onCurrentAddressLocalitySelect() + if (hasFocus) analyticsEventTracker.onCurrentAddressLocalitySelect() } binding.addressLayout.currentAddressLine3.id -> { - if (hasFocus) - analyticsEventTracker.onCurrentAddressStreetSelect() + if (hasFocus) analyticsEventTracker.onCurrentAddressStreetSelect() } - binding.addressLayout.currentAddressPincode.id -> { - if (hasFocus) - analyticsEventTracker.onCurrentAddressPincodeSelect() + if (hasFocus) analyticsEventTracker.onCurrentAddressPincodeSelect() } - binding.addressLayout.currentAddressCity.id -> { - if (hasFocus) - analyticsEventTracker.onCurrentAddressCitySelect() + if (hasFocus) analyticsEventTracker.onCurrentAddressCitySelect() } } } @@ -543,16 +551,17 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe private const val CORRESPONDENCE = "CORRESPONDENCE" } - - private val pollingTimeoutClickListener: View.OnClickListener = View.OnClickListener { - when (errorTag) { - ApiErrorTagType.KYC_DETAIL_UPLOAD -> { - viewModel.addressDetailsLiveData.value?.content?.currentAddress?.let { currentAddress -> - submitKycDetails(currentAddress) + private val pollingTimeoutClickListener: View.OnClickListener = + View.OnClickListener { + when (errorTag) { + ApiErrorTagType.KYC_DETAIL_UPLOAD -> { + viewModel.addressDetailsLiveData.value?.content?.currentAddress?.let { + currentAddress -> + submitKycDetails(currentAddress) + } } } } - } private fun handleTimeOutError(errorTag: String) { showTimeoutErrorScreen( @@ -566,27 +575,27 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe } private var errorTag: String? = null - private val onPollingEnd = { - handleTimeOutError(errorTag.orEmpty()) - } + private val onPollingEnd = { handleTimeOutError(errorTag.orEmpty()) } private fun apiPollInit(requestId: String, type: String) { errorTag = ApiErrorTagType.KYC_DETAIL_UPLOAD - apiPollScheduler = ApiPollScheduler(doOnTimeout = onPollingEnd) { - viewModel.checkApiPollStatus(requestId, type) - } + apiPollScheduler = + ApiPollScheduler(doOnTimeout = onPollingEnd) { + viewModel.checkApiPollStatus(requestId, type) + } apiPollScheduler?.scheduleApiPoll() } private fun firebaseInit(requestId: String, type: String, notificationPath: String) { - firebaseDataReceiveListener = object : FirebaseDataReceiveListener { - override fun onDataReceive(firebaseResponse: FirebaseResponse?) { - firebaseResponse?.let { - apiPollScheduler?.stopApiPoll() - handleFirebaseResult(it.status.orEmpty(), type, false) + firebaseDataReceiveListener = + object : FirebaseDataReceiveListener { + override fun onDataReceive(firebaseResponse: FirebaseResponse?) { + firebaseResponse?.let { + apiPollScheduler?.stopApiPoll() + handleFirebaseResult(it.status.orEmpty(), type, false) + } } } - } firebaseDataHelper = null firebaseDataHelper = FirebaseDataHelper() firebaseDataHelper?.initFirebaseDataReceiver( @@ -598,15 +607,10 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe ) } - private fun handleFirebaseResult( - status: String, - type: String, - isPolling: Boolean = true - ) { - if (TextUtils.equals(status, FirebaseStatusType.SUCCESS) - || TextUtils.equals( - status, FirebaseStatusType.FAILURE - ) + private fun handleFirebaseResult(status: String, type: String, isPolling: Boolean = true) { + if ( + TextUtils.equals(status, FirebaseStatusType.SUCCESS) || + TextUtils.equals(status, FirebaseStatusType.FAILURE) ) { deInitializeFirebaseListener() apiPollScheduler?.stopApiPoll() @@ -632,13 +636,9 @@ class KycAddressFragment : BaseFragment(), View.OnClickListener, View.OnKeyListe override fun onKey(v: View?, keyCode: Int, event: KeyEvent?): Boolean { if (event?.action != KeyEvent.ACTION_DOWN || keyCode != KeyEvent.KEYCODE_ENTER) return false when (v?.id) { - R.id.current_address_pincode -> context?.let { - hideKeyboard( - it, - binding.addressLayout.currentAddressPincode - ) - } + R.id.current_address_pincode -> + context?.let { hideKeyboard(it, binding.addressLayout.currentAddressPincode) } } return false } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/fragments/KycAddressProofFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/fragments/KycAddressProofFragment.kt index fb68b00ae8..1750f5060f 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/fragments/KycAddressProofFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/fragments/KycAddressProofFragment.kt @@ -20,7 +20,7 @@ import com.navi.base.model.CtaData import com.navi.common.firebasedb.* import com.navi.common.listeners.HeaderInteractionListener import com.navi.common.listeners.LocationUpdateListener -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* import com.naviapp.BuildConfig @@ -47,8 +47,9 @@ import com.naviapp.personalloan.getloan.kyc.fragments.KycFragment import com.naviapp.personalloan.getloan.kyc.listeners.DocumentUploadListener import com.naviapp.personalloan.getloan.kyc.utils.DocumentType.ELECTRICITY_BILL import com.naviapp.personalloan.getloan.kyc.utils.getKycDocuments -import com.naviapp.utils.* import com.naviapp.utils.Constants +import com.naviapp.utils.DEV +import com.naviapp.utils.toast class KycAddressProofFragment : BaseFragment(), diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/viewmodels/AddressVerificationVM.kt b/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/viewmodels/AddressVerificationVM.kt index 18c2c1d4ff..c20e53554a 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/viewmodels/AddressVerificationVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/addressverification/viewmodels/AddressVerificationVM.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -11,6 +11,8 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.navi.common.firebasedb.UPDATE_KYC_DETAILS import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.utils.orTrue import com.navi.common.viewmodel.BaseVM import com.naviapp.models.RedirectPageStatus import com.naviapp.models.request.Address @@ -19,8 +21,6 @@ import com.naviapp.models.request.SaveCorrespondenceAddressRequest import com.naviapp.models.response.* import com.naviapp.network.ApiErrorTagType import com.naviapp.personalloan.getloan.kyc.fragments.KycFragment -import com.navi.common.model.GenericErrorResponse -import com.navi.common.utils.orTrue import com.naviapp.personalloan.getloan.kyc.models.KycInReviewResponse import com.naviapp.personalloan.getloan.kyc.repositories.KycRepository import com.naviapp.personalloanrevamp.addressverificationrevamp.fragment.KycAddressProofV2Fragment @@ -86,7 +86,6 @@ class AddressVerificationVM(private val repository: KycRepository = KycRepositor val documentViewData: LiveData get() = _documentViewData - fun fetchDocumentUploadData() { coroutineScope.launch { val response = repository.fetchDocumentUploadViewData() @@ -102,7 +101,6 @@ class AddressVerificationVM(private val repository: KycRepository = KycRepositor } } - fun fetchCurrentAddressDetails() { coroutineScope.launch { val response = repository.fetchCurrentAddressDetails() @@ -133,7 +131,6 @@ class AddressVerificationVM(private val repository: KycRepository = KycRepositor } } - fun setUploadTypeAndDocumentUrl(documentType: String, documentUrl: String) { _uploadedDocumentTypeAndUrl.value = Pair(documentType, documentUrl) } @@ -150,56 +147,57 @@ class AddressVerificationVM(private val repository: KycRepository = KycRepositor } fun confirmAddress(currentAddressIndex: Int): Boolean { - val currentAddress = when { - currentAddressIndex == -2 -> { - if (uploadedDocumentTypeAndUrl.value != null) { - CurrentAddress( - status = KycFragment.COMPLETED, - documentType = uploadedDocumentTypeAndUrl.value?.first, - documentUrl = uploadedDocumentTypeAndUrl.value?.second, - city = addressProofLiveData.value?.content?.city, - state = addressProofLiveData.value?.content?.state, - street = addressProofLiveData.value?.content?.street, - locality = addressProofLiveData.value?.content?.locality, - houseNumber = addressProofLiveData.value?.content?.houseNumber, - pinCode = addressProofLiveData.value?.content?.pinCode - ) - } else { + val currentAddress = + when { + currentAddressIndex == -2 -> { + if (uploadedDocumentTypeAndUrl.value != null) { + CurrentAddress( + status = KycFragment.COMPLETED, + documentType = uploadedDocumentTypeAndUrl.value?.first, + documentUrl = uploadedDocumentTypeAndUrl.value?.second, + city = addressProofLiveData.value?.content?.city, + state = addressProofLiveData.value?.content?.state, + street = addressProofLiveData.value?.content?.street, + locality = addressProofLiveData.value?.content?.locality, + houseNumber = addressProofLiveData.value?.content?.houseNumber, + pinCode = addressProofLiveData.value?.content?.pinCode + ) + } else { + null + } + } + currentAddressIndex > -1 -> { + noProofAddressList.value?.addresses?.getOrNull(currentAddressIndex) + ?: kotlin.run { null } + } + else -> { null } } - currentAddressIndex > -1 -> { - noProofAddressList.value?.addresses?.getOrNull(currentAddressIndex) - ?: kotlin.run { - null - } - } - else -> { - null - } - } return currentAddress?.let { submitKycDetails(currentAddress) true - } ?: run { - setErrorData(listOf(getUploadDocumentErrorData())) - false } + ?: run { + setErrorData(listOf(getUploadDocumentErrorData())) + false + } } fun submitKycDetails(currentAddress: CurrentAddress?) { - val address = Address( - houseNumber = currentAddress?.houseNumber, - street = currentAddress?.street, - locality = currentAddress?.locality, - city = currentAddress?.city, - state = currentAddress?.state, - pinCode = currentAddress?.pinCode, - documentType = currentAddress?.documentType, - documentTempUrl = currentAddress?.documentUrl, - type = KycAddressProofV2Fragment.CORRESPONDENCE, - current = true - ) + val address = + Address( + houseNumber = currentAddress?.houseNumber, + street = currentAddress?.street, + locality = currentAddress?.locality, + city = currentAddress?.city, + state = currentAddress?.state, + pinCode = currentAddress?.pinCode, + documentType = currentAddress?.documentType, + documentTempUrl = currentAddress?.documentUrl, + type = KycAddressProofV2Fragment.CORRESPONDENCE, + current = true + ) updateKycDetails(KycRequest(address)) } @@ -209,11 +207,7 @@ class AddressVerificationVM(private val repository: KycRepository = KycRepositor if (response.error == null && response.errors.isNullOrEmpty()) { _addressStatusNextCta.value = response.data } else { - setErrorData( - response.errors, - response.error, - ApiErrorTagType.SUBMIT_KYC_API_ERROR - ) + setErrorData(response.errors, response.error, ApiErrorTagType.SUBMIT_KYC_API_ERROR) } } } @@ -250,11 +244,7 @@ class AddressVerificationVM(private val repository: KycRepository = KycRepositor if (response.error == null && response.errors?.isEmpty().orTrue()) { _kycAddressDetailsSubmitAsyncData.value = response.data } else { - setErrorData( - response.errors, - response.error, - ApiErrorTagType.SUBMIT_KYC_API_ERROR - ) + setErrorData(response.errors, response.error, ApiErrorTagType.SUBMIT_KYC_API_ERROR) } } } @@ -268,10 +258,11 @@ class AddressVerificationVM(private val repository: KycRepository = KycRepositor } } else { _asyncError.value = true - val errorTag = when (type) { - UPDATE_KYC_DETAILS -> ApiErrorTagType.UPDATE_KYC_ASYNC_API_ERROR - else -> null - } + val errorTag = + when (type) { + UPDATE_KYC_DETAILS -> ApiErrorTagType.UPDATE_KYC_ASYNC_API_ERROR + else -> null + } setErrorData(response.errors, response.error, errorTag) } } @@ -300,4 +291,4 @@ class AddressVerificationVM(private val repository: KycRepository = KycRepositor } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/repositories/FindIfscRepository.kt b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/repositories/FindIfscRepository.kt index faee964f23..6c14fabf39 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/repositories/FindIfscRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/repositories/FindIfscRepository.kt @@ -1,21 +1,22 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.getloan.bankdetails.repositories -import com.naviapp.personalloan.getloan.bankdetails.models.BankBranch -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult import com.naviapp.network.retrofit.ResponseCallback +import com.naviapp.personalloan.getloan.bankdetails.models.BankBranch import com.naviapp.utils.retrofitService class FindIfscRepository : ResponseCallback() { - suspend fun getBranches(bankCode: String, branchNameEntered: String): RepoResult> { - return apiResponseCallback( - retrofitService().getBranches(bankCode, branchNameEntered) - ) + suspend fun getBranches( + bankCode: String, + branchNameEntered: String + ): RepoResult> { + return apiResponseCallback(retrofitService().getBranches(bankCode, branchNameEntered)) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/viewmodels/BankDetailsVM.kt b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/viewmodels/BankDetailsVM.kt index 7c85a15774..1835165050 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/viewmodels/BankDetailsVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/bankdetails/viewmodels/BankDetailsVM.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -11,8 +11,8 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.navi.base.sharedpref.PreferenceManager -import com.navi.common.model.GenericErrorResponse import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.viewmodel.BaseVM import com.naviapp.models.RedirectPageStatus import com.naviapp.models.request.BankDetail @@ -156,10 +156,7 @@ class BankDetailsVM(private val repository: BankDetailsRepository = BankDetailsR if (response.error == null) { _loanBasicDetails.value = response.data response.data?.loanApplicationId?.let { - PreferenceManager.setStringPreference( - LOAN_APPLICATION_ID, - it - ) + PreferenceManager.setStringPreference(LOAN_APPLICATION_ID, it) } } else { updateErrorMessage( @@ -172,9 +169,7 @@ class BankDetailsVM(private val repository: BankDetailsRepository = BankDetailsR } fun fetchAsyncRequestWithError(requestId: String) { - coroutineScope.launch { - repository.fetchAsyncRequestWithError(requestId) - } + coroutineScope.launch { repository.fetchAsyncRequestWithError(requestId) } } fun fetchRejectionDetails() { 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 0872f166bf..50a566af51 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 @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -30,7 +30,7 @@ import com.navi.common.firebasedb.FirebaseStatusType.PENDING import com.navi.common.firebasedb.FirebaseStatusType.SUCCESS import com.navi.common.listeners.HeaderInteractionListener import com.navi.common.model.Action -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.ActionWarningFragment import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* @@ -44,7 +44,6 @@ import com.naviapp.dashboard.listeners.FragmentInteractionListener import com.naviapp.databinding.BankDetailsAutoDebitFragmentBinding import com.naviapp.manager.UserManager import com.naviapp.models.FeedbackPageType -import com.naviapp.models.TimerWithLoader import com.naviapp.models.request.AutoPayOptionData import com.naviapp.models.response.* import com.naviapp.network.ApiErrorTagType @@ -64,12 +63,13 @@ import com.naviapp.utils.Constants.MANDATE_TYPE import com.naviapp.utils.Constants.RE_ENACH import com.naviapp.utils.Constants.SUB_REDIRECT - -class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, - FooterInteractionListener, BackListener { +class BankDetailsAutoDebitFragment : + BaseFragment(), View.OnClickListener, FooterInteractionListener, BackListener { private lateinit var binding: BankDetailsAutoDebitFragmentBinding private var listener: FragmentInteractionListener? = null - private val viewModel by lazy { ViewModelProvider(this).get(BankDetailsAutoDebitVM::class.java) } + private val viewModel by lazy { + ViewModelProvider(this).get(BankDetailsAutoDebitVM::class.java) + } private var apiPollScheduler: ApiPollScheduler? = null private var firebaseHelper: FirebaseDataHelper? = null private var firebaseDataReceiveListener: FirebaseDataReceiveListener? = null @@ -83,8 +83,9 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - loanApplicationId = arguments?.getString(Constants.PERSONAL_LOAN_APPLICATION_ID) - ?: PreferenceManager.getStringPreference(LOAN_APPLICATION_ID) + loanApplicationId = + arguments?.getString(Constants.PERSONAL_LOAN_APPLICATION_ID) + ?: PreferenceManager.getStringPreference(LOAN_APPLICATION_ID) } override fun onCreateView( @@ -105,9 +106,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, arguments?.getParcelable(Constants.KEY_CTA)?.let { it.parameters?.let { parameters -> parameters.forEach { item -> - item.key?.let { key -> - ctaQueryMap[key] = "${item.value}" - } + item.key?.let { key -> ctaQueryMap[key] = "${item.value}" } } ctaQueryMap[Constants.KEY_CURRENT_SCREEN] = GetLoanActivity.BANK_DETAILS_AUTO_DEBIT_SCREEN @@ -117,7 +116,8 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, private fun initError() { initError( - viewModel, listOf( + viewModel, + listOf( Pair(handleLoanBasicDetailsError, ApiErrorTagType.FETCH_LOAN_BASIC_DETAILS_ERROR), Pair(handleMandateIdError, ApiErrorTagType.FETCH_MANDATE_ID_ERROR), Pair(handleMandateDataError, ApiErrorTagType.FETCH_MANDATE_DATA_ERROR), @@ -130,36 +130,39 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, ) } - private val handleLoanBasicDetailsError = View.OnClickListener { - showLoader() - viewModel.fetchLoanBasicDetails() - } - - private val handleMandateIdError = View.OnClickListener { - setupAutoDebit() - } - - private val handleMandateDataError = View.OnClickListener { - viewModel.mandateId.value?.requestId?.let { id -> viewModel.fetchMandateData(id) } - ?: setupAutoDebit() - } - - private val handleEnachStatusError = View.OnClickListener { - viewModel.mandateId.value?.requestId?.let { id -> + private val handleLoanBasicDetailsError = + View.OnClickListener { showLoader() - viewModel.fetchEnachStatus(id) - } ?: setupAutoDebit() - } - - private val handleDisbursementDetailsError = View.OnClickListener { - val id = loanApplicationId - if (!id.isNullOrEmpty()) { - showLoader() - viewModel.fetchDisbursementDetails(id, ctaQueryMap) - } else { viewModel.fetchLoanBasicDetails() } - } + + private val handleMandateIdError = View.OnClickListener { setupAutoDebit() } + + private val handleMandateDataError = + View.OnClickListener { + viewModel.mandateId.value?.requestId?.let { id -> viewModel.fetchMandateData(id) } + ?: setupAutoDebit() + } + + private val handleEnachStatusError = + View.OnClickListener { + viewModel.mandateId.value?.requestId?.let { id -> + showLoader() + viewModel.fetchEnachStatus(id) + } + ?: setupAutoDebit() + } + + private val handleDisbursementDetailsError = + View.OnClickListener { + val id = loanApplicationId + if (!id.isNullOrEmpty()) { + showLoader() + viewModel.fetchDisbursementDetails(id, ctaQueryMap) + } else { + viewModel.fetchLoanBasicDetails() + } + } private fun initObservers() { observeActiveLoanApplicationDetails() @@ -193,7 +196,8 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } } - //Backend doesn't know all the messages being sent to app. Fixing the grammatical issue, where message first word is shown in cap after comma. + // Backend doesn't know all the messages being sent to app. Fixing the grammatical issue, where + // message first word is shown in cap after comma. private fun getErrorTitle(it: GenericErrorResponse): String? { if (it.message.isNullOrEmpty()) { return it.title @@ -201,9 +205,10 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, if (it.title.isNullOrEmpty()) { return it.message } - return it.title + ", " + if (isFirstWordInUpperCase(it.message!!)) it.message else makeFirstWordLowerCase( - it.message!! - ) + return it.title + + ", " + + if (isFirstWordInUpperCase(it.message!!)) it.message + else makeFirstWordLowerCase(it.message!!) } private fun observeMandateTimerError() { @@ -213,10 +218,11 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } } - private fun primaryActionForMandateFailure(actions: List?) = View.OnClickListener { - if (actions?.size != 2) return@OnClickListener - Handler().postDelayed({ handleEditAccountClick() }, EDIT_BANK_CONFIRM_DELAY) - } + private fun primaryActionForMandateFailure(actions: List?) = + View.OnClickListener { + if (actions?.size != 2) return@OnClickListener + Handler().postDelayed({ handleEditAccountClick() }, EDIT_BANK_CONFIRM_DELAY) + } private fun observeLoanBasicDetails() { viewModel.loanBasicDetails.observeNonNull(this) { basicDetails -> @@ -239,8 +245,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, it.loanApplicationId, arguments?.getBoolean(Constants.MANDATE_CHANGE).orFalse() ) - } else - viewModel.fetchLoanBasicDetails() + } else viewModel.fetchLoanBasicDetails() } } } @@ -264,11 +269,12 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, ) } EnachStub( - activity, - stubEndpoint, - fetchEnachStatus, - it.details.provider - ).launch() + activity, + stubEndpoint, + fetchEnachStatus, + it.details.provider + ) + .launch() } } else { handleEnachSuccess(it, activity) @@ -277,17 +283,17 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } } FAILURE -> { - it.details?.mandateError?.let { - mandateError-> + it.details?.mandateError?.let { mandateError -> deInitializeAsyncListeners(firebaseHelper, apiPollScheduler) showErrorTimerForMandate(mandateError) - }?: run { - apiPollScheduler?.stopApiPoll() - firebaseHelper?.clear() - hideLoader() - naviAnalyticsEventTracker.onAutoDebitApiFailure() - setAutoDebitState(FAILURE) } + ?: run { + apiPollScheduler?.stopApiPoll() + firebaseHelper?.clear() + hideLoader() + naviAnalyticsEventTracker.onAutoDebitApiFailure() + setAutoDebitState(FAILURE) + } } } } @@ -304,7 +310,6 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, ) } - private fun handleEnachSuccess( data: AdditionalDataAsyncResponse, activity: Activity @@ -317,8 +322,8 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, else -> { EnachHelper().apply { initConfig(activity, data.details?.logo) - ifLet(data.details?.mandateId, UserManager.getPhoneNumber()) - { (documentId, phoneNumber) -> + ifLet(data.details?.mandateId, UserManager.getPhoneNumber()) { + (documentId, phoneNumber) -> eSign( documentId, phoneNumber, @@ -365,9 +370,8 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } } when (disbursementDetailsResponse?.disbursementDetails?.autoDebitStatus) { - AutoPayStatus.AADHAR_PENDING.name, AutoPayStatus.WAITING.name -> binding.footerView.enableNextButton( - false - ) + AutoPayStatus.AADHAR_PENDING.name, + AutoPayStatus.WAITING.name -> binding.footerView.enableNextButton(false) } disbursementDetailsResponse?.disbursementDetails?.lastMandateInformation?.let { if (it.iconCode != null && it.reason != null) { @@ -390,7 +394,8 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, navigateToEnachTutorial(hideFooter = true) } EmiMethodSelectorSkipMandate.EmiMethodSelectorListenerType.PAY_USING_APP.value, - EmiMethodSelectorSkipMandate.EmiMethodSelectorListenerType.SETUP_ENACH_POST_DISBURSEMENT.value -> { + EmiMethodSelectorSkipMandate.EmiMethodSelectorListenerType.SETUP_ENACH_POST_DISBURSEMENT + .value -> { skipMandateSelectedOption = type } } @@ -423,8 +428,9 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } } // sending status details to server - if (loanApplicationId.isNullOrBlank() - .not() && enachSharedVM.enachStatusData.value != null + if ( + loanApplicationId.isNullOrBlank().not() && + enachSharedVM.enachStatusData.value != null ) viewModel.updateEnachStatusDetail( loanApplicationId.orEmpty(), @@ -438,14 +444,13 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, private fun firebaseInit(requestId: String, type: String, notificationPath: String) { firebaseHelper?.clear() - firebaseDataReceiveListener = object : FirebaseDataReceiveListener { - override fun onDataReceive(firebaseResponse: FirebaseResponse?) { - naviAnalyticsEventTracker.logFirebaseData(type, firebaseResponse.toString()) - firebaseResponse?.let { - handleResponse(it.status, type, null, it.details) + firebaseDataReceiveListener = + object : FirebaseDataReceiveListener { + override fun onDataReceive(firebaseResponse: FirebaseResponse?) { + naviAnalyticsEventTracker.logFirebaseData(type, firebaseResponse.toString()) + firebaseResponse?.let { handleResponse(it.status, type, null, it.details) } } } - } firebaseHelper = FirebaseDataHelper() firebaseHelper?.initFirebaseDataReceiver( lifecycle, @@ -483,8 +488,11 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, firebaseHelper?.clear() binding.changeBankTv.visibility = View.GONE val firebaseStatus = Gson().fromJson(details, AutoDebitMandateDetails::class.java) - if (autoDebitMandateDetails?.autoDebitRegistrationStatus == AutoPayStatus.AADHAR_PENDING.name - || firebaseStatus?.autoDebitRegistrationStatus == AutoPayStatus.AADHAR_PENDING.name + if ( + autoDebitMandateDetails?.autoDebitRegistrationStatus == + AutoPayStatus.AADHAR_PENDING.name || + firebaseStatus?.autoDebitRegistrationStatus == + AutoPayStatus.AADHAR_PENDING.name ) { setAutoDebitState(AutoPayStatus.AADHAR_PENDING.name) return @@ -523,25 +531,25 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } private fun gotoGetLoan() { - Handler().postDelayed({ - if (activity?.isFinishing.orTrue()) return@postDelayed - viewModel.disbursementDetails.value?.footer?.nextCta?.url?.let { - listener?.navigateTo( - it, Bundle().apply { - putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) + Handler() + .postDelayed( + { + if (activity?.isFinishing.orTrue()) return@postDelayed + viewModel.disbursementDetails.value?.footer?.nextCta?.url?.let { + listener?.navigateTo( + it, + Bundle().apply { + putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) + } + ) } - ) - } - }, DELAY_AFTER_ENACH_SUCCESS) + }, + DELAY_AFTER_ENACH_SUCCESS + ) } private fun handleTimeOutError(errorTag: String = ApiErrorTagType.MANDATE_CREATION_ERROR) { - showTimeoutErrorScreen( - firebaseHelper, - apiPollScheduler, - { setupAutoDebit() }, - errorTag - ) + showTimeoutErrorScreen(firebaseHelper, apiPollScheduler, { setupAutoDebit() }, errorTag) firebaseHelper = null firebaseDataReceiveListener = null } @@ -549,51 +557,49 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, private fun apiPollInit(requestId: String, type: String) { when (type) { MANDATE -> { - apiPollScheduler = ApiPollScheduler( - numberOfRetry = NUMBER_OF_RETRY_MANDATE_CREATION, - doOnTimeout = { - activity?.runOnUiThread { - handleTimeOutError() - } + apiPollScheduler = + ApiPollScheduler( + numberOfRetry = NUMBER_OF_RETRY_MANDATE_CREATION, + doOnTimeout = { activity?.runOnUiThread { handleTimeOutError() } } + ) { + viewModel.fetchMandateData(requestId) } - ) { - viewModel.fetchMandateData(requestId) - } apiPollScheduler?.scheduleApiPoll() } MANDATE_FAILURE -> { - apiPollScheduler = ApiPollScheduler(initialDelay = 0L, - numberOfRetry = NUMBER_OF_RETRY_MANDATE_FAILURE_STATUS, - doOnTimeout = { - activity?.runOnUiThread { - hideLoader() - if (isAdded) { - binding.errorMessageView.setProperties( - context?.getString(R.string.auto_pay_setup_failed), - IconUtils.RED_ICON_WARNING, - R.style.RedBoldExtraSmall - ) + apiPollScheduler = + ApiPollScheduler( + initialDelay = 0L, + numberOfRetry = NUMBER_OF_RETRY_MANDATE_FAILURE_STATUS, + doOnTimeout = { + activity?.runOnUiThread { + hideLoader() + if (isAdded) { + binding.errorMessageView.setProperties( + context?.getString(R.string.auto_pay_setup_failed), + IconUtils.RED_ICON_WARNING, + R.style.RedBoldExtraSmall + ) + } } } - }) { - viewModel.fetchMandateData(requestId) - } + ) { + viewModel.fetchMandateData(requestId) + } apiPollScheduler?.scheduleApiPoll() } else -> { - apiPollScheduler = ApiPollScheduler( - numberOfRetry = NUMBER_OF_RETRY_MANDATE_STATUS, - doOnTimeout = { - activity?.runOnUiThread { - handleResponse( - AutoPayStatus.WAITING.name, - MANDATE_COMPLETE - ) + apiPollScheduler = + ApiPollScheduler( + numberOfRetry = NUMBER_OF_RETRY_MANDATE_STATUS, + doOnTimeout = { + activity?.runOnUiThread { + handleResponse(AutoPayStatus.WAITING.name, MANDATE_COMPLETE) + } } + ) { + viewModel.fetchEnachStatus(requestId) } - ) { - viewModel.fetchEnachStatus(requestId) - } apiPollScheduler?.scheduleApiPoll() } } @@ -612,15 +618,15 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, when (autoDebitStatus) { SUCCESS -> naviAnalyticsEventTracker.onAutoDebitSuccessScreen() FAILURE -> naviAnalyticsEventTracker.onAutoDebitFailureScreen() - AutoPayStatus.AADHAR_PENDING.name -> naviAnalyticsEventTracker.onAutoDebitAadharMandatePending() + AutoPayStatus.AADHAR_PENDING.name -> + naviAnalyticsEventTracker.onAutoDebitAadharMandatePending() } viewModel.setAutoDebitState(autoDebitStatus) binding.viewModel = viewModel when (autoDebitStatus) { SUCCESS -> binding.footerView.visibility = View.GONE - AutoPayStatus.AADHAR_PENDING.name, AutoPayStatus.WAITING.name -> binding.footerView.enableNextButton( - false - ) + AutoPayStatus.AADHAR_PENDING.name, + AutoPayStatus.WAITING.name -> binding.footerView.enableNextButton(false) else -> binding.footerView.visibility = View.VISIBLE } } @@ -635,8 +641,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, viewModel.fetchActiveLoanApplicationForReEnach( arguments?.getString(Constants.LOAN_ACCOUNT_NUMBER).orEmpty() ) - } else - viewModel.fetchLoanBasicDetails() + } else viewModel.fetchLoanBasicDetails() } private fun initListeners() { @@ -644,16 +649,24 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, binding.changeBankTv.setOnClickListener(this) } - private fun setupAutoDebit(autoPayTypeId: String? = binding.selectManadateView.mandateOptionsRv.selectedLabelLiveData.value?.id) { + private fun setupAutoDebit( + autoPayTypeId: String? = + binding.selectManadateView.mandateOptionsRv.selectedLabelLiveData.value?.id + ) { if (!isAdded && activity?.isFinishing.orTrue()) return naviAnalyticsEventTracker.onSetupAutoDebitClicked(autoPayTypeId) val id = loanApplicationId if (!id.isNullOrEmpty()) { showLoader() viewModel.fetchMandateRequestId( - id, loanType, AutoPayOptionData( + id, + loanType, + AutoPayOptionData( autoPayOptionId = autoPayTypeId, - viewModel.disbursementDetails.value?.disbursementDetails?.bankDetails?.referenceId + viewModel.disbursementDetails.value + ?.disbursementDetails + ?.bankDetails + ?.referenceId ) ) } @@ -688,13 +701,12 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, private fun handleEditAccountClick() { naviAnalyticsEventTracker.onEditAccountTap() naviAnalyticsEventTracker.onEnachChangeBankClick() - val primaryAction = View.OnClickListener { - naviAnalyticsEventTracker.onConfirmButtonTap() - navigateToBankDetailsScreen() - } - val secondaryAction = View.OnClickListener { - naviAnalyticsEventTracker.onCancelButtonTap() - } + val primaryAction = + View.OnClickListener { + naviAnalyticsEventTracker.onConfirmButtonTap() + navigateToBankDetailsScreen() + } + val secondaryAction = View.OnClickListener { naviAnalyticsEventTracker.onCancelButtonTap() } try { val ft = childFragmentManager.beginTransaction() val prev = childFragmentManager.findFragmentByTag(ActionWarningFragment.TAG) @@ -720,14 +732,15 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } private fun navigateToBankDetailsScreen() { - listener?.navigateTo(GetLoanActivity.BANK_DETAILS_SCREEN, Bundle().apply { - putBoolean(EDIT_ACCOUNT, true) - putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) - putString(SUB_REDIRECT, arguments?.getString(SUB_REDIRECT)) - viewModel.disbursementDetails.value?.let { - putParcelable(DISBURSEMENT_DETAILS, it) + listener?.navigateTo( + GetLoanActivity.BANK_DETAILS_SCREEN, + Bundle().apply { + putBoolean(EDIT_ACCOUNT, true) + putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) + putString(SUB_REDIRECT, arguments?.getString(SUB_REDIRECT)) + viewModel.disbursementDetails.value?.let { putParcelable(DISBURSEMENT_DETAILS, it) } } - }) + ) } override fun onAttach(context: Context) { @@ -761,14 +774,8 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, naviAnalyticsEventTracker.onEnachBackBottomClick() val bundle = Bundle() bundle.putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) - ctaData?.parameters?.forEach { keyValue -> - bundle.putString(keyValue.key, keyValue.value) - } - ctaData?.url?.let { - listener?.navigateTo( - it, bundle - ) - } + ctaData?.parameters?.forEach { keyValue -> bundle.putString(keyValue.key, keyValue.value) } + ctaData?.url?.let { listener?.navigateTo(it, bundle) } } private fun observeSkipMandateSavingData() { @@ -777,24 +784,25 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, hideLoader() if (status == true) { listener?.navigateTo( - it, Bundle().apply { + it, + Bundle().apply { putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) } ) } else { viewModel.setError( - errors = listOf( - GenericErrorResponse( - title = resources.getString(R.string.something_went_wrong), - message = null, - actions = listOf(Action(title = resources.getString(R.string.retry))), - assetDetails = null, - + errors = + listOf( + GenericErrorResponse( + title = resources.getString(R.string.something_went_wrong), + message = null, + actions = + listOf(Action(title = resources.getString(R.string.retry))), + assetDetails = null, ) - ) + ) ) } - } } } @@ -806,24 +814,29 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, } showLoader() viewModel.saveSkipMandateOption( - RepaymentMethodData( - loanApplicationId, - skipMandateSelectedOption - ) + RepaymentMethodData(loanApplicationId, skipMandateSelectedOption) ) } override fun onFooterNextPress(ctaData: CtaData?, skipValidation: Boolean?) { NaviTrackEvent.setStartTs(screenName) - naviAnalyticsEventTracker.onEnachSetupAutoDebitClick(binding.selectManadateView.mandateOptionsRv.selectedLabelLiveData.value?.id) - if (viewModel.disbursementDetails.value?.disbursementDetails?.skipMandateSectionData.isNotNull()) { + naviAnalyticsEventTracker.onEnachSetupAutoDebitClick( + binding.selectManadateView.mandateOptionsRv.selectedLabelLiveData.value?.id + ) + if ( + viewModel.disbursementDetails.value + ?.disbursementDetails + ?.skipMandateSectionData + .isNotNull() + ) { saveSkipMandateOption() return } if (viewModel.isAutoPaySuccess()) { ctaData?.url?.let { listener?.navigateTo( - it, Bundle().apply { + it, + Bundle().apply { putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) } ) @@ -848,9 +861,7 @@ class BankDetailsAutoDebitFragment : BaseFragment(), View.OnClickListener, private const val NUMBER_OF_RETRY_MANDATE_FAILURE_STATUS = 3 fun newInstance(bundle: Bundle?): BankDetailsAutoDebitFragment { - return BankDetailsAutoDebitFragment().apply { - arguments = bundle - } + return BankDetailsAutoDebitFragment().apply { arguments = bundle } } } } 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 6cc99ef945..758e6984c5 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 @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -10,15 +10,15 @@ package com.naviapp.personalloan.getloan.bankdetailsautodebit.viewmodels import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.utils.orZero import com.navi.common.viewmodel.BaseVM import com.naviapp.models.ActiveLoanApplicationDetails import com.naviapp.models.EnachData import com.naviapp.models.request.AutoPayOptionData import com.naviapp.models.response.* -import com.naviapp.network.ApiErrorTagType -import com.navi.common.model.GenericErrorResponse -import com.navi.common.utils.orZero import com.naviapp.network.ApiConstants +import com.naviapp.network.ApiErrorTagType import com.naviapp.personalloan.getloan.bankdetailsautodebit.repositories.BankDetailsAutoDebitRepository import com.naviapp.personalloanrevamp.models.response.EnachV2Response import com.naviapp.utils.Constants.RE_ENACH @@ -77,10 +77,8 @@ class BankDetailsAutoDebitVM : BaseVM() { val saveSkipMandateOption: LiveData get() = _saveSkipMandateOption - private var subRedirect: String? = null - fun updateSubRedirect(subRedirect: String) { this.subRedirect = subRedirect } @@ -163,12 +161,13 @@ class BankDetailsAutoDebitVM : BaseVM() { response.data?.details?.mandateError?.let { _mandateTimerError.value = it return@launch - } ?: run { - if (!response.errors.isNullOrEmpty()) { - _mandateFailure.value = response.errors?.firstOrNull() - return@launch - } } + ?: run { + if (!response.errors.isNullOrEmpty()) { + _mandateFailure.value = response.errors?.firstOrNull() + return@launch + } + } updateErrorMessage(response.error, ApiErrorTagType.FETCH_MANDATE_DATA_ERROR, false) } } @@ -202,9 +201,7 @@ class BankDetailsAutoDebitVM : BaseVM() { fun updateEnachStatusDetail(loanApplicationId: String, data: EnachData?) { if (data == null) return - coroutineScope.launch { - repository.postEmandateStatus(loanApplicationId, data) - } + coroutineScope.launch { repository.postEmandateStatus(loanApplicationId, data) } } fun fetchEnachDetails(loanApplicationId: String) { @@ -213,10 +210,7 @@ class BankDetailsAutoDebitVM : BaseVM() { if (response.error == null) { _enachDetails.value = response.data } else { - setErrorData( - response.errors, - response.error - ) + setErrorData(response.errors, response.error) } } } @@ -227,10 +221,7 @@ class BankDetailsAutoDebitVM : BaseVM() { if (response.error == null) { _enachV2Details.value = response.data } else { - setErrorData( - response.errors, - response.error - ) + setErrorData(response.errors, response.error) } } } @@ -240,34 +231,44 @@ class BankDetailsAutoDebitVM : BaseVM() { } fun isAutoPaySuccess(): Boolean { - return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.SUCCESS.name + return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.SUCCESS.name } fun isAutoPayAadharPending(): Boolean { - return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.AADHAR_PENDING.name + return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.AADHAR_PENDING.name } fun isAutoPayWaiting(): Boolean { - return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.WAITING.name + return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.WAITING.name } fun isAutoPayPendingOrFailure(): Boolean { - return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.PENDING.name || - _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.FAILURE.name + return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.PENDING.name || + _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.FAILURE.name } fun isAutoPayPendingOrFailureandLastMandateInformationisPresent(): Boolean { - return ((_disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.PENDING.name - || _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.FAILURE.name) - && (_disbursementDetails.value?.disbursementDetails?.lastMandateInformation?.reason != null)) + return ((_disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.PENDING.name || + _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.FAILURE.name) && + (_disbursementDetails.value?.disbursementDetails?.lastMandateInformation?.reason != + null)) } fun isAutoPayFailure(): Boolean { - return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.FAILURE.name + return _disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.FAILURE.name } fun isShowNote(): Boolean { - return (_disbursementDetails.value?.disbursementDetails?.autoDebitStatus == AutoPayStatus.PENDING.name) && (this.subRedirect != RE_ENACH) + return (_disbursementDetails.value?.disbursementDetails?.autoDebitStatus == + AutoPayStatus.PENDING.name) && (this.subRedirect != RE_ENACH) } fun getBankName(): String? { @@ -279,12 +280,15 @@ class BankDetailsAutoDebitVM : BaseVM() { } fun canChangeBank(): Boolean { - return (_disbursementDetails.value?.disbursementDetails?.editBankRetriesLeft.orZero() <= 0 || - _disbursementDetails.value?.disbursementDetails?.autoDebitStatus in arrayListOf( - AutoPayStatus.SUCCESS.name, - AutoPayStatus.WAITING.name, - AutoPayStatus.AADHAR_PENDING.name - )).not() + return (_disbursementDetails.value?.disbursementDetails?.editBankRetriesLeft.orZero() <= + 0 || + _disbursementDetails.value?.disbursementDetails?.autoDebitStatus in + arrayListOf( + AutoPayStatus.SUCCESS.name, + AutoPayStatus.WAITING.name, + AutoPayStatus.AADHAR_PENDING.name + )) + .not() } fun getAutoPayFooterData(): Footer? { @@ -310,4 +314,4 @@ class BankDetailsAutoDebitVM : BaseVM() { fun getNoteData(): String? { return _disbursementDetails.value?.disbursementDetails?.note?.title } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/common/fragment/CustomerSupportFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/common/fragment/CustomerSupportFragment.kt index 3f3657ac63..f08c940d1e 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/common/fragment/CustomerSupportFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/common/fragment/CustomerSupportFragment.kt @@ -88,8 +88,8 @@ class CustomerSupportFragment : BaseBottomSheet(), View.OnClickListener { isRootActivity = false ) } - viewModel.customerSupportOptionsResponse.observeNonNull(this) { - customerSupportOptionResponse -> + + viewModel.customerSupportOptionsResponse.observeNonNull(this) { customerSupportOptionResponse -> hideLoader() customerSupportOptionResponse.listOfOptions?.let { listOfOptions -> for (customerSupportOption in listOfOptions) { @@ -185,14 +185,14 @@ class CustomerSupportFragment : BaseBottomSheet(), View.OnClickListener { source = touchPointName.orEmpty(), sourceId = DEFAULT_SOURCE_ID_FOR_PL, currentUserName = - PreferenceManager.getObjectPrefrences( - Constants.CURRENT_USER, - UserDetail::class.java - ) - ?.name - .orEmpty(), + PreferenceManager.getObjectPrefrences( + Constants.CURRENT_USER, + UserDetail::class.java + ) + ?.name + .orEmpty(), externalCustomerId = - PreferenceManager.getStringPreference(USER_EXTERNAL_ID).orEmpty() + PreferenceManager.getStringPreference(USER_EXTERNAL_ID).orEmpty() ) NaviTrackEvent.trackEventOnClickStream( CHAT_TOUCH_POINT_CLICKED, @@ -255,7 +255,18 @@ class CustomerSupportFragment : BaseBottomSheet(), View.OnClickListener { NaviAnalytics.SELFIE_V2 -> loanDetailsFaqs(requireContext()) NaviAnalytics.PL_GETLOAN_PAGE_LANDS_V2 -> loanDetailsFaqs(requireContext()) NaviAnalytics.VIDEO_KYC_V2 -> loanDetailsFaqs(requireContext()) - NaviAnalytics.DELAYED_DISBURSEMENT_DETAILS_V2_SCREEN -> loanDetailsFaqs(requireContext()) + NaviAnalytics.DELAYED_DISBURSEMENT_DETAILS_V2_SCREEN -> loanDetailsFaqs( + requireContext() + ) + NaviAnalytics.MFI_REJECTED_FRAGMENT_V2 -> loanDetailsFaqs(requireContext()) + NaviAnalytics.COMMON_REJECTED_FRAGMENT_V2 -> loanDetailsFaqs(requireContext()) + NaviAnalytics.PROFILE -> loanDetailsFaqs(requireContext()) + NaviAnalytics.MFI_INFO_SCREEN_V2 -> loanDetailsFaqs(requireContext()) + NaviAnalytics.EPFO -> loanDetailsFaqs(requireContext()) + NaviAnalytics.EFFECTIVE_INTEREST_COST_SCREEN_V2 -> loanDetailsFaqs(requireContext()) + NaviAnalytics.PERSONAL_LOAN_KYC_IN_PROGRESS_V2 -> loanDetailsFaqs(requireContext()) + NaviAnalytics.KYC_ADDRESS_V2 -> loanDetailsFaqs(requireContext()) + NaviAnalytics.KYC_ADDRESS_PROOF_V2 -> loanDetailsFaqs(requireContext()) else -> null } faqsData?.let { @@ -298,6 +309,9 @@ class CustomerSupportFragment : BaseBottomSheet(), View.OnClickListener { NaviAnalytics.PART_PRE_PAYMENT_CUSTOM_AMOUNT_SCREEN, NaviAnalytics.PART_PRE_PAYMENT_TYPE_SCREEN, NaviAnalytics.PART_PRE_PAYMENT_EMI_CALENDAR_SCREEN, + NaviAnalytics.LOAN_REPAYMENT_TYPE_SCREEN, + NaviAnalytics.CUSTOM_PAYMENT_TYPE_SCREEN, + NaviAnalytics.CUSTOM_AMOUNT_CALENDAR_REVIEW_SCREEN, NaviAnalytics.REWARD_INFO_SCREEN, NaviAnalytics.REWARD_SUMMARY_SCREEN, NaviAnalytics.TRACKER_SCREEN, @@ -315,7 +329,17 @@ class CustomerSupportFragment : BaseBottomSheet(), View.OnClickListener { NaviAnalytics.PL_GETLOAN_PAGE_LANDS_V2, NaviAnalytics.VIDEO_KYC_V2, VKYC_WAITING_FOR_EXECUTIVE_SCREEN, - NaviAnalytics.DELAYED_DISBURSEMENT_DETAILS_V2_SCREEN -> true + NaviAnalytics.DELAYED_DISBURSEMENT_DETAILS_V2_SCREEN, + NaviAnalytics.MFI_REJECTED_FRAGMENT_V2, + NaviAnalytics.COMMON_REJECTED_FRAGMENT_V2, + NaviAnalytics.WORK_DETAIL_V2, + NaviAnalytics.MFI_INFO_SCREEN_V2, + NaviAnalytics.EPFO, + NaviAnalytics.TELCO_OTP_SCREEN_V2, + NaviAnalytics.EFFECTIVE_INTEREST_COST_SCREEN_V2, + NaviAnalytics.PERSONAL_LOAN_KYC_IN_PROGRESS_V2, + NaviAnalytics.KYC_ADDRESS_V2, + NaviAnalytics.KYC_ADDRESS_PROOF_V2 -> true else -> false } } @@ -346,3 +370,4 @@ class CustomerSupportFragment : BaseBottomSheet(), View.OnClickListener { } } } + diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/emi/fragments/EMIUpdatedCalendarFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/emi/fragments/EMIUpdatedCalendarFragment.kt index bcc27d8e64..6eaff30d11 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/emi/fragments/EMIUpdatedCalendarFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/emi/fragments/EMIUpdatedCalendarFragment.kt @@ -14,7 +14,9 @@ import android.view.View import android.view.ViewGroup import androidx.lifecycle.ViewModelProvider import com.navi.analytics.utils.NaviTrackEvent +import com.navi.base.model.AnalyticsEvent import com.navi.base.model.CtaData +import com.navi.base.model.CtaType import com.navi.common.decorator.TopMarginItemDecoration import com.navi.common.listeners.HeaderInteractionListener import com.navi.common.model.StyledTextWithIconCode @@ -22,6 +24,8 @@ import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.observeNonNull import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.analytics.utils.NaviAnalytics.Companion.COLENDING_BALANCE_TRANSFER_EVENT +import com.naviapp.analytics.utils.NaviAnalytics.Companion.ELIGIBLE_FOR_BALANCE_TRANSFER import com.naviapp.common.listeners.FooterInteractionListener import com.naviapp.common.navigator.NaviDeepLinkNavigator import com.naviapp.databinding.EmiUpdatedCalendarFragmentBinding @@ -33,6 +37,8 @@ import com.naviapp.personalloan.getloan.emi.adapters.EMIUpdatedCalendarAdapter import com.naviapp.personalloan.getloan.emi.viewmodels.EMIUpdatedCalendarFragmentVM import com.naviapp.utils.Constants.LOAN_ACCOUNT_NUMBER_DATA import com.naviapp.utils.Constants.LOAN_TYPE +import com.naviapp.utils.NaviDownloadManager +import java.lang.ref.WeakReference class EMIUpdatedCalendarFragment : BaseFragment(), View.OnClickListener, FooterInteractionListener { @@ -44,6 +50,8 @@ class EMIUpdatedCalendarFragment : BaseFragment(), View.OnClickListener, FooterI private var emiAmountStatusText: String? = null private lateinit var emiAmountStatus: String private lateinit var amount: String + private var isColendingBalanceTransferEligible = false + private var naviDownloadManager: NaviDownloadManager? = null private val viewModel by lazy { ViewModelProvider(this).get(EMIUpdatedCalendarFragmentVM::class.java) @@ -130,6 +138,13 @@ class EMIUpdatedCalendarFragment : BaseFragment(), View.OnClickListener, FooterI emiUpdatedCalendarResponse.content?.updatedCalendar, emiUpdatedCalendarResponse.content?.calendarVisibilityConfig ) + var coLendingBalanceTransferEvent = + emiUpdatedCalendarResponse.metadata?.get(COLENDING_BALANCE_TRANSFER_EVENT)?.data + as? AnalyticsEvent + if (coLendingBalanceTransferEvent != null) { + NaviAnalytics.naviAnalytics.sendAnalyticsEvent(coLendingBalanceTransferEvent) + isColendingBalanceTransferEligible = true + } } viewModel.emiDateChangeDetails.observe(viewLifecycleOwner) { ctaData -> @@ -208,6 +223,9 @@ class EMIUpdatedCalendarFragment : BaseFragment(), View.OnClickListener, FooterI nextButtonIconId = null ) headerInteractionListener?.setProperties(emiUpdatedCalendarResponse.header?.title) + emiUpdatedCalendarResponse.footer?.message?.let { + binding.footerView.setMessage(emiUpdatedCalendarResponse.footer?.message, this) + } } private fun initEmiCalendarAdapter(emiDateList: List?) { @@ -276,5 +294,30 @@ class EMIUpdatedCalendarFragment : BaseFragment(), View.OnClickListener, FooterI ), ctaData ) + ctaData?.analyticsEventProperties?.let { + NaviTrackEvent.trackEventOnClickStream( + it.name.toString(), + mapOf( + Pair( + ELIGIBLE_FOR_BALANCE_TRANSFER, + isColendingBalanceTransferEligible.toString() + ) + ) + ) + } + } + + override fun onFooterTextPress(ctaData: CtaData?) { + if (ctaData?.url == CtaType.DOWNLOAD.name) { + if (naviDownloadManager == null) { + naviDownloadManager = NaviDownloadManager(WeakReference(activity)) + } + naviDownloadManager?.start( + TAG, + ctaData.title.toString(), + ctaData.parameters?.getOrNull(0)?.value.toString(), + "" + ) + } } } diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/emi/repository/EMIDateChangeRepository.kt b/app/src/main/java/com/naviapp/personalloan/getloan/emi/repository/EMIDateChangeRepository.kt index 4af953d376..6eba1f7ab1 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/emi/repository/EMIDateChangeRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/emi/repository/EMIDateChangeRepository.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022 by Navi Technologies Private Limited + * * Copyright © 2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -16,13 +16,14 @@ class EMIDateChangeRepository : ResponseCallback() { suspend fun fetchEMIDateChangeResponse(loanApplicationId: String) = apiResponseCallback(retrofitService().fetchEMIDateChangeResponse(loanApplicationId)) - suspend fun fetchEMIUpdatedCalendarResponse(loanApplicationId: String,date: String) = - apiResponseCallback(retrofitService().fetchEMIUpdatedCalendarResponse(loanApplicationId,date)) + suspend fun fetchEMIUpdatedCalendarResponse(loanApplicationId: String, date: String) = + apiResponseCallback( + retrofitService().fetchEMIUpdatedCalendarResponse(loanApplicationId, date) + ) suspend fun postEmiDateChangeDetails(emiDateChangeDetails: EmiDateChangeDetails) = apiResponseCallback(retrofitService().fetchEMiDateChangeStatus(emiDateChangeDetails)) suspend fun fetchLoanBasicDetails() = apiResponseCallback(retrofitService().fetchLoanBasicDetails()) - -} \ No newline at end of file +} 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 9df809cf39..f7747a780f 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 @@ -39,8 +39,8 @@ import com.navi.common.listeners.LocationUpdateListener import com.navi.common.managers.PermissionsManager import com.navi.common.managers.PermissionsManager.Companion.CAMERA_PERMISSION import com.navi.common.managers.PermissionsManager.Companion.STORAGE_PERMISSION -import com.navi.common.model.GenericErrorResponse import com.navi.common.model.UpdateAppDetails +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* import com.naviapp.BuildConfig @@ -77,19 +77,22 @@ import com.naviapp.personalloan.getloan.kyc.adapter.KycItemsAdapter import com.naviapp.personalloan.getloan.kyc.listeners.AadhaarVerificationListener import com.naviapp.personalloan.getloan.kyc.listeners.KycItemsListener import com.naviapp.personalloan.getloan.kyc.listeners.SelfieCaptureListener -import com.naviapp.personalloan.getloan.kyc.models.* +import com.naviapp.personalloan.getloan.kyc.models.AadhaarDetails +import com.naviapp.personalloan.getloan.kyc.models.AadhaarVerificationData +import com.naviapp.personalloan.getloan.kyc.models.SupportedOvd import com.naviapp.personalloan.getloan.kyc.utils.DocumentType.AADHAAR_CARD import com.naviapp.personalloan.getloan.kyc.utils.DocumentType.PAN_CARD 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 import com.naviapp.utils.Constants.AADHAAR_OTP_VERIFICATION_UNSUCCESSFUL import com.naviapp.utils.Constants.PL_KYC_LOCATION import com.naviapp.utils.Constants.SELFIE_UPLOAD_UNSUCCESSFUL import com.naviapp.utils.Constants.VIDEO_KYC_STATUS_DELAY import com.naviapp.utils.EMPTY +import com.naviapp.utils.PROD import com.naviapp.utils.isDead +import com.naviapp.utils.toast import java.io.ByteArrayOutputStream import java.io.File import java.io.FileInputStream diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/PhysicalKycFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/PhysicalKycFragment.kt index b44cf0b4e6..d6ce2e8c5f 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/PhysicalKycFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/PhysicalKycFragment.kt @@ -29,7 +29,7 @@ import com.navi.common.decorator.TopMarginItemDecoration import com.navi.common.firebasedb.* import com.navi.common.listeners.HeaderInteractionListener import com.navi.common.managers.PermissionsManager -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* import com.naviapp.BuildConfig @@ -61,10 +61,12 @@ import com.naviapp.personalloan.getloan.kyc.models.SupportedOvd import com.naviapp.personalloan.getloan.kyc.utils.DocumentType import com.naviapp.personalloan.getloan.kyc.viewmodels.KycSharedVM import com.naviapp.personalloan.getloan.kyc.viewmodels.PhysicalKycVM -import com.naviapp.utils.* import com.naviapp.utils.Constants import com.naviapp.utils.EMPTY +import com.naviapp.utils.IconUtils +import com.naviapp.utils.PROD import com.naviapp.utils.isDead +import com.naviapp.utils.toast import java.io.ByteArrayOutputStream import java.io.File import java.io.FileInputStream diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/VideoKycFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/VideoKycFragment.kt index 37ae809dff..b4c9499004 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/VideoKycFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/fragments/VideoKycFragment.kt @@ -38,7 +38,7 @@ import com.navi.common.listeners.HeaderInteractionListener import com.navi.common.managers.PermissionsManager import com.navi.common.managers.PermissionsManager.Companion.CAMERA_PERMISSION import com.navi.common.managers.PermissionsManager.Companion.STORAGE_PERMISSION -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* import com.naviapp.R @@ -64,11 +64,12 @@ import com.naviapp.personalloan.getloan.kyc.models.SupportedOvd import com.naviapp.personalloan.getloan.kyc.utils.DocumentType import com.naviapp.personalloan.getloan.kyc.viewmodels.KycSharedVM import com.naviapp.personalloan.getloan.kyc.viewmodels.VideoKycVM -import com.naviapp.utils.* import com.naviapp.utils.Constants import com.naviapp.utils.Constants.MILLISECONDS_PER_SECOND import com.naviapp.utils.Constants.VIDEO_KYC_STATUS_DELAY import com.naviapp.utils.EMPTY +import com.naviapp.utils.IconUtils +import com.naviapp.utils.toast import java.io.ByteArrayOutputStream import java.io.File import kotlinx.coroutines.* diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/repositories/BaseKycRepository.kt b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/repositories/BaseKycRepository.kt index 8cf8dd6097..124fa2c7ae 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/repositories/BaseKycRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/repositories/BaseKycRepository.kt @@ -1,34 +1,31 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.getloan.kyc.repositories -import com.naviapp.models.request.SelfieSetting import com.navi.common.model.UploadDataAsyncResponse -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult +import com.naviapp.models.request.SelfieSetting import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService +import javax.inject.Inject import okhttp3.MultipartBody import okhttp3.RequestBody import retrofit2.http.Part -import javax.inject.Inject -open class BaseKycRepository @Inject constructor(): ResponseCallback() { +open class BaseKycRepository @Inject constructor() : ResponseCallback() { suspend fun fetchAsyncRequestData(requestId: String): RepoResult = apiResponseCallback(retrofitService().fetchAsyncRequestWithError(requestId)) suspend fun fetchSelfieSettingRequestData(): RepoResult = apiResponseCallback(retrofitService().fetchSelfieSettings()) - suspend fun submitSelfie( - @Part type: RequestBody? = null, - @Part file: MultipartBody.Part - ) = apiResponseCallback(retrofitService().submitSelfie(type, file)) + suspend fun submitSelfie(@Part type: RequestBody? = null, @Part file: MultipartBody.Part) = + apiResponseCallback(retrofitService().submitSelfie(type, file)) - suspend fun fetchKycStatus() = - apiResponseCallback(retrofitService().fetchKycStatus()) -} \ No newline at end of file + suspend fun fetchKycStatus() = apiResponseCallback(retrofitService().fetchKycStatus()) +} diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/repositories/KycRepository.kt b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/repositories/KycRepository.kt index 4066af9d3e..607f43cde7 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/repositories/KycRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/repositories/KycRepository.kt @@ -1,25 +1,25 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.getloan.kyc.repositories +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.RepoResult import com.naviapp.models.request.KycRequest import com.naviapp.models.request.SaveCorrespondenceAddressRequest -import com.navi.common.model.UploadDataAsyncResponse -import com.navi.common.model.RepoResult import com.naviapp.personalloan.getloan.kyc.models.AadhaarVerificationData import com.naviapp.utils.retrofitService +import javax.inject.Inject import okhttp3.MultipartBody import okhttp3.RequestBody import retrofit2.http.Body import retrofit2.http.Part -import javax.inject.Inject -class KycRepository @Inject constructor(): BaseKycRepository() { +class KycRepository @Inject constructor() : BaseKycRepository() { suspend fun submitKYCDocument(@Part type: RequestBody, @Part file: MultipartBody.Part) = apiResponseCallback(retrofitService().submitKYCDocument(type, file)) @@ -32,14 +32,12 @@ class KycRepository @Inject constructor(): BaseKycRepository() { suspend fun requestAadhaarDetails() = apiResponseCallback(retrofitService().requestAadhaarDetails()) - suspend fun fetchKycDetails() = - apiResponseCallback(retrofitService().fetchKycDetails()) + suspend fun fetchKycDetails() = apiResponseCallback(retrofitService().fetchKycDetails()) -// suspend fun fetchKycDetailsV2() = -// apiResponseCallback(retrofitService().fetchKycDetailsV2()) + // suspend fun fetchKycDetailsV2() = + // apiResponseCallback(retrofitService().fetchKycDetailsV2()) - suspend fun fetchKycDetailsV2() = - apiResponseCallback(retrofitService().fetchKycDetailsV2()) + suspend fun fetchKycDetailsV2() = apiResponseCallback(retrofitService().fetchKycDetailsV2()) suspend fun fetchCurrentAddressDetails() = apiResponseCallback(retrofitService().fetchCurrentAddressDetails()) @@ -56,8 +54,7 @@ class KycRepository @Inject constructor(): BaseKycRepository() { suspend fun fetchNoProofAddressList() = apiResponseCallback(retrofitService().fetchNoProofAddressList()) - suspend fun checkUiStatus() = - apiResponseCallback(retrofitService().getRedirectPageStatus()) + suspend fun checkUiStatus() = apiResponseCallback(retrofitService().getRedirectPageStatus()) suspend fun postAadhaarVerificationData(data: AadhaarVerificationData) = apiResponseCallback(retrofitService().postAadharVerificationData(data)) @@ -78,8 +75,8 @@ class KycRepository @Inject constructor(): BaseKycRepository() { suspend fun fetchCityAndState(pinCode: String) = apiResponseCallback(retrofitService().fetchCityAndState(pinCode)) - suspend fun fetchVideoKycStatus() = - apiResponseCallback(retrofitService().fetchVideoKycStatus()) + suspend fun fetchVideoKycStatus() = apiResponseCallback(retrofitService().fetchVideoKycStatus()) - suspend fun fetchDocumentUploadViewData() = apiResponseCallback(retrofitService().fetchDocumentUploadViewData()) + suspend fun fetchDocumentUploadViewData() = + apiResponseCallback(retrofitService().fetchDocumentUploadViewData()) } 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 8d3c9d3318..b6e6347aea 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 @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -14,10 +14,14 @@ import androidx.lifecycle.MutableLiveData import com.navi.common.extensions.isNull import com.navi.common.firebasedb.* import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.ErrorMessage +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.utils.orFalse +import com.navi.common.utils.orTrue +import com.navi.common.viewmodel.BaseVM import com.naviapp.BuildConfig import com.naviapp.R import com.naviapp.app.NaviApplication -import com.navi.common.viewmodel.BaseVM import com.naviapp.models.RedirectPageStatus import com.naviapp.models.request.KycRequest import com.naviapp.models.request.SelfieSetting @@ -25,10 +29,6 @@ import com.naviapp.models.request.SelfieUploadRequestData import com.naviapp.models.response.* import com.naviapp.network.ApiConstants import com.naviapp.network.ApiErrorTagType -import com.navi.common.model.GenericErrorResponse -import com.navi.common.network.models.ErrorMessage -import com.navi.common.utils.orFalse -import com.navi.common.utils.orTrue import com.naviapp.payment.models.ProviderType import com.naviapp.personalloan.getloan.common.view.KycPanView import com.naviapp.personalloan.getloan.common.view.StatusIndicatorView @@ -173,18 +173,10 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() } val multipartBody = getMultipartBody(bytes, FILE_NAME) coroutineScope.launch { - val response = repository.submitSelfie( - requestBody, - multipartBody - ) - if (response.error == null) - _selfieUploadAsyncData.value = response.data + val response = repository.submitSelfie(requestBody, multipartBody) + if (response.error == null) _selfieUploadAsyncData.value = response.data else { - setErrorData( - response.errors, - response.error, - ApiErrorTagType.SELFIE_UPLOAD - ) + setErrorData(response.errors, response.error, ApiErrorTagType.SELFIE_UPLOAD) } } } @@ -193,10 +185,7 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() val requestBody = getMultipartRequestBody(KYC) val multipartBody = getMultipartBody(bytes, KYC_FILE_NAME) coroutineScope.launch { - val response = repository.submitKYCDocument( - requestBody, - multipartBody - ) + val response = repository.submitKYCDocument(requestBody, multipartBody) if (response.error == null && response.errors?.isEmpty().orTrue()) { _kycUrl.value = response.data } else { @@ -211,11 +200,7 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() if (response.error == null && response.errors.isNullOrEmpty()) { _textFieldSubmitAsyncResponse.value = response.data } else { - setErrorData( - response.errors, - response.error, - ApiErrorTagType.SUBMIT_KYC_API_ERROR - ) + setErrorData(response.errors, response.error, ApiErrorTagType.SUBMIT_KYC_API_ERROR) } } } @@ -233,34 +218,52 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() VIDEO_KYC -> _videoKycAsyncResponse.value = response.data } } else { - if (type == VIDEO_KYC && response.errors?.getOrNull(0)?.code == ApiConstants.E_VKYC_REJECTED) { + if ( + type == VIDEO_KYC && + response.errors?.getOrNull(0)?.code == ApiConstants.E_VKYC_REJECTED + ) { _videoKycAsyncResponse.value = response.data - } else if (type == SELFIE && response.errors?.getOrNull(0)?.code == ApiConstants.E_KYC_SOFT_REJECTED_01) { + } else if ( + type == SELFIE && + response.errors?.getOrNull(0)?.code == ApiConstants.E_KYC_SOFT_REJECTED_01 + ) { _selfieUploadStatus.value = response.data - } else if (type == SELFIE && response.errors?.getOrNull(0)?.code == ApiConstants.E_SELFIE_INVALID_01 && isForV2) { + } else if ( + type == SELFIE && + response.errors?.getOrNull(0)?.code == ApiConstants.E_SELFIE_INVALID_01 && + isForV2 + ) { _selfieError.value = true _asyncError.value = true - } else if (type == AADHAR_VERIFICATION && response.errors?.getOrNull(0)?.code == ApiConstants.E_AADHAAR_VERIFICATION_FAILED_01 && isForV2) { + } else if ( + type == AADHAR_VERIFICATION && + response.errors?.getOrNull(0)?.code == + ApiConstants.E_AADHAAR_VERIFICATION_FAILED_01 && + isForV2 + ) { _aadhaarError.value = true _asyncError.value = true - } else if (type == AADHAR_VERIFICATION && response.errors?.getOrNull(0)?.code == ApiConstants.E_KYC_SOFT_REJECTED_01 && isForV2) { + } else if ( + type == AADHAR_VERIFICATION && + response.errors?.getOrNull(0)?.code == + ApiConstants.E_KYC_SOFT_REJECTED_01 && + isForV2 + ) { _aadhaarUploadStatus.value = true _asyncError.value = true } else { _asyncError.value = true - val errorTag = when (type) { - SELFIE -> ApiErrorTagType.SELFIE_ASYNC_API_ERROR - UPDATE_KYC_DETAILS -> ApiErrorTagType.UPDATE_KYC_ASYNC_API_ERROR - AADHAR_VERIFICATION -> ApiErrorTagType.AADHAAR_VERIFICATION_ASYNC_API_ERROR - OVD_UPLOAD -> ApiErrorTagType.OVD_UPLOAD_ERROR - PAN_UPLOAD -> ApiErrorTagType.PAN_UPLOAD_ERROR - else -> null - } - if (type != OVD_UPLOAD) setErrorData( - response.errors, - response.error, - errorTag - ) + val errorTag = + when (type) { + SELFIE -> ApiErrorTagType.SELFIE_ASYNC_API_ERROR + UPDATE_KYC_DETAILS -> ApiErrorTagType.UPDATE_KYC_ASYNC_API_ERROR + AADHAR_VERIFICATION -> + ApiErrorTagType.AADHAAR_VERIFICATION_ASYNC_API_ERROR + OVD_UPLOAD -> ApiErrorTagType.OVD_UPLOAD_ERROR + PAN_UPLOAD -> ApiErrorTagType.PAN_UPLOAD_ERROR + else -> null + } + if (type != OVD_UPLOAD) setErrorData(response.errors, response.error, errorTag) } } } @@ -276,12 +279,17 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() return@launch } val provider = response.data?.providerType - if ((provider == ProviderType.DIGITAP && data?.identifier.isNullOrEmpty()) - || (provider != ProviderType.DIGITAP && (data?.clientId.isNullOrEmpty() || data?.clientSecret.isNullOrEmpty())) + if ( + (provider == ProviderType.DIGITAP && data?.identifier.isNullOrEmpty()) || + (provider != ProviderType.DIGITAP && + (data?.clientId.isNullOrEmpty() || data?.clientSecret.isNullOrEmpty())) ) { updateErrorMessage( ErrorMessage( - message = NaviApplication.instance.getString(R.string.could_not_initiate_verification), + message = + NaviApplication.instance.getString( + R.string.could_not_initiate_verification + ), errorTag = ApiErrorTagType.INIT_AADHAAR_VERIFICATION_API_ERROR ) ) @@ -304,27 +312,18 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() if (response.error == null && response.errors.isNullOrEmpty()) { _kycDetailsV2.value = response.data } else { - updateErrorMessage( - response.error, - ApiErrorTagType.FETCH_KYC_GET_API_ERROR, - false - ) + updateErrorMessage(response.error, ApiErrorTagType.FETCH_KYC_GET_API_ERROR, false) } } } - fun fetchKycDetails() { coroutineScope.launch { val response = repository.fetchKycDetails() if (response.error == null && response.errors.isNullOrEmpty()) { _kycDetails.value = response.data } else { - updateErrorMessage( - response.error, - ApiErrorTagType.FETCH_KYC_GET_API_ERROR, - false - ) + updateErrorMessage(response.error, ApiErrorTagType.FETCH_KYC_GET_API_ERROR, false) } } } @@ -417,11 +416,7 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() if (response.error == null && response.errors?.isEmpty().orTrue()) { _supportedPANOvdsUpload.value = response.data } else { - setErrorData( - response.errors, - response.error, - ApiErrorTagType.PAN_UPLOAD_ERROR - ) + setErrorData(response.errors, response.error, ApiErrorTagType.PAN_UPLOAD_ERROR) } } } @@ -450,9 +445,7 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() } fun setTextFieldData(name: String?) { - name?.let { - _textFieldData.value = name - } + name?.let { _textFieldData.value = name } } fun isKycItemNotCompleted(type: String, kycItemList: List?): Boolean { @@ -526,4 +519,4 @@ class KycVM(private val repository: KycRepository = KycRepository()) : BaseVM() const val FRONT = "front" private const val BACK = "back" } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/viewmodels/VideoKycVM.kt b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/viewmodels/VideoKycVM.kt index 15e38db1fa..38e7338101 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/kyc/viewmodels/VideoKycVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/kyc/viewmodels/VideoKycVM.kt @@ -10,8 +10,8 @@ package com.naviapp.personalloan.getloan.kyc.viewmodels import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.navi.common.extensions.isNull -import com.navi.common.model.GenericErrorResponse import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.utils.orTrue import com.navi.common.viewmodel.BaseVM import com.naviapp.analytics.utils.NaviAnalytics diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/fragments/EmiSelectorFragment.kt b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/fragments/EmiSelectorFragment.kt index 326b6f64db..50d4d6da1e 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/fragments/EmiSelectorFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/fragments/EmiSelectorFragment.kt @@ -149,11 +149,11 @@ class EmiSelectorFragment : BaseFragment() { ?: run { startDate } if (startDate != null && endDate != null && defaultDate != null) { - binding.calendarList.initNaviCalendar(startDate, endDate, defaultDate, null) { + binding.calendarList.initNaviCalendar(startDate, endDate, defaultDate, null, callback = { analyticsEventTracker.onDateSelect(formatDateInto(it, DATE_FORMAT_YYYY_MM_DD)) changeDescriptionText(it) selectedDate = it - } + }) } } diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstOtpGenerationState.kt b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstOtpGenerationState.kt index 2abdc3da25..507d8d4f45 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstOtpGenerationState.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstOtpGenerationState.kt @@ -1,19 +1,21 @@ /* - * * - * * Copyright (c) 2022 . All rights reserved @Navi + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.getloan.loandetails.states +import com.navi.common.network.models.GenericErrorResponse import com.naviapp.models.response.GstOtpGenerationResponse -import com.navi.common.model.GenericErrorResponse import com.naviapp.personalloan.getloan.loandetails.viewmodels.GstDetailsVM sealed class GstOtpGenerationState { - class Success(val gstOtpGenerationResponse: GstOtpGenerationResponse?) : GstOtpGenerationState() + class Success(val gstOtpGenerationResponse: GstOtpGenerationResponse?) : + GstOtpGenerationState() class Failure( val gstOtpGenerationResponseCode: GstDetailsVM.GstOtpGenerationResponseCode?, val errorResponse: GenericErrorResponse? ) : GstOtpGenerationState() -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstVerificationLoginState.kt b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstVerificationLoginState.kt index 84f983153f..e49efe05c6 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstVerificationLoginState.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstVerificationLoginState.kt @@ -1,15 +1,17 @@ /* - * * - * * Copyright (c) 2022 . All rights reserved @Navi + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.getloan.loandetails.states +import com.navi.common.network.models.GenericErrorResponse import com.naviapp.models.response.GstVerificationResponse -import com.navi.common.model.GenericErrorResponse sealed class GstVerificationLoginState { - class Success(val gstVerificationResponse: GstVerificationResponse?) : GstVerificationLoginState() + class Success(val gstVerificationResponse: GstVerificationResponse?) : + GstVerificationLoginState() class Failure(val errorResponse: GenericErrorResponse?) : GstVerificationLoginState() -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstVerificationState.kt b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstVerificationState.kt index 0f51217a18..3a4c6a07a7 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstVerificationState.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/loandetails/states/GstVerificationState.kt @@ -1,15 +1,16 @@ /* - * * - * * Copyright (c) 2022 . All rights reserved @Navi + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.getloan.loandetails.states +import com.navi.common.network.models.GenericErrorResponse import com.naviapp.models.response.GstVerificationResponse -import com.navi.common.model.GenericErrorResponse sealed class GstVerificationState { class Success(val gstVerificationResponse: GstVerificationResponse?) : GstVerificationState() class Failure(val errorResponse: GenericErrorResponse?) : GstVerificationState() -} \ No newline at end of file +} 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 e21a326c30..00c467d433 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 @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -9,15 +9,15 @@ package com.naviapp.personalloan.getloan.loandetails.viewmodels import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import com.navi.base.model.CtaData +import com.navi.base.model.LineItem +import com.navi.base.sharedpref.PreferenceManager import com.navi.common.firebasedb.FirebaseStatusType import com.navi.common.firebasedb.LOAN_APPLY import com.navi.common.firebasedb.OFFER_GENERATE import com.navi.common.firebasedb.PRE_ELIGIBILITY -import com.navi.base.model.CtaData -import com.navi.common.model.GenericErrorResponse -import com.navi.base.model.LineItem import com.navi.common.model.Money -import com.navi.base.sharedpref.PreferenceManager +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.utils.orFalse import com.navi.common.viewmodel.BaseVM import com.naviapp.models.* @@ -34,7 +34,9 @@ import kotlinx.coroutines.launch class LoanDetailsVM(private val repository: LoanDetailsRepository = LoanDetailsRepository()) : BaseVM() { - private val _requestIdGenerateOffer by lazy { MutableLiveData() } + private val _requestIdGenerateOffer by lazy { + MutableLiveData() + } val requestIdGenerateOffer: LiveData get() = _requestIdGenerateOffer @@ -139,7 +141,10 @@ class LoanDetailsVM(private val repository: LoanDetailsRepository = LoanDetailsR } } - fun generateOffer(loanOfferType: String? = null, offerImprovementChannelType: ArrayList? = null) { + fun generateOffer( + loanOfferType: String? = null, + offerImprovementChannelType: ArrayList? = null + ) { coroutineScope.launch { val request = GenerateOfferRequest(null, loanOfferType, offerImprovementChannelType) val response = repository.generateOffer(request) @@ -197,14 +202,15 @@ class LoanDetailsVM(private val repository: LoanDetailsRepository = LoanDetailsR promotionOfferId: String? ) { coroutineScope.launch { - val request = LoanRequest( - offerId, - loanAmount, - emiAmount, - tenure, - firstEmiDueDate, - promotionOfferId - ) + val request = + LoanRequest( + offerId, + loanAmount, + emiAmount, + tenure, + firstEmiDueDate, + promotionOfferId + ) val response = repository.applyLoan(request) if (response.error == null && response.errors.isNullOrEmpty()) { _requestIdApplyLoan.value = response.data @@ -355,10 +361,7 @@ class LoanDetailsVM(private val repository: LoanDetailsRepository = LoanDetailsR } } - fun setShouldUpdateEmiSlider( - previousRateOfInterest: Double?, - actualRateOfInterest: Double? - ) { + fun setShouldUpdateEmiSlider(previousRateOfInterest: Double?, actualRateOfInterest: Double?) { this.shouldUpdateEmiSlider = previousRateOfInterest != actualRateOfInterest } @@ -396,21 +399,20 @@ class LoanDetailsVM(private val repository: LoanDetailsRepository = LoanDetailsR fun getEmiTenure(): LineItem? = emiTenure - fun setLoanAmountSliderValue(oldValue: String?, newValue: String?){ - oldValue?.let { loanAmountSliderValue.startValue = it } - newValue?.let { loanAmountSliderValue.stopValue = it } + fun setLoanAmountSliderValue(oldValue: String?, newValue: String?) { + oldValue?.let { loanAmountSliderValue.startValue = it } + newValue?.let { loanAmountSliderValue.stopValue = it } } fun getLoanAmountSliderValue() = loanAmountSliderValue - fun setEmiSliderValue(oldValue: String?, newValue: String?){ - oldValue?.let { emiSliderValue.startValue = it } - newValue?.let { emiSliderValue.stopValue = it } + fun setEmiSliderValue(oldValue: String?, newValue: String?) { + oldValue?.let { emiSliderValue.startValue = it } + newValue?.let { emiSliderValue.stopValue = it } } fun getEmiSliderValue() = emiSliderValue - fun setOldEmiTenure(emiTenure: Int?) { this.oldEmiTenure = emiTenure } diff --git a/app/src/main/java/com/naviapp/personalloan/getloan/repositories/LoanDisbursementRepository.kt b/app/src/main/java/com/naviapp/personalloan/getloan/repositories/LoanDisbursementRepository.kt index 1e6bc0b02f..e5151df523 100644 --- a/app/src/main/java/com/naviapp/personalloan/getloan/repositories/LoanDisbursementRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/getloan/repositories/LoanDisbursementRepository.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -8,29 +8,32 @@ package com.naviapp.personalloan.getloan.repositories import com.navi.common.model.ModuleName +import com.navi.common.network.models.RepoResult import com.naviapp.models.response.AdditionalDataAsyncResponse import com.naviapp.models.response.LoanDisbursementStatusMessageResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService import com.naviapp.utils.superAppRetrofitService class LoanDisbursementRepository : ResponseCallback() { - suspend fun getDisbursementStatus(loanApplicationId: String): RepoResult> = + suspend fun getDisbursementStatus( + loanApplicationId: String + ): RepoResult> = apiResponseCallback(retrofitService().getDisbursementStatus(loanApplicationId)) - suspend fun fetchAsyncRequestData(requestId: String): RepoResult> = + suspend fun fetchAsyncRequestData( + requestId: String + ): RepoResult> = apiResponseCallback(retrofitService().fetchAsyncRequestDataWithAdditionalData(requestId)) suspend fun fetchLoanBasicDetails() = apiResponseCallback(retrofitService().fetchLoanBasicDetails()) suspend fun fetchABExperiment(experimentName: String) = - superAppRetrofitService().fetchABExperiment( - experimentName, - ModuleName.LITMUS.name - ) + superAppRetrofitService().fetchABExperiment(experimentName, ModuleName.LITMUS.name) suspend fun fetchRewardsDetails(type: String, typeId: String) = - apiResponseCallback(superAppRetrofitService().fetchRewardsDetails(type = type, typeId = typeId)) -} \ No newline at end of file + apiResponseCallback( + superAppRetrofitService().fetchRewardsDetails(type = type, typeId = typeId) + ) +} 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 693b3c72f1..40e94b94c4 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 @@ -70,6 +70,7 @@ 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.naviapp.personalloanrevamp.useridentificationv2.activities.LoanEligibilityLoaderV2Activity import com.naviapp.receiver.WifiTrackerBaseActivity import com.naviapp.registration.viewmodel.ConfigVM import com.naviapp.utils.* @@ -365,6 +366,14 @@ class LoanEligibilityLoaderActivity : WifiTrackerBaseActivity(), private fun apiPollInitPermission(uploadDataAsyncResponse: UploadDataAsyncResponse) { apiPollScheduler = ApiPollScheduler( + initialDelay = uploadDataAsyncResponse.requestConfig?.initialDelay?.toLong() + .orValue( + Constants.PERMISSION_POLLING_INITIAL_DELAY + ), + pollInterval = uploadDataAsyncResponse.requestConfig?.interval?.toLong() + .orValue( + Constants.PERMISSION_POLLING_INTERVAL + ), numberOfRetry = uploadDataAsyncResponse.requestConfig?.numOfRetries.orValue( NUMBER_OF_RETRY ) diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/employmentverification/repositories/EmploymentVerificationRepository.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/employmentverification/repositories/EmploymentVerificationRepository.kt index 5bf793ddd3..f0d593f19f 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/employmentverification/repositories/EmploymentVerificationRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/employmentverification/repositories/EmploymentVerificationRepository.kt @@ -1,16 +1,16 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.useridentification.employmentverification.repositories +import com.navi.common.network.models.RepoResult import com.naviapp.homeloandigital.models.OTPVerifyResponse import com.naviapp.models.request.OtpRequest import com.naviapp.models.response.EmploymentVerificationResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService @@ -20,8 +20,7 @@ class EmploymentVerificationRepository : ResponseCallback() { return apiResponseCallback(retrofitService().fetchEPFODetails(pageType)) } - suspend fun sendOtp() = - apiResponseCallback(retrofitService().sendOtpForEPFO()) + suspend fun sendOtp() = apiResponseCallback(retrofitService().sendOtpForEPFO()) suspend fun fetchEPFOOtpPageDetails() = apiResponseCallback(retrofitService().fetchEPFOOtpPageDetails()) @@ -31,5 +30,4 @@ class EmploymentVerificationRepository : ResponseCallback() { suspend fun fetchAsyncRequestData(requestId: String): RepoResult = apiResponseCallback(retrofitService().fetchAsyncResponse(requestId)) - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/pan/fragments/PanErrorFragment.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/pan/fragments/PanErrorFragment.kt index 646191298f..7ab6c5a5b9 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/pan/fragments/PanErrorFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/pan/fragments/PanErrorFragment.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -10,25 +10,24 @@ package com.naviapp.personalloan.useridentification.pan.fragments import android.os.Bundle import android.view.ViewStub import androidx.databinding.DataBindingUtil +import com.navi.common.extensions.orFalse +import com.navi.common.listeners.FragmentInterchangeListener +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.ui.fragment.BaseBottomSheet import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics -import com.navi.common.ui.fragment.BaseBottomSheet -import com.navi.common.listeners.FragmentInterchangeListener import com.naviapp.databinding.PanNameMismatchLayoutBinding import com.naviapp.models.SubPageStatusType import com.naviapp.personalloan.getloan.common.adapters.InstructionsAdapter -import com.navi.common.model.GenericErrorResponse import com.naviapp.personalloan.useridentification.common.PanOptionView import com.naviapp.personalloan.useridentification.common.PanOptionView.PanOptionTag.PAN_NAME import com.naviapp.personalloan.useridentification.common.PanOptionView.PanOptionTag.PAN_NUMBER -import com.navi.common.extensions.orFalse class PanErrorFragment : BaseBottomSheet(), PanOptionView.PanOptionViewListener { private lateinit var binding: PanNameMismatchLayoutBinding private var listener: FragmentInterchangeListener? = null private var isForHomeLoan: Boolean? = false - override fun setContainerView(viewStub: ViewStub) { viewStub.layoutResource = R.layout.pan_name_mismatch_layout binding = DataBindingUtil.getBinding(viewStub.inflate())!! @@ -49,23 +48,31 @@ class PanErrorFragment : BaseBottomSheet(), PanOptionView.PanOptionViewListener } private fun GenericErrorResponse.initActions() { - actions?.map { it.title?.split(DELIMITER) }?.let { - if (it.isEmpty()) return@let + actions + ?.map { it.title?.split(DELIMITER) } + ?.let { + if (it.isEmpty()) return@let - it.getOrNull(0)?.apply { - binding.nameOptionView.setProperties( - getOrNull(0), getOrNull(1)?.trim(), R.drawable.ic_forward_arrow_svg, - this@PanErrorFragment, PAN_NAME - ) - } + it.getOrNull(0)?.apply { + binding.nameOptionView.setProperties( + getOrNull(0), + getOrNull(1)?.trim(), + R.drawable.ic_forward_arrow_svg, + this@PanErrorFragment, + PAN_NAME + ) + } - it.getOrNull(1)?.apply { - binding.panOptionView.setProperties( - getOrNull(0), getOrNull(1)?.trim(), R.drawable.ic_edit_svg, - this@PanErrorFragment, PAN_NUMBER - ) + it.getOrNull(1)?.apply { + binding.panOptionView.setProperties( + getOrNull(0), + getOrNull(1)?.trim(), + R.drawable.ic_edit_svg, + this@PanErrorFragment, + PAN_NUMBER + ) + } } - } } override fun onClickActionBtn(tag: PanOptionView.PanOptionTag) { @@ -74,8 +81,7 @@ class PanErrorFragment : BaseBottomSheet(), PanOptionView.PanOptionViewListener if (isForHomeLoan.orFalse().not()) listener?.navigateToNextScreen(SubPageStatusType.BASIC_DETAILS, Bundle.EMPTY) } - PAN_NUMBER -> { - } + PAN_NUMBER -> {} } dialog?.dismiss() } @@ -103,12 +109,13 @@ class PanErrorFragment : BaseBottomSheet(), PanOptionView.PanOptionViewListener error: GenericErrorResponse, listener: FragmentInterchangeListener?, isForHomeLoan: Boolean? = null - ) = PanErrorFragment().apply { - this.listener = listener - this.isForHomeLoan = isForHomeLoan - val bundle = Bundle() - bundle.putParcelable(ERROR_DATA, error) - arguments = bundle - } + ) = + PanErrorFragment().apply { + this.listener = listener + this.isForHomeLoan = isForHomeLoan + val bundle = Bundle() + bundle.putParcelable(ERROR_DATA, error) + arguments = bundle + } } } diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/pan/repositories/PanRepository.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/pan/repositories/PanRepository.kt index b2c3c3c531..f903636677 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/pan/repositories/PanRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/pan/repositories/PanRepository.kt @@ -1,16 +1,16 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.useridentification.pan.repositories +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.RepoResult import com.naviapp.models.request.PanRequest import com.naviapp.models.response.ProfileDetailsResponse -import com.navi.common.model.UploadDataAsyncResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService @@ -26,9 +26,8 @@ class PanRepository : ResponseCallback() { suspend fun fetchAsyncRequestData(requestId: String) = apiResponseCallback(retrofitService().fetchAsyncRequestWithError(requestId)) - suspend fun checkUiStatus() = - apiResponseCallback(retrofitService().getRedirectPageStatus()) + suspend fun checkUiStatus() = apiResponseCallback(retrofitService().getRedirectPageStatus()) suspend fun fetchCityAndState(pinCode: String) = apiResponseCallback(retrofitService().fetchCityAndState(pinCode)) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/pan/viewmodels/PanVM.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/pan/viewmodels/PanVM.kt index cf6d3f2de1..10bbd668fe 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/pan/viewmodels/PanVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/pan/viewmodels/PanVM.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -10,18 +10,18 @@ package com.naviapp.personalloan.useridentification.pan.viewmodels import android.text.TextUtils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.navi.common.viewmodel.BaseVM import com.navi.common.firebasedb.FirebaseStatusType +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.network.models.GenericWarningResponse +import com.navi.common.viewmodel.BaseVM import com.naviapp.models.RedirectPageStatus import com.naviapp.models.request.PanRequest import com.naviapp.models.response.PinCodeData import com.naviapp.models.response.ProfileDetailsResponse -import com.navi.common.model.UploadDataAsyncResponse import com.naviapp.network.ApiConstants.E_PAN_NAME_MISMATCH import com.naviapp.network.ApiErrorTagType import com.naviapp.network.ApiErrorTagType.PAN_DETAILS_UPLOAD -import com.navi.common.model.GenericErrorResponse -import com.navi.common.model.GenericWarningResponse import com.naviapp.personalloan.useridentification.pan.repositories.PanRepository import kotlinx.coroutines.launch @@ -73,12 +73,13 @@ class PanVM(private val repository: PanRepository = PanRepository()) : BaseVM() skipValidation: Boolean = false ) { coroutineScope.launch { - val panRequest = PanRequest( - panNumber = panNumber, - dateOfBirth = dob, - pinCode = pinCode, - skipValidation = skipValidation - ) + val panRequest = + PanRequest( + panNumber = panNumber, + dateOfBirth = dob, + pinCode = pinCode, + skipValidation = skipValidation + ) val response = repository.submitPanDetails(panRequest) if (response.error == null) { if (TextUtils.equals(response.data?.status, FirebaseStatusType.FAILURE)) { @@ -103,18 +104,13 @@ class PanVM(private val repository: PanRepository = PanRepository()) : BaseVM() _dataAsyncResponse.value = response.data } else { val error = response.errors?.firstOrNull() - if (error?.code == E_PAN_NAME_MISMATCH) - _panNameMismatchError.value = error - else - checkUiStatus(response.errors, response.warning) + if (error?.code == E_PAN_NAME_MISMATCH) _panNameMismatchError.value = error + else checkUiStatus(response.errors, response.warning) } } } - fun checkUiStatus( - errors: List?, - warning: GenericWarningResponse? - ) { + fun checkUiStatus(errors: List?, warning: GenericWarningResponse?) { coroutineScope.launch { val response = repository.checkUiStatus() if (response.error == null) { @@ -140,4 +136,4 @@ class PanVM(private val repository: PanRepository = PanRepository()) : BaseVM() } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/profession/repository/ProfessionRepository.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/profession/repository/ProfessionRepository.kt index 368443de8a..7b6e3e6076 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/profession/repository/ProfessionRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/profession/repository/ProfessionRepository.kt @@ -1,8 +1,15 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.personalloan.useridentification.profession.repository +import com.navi.common.network.models.RepoResult import com.naviapp.models.response.ProfessionDetailsResponse import com.naviapp.models.response.ProfessionDetailsUploadData -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.network.retrofit.RetrofitService import javax.inject.Inject @@ -18,4 +25,4 @@ class ProfessionRepository @Inject constructor(private val retrofitService: Retr suspend fun fetchProfessionDetailsData(): RepoResult { return apiResponseCallback(retrofitService.fetchProfessionDetailsData()) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/profile/repositories/ProfileRepository.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/profile/repositories/ProfileRepository.kt index cd461b7827..010efa17f2 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/profile/repositories/ProfileRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/profile/repositories/ProfileRepository.kt @@ -1,16 +1,16 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.useridentification.profile.repositories +import com.navi.common.network.models.RepoResult import com.naviapp.models.FinoramicPostData import com.naviapp.models.request.ProfileRequest import com.naviapp.models.response.ProfileDetailsResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService @@ -25,8 +25,7 @@ class ProfileRepository : ResponseCallback() { suspend fun fetchAsyncRequestData(requestId: String) = apiResponseCallback(retrofitService().fetchAsyncRequestData(requestId)) - suspend fun checkUiStatus() = - apiResponseCallback(retrofitService().getRedirectPageStatus()) + suspend fun checkUiStatus() = apiResponseCallback(retrofitService().getRedirectPageStatus()) suspend fun postFinoramicData(finoramicPostData: FinoramicPostData) = apiResponseCallback(retrofitService().sendFinoramicData(finoramicPostData)) @@ -36,5 +35,4 @@ class ProfileRepository : ResponseCallback() { suspend fun fetchAsyncRequestDataWithError(requestId: String) = apiResponseCallback(retrofitService().fetchAsyncRequestWithError(requestId)) - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/profile/viewmodels/ProfileVM.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/profile/viewmodels/ProfileVM.kt index 16a0a9d8bc..3cd9a66624 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/profile/viewmodels/ProfileVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/profile/viewmodels/ProfileVM.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -10,18 +10,18 @@ package com.naviapp.personalloan.useridentification.profile.viewmodels import android.text.TextUtils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.navi.common.viewmodel.BaseVM import com.navi.common.firebasedb.FirebaseStatusType +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.network.models.GenericWarningResponse +import com.navi.common.viewmodel.BaseVM import com.naviapp.models.FinoramicPostData import com.naviapp.models.RedirectPageStatus import com.naviapp.models.request.ProfileRequest import com.naviapp.models.response.ProfileDetailsResponse import com.naviapp.models.response.SuccessResponse -import com.navi.common.model.UploadDataAsyncResponse import com.naviapp.network.ApiConstants.E_PAN_NAME_MISMATCH import com.naviapp.network.ApiErrorTagType.PROFILE_DETAILS_UPLOAD -import com.navi.common.model.GenericErrorResponse -import com.navi.common.model.GenericWarningResponse import com.naviapp.personalloan.useridentification.profile.repositories.ProfileRepository import kotlinx.coroutines.launch @@ -80,14 +80,15 @@ class ProfileVM(private val repository: ProfileRepository = ProfileRepository()) prevPage: String ) { coroutineScope.launch { - val profileRequest = ProfileRequest( - name = name, - dateOfBirth = dob, - maritalStatus = maritalStatus, - skipValidation = skipValidation, - panNumber = panNumber, - pinCode = pinCode - ) + val profileRequest = + ProfileRequest( + name = name, + dateOfBirth = dob, + maritalStatus = maritalStatus, + skipValidation = skipValidation, + panNumber = panNumber, + pinCode = pinCode + ) val response = repository.submitProfileDetails(profileRequest, prevPage) if (response.error == null) { if (TextUtils.equals(response.data?.status, FirebaseStatusType.FAILURE)) { @@ -101,10 +102,7 @@ class ProfileVM(private val repository: ProfileRepository = ProfileRepository()) } } - fun checkUiStatus( - errors: List?, - warning: GenericWarningResponse? - ) { + fun checkUiStatus(errors: List?, warning: GenericWarningResponse?) { coroutineScope.launch { val response = repository.checkUiStatus() if (response.error == null) { @@ -133,8 +131,9 @@ class ProfileVM(private val repository: ProfileRepository = ProfileRepository()) coroutineScope.launch { val response = repository.fetchNextCta(requestId = requestId) if (response.error == null) { - _nextCtaData.value = response.data?.plNextCtaData?.intermediateCta - ?: response.data?.plNextCtaData?.url + _nextCtaData.value = + response.data?.plNextCtaData?.intermediateCta + ?: response.data?.plNextCtaData?.url ?: profileDataResponse.value?.footer?.nextCta?.url } else { _nextCtaData.value = profileDataResponse.value?.footer?.nextCta?.url @@ -165,4 +164,4 @@ class ProfileVM(private val repository: ProfileRepository = ProfileRepository()) } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/work/fragments/WorkFragment.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/work/fragments/WorkFragment.kt index c88ac50dea..f9f565421e 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/work/fragments/WorkFragment.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/work/fragments/WorkFragment.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -17,61 +17,60 @@ import android.view.View import android.view.ViewGroup import android.widget.AdapterView import android.widget.TextView -import androidx.core.view.isVisible import androidx.core.content.res.ResourcesCompat +import androidx.core.view.isVisible import androidx.core.widget.addTextChangedListener import androidx.lifecycle.ViewModelProvider import com.navi.analytics.newrelic.NewrelicConstants.PL_WORK_SCREEN_LOAD import com.navi.analytics.newrelic.NewrelicConstants.PL_WORK_SUBMIT_LOAD import com.navi.analytics.utils.NaviTrackEvent -import com.navi.common.extensions.isNotNull -import com.navi.common.firebasedb.* -import com.navi.common.firebasedb.FirebaseStatusType import com.navi.base.model.CtaData import com.navi.base.sharedpref.PreferenceManager +import com.navi.common.extensions.isNotNull +import com.navi.common.firebasedb.* +import com.navi.common.listeners.FragmentInterchangeListener +import com.navi.common.listeners.HeaderInteractionListener +import com.navi.common.network.models.GenericWarningResponse +import com.navi.common.ui.fragment.BaseFragment +import com.navi.common.utils.* +import com.navi.design.utils.getNaviDrawable import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.adapter.HintAdapter import com.naviapp.common.customview.BoxWithIconView import com.naviapp.common.customview.LabelWithInputView import com.naviapp.common.customview.LabelWithSpinnerView -import com.navi.common.ui.fragment.BaseFragment import com.naviapp.common.listeners.FooterInteractionListener -import com.navi.common.listeners.HeaderInteractionListener import com.naviapp.common.navigator.ScreenNavigator -import com.navi.common.listeners.FragmentInterchangeListener import com.naviapp.databinding.WorkFragmentBinding import com.naviapp.errors.activities.ErrorActivity +import com.naviapp.models.UserDetail import com.naviapp.models.response.EmploymentTypeResponse import com.naviapp.models.response.WorkDetailsContent import com.naviapp.models.response.WorkDetailsResponse import com.naviapp.network.ApiErrorTagType.WORK_DETAILS_UPLOAD -import com.navi.common.model.GenericWarningResponse -import com.navi.common.utils.* -import com.navi.design.utils.getNaviDrawable -import com.naviapp.models.UserDetail import com.naviapp.personalloan.useridentification.work.adapters.CompanyNameAdapter import com.naviapp.personalloan.useridentification.work.viewmodels.WorkVM import com.naviapp.utils.* +import com.naviapp.utils.COMMA import com.naviapp.utils.Constants import com.naviapp.utils.Constants.CURRENT_USER import com.naviapp.utils.Constants.EPFO_PAGE_TYPE import com.naviapp.utils.Constants.PROFESSION_TYPE import com.naviapp.utils.Constants.WORK import com.naviapp.utils.EMPTY -import com.naviapp.utils.COMMA import com.naviapp.utils.openKeyboard import kotlinx.android.synthetic.main.view_label_with_input.view.* - -class WorkFragment : BaseFragment(), View.OnClickListener, - AdapterView.OnItemSelectedListener, CompanyNameAdapter.OnCompanyNameItemClick, +class WorkFragment : + BaseFragment(), + View.OnClickListener, + AdapterView.OnItemSelectedListener, + CompanyNameAdapter.OnCompanyNameItemClick, FooterInteractionListener { private lateinit var binding: WorkFragmentBinding - private val viewModel by lazy { - ViewModelProvider(this).get(WorkVM::class.java) - } + private val viewModel by lazy { ViewModelProvider(this).get(WorkVM::class.java) } private var listener: FragmentInterchangeListener? = null private var apiPollScheduler: ApiPollScheduler? = null @@ -86,9 +85,7 @@ class WorkFragment : BaseFragment(), View.OnClickListener, savedInstanceState: Bundle? ): View { binding = WorkFragmentBinding.inflate(inflater, container, false) - initError(viewModel, dialogDismissClicked = { - onErrorActionClick(it.tag as? String) - }) + initError(viewModel, dialogDismissClicked = { onErrorActionClick(it.tag as? String) }) initWarning() initObservers() initUi() @@ -129,11 +126,12 @@ class WorkFragment : BaseFragment(), View.OnClickListener, private fun initV2UI() { handleFormattingOfMonthlyIncome() resetEmploymentSelection() - binding.v2View.monthlyIncomeContainer.background = getNaviDrawable( - cornerRadius = resources.getDimension(R.dimen.layout_dp_8).toInt(), - strokeColor = ResourcesCompat.getColor(resources, R.color.grey_card_border, null), - strokeWidth = resources.getDimension(R.dimen.layout_dp_1).toInt() - ) + binding.v2View.monthlyIncomeContainer.background = + getNaviDrawable( + cornerRadius = resources.getDimension(R.dimen.layout_dp_8).toInt(), + strokeColor = ResourcesCompat.getColor(resources, R.color.grey_card_border, null), + strokeWidth = resources.getDimension(R.dimen.layout_dp_1).toInt() + ) binding.v2View.apply { firstBox.setOnClickListener { resetEmploymentSelection() @@ -163,9 +161,7 @@ class WorkFragment : BaseFragment(), View.OnClickListener, enableNextButton() } } - viewModel.workDetailsResponse.value?.let { - setUpV2View(it) - } + viewModel.workDetailsResponse.value?.let { setUpV2View(it) } enableNextButton() } @@ -178,44 +174,48 @@ class WorkFragment : BaseFragment(), View.OnClickListener, } private fun handleFormattingOfMonthlyIncome() { - binding.v2View.monthlyIncomeEdt.addTextChangedListener(object : TextWatcher { + binding.v2View.monthlyIncomeEdt.addTextChangedListener( + object : TextWatcher { - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + override fun beforeTextChanged( + s: CharSequence?, + start: Int, + count: Int, + after: Int + ) {} - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} - override fun afterTextChanged(s: Editable?) { - binding.v2View.monthlyIncomeEdt.removeTextChangedListener(this) + override fun afterTextChanged(s: Editable?) { + binding.v2View.monthlyIncomeEdt.removeTextChangedListener(this) - if (binding.v2View.monthlyIncomeEdt.text.isNullOrEmpty()) { - binding.v2View.monthlyIncomeEdt.setTextColor( - ResourcesCompat.getColor( - resources, - R.color.description_color_seven, - null + if (binding.v2View.monthlyIncomeEdt.text.isNullOrEmpty()) { + binding.v2View.monthlyIncomeEdt.setTextColor( + ResourcesCompat.getColor( + resources, + R.color.description_color_seven, + null + ) + ) + } else { + var originalText = binding.v2View.monthlyIncomeEdt.text.toString() + if (originalText.contains(COMMA)) { + originalText = originalText.replace(COMMA, EMPTY, true) + } + val amount = originalText.toDouble() + binding.v2View.monthlyIncomeEdt.setText(amount.formatAmount()) + binding.v2View.monthlyIncomeEdt.setSelection( + binding.v2View.monthlyIncomeEdt.text.length + ) + binding.v2View.monthlyIncomeEdt.setTextColor( + ResourcesCompat.getColor(resources, R.color.title_color_four, null) ) - ) - } else { - var originalText = binding.v2View.monthlyIncomeEdt.text.toString() - if (originalText.contains(COMMA)) { - originalText = originalText.replace(COMMA, EMPTY, true) } - val amount = originalText.toDouble() - binding.v2View.monthlyIncomeEdt.setText(amount.formatAmount()) - binding.v2View.monthlyIncomeEdt.setSelection(binding.v2View.monthlyIncomeEdt.text.length) - binding.v2View.monthlyIncomeEdt.setTextColor( - ResourcesCompat.getColor( - resources, - R.color.title_color_four, - null - ) - ) + binding.v2View.monthlyIncomeEdt.addTextChangedListener(this) + enableNextButton() } - binding.v2View.monthlyIncomeEdt.addTextChangedListener(this) - enableNextButton() } - - }) + ) } private fun softRejectObserver() { @@ -257,37 +257,23 @@ class WorkFragment : BaseFragment(), View.OnClickListener, ) } perfUtils.endInteraction(PL_WORK_SCREEN_LOAD) - - } } private fun setUpView(data: WorkDetailsResponse, context: Context) { binding.employmentTypeLayout.isVisible = true - data.content?.monthlyIncomeTitle?.let { - initMonthlyIncomeUI() - } - data.content?.otherIncomeTitle?.let { - initOtherIncomeUI() - } + data.content?.monthlyIncomeTitle?.let { initMonthlyIncomeUI() } + data.content?.otherIncomeTitle?.let { initOtherIncomeUI() } data.content?.monthlyIncomeInfo?.let { genericWarningResponse -> - binding.monthlyIncomeLayout.setInfoIcon( - IconUtils.ICON_INFO - ) + binding.monthlyIncomeLayout.setInfoIcon(IconUtils.ICON_INFO) binding.monthlyIncomeLayout.binding.infoIconIv.setOnClickListener { - openBottomSheet( - genericWarningResponse - ) + openBottomSheet(genericWarningResponse) } } data.content?.otherIncomeInfo?.let { genericWarningResponse -> - binding.otherIncomeLayout.setInfoIcon( - IconUtils.ICON_INFO - ) + binding.otherIncomeLayout.setInfoIcon(IconUtils.ICON_INFO) binding.otherIncomeLayout.binding.infoIconIv.setOnClickListener { - openBottomSheet( - genericWarningResponse - ) + openBottomSheet(genericWarningResponse) } } setupSpinnerAdapter( @@ -313,24 +299,19 @@ class WorkFragment : BaseFragment(), View.OnClickListener, } data.content?.employmentTypes?.forEachIndexed { index, employmentTypeResponse -> - val view = when (index) { - 0 -> binding.v2View.firstBox - 1 -> binding.v2View.secondBox - 2 -> binding.v2View.thirdBox - else -> binding.v2View.firstBox - } - setEmploymentItems( - view, - employmentTypeResponse - ) + val view = + when (index) { + 0 -> binding.v2View.firstBox + 1 -> binding.v2View.secondBox + 2 -> binding.v2View.thirdBox + else -> binding.v2View.firstBox + } + setEmploymentItems(view, employmentTypeResponse) } enableNextButton() } - private fun setEmploymentItems( - view: BoxWithIconView, - data: EmploymentTypeResponse - ) { + private fun setEmploymentItems(view: BoxWithIconView, data: EmploymentTypeResponse) { val title = data.description val unselectedIcon = data.unselectedIconCode val selectedIcon = data.selectedIconCode @@ -348,19 +329,18 @@ class WorkFragment : BaseFragment(), View.OnClickListener, context: Context, typeList: List ) { - val spinnerAdapter = HintAdapter( - context, - R.layout.spinner_text_view, - typeList.map { it.description } - .toMutableList() - .apply { add(context.getString(R.string.select)) } - ) + val spinnerAdapter = + HintAdapter( + context, + R.layout.spinner_text_view, + typeList + .map { it.description } + .toMutableList() + .apply { add(context.getString(R.string.select)) } + ) spinnerAdapter.setDropDownViewResource(R.layout.spinner_drop_down_view) view?.binding?.spinner?.adapter = spinnerAdapter - view?.binding?.spinner?.setSelection( - spinnerAdapter.count, - true - ) + view?.binding?.spinner?.setSelection(spinnerAdapter.count, true) } private fun onWorkSubmissionResponse(status: String?, isPolling: Boolean = true) { @@ -378,10 +358,14 @@ class WorkFragment : BaseFragment(), View.OnClickListener, userDetailForAnalytics?.monthlyIncome?.amount ) if (binding.otherProfessionTypeLayout.getText().isNotEmpty()) { - naviAnalyticsEventTracker.onSpecifyProfessionClicked(binding.otherProfessionTypeLayout.getText()) + naviAnalyticsEventTracker.onSpecifyProfessionClicked( + binding.otherProfessionTypeLayout.getText() + ) } if (binding.monthlyIncomeLayout.getText().isNotEmpty()) { - naviAnalyticsEventTracker.onMonthlyIncomeEntered(binding.monthlyIncomeLayout.getText()) + naviAnalyticsEventTracker.onMonthlyIncomeEntered( + binding.monthlyIncomeLayout.getText() + ) } perfUtils.endInteraction(PL_WORK_SUBMIT_LOAD) navigateToNextScreen() @@ -397,7 +381,8 @@ class WorkFragment : BaseFragment(), View.OnClickListener, else -> { viewModel.workAsyncResponse.value?.requestId?.let { requestId -> viewModel.fetchAsyncRequestDataWithError(requestId) - } ?: viewModel.checkUiStatus(null, null) + } + ?: viewModel.checkUiStatus(null, null) } } } @@ -405,16 +390,18 @@ class WorkFragment : BaseFragment(), View.OnClickListener, } private fun navigateToNextScreen() { - val selectedEmploymentType = viewModel.getSelectedEmploymentType( - binding.employmentTypeLayout.getSelectedItem()?.toString() - ) + val selectedEmploymentType = + viewModel.getSelectedEmploymentType( + binding.employmentTypeLayout.getSelectedItem()?.toString() + ) var nextCta = selectedEmploymentType?.nextCta if (selectedEmploymentType?.professionRequired.orFalse()) { - viewModel.getSelectedProfessionType( - binding.professionTypeLayout.getSelectedItem()?.toString() - )?.nextCta?.let { - nextCta = it - } + viewModel + .getSelectedProfessionType( + binding.professionTypeLayout.getSelectedItem()?.toString() + ) + ?.nextCta + ?.let { nextCta = it } } if (nextCta == null) { nextCta = viewModel.workDetailsResponse.value?.footer?.nextCta @@ -435,64 +422,53 @@ class WorkFragment : BaseFragment(), View.OnClickListener, } private fun firebaseInit(requestId: String, notificationPath: String) { - firebaseDataReceiveListener = object : FirebaseDataReceiveListener { - override fun onDataReceive(firebaseResponse: FirebaseResponse?) { - firebaseResponse?.let { - onWorkSubmissionResponse(it.status, false) + firebaseDataReceiveListener = + object : FirebaseDataReceiveListener { + override fun onDataReceive(firebaseResponse: FirebaseResponse?) { + firebaseResponse?.let { onWorkSubmissionResponse(it.status, false) } } } - } firebaseDataHelper = null - firebaseDataHelper = FirebaseDataHelper().apply { - initFirebaseDataReceiver( - lifecycle, - firebaseDataReceiveListener, - WORK_DETAILS, - requestId, - notificationPath - ) - } + firebaseDataHelper = + FirebaseDataHelper().apply { + initFirebaseDataReceiver( + lifecycle, + firebaseDataReceiveListener, + WORK_DETAILS, + requestId, + notificationPath + ) + } } - private val clickListener: View.OnClickListener = View.OnClickListener { - submitWorkDetails() - } + private val clickListener: View.OnClickListener = View.OnClickListener { submitWorkDetails() } private fun handleTimeOutError(errorTag: String) { firebaseDataReceiveListener = null - showTimeoutErrorScreen( - firebaseDataHelper, - apiPollScheduler, - clickListener, - errorTag - ) + showTimeoutErrorScreen(firebaseDataHelper, apiPollScheduler, clickListener, errorTag) firebaseDataHelper = null } - private val onPollingEnd = { - handleTimeOutError(WORK_DETAILS_UPLOAD) - } + private val onPollingEnd = { handleTimeOutError(WORK_DETAILS_UPLOAD) } private fun apiPollInit(requestId: String) { - apiPollScheduler = ApiPollScheduler(doOnTimeout = onPollingEnd) { - viewModel.fetchAsyncRequestDataWithError(requestId) - } + apiPollScheduler = + ApiPollScheduler(doOnTimeout = onPollingEnd) { + viewModel.fetchAsyncRequestDataWithError(requestId) + } apiPollScheduler?.scheduleApiPoll() - viewModel.dataAsyncResponse.observeNonNull(this) { - onWorkSubmissionResponse(it.status) - } + viewModel.dataAsyncResponse.observeNonNull(this) { onWorkSubmissionResponse(it.status) } } private fun populateData(data: WorkDetailsContent?) { - data?.employmentTypes?.indexOfFirst { it.code == data.employmentType } - ?.let { - binding.employmentTypeLayout.binding.spinner.setSelection(it) - } + data + ?.employmentTypes + ?.indexOfFirst { it.code == data.employmentType } + ?.let { binding.employmentTypeLayout.binding.spinner.setSelection(it) } data?.professionType?.let { - data.professionTypes?.indexOfFirst { it.code == data.professionType } - ?.let { - binding.professionTypeLayout.binding.spinner.setSelection(it) - } + data.professionTypes + ?.indexOfFirst { it.code == data.professionType } + ?.let { binding.professionTypeLayout.binding.spinner.setSelection(it) } } data?.monthlyIncome?.amount?.let { binding.monthlyIncomeLayout.input_et.setText(it.formatAmount()) @@ -529,27 +505,23 @@ class WorkFragment : BaseFragment(), View.OnClickListener, } private fun openBottomSheet(genericWarningResponse: GenericWarningResponse?) { - viewModel.setWarning( - genericWarningResponse, - null - ) + viewModel.setWarning(genericWarningResponse, null) } private fun initListeners() { binding.monthlyIncomeLayout.input_et.setOnKeyListener { v, keyCode, _ -> - v?.let { - onKeyIncome(v, keyCode) - } + v?.let { onKeyIncome(v, keyCode) } false } binding.otherIncomeLayout.input_et.setOnKeyListener { v, keyCode, _ -> - v?.let { - onKeyIncome(v, keyCode) - } + v?.let { onKeyIncome(v, keyCode) } false } binding.monthlyIncomeLayout.input_et.setOnFocusChangeListener { _, hasFocus -> - if (hasFocus) naviAnalyticsEventTracker.onMonthlyIncomeEdit(binding.monthlyIncomeLayout.input_et.text.toString()) + if (hasFocus) + naviAnalyticsEventTracker.onMonthlyIncomeEdit( + binding.monthlyIncomeLayout.input_et.text.toString() + ) } binding.otherIncomeLayout.input_et.setOnFocusChangeListener { _, hasFocus -> if (hasFocus) naviAnalyticsEventTracker.onOtherIncomeEdit() @@ -557,7 +529,9 @@ class WorkFragment : BaseFragment(), View.OnClickListener, binding.professionTypeLayout.addOnItemSelectedListener(this) binding.companyNameLayout.companyNameEt.setOnClickListener(this) binding.companyNameLayout.companyNameEt.addTextChangedListener { enableNextButton() } - binding.otherProfessionTypeLayout.binding.inputEt.addTextChangedListener { enableNextButton() } + binding.otherProfessionTypeLayout.binding.inputEt.addTextChangedListener { + enableNextButton() + } } private fun workDetailsSubmittedObserver() { @@ -572,35 +546,42 @@ class WorkFragment : BaseFragment(), View.OnClickListener, private fun enableNextButton() { if (viewModel.workDetailsResponse.value?.content?.shouldShowNewDesign.orTrue()) { binding.footerView.changeNextButtonBackground( - viewModel.getSelectedEmploymentType() != null - && !binding.v2View.monthlyIncomeEdt.text.isNullOrEmpty() + viewModel.getSelectedEmploymentType() != null && + !binding.v2View.monthlyIncomeEdt.text.isNullOrEmpty() ) } else { binding.footerView.changeNextButtonBackground( binding.employmentTypeLayout.getSelectedItem() != null && - binding.employmentTypeLayout.getSelectedItem() - ?.toString() != context?.getString(R.string.select) - && binding.monthlyIncomeLayout.input_et.text.toString().isNotBlank() - && (viewModel.getSelectedEmploymentType( - binding.employmentTypeLayout.getSelectedItem()?.toString() - )?.companyNameRequired.orFalse() - .not() - || binding.companyNameLayout.companyNameEt.text.toString().isNotBlank()) - && ((binding.professionTypeLayout.visibility != View.VISIBLE) || (binding.professionTypeLayout.getSelectedItem() != null && - binding.professionTypeLayout.getSelectedItem() - ?.toString() != context?.getString( - R.string.select - ))) && (binding.otherProfessionTypeLayout.visibility != View.VISIBLE || !TextUtils.isEmpty( - binding.otherProfessionTypeLayout.getText() - )) + binding.employmentTypeLayout.getSelectedItem()?.toString() != + context?.getString(R.string.select) && + binding.monthlyIncomeLayout.input_et.text.toString().isNotBlank() && + (viewModel + .getSelectedEmploymentType( + binding.employmentTypeLayout.getSelectedItem()?.toString() + ) + ?.companyNameRequired + .orFalse() + .not() || + binding.companyNameLayout.companyNameEt.text.toString().isNotBlank()) && + ((binding.professionTypeLayout.visibility != View.VISIBLE) || + (binding.professionTypeLayout.getSelectedItem() != null && + binding.professionTypeLayout.getSelectedItem()?.toString() != + context?.getString(R.string.select))) && + (binding.otherProfessionTypeLayout.visibility != View.VISIBLE || + !TextUtils.isEmpty(binding.otherProfessionTypeLayout.getText())) ) binding.companyNameLayout.root.visibility = - if (viewModel.getSelectedEmploymentType( - binding.employmentTypeLayout.getSelectedItem()?.toString() - )?.companyNameRequired.orFalse() - ) View.VISIBLE else View.GONE + if ( + viewModel + .getSelectedEmploymentType( + binding.employmentTypeLayout.getSelectedItem()?.toString() + ) + ?.companyNameRequired + .orFalse() + ) + View.VISIBLE + else View.GONE } - } private fun initUi() { @@ -614,7 +595,9 @@ class WorkFragment : BaseFragment(), View.OnClickListener, resources.getString(R.string.profession) ) binding.professionTypeLayout.binding.spinner.addOnItemSelectedListener(this) - binding.companyNameLayout.companyNameEt.setDependentFormTextView(binding.companyNameLayout.companyNameTv) + binding.companyNameLayout.companyNameEt.setDependentFormTextView( + binding.companyNameLayout.companyNameTv + ) binding.otherProfessionTypeLayout.setProperties( iconCode = IconUtils.PROFESSION_ICON, label = getString(R.string.specify_your_profession), @@ -649,7 +632,11 @@ class WorkFragment : BaseFragment(), View.OnClickListener, ) incomeLayout.binding.inputEt.inputType = InputType.TYPE_CLASS_NUMBER incomeLayout.binding.inputEt.filters = - arrayOf(InputFilter.LengthFilter(resources.getInteger(R.integer.max_salary_length_including_comma))) + arrayOf( + InputFilter.LengthFilter( + resources.getInteger(R.integer.max_salary_length_including_comma) + ) + ) } override fun onClick(view: View?) { @@ -665,12 +652,13 @@ class WorkFragment : BaseFragment(), View.OnClickListener, private fun openCompanyNameSearch() { val companyNameFragment = CompanyNameFragment(this) - companyNameFragment.arguments = Bundle().apply { - putString( - COMPANY_NAME_SELECTED, - binding.companyNameLayout.companyNameEt.text.toString().trim() - ) - } + companyNameFragment.arguments = + Bundle().apply { + putString( + COMPANY_NAME_SELECTED, + binding.companyNameLayout.companyNameEt.text.toString().trim() + ) + } safelyShowBottomSheet(companyNameFragment, CompanyNameFragment.TAG) } @@ -698,74 +686,95 @@ class WorkFragment : BaseFragment(), View.OnClickListener, showLoader() } } else { - viewModel.workDetailsResponse.value?.content?.employmentTypes?.firstOrNull { - binding.employmentTypeLayout.getSelectedItem()?.toString() == it.description - }?.code?.let { - val monthlyIncome = - binding.monthlyIncomeLayout.input_et.text.toString().replace(",", EMPTY) - var otherIncome = - binding.otherIncomeLayout.input_et.text.toString().replace(",", EMPTY) - if (otherIncome.isEmpty()) otherIncome = "0" - val companyName = binding.companyNameLayout.companyNameEt.text.toString() - val userDetail = - PreferenceManager.getObjectPrefrences(CURRENT_USER, UserDetail::class.java) - ?: UserDetail() - userDetail.employmentType = it - userDetail.monthlyIncome = stringToDouble(monthlyIncome).getMoney() - userDetail.otherIncome = stringToDouble(monthlyIncome).getMoney() - PreferenceManager.setObjectPreference(CURRENT_USER, userDetail) - - //below is for analytics - userDetailForAnalytics?.monthlyIncome = userDetail.monthlyIncome - userDetailForAnalytics?.otherIncome = userDetail.otherIncome - userDetailForAnalytics?.employmentType = userDetail.employmentType - userDetailForAnalytics?.companyName = companyName - // end - - var professionTypeCode: String? = null - if (viewModel.getSelectedEmploymentType( - binding.employmentTypeLayout.getSelectedItem()?.toString() - )?.professionRequired.orFalse() - ) { - professionTypeCode = - viewModel.getSelectedProfessionType( - binding.professionTypeLayout.getSelectedItem()?.toString() - )?.code + viewModel.workDetailsResponse.value + ?.content + ?.employmentTypes + ?.firstOrNull { + binding.employmentTypeLayout.getSelectedItem()?.toString() == it.description + } + ?.code + ?.let { + val monthlyIncome = + binding.monthlyIncomeLayout.input_et.text.toString().replace(",", EMPTY) + var otherIncome = + binding.otherIncomeLayout.input_et.text.toString().replace(",", EMPTY) + if (otherIncome.isEmpty()) otherIncome = "0" + val companyName = binding.companyNameLayout.companyNameEt.text.toString() + val userDetail = + PreferenceManager.getObjectPrefrences(CURRENT_USER, UserDetail::class.java) + ?: UserDetail() + userDetail.employmentType = it + userDetail.monthlyIncome = stringToDouble(monthlyIncome).getMoney() + userDetail.otherIncome = stringToDouble(monthlyIncome).getMoney() + PreferenceManager.setObjectPreference(CURRENT_USER, userDetail) + + // below is for analytics + userDetailForAnalytics?.monthlyIncome = userDetail.monthlyIncome + userDetailForAnalytics?.otherIncome = userDetail.otherIncome + userDetailForAnalytics?.employmentType = userDetail.employmentType + userDetailForAnalytics?.companyName = companyName + // end + + var professionTypeCode: String? = null + if ( + viewModel + .getSelectedEmploymentType( + binding.employmentTypeLayout.getSelectedItem()?.toString() + ) + ?.professionRequired + .orFalse() + ) { + professionTypeCode = + viewModel + .getSelectedProfessionType( + binding.professionTypeLayout.getSelectedItem()?.toString() + ) + ?.code + } + perfUtils.startNewRelicInteraction(PL_WORK_SUBMIT_LOAD) + viewModel.submitWorkDetails( + it, + professionTypeCode, + monthlyIncome, + otherIncome, + companyName, + skipValidation + ) + showLoader() } - perfUtils.startNewRelicInteraction(PL_WORK_SUBMIT_LOAD) - viewModel.submitWorkDetails( - it, - professionTypeCode, - monthlyIncome, - otherIncome, - companyName, - skipValidation - ) - showLoader() - } } } private fun verifyWorkDetails(): Boolean { var validated = true if (viewModel.workDetailsResponse.value?.content?.shouldShowNewDesign.orTrue()) { - if (viewModel.getSelectedEmploymentType() != null && !binding.v2View.monthlyIncomeEdt.text.isNullOrEmpty()) { + if ( + viewModel.getSelectedEmploymentType() != null && + !binding.v2View.monthlyIncomeEdt.text.isNullOrEmpty() + ) { return true } return false } - if (binding.employmentTypeLayout.getSelectedItem() - ?.toString() == context?.getString(R.string.select) + if ( + binding.employmentTypeLayout.getSelectedItem()?.toString() == + context?.getString(R.string.select) ) { binding.employmentTypeLayout.setError() validated = false } - if (viewModel.getSelectedEmploymentType( - binding.employmentTypeLayout.getSelectedItem()?.toString() - )?.companyNameRequired.orFalse() && - (binding.companyNameLayout.companyNameEt.text.toString().isValidCompanyName().not()) + if ( + viewModel + .getSelectedEmploymentType( + binding.employmentTypeLayout.getSelectedItem()?.toString() + ) + ?.companyNameRequired + .orFalse() && + (binding.companyNameLayout.companyNameEt.text.toString().isValidCompanyName().not()) ) { - binding.companyNameLayout.companyNameEt.setError(getString(R.string.enter_valid_company_name)) + binding.companyNameLayout.companyNameEt.setError( + getString(R.string.enter_valid_company_name) + ) validated = false } if (binding.monthlyIncomeLayout.input_et.text.toString().isBlank()) { @@ -773,23 +782,32 @@ class WorkFragment : BaseFragment(), View.OnClickListener, context?.getString(R.string.enter_your_salary) validated = false } - if (viewModel.getSelectedEmploymentType( - binding.employmentTypeLayout.getSelectedItem()?.toString() - )?.professionRequired.orFalse() - ) { - if (binding.professionTypeLayout.getSelectedItem()?.toString() == context?.getString( - R.string.select + if ( + viewModel + .getSelectedEmploymentType( + binding.employmentTypeLayout.getSelectedItem()?.toString() ) + ?.professionRequired + .orFalse() + ) { + if ( + binding.professionTypeLayout.getSelectedItem()?.toString() == + context?.getString(R.string.select) ) { binding.professionTypeLayout.setError() validated = false } - if (viewModel.getSelectedProfessionType( - binding.professionTypeLayout.getSelectedItem()?.toString() - )?.code == OTHER && binding.otherProfessionTypeLayout.input_et.text.toString() - .isBlank() + if ( + viewModel + .getSelectedProfessionType( + binding.professionTypeLayout.getSelectedItem()?.toString() + ) + ?.code == OTHER && + binding.otherProfessionTypeLayout.input_et.text.toString().isBlank() ) { - binding.otherProfessionTypeLayout.setError(getString(R.string.enter_valid_profession_name)) + binding.otherProfessionTypeLayout.setError( + getString(R.string.enter_valid_profession_name) + ) validated = false } } @@ -808,14 +826,11 @@ class WorkFragment : BaseFragment(), View.OnClickListener, override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { when ((parent?.parent?.parent?.parent as? LabelWithSpinnerView)?.id) { R.id.employment_type_layout -> { - if (binding.employmentTypeLayout.getSelectedItem() - ?.toString() == context?.getString( - R.string.select - ) + if ( + binding.employmentTypeLayout.getSelectedItem()?.toString() == + context?.getString(R.string.select) ) { - (parent.getChildAt(0) as? TextView)?.let { - it.setTextColor(it.hintTextColors) - } + (parent.getChildAt(0) as? TextView)?.let { it.setTextColor(it.hintTextColors) } } else { naviAnalyticsEventTracker.onEmploymentTypeSelect( binding.employmentTypeLayout.getSelectedItem()?.toString() @@ -826,14 +841,11 @@ class WorkFragment : BaseFragment(), View.OnClickListener, updateProfessionView() } R.id.profession_type_layout -> { - if (binding.professionTypeLayout.getSelectedItem() - ?.toString() == context?.getString( - R.string.select - ) + if ( + binding.professionTypeLayout.getSelectedItem()?.toString() == + context?.getString(R.string.select) ) { - (parent.getChildAt(0) as? TextView)?.let { - it.setTextColor(it.hintTextColors) - } + (parent.getChildAt(0) as? TextView)?.let { it.setTextColor(it.hintTextColors) } } else { naviAnalyticsEventTracker.onProfessionTypeSelect( binding.professionTypeLayout.getSelectedItem()?.toString() @@ -868,8 +880,7 @@ class WorkFragment : BaseFragment(), View.OnClickListener, } } - override fun onNothingSelected(parent: AdapterView<*>?) { - } + override fun onNothingSelected(parent: AdapterView<*>?) {} override fun onAttach(context: Context) { super.onAttach(context) @@ -888,19 +899,14 @@ class WorkFragment : BaseFragment(), View.OnClickListener, val salary = salaryEt.text.toString().replace(",", EMPTY) salaryEt.setText(salary.toDoubleOrNull()?.formatAmount()) salaryEt.setSelection(salaryEt.text.toString().length) - } catch (e: Exception) { - } + } catch (e: Exception) {} } } enableNextButton() } override fun onFooterBackPress(ctaData: CtaData?) { - ctaData?.url?.let { - fragmentInterchangeListener?.navigateToNextScreen( - it, Bundle() - ) - } + ctaData?.url?.let { fragmentInterchangeListener?.navigateToNextScreen(it, Bundle()) } } override fun onFooterNextPress(ctaData: CtaData?, skipValidation: Boolean?) { @@ -920,4 +926,4 @@ class WorkFragment : BaseFragment(), View.OnClickListener, return WorkFragment() } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/work/repositories/WorkRepository.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/work/repositories/WorkRepository.kt index bf58023e9b..442df14e69 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/work/repositories/WorkRepository.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/work/repositories/WorkRepository.kt @@ -1,15 +1,15 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.personalloan.useridentification.work.repositories +import com.navi.common.network.models.RepoResult import com.naviapp.models.request.WorkRequest import com.naviapp.models.response.WorkDetailsResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.utils.retrofitService @@ -27,9 +27,8 @@ class WorkRepository : ResponseCallback() { suspend fun fetchCompanyNames(query: String) = apiResponseCallback(retrofitService().fetchCompanyNames(query)) - suspend fun checkUiStatus() = - apiResponseCallback(retrofitService().getRedirectPageStatus()) + suspend fun checkUiStatus() = apiResponseCallback(retrofitService().getRedirectPageStatus()) suspend fun getErrorPayload(requestId: String) = apiResponseCallback(retrofitService().fetchAsyncRequestDataWithErrorPayload(requestId)) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloan/useridentification/work/viewmodels/WorkVM.kt b/app/src/main/java/com/naviapp/personalloan/useridentification/work/viewmodels/WorkVM.kt index 0ad9b17489..d7bfeafe8e 100644 --- a/app/src/main/java/com/naviapp/personalloan/useridentification/work/viewmodels/WorkVM.kt +++ b/app/src/main/java/com/naviapp/personalloan/useridentification/work/viewmodels/WorkVM.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -10,17 +10,17 @@ package com.naviapp.personalloan.useridentification.work.viewmodels import android.text.TextUtils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.navi.common.viewmodel.BaseVM import com.navi.common.firebasedb.FirebaseStatusType +import com.navi.common.model.UploadDataAsyncResponse +import com.navi.common.network.models.GenericErrorResponse +import com.navi.common.network.models.GenericWarningResponse +import com.navi.common.viewmodel.BaseVM import com.naviapp.models.RedirectPageStatus import com.naviapp.models.request.WorkRequest import com.naviapp.models.response.CompanyNameResponse import com.naviapp.models.response.EmploymentTypeResponse -import com.navi.common.model.UploadDataAsyncResponse import com.naviapp.models.response.WorkDetailsResponse import com.naviapp.network.ApiErrorTagType.WORK_DETAILS_UPLOAD -import com.navi.common.model.GenericErrorResponse -import com.navi.common.model.GenericWarningResponse import com.naviapp.personalloan.useridentification.work.repositories.WorkRepository import com.naviapp.utils.getMoney import kotlinx.coroutines.launch @@ -53,7 +53,6 @@ class WorkVM(private val repository: WorkRepository = WorkRepository()) : BaseVM private val selectedEmploymentType = MutableLiveData(null) - fun submitWorkDetails( employmentType: String, professionType: String? = null, @@ -64,17 +63,18 @@ class WorkVM(private val repository: WorkRepository = WorkRepository()) : BaseVM ) { coroutineScope.launch { monthlyIncome.toDoubleOrNull()?.getMoney()?.let { - val workRequest = WorkRequest( - employmentType = employmentType, - professionType = professionType, - serviceType = null, - natureOfEmploymentType = null, - monthlyIncome = it, - companyName = companyName, - skipValidation = skipValidation, - workIndustry = null, - otherIncome = otherIncome.toDoubleOrNull()?.getMoney() - ) + val workRequest = + WorkRequest( + employmentType = employmentType, + professionType = professionType, + serviceType = null, + natureOfEmploymentType = null, + monthlyIncome = it, + companyName = companyName, + skipValidation = skipValidation, + workIndustry = null, + otherIncome = otherIncome.toDoubleOrNull()?.getMoney() + ) val response = repository.submitWorkDetails(workRequest) if (response.error == null) { if (TextUtils.equals(response.data?.status, FirebaseStatusType.FAILURE)) { @@ -89,19 +89,20 @@ class WorkVM(private val repository: WorkRepository = WorkRepository()) : BaseVM } } - fun fetchAsyncRequestDataWithError(requestId: String) = coroutineScope.launch { - val response = repository.getErrorPayload(requestId) - if (response.error == null && response.errors.isNullOrEmpty()) { - if (TextUtils.equals(response.data?.status, FirebaseStatusType.FAILURE)) { + fun fetchAsyncRequestDataWithError(requestId: String) = + coroutineScope.launch { + val response = repository.getErrorPayload(requestId) + if (response.error == null && response.errors.isNullOrEmpty()) { + if (TextUtils.equals(response.data?.status, FirebaseStatusType.FAILURE)) { + checkUiStatus(response.errors, response.warning) + return@launch + } + _dataAsyncResponse.value = response.data + } else { + _stopPolling.value = true checkUiStatus(response.errors, response.warning) - return@launch } - _dataAsyncResponse.value = response.data - } else { - _stopPolling.value = true - checkUiStatus(response.errors, response.warning) } - } fun fetchWorkDetailsData() { coroutineScope.launch { @@ -125,10 +126,7 @@ class WorkVM(private val repository: WorkRepository = WorkRepository()) : BaseVM } } - fun checkUiStatus( - errors: List?, - warning: GenericWarningResponse? - ) { + fun checkUiStatus(errors: List?, warning: GenericWarningResponse?) { coroutineScope.launch { val response = repository.checkUiStatus() if (response.error == null) { @@ -154,10 +152,10 @@ class WorkVM(private val repository: WorkRepository = WorkRepository()) : BaseVM } } - fun setSelectedEmploymentType(employmentTypeResponse: EmploymentTypeResponse){ + fun setSelectedEmploymentType(employmentTypeResponse: EmploymentTypeResponse) { selectedEmploymentType.value = employmentTypeResponse } fun getSelectedEmploymentType(): EmploymentTypeResponse? { return selectedEmploymentType.value } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/addressverificationrevamp/fragment/KycAddressV2Fragment.kt b/app/src/main/java/com/naviapp/personalloanrevamp/addressverificationrevamp/fragment/KycAddressV2Fragment.kt index 2563cce745..65c983fe1f 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/addressverificationrevamp/fragment/KycAddressV2Fragment.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/addressverificationrevamp/fragment/KycAddressV2Fragment.kt @@ -21,7 +21,7 @@ import com.navi.analytics.utils.NaviTrackEvent import com.navi.base.model.CtaData import com.navi.common.firebasedb.* import com.navi.common.listeners.LocationUpdateListener -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* import com.navi.design.font.FontWeightEnum diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/addressverificationrevamp/helper/AddressHelper.kt b/app/src/main/java/com/naviapp/personalloanrevamp/addressverificationrevamp/helper/AddressHelper.kt index 7ab8d00a8d..c6d309ba19 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/addressverificationrevamp/helper/AddressHelper.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/addressverificationrevamp/helper/AddressHelper.kt @@ -1,7 +1,14 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.personalloanrevamp.addressverificationrevamp.helper import com.navi.common.model.Action -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.naviapp.R import com.naviapp.app.NaviApplication import com.naviapp.models.request.Address @@ -9,10 +16,7 @@ import com.naviapp.models.response.CurrentAddress import com.naviapp.personalloan.getloan.kyc.fragments.KycFragment object AddressHelper { - fun getAddressFromCurrentAddress( - currentAddress: CurrentAddress, - current: Boolean - ): Address { + fun getAddressFromCurrentAddress(currentAddress: CurrentAddress, current: Boolean): Address { return Address( houseNumber = currentAddress.houseNumber, street = currentAddress.street, @@ -27,13 +31,15 @@ object AddressHelper { ) } - fun isValidRequestCode(requestCode: Int) = requestCode in listOf( - KycFragment.SELFIE_REQUEST_CODE, - KycFragment.PAN_CAMERA_REQUEST_CODE, - KycFragment.UPLOAD_AADHAR_REQUEST_CODE, - KycFragment.VIDEO_KYC_REQUEST_CODE, - KycFragment.AADHAR_OTP_REQUEST_CODE - ) + fun isValidRequestCode(requestCode: Int) = + requestCode in + listOf( + KycFragment.SELFIE_REQUEST_CODE, + KycFragment.PAN_CAMERA_REQUEST_CODE, + KycFragment.UPLOAD_AADHAR_REQUEST_CODE, + KycFragment.VIDEO_KYC_REQUEST_CODE, + KycFragment.AADHAR_OTP_REQUEST_CODE + ) fun getUploadDocumentErrorData(): GenericErrorResponse { val context = NaviApplication.instance @@ -46,4 +52,4 @@ object AddressHelper { } const val CORRESPONDENCE = "CORRESPONDENCE" -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/error/aactivity/ErrorScreenV2Activity.kt b/app/src/main/java/com/naviapp/personalloanrevamp/error/aactivity/ErrorScreenV2Activity.kt index d893c545cb..83f1cf16eb 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/error/aactivity/ErrorScreenV2Activity.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/error/aactivity/ErrorScreenV2Activity.kt @@ -17,10 +17,11 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import com.navi.analytics.utils.NaviTrackEvent import com.navi.base.model.CtaData +import com.navi.chat.utils.ChatPLScreens import com.navi.common.extensions.isNotNull import com.navi.common.extensions.orFalse -import com.navi.common.model.GenericErrorResponse import com.navi.common.model.ModuleNameV2 +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.activity.BaseActivity import com.navi.common.utils.log import com.navi.common.utils.observeNonNull @@ -42,6 +43,7 @@ import com.naviapp.personalloan.getloan.activities.GetLoanActivity import com.naviapp.personalloan.getloan.common.fragment.CustomerSupportFragment import com.naviapp.personalloanrevamp.error.fragments.ErrorV2Fragment import com.naviapp.personalloanrevamp.error.fragments.MFIErrorFragmentV2 +import com.naviapp.personalloanrevamp.getloanRevamp.helper.GetLoanV2ViewHelper import com.naviapp.personalloanrevamp.models.RejectionDetailsResponseV2 import com.naviapp.personalloanrevamp.useridentificationv2.activities.LoanEligibilityLoaderV2Activity.Companion.IS_UW_REJECTION import com.naviapp.utils.* @@ -64,6 +66,7 @@ class ErrorScreenV2Activity : BaseActivity(), NaviHeaderView.InteractionListener } private val analyticsEventTracker = NaviAnalytics.naviAnalytics.RatingDetail() private val helpEventTracker by lazy { NaviAnalytics.naviAnalytics.Faq() } + private var currentScreen: String = EMPTY override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -174,16 +177,30 @@ class ErrorScreenV2Activity : BaseActivity(), NaviHeaderView.InteractionListener putBoolean(ErrorActivity.IS_HOME_LOAN, isHomeLoan) } supportFragmentManager.beginTransaction().run { + updateCurrentScreen(getCurrentScreenName(data.first?.rejectReason)) replace(R.id.error_container_fl, fragment, tag) commit() } } + private fun getCurrentScreenName(rejectReason: String?): String { + return when (rejectReason) { + ErrorActivity.PROFILE_NOT_ELIGIBLE_DUE_TO_MFI, + OFFER_INELIGIBLE -> + NaviAnalytics.MFI_REJECTED_FRAGMENT_V2 + else -> + NaviAnalytics.COMMON_REJECTED_FRAGMENT_V2 + + } + } + private fun getFragment(rejectReason: String?, bundle: Bundle?): Fragment { return when (rejectReason) { ErrorActivity.PROFILE_NOT_ELIGIBLE_DUE_TO_MFI, - OFFER_INELIGIBLE -> MFIErrorFragmentV2() - else -> + OFFER_INELIGIBLE -> { + MFIErrorFragmentV2() + } + else ->{ ErrorV2Fragment().apply { arguments = Bundle().apply { @@ -193,9 +210,15 @@ class ErrorScreenV2Activity : BaseActivity(), NaviHeaderView.InteractionListener ) } } + } + } } + private fun updateCurrentScreen(screen: String) { + currentScreen = screen + } + private fun attachFragmentForRejection(data: RejectionDetailsResponseV2?) { val tag = getTag(data?.content?.rejectionCode) trackSoftRejectEvent(data?.content?.rejectionCode, data?.content?.rejectionCode) @@ -210,6 +233,7 @@ class ErrorScreenV2Activity : BaseActivity(), NaviHeaderView.InteractionListener putParcelable(REJECTION_DATA, data?.content) } supportFragmentManager.beginTransaction().run { + updateCurrentScreen(getCurrentScreenName(data?.content?.rejectionCode)) replace(R.id.error_container_fl, fragment, tag) commit() } @@ -310,8 +334,8 @@ class ErrorScreenV2Activity : BaseActivity(), NaviHeaderView.InteractionListener } override fun onHelpButtonPressed() { - helpEventTracker.onHelpButtonClick(screenName) - CustomerSupportFragment.newInstance(screenName, "") + helpEventTracker.onHelpButtonClick(currentScreen) + CustomerSupportFragment.newInstance(currentScreen, ChatPLScreens.PL_SOFT_REJECTION_SCREEN.name) .show(supportFragmentManager, CustomerSupportFragment.TAG) } diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/error/fragments/ErrorV2Fragment.kt b/app/src/main/java/com/naviapp/personalloanrevamp/error/fragments/ErrorV2Fragment.kt index 62bc9ee32c..726a08aaf6 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/error/fragments/ErrorV2Fragment.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/error/fragments/ErrorV2Fragment.kt @@ -14,11 +14,12 @@ import android.view.View import android.view.ViewGroup import androidx.core.content.res.ResourcesCompat import com.navi.base.model.CtaData -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.design.utils.GradientOrientation import com.navi.design.utils.getNaviDrawable import com.naviapp.R +import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.customview.NaviHeaderView import com.naviapp.common.navigator.NaviDeepLinkNavigator import com.naviapp.databinding.FragmentErrorV2Binding @@ -132,7 +133,7 @@ class ErrorV2Fragment : BaseFragment() { } override val screenName: String - get() = arguments?.getString(ERROR_SCREEN_NAME).orEmpty() + get() = NaviAnalytics.COMMON_REJECTED_FRAGMENT_V2 companion object { const val TAG = "ERROR_FRAGMENT_V2" diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/error/fragments/MFIErrorFragmentV2.kt b/app/src/main/java/com/naviapp/personalloanrevamp/error/fragments/MFIErrorFragmentV2.kt index e8045f867c..f2dbac7339 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/error/fragments/MFIErrorFragmentV2.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/error/fragments/MFIErrorFragmentV2.kt @@ -20,7 +20,7 @@ import com.navi.base.model.NaviClickAction import com.navi.common.extensions.isNotNull import com.navi.common.extensions.isNotNullAndNotEmpty import com.navi.common.extensions.orFalse -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.toCtaData import com.navi.design.utils.GradientOrientation @@ -208,7 +208,7 @@ class MFIErrorFragmentV2 : BaseFragment(), WidgetCallback { } override val screenName: String - get() = "MFI_REJECTED_FRAGMENT_V2" + get() = NaviAnalytics.MFI_REJECTED_FRAGMENT_V2 companion object { const val TAG = "MFI_REJECTED_FRAGMENT_V2" diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/activities/GetLoanV2Activity.kt b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/activities/GetLoanV2Activity.kt index 68a6ed5cc5..47943412d8 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/activities/GetLoanV2Activity.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/activities/GetLoanV2Activity.kt @@ -25,8 +25,8 @@ import com.navi.base.model.CtaData import com.navi.base.utils.BaseUtils import com.navi.chat.utils.ChatPLScreens import com.navi.common.firebasedb.FirebaseStatusType -import com.navi.common.model.GenericErrorResponse import com.navi.common.model.ModuleNameV2 +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.activity.BaseActivity import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.log diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/customview/OfferUpgradeCardV2View.kt b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/customview/OfferUpgradeCardV2View.kt new file mode 100644 index 0000000000..a0b1fdfcf4 --- /dev/null +++ b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/customview/OfferUpgradeCardV2View.kt @@ -0,0 +1,71 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.personalloanrevamp.getloanRevamp.customview + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.cardview.widget.CardView +import com.navi.design.utils.moveViewWithDistance +import com.navi.naviwidgets.widgets.textdisplay.Margin +import com.naviapp.R +import com.naviapp.databinding.OfferUpgradeCardV2ViewBinding +import com.naviapp.personalloanrevamp.getloanRevamp.listeners.LoanDetailsV2WidgetAdapterListener +import com.naviapp.personalloanrevamp.models.OfferUpgradeCardV2WidgetConfig +import com.naviapp.utils.Constants.OFFER_UPGRADE_CARD_V2_ANIMATION_DURATION +import com.naviapp.utils.setMargin + +class OfferUpgradeCardV2View(context: Context, attrs: AttributeSet? = null) : + CardView(context, attrs) { + + private val binding = + OfferUpgradeCardV2ViewBinding.inflate(LayoutInflater.from(context), this, true) + + init { + layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) + elevation = resources.getDimension(R.dimen.layout_dp_0) + radius = resources.getDimension(R.dimen.layout_dp_12) + } + + fun setProperties( + offerUpgradeCardWidgetConfig: OfferUpgradeCardV2WidgetConfig?, + listener: LoanDetailsV2WidgetAdapterListener? + ) { + offerUpgradeCardWidgetConfig?.let { widgetConfig -> + widgetConfig.widgetLayoutParams?.margin?.let { margin -> this.setMargin(margin) } + widgetConfig.widgetBody?.let { widgetBody -> + binding.offerBinder = widgetBody + widgetBody.description?.let { + binding.titleTv.setMargin( + Margin(startDp = 12.0f, topDp = 16.0f, endDp = 16.0f, bottomDp = 0.0f) + ) + binding.iconIv.setMargin( + Margin(startDp = 0.0f, topDp = 20.0f, endDp = 18.0f, bottomDp = 0.0f) + ) + binding.pgvShimmer.layoutParams.height = + resources.getDimension(R.dimen.layout_dp_96).toInt() + } + binding.offerUpgraderCardV2Cl.post { + moveViewWithDistance( + binding.pgvShimmer, + binding.offerUpgraderCardV2Cl.width, + OFFER_UPGRADE_CARD_V2_ANIMATION_DURATION + ) + } + } + } + binding.offerUpgraderCardV2Cl.setOnClickListener { + listener?.onCtaClick(offerUpgradeCardWidgetConfig?.widgetBody?.cta) + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + binding.unbind() + } +} diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/BankDetailsAutoDebitV2Fragment.kt b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/BankDetailsAutoDebitV2Fragment.kt index cbf7f709ad..473095cfa0 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/BankDetailsAutoDebitV2Fragment.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/BankDetailsAutoDebitV2Fragment.kt @@ -26,7 +26,7 @@ import com.navi.base.model.CtaData import com.navi.base.sharedpref.PreferenceManager import com.navi.common.firebasedb.* import com.navi.common.model.Action -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.ui.fragment.BaseFragment import com.navi.common.utils.* import com.naviapp.R diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/BankDetailsV2Fragment.kt b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/BankDetailsV2Fragment.kt index 988ca73d4d..21ef93b2c2 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/BankDetailsV2Fragment.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/BankDetailsV2Fragment.kt @@ -630,8 +630,8 @@ class BankDetailsV2Fragment : } if ( binding.bankAccountNumberLt.getUserInput().orEmpty().isBlank() || - binding.bankAccountNumberLt.getUserInput().orEmpty().length < - MIN_BANK_ACCOUNT_NUMBER_LENGTH + binding.bankAccountNumberLt.getUserInput().orEmpty().length < + MIN_BANK_ACCOUNT_NUMBER_LENGTH ) { setErrorProperties( binding.bankAccountNumberLt, @@ -641,7 +641,7 @@ class BankDetailsV2Fragment : } if ( binding.ifscLt.getUserInput().orEmpty().isBlank() || - binding.ifscLt.getUserInput().orEmpty().length != IFSC_CODE_LENGTH + binding.ifscLt.getUserInput().orEmpty().length != IFSC_CODE_LENGTH ) { setErrorProperties(binding.ifscLt, getString(R.string.enter_eleven_digit_code_message)) validated = false @@ -655,9 +655,9 @@ class BankDetailsV2Fragment : private fun enableConfirmIfRequired() { if ( binding.bankNameSearch.getText().orEmpty().isNotBlank() && - binding.bankAccountNumberLt.getUserInput().orEmpty().isNotBlank() && - binding.ifscLt.getUserInput().orEmpty().isNotBlank() && - binding.footerView.binding.checkboxCb.isChecked + binding.bankAccountNumberLt.getUserInput().orEmpty().isNotBlank() && + binding.ifscLt.getUserInput().orEmpty().isNotBlank() && + binding.footerView.binding.checkboxCb.isChecked ) { binding.footerView.setNextButtonEnable(true) } else { @@ -733,10 +733,10 @@ class BankDetailsV2Fragment : SelectBankV2Fragment.newInstance( binding.bankNameSearch.getText(), bankDisclaimerHeader = - viewModel.disbursementDetails.value - ?.disbursementDetails - ?.headersConfig - ?.bankSearchDisclaimerHeader + viewModel.disbursementDetails.value + ?.disbursementDetails + ?.headersConfig + ?.bankSearchDisclaimerHeader ) bankDetailFragment.setListener(this) safelyShowBottomSheet(bankDetailFragment, SelectBankV2Fragment.TAG) @@ -786,13 +786,22 @@ class BankDetailsV2Fragment : naviAnalyticsEventTracker.onBankNameSelect(bank.name, loanType, journeyType) val selectBankFragment = childFragmentManager.findFragmentByTag(SelectBankV2Fragment.TAG) - as? SelectBankV2Fragment + as? SelectBankV2Fragment selectBankFragment?.dismiss() + binding.bankDetailsBinder?.let { binding.bankDisclaimerView.bankDetailsLl.visibility = View.VISIBLE + if (viewModel.disbursementDetails.value?.disbursementDetails?.delayedDisbursementBankCodes?.contains( + bank.code + ).orFalse() + ) { + setDisclaimerView(viewModel.disbursementDetails.value?.disbursementDetails?.delayedDisbursmentDisclaimerHeader) + } else { + setDisclaimerView(viewModel.disbursementDetails.value?.disbursementDetails?.headersConfig?.bankNameDisclaimerHeader) + } } bank.name?.let { - binding.bankNameSearch.setText(it, false, false) + binding.bankNameSearch.setText(it, showSearchIcon = false, showCloseIcon = false) binding.bankNameSearch.setError(null) viewModel.toastId.value?.let { toastIdValue -> binding.root.findViewById(toastIdValue).visibility = View.GONE @@ -819,7 +828,7 @@ class BankDetailsV2Fragment : listener?.navigateTo( it, Bundle().apply { - putString(Constants.PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) + putString(PERSONAL_LOAN_APPLICATION_ID, loanApplicationId) } ) } diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/EmiSelectorV2Fragment.kt b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/EmiSelectorV2Fragment.kt index 9bc7c21ea7..f7ae930970 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/EmiSelectorV2Fragment.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/EmiSelectorV2Fragment.kt @@ -172,13 +172,13 @@ class EmiSelectorV2Fragment : BaseFragment(), BackListener { ?: run { startDate } if (startDate != null && endDate != null && defaultDate != null) { - binding.calendarList.initNaviCalendar(startDate, endDate, defaultDate) { + binding.calendarList.initNaviCalendar(startDate, endDate, defaultDate, callback = { analyticsEventTracker.onDateSelect( formatDateInto(it, Constants.DATE_FORMAT_YYYY_MM_DD) ) changeDescriptionText(it) selectedDate = it - } + }) } } diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/LoanDetailsV2Fragment.kt b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/LoanDetailsV2Fragment.kt index 5e646a6612..617fda2e9e 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/LoanDetailsV2Fragment.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/fragments/LoanDetailsV2Fragment.kt @@ -524,6 +524,7 @@ class LoanDetailsV2Fragment : } private fun handleNextCta(ctaData: CtaData?) { + handleCtaEvent(ctaData) val bundle = Bundle().apply { putBoolean(GetLoanActivity.IS_FOR_SECOND_LOAN_JOURNEY, true) @@ -538,6 +539,12 @@ class LoanDetailsV2Fragment : listener?.navigateTo(ctaData?.url.orEmpty(), bundle) } + private fun handleCtaEvent(ctaData: CtaData?) { + when (ctaData?.url.orEmpty()) { + OFFER_UPGRADE_V2 -> loanDetailsEventTracker.onOfferUpgradeCardClicked() + } + } + private fun signLoanAgreement() { viewModel.getLoanApplicationId()?.let { applicationId -> showLoader() @@ -623,6 +630,9 @@ class LoanDetailsV2Fragment : .plus(SubPageStatusType.BANK_DETAILS_AUTO_DEBIT) private const val BANK_DETAILS_CTA = NaviDeepLinkNavigator.LOAN_APPLICATION.plus("/").plus(SubPageStatusType.BANK_DETAILS) + private const val OFFER_UPGRADE_V2 = + NaviDeepLinkNavigator.LOAN_APPLICATION_V2.plus("/") + .plus(GetLoanV2ViewHelper.LOAN_OFFER_UPGRADE_V2) fun newInstance(arguments: Bundle?) = LoanDetailsV2Fragment().apply { this.arguments = arguments } diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/helper/GetLoanV2Helper.kt b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/helper/GetLoanV2Helper.kt index 655d288e5d..820eb24562 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/helper/GetLoanV2Helper.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/helper/GetLoanV2Helper.kt @@ -122,6 +122,7 @@ object GetLoanV2ViewHelper { TRUE_CALLER_AUTHENTICATOR_V2 -> NaviAnalytics.TRUE_CALLER_AUTHENTICATOR_SCREEN_V2 MONEY_DISBURSEMENT_STATUS_V2 -> NaviAnalytics.DELAYED_DISBURSEMENT_DETAILS_V2_SCREEN EFFECTIVE_INTEREST_COST_V2 -> NaviAnalytics.EFFECTIVE_INTEREST_COST_SCREEN_V2 + LOAN_OFFER_UPGRADE_V2 -> NaviAnalytics.LOAN_OFFER_UPGRADE_V2_SCREEN else -> EMPTY } } diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/repository/LoanDetailsV2Repository.kt b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/repository/LoanDetailsV2Repository.kt index 4ad9fb327a..e6ab7129b8 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/repository/LoanDetailsV2Repository.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/getloanRevamp/repository/LoanDetailsV2Repository.kt @@ -14,8 +14,7 @@ package com.naviapp.personalloanrevamp.getloanRevamp.repository * */ -import com.google.gson.reflect.TypeToken -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult import com.naviapp.models.UserProfile import com.naviapp.models.request.GenerateOfferRequest import com.naviapp.models.request.LoanFeeDetailsRequest @@ -23,23 +22,20 @@ import com.naviapp.models.request.LoanRequest import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.network.retrofit.RetrofitService import com.naviapp.personalloanrevamp.models.response.LoanDetailsV2Response -import com.naviapp.utils.mockApiResponse import com.naviapp.utils.retrofitService import javax.inject.Inject class LoanDetailsV2Repository @Inject constructor(private val retrofitService: RetrofitService) : ResponseCallback() { - suspend fun fetchLoanDetails(offerId: String): RepoResult { - return apiResponseCallback( - retrofitService().fetchLoanDetailsV2Response(offerId) - ) - } + suspend fun fetchLoanDetails(offerId: String): RepoResult { + return apiResponseCallback(retrofitService().fetchLoanDetailsV2Response(offerId)) + } -// suspend fun fetchLoanDetails(offerId: String): RepoResult { -// val type = object : TypeToken() {}.type -// return mockApiResponse(type, "loanDetailsSummary") -// } + // suspend fun fetchLoanDetails(offerId: String): RepoResult { + // val type = object : TypeToken() {}.type + // return mockApiResponse(type, "loanDetailsSummary") + // } suspend fun generateOffer(request: GenerateOfferRequest) = apiResponseCallback(retrofitService().generateOffer(request)) diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/kyc/listener/UpdateKycStateListener.kt b/app/src/main/java/com/naviapp/personalloanrevamp/kyc/listener/UpdateKycStateListener.kt index c5920e8fd8..db107a7ced 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/kyc/listener/UpdateKycStateListener.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/kyc/listener/UpdateKycStateListener.kt @@ -1,9 +1,16 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.personalloanrevamp.kyc.listener -import com.navi.common.model.GenericErrorResponse +import com.navi.common.network.models.GenericErrorResponse import com.naviapp.models.RedirectPageStatus interface UpdateKycStateListener { fun onKycSuccess(onAnimationEnd: () -> Unit) fun onKycFailure(data: Pair? = null) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/models/LoanDetailsV2WidgetType.kt b/app/src/main/java/com/naviapp/personalloanrevamp/models/LoanDetailsV2WidgetType.kt index d1a70f371b..3300f57c7e 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/models/LoanDetailsV2WidgetType.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/models/LoanDetailsV2WidgetType.kt @@ -6,17 +6,12 @@ */ package com.naviapp.personalloanrevamp.models -/* - * - * * Copyright © 2022 by Navi Technologies Private Limited - * * All rights reserved. Strictly confidential - * - */ enum class LoanDetailsV2WidgetType(val value: String) { STYLED_KEY_VALUE_CARD("STYLED_KEY_VALUE_CARD"), BANK_NAME_CARD("BANK_NAME_CARD"), OFFER_UPGRADE_CARD("OFFER_UPGRADE_CARD"), + OFFER_UPGRADE_CARD_V2("OFFER_UPGRADE_CARD_V2"), TITLE_WITH_BUTTON("TITLE_WITH_BUTTON"), SLIDER_WITH_TOOLTIP_TITLE("SLIDER_WITH_TOOLTIP_TITLE"), WIDGET_LIST_WITH_RADIO_BUTTON("WIDGET_LIST_WITH_RADIO_BUTTON"), @@ -30,4 +25,4 @@ enum class LoanDetailsV2WidgetType(val value: String) { HEADER_TITLE_VIEW("HEADER_TITLE_VIEW"), VIEW_CTA_WIDGET("VIEW_CTA_WIDGET"), OFFER_UPGRADED_CARD_WIDGET("OFFER_UPGRADED_CARD_WIDGET") -} +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/models/OfferUpgradeCardV2WidgetConfig.kt b/app/src/main/java/com/naviapp/personalloanrevamp/models/OfferUpgradeCardV2WidgetConfig.kt new file mode 100644 index 0000000000..669c58abbd --- /dev/null +++ b/app/src/main/java/com/naviapp/personalloanrevamp/models/OfferUpgradeCardV2WidgetConfig.kt @@ -0,0 +1,23 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.personalloanrevamp.models + +import com.google.gson.annotations.SerializedName +import com.navi.base.model.CtaData +import com.navi.common.model.StyledTextWithIconCode +import com.naviapp.models.response.WidgetConfig + +data class OfferUpgradeCardV2WidgetConfig( + @SerializedName("body") val widgetBody: OfferUpgradeCardV2WidgetBody? = null +) : WidgetConfig() + +data class OfferUpgradeCardV2WidgetBody( + @SerializedName("styledTitle") val title: StyledTextWithIconCode? = null, + @SerializedName("description") val description: String? = null, + @SerializedName("cta") val cta: CtaData? = null +) diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/useridentificationv2/activities/LoanEligibilityLoaderV2Activity.kt b/app/src/main/java/com/naviapp/personalloanrevamp/useridentificationv2/activities/LoanEligibilityLoaderV2Activity.kt index 0097143a4c..b1527da5bc 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/useridentificationv2/activities/LoanEligibilityLoaderV2Activity.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/useridentificationv2/activities/LoanEligibilityLoaderV2Activity.kt @@ -48,6 +48,8 @@ import com.naviapp.utils.Constants import com.naviapp.utils.Constants.FLOW_TYPE import com.naviapp.utils.Constants.IS_COMING_FROM_INREVIEW_PAGE import com.naviapp.utils.Constants.OFFER_GENERATION_FLOW +import com.naviapp.utils.Constants.PERMISSION_POLLING_INITIAL_DELAY +import com.naviapp.utils.Constants.PERMISSION_POLLING_INTERVAL import com.naviapp.utils.Constants.SUCCESS_ANIMATION_GREEN_BG_TIME import com.naviapp.utils.Constants.SUCCESS_ANIMATION_WHITE_BG_TIME @@ -78,7 +80,7 @@ class LoanEligibilityLoaderV2Activity : WifiTrackerBaseActivity() { initError( loanDetailsVM, actions = - listOf(Pair(handlePanDetailsFailedFromCibil, ApiErrorTagType.INVALID_PAN_DETAILS)), + listOf(Pair(handlePanDetailsFailedFromCibil, ApiErrorTagType.INVALID_PAN_DETAILS)), actionErrorV2Enabled = true ) initError(permissionViewModel, actionErrorV2Enabled = true) @@ -101,7 +103,7 @@ class LoanEligibilityLoaderV2Activity : WifiTrackerBaseActivity() { initError( viewModel = loanDetailsVM, actions = - listOf(Pair(handlePanDetailsFailedFromCibil, ApiErrorTagType.INVALID_PAN_DETAILS)), + listOf(Pair(handlePanDetailsFailedFromCibil, ApiErrorTagType.INVALID_PAN_DETAILS)), actionErrorV2Enabled = true ) } @@ -216,8 +218,8 @@ class LoanEligibilityLoaderV2Activity : WifiTrackerBaseActivity() { this, CtaData( url = - NaviDeepLinkNavigator.INTERMEDIATE.plus(Constants.DIVIDER) - .plus(SubPageStatusType.CIBIL_FAILURE) + NaviDeepLinkNavigator.INTERMEDIATE.plus(Constants.DIVIDER) + .plus(SubPageStatusType.CIBIL_FAILURE) ) ) loadTimeEventTracker.onLoadingCompleted( @@ -335,8 +337,16 @@ class LoanEligibilityLoaderV2Activity : WifiTrackerBaseActivity() { private fun apiPollInitPermission(uploadDataAsyncResponse: UploadDataAsyncResponse) { apiPollScheduler = ApiPollScheduler( + initialDelay = uploadDataAsyncResponse.requestConfig?.initialDelay?.toLong() + .orValue( + PERMISSION_POLLING_INITIAL_DELAY + ), + pollInterval = uploadDataAsyncResponse.requestConfig?.interval?.toLong() + .orValue( + PERMISSION_POLLING_INTERVAL + ), numberOfRetry = - uploadDataAsyncResponse.requestConfig?.numOfRetries.orValue(NUMBER_OF_RETRY) + uploadDataAsyncResponse.requestConfig?.numOfRetries.orValue(NUMBER_OF_RETRY) ) { permissionViewModel.fetchAsyncRequestData( uploadDataAsyncResponse.requestId.orEmpty() @@ -426,7 +436,7 @@ class LoanEligibilityLoaderV2Activity : WifiTrackerBaseActivity() { apiPollScheduler = ApiPollScheduler( numberOfRetry = - uploadDataAsyncResponse.requestConfig?.numOfRetries.orValue(NUMBER_OF_RETRY), + uploadDataAsyncResponse.requestConfig?.numOfRetries.orValue(NUMBER_OF_RETRY), doOnTimeout = { if (type == PRE_ELIGIBILITY) { perfUtils.sendEventWithTimeStamp( @@ -509,7 +519,7 @@ class LoanEligibilityLoaderV2Activity : WifiTrackerBaseActivity() { private fun statusHandling(status: String) { if ( TextUtils.equals(status, FirebaseStatusType.SUCCESS) || - TextUtils.equals(status, FirebaseStatusType.FAILURE) + TextUtils.equals(status, FirebaseStatusType.FAILURE) ) { deInitializeAsyncListeners() apiPollScheduler?.stopApiPoll() @@ -643,6 +653,7 @@ class LoanEligibilityLoaderV2Activity : WifiTrackerBaseActivity() { override fun onAnimationEnd(p0: Animator?) { navigateToNextScreen() } + override fun onAnimationCancel(p0: Animator?) {} override fun onAnimationRepeat(p0: Animator?) {} } @@ -665,4 +676,4 @@ class LoanEligibilityLoaderV2Activity : WifiTrackerBaseActivity() { private const val AMOUNT_VIEW_ANIMATION_DELAY = 500L private const val NEXT_SCREEN_TRANSITION_DELAY = AMOUNT_VIEW_ANIMATION_DELAY + 1000L } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/personalloanrevamp/useridentificationv2/repository/PersonalLoanTrackerRepository.kt b/app/src/main/java/com/naviapp/personalloanrevamp/useridentificationv2/repository/PersonalLoanTrackerRepository.kt index eaf1857731..3d9862039f 100644 --- a/app/src/main/java/com/naviapp/personalloanrevamp/useridentificationv2/repository/PersonalLoanTrackerRepository.kt +++ b/app/src/main/java/com/naviapp/personalloanrevamp/useridentificationv2/repository/PersonalLoanTrackerRepository.kt @@ -1,22 +1,28 @@ +/* + * + * * Copyright © 2022 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + package com.naviapp.personalloanrevamp.useridentificationv2.repository -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult import com.naviapp.network.retrofit.ResponseCallback import com.naviapp.network.retrofit.RetrofitService import com.naviapp.personalloanrevamp.models.response.PersonalLoanTrackerResponse import com.naviapp.utils.retrofitService import javax.inject.Inject - -class PersonalLoanTrackerRepository @Inject constructor(private val retrofitService: RetrofitService) : - ResponseCallback() { +class PersonalLoanTrackerRepository +@Inject +constructor(private val retrofitService: RetrofitService) : ResponseCallback() { suspend fun fetchPersonalLoanStatusTracker(): RepoResult = apiResponseCallback(retrofitService().fetchPersonalLoanTrackerResponse()) - /*suspend fun fetchPersonalLoanStatusTracker(): RepoResult { val type = object : TypeToken() {}.type return mockApiResponse(type, "personalLoanTrackerResponse") }*/ -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/pushnotification/NotificationReceiverActivity.kt b/app/src/main/java/com/naviapp/pushnotification/NotificationReceiverActivity.kt new file mode 100644 index 0000000000..386d024eb8 --- /dev/null +++ b/app/src/main/java/com/naviapp/pushnotification/NotificationReceiverActivity.kt @@ -0,0 +1,39 @@ +package com.naviapp.pushnotification + +import android.app.NotificationManager +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import com.navi.base.utils.isNotNullAndNotEmpty +import com.navi.common.model.ModuleNameV2 +import com.navi.common.ui.activity.BaseActivity +import com.naviapp.analytics.utils.NaviAnalytics +import com.naviapp.registration.SplashActivity +import com.naviapp.utils.NotificationConstants + +class NotificationReceiverActivity : BaseActivity() { + + override val screenName: String + get() = NaviAnalytics.NOTIFICATION_RECEIVER_ACTIVITY + override val moduleName: ModuleNameV2 + get() = ModuleNameV2.COMMON + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + intent?.let { + val manager = getSystemService(NOTIFICATION_SERVICE) as? NotificationManager + manager?.cancel(it.getIntExtra(NotificationConstants.NOTIFICATION_ID, -1)) + + val actionIntent: Intent + if (it.getStringExtra(NotificationConstants.URL).isNotNullAndNotEmpty()) { + actionIntent = Intent(Intent.ACTION_VIEW, Uri.parse(it.getStringExtra(NotificationConstants.URL))) + } else { + actionIntent = Intent(this, SplashActivity::class.java) + } + actionIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + intent.extras?.let { it1 -> actionIntent.putExtras(it1) } + startActivity(actionIntent) + finish() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/pushnotification/firebase/NaviFirebaseMessagingService.kt b/app/src/main/java/com/naviapp/pushnotification/firebase/NaviFirebaseMessagingService.kt index 3a3033b14c..5f2424f955 100644 --- a/app/src/main/java/com/naviapp/pushnotification/firebase/NaviFirebaseMessagingService.kt +++ b/app/src/main/java/com/naviapp/pushnotification/firebase/NaviFirebaseMessagingService.kt @@ -12,9 +12,15 @@ import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.drawable.Drawable import android.media.RingtoneManager import android.os.Build import androidx.core.app.NotificationCompat +import com.bumptech.glide.Glide +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import com.navi.analytics.moengage.MoengageUtil @@ -31,6 +37,7 @@ import com.navi.insurance.notifications.GiNotificationHandler import com.naviapp.R import com.naviapp.common.navigator.NaviDeepLinkNavigator.CHAT_ACTIVITY import com.naviapp.pushnotification.NotificationHandler +import com.naviapp.pushnotification.NotificationReceiverActivity import com.naviapp.registration.SplashActivity import com.naviapp.utils.Constants import com.naviapp.utils.Constants.DELIVERED @@ -46,6 +53,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch +import org.json.JSONArray import timber.log.Timber @ExperimentalCoroutinesApi @@ -141,35 +149,102 @@ class NaviFirebaseMessagingService : FirebaseMessagingService() { return } } - val pendingIntent = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - - PendingIntent.getActivity( - this, - 0 /* Request code */, - intent, - PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT - ) - } else { - PendingIntent.getActivity( - this, - 0 /* Request code */, - intent, - PendingIntent.FLAG_UPDATE_CURRENT - ) - } + val pendingIntent = getPendingIntentForActivity(intent) val channelId = getString(R.string.default_notification_channel_id) + val notificationId = getNotificationId() val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val notificationBuilder = NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.notifiaction_icon_small) // TODO; icon needs to be changed + .setLargeIcon( + BitmapFactory.decodeResource( + resources, + R.drawable.notifiaction_icon_large + ) + ) .setContentTitle(title) .setContentText(messageBody) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent) + data?.get(NotificationConstants.ACTION_BUTTON)?.let { + val actionBtns = JSONArray(data[NotificationConstants.ACTION_BUTTON]) + for (i in 0..1) { + if (i < actionBtns.length()) { + val action = actionBtns.getJSONObject(i) + val actionText = action.getString(NotificationConstants.ACTION_TEXT) + val actionUrl = action.getString(NotificationConstants.URL) + val actionIntent = Intent(this, NotificationReceiverActivity::class.java) + actionIntent.putExtra(NotificationConstants.NOTIFICATION_ID, notificationId) + intent.extras?.let { it1 -> actionIntent.putExtras(it1) } + actionIntent.putExtra(NotificationConstants.URL, actionUrl) + notificationBuilder.addAction( + 0, actionText, + getPendingIntentForActivity(actionIntent) + ) + } + } + } + if (data?.get(NotificationConstants.IMAGE).isNullOrEmpty()) { + notificationBuilder.setStyle( + NotificationCompat.BigTextStyle() + .bigText(messageBody) + ) + notifyNotification(channelId, notificationId, title, notificationBuilder) + } else { + Glide.with(this) + .asBitmap() + .load(data?.get(NotificationConstants.IMAGE)) + .into(object : CustomTarget() { + override fun onResourceReady(resource: Bitmap, transition: Transition?) { + notificationBuilder.setStyle( + NotificationCompat.BigPictureStyle() + .bigPicture(resource) + ) + notifyNotification(channelId, notificationId, title, notificationBuilder) + } + + override fun onLoadCleared(placeholder: Drawable?) { + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + super.onLoadFailed(errorDrawable) + notificationBuilder.setStyle( + NotificationCompat.BigTextStyle() + .bigText(messageBody) + ) + notifyNotification(channelId, notificationId, title, notificationBuilder) + } + }) + } + } + + private fun getPendingIntentForActivity(intent: Intent): PendingIntent { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + return PendingIntent.getActivity( + this, + 0 /* Request code */, + intent, + PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + ) + } else { + return PendingIntent.getActivity( + this, + 0 /* Request code */, + intent, + PendingIntent.FLAG_UPDATE_CURRENT + ) + } + } + + private fun notifyNotification( + channelId: String, + notificationId: Int, + title: String, + notificationBuilder: NotificationCompat.Builder + ) { val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager @@ -181,7 +256,7 @@ class NaviFirebaseMessagingService : FirebaseMessagingService() { } notificationManager?.notify( - getNotificationId() /* ID of notification */, + notificationId /* ID of notification */, notificationBuilder.build() ) } diff --git a/app/src/main/java/com/naviapp/registration/OtpFragment.kt b/app/src/main/java/com/naviapp/registration/OtpFragment.kt index 8fc99e5dae..04c529eaec 100644 --- a/app/src/main/java/com/naviapp/registration/OtpFragment.kt +++ b/app/src/main/java/com/naviapp/registration/OtpFragment.kt @@ -37,6 +37,7 @@ import com.naviapp.dashboard.listeners.FragmentInteractionListener import com.naviapp.databinding.OtpFragmentBinding import com.naviapp.models.request.DeviceDetail import com.naviapp.models.request.LoginType +import com.naviapp.models.request.OtpRequest import com.naviapp.models.request.WifiDetails import com.naviapp.network.ApiErrorTagType import com.naviapp.registration.RegistrationActivity.Companion.LOGIN_SCREEN @@ -296,16 +297,22 @@ class OtpFragment : BaseFragment(), View.OnClickListener { ) ) apiCallLastTime = System.currentTimeMillis() + val otpRequest = + OtpRequest( + otp = binding.otpLayout.getText(), + otpToken = latestOtpToken, + otpAutofill = isAutoFetchOtp, + loginType = LoginType.OTP.name, + deviceDetail = deviceDetail, + source = arguments?.getString(LOGIN_SOURCE), + parameters = getParameters(), + installDeeplinkData = PreferenceManager.getSecureString(com.navi.common.utils.Constants.OFFER_VALUE) + .orEmpty() + ) registrationVM.verifyOtp( - binding.otpLayout.getText(), - latestOtpToken, - isAutoFetchOtp, - LoginType.OTP.name, - deviceDetail, - source = arguments?.getString(LOGIN_SOURCE), - parameters = getParameters(), + otpRequest, density = getDensityName(context = requireContext()).orEmpty(), - connectivityType = getNetworkType(context = requireContext()) + connectivityType = getNetworkType(context = requireContext()), ) } } diff --git a/app/src/main/java/com/naviapp/registration/RegistrationActivity.kt b/app/src/main/java/com/naviapp/registration/RegistrationActivity.kt index ccc100dc48..3c608c78d9 100644 --- a/app/src/main/java/com/naviapp/registration/RegistrationActivity.kt +++ b/app/src/main/java/com/naviapp/registration/RegistrationActivity.kt @@ -46,6 +46,7 @@ import com.naviapp.databinding.RegistrationActivityBinding import com.naviapp.models.TrueProfileData import com.naviapp.models.request.DeviceDetail import com.naviapp.models.request.LoginType +import com.naviapp.models.request.OtpRequest import com.naviapp.models.request.WifiDetails import com.naviapp.models.response.Medium import com.naviapp.models.response.NotificationSettings @@ -258,19 +259,25 @@ class RegistrationActivity : allowMockLocations = isLastLocationMocked(), clonedDetails = FraudUtil.getCloneDetails(applicationContext), appInstanceId = - PreferenceManager.getStringPreference( - CommonPrefConstants.FIREBASE_APP_INSTANCE - ), + PreferenceManager.getStringPreference( + CommonPrefConstants.FIREBASE_APP_INSTANCE + ), wifiDetails = - PreferenceManager.getObjectPrefrences( - com.naviapp.utils.Constants.WIFI_DETAILS, - WifiDetails::class.java - ) + PreferenceManager.getObjectPrefrences( + com.naviapp.utils.Constants.WIFI_DETAILS, + WifiDetails::class.java + ) ) - registrationVM.loginViaTrueCaller( - data = data, + val otpRequest = OtpRequest( + truecallerProfileData = data, + loginType = LoginType.TRUE_CALLER.name, source = source, deviceDetail = deviceDetail, + installDeeplinkData = PreferenceManager.getSecureString(Constants.OFFER_VALUE) + .orEmpty() + ) + registrationVM.loginViaTrueCaller( + otpRequest = otpRequest, density = getDensityName(context = this).orEmpty(), connectivityType = getNetworkType(context = this) ) @@ -375,6 +382,7 @@ class RegistrationActivity : } } hideLoader() + PreferenceManager.removeSecureKey(Constants.OFFER_VALUE) goToNextScreen(otpResponse.nextCta) } .addOnFailureListener { diff --git a/app/src/main/java/com/naviapp/registration/viewmodel/RegistrationVM.kt b/app/src/main/java/com/naviapp/registration/viewmodel/RegistrationVM.kt index 79f44cd283..8351ee3d91 100644 --- a/app/src/main/java/com/naviapp/registration/viewmodel/RegistrationVM.kt +++ b/app/src/main/java/com/naviapp/registration/viewmodel/RegistrationVM.kt @@ -10,15 +10,16 @@ package com.naviapp.registration.viewmodel import android.text.TextUtils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.navi.base.model.LineItem import com.navi.base.utils.BaseUtils import com.navi.common.firebasedb.FirebaseStatusType -import com.navi.common.model.GenericErrorResponse import com.navi.common.model.InAppUpdateResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.viewmodel.BaseVM import com.naviapp.models.TrueCallerDropCallData -import com.naviapp.models.TrueProfileData -import com.naviapp.models.request.* +import com.naviapp.models.request.LoginRequest +import com.naviapp.models.request.LoginType +import com.naviapp.models.request.OtpRequest +import com.naviapp.models.request.PtpSubmitRequest import com.naviapp.models.response.* import com.naviapp.network.ApiConstants.API_EXPIRED_OTP import com.naviapp.network.ApiConstants.API_TOO_MANY_REQUESTS @@ -145,26 +146,10 @@ class RegistrationVM(private val registerRepository: RegisterRepository = Regist } fun verifyOtp( - otp: String, - otpToken: String, - isAutoFetchOtp: Boolean, - loginType: String, - deviceDetail: DeviceDetail, - source: String?, - parameters: List?, + otpRequest: OtpRequest, density: String, connectivityType: String ) { - val otpRequest = - OtpRequest( - otp = otp, - otpToken = otpToken, - otpAutofill = isAutoFetchOtp, - loginType = loginType, - deviceDetail = deviceDetail, - source = source, - parameters = parameters - ) coroutineScope.launch { val response = registerRepository.verifyOtp( @@ -197,22 +182,14 @@ class RegistrationVM(private val registerRepository: RegisterRepository = Regist } fun loginViaTrueCaller( - data: TrueProfileData, - source: String?, - deviceDetail: DeviceDetail, + otpRequest: OtpRequest, density: String, connectivityType: String ) { coroutineScope.launch { val response = registerRepository.verifyOtp( - otpRequest = - OtpRequest( - truecallerProfileData = data, - loginType = LoginType.TRUE_CALLER.name, - source = source, - deviceDetail = deviceDetail - ), + otpRequest = otpRequest, density = density, connectivityType = connectivityType ) diff --git a/app/src/main/java/com/naviapp/usernotification/repositories/UserNotificationRepository.kt b/app/src/main/java/com/naviapp/usernotification/repositories/UserNotificationRepository.kt index affc2bf779..256a219845 100644 --- a/app/src/main/java/com/naviapp/usernotification/repositories/UserNotificationRepository.kt +++ b/app/src/main/java/com/naviapp/usernotification/repositories/UserNotificationRepository.kt @@ -1,14 +1,14 @@ /* * - * * Copyright © 2019 by Navi Technologies Private Limited + * * Copyright © 2019-2022 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ package com.naviapp.usernotification.repositories +import com.navi.common.network.models.RepoResult import com.naviapp.models.response.UserNotificationResponse -import com.navi.common.model.RepoResult import com.naviapp.network.retrofit.ResponseCallback class UserNotificationRepository : ResponseCallback() { @@ -16,4 +16,4 @@ class UserNotificationRepository : ResponseCallback() { // Remove this when api is implemented return RepoResult() } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/naviapp/utils/Constants.kt b/app/src/main/java/com/naviapp/utils/Constants.kt index 7f79434af4..c3466ee214 100644 --- a/app/src/main/java/com/naviapp/utils/Constants.kt +++ b/app/src/main/java/com/naviapp/utils/Constants.kt @@ -8,6 +8,7 @@ package com.naviapp.utils object Constants { + const val PREFERENCE = "PREFERENCE" const val SECONDS_PER_MINUTE = 60 const val MILLISECONDS_PER_SECOND = 1000 const val OTP_COUNTDOWN_IN_SECOND = 30 @@ -274,6 +275,7 @@ object Constants { const val REQUEST_ID = "requestId" const val VERIFICATION_PENDING = "PENDING" const val SHOW_BOTTOMSHEET = "show_bottomsheet" + const val GI_INFO_BOTTOMSHEET = "gi_info_bottomsheet" const val DASHBOARD_POLICY_LIST_BOTTOM_SHEET = "dashboard_policy_list_bottom_sheet" const val POLICY_BENEFIT_TYPE = "POLICY_BENEFIT_TYPE" const val POLICY_ID = "policyId" @@ -292,6 +294,13 @@ object Constants { const val MANDATE_CHANGE = "mandateChange" const val AUTO_DEBIT_BACK = "AUTO_DEBIT_BACK" const val CARD_GROUP_REFERENCE_ID = "cardGroupReferenceId" + const val SHOW_BOTTOM_SHEET = "showBottomSheet" + const val COMMON_BOTTOM_SHEET_ID = "commonBottomSheet" + const val SELL_GOLD = "SELL_GOLD" + const val GOLD = "gold" + const val BUY_GOLD = "BUY_GOLD" + const val SELL_GOLD_FRAGMENT = "sellScreen" + const val SELL_GOLD_UPI_FRAGMENT = "upiScreen" const val SELECTABLE_OPTION_CLICK = "selectableOptionClick" const val IS_REVAMP_FLOW = "IS_REVAMP_FLOW" const val SUCCESS_ANIMATION_WHITE_BG_TIME = 400L @@ -307,8 +316,25 @@ object Constants { const val CONVERSATION_ID = "conversationId" const val SKIP_TUTORIAL_SCREEN = "SKIP_TUTORIAL_SCREEN" const val PENDING = "PENDING" + const val OFFER_VIEWED = "OFFER_VIEWED" + const val APP = "APP" + const val OFFER_UPGRADE_CARD_V2_ANIMATION_DURATION = 2000L + const val PERMISSION_POLLING_INITIAL_DELAY = 1L + const val PERMISSION_POLLING_INTERVAL = 5L + const val REFUND_AMOUNT = "REFUND_AMOUNT" + const val REFUND_DATE = "REFUND_DATE" + const val NEGATIVE_FORECLOSURE = "NEGATIVE_FORECLOSURE" enum class JourneyType(val type: String) { POST_PURCHASE("post_purchase") } + + enum class FlowType(val type: String) { + PART_PRE_PAYMENT("PART_PRE_PAYMENT"), + INTEREST_RATE_RESET("INTEREST_RATE_RESET") + } + + enum class MetaDataKey(val value: String) { + METADATA_REPO_RATE_BOTTOM_SHEET("repoRateBottomSheetInfo") + } } diff --git a/app/src/main/java/com/naviapp/utils/CustomJsonDeserializers.kt b/app/src/main/java/com/naviapp/utils/CustomJsonDeserializers.kt index ff5bad56a4..fcdf8f7fb7 100644 --- a/app/src/main/java/com/naviapp/utils/CustomJsonDeserializers.kt +++ b/app/src/main/java/com/naviapp/utils/CustomJsonDeserializers.kt @@ -34,6 +34,9 @@ class WidgetConfigDeserializer : JsonDeserializer { LoanDetailsV2WidgetType.OFFER_UPGRADE_CARD.value -> { Gson().fromJson(jsonObject, OfferUpgradeCardWidgetConfig::class.java) } + LoanDetailsV2WidgetType.OFFER_UPGRADE_CARD_V2.value -> { + Gson().fromJson(jsonObject, OfferUpgradeCardV2WidgetConfig::class.java) + } LoanDetailsV2WidgetType.TITLE_WITH_BUTTON.value -> { Gson().fromJson(jsonObject, TitleWithButtonWidgetConfig::class.java) } diff --git a/app/src/main/java/com/naviapp/utils/IconUtils.kt b/app/src/main/java/com/naviapp/utils/IconUtils.kt index 8178bc0ce6..329464b934 100644 --- a/app/src/main/java/com/naviapp/utils/IconUtils.kt +++ b/app/src/main/java/com/naviapp/utils/IconUtils.kt @@ -283,6 +283,7 @@ object IconUtils { private const val ICON_ARROW_FORWARD_BLACK = "ICON_ARROW_FORWARD_BLACK" private const val ICON_DARK_BLUE_INFO = "ICON_DARK_BLUE_INFO" private const val OUTLINED_INFO_ICON_BLACK = "OUTLINED_INFO_ICON_BLACK" + const val CALENDAR_WITH_TIME = "calendar_with_time" private const val ICON_SUCCESS = "ICON_SUCCESS" fun updateIcon(imageDetail: ImageDetail, imageView: ImageView) { @@ -575,6 +576,7 @@ object IconUtils { ICON_ARROW_FORWARD_BLACK -> R.drawable.ic_arrow_forward_black ICON_DARK_BLUE_INFO -> R.drawable.ic_dark_blue_info OUTLINED_INFO_ICON_BLACK -> R.drawable.ic_info_icon_black + CALENDAR_WITH_TIME -> R.drawable.calendar_with_time ICON_SUCCESS -> R.drawable.ic_success_icon else -> -1 } diff --git a/app/src/main/java/com/naviapp/utils/MockUtil.kt b/app/src/main/java/com/naviapp/utils/MockUtil.kt index c0da96aba1..88b215b6b4 100644 --- a/app/src/main/java/com/naviapp/utils/MockUtil.kt +++ b/app/src/main/java/com/naviapp/utils/MockUtil.kt @@ -10,7 +10,7 @@ package com.naviapp.utils import com.google.gson.GsonBuilder import com.google.gson.JsonObject import com.google.gson.JsonParser -import com.navi.common.model.RepoResult +import com.navi.common.network.models.RepoResult import com.navi.naviwidgets.models.NaviWidget import com.navi.naviwidgets.models.ParameterValue import com.navi.naviwidgets.validations.BaseInputValidation diff --git a/app/src/main/java/com/naviapp/utils/NotificationConstants.kt b/app/src/main/java/com/naviapp/utils/NotificationConstants.kt index 6eb6530dbf..1ca90e2c12 100644 --- a/app/src/main/java/com/naviapp/utils/NotificationConstants.kt +++ b/app/src/main/java/com/naviapp/utils/NotificationConstants.kt @@ -15,4 +15,9 @@ object NotificationConstants { const val TITLE = "title" const val BODY = "body" const val MODULE= "module" + const val IMAGE = "image" + const val ACTION_BUTTON = "actionButton" + const val ACTION_TEXT = "actionText" + const val URL = "url" + const val NOTIFICATION_ID = "NOTIFICATION_ID" } \ No newline at end of file diff --git a/app/src/main/java/com/naviapp/utils/PrefConstants.kt b/app/src/main/java/com/naviapp/utils/PrefConstants.kt index d388a839dc..55e20b5f39 100644 --- a/app/src/main/java/com/naviapp/utils/PrefConstants.kt +++ b/app/src/main/java/com/naviapp/utils/PrefConstants.kt @@ -14,6 +14,7 @@ const val BANK_NAME = "BANK_NAME" const val FCM_TOKEN_LAST_UPDATED_TIME = "FCM_TOKEN_LAST_UPDATED_TIME" const val PRODUCT_CODE = "PRODUCT_CODE" const val LOAN_ACCOUNT_NUMBER = "LOAN_ACCOUNT_NUMBER" +const val CLOSURE_TYPE = "CLOSURE_TYPE" const val AMOUNT_DATA = "AMOUNT_DATA" const val PAYMENT_DATE = "PAYMENT_DATE" const val OFFER_ID = "OFFER_ID" diff --git a/app/src/main/java/com/naviapp/utils/SmsUtil.kt b/app/src/main/java/com/naviapp/utils/SmsUtil.kt index d1a2b95462..85fa5e9dbe 100644 --- a/app/src/main/java/com/naviapp/utils/SmsUtil.kt +++ b/app/src/main/java/com/naviapp/utils/SmsUtil.kt @@ -16,12 +16,14 @@ import com.google.gson.Gson import com.navi.analytics.newrelic.NewRelicEventLogger import com.navi.analytics.newrelic.NewrelicConstants.SMS_READ_ import com.navi.analytics.newrelic.NewrelicConstants.SMS_UPLOAD_ +import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper import com.navi.common.model.UserDataWrapper import com.navi.common.model.UserSms import com.navi.common.model.UserSmsData import com.navi.common.utils.Constants.UNDERSCORE import com.navi.common.utils.gzipCompress import com.navi.common.utils.log +import com.navi.insurance.util.FirebaseRemoteConfigUtils import com.naviapp.R import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.app.NaviApplication @@ -98,26 +100,32 @@ object SmsUtil { private suspend fun postSmsAndClearList( smsList: MutableList, totalPages: Int, - pageNumber: Int + pageNumber: Int, + retryCount: Int = 0 ) { perfUtils.startNewRelicInteraction(SMS_UPLOAD_.plus(pageNumber.toString())) analyticsTrackerSmsUpload.smsUploadStartTime(pageNumber) val request = UserDataWrapper(totalPages, pageNumber, smsList) - analyticsTrackerSmsUpload.onSmsUploadStart(totalPages, pageNumber, smsList.size) + analyticsTrackerSmsUpload.onSmsUploadStart(totalPages, pageNumber, smsList.size , retryCount) val response = UserDataRepository().postSms(request) perfUtils.endInteraction(SMS_UPLOAD_.plus(pageNumber.toString())) - analyticsTrackerSmsUpload.smsUploadEndTime(pageNumber) + analyticsTrackerSmsUpload.smsUploadEndTime(pageNumber , retryCount) response.error?.let { Exception(NaviApplication.instance.applicationContext.getString(R.string.network_error_installed_app) + UNDERSCORE + it.statusCode).log() analyticsTrackerSmsUpload.onSmsUploadFailure( totalPages, pageNumber, smsList.size, - it.statusCode + it.statusCode, ) + if (retryCount < FirebaseRemoteConfigUtils.getLong(FirebaseRemoteConfigHelper.RETRY_COUNT_OF_SMS_INGESTION)) { + postSmsAndClearList(smsList, totalPages, pageNumber, retryCount = retryCount + 1) + return + } + } ?: run { + smsList.clear() + analyticsTrackerSmsUpload.onSmsUploadSuccess(totalPages, pageNumber, smsList.size , retryCount) } - smsList.clear() - analyticsTrackerSmsUpload.onSmsUploadSuccess(totalPages, pageNumber, smsList.size) } private fun executeQueryToReadSms(applicationContext: Context): Cursor? { diff --git a/app/src/main/java/com/naviapp/utils/Utility.kt b/app/src/main/java/com/naviapp/utils/Utility.kt index d6fdf0ac22..7132ed3b25 100644 --- a/app/src/main/java/com/naviapp/utils/Utility.kt +++ b/app/src/main/java/com/naviapp/utils/Utility.kt @@ -36,7 +36,11 @@ import com.navi.base.model.LineItem import com.navi.base.sharedpref.PreferenceManager import com.navi.base.utils.BaseUtils import com.navi.common.juspay.HyperServicesHolder -import com.navi.common.model.* +import com.navi.common.model.ClickableTextType +import com.navi.common.model.EmailSubjectBodyResponse +import com.navi.common.model.ModuleNameV2 +import com.navi.common.model.PhoneNumberResponse +import com.navi.common.network.models.GenericErrorResponse import com.navi.common.utils.* import com.navi.common.utils.Constants.LOGIN_SOURCE import com.navi.insurance.navigator.NaviInsuranceDeeplinkNavigator diff --git a/app/src/main/res/drawable/bg_golden_sour_gradient.xml b/app/src/main/res/drawable/bg_golden_sour_gradient.xml new file mode 100644 index 0000000000..90cfc3e7c1 --- /dev/null +++ b/app/src/main/res/drawable/bg_golden_sour_gradient.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/calendar_with_time.xml b/app/src/main/res/drawable/calendar_with_time.xml new file mode 100644 index 0000000000..5ca13aeeb9 --- /dev/null +++ b/app/src/main/res/drawable/calendar_with_time.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_orange_tick_small.xml b/app/src/main/res/drawable/ic_orange_tick_small.xml new file mode 100644 index 0000000000..b91a71a709 --- /dev/null +++ b/app/src/main/res/drawable/ic_orange_tick_small.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/main/res/layout/activity_digital_gold_buy.xml b/app/src/main/res/layout/activity_digital_gold_buy.xml new file mode 100644 index 0000000000..8bff91e4c7 --- /dev/null +++ b/app/src/main/res/layout/activity_digital_gold_buy.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_digital_gold_home.xml b/app/src/main/res/layout/activity_digital_gold_home.xml new file mode 100644 index 0000000000..8b0e470700 --- /dev/null +++ b/app/src/main/res/layout/activity_digital_gold_home.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_digital_gold_sell.xml b/app/src/main/res/layout/activity_digital_gold_sell.xml new file mode 100644 index 0000000000..4cb4949cb4 --- /dev/null +++ b/app/src/main/res/layout/activity_digital_gold_sell.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_digital_gold_transaction.xml b/app/src/main/res/layout/activity_digital_gold_transaction.xml new file mode 100644 index 0000000000..104350d391 --- /dev/null +++ b/app/src/main/res/layout/activity_digital_gold_transaction.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_interest_reset.xml b/app/src/main/res/layout/activity_interest_reset.xml new file mode 100644 index 0000000000..a7dd00f191 --- /dev/null +++ b/app/src/main/res/layout/activity_interest_reset.xml @@ -0,0 +1,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_sheet_info_v3.xml b/app/src/main/res/layout/bottom_sheet_info_v3.xml new file mode 100644 index 0000000000..d64792bb24 --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_info_v3.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dashboard_insurance_bottomsheet.xml b/app/src/main/res/layout/dashboard_insurance_bottomsheet.xml new file mode 100644 index 0000000000..df8a8d0d33 --- /dev/null +++ b/app/src/main/res/layout/dashboard_insurance_bottomsheet.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + +