diff --git a/app/build.gradle b/app/build.gradle index b36046fc80..f8543a8dda 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,14 +6,16 @@ apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' + def version_retrofit = '2.6.2' def version_kotlin_coroutines = '1.3.2' + android { compileSdkVersion 29 buildToolsVersion "29.0.2" defaultConfig { - applicationId "com.navi.medici.android_customer_app" + applicationId "com.navi.medici.androidCustomerApp" minSdkVersion 21 targetSdkVersion 29 versionCode 1 @@ -46,8 +48,8 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' - implementation 'com.google.android.material:material:1.0.0' implementation 'com.android.support:cardview-v7:29.0.2' implementation 'com.android.support:design:29.0.2' implementation 'com.jakewharton.timber:timber:4.7.1' + implementation 'com.navi.medici.utils:amortization:1.1-SNAPSHOT' } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/EmiScheduleAdapter.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/EmiScheduleAdapter.kt new file mode 100644 index 0000000000..8f16b71d7e --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/EmiScheduleAdapter.kt @@ -0,0 +1,83 @@ +package com.navi.medici.androidCustomerApp.adapters + +import android.content.Context +import android.graphics.Typeface +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.navi.medici.androidCustomerApp.databinding.EmiScheduleCardBinding +import com.navi.medici.androidCustomerApp.models.EmiSchedule +import java.text.SimpleDateFormat +import java.util.* + + +class EmiScheduleAdapter(private val context: Context) : + RecyclerView.Adapter() { + private val emiScheduleList = mutableListOf() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmiScheduleViewHolder { + val layoutInflater = LayoutInflater.from(parent.context) + val view = EmiScheduleCardBinding.inflate(layoutInflater, parent, false) + return EmiScheduleViewHolder(view) + } + + fun setLoans(emiScheduleList: List) { + this.emiScheduleList.clear() + this.emiScheduleList.addAll(emiScheduleList) + notifyDataSetChanged() + } + + override fun getItemCount() = emiScheduleList.count() + + override fun onBindViewHolder(holder: EmiScheduleViewHolder, position: Int) { + val emiSchedule = emiScheduleList[position] + holder.binding.apply { + when { + position == 0 -> { + emiNoTxt.text = "No." + emiAmountTxt.text = "EMI Amount" + emiDueDateTxt.text = "Due Date" + emiNoTxt.typeface = Typeface.DEFAULT_BOLD + emiAmountTxt.typeface = Typeface.DEFAULT_BOLD + emiDueDateTxt.typeface = Typeface.DEFAULT_BOLD + } + else -> { + emiNoTxt.text = position.toString() + emiAmountTxt.text = + emiSchedule.emi?.symbol.toString() + " " + emiSchedule.emi?.amount.toString() + emiDueDateTxt.text = convertDueDate("2019-11-13T12:23:36.087+0000") + } + } + } + } + + fun convertDueDate(dueDate: String): String { + val tz = TimeZone.getTimeZone("UTC") + val df = + SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ") // Quoted "Z" to indicate UTC, no timezone offset + df.setTimeZone(tz) + val parsedDate = df.parse(dueDate) + + var cal = Calendar.getInstance() + cal.time = parsedDate + + val format2 = + SimpleDateFormat("dd'" + getDayNumberSuffix(cal.get(Calendar.DAY_OF_MONTH)) + "' MMM yyyy") + return format2.format(parsedDate) + } + + private fun getDayNumberSuffix(day: Int): String { + if (day >= 11 && day <= 13) { + return "th" + } + when (day % 10) { + 1 -> return "st" + 2 -> return "nd" + 3 -> return "rd" + else -> return "th" + } + } + + class EmiScheduleViewHolder(val binding: EmiScheduleCardBinding) : + RecyclerView.ViewHolder(binding.root) +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/LoanDetailsTabAdapter.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/LoanDetailsTabAdapter.kt index 391b589ab0..71018420d0 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/LoanDetailsTabAdapter.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/LoanDetailsTabAdapter.kt @@ -29,7 +29,7 @@ class LoanDetailsTabAdapter(fm: FragmentManager) : return when (position) { 0 -> "Loan Details" else -> { - "EMI Schedule" + "EMI Schedule" } } } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/LoanReasonAdapter.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/LoanReasonAdapter.kt new file mode 100644 index 0000000000..1331021cc4 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/adapters/LoanReasonAdapter.kt @@ -0,0 +1,55 @@ +package com.navi.medici.androidCustomerApp.adapters + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.TextView +import com.navi.medici.androidCustomerApp.R +import com.navi.medici.androidCustomerApp.models.LoanReason + + +class LoanReasonAdapter(val context: Context, var loanReasonList: List) : + BaseAdapter() { + + val mInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val vh: ItemRowHolder + if (convertView == null) { + view = mInflater.inflate(R.layout.loan_reason, parent, false) + vh = ItemRowHolder(view) + view?.tag = vh + } else { + view = convertView + vh = view.tag as ItemRowHolder + } + + // setting adapter item height programatically. + vh.label.text = loanReasonList.get(position).reason + return view + } + + + override fun getCount(): Int { + return loanReasonList.size + } + + override fun getItem(position: Int): Any { + return loanReasonList.get(position) + } + + override fun getItemId(position: Int): Long { + return loanReasonList.get(position).id.toLong() + } + + private class ItemRowHolder(row: View?) { + val label: TextView + init { + this.label = row?.findViewById(R.id.loan_reason_txt) as TextView + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/api/LoanApplicationApi.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/api/LoanApplicationApi.kt index 351d441746..8224c5384d 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/api/LoanApplicationApi.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/api/LoanApplicationApi.kt @@ -1,29 +1,44 @@ package com.navi.medici.androidCustomerApp.api import com.navi.medici.androidCustomerApp.common.RetrofitService -import com.navi.medici.androidCustomerApp.bottomNavigation.loanApplication.models.OfferResponse -import com.navi.medici.androidCustomerApp.loan_application.models.OfferSelected -import com.navi.medici.androidCustomerApp.loan_application.models.OfferAcceptResponse +import com.navi.medici.androidCustomerApp.models.ApplicationSummary +import com.navi.medici.androidCustomerApp.models.OfferResponse +import com.navi.medici.androidCustomerApp.models.OfferSelected +import com.navi.medici.androidCustomerApp.models.response.CreateApplicationResponse +import com.navi.medici.androidCustomerApp.models.response.OfferAcceptResponse import retrofit2.Response import retrofit2.http.* private const val BASE_URL = "https://loan-origination-service.np.navi-tech.in" - +//private const val BASE_URL = "http://192.168.31.220:3020" interface LoanApplicationApi { @PUT("/los/apply-loan") suspend fun acceptOffer( @Body offerData: OfferSelected? ): Response + @PUT("/los/application") + suspend fun createApplication( + @Body offerData: OfferSelected? + ): Response + @GET("/los/offers") suspend fun fetchOffer( @Query("person_id") personId: String? ): Response + + @GET("/los/application/summary") + suspend fun fetchApplicationSummary( + @Query("application_id") applicationId: String? + ): Response + + companion object { operator fun invoke(): LoanApplicationApi { return RetrofitService.build(BASE_URL).create( - LoanApplicationApi::class.java) + LoanApplicationApi::class.java + ) } } } \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/api/LoginApi.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/api/LoginApi.kt index 6a1da06246..218ee5385d 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/api/LoginApi.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/api/LoginApi.kt @@ -8,6 +8,7 @@ import retrofit2.http.Body import retrofit2.http.POST private const val BASE_URL = "https://auth-service.np.navi-tech.in" +//private const val BASE_URL = "http://192.168.31.220:3020" interface LoginApi { @POST("/auth/otps/generate") diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/api/MyLoansApi.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/api/MyLoansApi.kt index a0911c7e0d..21435b891c 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/api/MyLoansApi.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/api/MyLoansApi.kt @@ -7,6 +7,7 @@ import retrofit2.http.GET import retrofit2.http.Query private const val BASE_URL = "https://loan-accounts-service.np.navi-tech.in" +//private const val BASE_URL = "http://192.168.31.220:3020" interface MyLoansApi { @GET("/v1/loan-account-service/loan-accounts") diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/api/OtpApi.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/api/OtpApi.kt index 30b5fc34a1..13baf5d1be 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/api/OtpApi.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/api/OtpApi.kt @@ -8,6 +8,7 @@ import retrofit2.http.Body import retrofit2.http.POST private const val BASE_URL = "https://auth-service.np.navi-tech.in" +//private const val BASE_URL = "http://192.168.31.220:3020" interface OtpApi { @POST("/auth/tokens") diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/api/RegisterApi.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/api/RegisterApi.kt index 5e4869e964..6d53151f75 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/api/RegisterApi.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/api/RegisterApi.kt @@ -8,7 +8,7 @@ import retrofit2.http.Body import retrofit2.http.PUT private const val BASE_URL = "https://auth-service.np.navi-tech.in" - +//private const val BASE_URL = "http://192.168.31.220:3020" interface RegisterApi { @PUT("/auth/app-installations/register") suspend fun checkDevice(@Body registerRequest: RegisterRequest): Response diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/ApplicationSummary.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/ApplicationSummary.kt new file mode 100644 index 0000000000..eef21a142a --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/ApplicationSummary.kt @@ -0,0 +1,8 @@ +package com.navi.medici.androidCustomerApp.models + +data class ApplicationSummary( + var applicationId: String? = "", + var installments: List, + var loanApplicationDetails: LoanApplicationDetail +) { +} diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/EmiSchedule.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/EmiSchedule.kt new file mode 100644 index 0000000000..edbc5591c7 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/EmiSchedule.kt @@ -0,0 +1,4 @@ +package com.navi.medici.androidCustomerApp.models + +data class EmiSchedule(val emi: Money?, val numberOfMonthsRemaining: Int, val dueDate: String) { +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanAmount.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanAmount.kt index 2e1606efed..f7d210713e 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanAmount.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanAmount.kt @@ -1,9 +1,7 @@ package com.navi.medici.androidCustomerApp.models -import com.navi.medici.androidCustomerApp.bottomNavigation.loanApplication.models.response.Money - class LoanAmount( - val min: Money?, - val max: Money? + val min: Money, + val max: Money ) { } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanApplicationDetail.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanApplicationDetail.kt new file mode 100644 index 0000000000..837755853f --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanApplicationDetail.kt @@ -0,0 +1,15 @@ +package com.navi.medici.androidCustomerApp.models + +import java.math.BigDecimal + +data class LoanApplicationDetail( + val id: Int, + val loanAmount: Money, + val reason: String, + val tenure: TenureDetails, + val rateOfInterest: BigDecimal, + val personId: String, + val offerId: String, + val tenureValue: Int, + val customerId: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanReason.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanReason.kt new file mode 100644 index 0000000000..12ef1fd380 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/LoanReason.kt @@ -0,0 +1,4 @@ +package com.navi.medici.androidCustomerApp.models + +data class LoanReason(val id: Int, val reason: String) { +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/Money.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/Money.kt index c52e1105d3..f03cdfceeb 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/models/Money.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/Money.kt @@ -1,8 +1,14 @@ -package com.navi.medici.androidCustomerApp.bottomNavigation.loanApplication.models.response +package com.navi.medici.androidCustomerApp.models + +import java.math.BigDecimal data class Money( val currency: String?, val symbol: String?, - val amount: Int + val amount: BigDecimal ) { + + fun getDisplayStr(): String { + return "$symbol. $amount" + } } \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferResponse.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferResponse.kt index 54b6224ad6..d30fcc7c6c 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferResponse.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferResponse.kt @@ -1,13 +1,15 @@ -package com.navi.medici.androidCustomerApp.bottomNavigation.loanApplication.models +package com.navi.medici.androidCustomerApp.models import com.navi.medici.androidCustomerApp.models.LoanAmount import com.navi.medici.androidCustomerApp.models.OfferTenure +import java.math.BigDecimal data class OfferResponse( var schemeId: String? = "", var personId: String? = "", - var loanAmount: LoanAmount?, + var loanAmount: LoanAmount, var tenure: OfferTenure?, - var rateOfInterest: Double + var rateOfInterest: BigDecimal, + var loanReasons: List ) { } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferSelected.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferSelected.kt index 80e631a3cd..6f21483287 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferSelected.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferSelected.kt @@ -1,13 +1,14 @@ -package com.navi.medici.androidCustomerApp.loan_application.models +package com.navi.medici.androidCustomerApp.models -import com.navi.medici.androidCustomerApp.bottomNavigation.loanApplication.models.response.Money +import java.math.BigDecimal data class OfferSelected( var personId: String? = "", var offerId: String? = "", var loanAmount: Money?, var tenure: TenureDetails?, - var rateOfInterest: Double? = 0.0 + var rateOfInterest: BigDecimal? = BigDecimal(0), + var selectionReasonId: Long? ) { } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferTenure.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferTenure.kt index a83efc8de2..884508a858 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferTenure.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/OfferTenure.kt @@ -1,7 +1,5 @@ package com.navi.medici.androidCustomerApp.models -import com.navi.medici.androidCustomerApp.loan_application.models.TenureDetails - class OfferTenure( val min: TenureDetails?, val max: TenureDetails? diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/TenureDetails.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/TenureDetails.kt index 06b986eb63..03f7c84ab0 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/models/TenureDetails.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/TenureDetails.kt @@ -1,7 +1,10 @@ -package com.navi.medici.androidCustomerApp.loan_application.models +package com.navi.medici.androidCustomerApp.models data class TenureDetails( val value: Int = 0, val unit: String = "" ) { + fun getDisplayStr(): String { + return "$value $unit" + } } \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/TenureUnit.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/TenureUnit.kt new file mode 100644 index 0000000000..adb65360fc --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/TenureUnit.kt @@ -0,0 +1,20 @@ +package com.navi.medici.androidCustomerApp.models + + +enum class TenureUnit(val unit: String) { + MONTH("months"), + DAYS("days"), + HOURS("hrs"); + + // TODO: update it to a map + companion object { + fun getTenureUnitByValue(unit: String): TenureUnit { + return when (unit) { + "months" -> MONTH + "days" -> DAYS + "hrs" -> HOURS + else -> MONTH + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/response/CreateApplicationResponse.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/response/CreateApplicationResponse.kt new file mode 100644 index 0000000000..088e2bf719 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/response/CreateApplicationResponse.kt @@ -0,0 +1,4 @@ +package com.navi.medici.androidCustomerApp.models.response + +data class CreateApplicationResponse(val applicationId: String?) { +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/models/response/OfferAcceptResponse.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/models/response/OfferAcceptResponse.kt index 8ef8bcac35..0d6919407e 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/models/response/OfferAcceptResponse.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/models/response/OfferAcceptResponse.kt @@ -1,4 +1,4 @@ -package com.navi.medici.androidCustomerApp.loan_application.models +package com.navi.medici.androidCustomerApp.models.response data class OfferAcceptResponse( val customerId: String? = "" diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceManager.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceManager.kt index c369732410..cca0c3213a 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceManager.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceManager.kt @@ -1,38 +1,52 @@ package com.navi.medici.androidCustomerApp.preferences +import android.app.Activity import android.content.Context -import android.content.SharedPreferences object PreferenceManager { - val PREFS_FILENAME = "com.navi.medici.android_customer_app.preferences" - - fun getStringPreference(context: Context, preference: PreferenceNames): String? { - val sharedPref: SharedPreferences = - context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE) - return sharedPref.getString(preference.name, "") + fun getPersonId(context: Context): String? { + return PreferenceWrapper.getStringPreference( + context, + PreferenceNames.PERSON_ID + ) } - fun setStringPreference(context: Context, preference: PreferenceNames, value: String?) { - val sharedPref: SharedPreferences = - context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE) - val editor = sharedPref.edit() - editor.putString(preference.name, value) - editor.apply() + fun getCustomerId(context: Context): String? { + return PreferenceWrapper.getStringPreference( + context, + PreferenceNames.CUSTOMER_ID + ) } - - fun getIntPreference(context: Context, preference: PreferenceNames): Int { - val sharedPref: SharedPreferences = - context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE) - return sharedPref.getInt(preference.name, 0) + fun getApplicationId(context: Context): String? { + return PreferenceWrapper.getStringPreference( + context, + PreferenceNames.CUSTOMER_ID + ) } - fun setIntPreference(context: Context, preference: PreferenceNames, value: Int) { - val sharedPref: SharedPreferences = - context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE) - val editor = sharedPref.edit() - editor.putInt(preference.name, value) - editor.apply() + fun saveCustomerId(customerId: String?, activity: Activity) { + PreferenceWrapper.setStringPreference( + activity, + PreferenceNames.CUSTOMER_ID, + customerId + ) + } + + fun savePersonId(personId: String?, activity: Activity) { + PreferenceWrapper.setStringPreference( + activity, + PreferenceNames.PERSON_ID, + personId + ) + } + + fun saveApplicationId(applicationId: String?, activity: Activity) { + PreferenceWrapper.setStringPreference( + activity, + PreferenceNames.APPLICATION_ID, + applicationId + ) } fun getBooleanPreference( diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceNames.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceNames.kt index 263fff7ff0..059a9b2faa 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceNames.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceNames.kt @@ -7,5 +7,6 @@ enum class PreferenceNames { APPROVED_AMOUT, IMEI, PHONE_NUMBER, - NOT_FIRST_TIME_USER + NOT_FIRST_TIME_USER, + APPLICATION_ID } \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceWrapper.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceWrapper.kt new file mode 100644 index 0000000000..a8cad8a170 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/preferences/PreferenceWrapper.kt @@ -0,0 +1,37 @@ +package com.navi.medici.androidCustomerApp.preferences + +import android.content.Context +import android.content.SharedPreferences + +object PreferenceWrapper { + val PREFS_FILENAME = "com.navi.medici.androidCustomerApp.preferences" + + fun getStringPreference(context: Context, preference: PreferenceNames): String? { + val sharedPref: SharedPreferences = + context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE) + return sharedPref.getString(preference.name, "") + } + + fun setStringPreference(context: Context, preference: PreferenceNames, value: String?) { + val sharedPref: SharedPreferences = + context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE) + val editor = sharedPref.edit() + editor.putString(preference.name, value) + editor.apply() + } + + + fun getIntPreference(context: Context, preference: PreferenceNames): Int { + val sharedPref: SharedPreferences = + context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE) + return sharedPref.getInt(preference.name, 0) + } + + fun setIntPreference(context: Context, preference: PreferenceNames, value: Int) { + val sharedPref: SharedPreferences = + context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE) + val editor = sharedPref.edit() + editor.putInt(preference.name, value) + editor.apply() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/repositories/LoanApplicationRepository.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/repositories/LoanApplicationRepository.kt index 9d1ea33ddd..919c06e335 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/repositories/LoanApplicationRepository.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/repositories/LoanApplicationRepository.kt @@ -1,9 +1,11 @@ package com.navi.medici.androidCustomerApp.loan_application import com.navi.medici.androidCustomerApp.api.LoanApplicationApi -import com.navi.medici.androidCustomerApp.loan_application.models.OfferSelected +import com.navi.medici.androidCustomerApp.models.OfferSelected class LoanApplicationRepository(private val loanApplicationApi: LoanApplicationApi) { suspend fun offerAccept(offerAcceptInput: OfferSelected?) = suspend { loanApplicationApi.acceptOffer(offerAcceptInput) }.invoke() + suspend fun createApplication(offerAcceptInput: OfferSelected?) = suspend { loanApplicationApi.createApplication(offerAcceptInput) }.invoke() suspend fun fetchOffer(personId: String?) = suspend { loanApplicationApi.fetchOffer(personId) }.invoke() + suspend fun fetchApplicationSummary(applicationId: String?) = suspend { loanApplicationApi.fetchApplicationSummary(applicationId) }.invoke() } \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/BottomNavigationActivity.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/BottomNavigationActivity.kt index 0f4c8de98a..9ff3706923 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/BottomNavigationActivity.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/BottomNavigationActivity.kt @@ -8,6 +8,7 @@ import com.navi.medici.androidCustomerApp.R import com.navi.medici.androidCustomerApp.ui.fragments.OfferAcceptFragment import com.navi.medici.androidCustomerApp.ui.fragments.MyLoansFragment import com.navi.medici.androidCustomerApp.databinding.ActivityBottomNavigationBinding +import com.navi.medici.androidCustomerApp.ui.fragments.PreliminaryOfferFragment class BottomNavigationActivity : FragmentActivity() { @@ -21,12 +22,14 @@ class BottomNavigationActivity : FragmentActivity() { navigateToPage(it.itemId) } - var tagId = intent.getStringExtra("TAG_ID"); - if(tagId != null && tagId.equals(MyLoansFragment.TAG)) { - binding.bottomNavigationView.selectedItemId = R.id.my_loans - } else { - binding.bottomNavigationView.selectedItemId = R.id.home + var tagId = intent.getStringExtra("TAG_ID") + binding.bottomNavigationView.selectedItemId = when (tagId) { + MyLoansFragment.TAG -> R.id.my_loans + OfferAcceptFragment.TAG -> R.id.offer_accept + PreliminaryOfferFragment.TAG -> R.id.preliminary_offer + else -> R.id.home } + } private fun navigateToPage(itemId: Int): Boolean { @@ -46,16 +49,18 @@ class BottomNavigationActivity : FragmentActivity() { private fun getFragment(itemId: Int): Fragment { return when (itemId) { - R.id.home -> OfferAcceptFragment() + R.id.home -> PreliminaryOfferFragment() R.id.my_loans -> MyLoansFragment() + R.id.preliminary_offer -> PreliminaryOfferFragment() else -> OfferAcceptFragment() } } private fun getFragmentTag(itemId: Int): String { return when (itemId) { - R.id.home -> MyLoansFragment.TAG + R.id.home -> PreliminaryOfferFragment.TAG R.id.my_loans -> OfferAcceptFragment.TAG + R.id.preliminary_offer -> PreliminaryOfferFragment.TAG else -> MyLoansFragment.TAG } } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/LoginActivity.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/LoginActivity.kt index f12b012bd2..98ead0b012 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/LoginActivity.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/LoginActivity.kt @@ -11,6 +11,7 @@ import com.navi.medici.androidCustomerApp.R import com.navi.medici.androidCustomerApp.databinding.ActivityLoginBinding import com.navi.medici.androidCustomerApp.preferences.PreferenceManager import com.navi.medici.androidCustomerApp.preferences.PreferenceNames +import com.navi.medici.androidCustomerApp.preferences.PreferenceWrapper import com.navi.medici.androidCustomerApp.utils.showServiceNotAvailableToast import com.navi.medici.androidCustomerApp.viewModels.LoginViewModel @@ -27,7 +28,7 @@ class LoginActivity : AppCompatActivity() { loginViewModel.otpTokenAndPhone.observe(this, loggedInObserver()) binding.phoneEdit.addTextChangedListener { - PreferenceManager.getStringPreference( + PreferenceWrapper.getStringPreference( this, PreferenceNames.IMEI )?.let { imei -> @@ -41,7 +42,7 @@ class LoginActivity : AppCompatActivity() { private fun loggedInObserver(): Observer> { return Observer { otpTokenAndPhone -> - PreferenceManager.setStringPreference( + PreferenceWrapper.setStringPreference( this, PreferenceNames.PHONE_NUMBER, otpTokenAndPhone.second diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/OtpActivity.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/OtpActivity.kt index f3d368628a..22e0bc62fe 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/OtpActivity.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/OtpActivity.kt @@ -1,6 +1,5 @@ package com.navi.medici.androidCustomerApp.ui.activities -import android.app.Activity import android.content.Intent import android.os.Bundle import android.widget.Toast @@ -13,6 +12,7 @@ import com.navi.medici.androidCustomerApp.R import com.navi.medici.androidCustomerApp.databinding.ActivityOtpBinding import com.navi.medici.androidCustomerApp.preferences.PreferenceManager import com.navi.medici.androidCustomerApp.preferences.PreferenceNames +import com.navi.medici.androidCustomerApp.preferences.PreferenceWrapper import com.navi.medici.androidCustomerApp.viewModels.OtpViewModel class OtpActivity : AppCompatActivity() { @@ -25,7 +25,7 @@ class OtpActivity : AppCompatActivity() { binding = DataBindingUtil.setContentView(this, R.layout.activity_otp) otpViewModel = ViewModelProviders.of(this).get(OtpViewModel::class.java) - val phoneNumber = PreferenceManager.getStringPreference( + val phoneNumber = PreferenceWrapper.getStringPreference( this, PreferenceNames.PHONE_NUMBER ) @@ -53,7 +53,7 @@ class OtpActivity : AppCompatActivity() { private fun verifiedOtpObserver(): Observer { return Observer { if (it) { - savePersonId(otpViewModel.personId, this) + PreferenceManager.savePersonId(otpViewModel.personId, this) val intent = Intent(this, UploadPanActivity::class.java) startActivity(intent) } else { @@ -61,12 +61,4 @@ class OtpActivity : AppCompatActivity() { } } } - - private fun savePersonId(personId: String?, activity: Activity) { - PreferenceManager.setStringPreference( - activity, - PreferenceNames.PERSON_ID, - personId - ) - } } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/SplashScreenActivity.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/SplashScreenActivity.kt index 94f1a56f2e..a878271e55 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/SplashScreenActivity.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/activities/SplashScreenActivity.kt @@ -17,6 +17,7 @@ import androidx.lifecycle.ViewModelProviders import com.navi.medici.androidCustomerApp.R import com.navi.medici.androidCustomerApp.preferences.PreferenceManager import com.navi.medici.androidCustomerApp.preferences.PreferenceNames +import com.navi.medici.androidCustomerApp.preferences.PreferenceWrapper import com.navi.medici.androidCustomerApp.utils.showServiceNotAvailableToast import com.navi.medici.androidCustomerApp.viewModels.SplashScreenViewModel @@ -72,7 +73,7 @@ class SplashScreenActivity : AppCompatActivity() { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { getImei().let { splashScreenViewModel.checkDevice(it) - PreferenceManager.setStringPreference( + PreferenceWrapper.setStringPreference( this, PreferenceNames.IMEI, it diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/EmiScheduleFragment.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/EmiScheduleFragment.kt index ca7323b630..eb241f39f4 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/EmiScheduleFragment.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/EmiScheduleFragment.kt @@ -1,7 +1,46 @@ package com.navi.medici.androidCustomerApp.ui.fragments +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import androidx.recyclerview.widget.LinearLayoutManager +import com.navi.medici.androidCustomerApp.R +import com.navi.medici.androidCustomerApp.adapters.EmiScheduleAdapter +import com.navi.medici.androidCustomerApp.databinding.EmiScheduleFragmentBinding +import com.navi.medici.androidCustomerApp.viewModels.OfferAcceptViewModel class EmiScheduleFragment : Fragment() { + private lateinit var binding: EmiScheduleFragmentBinding + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val activity = activity as FragmentActivity + val viewModel = + ViewModelProviders.of(activity).get(OfferAcceptViewModel::class.java) + binding = DataBindingUtil.inflate( + inflater, + R.layout.emi_schedule_fragment, + container, + false + ) + + + viewModel.applicationSummary.observe(this, Observer { summary -> + val emiScheduleAdapter = EmiScheduleAdapter(activity) + emiScheduleAdapter.setLoans(summary.installments) + binding.emiScheduleRecyclerView.layoutManager = LinearLayoutManager(activity) + binding.emiScheduleRecyclerView.adapter = emiScheduleAdapter + }) + + return binding.root + } } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/LoanDetailsFragment.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/LoanDetailsFragment.kt index 2ccc49168a..863c25fd23 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/LoanDetailsFragment.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/LoanDetailsFragment.kt @@ -32,10 +32,16 @@ class LoanDetailsFragment : Fragment() { false ) - viewModel.offerSelected.observe(this, Observer { offer -> - binding.totalAmount.setText(offer.loanAmount?.symbol.toString() + ". " + offer.loanAmount?.amount.toString()) + viewModel.applicationSummary.observe(this, Observer { summary -> + binding.loanAmountTxt.setText(summary.loanApplicationDetails.loanAmount.symbol + " " + summary.loanApplicationDetails.loanAmount.amount.toInt().toString()) + binding.interestTxt.setText(summary.loanApplicationDetails.rateOfInterest.toString() + "%") + binding.emiTxt.setText(summary.installments[0].emi?.amount?.toInt().toString()) }) +// viewModel.offerSelected.observe(this, Observer { offer -> +// binding.totalAmount.setText(offer.loanAmount?.symbol.toString() + ". " + offer.loanAmount?.loanAmount.toString()) +// }) + return binding.root } } diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/MyLoansFragment.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/MyLoansFragment.kt index 7d75283246..bf57a4ef6f 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/MyLoansFragment.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/MyLoansFragment.kt @@ -1,6 +1,5 @@ package com.navi.medici.androidCustomerApp.ui.fragments -import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -12,11 +11,10 @@ import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.LinearLayoutManager import com.navi.medici.androidCustomerApp.R import com.navi.medici.androidCustomerApp.adapters.MyLoansAdapter -import com.navi.medici.androidCustomerApp.models.response.MyLoansResponse -import com.navi.medici.androidCustomerApp.viewModels.MyLoansViewModel import com.navi.medici.androidCustomerApp.databinding.MyLoansFragmentBinding +import com.navi.medici.androidCustomerApp.models.response.MyLoansResponse import com.navi.medici.androidCustomerApp.preferences.PreferenceManager -import com.navi.medici.androidCustomerApp.preferences.PreferenceNames +import com.navi.medici.androidCustomerApp.viewModels.MyLoansViewModel class MyLoansFragment : Fragment() { private lateinit var viewModel: MyLoansViewModel @@ -58,17 +56,11 @@ class MyLoansFragment : Fragment() { ) ) - viewModel.fetchMyLoans(getCustomerId(it)) + viewModel.fetchMyLoans(PreferenceManager.getCustomerId(it)) } return binding.root } - private fun getCustomerId(context: Context): String? { - return PreferenceManager.getStringPreference( - context, - PreferenceNames.CUSTOMER_ID - ) - } private fun myLoansObserver( myActiveLoansAdapter: MyLoansAdapter, diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/OfferAcceptFragment.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/OfferAcceptFragment.kt index 30c66035da..f773b5855a 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/OfferAcceptFragment.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/OfferAcceptFragment.kt @@ -1,11 +1,12 @@ package com.navi.medici.androidCustomerApp.ui.fragments -import android.app.Activity import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.animation.Animation +import android.view.animation.AnimationUtils import android.widget.Toast import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment @@ -21,6 +22,7 @@ import com.navi.medici.androidCustomerApp.preferences.PreferenceNames import com.navi.medici.androidCustomerApp.ui.activities.BottomNavigationActivity import com.navi.medici.androidCustomerApp.viewModels.OfferAcceptViewModel + class OfferAcceptFragment : Fragment() { private lateinit var viewModel: OfferAcceptViewModel private lateinit var binding: OfferAcceptFragmentBinding @@ -50,13 +52,15 @@ class OfferAcceptFragment : Fragment() { binding.offerAcceptViewpager.adapter = fragmentAdapter binding.tabLayout.setupWithViewPager(binding.offerAcceptViewpager) + val activity = activity as FragmentActivity viewModel = ViewModelProviders.of(activity).get(OfferAcceptViewModel::class.java) - viewModel.fetchOffers(getPersonId(activity)) + animateLoanApproval() + viewModel.fetchApplication(PreferenceManager.getApplicationId(activity)) binding.acceptOfferBtn.setOnClickListener { if (binding.checkbox.isChecked) { - viewModel.onSubmitOfferAccept() + viewModel.onSubmitOfferAccept(PreferenceManager.getPersonId(activity)) } else { var errorMessage = Toast.makeText( activity, @@ -69,7 +73,7 @@ class OfferAcceptFragment : Fragment() { viewModel.customerId.observe(this, Observer { customerId -> if (customerId.isNotEmpty()) { - saveCustomerId(customerId, activity) + PreferenceManager.saveCustomerId(customerId, activity) openMyLoansPage() } }) @@ -82,19 +86,22 @@ class OfferAcceptFragment : Fragment() { startActivity(intent) } - private fun saveCustomerId(customerId: String?, activity: Activity) { - PreferenceManager.setStringPreference( - activity, - PreferenceNames.CUSTOMER_ID, - customerId - ) + fun animateLoanApproval() { + binding.fireworkImage11.startAnimation(buildAnimation(200)) + binding.fireworkImage12.startAnimation(buildAnimation(400)) + binding.fireworkImage13.startAnimation(buildAnimation(600)) + + binding.fireworkImage21.startAnimation(buildAnimation(200)) + binding.fireworkImage22.startAnimation(buildAnimation(400)) + binding.fireworkImage23.startAnimation(buildAnimation(600)) } - private fun getPersonId(activity: Activity): String? { - return PreferenceManager.getStringPreference( - activity, - PreferenceNames.PERSON_ID - ) + fun buildAnimation(startOffet: Long): Animation { + val aniSlide = + AnimationUtils.loadAnimation(context, R.anim.zoom_in) + aniSlide.startOffset = startOffet + aniSlide.duration = 2000 + return aniSlide } companion object { diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/PreliminaryOfferFragment.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/PreliminaryOfferFragment.kt new file mode 100644 index 0000000000..534e80a90d --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/ui/fragments/PreliminaryOfferFragment.kt @@ -0,0 +1,197 @@ +package com.navi.medici.androidCustomerApp.ui.fragments + +import android.app.Activity +import android.app.AlertDialog +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.SeekBar +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import com.navi.medici.androidCustomerApp.R +import com.navi.medici.androidCustomerApp.adapters.LoanReasonAdapter +import com.navi.medici.androidCustomerApp.databinding.PreliminaryOfferFragmentBinding +import com.navi.medici.androidCustomerApp.models.Money +import com.navi.medici.androidCustomerApp.models.TenureDetails +import com.navi.medici.androidCustomerApp.models.TenureUnit +import com.navi.medici.androidCustomerApp.preferences.PreferenceManager +import com.navi.medici.androidCustomerApp.ui.activities.BottomNavigationActivity +import com.navi.medici.androidCustomerApp.viewModels.PreliminaryOfferViewModel +import kotlinx.android.synthetic.main.amount_dialog.view.amount_edt +import kotlinx.android.synthetic.main.amount_dialog.view.ok_btn +import kotlinx.android.synthetic.main.tenure_dialog.view.* + +class PreliminaryOfferFragment : Fragment() { + private lateinit var binding: PreliminaryOfferFragmentBinding + + private lateinit var viewModel: PreliminaryOfferViewModel + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = DataBindingUtil.inflate( + inflater, + R.layout.preliminary_offer_fragment, + container, + false + ) + + val activity = activity as FragmentActivity + viewModel = ViewModelProviders.of(activity).get(PreliminaryOfferViewModel::class.java) + binding.viewModel = viewModel + binding.executePendingBindings() + //TODO: fetches the existing offers.Remove this post fetch offer screen is built + viewModel.fetchOffers(PreferenceManager.getPersonId(activity)) + + viewModel.offerResponse.observe(this, Observer { offer -> + binding.amountSlider.max = viewModel.scaleToAmountMap.size - 1 + binding.tenureSlider.max = viewModel.scaleToTenureMap.size - 1 + var loanAmount = viewModel.offerResponse.value?.loanAmount + var loanTenure = viewModel.offerResponse.value?.tenure + binding.minAmountTxt.setText(loanAmount?.min?.getDisplayStr()) + binding.maxAmountTxt.setText(loanAmount?.max?.getDisplayStr()) + + binding.minTenureTxt.setText(loanTenure?.min?.getDisplayStr()) + binding.maxTenureTxt.setText(loanTenure?.max?.getDisplayStr()) + binding.tenureSlider.progress = binding.tenureSlider.max / 2 + binding.amountSlider.progress = binding.amountSlider.max / 2 + binding.reasonSpinner.adapter = LoanReasonAdapter(activity, offer.loanReasons) + }) + + binding.amountSlider.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) { + var amount = viewModel.scaleToAmountMap.get(seekBar.progress) + updateAmount(amount) + } + + override fun onStartTrackingTouch(seekBar: SeekBar) { + } + + override fun onStopTrackingTouch(seekBar: SeekBar) { + } + }) + + binding.tenureSlider.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) { + var tenureDetails = viewModel.scaleToTenureMap.get(seekBar.progress) + updateTenure(tenureDetails) + } + + override fun onStartTrackingTouch(seekBar: SeekBar) { + } + + override fun onStopTrackingTouch(seekBar: SeekBar) { + } + }) + + viewModel.applicationId.observe(this, Observer { applicationId -> + PreferenceManager.saveApplicationId(applicationId, activity) + openOfferAcceptFragment() + }) + + binding.loanSelectedAmountTxt.setOnClickListener { + showAmountDialog() + } + + binding.tenureSelectedTxt.setOnClickListener { + showTenureDialog() + } + + binding.acceptOfferBtn.setOnClickListener { + viewModel.onSubmitApplicationCreate( + PreferenceManager.getPersonId(activity), + binding.reasonSpinner.selectedItemId + ) + } + + + return binding.root + } + + fun updateAmount(amount: Money?) { + viewModel.setSelectedLoanAmount(amount) +// binding.loanSelectedAmountTxt.setText(amount?.currency + " " + amount?.amount) + } + + fun updateTenure(tenureDetails: TenureDetails?) { + viewModel.setSelectedTenureDetails(tenureDetails) +// binding.tenureSelectedTxt.setText(tenureDetails?.value.toString() + " " + tenureDetails?.unit) + } + + + fun showAmountDialog() { + val dialogBuilder = AlertDialog.Builder(context) + val inflater = this.layoutInflater + val dialogView = inflater.inflate(R.layout.amount_dialog, null) + dialogBuilder.setView(dialogView) + + + val alertDialog = dialogBuilder.create() + + dialogView.ok_btn.setOnClickListener { + if (dialogView.amount_edt.text.toString().isNotEmpty()) { + var amount = dialogView.amount_edt.text.toString().toBigDecimal() + var maxAmount = viewModel.getLoanAmount()?.max + maxAmount?.let { + if (amount > maxAmount.amount) { + amount = maxAmount.amount + } + } + + updateAmount(Money(maxAmount?.currency, maxAmount?.symbol, amount)) + } + + alertDialog.dismiss() + } + alertDialog.show() + } + + fun showTenureDialog() { + val dialogBuilder = AlertDialog.Builder(context) + val inflater = this.layoutInflater + val dialogView = inflater.inflate(R.layout.tenure_dialog, null) + dialogBuilder.setView(dialogView) + + + var tenureTypes = arrayOf(TenureUnit.DAYS.unit, TenureUnit.MONTH.unit) + val mainActivity = activity as Activity + val arrayAdapter = + ArrayAdapter(mainActivity, android.R.layout.simple_list_item_1, tenureTypes) + arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + dialogView.tenure_type_spinner!!.setAdapter(arrayAdapter) + + val alertDialog = dialogBuilder.create() + dialogView.ok_btn.setOnClickListener { + if (dialogView.tenure_edt.text.toString().isNotEmpty()) { + var tenure = dialogView.tenure_edt.text.toString().toInt() + var tenureType = dialogView.tenure_type_spinner.selectedItem.toString() + var maxTenure = viewModel.getTenure()?.max + maxTenure?.let { + if (tenure > maxTenure.value && tenureType.equals(maxTenure.unit)) { + tenure = maxTenure.value + } + } + updateTenure(TenureDetails(tenure, tenureType)) + } + alertDialog.dismiss() + } + alertDialog.show() + } + + private fun openOfferAcceptFragment() { + val intent = Intent(activity, BottomNavigationActivity::class.java) + intent.putExtra("TAG_ID", OfferAcceptFragment.TAG) + startActivity(intent) + } + + + companion object { + const val TAG = "PRELIMINORY_OFFER_FRAGMENT" + } +} diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/utils/EmiCalculator.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/utils/EmiCalculator.kt new file mode 100644 index 0000000000..2cf2eed3f7 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/utils/EmiCalculator.kt @@ -0,0 +1,23 @@ +package com.navi.medici.androidCustomerApp.utils + +import com.navi.medici.androidCustomerApp.models.TenureDetails +import com.navi.medici.androidCustomerApp.models.TenureUnit +import com.navi.medici.utils.amortization.EmiCalculator +import org.joda.money.BigMoney +import org.joda.money.CurrencyUnit +import java.math.BigDecimal + +class EmiCalculator() { + fun calculateEmi(amount: BigDecimal, interestRate: BigDecimal, tenure: TenureDetails): BigDecimal { + val loanTenureInMonths: Int + if (tenure.unit.equals(TenureUnit.DAYS.unit)) { + loanTenureInMonths = 1 + } else { + loanTenureInMonths = tenure.value + } + var principalAmount = BigMoney.of(CurrencyUnit.of("INR"), BigDecimal(amount.toDouble())) + val emiValue = EmiCalculator(principalAmount, interestRate, loanTenureInMonths).calculate() + return emiValue.amount + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/utils/MockResponseBuilder.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/utils/MockResponseBuilder.kt new file mode 100644 index 0000000000..d7b14a5ae3 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/utils/MockResponseBuilder.kt @@ -0,0 +1,22 @@ +package com.navi.medici.androidCustomerApp.utils + +import com.navi.medici.androidCustomerApp.models.* +import java.math.BigDecimal + +class MockResponseBuilder { + + fun buildSampleOfferResponse(): OfferResponse? { + var offerTenure = OfferTenure(TenureDetails(1, "day"), TenureDetails(6, "months")) + var loanReasons = + arrayListOf(LoanReason(1, "home construction"), LoanReason(1, "personal emergency")) + var offerResponseVal: OfferResponse? = OfferResponse( + "1", + "123", + LoanAmount(Money("Rs", "Rs", 500.toBigDecimal()), Money("Rs", "Rs", 25000.toBigDecimal())), + offerTenure, + BigDecimal(12.5), + loanReasons + ) + return offerResponseVal + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/utils/StepFunctionCalculator.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/utils/StepFunctionCalculator.kt new file mode 100644 index 0000000000..c86c2834f5 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/utils/StepFunctionCalculator.kt @@ -0,0 +1,41 @@ +package com.navi.medici.androidCustomerApp.utils + +import com.navi.medici.androidCustomerApp.models.* +import java.math.BigDecimal + +class StepFunctionCalculator { + val STEP_FUNCTION_AMOUNT = 500 + fun buildTenureStepFunction(offerResponse: OfferResponse?): MutableList { + var stepFunctionVals = ArrayList() + + for (tenureVal in 1 until 30) { + stepFunctionVals.add(TenureDetails(tenureVal, TenureUnit.DAYS.unit)) + } + + var minMonth: Int = 12 + offerResponse?.tenure?.max?.let { + if (it.unit.equals(TenureUnit.MONTH.unit)) { + minMonth = it.value + } + } + + for (tenureVal in 1 until minMonth + 1) { + stepFunctionVals.add(TenureDetails(tenureVal, TenureUnit.MONTH.unit)) + } + return stepFunctionVals + } + + + fun buildScaleToAmountMap(loanAmount: LoanAmount) : MutableList{ + var minAmount = loanAmount.min.amount + var stepFunctionVals = ArrayList() + + var index = 0 + while (minAmount <= loanAmount.max.amount) { + stepFunctionVals.add(Money(loanAmount.max.currency, loanAmount.max.symbol, minAmount)) + minAmount += BigDecimal(STEP_FUNCTION_AMOUNT) + index++ + } + return stepFunctionVals + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/viewModels/OfferAcceptViewModel.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/viewModels/OfferAcceptViewModel.kt index 93004aa484..bbad0a0daa 100644 --- a/app/src/main/java/com/navi/medici/androidCustomerApp/viewModels/OfferAcceptViewModel.kt +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/viewModels/OfferAcceptViewModel.kt @@ -4,9 +4,9 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.navi.medici.androidCustomerApp.api.LoanApplicationApi -import com.navi.medici.androidCustomerApp.bottomNavigation.loanApplication.models.OfferResponse import com.navi.medici.androidCustomerApp.loan_application.LoanApplicationRepository -import com.navi.medici.androidCustomerApp.loan_application.models.OfferSelected +import com.navi.medici.androidCustomerApp.models.ApplicationSummary +import com.navi.medici.androidCustomerApp.models.OfferSelected import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -17,40 +17,60 @@ class OfferAcceptViewModel : ViewModel() { val customerId: LiveData get() = _customerId - var offerSelected = MutableLiveData(); private val offerAcceptRepository = LoanApplicationRepository(LoanApplicationApi()) private val coroutineScope = CoroutineScope(Dispatchers.Main) - fun onSubmitOfferAccept() { - coroutineScope.launch { - offerSelected.value?.let { - val response = offerAcceptRepository.offerAccept(offerSelected.value) - if (response.isSuccessful) { - _customerId.value = response.body()?.customerId - Timber.i("Offer Accept response ${response.body().toString()}") - } - } - } - } + val applicationSummary = MutableLiveData() - fun fetchOffers(personId: String?) { + fun onSubmitOfferAccept(personId: String?) { coroutineScope.launch { - val response = offerAcceptRepository.fetchOffer(personId) - if (response.isSuccessful) { - selectOffer(response.body(), personId) - Timber.i("OfferSelected response ${response.body().toString()}") - } - } - } - - private fun selectOffer(offerResponse: OfferResponse?, personId: String?) { - offerSelected.value = - OfferSelected( + var applicationDetail = applicationSummary.value?.loanApplicationDetails + // TODO: updateit to send only the application id + var offerSelected = OfferSelected( personId, - offerResponse?.schemeId, - offerResponse?.loanAmount?.max, - offerResponse?.tenure?.max, - offerResponse?.rateOfInterest + applicationDetail?.offerId, + applicationDetail?.loanAmount, + applicationDetail?.tenure, + applicationDetail?.rateOfInterest, + 1 ) + + val response = offerAcceptRepository.offerAccept(offerSelected) + if (response.isSuccessful) { + _customerId.value = response.body()?.customerId + Timber.i("Offer Accept response $response.body().toString()") + } + } } + + fun fetchApplication(applicationId: String?) { + coroutineScope.launch { + val response = offerAcceptRepository.fetchApplicationSummary(applicationId) + if (response.isSuccessful) { + applicationSummary.value = response.body() + Timber.i("OfferSelected response $response.body().toString()") + } + } + } + +// fun fetchOffers(personId: String?) { +// coroutineScope.launch { +// val response = offerAcceptRepository.fetchOffer(personId) +// if (response.isSuccessful) { +// selectOffer(response.body(), personId) +// Log.i("OfferSelected response", response.body().toString()) +// } +// } +// } + +// private fun selectOffer(offerResponse: OfferResponse?, personId: String?) { +// offerSelected.value = +// OfferSelected( +// personId, +// offerResponse?.schemeId, +// offerResponse?.loanAmount?.max, +// offerResponse?.tenure?.max, +// offerResponse?.rateOfInterest +// ) +// } } \ No newline at end of file diff --git a/app/src/main/java/com/navi/medici/androidCustomerApp/viewModels/PreliminaryOfferViewModel.kt b/app/src/main/java/com/navi/medici/androidCustomerApp/viewModels/PreliminaryOfferViewModel.kt new file mode 100644 index 0000000000..d8a13e83f2 --- /dev/null +++ b/app/src/main/java/com/navi/medici/androidCustomerApp/viewModels/PreliminaryOfferViewModel.kt @@ -0,0 +1,130 @@ +package com.navi.medici.androidCustomerApp.viewModels + +import android.util.Log +import android.widget.SeekBar +import androidx.databinding.ObservableField +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.navi.medici.androidCustomerApp.api.LoanApplicationApi +import com.navi.medici.androidCustomerApp.loan_application.LoanApplicationRepository +import com.navi.medici.androidCustomerApp.models.* +import com.navi.medici.androidCustomerApp.utils.EmiCalculator +import com.navi.medici.androidCustomerApp.utils.MockResponseBuilder +import com.navi.medici.androidCustomerApp.utils.StepFunctionCalculator +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.math.BigDecimal + +class PreliminaryOfferViewModel : ViewModel() { + var scaleToTenureMap = HashMap() + var scaleToAmountMap = HashMap() + private val _applicationId = MutableLiveData() + val applicationId: LiveData + get() = _applicationId + private val offerAcceptRepository = LoanApplicationRepository(LoanApplicationApi()) + private val coroutineScope = CoroutineScope(Dispatchers.Main) + var offerResponse = MutableLiveData(); + var selectedLoanAmount = ObservableField() + var selectedTenureDetails = ObservableField() + var emiValue = ObservableField() + + fun fetchOffers(personId: String?) { + coroutineScope.launch { + val response = offerAcceptRepository.fetchOffer(personId) + if (response.isSuccessful) { + var offerResponseVal = response.body() + + buildAmountTenureMap(offerResponseVal) + offerResponse.value = offerResponseVal + Log.i("OfferSelected response", offerResponseVal.toString()) + } + } + } + + fun onSubmitApplicationCreate( + personId: String?, + selectionReasonId: Long? + ) { + coroutineScope.launch { + var offerSelected = OfferSelected( + personId, + offerResponse.value?.schemeId, + selectedLoanAmount.get(), + selectedTenureDetails.get(), + offerResponse.value?.rateOfInterest, + selectionReasonId + ) + + val response = offerAcceptRepository.createApplication(offerSelected) + if (response.isSuccessful) { + _applicationId.value = response.body()?.applicationId + Log.i("CreateAplctn response", response.body().toString()) + } + } + } + + fun getLoanAmount(): LoanAmount? { + return offerResponse.value?.loanAmount + } + + fun getTenure(): OfferTenure? { + return offerResponse.value?.tenure + } + + + fun setSelectedLoanAmount(amount: Money?) { + selectedLoanAmount.set(amount) + updateEma() + } + + fun setSelectedTenureDetails(tenureDetails: TenureDetails?) { + selectedTenureDetails.set(tenureDetails) + updateEma() + } + + fun updateEma() { + var amount = selectedLoanAmount.get() + var tenureDetails = selectedTenureDetails.get() + + amount?.let { + tenureDetails?.let { + calculateEmi( + amount?.amount, + tenureDetails + ) + } + } + } + + + fun buildAmountTenureMap(offerResponse: OfferResponse?) { + offerResponse?.let { + var tenureStepValue = StepFunctionCalculator().buildTenureStepFunction(offerResponse) + for (index in 0 until tenureStepValue.size) { + scaleToTenureMap.put(index, tenureStepValue.get(index)) + } + + var amountsStepValue = + StepFunctionCalculator().buildScaleToAmountMap(offerResponse.loanAmount) + for (index in 0 until amountsStepValue.size) { + scaleToAmountMap.put(index, amountsStepValue.get(index)) + } + } + } + + + private fun calculateEmi(amount: BigDecimal, tenure: TenureDetails) { + offerResponse.value?.let { + emiValue.set( + getLoanAmount()?.max?.symbol + " " + EmiCalculator().calculateEmi( + amount, + it.rateOfInterest, + tenure + ).toLong() + ) + } + } + +} diff --git a/app/src/main/res/anim/zoom_in.xml b/app/src/main/res/anim/zoom_in.xml new file mode 100644 index 0000000000..ec653eba53 --- /dev/null +++ b/app/src/main/res/anim/zoom_in.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/border_shadow.xml b/app/src/main/res/drawable/border_shadow.xml new file mode 100644 index 0000000000..d8ff88656a --- /dev/null +++ b/app/src/main/res/drawable/border_shadow.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/custom_thumb.xml b/app/src/main/res/drawable/custom_thumb.xml new file mode 100644 index 0000000000..b951a225a6 --- /dev/null +++ b/app/src/main/res/drawable/custom_thumb.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/seekbar_progress.xml b/app/src/main/res/drawable/seekbar_progress.xml new file mode 100644 index 0000000000..7ee8ed2bbc --- /dev/null +++ b/app/src/main/res/drawable/seekbar_progress.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/seekbar_style.xml b/app/src/main/res/drawable/seekbar_style.xml new file mode 100644 index 0000000000..3243fd50fd --- /dev/null +++ b/app/src/main/res/drawable/seekbar_style.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_bottom_navigation.xml b/app/src/main/res/layout/activity_bottom_navigation.xml index 9a5d5490a4..bb025aacd0 100644 --- a/app/src/main/res/layout/activity_bottom_navigation.xml +++ b/app/src/main/res/layout/activity_bottom_navigation.xml @@ -8,6 +8,17 @@ android:layout_height="match_parent" tools:context=".ui.activities.BottomNavigationActivity"> + + + app:layout_constraintTop_toBottomOf="@id/toolbar" /> + + + + + + + + + + + +