Advertisement
BlackZerg

Phone Number

Aug 13th, 2021
1,111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 6.30 KB | None | 0 0
  1. //Fragment
  2. class PhoneFragment : BaseFragment(R.layout.fragment_phone) {
  3.  
  4.     private val viewModel: PhoneViewModel by lazy { injectViewModel() }
  5.  
  6.     private val contextMenu: ContextMenuDialog by lazy { ContextMenuDialog() }
  7.  
  8.     override fun setupUI(v: View) {
  9.         FragmentPhoneBinding.bind(v).apply {
  10.             subtitle.startAnimation(root.context.setAnimationTextLeft())
  11.             phoneET.apply {
  12.                 requestFocus()
  13.                 setOnFocusChangeListener { _, hasFocus ->
  14.                     if (hasFocus) {
  15.                         setupTextEditWatcher(this, false, PHONE_NUMBER_MASK, CODE_LENGTH) {
  16.                             viewModel.onSetPhoneNumber(it)
  17.                             updateEditText(it, edBackgroundInput)
  18.                         }
  19.                     }
  20.                 }
  21.             }
  22.             menu.setOnClickListener {
  23.                 contextMenu.show(requireActivity().supportFragmentManager, DIALOG_MENU_TAG)
  24.             }
  25.             loginButton.setOnClickListener {
  26.                 viewModel.sendLoginCode(phoneET.text.toString())
  27.             }
  28.             lifecycleScope.launch {
  29.                 launch { viewModel.progress.collect { progressBar.showProgressBar(it) } }
  30.                 launch {
  31.                     viewModel.errors.collect { ex ->
  32.                         processingServerError(ex, requireActivity()) { }
  33.                     }
  34.                 }
  35.                 launch { viewModel.watchButtonState.collect { renderButton(it, this@apply) } }
  36.                 launch {
  37.                     viewModel
  38.                         .watchPhoneNumberSending
  39.                         .filter { status -> status == PhoneStatusType.SUCCESS }
  40.                         .combine(viewModel.watchPhoneNumber) { _, p -> p }
  41.                         .combine(viewModel.watchVerificationCode) { p, c -> p to c }
  42.                         .collect { (p, c) ->
  43.                             navigateTo(
  44.                                 R.id.action_phoneFragment_to_codeFragment,
  45.                                 bundleOf(
  46.                                     KEY_PHONE_NUMBER to p,
  47.                                     KEY_VERIFICATION_CODE to c
  48.                                 )
  49.                             )
  50.                         }
  51.                 }
  52.             }
  53.         }
  54.     }
  55.  
  56.     override fun setupObserver() {  }
  57.  
  58.     private fun updateEditText(phone: String, backgroundInput: EditText) {
  59.         val newHint = resources
  60.             .getString(R.string.hint_background)
  61.             .replaceRange(0, phone.length, phone)
  62.         backgroundInput.hint = newHint
  63.     }
  64.  
  65.     private fun renderButton(state: ButtonState, binding: FragmentPhoneBinding) {
  66.         binding.apply {
  67.             if (state != ButtonState.NeutralState) showFailedInput(
  68.                 state != ButtonState.DisabledState,
  69.                 root.context,
  70.                 phoneImageFail, false,
  71.                 tvPhone,
  72.                 resources.getString(R.string.phone_number),
  73.                 resources.getString(R.string.phone_number_fail)
  74.             )
  75.             loginButton.isEnabled = when (state) {
  76.                 ButtonState.NeutralState -> false
  77.                 ButtonState.DisabledState -> false
  78.                 ButtonState.EnabledState -> true
  79.             }
  80.         }
  81.     }
  82. }
  83.  
  84. //ViewModel
  85. class PhoneViewModel
  86. @Inject
  87. constructor(
  88.     private val repository: LoginRepository
  89. ) : ViewModel() {
  90.  
  91.     // Watchers
  92.     val progress: Flow<Int>
  93.         get() = _progress
  94.     val errors: Flow<Exception>
  95.         get() = _errors
  96.     val watchButtonState: Flow<ButtonState>
  97.         get() = _buttonState
  98.     val watchPhoneNumber: Flow<String>
  99.         get() = _phoneNumber
  100.     val watchVerificationCode: Flow<String>
  101.         get() = _verificationCode
  102.     val watchPhoneNumberSending: Flow<PhoneStatusType>
  103.         get() = _phoneNumberSending
  104.  
  105.     // Flows
  106.     private val _progress = MutableSharedFlow<Int>()
  107.     private val _errors = MutableSharedFlow<Exception>()
  108.     private val _buttonState = MutableStateFlow<ButtonState>(ButtonState.NeutralState)
  109.     private val _phoneNumber = MutableSharedFlow<String>()
  110.     private val _verificationCode = MutableSharedFlow<String>()
  111.     private val _phoneNumberSending = MutableSharedFlow<PhoneStatusType>()
  112.  
  113.     // Properties
  114.     private var counter = 0
  115.  
  116.     init {
  117.         viewModelScope.launch {
  118.             launch {
  119.                 _phoneNumber
  120.                     .filterNotNull()
  121.                     .collect { checkPhoneNumber(it) }
  122.             }
  123.             launch {
  124.                 _verificationCode
  125.                     .filterNotNull()
  126.                     .distinctUntilChanged()
  127.                     .collect { _phoneNumberSending.emit(PhoneStatusType.SUCCESS) }
  128.             }
  129.         }
  130.     }
  131.  
  132.     // Flow setters
  133.     fun onSetPhoneNumber(text: String) {
  134.         viewModelScope.launch { _phoneNumber.emit(text) }
  135.     }
  136.  
  137.     private fun onSetVerificationCode(code: String) {
  138.         viewModelScope.launch { _verificationCode.emit(code) }
  139.     }
  140.  
  141.     private suspend fun checkPhoneNumber(phone: String) {
  142.         _buttonState.emit(
  143.             when {
  144.                 phone.isEmpty() -> ButtonState.DisabledState
  145.                 phone.length == PHONE_HINT_LENGTH && containsPhoneSymbols(phone) ->
  146.                     ButtonState.EnabledState
  147.                 else -> ButtonState.DisabledState
  148.             }
  149.         )
  150.     }
  151.  
  152.     fun sendLoginCode(phone: String) {
  153.         viewModelScope.launch {
  154.             counter += 1
  155.             _progress.emit(counter)
  156.  
  157.             _buttonState.emit(ButtonState.NeutralState)
  158.  
  159.             when (val r = repository.getCode(createOtpModel(phone))) {
  160.                 is Left -> _errors.emit(r.value)
  161.                 is Right -> onSetVerificationCode(r.value.data.verificationCode)
  162.             }
  163.  
  164.             counter -= 1
  165.             _progress.emit(counter)
  166.         }
  167.     }
  168.  
  169.     private fun createOtpModel(phone: String) = OtpM(
  170.         replacePhoneSymbols(phone),
  171.         getDeviceId()
  172.     )
  173. }
  174.  
  175. //Extensions
  176. fun getDeviceId(): String = deviceId ?: UUID.randomUUID().toString()
  177.  
  178. fun containsPhoneSymbols(phone: String): Boolean =
  179.     replacePhoneSymbols(phone).length == UIUtility.PHONE_LENGTH
  180.  
  181. fun replacePhoneSymbols(phone: String): String = phone.replace("[^0-9]".toRegex(), "")
  182.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement