Commit 46cfb422 authored by shohboz's avatar shohboz

[UPD] MUS-288, Feature, updated add card

parent ff55e2e3
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<entry key="../../.gradle/caches/transforms-3/272c6ad3bc9f3b40802fd3a427796f36/transformed/jetified-agr-sdk-mobi-uz-release-1.0.0/res/layout/agr_layout_empty.xml" value="0.25625" /> <entry key="../../.gradle/caches/transforms-3/272c6ad3bc9f3b40802fd3a427796f36/transformed/jetified-agr-sdk-mobi-uz-release-1.0.0/res/layout/agr_layout_empty.xml" value="0.25625" />
<entry key="../../.gradle/caches/transforms-3/eea77424a90e1e1097be3e7a9314e37d/transformed/jetified-mobi_uz/res/layout/agr_fragment_fast_pay.xml" value="0.25" /> <entry key="../../.gradle/caches/transforms-3/eea77424a90e1e1097be3e7a9314e37d/transformed/jetified-mobi_uz/res/layout/agr_fragment_fast_pay.xml" value="0.25" />
<entry key="../../.gradle/caches/transforms-3/fd180e2afb980e83e4951f5e21e58af5/transformed/jetified-agr-sdk-coreui-release-1.7.0/res/layout/agr_core_ui_layout_zero.xml" value="0.25625" /> <entry key="../../.gradle/caches/transforms-3/fd180e2afb980e83e4951f5e21e58af5/transformed/jetified-agr-sdk-coreui-release-1.7.0/res/layout/agr_core_ui_layout_zero.xml" value="0.25625" />
<entry key="../../.gradle/caches/transforms-3/fd180e2afb980e83e4951f5e21e58af5/transformed/jetified-agr-sdk-coreui-release-1.7.0/res/layout/agr_item_card.xml" value="0.25625" />
<entry key="..\:/Users/NEW AGE/StudioProjects/shunchaki/app/src/main/res/layout/fragment_billing.xml" value="0.20520833333333333" /> <entry key="..\:/Users/NEW AGE/StudioProjects/shunchaki/app/src/main/res/layout/fragment_billing.xml" value="0.20520833333333333" />
<entry key="app/src/main/res/drawable/bgn_avatar.xml" value="0.25069444444444444" /> <entry key="app/src/main/res/drawable/bgn_avatar.xml" value="0.25069444444444444" />
<entry key="app/src/main/res/drawable/bgn_lang.xml" value="0.2796296296296296" /> <entry key="app/src/main/res/drawable/bgn_lang.xml" value="0.2796296296296296" />
...@@ -117,6 +118,7 @@ ...@@ -117,6 +118,7 @@
<entry key="app/src/main/res/layout/item_ussd.xml" value="0.22" /> <entry key="app/src/main/res/layout/item_ussd.xml" value="0.22" />
<entry key="app/src/main/res/layout/large.xml" value="0.25625" /> <entry key="app/src/main/res/layout/large.xml" value="0.25625" />
<entry key="app/src/main/res/layout/layout_ask_create_task.xml" value="0.22643442622950818" /> <entry key="app/src/main/res/layout/layout_ask_create_task.xml" value="0.22643442622950818" />
<entry key="app/src/main/res/layout/layout_empty.xml" value="0.25625" />
<entry key="app/src/main/res/layout/layout_exit.xml" value="0.25625" /> <entry key="app/src/main/res/layout/layout_exit.xml" value="0.25625" />
<entry key="app/src/main/res/layout/layout_home_header.xml" value="0.25625" /> <entry key="app/src/main/res/layout/layout_home_header.xml" value="0.25625" />
<entry key="app/src/main/res/layout/layout_offline_bottom_sheet.xml" value="0.266051912568306" /> <entry key="app/src/main/res/layout/layout_offline_bottom_sheet.xml" value="0.266051912568306" />
......
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "uz.mobiuz.mobiservice.dev",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}
\ No newline at end of file
...@@ -11,6 +11,10 @@ import dagger.hilt.android.lifecycle.HiltViewModel ...@@ -11,6 +11,10 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import uz.agr.sdk.core.entity.card.CardInfo
import uz.agr.sdk.core.entity.card.CardRegistration
import uz.agr.sdk.pgw_core.mobi.BaseListener
import uz.agr.sdk.pgw_core.mobi.MobiUz
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
...@@ -99,4 +103,49 @@ class AuthViewModel @Inject constructor( ...@@ -99,4 +103,49 @@ class AuthViewModel @Inject constructor(
} }
private val _cardConfirmUiState = MutableSharedFlow<UiStateObject<CardInfo>>()
val cardConfirmUiState: SharedFlow<UiStateObject<CardInfo>> = _cardConfirmUiState
fun cardConfirm(cardId: String, code: String) = viewModelScope.launch {
_cardConfirmUiState.emit(UiStateObject.LOADING)
MobiUz.cardConfirmSms(cardId, code, object : BaseListener<CardInfo> {
override fun error(message: String) {
viewModelScope.launch {
_cardConfirmUiState.emit(UiStateObject.ERROR(message))
}
}
override fun loading(boolean: Boolean) {}
override fun success(data: CardInfo) {
viewModelScope.launch {
_cardConfirmUiState.emit(UiStateObject.SUCCESS(data))
}
}
})
}
private val _resendSmsUiState = MutableSharedFlow<UiStateObject<CardRegistration>>()
val resendSmsUiState: SharedFlow<UiStateObject<CardRegistration>> = _resendSmsUiState
fun resendSms(phoneNumber: String, cardNumber: String, cardExpire: String) = viewModelScope.launch {
_resendSmsUiState.emit(UiStateObject.LOADING)
MobiUz.registerCardResendSms(phoneNumber, cardNumber, cardExpire,object : BaseListener<CardRegistration> {
override fun error(message: String) {
viewModelScope.launch {
_resendSmsUiState.emit(UiStateObject.ERROR(message))
}
}
override fun loading(boolean: Boolean) {}
override fun success(data: CardRegistration) {
viewModelScope.launch {
_resendSmsUiState.emit(UiStateObject.SUCCESS(data))
}
}
})
}
} }
\ No newline at end of file
package uz.mobiuz.mobiservice.dev.ui.auth.verification package uz.mobiuz.mobiservice.dev.ui.auth.verification
import android.app.Activity
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent import android.view.KeyEvent
import android.view.View import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.isVisible import androidx.core.view.isVisible
...@@ -10,6 +16,7 @@ import androidx.fragment.app.viewModels ...@@ -10,6 +16,7 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import uz.mobiuz.mobiservice.dev.R import uz.mobiuz.mobiservice.dev.R
import uz.mobiuz.mobiservice.dev.databinding.FragmentVerificationBinding import uz.mobiuz.mobiservice.dev.databinding.FragmentVerificationBinding
...@@ -30,6 +37,10 @@ import uz.mobiuz.mobiservice.dev.utils.hideKeyboard ...@@ -30,6 +37,10 @@ import uz.mobiuz.mobiservice.dev.utils.hideKeyboard
import uz.mobiuz.mobiservice.dev.utils.showKeyboard import uz.mobiuz.mobiservice.dev.utils.showKeyboard
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import uz.agr.mobiuz.extension.SmsBroadcastReceiver
import uz.agr.mobiuz.ui.dialog.MessageDialog
import uz.agr.sdk.coreui.extension.hideSoftInput
import java.util.regex.Pattern
import javax.inject.Inject import javax.inject.Inject
...@@ -46,17 +57,25 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) { ...@@ -46,17 +57,25 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) {
private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { NavHostFragment.findNavController(this) } private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { NavHostFragment.findNavController(this) }
private var verificationCode = "" private var verificationCode = ""
private var code = "" private var code = ""
private var phone = "" private var phone = ""
private var type = "" private var type = ""
private var smsBroadcastReceiver: SmsBroadcastReceiver? = null
private var cardNumber = ""
private var cardId = ""
private var cardExpire = ""
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
arguments?.let { arguments?.let {
phone = it.getString(CONSTANTS.PHONE) ?: "" phone = it.getString(CONSTANTS.PHONE) ?: ""
type = it.getString(CONSTANTS.TYPE_VERIFICATION) ?: "" type = it.getString(CONSTANTS.TYPE_VERIFICATION) ?: ""
verificationCode = it.getString(CONSTANTS.PIN_CODE) ?: "" verificationCode = it.getString(CONSTANTS.PIN_CODE) ?: ""
//card
cardId = it.getString(CONSTANTS.CARD_ID) ?: ""
cardNumber = it.getString(CONSTANTS.CARD_NUMBER) ?: ""
cardExpire = it.getString(CONSTANTS.CARD_EXPIRE) ?: ""
} }
} }
...@@ -64,6 +83,8 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) { ...@@ -64,6 +83,8 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) {
_bn = FragmentVerificationBinding.bind(view) _bn = FragmentVerificationBinding.bind(view)
setUpUI() setUpUI()
count(true) count(true)
startSmsUserConsent()
registerBroadcastReceiver()
collects() collects()
} }
...@@ -91,18 +112,27 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) { ...@@ -91,18 +112,27 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) {
btnVerification.setOnClickListener(object : ButtonClick() { btnVerification.setOnClickListener(object : ButtonClick() {
override fun onSingleClick(v: View?) { override fun onSingleClick(v: View?) {
getLinePinCodes() getLinePinCodes()
val auth = UserAuth(phone.replace("+", "").replace(" ", ""), null, code) val auth = UserAuth(phone.filter { it.isDigit() }, null, code)
if (type == CONSTANTS.TYPE_FORGET) { when (type) {
CONSTANTS.TYPE_FORGET -> {
viewModel.checkResetCode(auth) viewModel.checkResetCode(auth)
} else { }
CONSTANTS.TYPE_ADD_CARD -> {
viewModel.cardConfirm(cardId, getLinePinCodes())
}
else -> {
viewModel.verification(auth) viewModel.verification(auth)
} }
}
} }
}) })
sentCodeAgain.setOnClickListener { sentCodeAgain.setOnClickListener {
viewModel.resetSmsCode(UserAuth(phone.replace("+", "").replace(" ", ""))) if(type == CONSTANTS.TYPE_ADD_CARD){
viewModel.resendSms("998949125150", cardNumber, cardExpire)
}else
viewModel.resetSmsCode(UserAuth(phone.filter { it.isDigit() }))
} }
coutdownView.setOnCountdownEndListener { coutdownView.setOnCountdownEndListener {
count(false) count(false)
...@@ -111,7 +141,7 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) { ...@@ -111,7 +141,7 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) {
} }
} }
private fun setVerificationCode() { private fun setVerificationCode(code:String) {
if(verificationCode.length == 6){ if(verificationCode.length == 6){
bn.apply { bn.apply {
pin1.setText(verificationCode[0].toString()) pin1.setText(verificationCode[0].toString())
...@@ -126,7 +156,7 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) { ...@@ -126,7 +156,7 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) {
} }
} }
private fun getLinePinCodes() { private fun getLinePinCodes() :String{
bn.apply { bn.apply {
code = "" code = ""
code += pin1.text.toString() code += pin1.text.toString()
...@@ -136,6 +166,7 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) { ...@@ -136,6 +166,7 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) {
code += pin5.text.toString() code += pin5.text.toString()
code += pin6.text.toString() code += pin6.text.toString()
} }
return code
} }
private fun setColorPins(color: Int) { private fun setColorPins(color: Int) {
...@@ -286,6 +317,47 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) { ...@@ -286,6 +317,47 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) {
} }
} }
} }
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.cardConfirmUiState.collect {
when (it) {
is UiStateObject.SUCCESS -> {
showProgressDialog(false)
showSuccessDialog()
}
is UiStateObject.ERROR -> {
showProgressDialog(false)
setColorPins(getColorCompat(R.color.primary100))
bn.txtErrorCode.isVisible = true
bn.pinView.startAnimation(AnimationUtils.loadAnimation(requireContext(), R.anim.shake))
showToastMessage(it.message)
}
is UiStateObject.LOADING -> {
showProgressDialog(true)
}
else -> Unit
}
}
}
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.resendSmsUiState.collect {
when (it) {
is UiStateObject.SUCCESS -> {
showProgressDialog(false)
count(true)
}
is UiStateObject.ERROR -> {
showProgressDialog(false)
}
is UiStateObject.LOADING -> {
showProgressDialog(true)
}
else -> Unit
}
}
}
} }
private fun count(status: Boolean) { private fun count(status: Boolean) {
...@@ -297,7 +369,68 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) { ...@@ -297,7 +369,68 @@ class VerificationFragment : BaseFragment(R.layout.fragment_verification) {
} }
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
activity?.hideSoftInput(bn.pinView)
if (requestCode == 200) {
if (resultCode == Activity.RESULT_OK && data != null) { //That gives all message to us.
val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
message?.let {
getOtpFromMessage(message)
}
}
}
}
private fun getOtpFromMessage(message: String) { // This will match any 6 digit number in the message
val matcher = Pattern.compile("(|^)\\d{6}").matcher(message)
if (matcher.find()) {
setVerificationCode(matcher.group(0))
// etConfirmCode.setText(matcher.group(0))
}
}
private fun showSuccessDialog() {
val dialog = MessageDialog(
requireContext(),
getString(uz.agr.mobiuz.R.string.agr_mobi_uz_card_added),
getString(uz.agr.mobiuz.R.string.agr_mobi_uz_close_process)
)
dialog.window!!.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.setCanceledOnTouchOutside(true)
dialog.setOnOkClickListener(object : MessageDialog.OnClickListener {
override fun dialogPositiveClicked() {
dialog.dismiss()
navController.popBackStack(R.id.cardsListFragment, false)
}
})
dialog.show()
}
private fun startSmsUserConsent() {
val client = SmsRetriever.getClient(requireContext())
client.startSmsUserConsent(null)
.addOnSuccessListener { /**/ }
.addOnFailureListener { /**/ }
}
private fun registerBroadcastReceiver() {
smsBroadcastReceiver = SmsBroadcastReceiver()
smsBroadcastReceiver!!.smsBroadcastReceiverListener =
object : SmsBroadcastReceiver.SmsBroadcastReceiverListener {
override fun onSuccess(intent: Intent?) {
startActivityForResult(intent, 200)
}
override fun onFailure() {}
}
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
requireActivity().registerReceiver(smsBroadcastReceiver, intentFilter)
}
override fun onDestroy() { override fun onDestroy() {
requireActivity().unregisterReceiver(smsBroadcastReceiver)
_bn = null _bn = null
super.onDestroy() super.onDestroy()
} }
......
...@@ -3,6 +3,8 @@ package uz.mobiuz.mobiservice.dev.ui.global ...@@ -3,6 +3,8 @@ package uz.mobiuz.mobiservice.dev.ui.global
object CONSTANTS { object CONSTANTS {
const val CARD_ID = "CARD_ID" const val CARD_ID = "CARD_ID"
const val CARD_NUMBER = "CARD_NUMBER"
const val CARD_EXPIRE = "CARD_EXPIRE"
const val UNAUTHORIZED = "UNAUTHORIZED" const val UNAUTHORIZED = "UNAUTHORIZED"
const val BASE_URL = "https://mobileapp.mobi.uz/api/v1/" const val BASE_URL = "https://mobileapp.mobi.uz/api/v1/"
...@@ -36,7 +38,7 @@ object CONSTANTS { ...@@ -36,7 +38,7 @@ object CONSTANTS {
const val PHONE2 = "+998 97 130 09 09" const val PHONE2 = "+998 97 130 09 09"
const val PHONE3 = "+998 97 203 10 10" const val PHONE3 = "+998 97 203 10 10"
const val DEFAULT_PHONE = "+998 97 999-99-99" const val DEFAULT_PHONE = "+998 97 999-99-99"
const val RESEND_CODE_TIME = 60000L const val RESEND_CODE_TIME = 6000L
const val BLOCKED_TIME = 6000 const val BLOCKED_TIME = 6000
...@@ -46,6 +48,7 @@ object CONSTANTS { ...@@ -46,6 +48,7 @@ object CONSTANTS {
const val REGISTER = "register" const val REGISTER = "register"
const val TYPE_VERIFICATION = "type_verification" const val TYPE_VERIFICATION = "type_verification"
const val TYPE_FORGET = "type_forget" const val TYPE_FORGET = "type_forget"
const val TYPE_ADD_CARD = "TYPE_ADD_CARD"
const val PIN_CODE = "PIN_CODE" const val PIN_CODE = "PIN_CODE"
const val FIRST = "first" const val FIRST = "first"
const val SERVICE = "service" const val SERVICE = "service"
......
...@@ -43,20 +43,7 @@ class BillingFragment : BaseFragment(R.layout.fragment_billing) { ...@@ -43,20 +43,7 @@ class BillingFragment : BaseFragment(R.layout.fragment_billing) {
savedCards.setOnClickListener { savedCards.setOnClickListener {
getPhoneNumber(object : LoadPhoneNumber { getPhoneNumber(object : LoadPhoneNumber {
override fun invoke(phoneNumber: String) { override fun invoke(phoneNumber: String) {
// navController.navigate(R.id.cardsListFragment, bundleOf(CONSTANTS.PHONE to pref.userPhone.filter { it.isDigit() })) navController.navigate(R.id.cardsListFragment, bundleOf(CONSTANTS.PHONE to pref.userPhone.filter { it.isDigit() }))
MobiUz.registerCard("998990552109", "8600312917291250", "0325", object : BaseListener<CardRegistration> {
override fun error(message: String) {
Log.e("TTT", "Error : $message")
}
override fun loading(boolean: Boolean) {
Log.d("TTT", "Loading : $boolean")
}
override fun success(data: CardRegistration) {
Log.d("TTT", "Data: ${data.maskedPhoneNumber}")
}
})
} }
}) })
} }
......
package uz.mobiuz.mobiservice.dev.ui.sdk.card package uz.mobiuz.mobiservice.dev.ui.sdk.card
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.text.method.DigitsKeyListener import android.text.method.DigitsKeyListener
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
...@@ -12,6 +15,7 @@ import androidx.navigation.NavController ...@@ -12,6 +15,7 @@ import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import uz.agr.mobiuz.ui.dialog.MessageDialog
import uz.agr.mobiuz.ui.fast_action.animation.getColorCompat import uz.agr.mobiuz.ui.fast_action.animation.getColorCompat
import uz.agr.sdk.core.entity.card.CardRegistration import uz.agr.sdk.core.entity.card.CardRegistration
import uz.agr.sdk.coreui.extension.hideSoftInput import uz.agr.sdk.coreui.extension.hideSoftInput
...@@ -66,12 +70,12 @@ class AddCardFragment : BaseFragment(R.layout.fragment_add_card) { ...@@ -66,12 +70,12 @@ class AddCardFragment : BaseFragment(R.layout.fragment_add_card) {
btnContinue.setOnClickListener(object : ButtonClick() { btnContinue.setOnClickListener(object : ButtonClick() {
override fun onSingleClick(v: View?) { override fun onSingleClick(v: View?) {
if (cardNumberValid != null && cardExpiryValid != null) { if (cardNumberValid != null && cardExpiryValid != null) {
viewModel.cardRegistration(pref.userPhone.filter { it.isDigit() }, cardNumberValid!!, cardExpiryValid!!) // viewModel.cardRegistration(pref.userPhone.filter { it.isDigit() }, cardNumberValid!!, cardExpiryValid!!)
viewModel.cardRegistration("998949125150", cardNumberValid!!, cardExpiryValid!!)
} }
} }
}) })
} }
} }
...@@ -82,7 +86,14 @@ class AddCardFragment : BaseFragment(R.layout.fragment_add_card) { ...@@ -82,7 +86,14 @@ class AddCardFragment : BaseFragment(R.layout.fragment_add_card) {
is UiStateObject.SUCCESS -> { is UiStateObject.SUCCESS -> {
showProgressDialog(false) showProgressDialog(false)
showToastMessage("success:${it.data.maskedPhoneNumber}") showToastMessage("success:${it.data.maskedPhoneNumber}")
navController.navigate(R.id.cardConfirmFragment, bundleOf(CONSTANTS.CARD_ID to it.data.cardId)) navController.navigate(R.id.verificationFragment,
bundleOf(
CONSTANTS.TYPE_VERIFICATION to CONSTANTS.TYPE_ADD_CARD,
CONSTANTS.CARD_ID to it.data.cardId,
CONSTANTS.CARD_NUMBER to cardNumberValid,
CONSTANTS.CARD_EXPIRE to cardExpiryValid,
)
)
} }
is UiStateObject.ERROR -> { is UiStateObject.ERROR -> {
...@@ -91,7 +102,6 @@ class AddCardFragment : BaseFragment(R.layout.fragment_add_card) { ...@@ -91,7 +102,6 @@ class AddCardFragment : BaseFragment(R.layout.fragment_add_card) {
} }
is UiStateObject.LOADING -> { is UiStateObject.LOADING -> {
showProgressDialog(true) showProgressDialog(true)
} }
else -> Unit else -> Unit
...@@ -122,7 +132,7 @@ class AddCardFragment : BaseFragment(R.layout.fragment_add_card) { ...@@ -122,7 +132,7 @@ class AddCardFragment : BaseFragment(R.layout.fragment_add_card) {
tvErrorMsg.visible(false) tvErrorMsg.visible(false)
} else { } else {
etCardNumber.setBackgroundResource(uz.agr.mobiuz.R.drawable.agr_edit_text_error) etCardNumber.setBackgroundResource(uz.agr.mobiuz.R.drawable.agr_edit_text_error)
etCardNumber.setTextColor(getColorCompat(uz.agr.mobiuz.R.color.primary100)) etCardNumber.setTextColor(getColorCompat(R.color.primary100))
tvErrorMsg.visible(true) tvErrorMsg.visible(true)
} }
checkValidForm() checkValidForm()
......
package uz.mobiuz.mobiservice.dev.ui.sdk.card package uz.mobiuz.mobiservice.dev.ui.sdk.card
import android.app.Activity
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent
import android.view.View import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.material.textfield.TextInputEditText
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import uz.agr.mobiuz.extension.SmsBroadcastReceiver
import uz.agr.mobiuz.ui.dialog.MessageDialog
import uz.agr.mobiuz.ui.fast_action.animation.getColorCompat
import uz.agr.mobiuz.ui.fast_action.animation.showKeyboard
import uz.agr.sdk.coreui.extension.hideSoftInput
import uz.agr.sdk.coreui.extension.visible
import uz.agr.sdk.coreui.ui.ButtonClick
import uz.agr.sdk.coreui.ui.TextWatcherWrapper
import uz.mobiuz.mobiservice.dev.R import uz.mobiuz.mobiservice.dev.R
import uz.mobiuz.mobiservice.dev.databinding.FragmentCardConfirmBinding import uz.mobiuz.mobiservice.dev.databinding.FragmentCardConfirmBinding
import uz.mobiuz.mobiservice.dev.model.SharedPref import uz.mobiuz.mobiservice.dev.model.SharedPref
import uz.mobiuz.mobiservice.dev.network.model.UiStateObject import uz.mobiuz.mobiservice.dev.network.model.UiStateObject
import uz.mobiuz.mobiservice.dev.ui.base.BaseFragment import uz.mobiuz.mobiservice.dev.ui.base.BaseFragment
import uz.mobiuz.mobiservice.dev.ui.global.CONSTANTS import uz.mobiuz.mobiservice.dev.ui.global.CONSTANTS
import uz.mobiuz.mobiservice.dev.ui.home.HomeViewModel import uz.mobiuz.mobiservice.dev.utils.extensions.clearText
import uz.mobiuz.mobiservice.dev.utils.extensions.isEmpty
import uz.mobiuz.mobiservice.dev.utils.extensions.isNotEmpty
import uz.mobiuz.mobiservice.dev.utils.hideKeyboard
import java.util.regex.Pattern
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
...@@ -25,14 +48,23 @@ class CardConfirmFragment : BaseFragment(R.layout.fragment_card_confirm) { ...@@ -25,14 +48,23 @@ class CardConfirmFragment : BaseFragment(R.layout.fragment_card_confirm) {
private var _bn: FragmentCardConfirmBinding? = null private var _bn: FragmentCardConfirmBinding? = null
private val bn get() = _bn ?: throw NullPointerException("cannot inflate") private val bn get() = _bn ?: throw NullPointerException("cannot inflate")
private val viewModel: HomeViewModel by viewModels() private val viewModel: CardViewModel by viewModels()
private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { NavHostFragment.findNavController(this) } private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { NavHostFragment.findNavController(this) }
private var smsBroadcastReceiver: SmsBroadcastReceiver? = null
private var cardNumber = ""
private var cardId = "" private var cardId = ""
private var cardExpire = ""
// private val phoneNumber: String by argument(CardConfirmFragment.ARG_PHONE_NUMBER)
// private val maskedPhoneNumber: String by argument(CardConfirmFragment.ARG_MASKED_PHONE_NUMBER)
private var code = ""
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
arguments?.let { arguments?.let {
cardId = it.getString(CONSTANTS.CARD_ID) ?: "" cardId = it.getString(CONSTANTS.CARD_ID) ?: ""
cardNumber = it.getString(CONSTANTS.CARD_NUMBER) ?: ""
cardExpire = it.getString(CONSTANTS.CARD_EXPIRE) ?: ""
} }
} }
...@@ -41,41 +73,264 @@ class CardConfirmFragment : BaseFragment(R.layout.fragment_card_confirm) { ...@@ -41,41 +73,264 @@ class CardConfirmFragment : BaseFragment(R.layout.fragment_card_confirm) {
_bn = FragmentCardConfirmBinding.bind(view) _bn = FragmentCardConfirmBinding.bind(view)
setUpUI() setUpUI()
count(true)
startSmsUserConsent()
registerBroadcastReceiver()
collects() collects()
} }
override fun setUpUI() { override fun setUpUI() {
bn.apply {
btnResend.setOnClickListener(object : ButtonClick() {
override fun onSingleClick(v: View?) {
// viewModel.resendSms(pref.userPhone.filter { it.isDigit() },cardNumber,cardExpire)
viewModel.resendSms("998949125150", cardNumber, cardExpire)
}
})
btnConfirm.setOnClickListener(object : ButtonClick() {
override fun onSingleClick(v: View?) {
viewModel.cardConfirm(cardId, getLinePinCodes())
}
})
toolbar.setNavigationOnClickListener { navController.navigateUp() }
loadEdited()
frame.setOnClickListener(object : ButtonClick() {
override fun onSingleClick(v: View?) {
checkFocus().showKeyboard()
setColorPins(getColorCompat(R.color.black100))
}
})
coutdownView.setOnCountdownEndListener {
count(false)
}
}
}
private fun count(status: Boolean) {
bn.apply {
btnResend.isVisible = !status
coutdownViewHelperText.isVisible = !status
coutdownView.isVisible = status
if (status) coutdownView.start(CONSTANTS.RESEND_CODE_TIME)
}
} }
override fun collects() { override fun collects() {
viewLifecycleOwner.lifecycleScope.launchWhenStarted { viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.mainIndexUiState.collect { viewModel.cardConfirmUiState.collect {
when (it) { when (it) {
is UiStateObject.SUCCESS -> { is UiStateObject.SUCCESS -> {
showProgressDialog(false)
showSuccessDialog()
} }
is UiStateObject.ERROR -> { is UiStateObject.ERROR -> {
showProgressDialog(false)
setColorPins(getColorCompat(R.color.primary100))
bn.txtErrorCode.isVisible = true
bn.pinView.startAnimation(AnimationUtils.loadAnimation(requireContext(), R.anim.shake))
showToastMessage(it.message)
}
is UiStateObject.LOADING -> {
showProgressDialog(true)
}
else -> Unit
}
}
}
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.resendSmsUiState.collect {
when (it) {
is UiStateObject.SUCCESS -> {
showProgressDialog(false)
count(true)
}
is UiStateObject.ERROR -> {
showProgressDialog(false)
} }
is UiStateObject.LOADING -> { is UiStateObject.LOADING -> {
showProgressDialog(true)
}
else -> Unit
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
activity?.hideSoftInput(bn.etConfirmCode)
if (requestCode == 200) {
if (resultCode == Activity.RESULT_OK && data != null) { //That gives all message to us.
val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
message?.let {
getOtpFromMessage(message)
}
}
}
}
private fun getOtpFromMessage(message: String) { // This will match any 6 digit number in the message
val matcher = Pattern.compile("(|^)\\d{6}").matcher(message)
if (matcher.find()) {
setTextPinCodes(matcher.group(0))
// etConfirmCode.setText(matcher.group(0))
} }
else -> Unit
} }
private fun showSuccessDialog() {
val dialog = MessageDialog(
requireContext(),
getString(uz.agr.mobiuz.R.string.agr_mobi_uz_card_added),
getString(uz.agr.mobiuz.R.string.agr_mobi_uz_close_process)
)
dialog.window!!.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.setCanceledOnTouchOutside(true)
dialog.setOnOkClickListener(object : MessageDialog.OnClickListener {
override fun dialogPositiveClicked() {
dialog.dismiss()
navController.popBackStack(R.id.cardsListFragment, false)
}
})
dialog.show()
}
private fun getLinePinCodes(): String {
bn.apply {
code = ""
code += pin1.text.toString()
code += pin2.text.toString()
code += pin3.text.toString()
code += pin4.text.toString()
code += pin5.text.toString()
code += pin6.text.toString()
}
return code.filter { it.isDigit() }
} }
private fun setColorPins(color: Int) {
bn.apply {
pin1.setTextColor(color)
pin2.setTextColor(color)
pin3.setTextColor(color)
pin4.setTextColor(color)
pin5.setTextColor(color)
pin6.setTextColor(color)
} }
}
private fun checkFocus(): View {
bn.apply {
return when {
pin1.isEmpty() -> pin1
pin2.isEmpty() -> pin2
pin3.isEmpty() -> pin3
pin4.isEmpty() -> pin4
pin5.isEmpty() -> pin5
else -> pin6
}
}
} }
private fun clearLatest(): View {
bn.apply {
return when {
pin6.isNotEmpty() -> pin6.clearText()
pin5.isNotEmpty() -> pin5.clearText()
pin4.isNotEmpty() -> pin4.clearText()
pin3.isNotEmpty() -> pin3.clearText()
pin2.isNotEmpty() -> pin2.clearText()
else -> pin1.clearText()
}
}
}
private fun setTextPinCodes(code: String) {
bn.apply {
if (code.length != 6) return
pin1.setText(code[0].toString())
pin2.setText(code[1].toString())
pin3.setText(code[2].toString())
pin4.setText(code[3].toString())
pin5.setText(code[4].toString())
pin6.setText(code[5].toString())
}
}
private fun loadEdited() {
bn.apply {
for (i in 0 until pinView.childCount) {
(pinView.getChildAt(i) as TextInputEditText).apply {
this.addTextChangedListener(object : TextWatcherWrapper() {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
super.onTextChanged(s, start, before, count)
bn.txtErrorCode.isVisible = false
txtErrorCode.visible(false)
if (s.toString().isNotEmpty()) {
if (i == pinView.childCount - 1) {
pin6.hideKeyboard()
btnConfirm.isEnabled = true
} else pinView.getChildAt(i + 1).requestFocus()
this@apply.setBackgroundResource(uz.agr.mobiuz.R.drawable.agr_bgn_ver_checked)
} else {
if (i == pinView.childCount - 1) {
btnConfirm.isEnabled = false
}
this@apply.setBackgroundResource(uz.agr.mobiuz.R.drawable.agr_bgn_ver_unchecked)
}
}
})
}
}
for (i in 0 until pinView.childCount) {
pinView.getChildAt(i).setOnKeyListener { _, keyCode, event ->
if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_DEL) {
clearLatest().requestFocus()
return@setOnKeyListener false
}
false
}
}
}
}
private fun startSmsUserConsent() {
val client = SmsRetriever.getClient(requireContext())
client.startSmsUserConsent(null)
.addOnSuccessListener { /**/ }
.addOnFailureListener { /**/ }
}
private fun registerBroadcastReceiver() {
smsBroadcastReceiver = SmsBroadcastReceiver()
smsBroadcastReceiver!!.smsBroadcastReceiverListener =
object : SmsBroadcastReceiver.SmsBroadcastReceiverListener {
override fun onSuccess(intent: Intent?) {
startActivityForResult(intent, 200)
}
override fun onFailure() {}
}
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
context?.registerReceiver(smsBroadcastReceiver, intentFilter)
}
override fun onDestroy() { override fun onDestroy() {
requireActivity().unregisterReceiver(smsBroadcastReceiver)
_bn = null _bn = null
super.onDestroy() super.onDestroy()
} }
......
...@@ -7,18 +7,19 @@ import android.view.ViewGroup ...@@ -7,18 +7,19 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.hannesdorfmann.adapterdelegates4.AdapterDelegate import com.hannesdorfmann.adapterdelegates4.AdapterDelegate
import kotlinx.android.synthetic.main.mobi_uz_item_card.view.* import kotlinx.android.synthetic.main.mobi_uz_item_card.view.*
import timber.log.Timber
import uz.agr.sdk.core.entity.card.CardInfo import uz.agr.sdk.core.entity.card.CardInfo
import uz.agr.sdk.coreui.extension.* import uz.agr.sdk.coreui.extension.*
import uz.agr.sdk.coreui.model.storage.Prefs import uz.agr.sdk.coreui.model.storage.Prefs
import uz.mobiuz.mobiservice.dev.R import uz.mobiuz.mobiservice.dev.R
import uz.mobiuz.mobiservice.dev.utils.LayoutContainer import uz.mobiuz.mobiservice.dev.utils.extensions.MultiBlock
class CardDelegate( class CardDelegate(
private val hideSettingsIcon: (Boolean), private val hideSettingsIcon: (Boolean),
private val clickListener: (CardInfo, Int) -> Unit
) : AdapterDelegate<MutableList<Any>>() { ) : AdapterDelegate<MutableList<Any>>() {
private var listener: MultiBlock<CardInfo, Int>? = null
private var amount: Long = 0L private var amount: Long = 0L
private var cardsList: List<String> = emptyList() private var cardsList: List<String> = emptyList()
...@@ -42,7 +43,7 @@ class CardDelegate( ...@@ -42,7 +43,7 @@ class CardDelegate(
return (viewHolder as ViewHolder).bind(items[position] as CardInfo, position) return (viewHolder as ViewHolder).bind(items[position] as CardInfo, position)
} }
private inner class ViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView), LayoutContainer { private inner class ViewHolder(val containerView: View) : RecyclerView.ViewHolder(containerView) {
private lateinit var cardInfo: CardInfo private lateinit var cardInfo: CardInfo
init { init {
...@@ -60,7 +61,7 @@ class CardDelegate( ...@@ -60,7 +61,7 @@ class CardDelegate(
} }
if (!hideSettingsIcon) { if (!hideSettingsIcon) {
containerView.btnSetting.setOnClickListener { containerView.btnSetting.setOnClickListener {
clickListener(cardInfo, adapterPosition) listener?.invoke(cardInfo, adapterPosition)
} }
} }
containerView.btnSetting.visible(!hideSettingsIcon) containerView.btnSetting.visible(!hideSettingsIcon)
...@@ -70,12 +71,10 @@ class CardDelegate( ...@@ -70,12 +71,10 @@ class CardDelegate(
fun bind(cardInfo: CardInfo, position: Int) { fun bind(cardInfo: CardInfo, position: Int) {
this.cardInfo = cardInfo this.cardInfo = cardInfo
containerView.tvCardBalance.text = cardInfo.balance.formattedMoney() + " " + containerView.context.getString(R.string.agr_mobi_uz_curr) containerView.tvCardBalance.text = cardInfo.balance.formattedMoney() + " " + itemView.context.getString(R.string.agr_mobi_uz_curr)
containerView.tvCardPan.text = cardInfo.pan.formatToMaskedCardPan() containerView.tvCardPan.text = cardInfo.pan.formatToMaskedCardPan()
containerView.tvCardExpire.text = cardInfo.getExpiryFormatted() containerView.tvCardExpire.text = cardInfo.getExpiryFormatted()
containerView.tvCardHolderName.text = cardInfo.fullName containerView.tvCardHolderName.text = cardInfo.fullName
Timber.e("PAN: ${cardInfo.pan}")
Timber.e("EXpire: ${cardInfo.expiry}")
val isUzCard = cardInfo.pan.startsWith("8600") val isUzCard = cardInfo.pan.startsWith("8600")
val isHumoCard = cardInfo.pan.startsWith("9860") val isHumoCard = cardInfo.pan.startsWith("9860")
if (isHumoCard) { if (isHumoCard) {
...@@ -89,7 +88,7 @@ class CardDelegate( ...@@ -89,7 +88,7 @@ class CardDelegate(
private fun itemClicked() { private fun itemClicked() {
if (amount <= cardInfo.balance) if (amount <= cardInfo.balance)
clickListener(cardInfo, adapterPosition) listener?.invoke(cardInfo, adapterPosition)
else showError() else showError()
} }
...@@ -103,4 +102,8 @@ class CardDelegate( ...@@ -103,4 +102,8 @@ class CardDelegate(
dialog.show() dialog.show()
} }
} }
fun setOnClickListener(block: MultiBlock<CardInfo, Int>) {
listener = block
}
} }
\ No newline at end of file
package uz.mobiuz.mobiservice.dev.ui.sdk.card package uz.mobiuz.mobiservice.dev.ui.sdk.card
import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import uz.agr.sdk.core.entity.card.CardInfo
import uz.agr.sdk.core.entity.card.CardRegistration import uz.agr.sdk.core.entity.card.CardRegistration
import uz.agr.sdk.pgw_core.mobi.BaseListener import uz.agr.sdk.pgw_core.mobi.BaseListener
import uz.agr.sdk.pgw_core.mobi.CardListenerMobi
import uz.agr.sdk.pgw_core.mobi.MobiUz import uz.agr.sdk.pgw_core.mobi.MobiUz
import uz.mobiuz.mobiservice.dev.network.model.UiStateList
import uz.mobiuz.mobiservice.dev.network.model.UiStateObject import uz.mobiuz.mobiservice.dev.network.model.UiStateObject
import uz.mobiuz.mobiservice.dev.network.repository.MainRepository import uz.mobiuz.mobiservice.dev.network.repository.MainRepository
import javax.inject.Inject import javax.inject.Inject
...@@ -19,29 +21,95 @@ class CardViewModel @Inject constructor( ...@@ -19,29 +21,95 @@ class CardViewModel @Inject constructor(
private val repository: MainRepository private val repository: MainRepository
) : ViewModel() { ) : ViewModel() {
private val _cardListUiState = MutableSharedFlow<UiStateList<CardInfo>>()
val cardListUiState: SharedFlow<UiStateList<CardInfo>> = _cardListUiState
fun getAllCards() = viewModelScope.launch {
_cardListUiState.emit(UiStateList.LOADING)
MobiUz.getAllCards(object : CardListenerMobi<CardInfo> {
override fun error(message: String) {
viewModelScope.launch {
_cardListUiState.emit(UiStateList.ERROR(message))
}
}
override fun loading(boolean: Boolean) {}
override fun local(localData: List<CardInfo>) {
viewModelScope.launch {
_cardListUiState.emit(UiStateList.SUCCESS(localData))
}
}
override fun server(serverData: List<CardInfo>) {
viewModelScope.launch {
_cardListUiState.emit(UiStateList.SUCCESS(serverData))
}
}
})
}
private val _cardRegistrationUiState = MutableSharedFlow<UiStateObject<CardRegistration>>() private val _cardRegistrationUiState = MutableSharedFlow<UiStateObject<CardRegistration>>()
val cardRegistrationUiState: SharedFlow<UiStateObject<CardRegistration>> = _cardRegistrationUiState val cardRegistrationUiState: SharedFlow<UiStateObject<CardRegistration>> = _cardRegistrationUiState
fun cardRegistration(phone: String, card: String, expire: String) = viewModelScope.launch { fun cardRegistration(phone: String, card: String, expire: String) = viewModelScope.launch {
_cardRegistrationUiState.emit(UiStateObject.LOADING)
MobiUz.registerCard(phone, card, expire, object : BaseListener<CardRegistration> { MobiUz.registerCard(phone, card, expire, object : BaseListener<CardRegistration> {
override fun error(message: String) { override fun error(message: String) {
Log.d("TAG", "error: ")
viewModelScope.launch { viewModelScope.launch {
_cardRegistrationUiState.emit(UiStateObject.ERROR(message)) _cardRegistrationUiState.emit(UiStateObject.ERROR(message))
} }
} }
override fun loading(boolean: Boolean) { override fun loading(boolean: Boolean) {}
Log.d("TAG", "loading: $boolean ")
override fun success(data: CardRegistration) {
viewModelScope.launch { viewModelScope.launch {
_cardRegistrationUiState.emit(UiStateObject.LOADING) _cardRegistrationUiState.emit(UiStateObject.SUCCESS(data))
} }
} }
})
}
private val _cardConfirmUiState = MutableSharedFlow<UiStateObject<CardInfo>>()
val cardConfirmUiState: SharedFlow<UiStateObject<CardInfo>> = _cardConfirmUiState
fun cardConfirm(cardId: String, code: String) = viewModelScope.launch {
_cardConfirmUiState.emit(UiStateObject.LOADING)
MobiUz.cardConfirmSms(cardId, code, object : BaseListener<CardInfo> {
override fun error(message: String) {
viewModelScope.launch {
_cardConfirmUiState.emit(UiStateObject.ERROR(message))
}
}
override fun loading(boolean: Boolean) {}
override fun success(data: CardInfo) {
viewModelScope.launch {
_cardConfirmUiState.emit(UiStateObject.SUCCESS(data))
}
}
})
}
private val _resendSmsUiState = MutableSharedFlow<UiStateObject<CardRegistration>>()
val resendSmsUiState: SharedFlow<UiStateObject<CardRegistration>> = _resendSmsUiState
fun resendSms(phoneNumber: String, cardNumber: String, cardExpire: String) = viewModelScope.launch {
_resendSmsUiState.emit(UiStateObject.LOADING)
MobiUz.registerCardResendSms(phoneNumber, cardNumber, cardExpire,object : BaseListener<CardRegistration> {
override fun error(message: String) {
viewModelScope.launch {
_resendSmsUiState.emit(UiStateObject.ERROR(message))
}
}
override fun loading(boolean: Boolean) {}
override fun success(data: CardRegistration) { override fun success(data: CardRegistration) {
Log.d("TAG", "success: ${data.maskedPhoneNumber} ")
viewModelScope.launch { viewModelScope.launch {
_cardRegistrationUiState.emit(UiStateObject.SUCCESS(data)) _resendSmsUiState.emit(UiStateObject.SUCCESS(data))
} }
} }
}) })
......
...@@ -2,27 +2,25 @@ package uz.mobiuz.mobiservice.dev.ui.sdk.card ...@@ -2,27 +2,25 @@ package uz.mobiuz.mobiservice.dev.ui.sdk.card
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import com.hannesdorfmann.adapterdelegates4.ListDelegationAdapter import com.hannesdorfmann.adapterdelegates4.ListDelegationAdapter
import uz.agr.mobiuz.ui.card.select.CardDelegate
import uz.agr.sdk.core.entity.card.CardInfo import uz.agr.sdk.core.entity.card.CardInfo
import uz.agr.sdk.coreui.ui.list.ProgressAdapterDelegate import uz.agr.sdk.coreui.ui.list.ProgressAdapterDelegate
import uz.agr.sdk.coreui.ui.list.ProgressItem import uz.agr.sdk.coreui.ui.list.ProgressItem
import uz.mobiuz.mobiservice.dev.utils.extensions.MultiBlock import uz.mobiuz.mobiservice.dev.utils.extensions.MultiBlock
import uz.mobiuz.mobiservice.dev.utils.extensions.SingleBlock
class CardsListAdapter( class CardsListAdapter(
hideSettingsIcon: (Boolean), private val hideSettingsIcon: Boolean,
clickListener: (CardInfo, Int) -> Unit
) : ListDelegationAdapter<MutableList<Any>>() { ) : ListDelegationAdapter<MutableList<Any>>() {
// private var listener: MultiBlock<CardInfo,Int>? = null
// private var listener: MultiBlock<CardInfo, Int>? = null
// fun setOnClickListener(block: MultiBlock<CardInfo,Int>){
// listener = block
// }
init { init {
items = mutableListOf() items = mutableListOf()
delegatesManager.addDelegate(CardDelegate(hideSettingsIcon, clickListener)) val delegateAdapter = CardDelegate(hideSettingsIcon)
delegateAdapter.setOnClickListener { cardInfo, i ->
listener?.invoke(cardInfo,i)
}
delegatesManager.addDelegate(delegateAdapter)
delegatesManager.addDelegate(ProgressAdapterDelegate()) delegatesManager.addDelegate(ProgressAdapterDelegate())
} }
...@@ -86,4 +84,8 @@ class CardsListAdapter( ...@@ -86,4 +84,8 @@ class CardsListAdapter(
} }
} }
} }
fun setOnClickListener(block: MultiBlock<CardInfo, Int>) {
listener = block
}
} }
\ No newline at end of file
package uz.mobiuz.mobiservice.dev.ui.sdk.card package uz.mobiuz.mobiservice.dev.ui.sdk.card
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import uz.agr.mobiuz.presentation.card.dialog.MessageDialogFragment
import uz.agr.sdk.core.entity.card.CardInfo import uz.agr.sdk.core.entity.card.CardInfo
import uz.agr.sdk.core.entity.card.CardRegistration import uz.agr.sdk.coreui.extension.formattedCardNumber
import uz.agr.sdk.coreui.extension.visible
import uz.agr.sdk.coreui.ui.decoration.EndOffsetItemDecoration
import uz.agr.sdk.coreui.ui.decoration.StartOffsetItemDecoration
import uz.agr.sdk.pgw_core.mobi.BaseListener import uz.agr.sdk.pgw_core.mobi.BaseListener
import uz.agr.sdk.pgw_core.mobi.CardListenerMobi
import uz.agr.sdk.pgw_core.mobi.MobiUz import uz.agr.sdk.pgw_core.mobi.MobiUz
import uz.mobiuz.mobiservice.dev.R import uz.mobiuz.mobiservice.dev.R
import uz.mobiuz.mobiservice.dev.databinding.FragmentCardsListBinding import uz.mobiuz.mobiservice.dev.databinding.FragmentCardsListBinding
import uz.mobiuz.mobiservice.dev.model.SharedPref import uz.mobiuz.mobiservice.dev.model.SharedPref
import uz.mobiuz.mobiservice.dev.network.model.UiStateList
import uz.mobiuz.mobiservice.dev.ui.base.BaseFragment import uz.mobiuz.mobiservice.dev.ui.base.BaseFragment
import uz.mobiuz.mobiservice.dev.ui.global.CONSTANTS import uz.mobiuz.mobiservice.dev.ui.global.CONSTANTS
import javax.inject.Inject import javax.inject.Inject
...@@ -30,11 +39,14 @@ class CardsListFragment : BaseFragment(R.layout.fragment_cards_list) { ...@@ -30,11 +39,14 @@ class CardsListFragment : BaseFragment(R.layout.fragment_cards_list) {
private val bn get() = _bn ?: throw NullPointerException("cannot inflate") private val bn get() = _bn ?: throw NullPointerException("cannot inflate")
private val viewModel: CardViewModel by viewModels() private val viewModel: CardViewModel by viewModels()
private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { NavHostFragment.findNavController(this) } private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { NavHostFragment.findNavController(this) }
private var phone = "" private var phone = ""
private var selectedCard: CardInfo? = null
private lateinit var adapter: CardsListAdapter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
adapter = CardsListAdapter(false)
arguments?.let { arguments?.let {
phone = it.getString(CONSTANTS.PHONE) ?: "" phone = it.getString(CONSTANTS.PHONE) ?: ""
} }
...@@ -44,14 +56,20 @@ class CardsListFragment : BaseFragment(R.layout.fragment_cards_list) { ...@@ -44,14 +56,20 @@ class CardsListFragment : BaseFragment(R.layout.fragment_cards_list) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_bn = FragmentCardsListBinding.bind(view) _bn = FragmentCardsListBinding.bind(view)
viewModel.getAllCards()
setUpUI() setUpUI()
collects() collects()
} }
override fun setUpUI() { override fun setUpUI() {
bn.apply { bn.apply {
adapter.setOnClickListener { cardInfo, i ->
onCardClicked(cardInfo)
}
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
navController.navigateUp() navController.navigateUp()
} }
...@@ -60,99 +78,186 @@ class CardsListFragment : BaseFragment(R.layout.fragment_cards_list) { ...@@ -60,99 +78,186 @@ class CardsListFragment : BaseFragment(R.layout.fragment_cards_list) {
// addCard() // addCard()
navController.navigate(R.id.addCardFragment) navController.navigate(R.id.addCardFragment)
} }
}
MobiUz.hasCards(object : BaseListener<Boolean> { recyclerView.apply {
layoutManager = LinearLayoutManager(context)
setHasFixedSize(true)
adapter = this@CardsListFragment.adapter
visible(false)
}
recyclerView.addItemDecoration(
StartOffsetItemDecoration(
resources.getDimensionPixelOffset(
uz.agr.mobiuz.R.dimen.agr_card_list_start_offset
)
)
)
recyclerView.addItemDecoration(
EndOffsetItemDecoration(
resources.getDimensionPixelOffset(
uz.agr.mobiuz.R.dimen.agr_card_list_end_offset
)
)
)
swipeToRefresh.setColorSchemeResources(
uz.agr.mobiuz.R.color.agr_black,
uz.agr.mobiuz.R.color.agr_mobi_uz_colorAccent
)
swipeToRefresh.setOnRefreshListener {
MobiUz.refreshCardsInfo(object : BaseListener<List<CardInfo>>{
override fun error(message: String) { override fun error(message: String) {
showToastMessage(message)
} }
override fun loading(boolean: Boolean) { override fun loading(boolean: Boolean) {
swipeToRefresh.isRefreshing = boolean
} }
override fun success(data: Boolean) { override fun success(data: List<CardInfo>) {
getAllCards() setData(data)
} }
}) })
} }
private fun getAllCards() {
MobiUz.getAllCards(object : CardListenerMobi<CardInfo> {
override fun error(message: String) {
} }
override fun loading(boolean: Boolean) {
} }
override fun local(localData: List<CardInfo>) { private fun onCardClicked(cardInfo: CardInfo) {
selectedCard = cardInfo
showDeleteCardConfirmDialog(cardInfo.pan.formattedCardNumber())
} }
override fun server(serverData: List<CardInfo>) { private fun showDeleteCardConfirmDialog(cardNumber: String) {
val dialog = MessageDialogFragment(requireContext(), getString(uz.agr.mobiuz.R.string.agr_mobi_uz_delete_card_question))
} dialog.window!!.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
}) dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.setCanceledOnTouchOutside(true)
dialog.setOnCancelClickListener {
dialog.dismiss()
} }
dialog.setOnOkClickListener {
private fun addCard() { MobiUz.deleteCard(selectedCard!!,object : BaseListener<Boolean>{
MobiUz.registerCard("998990552109", "8600312917291250", "0325", object : BaseListener<CardRegistration> {
override fun error(message: String) { override fun error(message: String) {
Log.e("TTT", "error:$message")
} }
override fun loading(boolean: Boolean) { override fun loading(boolean: Boolean) {
Log.e("TTT", "loading:$boolean") // showProgressDialog(boolean)
} }
override fun success(data: CardRegistration) { override fun success(data: Boolean) {
Log.e("TTT", "success:${data.maskedPhoneNumber}") viewModel.getAllCards()
} }
}) })
dialog.dismiss()
} }
dialog.show()
private fun cardConfirm(cardId: String, code: String) {
MobiUz.cardConfirmSms(cardId, code, object : BaseListener<CardInfo> {
override fun error(message: String) {
}
override fun loading(boolean: Boolean) {
} }
override fun success(data: CardInfo) {
} // private fun hasCards() {
}) // MobiUz.hasCards(object : BaseListener<Boolean> {
} // override fun error(message: String) {
//
// }
//
// override fun loading(boolean: Boolean) {
//
// }
//
// override fun success(data: Boolean) {
// getAllCards()
// }
// })
// }
//
// private fun getAllCards() {
// MobiUz.getAllCards(object : CardListenerMobi<CardInfo> {
// override fun error(message: String) {
//
// }
//
// override fun loading(boolean: Boolean) {
//
// }
//
// override fun local(localData: List<CardInfo>) {
// setData(localData)
// }
//
// override fun server(serverData: List<CardInfo>) {
// setData(serverData)
// }
// })
// }
private fun delete(card: CardInfo) { private fun setData(data: List<CardInfo>) {
MobiUz.deleteCard(card) bn.recyclerView.isVisible = data.isNotEmpty()
bn.layoutEmpty.root.isVisible = data.isEmpty()
adapter.setData(data)
} }
// private fun addCard() {
override fun collects() { // MobiUz.registerCard("998990552109", "8600312917291250", "0325", object : BaseListener<CardRegistration> {
viewLifecycleOwner.lifecycleScope.launchWhenStarted { // override fun error(message: String) {
// viewModel.mainIndexUiState.collect { // Log.e("TTT", "error:$message")
// when (it) { // }
// is UiStateObject.SUCCESS -> { //
// override fun loading(boolean: Boolean) {
// Log.e("TTT", "loading:$boolean")
// }
// //
// override fun success(data: CardRegistration) {
// Log.e("TTT", "success:${data.maskedPhoneNumber}")
// }
// })
// }
//
// private fun cardConfirm(cardId: String, code: String) {
// MobiUz.cardConfirmSms(cardId, code, object : BaseListener<CardInfo> {
// override fun error(message: String) {
// //
// } // }
// is UiStateObject.ERROR -> {
// //
// override fun loading(boolean: Boolean) {
// //
// } // }
// is UiStateObject.LOADING -> {
// //
// override fun success(data: CardInfo) {
// //
// } // }
// else -> Unit // })
//
//
// } // }
//
// private fun delete(card: CardInfo) {
// MobiUz.deleteCard(card)
// } // }
override fun collects() {
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.cardListUiState.collect {
when (it) {
is UiStateList.SUCCESS -> {
showProgressDialog(false)
setData(it.data)
}
is UiStateList.ERROR -> {
showToastMessage(it.message)
showProgressDialog(false)
}
is UiStateList.LOADING -> {
showProgressDialog(true)
}
else -> Unit
}
}
} }
......
...@@ -126,7 +126,7 @@ ...@@ -126,7 +126,7 @@
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginBottom="40dp" android:layout_marginBottom="40dp"
android:enabled="false" android:enabled="true"
android:text="@string/agr_mobi_uz_add_card" android:text="@string/agr_mobi_uz_add_card"
android:textStyle="bold" /> android:textStyle="bold" />
</LinearLayout> </LinearLayout>
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
...@@ -130,45 +131,85 @@ ...@@ -130,45 +131,85 @@
android:visibility="gone" android:visibility="gone"
tools:ignore="Autofill,LabelFor" /> tools:ignore="Autofill,LabelFor" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="28dp"
android:layout_gravity="center"
android:layout_marginTop="@dimen/_34sdp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pin_view_group">
<TextView <TextView
android:id="@+id/tvTimeOut" android:id="@+id/countWaitText"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="32dp" android:layout_gravity="center_vertical"
android:layout_marginTop="64dp" android:text="@string/sent_code_again"
android:layout_marginRight="32dp" android:textColor="@color/grey110"
android:gravity="center" android:textSize="16sp" />
android:textColor="@color/agr_grey110"
android:textSize="14sp" <cn.iwgang.countdownview.CountdownView
tools:text="@string/agr_mobi_uz_sms_time_out_info" /> android:id="@+id/coutdown_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/_4sdp"
android:layout_marginTop="2dp"
app:isHideTimeBackground="false"
app:isShowDay="false"
app:isShowHour="false"
app:isShowMillisecond="false"
app:isShowMinute="true"
app:isShowSecond="true"
app:isShowTimeBgBorder="false"
app:isShowTimeBgDivisionLine="false"
app:suffixDay="days"
app:suffixGravity="center"
app:suffixHour=":"
app:suffixMillisecond="ss"
app:suffixMinute=":"
app:suffixSecond=""
app:suffixTextColor="@color/grey100"
app:suffixTextSize="14sp"
app:timeBgColor="@color/white100"
app:timeBgRadius="3dp"
app:timeBgSize="14dp"
app:timeTextSize="14sp" />
<TextView
android:id="@+id/coutdown_view_helper_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/_4sdp"
android:text="00:00"
android:textColor="@color/primary100"
android:textSize="16sp"
android:visibility="gone" />
</LinearLayout>
<Button <Button
android:id="@+id/btnConfirm" android:id="@+id/btnConfirm"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="56dp" android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginTop="51dp" android:layout_marginTop="51dp"
android:background="@drawable/button_selector"
android:enabled="false" android:enabled="false"
android:text="@string/agr_mobi_uz_next" android:text="@string/agr_mobi_uz_next" />
android:textAllCaps="false"
android:textColor="@color/agr_white"
android:textSize="15sp"
android:textStyle="bold" />
<Button <TextView
android:id="@+id/btnResend" android:id="@+id/btnResend"
style="@style/Widget.AppCompat.Button.Borderless.Colored" android:background="?android:selectableItemBackground"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="56dp" android:layout_height="wrap_content"
android:gravity="center"
android:paddingVertical="16dp"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_marginStart="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:text="@string/agr_mobi_uz_sms_resend" android:text="@string/agr_mobi_uz_sms_resend"
android:textAllCaps="false"
android:textColor="@color/primary100" android:textColor="@color/primary100"
android:textSize="14sp" android:textSize="14sp"
android:textStyle="bold" android:textStyle="bold"
......
...@@ -33,13 +33,15 @@ ...@@ -33,13 +33,15 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:visibility="visible"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:listitem="@layout/agr_item_card" tools:listitem="@layout/mobi_uz_item_card"
tools:paddingTop="@dimen/agr_card_list_start_offset" /> tools:paddingTop="@dimen/agr_card_list_start_offset" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<include <include
layout="@layout/agr_layout_empty" android:id="@+id/layout_empty"
layout="@layout/layout_empty"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="gone" /> android:visibility="gone" />
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
android:id="@+id/view_group" android:id="@+id/view_group"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/emptyLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/agr_white">
<Space
android:id="@+id/spaceTop"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/agr_white"
app:layout_constraintBottom_toTopOf="@id/ivNoCard"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_weight="1" />
<ImageView
android:id="@+id/ivNoCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/_25sdp"
android:contentDescription="@null"
app:layout_constraintBottom_toTopOf="@id/tvNoCard"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/ic_agr_no_cards" />
<TextView
android:id="@+id/tvNoCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:letterSpacing="0.05"
android:lineSpacingExtra="2dp"
android:layout_marginHorizontal="@dimen/_30sdp"
android:text="@string/agr_mobi_uz_no_card"
android:textColor="@color/agr_grey80"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Space
android:id="@+id/spaceBottom"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvNoCard"
app:layout_constraintVertical_weight="1.3" />
</androidx.constraintlayout.widget.ConstraintLayout>
...@@ -4,8 +4,7 @@ ...@@ -4,8 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="180dp" android:layout_height="180dp"
android:layout_marginStart="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="@dimen/_8sdp" android:layout_marginBottom="@dimen/_8sdp"
app:cardCornerRadius="@dimen/_6sdp"> app:cardCornerRadius="@dimen/_6sdp">
...@@ -143,5 +142,9 @@ ...@@ -143,5 +142,9 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvCardBalance" app:layout_constraintTop_toTopOf="@id/tvCardBalance"
app:srcCompat="@drawable/ic_mobi_uz_delete" /> app:srcCompat="@drawable/ic_mobi_uz_delete" />
<View
android:layout_width="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_height="1dp"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
\ No newline at end of file
...@@ -82,8 +82,13 @@ ...@@ -82,8 +82,13 @@
android:label="AddCardFragment" /> android:label="AddCardFragment" />
<fragment <fragment
android:id="@+id/cardConfirmFragment" android:id="@+id/cardConfirmFragment"
tools:layout="" tools:layout="@layout/fragment_card_confirm"
android:name="uz.mobiuz.mobiservice.dev.ui.sdk.card.CardConfirmFragment" android:name="uz.mobiuz.mobiservice.dev.ui.sdk.card.CardConfirmFragment"
android:label="CardConfirmFragment" /> android:label="CardConfirmFragment" />
<fragment
android:id="@+id/verificationFragment"
android:name="uz.mobiuz.mobiservice.dev.ui.auth.verification.VerificationFragment"
android:label="MyVerificationFragment" />
</navigation> </navigation>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment