From 927d4784e77bd1247c8a08b133168c8f09a3233c Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Sat, 17 Jun 2023 15:53:18 +0530 Subject: [PATCH 01/14] feat : Migrating registration verification fragment to MVVM --- .../RegistrationVerificationFragment.kt | 37 ++++++++++----- .../RegistrationVerificationViewModel.kt | 46 +++++++++++++++++++ ...egistrationVerificationViewModelFactory.kt | 17 +++++++ 3 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModelFactory.kt diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt index 7962982b9..d75c96064 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt @@ -6,27 +6,30 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.lifecycle.ViewModelProvider import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentRegistrationVerificationBinding import org.mifos.mobile.models.register.UserVerify -import org.mifos.mobile.presenters.RegistrationVerificationPresenter import org.mifos.mobile.ui.activities.LoginActivity import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.RegistrationVerificationView +import org.mifos.mobile.utils.MFErrorParser import org.mifos.mobile.utils.Toaster +import org.mifos.mobile.viewModels.RegistrationVerificationViewModel +import org.mifos.mobile.viewModels.RegistrationVerificationViewModelFactory import javax.inject.Inject /** * Created by dilpreet on 31/7/17. */ -class RegistrationVerificationFragment : BaseFragment(), RegistrationVerificationView { +class RegistrationVerificationFragment : BaseFragment() { private var _binding: FragmentRegistrationVerificationBinding? = null private val binding get() = _binding!! + private lateinit var viewModel : RegistrationVerificationViewModel - @JvmField @Inject - var presenter: RegistrationVerificationPresenter? = null + lateinit var viewModelFactory : RegistrationVerificationViewModelFactory + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -35,12 +38,22 @@ class RegistrationVerificationFragment : BaseFragment(), RegistrationVerificatio _binding = FragmentRegistrationVerificationBinding.inflate(inflater, container, false) val rootView = binding.root (activity as BaseActivity?)?.activityComponent?.inject(this) - presenter?.attachView(this) + viewModel = ViewModelProvider(this, viewModelFactory)[RegistrationVerificationViewModel::class.java] return rootView } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.readVerificationResultSuccess.observe(viewLifecycleOwner) { verificationResultSuccess -> + hideProgress() + if (verificationResultSuccess == true) { + showVerifiedSuccessfully() + } else { + showError(MFErrorParser.errorMessage(viewModel.readExceptionOnVerification)) + } + } + binding.btnVerify.setOnClickListener { verifyClicked() } @@ -50,30 +63,30 @@ class RegistrationVerificationFragment : BaseFragment(), RegistrationVerificatio val userVerify = UserVerify() userVerify.authenticationToken = binding.etAuthenticationToken.text.toString() userVerify.requestId = binding.etRequestId.text.toString() - presenter?.verifyUser(userVerify) + showProgress() + viewModel.verifyUser(userVerify) } - override fun showVerifiedSuccessfully() { + private fun showVerifiedSuccessfully() { startActivity(Intent(activity, LoginActivity::class.java)) Toast.makeText(context, getString(R.string.verified), Toast.LENGTH_SHORT).show() activity?.finish() } - override fun showError(msg: String?) { + fun showError(msg: String?) { Toaster.show(binding.root, msg) } - override fun showProgress() { + fun showProgress() { showMifosProgressDialog(getString(R.string.verifying)) } - override fun hideProgress() { + fun hideProgress() { hideMifosProgressDialog() } override fun onDestroyView() { super.onDestroyView() - presenter?.detachView() _binding = null } diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModel.kt new file mode 100644 index 000000000..e21af41b3 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModel.kt @@ -0,0 +1,46 @@ +package org.mifos.mobile.viewModels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.observers.DisposableObserver +import io.reactivex.schedulers.Schedulers +import okhttp3.ResponseBody +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.register.UserVerify +import javax.inject.Inject + +class RegistrationVerificationViewModel @Inject constructor(private val dataManager : DataManager?) : ViewModel() { + + private val compositeDisposables : CompositeDisposable = CompositeDisposable() + + private var verificationResultSuccess = MutableLiveData() + val readVerificationResultSuccess : LiveData get() = verificationResultSuccess + + private var exceptionOnVerification : Throwable? = null + val readExceptionOnVerification : Throwable? get() = exceptionOnVerification!! + + fun verifyUser(userVerify: UserVerify?) { + dataManager?.verifyUser(userVerify) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + exceptionOnVerification = e + verificationResultSuccess.value = false + } + + override fun onNext(responseBody: ResponseBody) { + verificationResultSuccess.value = true + } + })?.let { compositeDisposables.add(it) } + } + + override fun onCleared() { + super.onCleared() + compositeDisposables.clear() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModelFactory.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModelFactory.kt new file mode 100644 index 000000000..0d0fc5e79 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModelFactory.kt @@ -0,0 +1,17 @@ +package org.mifos.mobile.viewModels + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import org.mifos.mobile.api.DataManager +import javax.inject.Inject + +class RegistrationVerificationViewModelFactory @Inject constructor(private val dataManager: DataManager?) + : ViewModelProvider.Factory { + + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(RegistrationVerificationViewModel::class.java)) { + return RegistrationVerificationViewModel(dataManager) as T + } + throw IllegalArgumentException("Unknown ViewModel class: " + modelClass.name) + } +} \ No newline at end of file From 32ea26ce367fd195661d5b5b8e9ee4c16a4d5682 Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Sun, 18 Jun 2023 23:35:22 +0530 Subject: [PATCH 02/14] feat : migrating notification fragment to MVVM --- .../ui/fragments/NotificationFragment.kt | 44 +++++++++++++------ .../viewModels/NotificationViewModel.kt | 43 ++++++++++++++++++ .../NotificationViewModelFactory.kt | 19 ++++++++ 3 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModelFactory.kt diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt index 490cb028b..c08521874 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler @@ -12,25 +13,25 @@ import org.mifos.mobile.BuildConfig import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentNotificationBinding import org.mifos.mobile.models.notification.MifosNotification -import org.mifos.mobile.presenters.NotificationPresenter import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.adapters.NotificationAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.NotificationView import org.mifos.mobile.utils.DividerItemDecoration import org.mifos.mobile.utils.Network +import org.mifos.mobile.viewModels.NotificationViewModel +import org.mifos.mobile.viewModels.NotificationViewModelFactory import javax.inject.Inject /** * Created by dilpreet on 13/9/17. */ -class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener { +class NotificationFragment : BaseFragment(), OnRefreshListener { private var _binding: FragmentNotificationBinding? = null private val binding get() = _binding!! + private lateinit var viewModel : NotificationViewModel - @JvmField @Inject - var presenter: NotificationPresenter? = null + lateinit var viewModelFactory : NotificationViewModelFactory @JvmField @Inject @@ -49,6 +50,7 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener ): View { _binding = FragmentNotificationBinding.inflate(inflater, container, false) val rootView = binding.root + viewModel = ViewModelProvider(this, viewModelFactory)[NotificationViewModel::class.java] sweetUIErrorHandler = SweetUIErrorHandler(activity, rootView) val layoutManager = LinearLayoutManager(activity) layoutManager.orientation = LinearLayoutManager.VERTICAL @@ -67,12 +69,11 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener R.color.red_light, ) binding.swipeNotificationContainer.setOnRefreshListener(this) - presenter?.attachView(this) - presenter?.loadNotifications() + loadNotifications() return rootView } - override fun showNotifications(notifications: List?) { + private fun showNotifications(notifications: List?) { if (BuildConfig.DEBUG && notifications == null) { error("Assertion failed") } @@ -88,7 +89,7 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener } } - override fun showError(msg: String?) { + fun showError(msg: String?) { if (!Network.isConnected(activity)) { sweetUIErrorHandler?.showSweetNoInternetUI( binding.rvNotifications, @@ -106,18 +107,33 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.readLoadNotificationsResultSuccess.observe(viewLifecycleOwner) { loadNotificationsResultSuccess -> + hideProgress() + if(loadNotificationsResultSuccess == true) { + showNotifications(viewModel.readLoadedNotifications) + } else { + showError(context?.getString(R.string.notification)) + } + } + binding.layoutError.btnTryAgain.setOnClickListener { retryClicked() } } - fun retryClicked() { + private fun loadNotifications() { + showProgress() + viewModel.loadNotifications() + } + + private fun retryClicked() { if (Network.isConnected(context)) { sweetUIErrorHandler?.hideSweetErrorLayoutUI( binding.rvNotifications, binding.layoutError.root, ) - presenter?.loadNotifications() + loadNotifications() } else { Toast.makeText( context, @@ -127,11 +143,11 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener } } - override fun showProgress() { + fun showProgress() { binding.swipeNotificationContainer.isRefreshing = true } - override fun hideProgress() { + fun hideProgress() { binding.swipeNotificationContainer.isRefreshing = false } @@ -140,7 +156,7 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener binding.rvNotifications, binding.layoutError.root, ) - presenter?.loadNotifications() + loadNotifications() } override fun onDestroyView() { diff --git a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt new file mode 100644 index 000000000..de1198cc1 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt @@ -0,0 +1,43 @@ +package org.mifos.mobile.viewModels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.observers.DisposableObserver +import io.reactivex.schedulers.Schedulers +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.notification.MifosNotification +import javax.inject.Inject + +class NotificationViewModel @Inject constructor(private val dataManager : DataManager?): ViewModel() { + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + + private var loadNotificationsResultSuccess = MutableLiveData() + val readLoadNotificationsResultSuccess : LiveData get() = loadNotificationsResultSuccess + + private var loadedNotifications : List? = null + val readLoadedNotifications : List get() = loadedNotifications!! + + fun loadNotifications() { + dataManager?.notifications + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver?>() { + override fun onComplete() {} + override fun onError(e: Throwable) { + loadNotificationsResultSuccess.value = false + } + override fun onNext(notificationModels: List) { + loadedNotifications = notificationModels + loadNotificationsResultSuccess.value = true + } + })?.let { compositeDisposables.add(it) } + } + + override fun onCleared() { + super.onCleared() + compositeDisposables.clear() + } +} diff --git a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModelFactory.kt b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModelFactory.kt new file mode 100644 index 000000000..b8d65999a --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModelFactory.kt @@ -0,0 +1,19 @@ +package org.mifos.mobile.viewModels + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.injection.PerActivity +import javax.inject.Inject + +@PerActivity +class NotificationViewModelFactory @Inject constructor(private val dataManager : DataManager?) : + ViewModelProvider.Factory { + + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(NotificationViewModel::class.java)) { + return NotificationViewModel(dataManager) as T + } + throw IllegalArgumentException("Unknown ViewModel class: " + modelClass.name) + } +} From c7c42b6a51bf6ccc46b1f30f6c01ed4452a6c808 Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Fri, 23 Jun 2023 00:44:10 +0530 Subject: [PATCH 03/14] feat : Migrating Notification Fragment to MVVM. --- .../mifos/mobile/NotificationRepository.kt | 12 ++++++++++++ .../ui/fragments/NotificationFragment.kt | 19 ++++++++++++------- .../mifos/mobile/utils/NotificationUiState.kt | 9 +++++++++ .../viewModels/NotificationViewModel.kt | 18 +++++++++--------- 4 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/org/mifos/mobile/NotificationRepository.kt create mode 100644 app/src/main/java/org/mifos/mobile/utils/NotificationUiState.kt diff --git a/app/src/main/java/org/mifos/mobile/NotificationRepository.kt b/app/src/main/java/org/mifos/mobile/NotificationRepository.kt new file mode 100644 index 000000000..ae826210d --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/NotificationRepository.kt @@ -0,0 +1,12 @@ +package org.mifos.mobile + +import io.reactivex.Observable +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.notification.MifosNotification + +class NotificationRepository(private val dataManager: DataManager?) { + + fun loadNotifications() : Observable?>? { + return dataManager?.notifications + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt index c08521874..31f7e67c3 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt @@ -10,6 +10,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler import org.mifos.mobile.BuildConfig +import org.mifos.mobile.utils.NotificationUiState import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentNotificationBinding import org.mifos.mobile.models.notification.MifosNotification @@ -108,12 +109,17 @@ class NotificationFragment : BaseFragment(), OnRefreshListener { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.readLoadNotificationsResultSuccess.observe(viewLifecycleOwner) { loadNotificationsResultSuccess -> - hideProgress() - if(loadNotificationsResultSuccess == true) { - showNotifications(viewModel.readLoadedNotifications) - } else { - showError(context?.getString(R.string.notification)) + viewModel.notificationUiState.observe(viewLifecycleOwner) { state -> + when(state) { + NotificationUiState.Loading -> showProgress() + NotificationUiState.Error -> { + hideProgress() + showError(context?.getString(R.string.notification)) + } + is NotificationUiState.LoadNotificationsSuccessful -> { + hideProgress() + showNotifications(state.notifications) + } } } @@ -123,7 +129,6 @@ class NotificationFragment : BaseFragment(), OnRefreshListener { } private fun loadNotifications() { - showProgress() viewModel.loadNotifications() } diff --git a/app/src/main/java/org/mifos/mobile/utils/NotificationUiState.kt b/app/src/main/java/org/mifos/mobile/utils/NotificationUiState.kt new file mode 100644 index 000000000..d0a1216ed --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/NotificationUiState.kt @@ -0,0 +1,9 @@ +package org.mifos.mobile.utils + +import org.mifos.mobile.models.notification.MifosNotification + +sealed class NotificationUiState { + object Loading : NotificationUiState() + data class LoadNotificationsSuccessful(val notifications : List) : NotificationUiState() + object Error : NotificationUiState() +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt index de1198cc1..03ee49473 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt @@ -7,6 +7,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers +import org.mifos.mobile.NotificationRepository +import org.mifos.mobile.utils.NotificationUiState import org.mifos.mobile.api.DataManager import org.mifos.mobile.models.notification.MifosNotification import javax.inject.Inject @@ -14,24 +16,22 @@ import javax.inject.Inject class NotificationViewModel @Inject constructor(private val dataManager : DataManager?): ViewModel() { private val compositeDisposables: CompositeDisposable = CompositeDisposable() - private var loadNotificationsResultSuccess = MutableLiveData() - val readLoadNotificationsResultSuccess : LiveData get() = loadNotificationsResultSuccess - - private var loadedNotifications : List? = null - val readLoadedNotifications : List get() = loadedNotifications!! + private val notificationRepository = NotificationRepository(dataManager) + private val _notificationUiState = MutableLiveData() + val notificationUiState : LiveData get() = _notificationUiState fun loadNotifications() { - dataManager?.notifications + _notificationUiState.value = NotificationUiState.Loading + notificationRepository.loadNotifications() ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribeOn(Schedulers.io()) ?.subscribeWith(object : DisposableObserver?>() { override fun onComplete() {} override fun onError(e: Throwable) { - loadNotificationsResultSuccess.value = false + _notificationUiState.value = NotificationUiState.Error } override fun onNext(notificationModels: List) { - loadedNotifications = notificationModels - loadNotificationsResultSuccess.value = true + _notificationUiState.value = NotificationUiState.LoadNotificationsSuccessful(notificationModels) } })?.let { compositeDisposables.add(it) } } From 3d2c4ecbf411e514085a79a251c8f938bd6b4a3c Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Tue, 4 Jul 2023 12:22:58 +0530 Subject: [PATCH 04/14] fix : Notification Fragment migration to MVVM 1. Fixed Merge Conflicts 2. Fix for build fail --- .../mifos/mobile/NotificationRepository.kt | 12 ------------ .../injection/module/RepositoryModule.kt | 7 +++++++ .../repositories/NotificationRepository.kt | 9 +++++++++ .../repositories/NotificationRepositoryImp.kt | 12 ++++++++++++ .../ui/fragments/NotificationFragment.kt | 7 +------ .../viewModels/NotificationViewModel.kt | 10 ++++++---- .../NotificationViewModelFactory.kt | 19 ------------------- 7 files changed, 35 insertions(+), 41 deletions(-) delete mode 100644 app/src/main/java/org/mifos/mobile/NotificationRepository.kt create mode 100644 app/src/main/java/org/mifos/mobile/repositories/NotificationRepository.kt create mode 100644 app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModelFactory.kt diff --git a/app/src/main/java/org/mifos/mobile/NotificationRepository.kt b/app/src/main/java/org/mifos/mobile/NotificationRepository.kt deleted file mode 100644 index ae826210d..000000000 --- a/app/src/main/java/org/mifos/mobile/NotificationRepository.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.mifos.mobile - -import io.reactivex.Observable -import org.mifos.mobile.api.DataManager -import org.mifos.mobile.models.notification.MifosNotification - -class NotificationRepository(private val dataManager: DataManager?) { - - fun loadNotifications() : Observable?>? { - return dataManager?.notifications - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt b/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt index 2063047cc..92abe7dbd 100644 --- a/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt +++ b/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt @@ -4,7 +4,9 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import org.mifos.mobile.repositories.NotificationRepositoryImp import org.mifos.mobile.api.DataManager +import org.mifos.mobile.repositories.NotificationRepository import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.repositories.UserAuthRepositoryImp @@ -16,4 +18,9 @@ class RepositoryModule { fun providesUserAuthRepository(dataManager: DataManager): UserAuthRepository { return UserAuthRepositoryImp(dataManager) } + + @Provides + fun providesNotificationRepository(dataManager: DataManager) : NotificationRepository { + return NotificationRepositoryImp(dataManager) + } } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/NotificationRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepository.kt new file mode 100644 index 000000000..19d4c2655 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepository.kt @@ -0,0 +1,9 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import org.mifos.mobile.models.notification.MifosNotification + +interface NotificationRepository { + + fun loadNotifications(): Observable?>? +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt new file mode 100644 index 000000000..fa4ed2ace --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt @@ -0,0 +1,12 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.notification.MifosNotification + +class NotificationRepositoryImp(private val dataManager: DataManager?) : NotificationRepository { + + override fun loadNotifications(): Observable?>? { + return dataManager?.notifications + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt index 8eb737f4b..817d11956 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/NotificationFragment.kt @@ -15,13 +15,11 @@ import org.mifos.mobile.utils.NotificationUiState import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentNotificationBinding import org.mifos.mobile.models.notification.MifosNotification -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.adapters.NotificationAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.DividerItemDecoration import org.mifos.mobile.utils.Network import org.mifos.mobile.viewModels.NotificationViewModel -import org.mifos.mobile.viewModels.NotificationViewModelFactory import javax.inject.Inject /** @@ -33,9 +31,6 @@ class NotificationFragment : BaseFragment(), OnRefreshListener { private val binding get() = _binding!! private lateinit var viewModel : NotificationViewModel - @Inject - lateinit var viewModelFactory : NotificationViewModelFactory - @JvmField @Inject var adapter: NotificationAdapter? = null @@ -52,7 +47,7 @@ class NotificationFragment : BaseFragment(), OnRefreshListener { ): View { _binding = FragmentNotificationBinding.inflate(inflater, container, false) val rootView = binding.root - viewModel = ViewModelProvider(this, viewModelFactory)[NotificationViewModel::class.java] + viewModel = ViewModelProvider(this)[NotificationViewModel::class.java] sweetUIErrorHandler = SweetUIErrorHandler(activity, rootView) val layoutManager = LinearLayoutManager(activity) layoutManager.orientation = LinearLayoutManager.VERTICAL diff --git a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt index 03ee49473..857cd9af4 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt @@ -3,26 +3,28 @@ package org.mifos.mobile.viewModels import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers -import org.mifos.mobile.NotificationRepository +import org.mifos.mobile.repositories.NotificationRepositoryImp import org.mifos.mobile.utils.NotificationUiState import org.mifos.mobile.api.DataManager import org.mifos.mobile.models.notification.MifosNotification +import org.mifos.mobile.repositories.NotificationRepository import javax.inject.Inject -class NotificationViewModel @Inject constructor(private val dataManager : DataManager?): ViewModel() { +@HiltViewModel +class NotificationViewModel @Inject constructor(private val notificationRepositoryImp: NotificationRepository): ViewModel() { private val compositeDisposables: CompositeDisposable = CompositeDisposable() - private val notificationRepository = NotificationRepository(dataManager) private val _notificationUiState = MutableLiveData() val notificationUiState : LiveData get() = _notificationUiState fun loadNotifications() { _notificationUiState.value = NotificationUiState.Loading - notificationRepository.loadNotifications() + notificationRepositoryImp.loadNotifications() ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribeOn(Schedulers.io()) ?.subscribeWith(object : DisposableObserver?>() { diff --git a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModelFactory.kt b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModelFactory.kt deleted file mode 100644 index b8d65999a..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModelFactory.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.mifos.mobile.viewModels - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.PerActivity -import javax.inject.Inject - -@PerActivity -class NotificationViewModelFactory @Inject constructor(private val dataManager : DataManager?) : - ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(NotificationViewModel::class.java)) { - return NotificationViewModel(dataManager) as T - } - throw IllegalArgumentException("Unknown ViewModel class: " + modelClass.name) - } -} From 27673517750094d95908ebf9e2dc7add62480d6d Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Tue, 4 Jul 2023 16:57:33 +0530 Subject: [PATCH 05/14] feat : notification fragment migration 1. added unit tests for notification viewModel and repository --- .../repositories/NotificationRepository.kt | 2 +- .../repositories/NotificationRepositoryImp.kt | 7 +- .../viewModels/NotificationViewModel.kt | 4 +- .../NotificationRepositoryImpTest.kt | 60 ++++++++++++++ .../viewModels/NotificationViewModelTest.kt | 80 +++++++++++++++++++ 5 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 app/src/test/java/org/mifos/mobile/repositories/NotificationRepositoryImpTest.kt create mode 100644 app/src/test/java/org/mifos/mobile/viewModels/NotificationViewModelTest.kt diff --git a/app/src/main/java/org/mifos/mobile/repositories/NotificationRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepository.kt index 19d4c2655..96a4c4f2c 100644 --- a/app/src/main/java/org/mifos/mobile/repositories/NotificationRepository.kt +++ b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepository.kt @@ -5,5 +5,5 @@ import org.mifos.mobile.models.notification.MifosNotification interface NotificationRepository { - fun loadNotifications(): Observable?>? + fun loadNotifications(): Observable?> } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt index fa4ed2ace..856f69970 100644 --- a/app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt +++ b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt @@ -3,10 +3,11 @@ package org.mifos.mobile.repositories import io.reactivex.Observable import org.mifos.mobile.api.DataManager import org.mifos.mobile.models.notification.MifosNotification +import javax.inject.Inject -class NotificationRepositoryImp(private val dataManager: DataManager?) : NotificationRepository { +class NotificationRepositoryImp @Inject constructor(private val dataManager: DataManager) : NotificationRepository { - override fun loadNotifications(): Observable?>? { - return dataManager?.notifications + override fun loadNotifications(): Observable?> { + return dataManager.notifications } } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt index 857cd9af4..365fe0a5b 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/NotificationViewModel.kt @@ -8,9 +8,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers -import org.mifos.mobile.repositories.NotificationRepositoryImp import org.mifos.mobile.utils.NotificationUiState -import org.mifos.mobile.api.DataManager import org.mifos.mobile.models.notification.MifosNotification import org.mifos.mobile.repositories.NotificationRepository import javax.inject.Inject @@ -25,7 +23,7 @@ class NotificationViewModel @Inject constructor(private val notificationReposito fun loadNotifications() { _notificationUiState.value = NotificationUiState.Loading notificationRepositoryImp.loadNotifications() - ?.observeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) ?.subscribeOn(Schedulers.io()) ?.subscribeWith(object : DisposableObserver?>() { override fun onComplete() {} diff --git a/app/src/test/java/org/mifos/mobile/repositories/NotificationRepositoryImpTest.kt b/app/src/test/java/org/mifos/mobile/repositories/NotificationRepositoryImpTest.kt new file mode 100644 index 000000000..7fd5615d7 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/repositories/NotificationRepositoryImpTest.kt @@ -0,0 +1,60 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable + +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.notification.MifosNotification +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class NotificationRepositoryImpTest { + + @Mock + lateinit var dataManager: DataManager + + private lateinit var notificationRepositoryImp: NotificationRepository + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + notificationRepositoryImp = NotificationRepositoryImp(dataManager) + } + + @Test + fun testLoadNotifications_SuccessResponseReceivedFromDataManager_ReturnsSuccess() { + val notificationList : List = ArrayList() + val successResponse: Observable?> = + Observable.just(notificationList) + Mockito.`when`( + dataManager.notifications + ).thenReturn(successResponse) + + val result = notificationRepositoryImp.loadNotifications() + + Mockito.verify(dataManager).notifications + Assert.assertEquals(result, successResponse) + + } + + @Test + fun testLoadNotifications_ErrorResponseReceivedFromDataManager_ReturnsError() { + val errorResponse: Observable?> = + Observable.error(Throwable("LoadNotifications Unsuccessful")) + Mockito.`when`( + dataManager.notifications + ).thenReturn(errorResponse) + + val result = notificationRepositoryImp.loadNotifications() + + Mockito.verify(dataManager).notifications + Assert.assertEquals(result, errorResponse) + } + +} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/NotificationViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/NotificationViewModelTest.kt new file mode 100644 index 000000000..c10fb80c9 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/NotificationViewModelTest.kt @@ -0,0 +1,80 @@ +package org.mifos.mobile.viewModels + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Observer +import io.reactivex.Observable +import org.junit.After +import org.junit.Assert.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.models.notification.MifosNotification +import org.mifos.mobile.repositories.NotificationRepository +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.NotificationUiState +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner +import java.lang.RuntimeException + +@RunWith(MockitoJUnitRunner::class) +class NotificationViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var notificationRepositoryImp: NotificationRepository + + @Mock + lateinit var notificationUiStateObserver: Observer + + private lateinit var notificationViewModel: NotificationViewModel + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + notificationViewModel = NotificationViewModel(notificationRepositoryImp) + notificationViewModel.notificationUiState.observeForever(notificationUiStateObserver) + } + + @Test + fun testLoadNotifications_NotificationsSuccessfullyReceivedFromRepository_ReturnsNotificationsSuccessfully() { + val notificationsReceived: List = ArrayList() + Mockito.`when`( + notificationRepositoryImp.loadNotifications() + ).thenReturn(Observable.just(notificationsReceived)) + + notificationViewModel.loadNotifications() + + Mockito.verify(notificationUiStateObserver).onChanged(NotificationUiState.Loading) + Mockito.verify(notificationUiStateObserver).onChanged(NotificationUiState.LoadNotificationsSuccessful(notificationsReceived)) + Mockito.verifyNoMoreInteractions(notificationUiStateObserver) + } + + @Test + fun testLoadNotifications_NotificationsNotReceivedFromRepository_ReturnsError() { + val error = RuntimeException("loadNotifications Unsuccessful") + Mockito.`when`( + notificationRepositoryImp.loadNotifications() + ).thenReturn(Observable.error(error)) + + notificationViewModel.loadNotifications() + + Mockito.verify(notificationUiStateObserver).onChanged(NotificationUiState.Loading) + Mockito.verify(notificationUiStateObserver).onChanged(NotificationUiState.Error) + Mockito.verifyNoMoreInteractions(notificationUiStateObserver) + + } + + @After + fun tearDown() { + notificationViewModel.notificationUiState.removeObserver(notificationUiStateObserver) + } +} \ No newline at end of file From 57270b912a11c9972006357b3fc82e2c7d65d35e Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Tue, 4 Jul 2023 23:08:23 +0530 Subject: [PATCH 06/14] fix : RegistrationVerificationFragment migration to MVVM 1. deleted registerationVerification viewModel and moved logic to registration viewModel. 2. added unit tests for registerationVerification's verifyUser function of viewModel and repository. 3. moved UI state change logic to registerationVerificationUiState sealed class. --- .../mobile/repositories/UserAuthRepository.kt | 3 ++ .../repositories/UserAuthRepositoryImp.kt | 5 ++ .../RegistrationVerificationFragment.kt | 32 +++++++------ .../utils/RegistrationVerificationUiState.kt | 8 ++++ .../RegistrationVerificationViewModel.kt | 46 ------------------- ...egistrationVerificationViewModelFactory.kt | 17 ------- .../viewModels/RegistrationViewModel.kt | 24 ++++++++++ .../repositories/UserAuthRepositoryImpTest.kt | 31 ++++++++++++- .../viewModels/RegistrationViewModelTest.kt | 46 ++++++++++++++++++- 9 files changed, 131 insertions(+), 81 deletions(-) create mode 100644 app/src/main/java/org/mifos/mobile/utils/RegistrationVerificationUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModel.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModelFactory.kt diff --git a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt index 145c251ef..e8f159d79 100644 --- a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt +++ b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt @@ -2,6 +2,7 @@ package org.mifos.mobile.repositories import io.reactivex.Observable import okhttp3.ResponseBody +import org.mifos.mobile.models.register.UserVerify interface UserAuthRepository { @@ -15,4 +16,6 @@ interface UserAuthRepository { password: String?, username: String? ): Observable? + + fun verifyUser(userVerify: UserVerify?): Observable? } diff --git a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt index 27f45872d..e28f6c1a3 100644 --- a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt +++ b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt @@ -4,6 +4,7 @@ import io.reactivex.Observable import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager import org.mifos.mobile.models.register.RegisterPayload +import org.mifos.mobile.models.register.UserVerify import javax.inject.Inject class UserAuthRepositoryImp @Inject constructor(private val dataManager: DataManager) : @@ -31,4 +32,8 @@ class UserAuthRepositoryImp @Inject constructor(private val dataManager: DataMan } return dataManager.registerUser(registerPayload) } + + override fun verifyUser(userVerify: UserVerify?): Observable? { + return dataManager.verifyUser(userVerify) + } } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt index 137d3f162..e0e778bb6 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt @@ -14,10 +14,9 @@ import org.mifos.mobile.models.register.UserVerify import org.mifos.mobile.ui.activities.LoginActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.MFErrorParser +import org.mifos.mobile.utils.RegistrationVerificationUiState import org.mifos.mobile.utils.Toaster -import org.mifos.mobile.viewModels.RegistrationVerificationViewModel -import org.mifos.mobile.viewModels.RegistrationVerificationViewModelFactory -import javax.inject.Inject +import org.mifos.mobile.viewModels.RegistrationViewModel /** * Created by dilpreet on 31/7/17. @@ -26,10 +25,7 @@ import javax.inject.Inject class RegistrationVerificationFragment : BaseFragment() { private var _binding: FragmentRegistrationVerificationBinding? = null private val binding get() = _binding!! - private lateinit var viewModel : RegistrationVerificationViewModel - - @Inject - lateinit var viewModelFactory : RegistrationVerificationViewModelFactory + private lateinit var viewModel: RegistrationViewModel override fun onCreateView( inflater: LayoutInflater, @@ -38,20 +34,26 @@ class RegistrationVerificationFragment : BaseFragment() { ): View { _binding = FragmentRegistrationVerificationBinding.inflate(inflater, container, false) val rootView = binding.root - (activity as BaseActivity?)?.activityComponent?.inject(this) - viewModel = ViewModelProvider(this, viewModelFactory)[RegistrationVerificationViewModel::class.java] + viewModel = ViewModelProvider(this)[RegistrationViewModel::class.java] return rootView } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.readVerificationResultSuccess.observe(viewLifecycleOwner) { verificationResultSuccess -> - hideProgress() - if (verificationResultSuccess == true) { - showVerifiedSuccessfully() - } else { - showError(MFErrorParser.errorMessage(viewModel.readExceptionOnVerification)) + viewModel.registrationVerificationUiState.observe(viewLifecycleOwner) { state -> + when (state) { + RegistrationVerificationUiState.Loading -> showProgress() + + RegistrationVerificationUiState.RegistrationVerificationSuccessful -> { + hideProgress() + showVerifiedSuccessfully() + } + + is RegistrationVerificationUiState.ErrorOnRegistrationVerification -> { + hideProgress() + showError(MFErrorParser.errorMessage(state.exception)) + } } } diff --git a/app/src/main/java/org/mifos/mobile/utils/RegistrationVerificationUiState.kt b/app/src/main/java/org/mifos/mobile/utils/RegistrationVerificationUiState.kt new file mode 100644 index 000000000..25506244b --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/RegistrationVerificationUiState.kt @@ -0,0 +1,8 @@ +package org.mifos.mobile.utils + +sealed class RegistrationVerificationUiState { + object Loading : RegistrationVerificationUiState() + object RegistrationVerificationSuccessful : RegistrationVerificationUiState() + data class ErrorOnRegistrationVerification(val exception: Throwable) : + RegistrationVerificationUiState() +} diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModel.kt deleted file mode 100644 index e21af41b3..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModel.kt +++ /dev/null @@ -1,46 +0,0 @@ -package org.mifos.mobile.viewModels - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.observers.DisposableObserver -import io.reactivex.schedulers.Schedulers -import okhttp3.ResponseBody -import org.mifos.mobile.api.DataManager -import org.mifos.mobile.models.register.UserVerify -import javax.inject.Inject - -class RegistrationVerificationViewModel @Inject constructor(private val dataManager : DataManager?) : ViewModel() { - - private val compositeDisposables : CompositeDisposable = CompositeDisposable() - - private var verificationResultSuccess = MutableLiveData() - val readVerificationResultSuccess : LiveData get() = verificationResultSuccess - - private var exceptionOnVerification : Throwable? = null - val readExceptionOnVerification : Throwable? get() = exceptionOnVerification!! - - fun verifyUser(userVerify: UserVerify?) { - dataManager?.verifyUser(userVerify) - ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribeOn(Schedulers.io()) - ?.subscribeWith(object : DisposableObserver() { - override fun onComplete() {} - override fun onError(e: Throwable) { - exceptionOnVerification = e - verificationResultSuccess.value = false - } - - override fun onNext(responseBody: ResponseBody) { - verificationResultSuccess.value = true - } - })?.let { compositeDisposables.add(it) } - } - - override fun onCleared() { - super.onCleared() - compositeDisposables.clear() - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModelFactory.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModelFactory.kt deleted file mode 100644 index 0d0fc5e79..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationVerificationViewModelFactory.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.mifos.mobile.viewModels - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import org.mifos.mobile.api.DataManager -import javax.inject.Inject - -class RegistrationVerificationViewModelFactory @Inject constructor(private val dataManager: DataManager?) - : ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(RegistrationVerificationViewModel::class.java)) { - return RegistrationVerificationViewModel(dataManager) as T - } - throw IllegalArgumentException("Unknown ViewModel class: " + modelClass.name) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt index f773d8d9f..39bfbd770 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt @@ -10,8 +10,10 @@ import io.reactivex.disposables.CompositeDisposable import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody +import org.mifos.mobile.models.register.UserVerify import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.utils.RegistrationUiState +import org.mifos.mobile.utils.RegistrationVerificationUiState import javax.inject.Inject @HiltViewModel @@ -22,6 +24,10 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm private val _registrationUiState = MutableLiveData() val registrationUiState: LiveData get() = _registrationUiState + private val _registrationVerificationUiState = + MutableLiveData() + val registrationVerificationUiState: LiveData get() = _registrationVerificationUiState + fun isInputFieldBlank(fieldText: String): Boolean { return fieldText.trim().isEmpty() } @@ -75,6 +81,24 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm })?.let { compositeDisposables.add(it) } } + fun verifyUser(userVerify: UserVerify?) { + _registrationVerificationUiState.value = RegistrationVerificationUiState.Loading + userAuthRepositoryImp.verifyUser(userVerify)?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _registrationVerificationUiState.value = + RegistrationVerificationUiState.ErrorOnRegistrationVerification(e) + } + + override fun onNext(responseBody: ResponseBody) { + _registrationVerificationUiState.value = + RegistrationVerificationUiState.RegistrationVerificationSuccessful + } + })?.let { compositeDisposables.add(it) } + } + override fun onCleared() { super.onCleared() compositeDisposables.clear() diff --git a/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt b/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt index bd2b68744..a1cffde64 100644 --- a/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt +++ b/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt @@ -6,6 +6,7 @@ import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mifos.mobile.FakeRemoteDataSource.userVerify import org.mifos.mobile.api.DataManager import org.mifos.mobile.models.register.RegisterPayload import org.mockito.Mock @@ -19,7 +20,7 @@ class UserAuthRepositoryImpTest { @Mock lateinit var dataManager: DataManager - private lateinit var userAuthRepositoryImp: UserAuthRepositoryImp + private lateinit var userAuthRepositoryImp: UserAuthRepository @Before fun setUp() { @@ -89,4 +90,32 @@ class UserAuthRepositoryImpTest { Mockito.verify(dataManager).registerUser(registerPayload) Assert.assertEquals(result, error) } + + @Test + fun testVerifyUser_SuccessResponseReceivedFromDataManager_ReturnsSuccessfulRegistrationVerification() { + val successResponse: Observable = + Observable.just(Mockito.mock(ResponseBody::class.java)) + Mockito.`when`( + dataManager.verifyUser(userVerify) + ).thenReturn(successResponse) + + val result = userAuthRepositoryImp.verifyUser(userVerify) + + Mockito.verify(dataManager).verifyUser(userVerify) + Assert.assertEquals(result, successResponse) + } + + @Test + fun testVerifyUser_ErrorResponseReceivedFromDataManager_ReturnsUnsuccessfulRegistrationVerification() { + val errorResponse: Observable = + Observable.error(Throwable("RegistrationVerification failed")) + Mockito.`when`( + dataManager.verifyUser(userVerify) + ).thenReturn(errorResponse) + + val result = userAuthRepositoryImp.verifyUser(userVerify) + Mockito.verify(dataManager).verifyUser(userVerify) + Assert.assertEquals(result, errorResponse) + + } } \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt index 63d0f6d64..f882cd7d7 100644 --- a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt +++ b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt @@ -10,9 +10,11 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mifos.mobile.repositories.UserAuthRepositoryImp +import org.mifos.mobile.FakeRemoteDataSource.userVerify +import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.util.RxSchedulersOverrideRule import org.mifos.mobile.utils.RegistrationUiState +import org.mifos.mobile.utils.RegistrationVerificationUiState import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations @@ -30,11 +32,14 @@ class RegistrationViewModelTest { val rule = InstantTaskExecutorRule() @Mock - lateinit var userAuthRepositoryImp: UserAuthRepositoryImp + lateinit var userAuthRepositoryImp: UserAuthRepository @Mock lateinit var registrationUiStateObserver: Observer + @Mock + lateinit var registrationVerificationUiStateObserver: Observer + private lateinit var registrationViewModel: RegistrationViewModel @Before @@ -42,6 +47,9 @@ class RegistrationViewModelTest { MockitoAnnotations.openMocks(this) registrationViewModel = RegistrationViewModel(userAuthRepositoryImp) registrationViewModel.registrationUiState.observeForever(registrationUiStateObserver) + registrationViewModel.registrationVerificationUiState.observeForever( + registrationVerificationUiStateObserver + ) } @Test @@ -166,8 +174,42 @@ class RegistrationViewModelTest { Mockito.verifyNoMoreInteractions(registrationUiStateObserver) } + @Test + fun testVerifyUser_SuccessfulRegistrationVerificationReceivedFromRepository_ReturnsRegistrationVerificationSuccessful() { + Mockito.`when`( + userAuthRepositoryImp.verifyUser(userVerify) + ).thenReturn(Observable.just(Mockito.mock(ResponseBody::class.java))) + + registrationViewModel.verifyUser(userVerify) + + Mockito.verify(registrationVerificationUiStateObserver) + .onChanged(RegistrationVerificationUiState.Loading) + Mockito.verify(registrationVerificationUiStateObserver) + .onChanged(RegistrationVerificationUiState.RegistrationVerificationSuccessful) + Mockito.verifyNoMoreInteractions(registrationUiStateObserver) + } + + @Test + fun testVerifyUser_UnsuccessfulRegistrationVerificationReceivedFromRepository_ReturnsRegistrationVerificationUnsuccessful() { + val error = RuntimeException("RegistrationVerification Failed") + Mockito.`when`( + userAuthRepositoryImp.verifyUser(userVerify) + ).thenReturn(Observable.error(error)) + + registrationViewModel.verifyUser(userVerify) + + Mockito.verify(registrationVerificationUiStateObserver) + .onChanged(RegistrationVerificationUiState.Loading) + Mockito.verify(registrationVerificationUiStateObserver) + .onChanged(RegistrationVerificationUiState.ErrorOnRegistrationVerification(error)) + Mockito.verifyNoMoreInteractions(registrationUiStateObserver) + } + @After fun tearDown() { registrationViewModel.registrationUiState.removeObserver(registrationUiStateObserver) + registrationViewModel.registrationVerificationUiState.removeObserver( + registrationVerificationUiStateObserver + ) } } \ No newline at end of file From a648a6204e3ab7b0994cfbe074404404791aea0f Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Tue, 4 Jul 2023 23:59:19 +0530 Subject: [PATCH 07/14] fix : registration verification fragment mvvm migration shifted userVerify payload creation to datalayer(i.e. in repository) --- .../org/mifos/mobile/repositories/UserAuthRepository.kt | 3 +-- .../mifos/mobile/repositories/UserAuthRepositoryImp.kt | 6 +++++- .../ui/fragments/RegistrationVerificationFragment.kt | 9 +++------ .../org/mifos/mobile/viewModels/RegistrationViewModel.kt | 5 ++--- .../mobile/repositories/UserAuthRepositoryImpTest.kt | 6 ++++-- .../mifos/mobile/viewModels/RegistrationViewModelTest.kt | 9 ++++----- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt index e8f159d79..d42f678ea 100644 --- a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt +++ b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt @@ -2,7 +2,6 @@ package org.mifos.mobile.repositories import io.reactivex.Observable import okhttp3.ResponseBody -import org.mifos.mobile.models.register.UserVerify interface UserAuthRepository { @@ -17,5 +16,5 @@ interface UserAuthRepository { username: String? ): Observable? - fun verifyUser(userVerify: UserVerify?): Observable? + fun verifyUser(authenticationToken: String?, requestId: String?): Observable? } diff --git a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt index e28f6c1a3..523dc55d0 100644 --- a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt +++ b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt @@ -33,7 +33,11 @@ class UserAuthRepositoryImp @Inject constructor(private val dataManager: DataMan return dataManager.registerUser(registerPayload) } - override fun verifyUser(userVerify: UserVerify?): Observable? { + override fun verifyUser(authenticationToken: String?, requestId: String?): Observable? { + val userVerify = UserVerify().apply { + this.authenticationToken = authenticationToken + this.requestId = requestId + } return dataManager.verifyUser(userVerify) } } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt index e0e778bb6..c45b2dbe2 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt @@ -10,7 +10,6 @@ import androidx.lifecycle.ViewModelProvider import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentRegistrationVerificationBinding -import org.mifos.mobile.models.register.UserVerify import org.mifos.mobile.ui.activities.LoginActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.MFErrorParser @@ -63,11 +62,9 @@ class RegistrationVerificationFragment : BaseFragment() { } private fun verifyClicked() { - val userVerify = UserVerify() - userVerify.authenticationToken = binding.etAuthenticationToken.text.toString() - userVerify.requestId = binding.etRequestId.text.toString() - showProgress() - viewModel.verifyUser(userVerify) + val authenticationToken = binding.etAuthenticationToken.text.toString() + val requestId = binding.etRequestId.text.toString() + viewModel.verifyUser(authenticationToken, requestId) } private fun showVerifiedSuccessfully() { diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt index 39bfbd770..7b9b2b31e 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt @@ -10,7 +10,6 @@ import io.reactivex.disposables.CompositeDisposable import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody -import org.mifos.mobile.models.register.UserVerify import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.utils.RegistrationUiState import org.mifos.mobile.utils.RegistrationVerificationUiState @@ -81,9 +80,9 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm })?.let { compositeDisposables.add(it) } } - fun verifyUser(userVerify: UserVerify?) { + fun verifyUser(authenticationToken: String?, requestId: String?) { _registrationVerificationUiState.value = RegistrationVerificationUiState.Loading - userAuthRepositoryImp.verifyUser(userVerify)?.observeOn(AndroidSchedulers.mainThread()) + userAuthRepositoryImp.verifyUser(authenticationToken, requestId)?.observeOn(AndroidSchedulers.mainThread()) ?.subscribeOn(Schedulers.io()) ?.subscribeWith(object : DisposableObserver() { override fun onComplete() {} diff --git a/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt b/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt index a1cffde64..50bf0897f 100644 --- a/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt +++ b/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt @@ -99,7 +99,8 @@ class UserAuthRepositoryImpTest { dataManager.verifyUser(userVerify) ).thenReturn(successResponse) - val result = userAuthRepositoryImp.verifyUser(userVerify) + val result = + userAuthRepositoryImp.verifyUser(userVerify.authenticationToken, userVerify.requestId) Mockito.verify(dataManager).verifyUser(userVerify) Assert.assertEquals(result, successResponse) @@ -113,7 +114,8 @@ class UserAuthRepositoryImpTest { dataManager.verifyUser(userVerify) ).thenReturn(errorResponse) - val result = userAuthRepositoryImp.verifyUser(userVerify) + val result = + userAuthRepositoryImp.verifyUser(userVerify.authenticationToken, userVerify.requestId) Mockito.verify(dataManager).verifyUser(userVerify) Assert.assertEquals(result, errorResponse) diff --git a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt index f882cd7d7..a13b34559 100644 --- a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt +++ b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt @@ -10,7 +10,6 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mifos.mobile.FakeRemoteDataSource.userVerify import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.util.RxSchedulersOverrideRule import org.mifos.mobile.utils.RegistrationUiState @@ -177,10 +176,10 @@ class RegistrationViewModelTest { @Test fun testVerifyUser_SuccessfulRegistrationVerificationReceivedFromRepository_ReturnsRegistrationVerificationSuccessful() { Mockito.`when`( - userAuthRepositoryImp.verifyUser(userVerify) + userAuthRepositoryImp.verifyUser(Mockito.anyString(), Mockito.anyString()) ).thenReturn(Observable.just(Mockito.mock(ResponseBody::class.java))) - registrationViewModel.verifyUser(userVerify) + registrationViewModel.verifyUser("authenticationToken", "requestId") Mockito.verify(registrationVerificationUiStateObserver) .onChanged(RegistrationVerificationUiState.Loading) @@ -193,10 +192,10 @@ class RegistrationViewModelTest { fun testVerifyUser_UnsuccessfulRegistrationVerificationReceivedFromRepository_ReturnsRegistrationVerificationUnsuccessful() { val error = RuntimeException("RegistrationVerification Failed") Mockito.`when`( - userAuthRepositoryImp.verifyUser(userVerify) + userAuthRepositoryImp.verifyUser(Mockito.anyString(), Mockito.anyString()) ).thenReturn(Observable.error(error)) - registrationViewModel.verifyUser(userVerify) + registrationViewModel.verifyUser("authenticationToken", "requestId") Mockito.verify(registrationVerificationUiStateObserver) .onChanged(RegistrationVerificationUiState.Loading) From b0b93689cd238d2bc101b54995c7e7d46014fbdc Mon Sep 17 00:00:00 2001 From: Pratyush Singh Date: Fri, 7 Jul 2023 01:38:30 +0530 Subject: [PATCH 08/14] feat: recent transaction fragment to mvvm --- .../injection/module/RepositoryModule.kt | 7 ++ .../RecentTransactionRepository.kt | 14 ++++ .../RecentTransactionRepositoryImp.kt | 15 ++++ .../fragments/RecentTransactionsFragment.kt | 72 ++++++++++++------- .../mobile/utils/RecentTransactionUiState.kt | 11 +++ .../viewModels/RecentTransactionViewModel.kt | 68 ++++++++++++++++++ 6 files changed, 160 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/org/mifos/mobile/repositories/RecentTransactionRepository.kt create mode 100644 app/src/main/java/org/mifos/mobile/repositories/RecentTransactionRepositoryImp.kt create mode 100644 app/src/main/java/org/mifos/mobile/utils/RecentTransactionUiState.kt create mode 100644 app/src/main/java/org/mifos/mobile/viewModels/RecentTransactionViewModel.kt diff --git a/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt b/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt index 2063047cc..89d331320 100644 --- a/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt +++ b/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt @@ -5,6 +5,8 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import org.mifos.mobile.api.DataManager +import org.mifos.mobile.repositories.RecentTransactionRepository +import org.mifos.mobile.repositories.RecentTransactionRepositoryImp import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.repositories.UserAuthRepositoryImp @@ -16,4 +18,9 @@ class RepositoryModule { fun providesUserAuthRepository(dataManager: DataManager): UserAuthRepository { return UserAuthRepositoryImp(dataManager) } + + @Provides + fun providesRecentTransactionRepository(dataManager: DataManager): RecentTransactionRepository { + return RecentTransactionRepositoryImp(dataManager) + } } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/RecentTransactionRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/RecentTransactionRepository.kt new file mode 100644 index 000000000..ea184ec98 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/RecentTransactionRepository.kt @@ -0,0 +1,14 @@ +package org.mifos.mobile.repositories + + +import io.reactivex.Observable +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.Transaction + +interface RecentTransactionRepository { + + fun recentTransactions( + offset: Int?, + limit: Int? + ): Observable?>? +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/RecentTransactionRepositoryImp.kt b/app/src/main/java/org/mifos/mobile/repositories/RecentTransactionRepositoryImp.kt new file mode 100644 index 000000000..da822044a --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/RecentTransactionRepositoryImp.kt @@ -0,0 +1,15 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.Transaction +import javax.inject.Inject + +class RecentTransactionRepositoryImp @Inject constructor(private val dataManager: DataManager) : + RecentTransactionRepository { + + override fun recentTransactions(offset: Int?, limit: Int?): Observable?>? { + return limit?.let { offset?.let { it1 -> dataManager.getRecentTransactions(it1, it) } } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RecentTransactionsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RecentTransactionsFragment.kt index 33fb7d214..fa64eacc9 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/RecentTransactionsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RecentTransactionsFragment.kt @@ -6,6 +6,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener @@ -14,16 +15,12 @@ import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentRecentTransactionsBinding import org.mifos.mobile.models.Transaction -import org.mifos.mobile.presenters.RecentTransactionsPresenter import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.adapters.RecentTransactionListAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.RecentTransactionsView -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.DividerItemDecoration -import org.mifos.mobile.utils.EndlessRecyclerViewScrollListener +import org.mifos.mobile.utils.* import org.mifos.mobile.utils.Network.isConnected -import org.mifos.mobile.utils.Toaster +import org.mifos.mobile.viewModels.RecentTransactionViewModel import javax.inject.Inject /** @@ -31,18 +28,17 @@ import javax.inject.Inject * @since 09/08/16 */ @AndroidEntryPoint -class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRefreshListener { +class RecentTransactionsFragment : BaseFragment(), OnRefreshListener { private var _binding: FragmentRecentTransactionsBinding? = null private val binding get() = _binding!! - @JvmField - @Inject - var recentTransactionsPresenter: RecentTransactionsPresenter? = null - @JvmField @Inject var recentTransactionsListAdapter: RecentTransactionListAdapter? = null + + private lateinit var recentTransactionViewModel: RecentTransactionViewModel + private var sweetUIErrorHandler: SweetUIErrorHandler? = null private var recentTransactionList: MutableList? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -56,18 +52,41 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef savedInstanceState: Bundle?, ): View { _binding = FragmentRecentTransactionsBinding.inflate(inflater, container, false) - recentTransactionsPresenter?.attachView(this) + recentTransactionViewModel = ViewModelProvider(this)[RecentTransactionViewModel::class.java] sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) showUserInterface() setToolbarTitle(getString(R.string.recent_transactions)) if (savedInstanceState == null) { - recentTransactionsPresenter?.loadRecentTransactions(false, 0) + recentTransactionViewModel.loadRecentTransactions(false, 0) } return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + recentTransactionViewModel.recentTransactionUiState.observe(viewLifecycleOwner) { + when (it) { + is RecentTransactionUiState.Loading -> showProgress() + is RecentTransactionUiState.RecentTransactions -> { + hideProgress() + showRecentTransactions(it.transactions) + } + is RecentTransactionUiState.Error -> { + hideProgress() + showMessage(getString(it.message)) + } + is RecentTransactionUiState.EmptyTransaction -> { + hideProgress() + showEmptyTransaction() + } + is RecentTransactionUiState.LoadMoreRecentTransactions -> { + hideProgress() + showLoadMoreRecentTransactions(it.transactions) + } + } + } + binding.layoutError.btnTryAgain.setOnClickListener { retryClicked() } @@ -95,7 +114,7 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef /** * Setting up `rvRecentTransactions` */ - override fun showUserInterface() { + fun showUserInterface() { val layoutManager = LinearLayoutManager(activity) layoutManager.orientation = LinearLayoutManager.VERTICAL binding.rvRecentTransactions.layoutManager = layoutManager @@ -111,7 +130,7 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef binding.rvRecentTransactions.addOnScrollListener( object : EndlessRecyclerViewScrollListener(layoutManager) { override fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView?) { - recentTransactionsPresenter?.loadRecentTransactions(true, totalItemsCount) + recentTransactionViewModel.loadRecentTransactions(true, totalItemsCount) } override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { @@ -138,13 +157,13 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef if (binding.layoutError.root.visibility == View.VISIBLE) { resetUI() } - recentTransactionsPresenter?.loadRecentTransactions(false, 0) + recentTransactionViewModel.loadRecentTransactions(false, 0) } /** * Shows a Toast */ - override fun showMessage(message: String?) { + fun showMessage(message: String?) { (activity as BaseActivity?)?.showToast(message!!) } @@ -154,7 +173,7 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef * * @param recentTransactionList List of [Transaction] */ - override fun showRecentTransactions(recentTransactionList: List?) { + fun showRecentTransactions(recentTransactionList: List?) { this.recentTransactionList = recentTransactionList as MutableList? recentTransactionsListAdapter?.setTransactions(recentTransactionList) } @@ -164,12 +183,12 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef * * @param transactions List of [Transaction] */ - override fun showLoadMoreRecentTransactions(transactions: List?) { + fun showLoadMoreRecentTransactions(transactions: List?) { this.recentTransactionList?.addAll(recentTransactionList!!) recentTransactionsListAdapter?.notifyDataSetChanged() } - override fun resetUI() { + fun resetUI() { sweetUIErrorHandler?.hideSweetErrorLayoutUI( binding.rvRecentTransactions, binding.layoutError.root, @@ -179,7 +198,7 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef /** * Hides `rvRecentTransactions` and shows a textview prompting no transactions */ - override fun showEmptyTransaction() { + fun showEmptyTransaction() { sweetUIErrorHandler?.showSweetEmptyUI( getString(R.string.recent_transactions), R.drawable.ic_error_black_24dp, @@ -193,7 +212,7 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef * * @param message Error message that tells the user about the problem. */ - override fun showErrorFetchingRecentTransactions(message: String?) { + fun showErrorFetchingRecentTransactions(message: String?) { if (!isConnected(requireActivity())) { sweetUIErrorHandler?.showSweetNoInternetUI( binding.rvRecentTransactions, @@ -214,7 +233,7 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef binding.rvRecentTransactions, binding.layoutError.root, ) - recentTransactionsPresenter?.loadRecentTransactions(false, 0) + recentTransactionViewModel.loadRecentTransactions(false, 0) } else { Toast.makeText( context, @@ -224,15 +243,15 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef } } - override fun showProgress() { + fun showProgress() { showSwipeRefreshLayout(true) } - override fun hideProgress() { + fun hideProgress() { showSwipeRefreshLayout(false) } - override fun showSwipeRefreshLayout(show: Boolean) { + fun showSwipeRefreshLayout(show: Boolean) { binding.swipeTransactionContainer.post { binding.swipeTransactionContainer.isRefreshing = show } @@ -240,7 +259,6 @@ class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRef override fun onDestroyView() { super.onDestroyView() - recentTransactionsPresenter?.detachView() _binding = null } diff --git a/app/src/main/java/org/mifos/mobile/utils/RecentTransactionUiState.kt b/app/src/main/java/org/mifos/mobile/utils/RecentTransactionUiState.kt new file mode 100644 index 000000000..2838e9512 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/RecentTransactionUiState.kt @@ -0,0 +1,11 @@ +package org.mifos.mobile.utils + +import org.mifos.mobile.models.Transaction + +sealed class RecentTransactionUiState { + object Loading : RecentTransactionUiState() + object EmptyTransaction : RecentTransactionUiState() + data class Error(val message: Int) : RecentTransactionUiState() + data class RecentTransactions(val transactions: List) : RecentTransactionUiState() + data class LoadMoreRecentTransactions(val transactions: List) : RecentTransactionUiState() +} diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RecentTransactionViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RecentTransactionViewModel.kt new file mode 100644 index 000000000..b4b2e1868 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/RecentTransactionViewModel.kt @@ -0,0 +1,68 @@ +package org.mifos.mobile.viewModels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.observers.DisposableObserver +import io.reactivex.schedulers.Schedulers +import org.mifos.mobile.R +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.Transaction +import org.mifos.mobile.repositories.RecentTransactionRepository +import org.mifos.mobile.utils.RecentTransactionUiState +import javax.inject.Inject + +@HiltViewModel +class RecentTransactionViewModel @Inject constructor(private val recentTransactionRepositoryImp: RecentTransactionRepository) : + ViewModel() { + + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + private val limit = 50 + private var loadmore = false + + private val _recentTransactionUiState = MutableLiveData() + val recentTransactionUiState: LiveData = _recentTransactionUiState + + fun loadRecentTransactions(loadmore: Boolean, offset: Int) { + this.loadmore = loadmore + loadRecentTransactions(offset, limit) + } + + private fun loadRecentTransactions(offset: Int, limit: Int) { + _recentTransactionUiState.value = RecentTransactionUiState.Loading + recentTransactionRepositoryImp.recentTransactions(offset, limit) + ?.observeOn( AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver?>() { + override fun onNext(transactions: Page) { + if (transactions.totalFilteredRecords == 0) { + _recentTransactionUiState.value = RecentTransactionUiState.EmptyTransaction + } else if (loadmore && transactions.pageItems.isNotEmpty()) { + _recentTransactionUiState.value = RecentTransactionUiState.LoadMoreRecentTransactions(transactions.pageItems) + } else if (transactions.pageItems.isNotEmpty()) { + _recentTransactionUiState.value = RecentTransactionUiState.RecentTransactions(transactions.pageItems) + } + } + + override fun onError(e: Throwable) { + _recentTransactionUiState.value = RecentTransactionUiState.Error(R.string.recent_transactions) + } + + override fun onComplete() {} + }).let { + if (it != null) { + compositeDisposables.add( + it, + ) + } + } + } + + override fun onCleared() { + super.onCleared() + compositeDisposables.clear() + } +} \ No newline at end of file From e3ed04d9237bfc815d449cf90a59a41c35415526 Mon Sep 17 00:00:00 2001 From: Pratyush Singh Date: Mon, 10 Jul 2023 22:26:47 +0530 Subject: [PATCH 09/14] feat: Unit tests for viewmodel and repository --- .../RecentTransactionRepositoryImpTest.kt | 61 +++++++ .../RecentTransactionViewModelTest.kt | 163 ++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 app/src/test/java/org/mifos/mobile/repositories/RecentTransactionRepositoryImpTest.kt create mode 100644 app/src/test/java/org/mifos/mobile/viewModels/RecentTransactionViewModelTest.kt diff --git a/app/src/test/java/org/mifos/mobile/repositories/RecentTransactionRepositoryImpTest.kt b/app/src/test/java/org/mifos/mobile/repositories/RecentTransactionRepositoryImpTest.kt new file mode 100644 index 000000000..a90f8075c --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/repositories/RecentTransactionRepositoryImpTest.kt @@ -0,0 +1,61 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.Transaction +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + + +@RunWith(MockitoJUnitRunner::class) +class RecentTransactionRepositoryImpTest { + + @Mock + lateinit var dataManager: DataManager + + private lateinit var recentTransactionRepositoryImp: RecentTransactionRepositoryImp + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + recentTransactionRepositoryImp = RecentTransactionRepositoryImp(dataManager) + } + + @Test + fun recentTransaction_successful_response_from_dataManger() { + val success: Observable?> = + Observable.just(Mockito.mock(Page()::class.java)) + val offset = 0 + val limit = 50 + + Mockito.`when`(dataManager.getRecentTransactions(offset, limit)).thenReturn(success) + + val result = recentTransactionRepositoryImp.recentTransactions(offset, limit) + + Mockito.verify(dataManager).getRecentTransactions(offset, limit) + Assert.assertEquals(result, success) + } + + @Test + fun recentTransaction_unsuccessful_response_from_dataManger() { + val error: Observable?> = + Observable.error(Throwable("Recent Transaction Failed")) + val offset = 0 + val limit = 50 + + Mockito.`when`(dataManager.getRecentTransactions(offset, limit)).thenReturn(error) + + val result = recentTransactionRepositoryImp.recentTransactions(offset, limit) + + Mockito.verify(dataManager).getRecentTransactions(offset, limit) + Assert.assertEquals(result, error) + } + +} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/RecentTransactionViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/RecentTransactionViewModelTest.kt new file mode 100644 index 000000000..aab9329ff --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/RecentTransactionViewModelTest.kt @@ -0,0 +1,163 @@ +package org.mifos.mobile.viewModels + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Observer +import io.reactivex.Observable +import org.junit.* +import org.junit.runner.RunWith +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.Transaction +import org.mifos.mobile.models.client.Currency +import org.mifos.mobile.models.client.Type +import org.mifos.mobile.repositories.RecentTransactionRepository +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.RecentTransactionUiState +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner +import org.mifos.mobile.R + +@RunWith(MockitoJUnitRunner::class) +class RecentTransactionViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var recentTransactionRepositoryImp: RecentTransactionRepository + + @Mock + lateinit var recentTransactionUiStateObserver: Observer + + @Mock + lateinit var type: Type + + @Mock + lateinit var currency: Currency + + lateinit var viewModel: RecentTransactionViewModel + + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + viewModel = RecentTransactionViewModel(recentTransactionRepositoryImp) + viewModel.recentTransactionUiState.observeForever(recentTransactionUiStateObserver) + } + + @Test + fun loadRecentTransaction_success_with_no_empty_transactions() { + val offset = 0 + val limit = 50 + + val transaction = Transaction( + id = 1L, + officeId = 2L, + officeName = "Office", + type = type, + date = listOf(2023, 7, 8), + currency = currency, + amount = 10.0, + submittedOnDate = listOf(2023, 7, 9), + reversed = false + ) + val transactions: Page = + Page(totalFilteredRecords = 1, pageItems = listOf(transaction)) + `when`(recentTransactionRepositoryImp.recentTransactions(offset, limit)) + .thenReturn(Observable.just(transactions)) + + viewModel.loadRecentTransactions(loadmore = false, offset) + + verify(recentTransactionUiStateObserver).onChanged(RecentTransactionUiState.Loading) + Assert.assertEquals( + transactions.pageItems.let { RecentTransactionUiState.RecentTransactions(it) }, + viewModel.recentTransactionUiState.value + ) + } + + @Test + fun loadRecentTransaction_success_with_empty_transactions() { + val offset = 0 + val limit = 50 + + val transaction = Transaction( + id = 1L, + officeId = 2L, + officeName = "Office", + type = type, + date = listOf(2023, 7, 8), + currency = currency, + amount = 10.0, + submittedOnDate = listOf(2023, 7, 9), + reversed = false + ) + val transactions: Page = + Page(totalFilteredRecords = 0, pageItems = listOf(transaction)) + `when`(recentTransactionRepositoryImp.recentTransactions(offset, limit)) + .thenReturn(Observable.just(transactions)) + + viewModel.loadRecentTransactions(loadmore = false, offset) + + verify(recentTransactionUiStateObserver).onChanged(RecentTransactionUiState.Loading) + Assert.assertEquals( + RecentTransactionUiState.EmptyTransaction, + viewModel.recentTransactionUiState.value + ) + } + + @Test + fun loadRecentTransaction_success_with_load_more_transactions() { + val offset = 0 + val limit = 50 + + val transaction = Transaction( + id = 1L, + officeId = 2L, + officeName = "Office", + type = type, + date = listOf(2023, 7, 8), + currency = currency, + amount = 10.0, + submittedOnDate = listOf(2023, 7, 9), + reversed = false + ) + val transactions: Page = + Page(totalFilteredRecords = 1, pageItems = listOf(transaction)) + `when`(recentTransactionRepositoryImp.recentTransactions(offset, limit)) + .thenReturn(Observable.just(transactions)) + + viewModel.loadRecentTransactions(loadmore = true, offset) + + verify(recentTransactionUiStateObserver).onChanged(RecentTransactionUiState.Loading) + Assert.assertEquals( + transactions.pageItems.let { RecentTransactionUiState.LoadMoreRecentTransactions(it) }, + viewModel.recentTransactionUiState.value + ) + + } + + @Test + fun loadRecentTransaction_unsuccessful() { + val error = Throwable("Recent Transaction error") + `when`(recentTransactionRepositoryImp.recentTransactions(anyInt(), anyInt())).thenReturn( + Observable.error(error) + ) + viewModel.loadRecentTransactions(false, 0) + + Assert.assertEquals( + RecentTransactionUiState.Error(R.string.recent_transactions), + viewModel.recentTransactionUiState.value + ) + } + + @After + fun tearDown() { + viewModel.recentTransactionUiState.removeObserver(recentTransactionUiStateObserver) + } + +} \ No newline at end of file From cd3b0f497d0c2e67e83003ee8255afef3249d188 Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Sun, 9 Jul 2023 18:47:38 +0530 Subject: [PATCH 10/14] feat : updatepassword fragment mvvm migration -> added viewModel and repository -> refactored "RegistrationUiState" to "UiState" so that it could be used across registrationFragment and updatePasscode fragment -> refactored updatePassword fragment's exisiting code, to use more kotlin specific ways. -> shifted client related logic from userAuthRepository to ClientRepository. -> added client repository to update password fragment using hilt, and modified repository module accordingly. --- .../injection/module/RepositoryModule.kt | 8 + .../mobile/repositories/ClientRepository.kt | 6 + .../repositories/ClientRepositoryImp.kt | 19 ++ .../mobile/repositories/UserAuthRepository.kt | 5 + .../repositories/UserAuthRepositoryImp.kt | 16 +- .../ui/fragments/RegistrationFragment.kt | 8 +- .../ui/fragments/UpdatePasswordFragment.kt | 209 +++++++++--------- .../mifos/mobile/utils/RegistrationUiState.kt | 7 - .../java/org/mifos/mobile/utils/UiState.kt | 7 + .../viewModels/RegistrationViewModel.kt | 12 +- .../viewModels/UpdatePasswordViewModel.kt | 62 ++++++ .../viewModels/RegistrationViewModelTest.kt | 14 +- 12 files changed, 245 insertions(+), 128 deletions(-) create mode 100644 app/src/main/java/org/mifos/mobile/repositories/ClientRepository.kt create mode 100644 app/src/main/java/org/mifos/mobile/repositories/ClientRepositoryImp.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt create mode 100644 app/src/main/java/org/mifos/mobile/utils/UiState.kt create mode 100644 app/src/main/java/org/mifos/mobile/viewModels/UpdatePasswordViewModel.kt diff --git a/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt b/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt index 2063047cc..dff1aadb2 100644 --- a/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt +++ b/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt @@ -5,6 +5,9 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import org.mifos.mobile.api.DataManager +import org.mifos.mobile.api.local.PreferencesHelper +import org.mifos.mobile.repositories.ClientRepository +import org.mifos.mobile.repositories.ClientRepositoryImp import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.repositories.UserAuthRepositoryImp @@ -16,4 +19,9 @@ class RepositoryModule { fun providesUserAuthRepository(dataManager: DataManager): UserAuthRepository { return UserAuthRepositoryImp(dataManager) } + + @Provides + fun providesClientRepository(preferencesHelper: PreferencesHelper): ClientRepository { + return ClientRepositoryImp(preferencesHelper) + } } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/ClientRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/ClientRepository.kt new file mode 100644 index 000000000..4a8b2e707 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/ClientRepository.kt @@ -0,0 +1,6 @@ +package org.mifos.mobile.repositories + +interface ClientRepository { + + fun updateAuthenticationToken(password: String) +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/ClientRepositoryImp.kt b/app/src/main/java/org/mifos/mobile/repositories/ClientRepositoryImp.kt new file mode 100644 index 000000000..12931d1a6 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/ClientRepositoryImp.kt @@ -0,0 +1,19 @@ +package org.mifos.mobile.repositories + +import okhttp3.Credentials +import org.mifos.mobile.api.BaseApiManager +import org.mifos.mobile.api.local.PreferencesHelper +import javax.inject.Inject + +class ClientRepositoryImp @Inject constructor(private val preferencesHelper: PreferencesHelper) : ClientRepository { + + override fun updateAuthenticationToken(password: String) { + val authenticationToken = Credentials.basic(preferencesHelper.userName!!, password) + preferencesHelper.saveToken(authenticationToken) + BaseApiManager.createService( + preferencesHelper.baseUrl, + preferencesHelper.tenant, + preferencesHelper.token, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt index 145c251ef..db996f66c 100644 --- a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt +++ b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt @@ -15,4 +15,9 @@ interface UserAuthRepository { password: String?, username: String? ): Observable? + + fun updateAccountPassword( + newPassword: String, confirmPassword: String + ): Observable? + } diff --git a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt index 27f45872d..1ec16eb3e 100644 --- a/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt +++ b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt @@ -3,11 +3,11 @@ package org.mifos.mobile.repositories import io.reactivex.Observable import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.UpdatePasswordPayload import org.mifos.mobile.models.register.RegisterPayload import javax.inject.Inject -class UserAuthRepositoryImp @Inject constructor(private val dataManager: DataManager) : - UserAuthRepository { +class UserAuthRepositoryImp @Inject constructor(private val dataManager: DataManager) : UserAuthRepository { override fun registerUser( accountNumber: String?, @@ -31,4 +31,16 @@ class UserAuthRepositoryImp @Inject constructor(private val dataManager: DataMan } return dataManager.registerUser(registerPayload) } + + override fun updateAccountPassword( + newPassword: String, confirmPassword: String + ): Observable? { + val payload = UpdatePasswordPayload().apply { + this.password = newPassword + this.repeatPassword = confirmPassword + } + + return dataManager.updateAccountPassword(payload) + } + } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt index 889047a32..76b318e27 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt @@ -19,7 +19,7 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.MFErrorParser import org.mifos.mobile.utils.Network import org.mifos.mobile.utils.PasswordStrength -import org.mifos.mobile.utils.RegistrationUiState +import org.mifos.mobile.utils.UiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.RegistrationViewModel @@ -91,14 +91,14 @@ class RegistrationFragment : BaseFragment() { viewModel.registrationUiState.observe(viewLifecycleOwner) { state -> when (state) { - RegistrationUiState.Loading -> showProgress() + UiState.Loading -> showProgress() - RegistrationUiState.RegistrationSuccessful -> { + UiState.Success -> { hideProgress() showRegisteredSuccessfully() } - is RegistrationUiState.ErrorOnRegistration -> { + is UiState.Error -> { hideProgress() showError(MFErrorParser.errorMessage(state.exception)) } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt index 5ab5f2152..3443d60a7 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt @@ -8,40 +8,27 @@ import android.view.View import android.view.View.OnFocusChangeListener import android.view.ViewGroup import android.widget.Toast +import androidx.lifecycle.ViewModelProvider import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.databinding.FragmentUpdatePasswordBinding -import org.mifos.mobile.models.UpdatePasswordPayload -import org.mifos.mobile.presenters.UpdatePasswordPresenter import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.UpdatePasswordView +import org.mifos.mobile.utils.MFErrorParser import org.mifos.mobile.utils.Network import org.mifos.mobile.utils.Toaster -import javax.inject.Inject +import org.mifos.mobile.utils.UiState +import org.mifos.mobile.viewModels.UpdatePasswordViewModel /* * Created by saksham on 13/July/2018 */ @AndroidEntryPoint -class UpdatePasswordFragment : - BaseFragment(), - UpdatePasswordView, - TextWatcher, - OnFocusChangeListener { +class UpdatePasswordFragment : BaseFragment(), TextWatcher, OnFocusChangeListener { private var _binding: FragmentUpdatePasswordBinding? = null private val binding get() = _binding!! - - @JvmField - @Inject - var presenter: UpdatePasswordPresenter? = null - - @JvmField - @Inject - var preferencesHelper: PreferencesHelper? = null - private var payload: UpdatePasswordPayload? = null + private lateinit var viewModel: UpdatePasswordViewModel private var isFocusLostNewPassword = false private var isFocusLostConfirmPassword = false @@ -52,7 +39,7 @@ class UpdatePasswordFragment : ): View { _binding = FragmentUpdatePasswordBinding.inflate(inflater, container, false) setToolbarTitle(getString(R.string.change_password)) - presenter?.attachView(this) + viewModel = ViewModelProvider(this)[UpdatePasswordViewModel::class.java] binding.tilNewPassword.editText?.addTextChangedListener(this) binding.tilConfirmNewPassword.editText?.addTextChangedListener(this) binding.tilNewPassword.editText?.onFocusChangeListener = this @@ -65,50 +52,115 @@ class UpdatePasswordFragment : binding.btnUpdatePassword.setOnClickListener { updatePassword() } + + viewModel.updatePasswordUiState.observe(viewLifecycleOwner) { state -> + when (state) { + UiState.Loading -> showProgress() + UiState.Success -> { + hideProgress() + showPasswordUpdatedSuccessfully() + } + + is UiState.Error -> { + hideProgress() + showError(MFErrorParser.errorMessage(state.exception)) + } + } + } } - fun updatePassword() { - if (isFieldsCompleted) { - presenter?.updateAccountPassword(updatePasswordPayload) + private fun updatePassword() { + val newPassword = binding.tilNewPassword.editText?.text.toString().trim() + val confirmPassword = binding.tilConfirmNewPassword.editText?.text.toString().trim() + + if (areFieldsValidated(newPassword, confirmPassword)) { + viewModel.updateAccountPassword(newPassword, confirmPassword) } } - private val isFieldsCompleted: Boolean - get() { - var rv = true - val newPassword = binding.tilNewPassword.editText?.text.toString().trim { it <= ' ' } - val repeatPassword = - binding.tilConfirmNewPassword.editText?.text.toString().trim { it <= ' ' } - if (!checkNewPasswordFieldsComplete()) { - rv = false - } - if (!checkConfirmPasswordFieldsComplete()) { - rv = false - } - if (newPassword != repeatPassword) { + private fun areFieldsValidated(newPassword: String, confirmPassword: String): Boolean { + return when { + !isNewPasswordValidated() -> false + !isConfirmPasswordValidated() -> false + (!viewModel.validatePasswordMatch(newPassword, confirmPassword)) -> { Toaster.show(binding.root, getString(R.string.error_password_not_match)) - rv = false + false + } + + else -> true + } + } + + private fun isNewPasswordValidated(): Boolean { + with(binding) { + val newPassword = tilNewPassword.editText?.text.toString() + isFocusLostNewPassword = true + return when { + viewModel.isInputFieldEmpty(newPassword) -> { + tilNewPassword.error = getString( + R.string.error_validation_blank, + getString(R.string.new_password), + ) + false + } + + viewModel.isInputLengthInadequate(newPassword) -> { + tilNewPassword.error = getString( + R.string.error_validation_minimum_chars, + getString(R.string.new_password), + resources.getInteger(R.integer.password_minimum_length), + ) + false + } + + else -> { + tilNewPassword.isErrorEnabled = false + return true + } } - return rv } - private val updatePasswordPayload: UpdatePasswordPayload? - get() { - payload = UpdatePasswordPayload() - payload?.password = binding.tilNewPassword.editText?.text.toString().trim { it <= ' ' } - payload?.repeatPassword = - binding.tilConfirmNewPassword.editText?.text.toString().trim { it <= ' ' } - return payload + } + + private fun isConfirmPasswordValidated(): Boolean { + with(binding) { + val confirmPassword = tilConfirmNewPassword.editText?.text.toString() + isFocusLostConfirmPassword = true + return when { + viewModel.isInputFieldEmpty(confirmPassword) -> { + tilConfirmNewPassword.error = getString( + R.string.error_validation_blank, + getString(R.string.confirm_password), + ) + false + } + + viewModel.isInputLengthInadequate(confirmPassword) -> { + tilConfirmNewPassword.error = getString( + R.string.error_validation_minimum_chars, + getString(R.string.confirm_password), + resources.getInteger(R.integer.password_minimum_length), + ) + return false + } + + else -> { + tilConfirmNewPassword.isErrorEnabled = false + return true + } + } } - override fun showError(message: String?) { - var message = message + } + + fun showError(message: String?) { + var errorMessage = message if (!Network.isConnected(activity)) { - message = getString(R.string.no_internet_connection) + errorMessage = getString(R.string.no_internet_connection) } - Toaster.show(binding.root, message) + Toaster.show(binding.root, errorMessage) } - override fun showPasswordUpdatedSuccessfully() { + private fun showPasswordUpdatedSuccessfully() { Toast.makeText( context, getString( @@ -125,86 +177,41 @@ class UpdatePasswordFragment : ) } - override fun showProgress() { + fun showProgress() { showMifosProgressDialog(getString(R.string.progress_message_loading)) } - override fun hideProgress() { + fun hideProgress() { hideMifosProgressDialog() } override fun onDestroyView() { super.onDestroyView() - presenter?.detachView() _binding = null } override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { if (binding.tilNewPassword.editText?.hasFocus() == true && isFocusLostNewPassword) { - checkNewPasswordFieldsComplete() + isNewPasswordValidated() } if (binding.tilConfirmNewPassword.editText?.hasFocus() == true && isFocusLostConfirmPassword) { - checkConfirmPasswordFieldsComplete() + isConfirmPasswordValidated() } } override fun afterTextChanged(s: Editable) {} override fun onFocusChange(v: View, hasFocus: Boolean) { if (v.id == R.id.et_new_password && !isFocusLostNewPassword && !hasFocus) { - checkNewPasswordFieldsComplete() + isNewPasswordValidated() isFocusLostNewPassword = true } if (v.id == R.id.et_confirm_password && !isFocusLostConfirmPassword && !hasFocus) { - checkConfirmPasswordFieldsComplete() + isConfirmPasswordValidated() isFocusLostConfirmPassword = true } } - private fun checkNewPasswordFieldsComplete(): Boolean { - val newPassword = binding.tilNewPassword.editText?.text.toString() - isFocusLostNewPassword = true - if (newPassword.isEmpty()) { - binding.tilNewPassword.error = getString( - R.string.error_validation_blank, - getString(R.string.new_password), - ) - return false - } - if (newPassword.length < 6) { - binding.tilNewPassword.error = getString( - R.string.error_validation_minimum_chars, - getString(R.string.new_password), - resources.getInteger(R.integer.password_minimum_length), - ) - return false - } - binding.tilNewPassword.isErrorEnabled = false - return true - } - - private fun checkConfirmPasswordFieldsComplete(): Boolean { - val confirmPassword = binding.tilConfirmNewPassword.editText?.text.toString() - isFocusLostConfirmPassword = true - if (confirmPassword.isEmpty()) { - binding.tilConfirmNewPassword.error = getString( - R.string.error_validation_blank, - getString(R.string.confirm_password), - ) - return false - } - if (confirmPassword.length < 6) { - binding.tilConfirmNewPassword.error = getString( - R.string.error_validation_minimum_chars, - getString(R.string.confirm_password), - resources.getInteger(R.integer.password_minimum_length), - ) - return false - } - binding.tilConfirmNewPassword.isErrorEnabled = false - return true - } - companion object { @JvmStatic fun newInstance(): UpdatePasswordFragment { diff --git a/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt b/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt deleted file mode 100644 index a380f5222..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.mifos.mobile.utils - -sealed class RegistrationUiState { - data class ErrorOnRegistration(val exception: Throwable) : RegistrationUiState() - object RegistrationSuccessful : RegistrationUiState() - object Loading : RegistrationUiState() -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/utils/UiState.kt b/app/src/main/java/org/mifos/mobile/utils/UiState.kt new file mode 100644 index 000000000..5180a9059 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/UiState.kt @@ -0,0 +1,7 @@ +package org.mifos.mobile.utils + +sealed class UiState { + data class Error(val exception: Throwable) : UiState() + object Success : UiState() + object Loading : UiState() +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt index f773d8d9f..2420a4c97 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt @@ -11,7 +11,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.repositories.UserAuthRepository -import org.mifos.mobile.utils.RegistrationUiState +import org.mifos.mobile.utils.UiState import javax.inject.Inject @HiltViewModel @@ -19,8 +19,8 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm ViewModel() { private val compositeDisposables: CompositeDisposable = CompositeDisposable() - private val _registrationUiState = MutableLiveData() - val registrationUiState: LiveData get() = _registrationUiState + private val _registrationUiState = MutableLiveData() + val registrationUiState: LiveData get() = _registrationUiState fun isInputFieldBlank(fieldText: String): Boolean { return fieldText.trim().isEmpty() @@ -52,7 +52,7 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm password: String, username: String ) { - _registrationUiState.value = RegistrationUiState.Loading + _registrationUiState.value = UiState.Loading userAuthRepositoryImp.registerUser( accountNumber, authenticationMode, @@ -66,11 +66,11 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm ?.subscribeWith(object : DisposableObserver() { override fun onComplete() {} override fun onError(e: Throwable) { - _registrationUiState.value = RegistrationUiState.ErrorOnRegistration(e) + _registrationUiState.value = UiState.Error(e) } override fun onNext(responseBody: ResponseBody) { - _registrationUiState.value = RegistrationUiState.RegistrationSuccessful + _registrationUiState.value = UiState.Success } })?.let { compositeDisposables.add(it) } } diff --git a/app/src/main/java/org/mifos/mobile/viewModels/UpdatePasswordViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/UpdatePasswordViewModel.kt new file mode 100644 index 000000000..747485278 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/UpdatePasswordViewModel.kt @@ -0,0 +1,62 @@ +package org.mifos.mobile.viewModels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.observers.DisposableObserver +import io.reactivex.schedulers.Schedulers +import okhttp3.ResponseBody +import org.mifos.mobile.repositories.ClientRepository +import org.mifos.mobile.repositories.UserAuthRepository +import org.mifos.mobile.utils.UiState +import javax.inject.Inject + +@HiltViewModel +class UpdatePasswordViewModel @Inject constructor( + private val userAuthRepositoryImp: UserAuthRepository, + private val clientRepositoryImp: ClientRepository +) : ViewModel() { + + private val compositeDisposable = CompositeDisposable() + private val _updatePasswordUiState = MutableLiveData() + val updatePasswordUiState: LiveData get() = _updatePasswordUiState + fun isInputFieldEmpty(fieldText: String): Boolean { + return fieldText.isEmpty() + } + + fun isInputLengthInadequate(fieldText: String): Boolean { + return fieldText.length < 6 + } + + fun validatePasswordMatch(newPassword: String, confirmPassword: String): Boolean { + return newPassword == confirmPassword + } + + fun updateAccountPassword(newPassword: String, confirmPassword: String) { + _updatePasswordUiState.value = UiState.Loading + userAuthRepositoryImp.updateAccountPassword(newPassword, confirmPassword) + ?.subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeWith(object : DisposableObserver() { + override fun onNext(responseBody: ResponseBody) { + _updatePasswordUiState.value = UiState.Success + clientRepositoryImp.updateAuthenticationToken(newPassword) + } + + override fun onError(e: Throwable) { + _updatePasswordUiState.value = UiState.Error(e) + } + + override fun onComplete() {} + })?.let { compositeDisposable.add(it) } + } + + + override fun onCleared() { + super.onCleared() + compositeDisposable.clear() + } +} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt index 63d0f6d64..9c3160bf4 100644 --- a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt +++ b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt @@ -12,7 +12,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mifos.mobile.repositories.UserAuthRepositoryImp import org.mifos.mobile.util.RxSchedulersOverrideRule -import org.mifos.mobile.utils.RegistrationUiState +import org.mifos.mobile.utils.UiState import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations @@ -33,7 +33,7 @@ class RegistrationViewModelTest { lateinit var userAuthRepositoryImp: UserAuthRepositoryImp @Mock - lateinit var registrationUiStateObserver: Observer + lateinit var registrationUiStateObserver: Observer private lateinit var registrationViewModel: RegistrationViewModel @@ -127,9 +127,8 @@ class RegistrationViewModelTest { "userName" ) - Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Loading) - Mockito.verify(registrationUiStateObserver) - .onChanged(RegistrationUiState.RegistrationSuccessful) + Mockito.verify(registrationUiStateObserver).onChanged(UiState.Loading) + Mockito.verify(registrationUiStateObserver).onChanged(UiState.Success) Mockito.verifyNoMoreInteractions(registrationUiStateObserver) } @@ -160,9 +159,8 @@ class RegistrationViewModelTest { "username" ) - Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Loading) - Mockito.verify(registrationUiStateObserver) - .onChanged(RegistrationUiState.ErrorOnRegistration(error)) + Mockito.verify(registrationUiStateObserver).onChanged(UiState.Loading) + Mockito.verify(registrationUiStateObserver).onChanged(UiState.Error(error)) Mockito.verifyNoMoreInteractions(registrationUiStateObserver) } From 1edb472ca38398b12b5412979456061b88d47b66 Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Tue, 11 Jul 2023 23:43:24 +0530 Subject: [PATCH 11/14] feat : updatePassword mvvm migration -> added unit tests for updatePasswordViewModel --- .../viewModels/UpdatePasswordViewModelTest.kt | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 app/src/test/java/org/mifos/mobile/viewModels/UpdatePasswordViewModelTest.kt diff --git a/app/src/test/java/org/mifos/mobile/viewModels/UpdatePasswordViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/UpdatePasswordViewModelTest.kt new file mode 100644 index 000000000..e31fbe326 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/UpdatePasswordViewModelTest.kt @@ -0,0 +1,122 @@ +package org.mifos.mobile.viewModels + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Observer +import io.reactivex.Observable +import okhttp3.ResponseBody + +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.repositories.ClientRepository +import org.mifos.mobile.repositories.UserAuthRepository +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.UiState +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner +import kotlin.RuntimeException + +@RunWith(MockitoJUnitRunner::class) +class UpdatePasswordViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var userAuthRepositoryImp: UserAuthRepository + + @Mock + lateinit var clientRepositoryImp: ClientRepository + + @Mock + private lateinit var updatePasswordUiStateObserver: Observer + + private lateinit var updatePasswordViewModel: UpdatePasswordViewModel + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + updatePasswordViewModel = + UpdatePasswordViewModel(userAuthRepositoryImp, clientRepositoryImp) + updatePasswordViewModel.updatePasswordUiState.observeForever(updatePasswordUiStateObserver) + } + + @Test + fun testIsInputFieldEmpty_WithEmptyStringInput_ReturnsTrue() { + val result = updatePasswordViewModel.isInputFieldEmpty("") + Assert.assertTrue(result) + } + + @Test + fun testIsInputFieldEmpty_WithNonEmptyStringInput_ReturnsFalse() { + val result = updatePasswordViewModel.isInputFieldEmpty("nonEmptyStringInput") + Assert.assertFalse(result) + } + + @Test + fun testIsInputLengthInadequate_WithAdequateLengthInput_ReturnsFalse() { + val result = updatePasswordViewModel.isInputLengthInadequate("Password123") + Assert.assertFalse(result) + } + + @Test + fun testIsInputLengthInadequate_WithInadequateLengthInput_ReturnsTrue() { + val result = updatePasswordViewModel.isInputLengthInadequate("") + Assert.assertTrue(result) + } + + @Test + fun testValidatePasswordMatch_WithSamePasswords_ReturnsTrue() { + val result = updatePasswordViewModel.validatePasswordMatch("password", "password") + Assert.assertTrue(result) + } + + @Test + fun testValidatePasswordMatch_WithDifferentPasswords_ReturnsFalse() { + val result = updatePasswordViewModel.validatePasswordMatch("password1", "password2") + Assert.assertFalse(result) + } + + @Test + fun testUpdateAccountPassword_SuccessReceivedFromRepository_ReturnsSuccess() { + val responseBody = Mockito.mock(ResponseBody::class.java) + Mockito.`when`( + userAuthRepositoryImp.updateAccountPassword(Mockito.anyString(), Mockito.anyString()) + ).thenReturn(Observable.just(responseBody)) + + updatePasswordViewModel.updateAccountPassword("newPassword", "newPassword") + Mockito.verify(updatePasswordUiStateObserver).onChanged(UiState.Loading) + Mockito.verify(updatePasswordUiStateObserver).onChanged(UiState.Success) + Mockito.verify(clientRepositoryImp).updateAuthenticationToken("newPassword") + Mockito.verifyNoMoreInteractions(updatePasswordUiStateObserver) + } + + @Test + fun testUpdateAccountPassword_ErrorReceivedFromRepository_ReturnsError() { + val error = RuntimeException("fail") + Mockito.`when`( + userAuthRepositoryImp.updateAccountPassword(Mockito.anyString(), Mockito.anyString()) + ).thenReturn(Observable.error(error)) + + updatePasswordViewModel.updateAccountPassword("newPassword", "newPassword") + + Mockito.verify(updatePasswordUiStateObserver).onChanged(UiState.Loading) + Mockito.verify(updatePasswordUiStateObserver).onChanged(UiState.Error(error)) + Mockito.verifyNoMoreInteractions(updatePasswordUiStateObserver) + } + + + @After + fun tearDown() { + updatePasswordViewModel.updatePasswordUiState.removeObserver(updatePasswordUiStateObserver) + } +} \ No newline at end of file From 3b97626fc516fbf5d53c9bf7b31fa7d7dca9c8c4 Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Fri, 14 Jul 2023 13:13:41 +0530 Subject: [PATCH 12/14] feat : updatepassword mvvm migration -> added unit tests for client repository. --- .../repositories/ClientRepositoryImpTest.kt | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt diff --git a/app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt b/app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt new file mode 100644 index 000000000..7ded8c55e --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt @@ -0,0 +1,42 @@ +package org.mifos.mobile.repositories + +import okhttp3.Credentials +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.api.BaseURL +import org.mifos.mobile.api.local.PreferencesHelper +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class ClientRepositoryImpTest { + + @Mock + lateinit var preferencesHelper: PreferencesHelper + + private lateinit var clientRepositoryImp: ClientRepository + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + clientRepositoryImp = ClientRepositoryImp(preferencesHelper) + } + + @Test + fun test() { + val mockPassword = "testPassword" + val mockUsername = "testUsername" + Mockito.`when`(preferencesHelper.userName).thenReturn(mockUsername) + + Mockito.`when`(preferencesHelper.baseUrl) + .thenReturn(BaseURL.PROTOCOL_HTTPS + BaseURL.API_ENDPOINT) + + clientRepositoryImp.updateAuthenticationToken(mockPassword) + val authenticationToken = Credentials.basic(preferencesHelper.userName!!, mockPassword) + + Mockito.verify(preferencesHelper).saveToken(authenticationToken) + } +} \ No newline at end of file From 23ff33738f210a46530acd5fe889252e70f6282e Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Sun, 16 Jul 2023 20:03:22 +0530 Subject: [PATCH 13/14] feat : udpatePassword mvvm migration -> renamed UiState to RegistrationUiState --- .../mobile/ui/fragments/RegistrationFragment.kt | 8 ++++---- .../ui/fragments/UpdatePasswordFragment.kt | 8 ++++---- .../mifos/mobile/utils/RegistrationUiState.kt | 7 +++++++ .../main/java/org/mifos/mobile/utils/UiState.kt | 7 ------- .../mobile/viewModels/RegistrationViewModel.kt | 12 ++++++------ .../mobile/viewModels/UpdatePasswordViewModel.kt | 12 ++++++------ .../repositories/ClientRepositoryImpTest.kt | 2 +- .../viewModels/RegistrationViewModelTest.kt | 16 ++++++++-------- .../viewModels/UpdatePasswordViewModelTest.kt | 12 ++++++------ 9 files changed, 42 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/UiState.kt diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt index 76b318e27..19a78ebc6 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt @@ -19,7 +19,7 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.MFErrorParser import org.mifos.mobile.utils.Network import org.mifos.mobile.utils.PasswordStrength -import org.mifos.mobile.utils.UiState +import org.mifos.mobile.utils.RegistrationUiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.RegistrationViewModel @@ -91,14 +91,14 @@ class RegistrationFragment : BaseFragment() { viewModel.registrationUiState.observe(viewLifecycleOwner) { state -> when (state) { - UiState.Loading -> showProgress() + RegistrationUiState.Loading -> showProgress() - UiState.Success -> { + RegistrationUiState.Success -> { hideProgress() showRegisteredSuccessfully() } - is UiState.Error -> { + is RegistrationUiState.Error -> { hideProgress() showError(MFErrorParser.errorMessage(state.exception)) } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt index 3443d60a7..f1145f3a9 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt @@ -17,7 +17,7 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.MFErrorParser import org.mifos.mobile.utils.Network import org.mifos.mobile.utils.Toaster -import org.mifos.mobile.utils.UiState +import org.mifos.mobile.utils.RegistrationUiState import org.mifos.mobile.viewModels.UpdatePasswordViewModel /* @@ -55,13 +55,13 @@ class UpdatePasswordFragment : BaseFragment(), TextWatcher, OnFocusChangeListene viewModel.updatePasswordUiState.observe(viewLifecycleOwner) { state -> when (state) { - UiState.Loading -> showProgress() - UiState.Success -> { + RegistrationUiState.Loading -> showProgress() + RegistrationUiState.Success -> { hideProgress() showPasswordUpdatedSuccessfully() } - is UiState.Error -> { + is RegistrationUiState.Error -> { hideProgress() showError(MFErrorParser.errorMessage(state.exception)) } diff --git a/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt b/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt new file mode 100644 index 000000000..a946db0b5 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt @@ -0,0 +1,7 @@ +package org.mifos.mobile.utils + +sealed class RegistrationUiState { + data class Error(val exception: Throwable) : RegistrationUiState() + object Success : RegistrationUiState() + object Loading : RegistrationUiState() +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/utils/UiState.kt b/app/src/main/java/org/mifos/mobile/utils/UiState.kt deleted file mode 100644 index 5180a9059..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/UiState.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.mifos.mobile.utils - -sealed class UiState { - data class Error(val exception: Throwable) : UiState() - object Success : UiState() - object Loading : UiState() -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt index 2420a4c97..fd2a1b1dd 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt @@ -11,7 +11,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.repositories.UserAuthRepository -import org.mifos.mobile.utils.UiState +import org.mifos.mobile.utils.RegistrationUiState import javax.inject.Inject @HiltViewModel @@ -19,8 +19,8 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm ViewModel() { private val compositeDisposables: CompositeDisposable = CompositeDisposable() - private val _registrationUiState = MutableLiveData() - val registrationUiState: LiveData get() = _registrationUiState + private val _registrationUiState = MutableLiveData() + val registrationUiState: LiveData get() = _registrationUiState fun isInputFieldBlank(fieldText: String): Boolean { return fieldText.trim().isEmpty() @@ -52,7 +52,7 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm password: String, username: String ) { - _registrationUiState.value = UiState.Loading + _registrationUiState.value = RegistrationUiState.Loading userAuthRepositoryImp.registerUser( accountNumber, authenticationMode, @@ -66,11 +66,11 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm ?.subscribeWith(object : DisposableObserver() { override fun onComplete() {} override fun onError(e: Throwable) { - _registrationUiState.value = UiState.Error(e) + _registrationUiState.value = RegistrationUiState.Error(e) } override fun onNext(responseBody: ResponseBody) { - _registrationUiState.value = UiState.Success + _registrationUiState.value = RegistrationUiState.Success } })?.let { compositeDisposables.add(it) } } diff --git a/app/src/main/java/org/mifos/mobile/viewModels/UpdatePasswordViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/UpdatePasswordViewModel.kt index 747485278..cf9ae264b 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/UpdatePasswordViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/UpdatePasswordViewModel.kt @@ -11,7 +11,7 @@ import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.repositories.ClientRepository import org.mifos.mobile.repositories.UserAuthRepository -import org.mifos.mobile.utils.UiState +import org.mifos.mobile.utils.RegistrationUiState import javax.inject.Inject @HiltViewModel @@ -21,8 +21,8 @@ class UpdatePasswordViewModel @Inject constructor( ) : ViewModel() { private val compositeDisposable = CompositeDisposable() - private val _updatePasswordUiState = MutableLiveData() - val updatePasswordUiState: LiveData get() = _updatePasswordUiState + private val _updatePasswordUiState = MutableLiveData() + val updatePasswordUiState: LiveData get() = _updatePasswordUiState fun isInputFieldEmpty(fieldText: String): Boolean { return fieldText.isEmpty() } @@ -36,18 +36,18 @@ class UpdatePasswordViewModel @Inject constructor( } fun updateAccountPassword(newPassword: String, confirmPassword: String) { - _updatePasswordUiState.value = UiState.Loading + _updatePasswordUiState.value = RegistrationUiState.Loading userAuthRepositoryImp.updateAccountPassword(newPassword, confirmPassword) ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribeWith(object : DisposableObserver() { override fun onNext(responseBody: ResponseBody) { - _updatePasswordUiState.value = UiState.Success + _updatePasswordUiState.value = RegistrationUiState.Success clientRepositoryImp.updateAuthenticationToken(newPassword) } override fun onError(e: Throwable) { - _updatePasswordUiState.value = UiState.Error(e) + _updatePasswordUiState.value = RegistrationUiState.Error(e) } override fun onComplete() {} diff --git a/app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt b/app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt index 7ded8c55e..ce384c1c4 100644 --- a/app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt +++ b/app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt @@ -26,7 +26,7 @@ class ClientRepositoryImpTest { } @Test - fun test() { + fun testUpdateAuthenticationToken() { val mockPassword = "testPassword" val mockUsername = "testUsername" Mockito.`when`(preferencesHelper.userName).thenReturn(mockUsername) diff --git a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt index 9c3160bf4..b815f9a3b 100644 --- a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt +++ b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt @@ -12,7 +12,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mifos.mobile.repositories.UserAuthRepositoryImp import org.mifos.mobile.util.RxSchedulersOverrideRule -import org.mifos.mobile.utils.UiState +import org.mifos.mobile.utils.RegistrationUiState import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations @@ -33,7 +33,7 @@ class RegistrationViewModelTest { lateinit var userAuthRepositoryImp: UserAuthRepositoryImp @Mock - lateinit var registrationUiStateObserver: Observer + lateinit var registrationUiStateObserver: Observer private lateinit var registrationViewModel: RegistrationViewModel @@ -70,7 +70,7 @@ class RegistrationViewModelTest { @Test fun testInputHasSpaces_WithSpacesInput_ReturnsTrue() { - val result = registrationViewModel.inputHasSpaces("test string") + val result = registrationViewModel.inputHasSpaces("testUpdateAuthenticationToken string") Assert.assertTrue(result) } @@ -94,7 +94,7 @@ class RegistrationViewModelTest { @Test fun testIsEmailInvalid_WithValidEmailInput_ReturnsFalse() { - val result = registrationViewModel.isEmailInvalid("test@example.com") + val result = registrationViewModel.isEmailInvalid("testUpdateAuthenticationToken@example.com") Assert.assertFalse(result) } @@ -127,8 +127,8 @@ class RegistrationViewModelTest { "userName" ) - Mockito.verify(registrationUiStateObserver).onChanged(UiState.Loading) - Mockito.verify(registrationUiStateObserver).onChanged(UiState.Success) + Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Loading) + Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Success) Mockito.verifyNoMoreInteractions(registrationUiStateObserver) } @@ -159,8 +159,8 @@ class RegistrationViewModelTest { "username" ) - Mockito.verify(registrationUiStateObserver).onChanged(UiState.Loading) - Mockito.verify(registrationUiStateObserver).onChanged(UiState.Error(error)) + Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Loading) + Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Error(error)) Mockito.verifyNoMoreInteractions(registrationUiStateObserver) } diff --git a/app/src/test/java/org/mifos/mobile/viewModels/UpdatePasswordViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/UpdatePasswordViewModelTest.kt index e31fbe326..d1014b4a5 100644 --- a/app/src/test/java/org/mifos/mobile/viewModels/UpdatePasswordViewModelTest.kt +++ b/app/src/test/java/org/mifos/mobile/viewModels/UpdatePasswordViewModelTest.kt @@ -14,7 +14,7 @@ import org.junit.runner.RunWith import org.mifos.mobile.repositories.ClientRepository import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.util.RxSchedulersOverrideRule -import org.mifos.mobile.utils.UiState +import org.mifos.mobile.utils.RegistrationUiState import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations @@ -38,7 +38,7 @@ class UpdatePasswordViewModelTest { lateinit var clientRepositoryImp: ClientRepository @Mock - private lateinit var updatePasswordUiStateObserver: Observer + private lateinit var updatePasswordUiStateObserver: Observer private lateinit var updatePasswordViewModel: UpdatePasswordViewModel @@ -94,8 +94,8 @@ class UpdatePasswordViewModelTest { ).thenReturn(Observable.just(responseBody)) updatePasswordViewModel.updateAccountPassword("newPassword", "newPassword") - Mockito.verify(updatePasswordUiStateObserver).onChanged(UiState.Loading) - Mockito.verify(updatePasswordUiStateObserver).onChanged(UiState.Success) + Mockito.verify(updatePasswordUiStateObserver).onChanged(RegistrationUiState.Loading) + Mockito.verify(updatePasswordUiStateObserver).onChanged(RegistrationUiState.Success) Mockito.verify(clientRepositoryImp).updateAuthenticationToken("newPassword") Mockito.verifyNoMoreInteractions(updatePasswordUiStateObserver) } @@ -109,8 +109,8 @@ class UpdatePasswordViewModelTest { updatePasswordViewModel.updateAccountPassword("newPassword", "newPassword") - Mockito.verify(updatePasswordUiStateObserver).onChanged(UiState.Loading) - Mockito.verify(updatePasswordUiStateObserver).onChanged(UiState.Error(error)) + Mockito.verify(updatePasswordUiStateObserver).onChanged(RegistrationUiState.Loading) + Mockito.verify(updatePasswordUiStateObserver).onChanged(RegistrationUiState.Error(error)) Mockito.verifyNoMoreInteractions(updatePasswordUiStateObserver) } From 4bb68387ee52fb48a8ff248402aec5c2936e8ab2 Mon Sep 17 00:00:00 2001 From: gururani-abhishek Date: Mon, 17 Jul 2023 17:14:25 +0530 Subject: [PATCH 14/14] feat : registration verification mvvm migration -> deleted extra RegistrationVerificationUiState and used RegistrationUiState instead. --- .../ui/fragments/RegistrationVerificationFragment.kt | 8 ++++---- .../mobile/utils/RegistrationVerificationUiState.kt | 8 -------- .../mifos/mobile/viewModels/RegistrationViewModel.kt | 11 +++++------ .../mobile/viewModels/RegistrationViewModelTest.kt | 11 +++++------ 4 files changed, 14 insertions(+), 24 deletions(-) delete mode 100644 app/src/main/java/org/mifos/mobile/utils/RegistrationVerificationUiState.kt diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt index c45b2dbe2..7b793d8fd 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt @@ -13,7 +13,7 @@ import org.mifos.mobile.databinding.FragmentRegistrationVerificationBinding import org.mifos.mobile.ui.activities.LoginActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.MFErrorParser -import org.mifos.mobile.utils.RegistrationVerificationUiState +import org.mifos.mobile.utils.RegistrationUiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.RegistrationViewModel @@ -42,14 +42,14 @@ class RegistrationVerificationFragment : BaseFragment() { viewModel.registrationVerificationUiState.observe(viewLifecycleOwner) { state -> when (state) { - RegistrationVerificationUiState.Loading -> showProgress() + RegistrationUiState.Loading -> showProgress() - RegistrationVerificationUiState.RegistrationVerificationSuccessful -> { + RegistrationUiState.Success -> { hideProgress() showVerifiedSuccessfully() } - is RegistrationVerificationUiState.ErrorOnRegistrationVerification -> { + is RegistrationUiState.Error -> { hideProgress() showError(MFErrorParser.errorMessage(state.exception)) } diff --git a/app/src/main/java/org/mifos/mobile/utils/RegistrationVerificationUiState.kt b/app/src/main/java/org/mifos/mobile/utils/RegistrationVerificationUiState.kt deleted file mode 100644 index 25506244b..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/RegistrationVerificationUiState.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.mifos.mobile.utils - -sealed class RegistrationVerificationUiState { - object Loading : RegistrationVerificationUiState() - object RegistrationVerificationSuccessful : RegistrationVerificationUiState() - data class ErrorOnRegistrationVerification(val exception: Throwable) : - RegistrationVerificationUiState() -} diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt index 9bb2329eb..ecdbd4a93 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt @@ -12,7 +12,6 @@ import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.utils.RegistrationUiState -import org.mifos.mobile.utils.RegistrationVerificationUiState import javax.inject.Inject @HiltViewModel @@ -24,8 +23,8 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm val registrationUiState: LiveData get() = _registrationUiState private val _registrationVerificationUiState = - MutableLiveData() - val registrationVerificationUiState: LiveData get() = _registrationVerificationUiState + MutableLiveData() + val registrationVerificationUiState: LiveData get() = _registrationVerificationUiState fun isInputFieldBlank(fieldText: String): Boolean { return fieldText.trim().isEmpty() @@ -81,19 +80,19 @@ class RegistrationViewModel @Inject constructor(private val userAuthRepositoryIm } fun verifyUser(authenticationToken: String?, requestId: String?) { - _registrationVerificationUiState.value = RegistrationVerificationUiState.Loading + _registrationVerificationUiState.value = RegistrationUiState.Loading userAuthRepositoryImp.verifyUser(authenticationToken, requestId)?.observeOn(AndroidSchedulers.mainThread()) ?.subscribeOn(Schedulers.io()) ?.subscribeWith(object : DisposableObserver() { override fun onComplete() {} override fun onError(e: Throwable) { _registrationVerificationUiState.value = - RegistrationVerificationUiState.ErrorOnRegistrationVerification(e) + RegistrationUiState.Error(e) } override fun onNext(responseBody: ResponseBody) { _registrationVerificationUiState.value = - RegistrationVerificationUiState.RegistrationVerificationSuccessful + RegistrationUiState.Success } })?.let { compositeDisposables.add(it) } } diff --git a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt index b27cc00f1..322322961 100644 --- a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt +++ b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt @@ -13,7 +13,6 @@ import org.junit.runner.RunWith import org.mifos.mobile.repositories.UserAuthRepository import org.mifos.mobile.util.RxSchedulersOverrideRule import org.mifos.mobile.utils.RegistrationUiState -import org.mifos.mobile.utils.RegistrationVerificationUiState import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations @@ -37,7 +36,7 @@ class RegistrationViewModelTest { lateinit var registrationUiStateObserver: Observer @Mock - lateinit var registrationVerificationUiStateObserver: Observer + lateinit var registrationVerificationUiStateObserver: Observer private lateinit var registrationViewModel: RegistrationViewModel @@ -180,9 +179,9 @@ class RegistrationViewModelTest { registrationViewModel.verifyUser("authenticationToken", "requestId") Mockito.verify(registrationVerificationUiStateObserver) - .onChanged(RegistrationVerificationUiState.Loading) + .onChanged(RegistrationUiState.Loading) Mockito.verify(registrationVerificationUiStateObserver) - .onChanged(RegistrationVerificationUiState.RegistrationVerificationSuccessful) + .onChanged(RegistrationUiState.Success) Mockito.verifyNoMoreInteractions(registrationUiStateObserver) } @@ -196,9 +195,9 @@ class RegistrationViewModelTest { registrationViewModel.verifyUser("authenticationToken", "requestId") Mockito.verify(registrationVerificationUiStateObserver) - .onChanged(RegistrationVerificationUiState.Loading) + .onChanged(RegistrationUiState.Loading) Mockito.verify(registrationVerificationUiStateObserver) - .onChanged(RegistrationVerificationUiState.ErrorOnRegistrationVerification(error)) + .onChanged(RegistrationUiState.Error(error)) Mockito.verifyNoMoreInteractions(registrationUiStateObserver) }