Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: QrCodeImport migrated to MVVM #2253

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import com.google.zxing.Result
Expand All @@ -17,34 +18,32 @@ import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobile.R
import org.mifos.mobile.databinding.FragmentQrCodeImportBinding
import org.mifos.mobile.models.beneficiary.Beneficiary
import org.mifos.mobile.presenters.QrCodeImportPresenter
import org.mifos.mobile.ui.activities.base.BaseActivity
import org.mifos.mobile.ui.enums.BeneficiaryState
import org.mifos.mobile.ui.fragments.base.BaseFragment
import org.mifos.mobile.ui.views.QrCodeImportView
import org.mifos.mobile.utils.Constants
import org.mifos.mobile.utils.QrCodeUiState
import org.mifos.mobile.utils.Toaster
import org.mifos.mobile.viewModels.QrCodeImportViewModel
import java.io.FileNotFoundException
import java.io.InputStream
import javax.inject.Inject

/**
* Created by manishkumar on 19/05/18.
*/
@AndroidEntryPoint
class QrCodeImportFragment : BaseFragment(), QrCodeImportView {
class QrCodeImportFragment : BaseFragment() {

private var _binding: FragmentQrCodeImportBinding? = null
private val binding get() = _binding!!

private lateinit var viewModel: QrCodeImportViewModel

private lateinit var qrUri: Uri
private var uriValue: String? = null
private var mFrameRect: RectF? = null
private var inputStream: InputStream? = null

@JvmField
@Inject
var qrCodeImportPresenter: QrCodeImportPresenter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (arguments != null) {
Expand All @@ -60,22 +59,40 @@ class QrCodeImportFragment : BaseFragment(), QrCodeImportView {
savedInstanceState: Bundle?,
): View {
_binding = FragmentQrCodeImportBinding.inflate(inflater, container, false)
viewModel = ViewModelProvider(this)[QrCodeImportViewModel::class.java]
setToolbarTitle(getString(R.string.import_qr))
// load the uri
setBitmapImage(qrUri)
binding.ivCropQrCode.setCompressFormat(Bitmap.CompressFormat.JPEG)
binding.ivCropQrCode.setOutputMaxSize(150, 150)
binding.ivCropQrCode.load(qrUri)
?.initialFrameRect(mFrameRect)
?.executeAsCompletable()
binding.ivCropQrCode.setCropMode(CropImageView.CropMode.FREE)
binding.ivCropQrCode.setInitialFrameScale(0.8f)
qrCodeImportPresenter?.attachView(this)
with(binding) {
ivCropQrCode.setCompressFormat(Bitmap.CompressFormat.JPEG)
ivCropQrCode.setOutputMaxSize(150, 150)
ivCropQrCode.load(qrUri)
?.initialFrameRect(mFrameRect)
?.executeAsCompletable()
ivCropQrCode.setCropMode(CropImageView.CropMode.FREE)
ivCropQrCode.setInitialFrameScale(0.8f)
}

return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

viewModel.qrCodeUiState.observe(viewLifecycleOwner) {
when (it) {
is QrCodeUiState.Loading -> showProgress()
is QrCodeUiState.ShowError -> {
hideProgress()
showErrorReadingQr(getString(it.message))
}
is QrCodeUiState.HandleDecodedResult -> {
hideProgress()
handleDecodedResult(it.result)
}
}
}

binding.btnProceed.setOnClickListener {
proceed()
}
Expand All @@ -98,15 +115,15 @@ class QrCodeImportFragment : BaseFragment(), QrCodeImportView {
}

fun proceed() {
qrCodeImportPresenter?.getDecodedResult(qrUri, binding.ivCropQrCode)
viewModel.getDecodedResult(qrUri, binding.ivCropQrCode)
}

/**
* It is called whenever any error occurs while executing a request
*
* @param message Error message that tells the user about the problem.
*/
override fun showErrorReadingQr(message: String?) {
fun showErrorReadingQr(message: String?) {
Toaster.show(binding.root, message)
}

Expand All @@ -117,7 +134,7 @@ class QrCodeImportFragment : BaseFragment(), QrCodeImportView {
*
* @param result contains the results from decoded QR bitmap
*/
override fun handleDecodedResult(result: Result?) {
fun handleDecodedResult(result: Result?) {
val gson = Gson()
try {
val beneficiary = gson.fromJson(result?.text, Beneficiary::class.java)
Expand All @@ -139,21 +156,20 @@ class QrCodeImportFragment : BaseFragment(), QrCodeImportView {
/**
* Shows [org.mifos.mobile.utils.ProgressBarHandler]
*/
override fun showProgress() {
fun showProgress() {
showProgressBar()
}

/**
* Hides [org.mifos.mobile.utils.ProgressBarHandler]
*/
override fun hideProgress() {
fun hideProgress() {
hideProgressBar()
}

override fun onDestroyView() {
super.onDestroyView()
hideProgress()
qrCodeImportPresenter?.detachView()
_binding = null
}

Expand Down
9 changes: 9 additions & 0 deletions app/src/main/java/org/mifos/mobile/utils/QrCodeUiState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.mifos.mobile.utils

import com.google.zxing.Result

sealed class QrCodeUiState {
object Loading : QrCodeUiState()
data class ShowError(val message: Int) : QrCodeUiState()
data class HandleDecodedResult(val result: Result?) : QrCodeUiState()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.mifos.mobile.viewModels

import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.google.zxing.*
import com.google.zxing.common.HybridBinarizer
import com.isseiaoki.simplecropview.CropImageView
import dagger.hilt.android.lifecycle.HiltViewModel
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import org.mifos.mobile.R
import org.mifos.mobile.utils.QrCodeUiState
import java.util.*
import javax.inject.Inject

@HiltViewModel
class QrCodeImportViewModel @Inject constructor() : ViewModel() {

private val compositeDisposables: CompositeDisposable = CompositeDisposable()

private var result: Result? = null
private var hasErrorOccurred = false

private val _qrCodeUiState = MutableLiveData<QrCodeUiState>()
val qrCodeUiState: LiveData<QrCodeUiState> = _qrCodeUiState

fun getDecodedResult(sourceUri: Uri?, cropImageView: CropImageView?) {
_qrCodeUiState.value = QrCodeUiState.Loading
cropImageView?.crop(sourceUri)
?.executeAsSingle()
?.flatMap { bMap ->
val intArray = IntArray(bMap.width * bMap.height)
// copy pixel data from the Bitmap into the 'intArray' array
bMap.getPixels(
intArray,
0,
bMap.width,
0,
0,
bMap.width,
bMap.height,
)
val source: LuminanceSource = RGBLuminanceSource(
bMap.width,
bMap.height,
intArray,
)
val bitmap = BinaryBitmap(HybridBinarizer(source))
// flags for decoding since it is large file
val tmpHintsMap: MutableMap<DecodeHintType, Boolean?> =
EnumMap(DecodeHintType::class.java)
tmpHintsMap[DecodeHintType.TRY_HARDER] = java.lang.Boolean.TRUE
tmpHintsMap[DecodeHintType.PURE_BARCODE] = java.lang.Boolean.TRUE
val reader: Reader = MultiFormatReader()
try {
result = reader.decode(bitmap, tmpHintsMap)
} catch (e: Exception) {
_qrCodeUiState.value = QrCodeUiState.ShowError(R.string.error_reading_qr)
}
Single.just(result)
}
?.subscribeOn(Schedulers.newThread())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe({ result ->
_qrCodeUiState.value = QrCodeUiState.HandleDecodedResult(result)
}) {
if (!hasErrorOccurred) {
_qrCodeUiState.value = QrCodeUiState.ShowError(R.string.error_reading_qr)
}
hasErrorOccurred = false
}?.let { compositeDisposables.add(it) }
}
}
Loading