diff --git a/app/build.gradle b/app/build.gradle index d808e8ae6..d76f90fcf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,6 +4,7 @@ apply plugin: 'com.google.android.gms.oss-licenses-plugin' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' +apply plugin: 'com.google.dagger.hilt.android' apply from: '../config/quality/quality.gradle' @@ -80,6 +81,10 @@ android { buildFeatures { viewBinding = true } + + kapt { + correctErrorTypes = true + } } dependencies { @@ -154,14 +159,19 @@ dependencies { //Biometric Authentication implementation "androidx.biometric:biometric:$rootProject.biometric" - // Unit tests dependencies + // Coroutines + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$rootProject.coroutines" + + // Unit tests dependencies testImplementation "junit:junit:$rootProject.jUnitVersion" testImplementation "org.mockito:mockito-core:$rootProject.mockitoVersion" - + implementation "org.mockito:mockito-core:$rootProject.mockitoVersion" + implementation "org.mockito:mockito-android:$rootProject.mockitoVersion" androidTestImplementation "junit:junit:$rootProject.jUnitVersion" androidTestImplementation "org.mockito:mockito-core:$rootProject.mockitoVersion" androidTestImplementation "org.mockito:mockito-android:$rootProject.mockitoVersion" androidTestImplementation "androidx.annotation:annotation:1.0.0" + implementation "androidx.arch.core:core-testing:$rootProject.archCoreVersion" androidTestImplementation("androidx.test.espresso:espresso-contrib:$rootProject.espressoVersion") { exclude group: 'com.android.support', module: 'appcompat' exclude group: 'com.android.support', module: 'support-v4' @@ -176,5 +186,9 @@ dependencies { implementation 'com.github.rahul-gill.mifos-ui-library:uihouse:alpha-2.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' + // Hilt + implementation("com.google.dagger:hilt-android:2.44") + kapt("com.google.dagger:hilt-android-compiler:2.44") + } apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/java/org/mifos/mobile/MifosSelfServiceApp.kt b/app/src/main/java/org/mifos/mobile/MifosSelfServiceApp.kt index b6f1e6168..602999043 100644 --- a/app/src/main/java/org/mifos/mobile/MifosSelfServiceApp.kt +++ b/app/src/main/java/org/mifos/mobile/MifosSelfServiceApp.kt @@ -8,10 +8,8 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics import com.mifos.mobile.passcode.utils.ForegroundChecker import com.raizlabs.android.dbflow.config.FlowConfig import com.raizlabs.android.dbflow.config.FlowManager +import dagger.hilt.android.HiltAndroidApp import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.component.ApplicationComponent -import org.mifos.mobile.injection.component.DaggerApplicationComponent -import org.mifos.mobile.injection.module.ApplicationModule import org.mifos.mobile.ui.fragments.applySavedTheme import org.mifos.mobile.utils.LanguageHelper.onAttach import java.util.Locale @@ -20,8 +18,8 @@ import java.util.Locale * @author ishan * @since 08/07/16 */ +@HiltAndroidApp class MifosSelfServiceApp : MultiDexApplication() { - private var applicationComponent: ApplicationComponent? = null companion object { private var instance: MifosSelfServiceApp? = null @@ -50,18 +48,4 @@ class MifosSelfServiceApp : MultiDexApplication() { override fun attachBaseContext(base: Context) { super.attachBaseContext(onAttach(base, Locale.getDefault().language)) } - - fun component(): ApplicationComponent? { - if (applicationComponent == null) { - applicationComponent = DaggerApplicationComponent.builder() - .applicationModule(ApplicationModule(this)) - .build() - } - return applicationComponent - } - - // Needed to replace the component with a test specific one - fun setComponent(applicationComponent: ApplicationComponent?) { - this.applicationComponent = applicationComponent - } } diff --git a/app/src/main/java/org/mifos/mobile/api/local/PreferencesHelper.kt b/app/src/main/java/org/mifos/mobile/api/local/PreferencesHelper.kt index 6bcc8d43d..5d383afcb 100644 --- a/app/src/main/java/org/mifos/mobile/api/local/PreferencesHelper.kt +++ b/app/src/main/java/org/mifos/mobile/api/local/PreferencesHelper.kt @@ -4,9 +4,9 @@ import android.content.Context import android.content.SharedPreferences import android.preference.PreferenceManager import android.text.TextUtils +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.api.BaseURL import org.mifos.mobile.api.SelfServiceInterceptor -import org.mifos.mobile.injection.ApplicationContext import org.mifos.mobile.ui.fragments.AppTheme import javax.inject.Inject import javax.inject.Singleton diff --git a/app/src/main/java/org/mifos/mobile/injection/ActivityContext.kt b/app/src/main/java/org/mifos/mobile/injection/ActivityContext.kt deleted file mode 100644 index d03aab08a..000000000 --- a/app/src/main/java/org/mifos/mobile/injection/ActivityContext.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.mifos.mobile.injection - -import javax.inject.Qualifier - -/** - * @author ishan - * @since 08/07/16 - */ -@Qualifier -@Retention(AnnotationRetention.RUNTIME) -annotation class ActivityContext diff --git a/app/src/main/java/org/mifos/mobile/injection/ApplicationContext.kt b/app/src/main/java/org/mifos/mobile/injection/ApplicationContext.kt deleted file mode 100644 index 79248bd6d..000000000 --- a/app/src/main/java/org/mifos/mobile/injection/ApplicationContext.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.mifos.mobile.injection - -import javax.inject.Qualifier - -/** - * @author ishan - * @since 08/07/16 - */ -@Qualifier -@Retention(AnnotationRetention.RUNTIME) -annotation class ApplicationContext diff --git a/app/src/main/java/org/mifos/mobile/injection/component/ActivityComponent.kt b/app/src/main/java/org/mifos/mobile/injection/component/ActivityComponent.kt deleted file mode 100644 index 5fb96e011..000000000 --- a/app/src/main/java/org/mifos/mobile/injection/component/ActivityComponent.kt +++ /dev/null @@ -1,94 +0,0 @@ -package org.mifos.mobile.injection.component - -import dagger.Component -import org.mifos.mobile.injection.PerActivity -import org.mifos.mobile.injection.module.ActivityModule -import org.mifos.mobile.ui.activities.HomeActivity -import org.mifos.mobile.ui.activities.LoginActivity -import org.mifos.mobile.ui.activities.PassCodeActivity -import org.mifos.mobile.ui.activities.SplashActivity -import org.mifos.mobile.ui.fragments.AccountOverviewFragment -import org.mifos.mobile.ui.fragments.AccountsFragment -import org.mifos.mobile.ui.fragments.AddGuarantorFragment -import org.mifos.mobile.ui.fragments.BeneficiaryAddOptionsFragment -import org.mifos.mobile.ui.fragments.BeneficiaryApplicationFragment -import org.mifos.mobile.ui.fragments.BeneficiaryDetailFragment -import org.mifos.mobile.ui.fragments.BeneficiaryListFragment -import org.mifos.mobile.ui.fragments.ClientAccountsFragment -import org.mifos.mobile.ui.fragments.ClientChargeFragment -import org.mifos.mobile.ui.fragments.GuarantorDetailFragment -import org.mifos.mobile.ui.fragments.GuarantorListFragment -import org.mifos.mobile.ui.fragments.HelpFragment -import org.mifos.mobile.ui.fragments.HomeFragment -import org.mifos.mobile.ui.fragments.HomeOldFragment -import org.mifos.mobile.ui.fragments.LoanAccountSummaryFragment -import org.mifos.mobile.ui.fragments.LoanAccountTransactionFragment -import org.mifos.mobile.ui.fragments.LoanAccountWithdrawFragment -import org.mifos.mobile.ui.fragments.LoanAccountsDetailFragment -import org.mifos.mobile.ui.fragments.LoanApplicationFragment -import org.mifos.mobile.ui.fragments.LoanRepaymentScheduleFragment -import org.mifos.mobile.ui.fragments.NotificationFragment -import org.mifos.mobile.ui.fragments.QrCodeImportFragment -import org.mifos.mobile.ui.fragments.QrCodeReaderFragment -import org.mifos.mobile.ui.fragments.RecentTransactionsFragment -import org.mifos.mobile.ui.fragments.RegistrationFragment -import org.mifos.mobile.ui.fragments.RegistrationVerificationFragment -import org.mifos.mobile.ui.fragments.ReviewLoanApplicationFragment -import org.mifos.mobile.ui.fragments.SavingAccountsDetailFragment -import org.mifos.mobile.ui.fragments.SavingAccountsTransactionFragment -import org.mifos.mobile.ui.fragments.SavingsAccountApplicationFragment -import org.mifos.mobile.ui.fragments.SavingsAccountWithdrawFragment -import org.mifos.mobile.ui.fragments.SavingsMakeTransferFragment -import org.mifos.mobile.ui.fragments.ThirdPartyTransferFragment -import org.mifos.mobile.ui.fragments.TransferProcessFragment -import org.mifos.mobile.ui.fragments.UpdatePasswordFragment -import org.mifos.mobile.ui.fragments.UserProfileFragment - -/** - * @author ishan - * @since 08/07/16 - */ -@PerActivity -@Component(dependencies = [ApplicationComponent::class], modules = [ActivityModule::class]) -interface ActivityComponent { - fun inject(loginActivity: LoginActivity?) - fun inject(homeActivity: HomeActivity?) - fun inject(passCodeActivity: PassCodeActivity?) - fun inject(homeFragment: HomeFragment?) - fun inject(clientAccountsFragment: ClientAccountsFragment?) - fun inject(recentTransactionsFragment: RecentTransactionsFragment?) - fun inject(clientChargeFragment: ClientChargeFragment?) - fun inject(savingAccountsDetailActivity: SavingAccountsDetailFragment?) - fun inject(loanAccountsDetailActivity: LoanAccountsDetailFragment?) - fun inject(accountsFragment: AccountsFragment?) - fun inject(loanAccountSummaryFragment: LoanAccountSummaryFragment?) - fun inject(loanAccountTransactionFragment: LoanAccountTransactionFragment?) - fun inject(loanRepaymentScheduleFragment: LoanRepaymentScheduleFragment?) - fun inject(loanApplicationFragment: LoanApplicationFragment?) - fun inject(loanAccountWithdrawFragment: LoanAccountWithdrawFragment?) - fun inject(savingAccountsTransactionFragment: SavingAccountsTransactionFragment?) - fun inject(savingsMakeTransferFragment: SavingsMakeTransferFragment?) - fun inject(beneficiaryAddOptionsFragment: BeneficiaryAddOptionsFragment?) - fun inject(beneficiaryListFragment: BeneficiaryListFragment?) - fun inject(beneficiaryApplicationFragment: BeneficiaryApplicationFragment?) - fun inject(beneficiaryDetailFragment: BeneficiaryDetailFragment?) - fun inject(thirdPartyTransferFragment: ThirdPartyTransferFragment?) - fun inject(transferProcessFragment: TransferProcessFragment?) - fun inject(userProfileFragment: UserProfileFragment?) - fun inject(helpFragment: HelpFragment?) - fun inject(registrationFragment: RegistrationFragment?) - fun inject(registrationVerificationFragment: RegistrationVerificationFragment?) - fun inject(accountOverviewFragment: AccountOverviewFragment?) - fun inject(homeOldFragment: HomeOldFragment?) - fun inject(notificationFragment: NotificationFragment?) - fun inject(qrCodeImportFragment: QrCodeImportFragment?) - fun inject(splashActivity: SplashActivity?) - fun inject(addGuarantorFragment: AddGuarantorFragment?) - fun inject(guarantorListFragment: GuarantorListFragment?) - fun inject(guarantorDetailFragment: GuarantorDetailFragment?) - fun inject(updatePasswordFragment: UpdatePasswordFragment?) - fun inject(savingsAccountApplicationFragment: SavingsAccountApplicationFragment?) - fun inject(savingsAccountWithdrawFragment: SavingsAccountWithdrawFragment?) - fun inject(reviewLoanApplicationFragment: ReviewLoanApplicationFragment?) - fun inject(qrCodeReaderFragment: QrCodeReaderFragment?) -} diff --git a/app/src/main/java/org/mifos/mobile/injection/component/ApplicationComponent.kt b/app/src/main/java/org/mifos/mobile/injection/component/ApplicationComponent.kt deleted file mode 100644 index b6982275c..000000000 --- a/app/src/main/java/org/mifos/mobile/injection/component/ApplicationComponent.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.mifos.mobile.injection.component - -import android.app.Application -import android.content.Context -import dagger.Component -import org.mifos.mobile.api.BaseApiManager -import org.mifos.mobile.api.DataManager -import org.mifos.mobile.api.local.DatabaseHelper -import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.ApplicationContext -import org.mifos.mobile.injection.module.ApplicationModule -import javax.inject.Singleton - -/** - * @author ishan - * @since 08/07/16 - */ -@Singleton -@Component(modules = [ApplicationModule::class]) -interface ApplicationComponent { - @ApplicationContext - fun context(): Context? - fun application(): Application? - fun dataManager(): DataManager? - fun prefManager(): PreferencesHelper? - fun baseApiManager(): BaseApiManager? - fun databaseHelper(): DatabaseHelper? -} diff --git a/app/src/main/java/org/mifos/mobile/injection/module/ActivityModule.kt b/app/src/main/java/org/mifos/mobile/injection/module/ActivityModule.kt deleted file mode 100644 index 9d574c14e..000000000 --- a/app/src/main/java/org/mifos/mobile/injection/module/ActivityModule.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.mifos.mobile.injection.module - -import android.app.Activity -import android.content.Context -import dagger.Module -import dagger.Provides -import org.mifos.mobile.injection.ActivityContext - -/** - * @author ishan - * @since 08/07/16 - */ -@Module -class ActivityModule(private val activity: Activity) { - @Provides - fun providesActivity(): Activity { - return activity - } - - @Provides - @ActivityContext - fun providesContext(): Context { - return activity - } -} diff --git a/app/src/main/java/org/mifos/mobile/injection/module/ApplicationModule.kt b/app/src/main/java/org/mifos/mobile/injection/module/ApplicationModule.kt index 97099e825..0674fa0bd 100644 --- a/app/src/main/java/org/mifos/mobile/injection/module/ApplicationModule.kt +++ b/app/src/main/java/org/mifos/mobile/injection/module/ApplicationModule.kt @@ -1,12 +1,15 @@ package org.mifos.mobile.injection.module -import android.app.Application import android.content.Context import dagger.Module import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent import org.mifos.mobile.api.BaseApiManager +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.api.local.DatabaseHelper import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.ApplicationContext import javax.inject.Singleton /** @@ -14,17 +17,8 @@ import javax.inject.Singleton * @since 08/07/16 */ @Module -class ApplicationModule(private val application: Application) { - @Provides - fun provideApplication(): Application { - return application - } - - @Provides - @ApplicationContext - fun provideContext(): Context { - return application - } +@InstallIn(SingletonComponent::class) +class ApplicationModule() { @Provides @Singleton @@ -37,4 +31,10 @@ class ApplicationModule(private val application: Application) { fun provideBaseApiManager(preferencesHelper: PreferencesHelper?): BaseApiManager { return BaseApiManager(preferencesHelper!!) } + + @Provides + @Singleton + fun providesDataManager(preferencesHelper: PreferencesHelper?, baseApiManager: BaseApiManager?, databaseHelper: DatabaseHelper): DataManager { + return DataManager(preferencesHelper!!, baseApiManager!!, databaseHelper!!) + } } 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 new file mode 100644 index 000000000..87715c069 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/injection/module/RepositoryModule.kt @@ -0,0 +1,50 @@ +package org.mifos.mobile.injection.module + +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.LoanRepository +import org.mifos.mobile.repositories.LoanRepositoryImp +import org.mifos.mobile.repositories.NotificationRepository +import org.mifos.mobile.api.local.PreferencesHelper +import org.mifos.mobile.repositories.ClientRepository +import org.mifos.mobile.repositories.ClientRepositoryImp +import org.mifos.mobile.repositories.RecentTransactionRepository +import org.mifos.mobile.repositories.RecentTransactionRepositoryImp +import org.mifos.mobile.repositories.UserAuthRepository +import org.mifos.mobile.repositories.UserAuthRepositoryImp + +@Module +@InstallIn(SingletonComponent::class) +class RepositoryModule { + + @Provides + fun providesUserAuthRepository(dataManager: DataManager): UserAuthRepository { + return UserAuthRepositoryImp(dataManager) + } + + @Provides + fun providesLoanRepository(dataManager: DataManager): LoanRepository { + return LoanRepositoryImp(dataManager) + } + + @Provides + fun providesNotificationRepository(dataManager: DataManager) : NotificationRepository { + return NotificationRepositoryImp(dataManager) + } + + @Provides + fun providesClientRepository( + dataManager: DataManager, preferencesHelper: PreferencesHelper + ): ClientRepository { + return ClientRepositoryImp(dataManager, preferencesHelper) + } + + @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/presenters/AccountOverviewPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/AccountOverviewPresenter.kt index 8a98dde09..642c33068 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/AccountOverviewPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/AccountOverviewPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.accounts.loan.LoanAccount import org.mifos.mobile.models.accounts.savings.SavingAccount import org.mifos.mobile.models.client.ClientAccounts diff --git a/app/src/main/java/org/mifos/mobile/presenters/AccountsPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/AccountsPresenter.kt index 84c559c55..e625d7ae9 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/AccountsPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/AccountsPresenter.kt @@ -9,7 +9,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.CheckboxStatus import org.mifos.mobile.models.accounts.loan.LoanAccount import org.mifos.mobile.models.accounts.savings.SavingAccount diff --git a/app/src/main/java/org/mifos/mobile/presenters/AddGuarantorPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/AddGuarantorPresenter.kt index 0ca554a72..27b4d6689 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/AddGuarantorPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/AddGuarantorPresenter.kt @@ -8,7 +8,9 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ActivityContext +import dagger.hilt.android.qualifiers.ActivityContext + + import org.mifos.mobile.models.guarantor.GuarantorApplicationPayload import org.mifos.mobile.models.guarantor.GuarantorTemplatePayload import org.mifos.mobile.presenters.base.BasePresenter diff --git a/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryApplicationPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryApplicationPresenter.kt index af026c36c..b87bd3694 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryApplicationPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryApplicationPresenter.kt @@ -9,7 +9,7 @@ import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.beneficiary.BeneficiaryPayload import org.mifos.mobile.models.beneficiary.BeneficiaryUpdatePayload import org.mifos.mobile.models.templates.beneficiary.BeneficiaryTemplate diff --git a/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryDetailPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryDetailPresenter.kt index fcd1f3237..bfd1e9545 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryDetailPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryDetailPresenter.kt @@ -8,7 +8,7 @@ import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.BeneficiaryDetailView import javax.inject.Inject diff --git a/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryListPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryListPresenter.kt index e68135957..c84a8771e 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryListPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/BeneficiaryListPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.beneficiary.Beneficiary import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.BeneficiariesView diff --git a/app/src/main/java/org/mifos/mobile/presenters/ClientChargePresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/ClientChargePresenter.kt index 7583f30be..f265c424a 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/ClientChargePresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/ClientChargePresenter.kt @@ -7,7 +7,9 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ActivityContext +import dagger.hilt.android.qualifiers.ActivityContext + + import org.mifos.mobile.models.Charge import org.mifos.mobile.models.Page import org.mifos.mobile.presenters.base.BasePresenter diff --git a/app/src/main/java/org/mifos/mobile/presenters/GuarantorDetailPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/GuarantorDetailPresenter.kt index c32389e6d..127cab091 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/GuarantorDetailPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/GuarantorDetailPresenter.kt @@ -8,7 +8,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.GuarantorDetailView import java.io.IOException diff --git a/app/src/main/java/org/mifos/mobile/presenters/GuarantorListPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/GuarantorListPresenter.kt index fd0c8f305..eabf305c8 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/GuarantorListPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/GuarantorListPresenter.kt @@ -6,7 +6,7 @@ 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.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.guarantor.GuarantorPayload import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.GuarantorListView diff --git a/app/src/main/java/org/mifos/mobile/presenters/HelpPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/HelpPresenter.kt index 862899aff..2276b253d 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/HelpPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/HelpPresenter.kt @@ -2,7 +2,7 @@ package org.mifos.mobile.presenters import android.content.Context import org.mifos.mobile.R -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.FAQ import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.HelpView diff --git a/app/src/main/java/org/mifos/mobile/presenters/HomeOldPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/HomeOldPresenter.kt index a68b56635..4d1af7355 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/HomeOldPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/HomeOldPresenter.kt @@ -4,6 +4,9 @@ import android.content.Context import android.graphics.Bitmap import android.util.Base64 import android.util.Log +import dagger.hilt.android.AndroidEntryPoint +import dagger.hilt.android.qualifiers.ActivityContext +import dagger.hilt.android.qualifiers.ApplicationContext import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.observers.DisposableObserver @@ -12,7 +15,6 @@ import okhttp3.ResponseBody import org.mifos.mobile.R import org.mifos.mobile.api.DataManager import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.ActivityContext import org.mifos.mobile.models.accounts.loan.LoanAccount import org.mifos.mobile.models.accounts.savings.SavingAccount import org.mifos.mobile.models.client.Client diff --git a/app/src/main/java/org/mifos/mobile/presenters/HomePresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/HomePresenter.kt index e5b40d709..1e9425f40 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/HomePresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/HomePresenter.kt @@ -12,7 +12,7 @@ import okhttp3.ResponseBody import org.mifos.mobile.R import org.mifos.mobile.api.DataManager import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.client.Client import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.HomeView diff --git a/app/src/main/java/org/mifos/mobile/presenters/LoanAccountWithdrawPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/LoanAccountWithdrawPresenter.kt index 8b71ea4ad..47684caca 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/LoanAccountWithdrawPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/LoanAccountWithdrawPresenter.kt @@ -8,7 +8,7 @@ import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.accounts.loan.LoanWithdraw import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.LoanAccountWithdrawView diff --git a/app/src/main/java/org/mifos/mobile/presenters/LoanAccountsDetailPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/LoanAccountsDetailPresenter.kt index e0716f4d0..d1908111a 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/LoanAccountsDetailPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/LoanAccountsDetailPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.accounts.loan.LoanWithAssociations import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.LoanAccountsDetailView diff --git a/app/src/main/java/org/mifos/mobile/presenters/LoanAccountsTransactionPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/LoanAccountsTransactionPresenter.kt index f2fa0f163..489b3ba52 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/LoanAccountsTransactionPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/LoanAccountsTransactionPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.accounts.loan.LoanWithAssociations import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.LoanAccountsTransactionView diff --git a/app/src/main/java/org/mifos/mobile/presenters/LoanApplicationPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/LoanApplicationPresenter.kt index 48aba11bd..0c2baf4c1 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/LoanApplicationPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/LoanApplicationPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.templates.loans.LoanTemplate import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.enums.LoanState diff --git a/app/src/main/java/org/mifos/mobile/presenters/LoanRepaymentSchedulePresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/LoanRepaymentSchedulePresenter.kt index 84c7693db..8f33c4fe9 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/LoanRepaymentSchedulePresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/LoanRepaymentSchedulePresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.accounts.loan.LoanWithAssociations import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.LoanRepaymentScheduleMvpView diff --git a/app/src/main/java/org/mifos/mobile/presenters/LoginPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/LoginPresenter.kt index 2fc997225..eddd5f085 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/LoginPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/LoginPresenter.kt @@ -10,7 +10,7 @@ import org.mifos.mobile.R import org.mifos.mobile.api.BaseApiManager import org.mifos.mobile.api.DataManager import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.Page import org.mifos.mobile.models.User import org.mifos.mobile.models.client.Client diff --git a/app/src/main/java/org/mifos/mobile/presenters/NotificationPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/NotificationPresenter.kt index 361dc62ca..b59e8c33e 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/NotificationPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/NotificationPresenter.kt @@ -1,13 +1,16 @@ package org.mifos.mobile.presenters import android.content.Context +import dagger.hilt.android.qualifiers.ApplicationContext 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.api.DataManager -import org.mifos.mobile.injection.ActivityContext +import dagger.hilt.android.qualifiers.ActivityContext + + import org.mifos.mobile.models.notification.MifosNotification import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.NotificationView @@ -18,7 +21,7 @@ import javax.inject.Inject */ class NotificationPresenter @Inject constructor( private val manager: DataManager?, - @ActivityContext context: Context?, + @ApplicationContext context: Context?, ) : BasePresenter(context) { diff --git a/app/src/main/java/org/mifos/mobile/presenters/QrCodeImportPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/QrCodeImportPresenter.kt index 733452867..840a9e58a 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/QrCodeImportPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/QrCodeImportPresenter.kt @@ -16,7 +16,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.QrCodeImportView import java.util.EnumMap diff --git a/app/src/main/java/org/mifos/mobile/presenters/RecentTransactionsPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/RecentTransactionsPresenter.kt index 7e1be07d5..f4b8d86d6 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/RecentTransactionsPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/RecentTransactionsPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.Page import org.mifos.mobile.models.Transaction import org.mifos.mobile.presenters.base.BasePresenter diff --git a/app/src/main/java/org/mifos/mobile/presenters/RegistrationPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/RegistrationPresenter.kt index 3f56ba955..b383c9340 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/RegistrationPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/RegistrationPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.register.RegisterPayload import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.RegistrationView diff --git a/app/src/main/java/org/mifos/mobile/presenters/RegistrationVerificationPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/RegistrationVerificationPresenter.kt index 0f461a199..c07e3f2f9 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/RegistrationVerificationPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/RegistrationVerificationPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.register.UserVerify import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.RegistrationVerificationView diff --git a/app/src/main/java/org/mifos/mobile/presenters/SavingAccountsDetailPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/SavingAccountsDetailPresenter.kt index 7b32314a2..057db9086 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/SavingAccountsDetailPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/SavingAccountsDetailPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.SavingAccountsDetailView diff --git a/app/src/main/java/org/mifos/mobile/presenters/SavingAccountsTransactionPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/SavingAccountsTransactionPresenter.kt index ef5d4b9ad..b74f6b4fe 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/SavingAccountsTransactionPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/SavingAccountsTransactionPresenter.kt @@ -9,7 +9,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.CheckboxStatus import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations import org.mifos.mobile.models.accounts.savings.Transactions diff --git a/app/src/main/java/org/mifos/mobile/presenters/SavingsAccountApplicationPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/SavingsAccountApplicationPresenter.kt index 94bc32997..9ab616b3e 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/SavingsAccountApplicationPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/SavingsAccountApplicationPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.accounts.savings.SavingsAccountApplicationPayload import org.mifos.mobile.models.accounts.savings.SavingsAccountUpdatePayload import org.mifos.mobile.models.templates.savings.SavingsAccountTemplate diff --git a/app/src/main/java/org/mifos/mobile/presenters/SavingsAccountWithdrawPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/SavingsAccountWithdrawPresenter.kt index 286019e4f..b6e3c2284 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/SavingsAccountWithdrawPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/SavingsAccountWithdrawPresenter.kt @@ -7,7 +7,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.accounts.savings.SavingsAccountWithdrawPayload import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.SavingsAccountWithdrawView diff --git a/app/src/main/java/org/mifos/mobile/presenters/SavingsMakeTransferPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/SavingsMakeTransferPresenter.kt index 44ce9581c..b1bc608cf 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/SavingsMakeTransferPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/SavingsMakeTransferPresenter.kt @@ -8,7 +8,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.payload.AccountDetail import org.mifos.mobile.models.templates.account.AccountOption import org.mifos.mobile.models.templates.account.AccountOptionsTemplate diff --git a/app/src/main/java/org/mifos/mobile/presenters/ThirdPartyTransferPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/ThirdPartyTransferPresenter.kt index 456bb47f5..7d5505dfc 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/ThirdPartyTransferPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/ThirdPartyTransferPresenter.kt @@ -9,7 +9,7 @@ import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.AccountOptionAndBeneficiary import org.mifos.mobile.models.beneficiary.Beneficiary import org.mifos.mobile.models.beneficiary.BeneficiaryDetail diff --git a/app/src/main/java/org/mifos/mobile/presenters/TransferProcessPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/TransferProcessPresenter.kt index 5afea342e..567a70f67 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/TransferProcessPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/TransferProcessPresenter.kt @@ -8,7 +8,7 @@ import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.mifos.mobile.R import org.mifos.mobile.api.DataManager -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.payload.TransferPayload import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.TransferProcessView diff --git a/app/src/main/java/org/mifos/mobile/presenters/UpdatePasswordPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/UpdatePasswordPresenter.kt index 8181ec15b..4ed099e30 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/UpdatePasswordPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/UpdatePasswordPresenter.kt @@ -10,7 +10,7 @@ import okhttp3.ResponseBody import org.mifos.mobile.api.BaseApiManager.Companion.createService import org.mifos.mobile.api.DataManager import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.UpdatePasswordPayload import org.mifos.mobile.presenters.base.BasePresenter import org.mifos.mobile.ui.views.UpdatePasswordView diff --git a/app/src/main/java/org/mifos/mobile/presenters/UserDetailsPresenter.kt b/app/src/main/java/org/mifos/mobile/presenters/UserDetailsPresenter.kt index fb90d13cc..ec530b608 100644 --- a/app/src/main/java/org/mifos/mobile/presenters/UserDetailsPresenter.kt +++ b/app/src/main/java/org/mifos/mobile/presenters/UserDetailsPresenter.kt @@ -12,7 +12,7 @@ import okhttp3.ResponseBody import org.mifos.mobile.R import org.mifos.mobile.api.DataManager import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.client.Client import org.mifos.mobile.models.notification.NotificationRegisterPayload import org.mifos.mobile.models.notification.NotificationUserDetail 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..24f929046 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/ClientRepository.kt @@ -0,0 +1,21 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.User +import org.mifos.mobile.models.client.Client + +interface ClientRepository { + + fun loadClient() : Observable?>? + + fun saveAuthenticationTokenForSession(user: User) + + fun reInitializeService() + + fun setClientId(clientId: Long?) + + fun clearPrefHelper() + + 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..716f9cf69 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/ClientRepositoryImp.kt @@ -0,0 +1,63 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import okhttp3.Credentials +import org.mifos.mobile.api.BaseApiManager +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.api.local.PreferencesHelper +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.User +import org.mifos.mobile.models.client.Client +import org.mifos.mobile.utils.Constants +import javax.inject.Inject + +class ClientRepositoryImp @Inject constructor( + private val dataManager: DataManager, private val preferencesHelper: PreferencesHelper +) : ClientRepository { + + override fun loadClient(): Observable?>? { + return dataManager.clients + } + + /** + * Save the authentication token from the server and the user ID. + * The authentication token would be used for accessing the authenticated + * APIs. + * + * @param user - The user that is to be saved. + */ + override fun saveAuthenticationTokenForSession(user: User) { + val authToken = Constants.BASIC + user.base64EncodedAuthenticationKey + preferencesHelper.userName = user.username + preferencesHelper.userId = user.userId + preferencesHelper.saveToken(authToken) + reInitializeService() + } + + override fun reInitializeService() { + BaseApiManager.createService( + preferencesHelper.baseUrl, + preferencesHelper.tenant, + preferencesHelper.token, + ) + } + + override fun setClientId(clientId: Long?) { + preferencesHelper.clientId = clientId + dataManager.clientId = clientId + } + + override fun clearPrefHelper() { + preferencesHelper.clear() + } + + 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/LoanRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/LoanRepository.kt new file mode 100644 index 000000000..a56dafa14 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/LoanRepository.kt @@ -0,0 +1,26 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import okhttp3.ResponseBody +import org.mifos.mobile.models.accounts.loan.LoanWithAssociations +import org.mifos.mobile.models.accounts.loan.LoanWithdraw +import org.mifos.mobile.models.templates.loans.LoanTemplate + +interface LoanRepository { + + fun getLoanWithAssociations( + associationType: String?, + loanId: Long? + ): Observable? + + fun withdrawLoanAccount( + loanId: Long?, + loanWithdraw: LoanWithdraw?, + ): Observable? + + fun template(): Observable? + + fun getLoanTemplateByProduct( + productId: Int? + ): Observable? +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/repositories/LoanRepositoryImp.kt b/app/src/main/java/org/mifos/mobile/repositories/LoanRepositoryImp.kt new file mode 100644 index 000000000..24247da37 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/LoanRepositoryImp.kt @@ -0,0 +1,34 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import okhttp3.ResponseBody +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.accounts.loan.LoanWithAssociations +import org.mifos.mobile.models.accounts.loan.LoanWithdraw +import org.mifos.mobile.models.templates.loans.LoanTemplate +import javax.inject.Inject + +class LoanRepositoryImp @Inject constructor(private val dataManager: DataManager) : LoanRepository { + + override fun getLoanWithAssociations( + associationType: String?, + loanId: Long? + ): Observable? { + return dataManager.getLoanWithAssociations(associationType, loanId) + } + + override fun withdrawLoanAccount( + loanId: Long?, + loanWithdraw: LoanWithdraw? + ): Observable? { + return dataManager.withdrawLoanAccount(loanId, loanWithdraw) + } + + override fun template(): Observable? { + return dataManager.loanTemplate + } + + override fun getLoanTemplateByProduct(productId: Int?): Observable? { + return dataManager.getLoanTemplateByProduct(productId) + } +} \ 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..96a4c4f2c --- /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..856f69970 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/NotificationRepositoryImp.kt @@ -0,0 +1,13 @@ +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 @Inject constructor(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/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/repositories/UserAuthRepository.kt b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt new file mode 100644 index 000000000..e0e29d5a1 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepository.kt @@ -0,0 +1,28 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import okhttp3.ResponseBody +import org.mifos.mobile.models.User + +interface UserAuthRepository { + + fun registerUser( + accountNumber: String?, + authenticationMode: String?, + email: String?, + firstName: String?, + lastName: String?, + mobileNumber: String?, + password: String?, + username: String? + ): Observable? + + fun login(username: String, password: String): Observable? + + fun verifyUser(authenticationToken: String?, requestId: 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 new file mode 100644 index 000000000..2438999b2 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/repositories/UserAuthRepositoryImp.kt @@ -0,0 +1,66 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import okhttp3.ResponseBody +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.User +import org.mifos.mobile.models.payload.LoginPayload +import org.mifos.mobile.models.UpdatePasswordPayload +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) : UserAuthRepository { + + override fun registerUser( + accountNumber: String?, + authenticationMode: String?, + email: String?, + firstName: String?, + lastName: String?, + mobileNumber: String?, + password: String?, + username: String? + ): Observable? { + val registerPayload = RegisterPayload().apply { + this.accountNumber = accountNumber + this.authenticationMode = authenticationMode + this.email = email + this.firstName = firstName + this.lastName = lastName + this.mobileNumber = mobileNumber + this.password = password + this.username = username + } + return dataManager.registerUser(registerPayload) + } + + override fun login(username: String, password: String): Observable? { + val loginPayload = LoginPayload().apply { + this.username = username + this.password = password + } + return dataManager.login(loginPayload) + } + + + override fun verifyUser(authenticationToken: String?, requestId: String?): Observable? { + val userVerify = UserVerify().apply { + this.authenticationToken = authenticationToken + this.requestId = requestId + } + return dataManager.verifyUser(userVerify) + } + + 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/activities/HomeActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/HomeActivity.kt index a6d7f72a3..0db7723d4 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/HomeActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/HomeActivity.kt @@ -22,6 +22,7 @@ import com.google.android.gms.common.GoogleApiAvailability import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.imageview.ShapeableImageView import com.google.android.material.navigation.NavigationView +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.databinding.ActivityHomeBinding @@ -51,6 +52,7 @@ import javax.inject.Inject * @author Vishwajeet * @since 14/07/2016 */ +@AndroidEntryPoint class HomeActivity : BaseActivity(), UserDetailsView, @@ -78,7 +80,6 @@ class HomeActivity : public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityHomeBinding.inflate(layoutInflater) - activityComponent?.inject(this) setContentView(binding.root) clientId = preferencesHelper?.clientId setupNavigationBar() diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/LoginActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/LoginActivity.kt index 735436305..82b7b0cb1 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/LoginActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/LoginActivity.kt @@ -6,35 +6,33 @@ import android.view.View import android.view.ViewGroup import android.widget.EditText import android.widget.Toast +import androidx.lifecycle.ViewModelProvider +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.MifosSelfServiceApp.Companion.context import org.mifos.mobile.R import org.mifos.mobile.databinding.ActivityLoginBinding -import org.mifos.mobile.models.payload.LoginPayload -import org.mifos.mobile.presenters.LoginPresenter import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.views.LoginView import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.LoginUiState import org.mifos.mobile.utils.Network import org.mifos.mobile.utils.Toaster -import javax.inject.Inject +import org.mifos.mobile.viewModels.LoginViewModel /** * @author Vishwajeet * @since 05/06/16 */ -class LoginActivity : BaseActivity(), LoginView { - - @JvmField - @Inject - var loginPresenter: LoginPresenter? = null +@AndroidEntryPoint +class LoginActivity : BaseActivity() { private lateinit var binding: ActivityLoginBinding + private lateinit var viewModel: LoginViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityLoginBinding.inflate(layoutInflater) - activityComponent?.inject(this) setContentView(binding.root) - loginPresenter?.attachView(this) + viewModel = ViewModelProvider(this)[LoginViewModel::class.java] dismissSoftKeyboardOnBkgTap(binding.nsvBackground) binding.btnLogin.setOnClickListener { onLoginClicked() @@ -42,18 +40,38 @@ class LoginActivity : BaseActivity(), LoginView { binding.btnRegister.setOnClickListener { onRegisterClicked() } - binding.etUsername.setOnTouchListener { view, event -> + binding.etUsername.setOnTouchListener { view, _ -> onTouch(view) } - binding.etPassword.setOnTouchListener { view, event -> + binding.etPassword.setOnTouchListener { view, _ -> onTouch(view) } + + viewModel.loginUiState.observe(this) { state -> + when (state) { + LoginUiState.Loading -> showProgress() + + LoginUiState.Error -> { + hideProgress() + showMessage(context?.getString(R.string.login_failed)) + } + + LoginUiState.LoginSuccess -> { + onLoginSuccess() + } + + is LoginUiState.LoadClientSuccess -> { + hideProgress() + showPassCodeActivity(state.clientName) + } + } + } } private fun dismissSoftKeyboardOnBkgTap(view: View) { if (view !is EditText) { - view.setOnTouchListener { view, event -> + view.setOnTouchListener { _, _ -> hideKeyboard(this@LoginActivity) false } @@ -66,10 +84,10 @@ class LoginActivity : BaseActivity(), LoginView { } } - fun onTouch(v: View): Boolean { + private fun onTouch(v: View): Boolean { when (v) { - binding.etUsername -> loginPresenter?.mvpView?.clearUsernameError() - binding.etPassword -> loginPresenter?.mvpView?.clearPasswordError() + binding.etUsername -> clearUsernameError() + binding.etPassword -> clearPasswordError() } return false } @@ -77,28 +95,28 @@ class LoginActivity : BaseActivity(), LoginView { /** * Called when Login is user has successfully logged in */ - override fun onLoginSuccess() { - loginPresenter?.loadClient() + private fun onLoginSuccess() { + viewModel.loadClient() } /** * Shows ProgressDialog when called */ - override fun showProgress() { + private fun showProgress() { showProgressDialog(getString(R.string.progress_message_login)) } /** * Hides the progressDialog which is being shown */ - override fun hideProgress() { + private fun hideProgress() { hideProgressDialog() } /** * Starts [PassCodeActivity] */ - override fun showPassCodeActivity(clientName: String?) { + private fun showPassCodeActivity(clientName: String?) { showToast(getString(R.string.toast_welcome, clientName)) startPassCodeActivity() } @@ -108,24 +126,24 @@ class LoginActivity : BaseActivity(), LoginView { * * @param errorMessage Error message that tells the user about the problem. */ - override fun showMessage(errorMessage: String?) { + private fun showMessage(errorMessage: String?) { showToast(errorMessage!!, Toast.LENGTH_LONG) binding.llLogin.visibility = View.VISIBLE } - override fun showUsernameError(error: String?) { + private fun showUsernameError(error: String?) { binding.tilUsername.error = error } - override fun showPasswordError(error: String?) { + private fun showPasswordError(error: String?) { binding.tilPassword.error = error } - override fun clearUsernameError() { + private fun clearUsernameError() { binding.tilUsername.isErrorEnabled = false } - override fun clearPasswordError() { + private fun clearPasswordError() { binding.tilPassword.isErrorEnabled = false } @@ -133,26 +151,89 @@ class LoginActivity : BaseActivity(), LoginView { * Called when Login Button is clicked, used for logging in the user */ - fun onLoginClicked() { + private fun onLoginClicked() { val username = binding.tilUsername.editText?.editableText.toString() val password = binding.tilPassword.editText?.editableText.toString() if (Network.isConnected(this)) { - val payload = LoginPayload() - payload.username = username - payload.password = password - loginPresenter?.login(payload) + if (isCredentialsValid(username, password)) + viewModel.login(username, password) } else { Toaster.show(binding.llLogin, getString(R.string.no_internet_connection)) } } - fun onRegisterClicked() { - startActivity(Intent(this@LoginActivity, RegistrationActivity::class.java)) + private fun isCredentialsValid(username: String, password: String): Boolean { + var credentialValid = true + val resources = context?.resources + when { + viewModel.isFieldEmpty(username) -> { + showUsernameError( + context?.getString( + R.string.error_validation_blank, + context?.getString(R.string.username), + ), + ) + credentialValid = false + } + + viewModel.isUsernameLengthInadequate(username) -> { + showUsernameError( + context?.getString( + R.string.error_validation_minimum_chars, + resources?.getString(R.string.username), + resources?.getInteger(R.integer.username_minimum_length), + ), + ) + credentialValid = false + } + + viewModel.usernameHasSpaces(username) -> { + showUsernameError( + context?.getString( + R.string.error_validation_cannot_contain_spaces, + resources?.getString(R.string.username), + context?.getString(R.string.not_contain_username), + ), + ) + credentialValid = false + } + + else -> { + clearUsernameError() + } + } + + when { + viewModel.isFieldEmpty(password) -> { + showPasswordError( + context?.getString( + R.string.error_validation_blank, + context?.getString(R.string.password), + ), + ) + credentialValid = false + } + + viewModel.isPasswordLengthInadequate(password) -> { + showPasswordError( + context?.getString( + R.string.error_validation_minimum_chars, + resources?.getString(R.string.password), + resources?.getInteger(R.integer.password_minimum_length), + ), + ) + credentialValid = false + } + + else -> { + clearPasswordError() + } + } + return credentialValid } - override fun onDestroy() { - super.onDestroy() - loginPresenter?.detachView() + private fun onRegisterClicked() { + startActivity(Intent(this@LoginActivity, RegistrationActivity::class.java)) } /** diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/SplashActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/SplashActivity.kt index d5143528c..0bae7c94b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/SplashActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/SplashActivity.kt @@ -3,6 +3,7 @@ package org.mifos.mobile.ui.activities import android.content.Intent import android.os.Bundle import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.utils.Constants @@ -16,7 +17,6 @@ class SplashActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { val intent: Intent? super.onCreate(savedInstanceState) - activityComponent?.inject(this) passcodePreferencesHelper = PasscodePreferencesHelper(this) if (passcodePreferencesHelper?.passCode?.isNotEmpty() == true) { intent = Intent(this, PassCodeActivity::class.java) diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/base/BaseActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/base/BaseActivity.kt index d736716a8..3a166f66c 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/base/BaseActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/base/BaseActivity.kt @@ -13,11 +13,8 @@ import androidx.core.view.ViewCompat import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import com.mifos.mobile.passcode.BasePassCodeActivity -import org.mifos.mobile.MifosSelfServiceApp +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R -import org.mifos.mobile.injection.component.ActivityComponent -import org.mifos.mobile.injection.component.DaggerActivityComponent -import org.mifos.mobile.injection.module.ActivityModule import org.mifos.mobile.ui.activities.PassCodeActivity import org.mifos.mobile.ui.views.BaseActivityCallback import org.mifos.mobile.utils.LanguageHelper @@ -26,6 +23,7 @@ import org.mifos.mobile.utils.LanguageHelper * @author ishan * @since 08/07/16 */ +@AndroidEntryPoint @SuppressLint("Registered") open class BaseActivity : BasePassCodeActivity(), BaseActivityCallback { /** @@ -34,21 +32,6 @@ open class BaseActivity : BasePassCodeActivity(), BaseActivityCallback { var toolbar: Toolbar? = null protected set - /** - * Used for dependency injection - * @return [ActivityComponent] which is used for injection - */ - var activityComponent: ActivityComponent? = null - get() { - if (field == null) { - field = DaggerActivityComponent.builder() - .activityModule(ActivityModule(this)) - .applicationComponent(MifosSelfServiceApp.get(this).component()) - .build() - } - return field - } - private set private var progress: ProgressDialog? = null override fun setContentView(layoutResID: Int) { super.setContentView(layoutResID) diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/FAQAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/FAQAdapter.kt index 6047fb849..29c916f77 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/FAQAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/FAQAdapter.kt @@ -8,7 +8,9 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import org.mifos.mobile.R import org.mifos.mobile.databinding.RowFaqBinding -import org.mifos.mobile.injection.ActivityContext +import dagger.hilt.android.qualifiers.ActivityContext + + import org.mifos.mobile.models.FAQ import org.mifos.mobile.utils.FaqDiffUtil import javax.inject.Inject diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/NotificationAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/NotificationAdapter.kt index e7b77bbcf..21e3f39b7 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/NotificationAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/NotificationAdapter.kt @@ -6,9 +6,11 @@ import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView +import dagger.hilt.android.qualifiers.ActivityContext import org.mifos.mobile.R import org.mifos.mobile.databinding.RowNotificationBinding -import org.mifos.mobile.injection.ActivityContext + + import org.mifos.mobile.models.notification.MifosNotification import org.mifos.mobile.ui.getThemeAttributeColor import org.mifos.mobile.utils.DateHelper.getDateAndTimeAsStringFromLong diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/RecentTransactionListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/RecentTransactionListAdapter.kt index c8247c54e..79810406d 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/RecentTransactionListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/RecentTransactionListAdapter.kt @@ -7,7 +7,9 @@ import androidx.recyclerview.widget.RecyclerView import org.mifos.mobile.MifosSelfServiceApp.Companion.context import org.mifos.mobile.R import org.mifos.mobile.databinding.RowRecentTransactionBinding -import org.mifos.mobile.injection.ActivityContext +import dagger.hilt.android.qualifiers.ActivityContext + + import org.mifos.mobile.models.Transaction import org.mifos.mobile.models.client.Type import org.mifos.mobile.utils.CurrencyUtil.formatCurrency diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/AboutUsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/AboutUsFragment.kt index 177825c1d..1e4fcc866 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/AboutUsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/AboutUsFragment.kt @@ -7,6 +7,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.google.android.gms.oss.licenses.OssLicensesMenuActivity +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.BuildConfig import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentAboutUsBinding @@ -18,6 +19,7 @@ import java.util.Calendar ~This project is licensed under the open source MPL V2. ~See https://github.com/openMF/self-service-app/blob/master/LICENSE.md */ +@AndroidEntryPoint class AboutUsFragment : BaseFragment() { private var _binding: FragmentAboutUsBinding? = null private val binding get() = _binding!! diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/AccountOverviewFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/AccountOverviewFragment.kt index 15b7d1384..656e9f1d9 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/AccountOverviewFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/AccountOverviewFragment.kt @@ -8,10 +8,10 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentAccountOverviewBinding import org.mifos.mobile.presenters.AccountOverviewPresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.views.AccountOverviewMvpView import org.mifos.mobile.utils.Constants @@ -24,6 +24,7 @@ import javax.inject.Inject * @author Rajan Maurya * On 16/10/17. */ +@AndroidEntryPoint class AccountOverviewFragment : BaseFragment(), AccountOverviewMvpView, OnRefreshListener { private var _binding: FragmentAccountOverviewBinding? = null @@ -45,7 +46,6 @@ class AccountOverviewFragment : BaseFragment(), AccountOverviewMvpView, OnRefres savedInstanceState: Bundle?, ): View { _binding = FragmentAccountOverviewBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) accountOverviewPresenter?.attachView(this) setToolbarTitle(getString(R.string.accounts_overview)) binding.swipeContainer.setColorSchemeResources( diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt index 1d71d9043..a01c7cbed 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt @@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentAccountsBinding import org.mifos.mobile.models.CheckboxStatus @@ -21,7 +22,6 @@ import org.mifos.mobile.models.accounts.share.ShareAccount import org.mifos.mobile.presenters.AccountsPresenter import org.mifos.mobile.ui.activities.LoanAccountContainerActivity import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.adapters.LoanAccountsListAdapter import org.mifos.mobile.ui.adapters.SavingAccountsListAdapter import org.mifos.mobile.ui.adapters.ShareAccountsListAdapter @@ -37,6 +37,7 @@ import javax.inject.Inject /** * Created by Rajan Maurya on 23/10/16. */ +@AndroidEntryPoint class AccountsFragment : BaseFragment(), OnRefreshListener, AccountsView { private var _binding: FragmentAccountsBinding? = null private val binding get() = _binding!! @@ -76,7 +77,6 @@ class AccountsFragment : BaseFragment(), OnRefreshListener, AccountsView { private var sweetUIErrorHandler: SweetUIErrorHandler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as BaseActivity?)?.activityComponent?.inject(this) loanAccounts = ArrayList() savingAccounts = ArrayList() shareAccounts = ArrayList() diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/AddGuarantorFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/AddGuarantorFragment.kt index 808b90423..10e51467c 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/AddGuarantorFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/AddGuarantorFragment.kt @@ -7,13 +7,13 @@ import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.Toast import com.google.android.material.textfield.MaterialAutoCompleteTextView +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentAddGuarantorBinding import org.mifos.mobile.models.guarantor.GuarantorApplicationPayload import org.mifos.mobile.models.guarantor.GuarantorPayload import org.mifos.mobile.models.guarantor.GuarantorTemplatePayload import org.mifos.mobile.presenters.AddGuarantorPresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.GuarantorState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.views.AddGuarantorView @@ -27,6 +27,7 @@ import javax.inject.Inject /* * Created by saksham on 23/July/2018 */ +@AndroidEntryPoint class AddGuarantorFragment : BaseFragment(), AddGuarantorView { private var _binding: FragmentAddGuarantorBinding? = null @@ -59,7 +60,6 @@ class AddGuarantorFragment : BaseFragment(), AddGuarantorView { savedInstanceState: Bundle?, ): View { _binding = FragmentAddGuarantorBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) presenter?.attachView(this) if (guarantorState == GuarantorState.CREATE) { setToolbarTitle(getString(R.string.add_guarantor)) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryAddOptionsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryAddOptionsFragment.kt index e11ef3025..f7e8aa379 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryAddOptionsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryAddOptionsFragment.kt @@ -8,6 +8,7 @@ import android.provider.MediaStore import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentBeneficiaryAddOptionsBinding import org.mifos.mobile.ui.activities.base.BaseActivity @@ -23,6 +24,7 @@ import org.mifos.mobile.utils.Toaster /** * Created by dilpreet on 5/7/17. */ +@AndroidEntryPoint class BeneficiaryAddOptionsFragment : BaseFragment() { private var _binding: FragmentBeneficiaryAddOptionsBinding? = null @@ -37,7 +39,6 @@ class BeneficiaryAddOptionsFragment : BaseFragment() { ): View { _binding = FragmentBeneficiaryAddOptionsBinding.inflate(inflater, container, false) setToolbarTitle(getString(R.string.add_beneficiary)) - (activity as BaseActivity?)?.activityComponent?.inject(this) return binding.root } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt index 030c4e521..907c5fe7d 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt @@ -6,6 +6,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentBeneficiaryApplicationBinding import org.mifos.mobile.models.beneficiary.Beneficiary @@ -13,7 +14,6 @@ import org.mifos.mobile.models.beneficiary.BeneficiaryPayload import org.mifos.mobile.models.beneficiary.BeneficiaryUpdatePayload import org.mifos.mobile.models.templates.beneficiary.BeneficiaryTemplate import org.mifos.mobile.presenters.BeneficiaryApplicationPresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.BeneficiaryState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.views.BeneficiaryApplicationView @@ -25,6 +25,7 @@ import javax.inject.Inject /** * Created by dilpreet on 16/6/17. */ +@AndroidEntryPoint class BeneficiaryApplicationFragment : BaseFragment(), BeneficiaryApplicationView { private var _binding: FragmentBeneficiaryApplicationBinding? = null @@ -69,7 +70,6 @@ class BeneficiaryApplicationFragment : BaseFragment(), BeneficiaryApplicationVie savedInstanceState: Bundle?, ): View { _binding = FragmentBeneficiaryApplicationBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) showUserInterface() presenter?.attachView(this) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryDetailFragment.kt index e53efbc0f..6f03e85ad 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryDetailFragment.kt @@ -8,6 +8,7 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentBeneficiaryDetailBinding import org.mifos.mobile.models.beneficiary.Beneficiary @@ -25,6 +26,7 @@ import javax.inject.Inject /** * Created by dilpreet on 15/6/17. */ +@AndroidEntryPoint class BeneficiaryDetailFragment : BaseFragment(), BeneficiaryDetailView { private var _binding: FragmentBeneficiaryDetailBinding? = null @@ -48,7 +50,6 @@ class BeneficiaryDetailFragment : BaseFragment(), BeneficiaryDetailView { savedInstanceState: Bundle?, ): View { _binding = FragmentBeneficiaryDetailBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) setToolbarTitle(getString(R.string.beneficiary_detail)) presenter?.attachView(this) showUserInterface() diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt index f32177c66..7baa909be 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentBeneficiaryListBinding import org.mifos.mobile.models.beneficiary.Beneficiary @@ -28,6 +29,7 @@ import javax.inject.Inject /** * Created by dilpreet on 14/6/17. */ +@AndroidEntryPoint class BeneficiaryListFragment : BaseFragment(), OnRefreshListener, BeneficiariesView { private var _binding: FragmentBeneficiaryListBinding? = null @@ -48,7 +50,6 @@ class BeneficiaryListFragment : BaseFragment(), OnRefreshListener, Beneficiaries ): View { _binding = FragmentBeneficiaryListBinding.inflate(inflater, container, false) beneficiaryListAdapter = BeneficiaryListAdapter(::onItemClick) - (activity as BaseActivity?)?.activityComponent?.inject(this) setToolbarTitle(getString(R.string.beneficiaries)) sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) showUserInterface() diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt index 5ccb6d085..0bc56be2a 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt @@ -20,6 +20,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.viewpager.widget.ViewPager.OnPageChangeListener import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.tabs.TabLayout +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentClientAccountsBinding import org.mifos.mobile.models.accounts.loan.LoanAccount @@ -42,7 +43,9 @@ import javax.inject.Inject /* ~This project is licensed under the open source MPL V2. ~See https://github.com/openMF/self-service-app/blob/master/LICENSE.md -*/ class ClientAccountsFragment : BaseFragment(), AccountsView { +*/ +@AndroidEntryPoint +class ClientAccountsFragment : BaseFragment(), AccountsView { private var _binding: FragmentClientAccountsBinding? = null private val binding get() = _binding!! @@ -71,7 +74,6 @@ import javax.inject.Inject ): View { _binding = FragmentClientAccountsBinding.inflate(inflater, container, false) val rootView = binding.root - (activity as BaseActivity?)?.activityComponent?.inject(this) accountsPresenter?.attachView(this) setToolbarTitle(getString(R.string.accounts)) setUpViewPagerAndTabLayout() diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientChargeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/ClientChargeFragment.kt index b3f852bfb..9b4f00737 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientChargeFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/ClientChargeFragment.kt @@ -13,10 +13,10 @@ import butterknife.BindView import butterknife.ButterKnife import butterknife.OnClick import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.models.Charge import org.mifos.mobile.presenters.ClientChargePresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.adapters.ClientChargeAdapter import org.mifos.mobile.ui.enums.ChargeType import org.mifos.mobile.ui.fragments.base.BaseFragment @@ -31,6 +31,7 @@ import javax.inject.Inject * @author Vishwajeet * @since 17/8/16. */ +@AndroidEntryPoint class ClientChargeFragment : BaseFragment(), ClientChargeView { @JvmField @@ -58,7 +59,6 @@ class ClientChargeFragment : BaseFragment(), ClientChargeView { private var sweetUIErrorHandler: SweetUIErrorHandler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as BaseActivity?)?.activityComponent?.inject(this) if (arguments != null) { id = arguments?.getLong(Constants.CLIENT_ID) chargeType = arguments?.getSerializable(Constants.CHARGE_TYPE) as ChargeType diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorDetailFragment.kt index 4d7704492..7902705ce 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorDetailFragment.kt @@ -8,6 +8,7 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.Toast +import dagger.hilt.android.AndroidEntryPoint import io.reactivex.disposables.Disposable import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentGuarantorDetailBinding @@ -29,7 +30,9 @@ import javax.inject.Inject /* * Created by saksham on 24/July/2018 -*/ class GuarantorDetailFragment : BaseFragment(), GuarantorDetailView { +*/ +@AndroidEntryPoint +class GuarantorDetailFragment : BaseFragment(), GuarantorDetailView { private var _binding: FragmentGuarantorDetailBinding? = null private val binding get() = _binding!! @@ -61,7 +64,6 @@ import javax.inject.Inject _binding = FragmentGuarantorDetailBinding.inflate(inflater, container, false) setToolbarTitle(getString(R.string.guarantor_details)) setHasOptionsMenu(true) - (activity as BaseActivity?)?.activityComponent?.inject(this) if (isFirstTime) { isFirstTime = false setUpRxBus() diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorListFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorListFragment.kt index ccaed0a8e..f6ec88bb2 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorListFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorListFragment.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.LinearLayoutManager import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import io.reactivex.disposables.Disposable import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentGuarantorListBinding @@ -26,6 +27,7 @@ import javax.inject.Inject /* * Created by saksham on 23/July/2018 */ +@AndroidEntryPoint class GuarantorListFragment : BaseFragment(), GuarantorListView { private var _binding: FragmentGuarantorListBinding? = null @@ -52,7 +54,6 @@ class GuarantorListFragment : BaseFragment(), GuarantorListView { ): View { _binding = FragmentGuarantorListBinding.inflate(inflater, container, false) setToolbarTitle(getString(R.string.view_guarantor)) - (activity as BaseActivity?)?.activityComponent?.inject(this) presenter?.attachView(this) if (list == null) { presenter?.getGuarantorList(loanId) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/HelpFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/HelpFragment.kt index aba6175e0..3736a0119 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/HelpFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/HelpFragment.kt @@ -15,6 +15,7 @@ import android.widget.Toast import androidx.appcompat.widget.SearchView import androidx.recyclerview.widget.LinearLayoutManager import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentHelpBinding import org.mifos.mobile.models.FAQ @@ -31,6 +32,7 @@ import javax.inject.Inject ~This project is licensed under the open source MPL V2. ~See https://github.com/openMF/self-service-app/blob/master/LICENSE.md */ +@AndroidEntryPoint class HelpFragment : BaseFragment(), HelpView { private var _binding: FragmentHelpBinding? = null private val binding get() = _binding!! @@ -53,7 +55,6 @@ class HelpFragment : BaseFragment(), HelpView { _binding = FragmentHelpBinding.inflate(inflater, container, false) val rootView = binding.root setHasOptionsMenu(true) - (activity as BaseActivity?)?.activityComponent?.inject(this) presenter?.attachView(this) setToolbarTitle(getString(R.string.help)) sweetUIErrorHandler = SweetUIErrorHandler(activity, rootView) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/HomeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/HomeFragment.kt index 65cbdaf9c..99602c337 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/HomeFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/HomeFragment.kt @@ -71,7 +71,6 @@ class HomeFragment : BaseFragment(), HomeView, OnRefreshListener { savedInstanceState: Bundle?, ): View { rootView = inflater.inflate(R.layout.fragment_home_ui, container, false) - (activity as HomeActivity?)?.activityComponent?.inject(this) ButterKnife.bind(this, rootView) clientId = preferencesHelper?.clientId setHasOptionsMenu(true) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/HomeOldFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/HomeOldFragment.kt index 48a746912..f945fea83 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/HomeOldFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/HomeOldFragment.kt @@ -20,6 +20,7 @@ import android.widget.TextView import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.databinding.FragmentHomeOldBinding @@ -45,6 +46,7 @@ import javax.inject.Inject /** * Created by michaelsosnick on 1/1/17. */ +@AndroidEntryPoint class HomeOldFragment : BaseFragment(), HomeOldView, OnRefreshListener { private var _binding: FragmentHomeOldBinding? = null private val binding get() = _binding!! @@ -72,7 +74,6 @@ class HomeOldFragment : BaseFragment(), HomeOldView, OnRefreshListener { ): View { _binding = FragmentHomeOldBinding.inflate(inflater, container, false) val rootView = binding.root - (activity as HomeActivity?)?.activityComponent?.inject(this) clientId = preferencesHelper?.clientId presenter?.attachView(this) setHasOptionsMenu(true) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountSummaryFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountSummaryFragment.kt index 2fdbaef51..38e7052fa 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountSummaryFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountSummaryFragment.kt @@ -4,10 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentLoanAccountSummaryBinding import org.mifos.mobile.models.accounts.loan.LoanWithAssociations -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.CurrencyUtil @@ -18,13 +18,13 @@ import org.mifos.mobile.utils.CurrencyUtil */ /** * Created by dilpreet on 25/2/17. */ +@AndroidEntryPoint class LoanAccountSummaryFragment : BaseFragment() { private var _binding: FragmentLoanAccountSummaryBinding? = null private val binding get() = _binding!! private var loanWithAssociations: LoanWithAssociations? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as BaseActivity?)?.activityComponent?.inject(this) if (arguments != null) { loanWithAssociations = arguments?.getParcelable(Constants.LOAN_ACCOUNT) } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountTransactionFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountTransactionFragment.kt index e98a76ee6..98a3fb308 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountTransactionFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountTransactionFragment.kt @@ -7,19 +7,20 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import android.widget.Toast +import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentLoanAccountTransactionsBinding import org.mifos.mobile.models.accounts.loan.LoanWithAssociations -import org.mifos.mobile.presenters.LoanAccountsTransactionPresenter -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.LoanAccountsTransactionView import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.LoanUiState import org.mifos.mobile.utils.Network +import org.mifos.mobile.viewModels.LoanAccountTransactionViewModel import javax.inject.Inject /* @@ -28,7 +29,8 @@ import javax.inject.Inject */ /** * Created by dilpreet on 4/3/17. */ -class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionView { +@AndroidEntryPoint +class LoanAccountTransactionFragment : BaseFragment() { private var _binding: FragmentLoanAccountTransactionsBinding? = null private val binding get() = _binding!! @@ -36,15 +38,13 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi @Inject var transactionsListAdapter: RecentTransactionListAdapter? = null - @JvmField - @Inject - var loanAccountsTransactionPresenter: LoanAccountsTransactionPresenter? = null + lateinit var viewModel: LoanAccountTransactionViewModel + private var loanId: Long? = 0 private var loanWithAssociations: LoanWithAssociations? = null private var sweetUIErrorHandler: SweetUIErrorHandler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as BaseActivity?)?.activityComponent?.inject(this) if (arguments != null) { loanId = arguments?.getLong(Constants.LOAN_ID) } @@ -56,13 +56,13 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi savedInstanceState: Bundle?, ): View { _binding = FragmentLoanAccountTransactionsBinding.inflate(inflater, container, false) + viewModel = ViewModelProvider(this)[LoanAccountTransactionViewModel::class.java] val rootView = binding.root setToolbarTitle(getString(R.string.transactions)) - loanAccountsTransactionPresenter?.attachView(this) sweetUIErrorHandler = SweetUIErrorHandler(context, rootView) showUserInterface() if (savedInstanceState == null) { - loanAccountsTransactionPresenter?.loadLoanAccountDetails(loanId) + viewModel.loadLoanAccountDetails(loanId) } return rootView } @@ -82,7 +82,7 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi /** * Initialized [RecyclerView] `rvLoanTransactions` */ - override fun showUserInterface() { + fun showUserInterface() { val layoutManager = LinearLayoutManager(activity) layoutManager.orientation = LinearLayoutManager.VERTICAL with(binding) { @@ -98,7 +98,7 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi * * @param loanWithAssociations object containing details about a Loan Account with Associations */ - override fun showLoanTransactions(loanWithAssociations: LoanWithAssociations?) { + fun showLoanTransactions(loanWithAssociations: LoanWithAssociations?) { this.loanWithAssociations = loanWithAssociations binding.llLoanAccountTrans.visibility = View.VISIBLE binding.tvLoanProductName.text = loanWithAssociations?.loanProductName @@ -108,7 +108,7 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi /** * Sets a [TextView] with a msg if Transactions list is empty */ - override fun showEmptyTransactions(loanWithAssociations: LoanWithAssociations?) { + fun showEmptyTransactions(loanWithAssociations: LoanWithAssociations?) { sweetUIErrorHandler?.showSweetEmptyUI( getString(R.string.transactions), R.drawable.ic_compare_arrows_black_24dp, @@ -122,7 +122,7 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi * * @param message Error message that tells the user about the problem. */ - override fun showErrorFetchingLoanAccountsDetail(message: String?) { + fun showErrorFetchingLoanAccountsDetail(message: String?) { with(binding) { if (!Network.isConnected(activity)) { sweetUIErrorHandler?.showSweetNoInternetUI( @@ -142,6 +142,26 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.loanUiState.observe(viewLifecycleOwner) { + when (it) { + is LoanUiState.Loading -> showProgress() + is LoanUiState.ShowError -> { + hideProgress() + showErrorFetchingLoanAccountsDetail(getString(it.message)) + } + is LoanUiState.ShowLoan -> { + hideProgress() + showLoanTransactions(it.loanWithAssociations) + } + is LoanUiState.ShowEmpty -> { + hideProgress() + showEmptyTransactions(it.loanWithAssociations) + } + else -> throw IllegalStateException("Unexpected state: $it") + } + } + binding.layoutError.btnTryAgain.setOnClickListener { retryClicked() } @@ -153,7 +173,7 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi binding.rvLoanTransactions, binding.layoutError.root, ) - loanAccountsTransactionPresenter?.loadLoanAccountDetails(loanId) + viewModel.loadLoanAccountDetails(loanId) } else { Toast.makeText( context, @@ -163,18 +183,17 @@ class LoanAccountTransactionFragment : BaseFragment(), LoanAccountsTransactionVi } } - override fun showProgress() { + fun showProgress() { showProgressBar() } - override fun hideProgress() { + fun hideProgress() { hideProgressBar() } override fun onDestroyView() { super.onDestroyView() hideProgressBar() - loanAccountsTransactionPresenter?.detachView() _binding = null } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountWithdrawFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountWithdrawFragment.kt index bfcfd367b..36c3ca519 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountWithdrawFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountWithdrawFragment.kt @@ -4,34 +4,33 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.lifecycle.ViewModelProvider +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentLoanWithdrawBinding import org.mifos.mobile.models.accounts.loan.LoanWithAssociations import org.mifos.mobile.models.accounts.loan.LoanWithdraw -import org.mifos.mobile.presenters.LoanAccountWithdrawPresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.LoanAccountWithdrawView import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DateHelper +import org.mifos.mobile.utils.LoanUiState import org.mifos.mobile.utils.Toaster -import javax.inject.Inject +import org.mifos.mobile.viewModels.LoanAccountWithdrawViewModel /** * Created by dilpreet on 7/6/17. */ -class LoanAccountWithdrawFragment : BaseFragment(), LoanAccountWithdrawView { +@AndroidEntryPoint +class LoanAccountWithdrawFragment : BaseFragment() { private var _binding: FragmentLoanWithdrawBinding? = null private val binding get() = _binding!! - @JvmField - @Inject - var loanAccountWithdrawPresenter: LoanAccountWithdrawPresenter? = null + lateinit var viewModel: LoanAccountWithdrawViewModel + private var loanWithAssociations: LoanWithAssociations? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as BaseActivity?)?.activityComponent?.inject(this) if (arguments != null) { loanWithAssociations = arguments?.getParcelable(Constants.LOAN_ACCOUNT) } @@ -43,14 +42,30 @@ class LoanAccountWithdrawFragment : BaseFragment(), LoanAccountWithdrawView { savedInstanceState: Bundle?, ): View { _binding = FragmentLoanWithdrawBinding.inflate(inflater, container, false) + viewModel = ViewModelProvider(this)[LoanAccountWithdrawViewModel::class.java] setToolbarTitle(getString(R.string.withdraw_loan)) showUserInterface() - loanAccountWithdrawPresenter?.attachView(this) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.loanUiState.observe(viewLifecycleOwner) { + when (it) { + is LoanUiState.Loading -> showProgress() + is LoanUiState.ShowError -> { + hideProgress() + showLoanAccountWithdrawError(getString(it.message)) + } + is LoanUiState.WithdrawSuccess -> { + hideProgress() + showLoanAccountWithdrawSuccess() + } + else -> throw IllegalStateException("Unexpected state: $it") + } + } + binding.btnWithdrawLoan.setOnClickListener { onLoanWithdraw() } @@ -72,7 +87,7 @@ class LoanAccountWithdrawFragment : BaseFragment(), LoanAccountWithdrawView { loanWithdraw.note = binding.etWithdrawReason.text.toString() loanWithdraw.withdrawnOnDate = DateHelper .getDateAsStringFromLong(System.currentTimeMillis()) - loanAccountWithdrawPresenter?.withdrawLoanAccount( + viewModel.withdrawLoanAccount( loanWithAssociations?.id?.toLong(), loanWithdraw, ) @@ -81,7 +96,7 @@ class LoanAccountWithdrawFragment : BaseFragment(), LoanAccountWithdrawView { /** * Receives A confirmation after successfull withdrawing of Loan Application. */ - override fun showLoanAccountWithdrawSuccess() { + fun showLoanAccountWithdrawSuccess() { Toaster.show(binding.root, R.string.loan_application_withdrawn_successfully) activity?.supportFragmentManager?.popBackStack() } @@ -92,22 +107,21 @@ class LoanAccountWithdrawFragment : BaseFragment(), LoanAccountWithdrawView { * * @param message Error Message displayed */ - override fun showLoanAccountWithdrawError(message: String?) { + fun showLoanAccountWithdrawError(message: String?) { Toaster.show(binding.root, message) } - override fun showProgress() { + fun showProgress() { showProgressBar() } - override fun hideProgress() { + fun hideProgress() { hideProgressBar() } override fun onDestroyView() { super.onDestroyView() hideProgress() - loanAccountWithdrawPresenter?.detachView() _binding = null } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountsDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountsDetailFragment.kt index d7c2c2591..755bb5b47 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountsDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountsDetailFragment.kt @@ -9,23 +9,20 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.lifecycle.ViewModelProvider import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.databinding.FragmentLoanAccountDetailsBinding import org.mifos.mobile.models.accounts.loan.LoanWithAssociations -import org.mifos.mobile.presenters.LoanAccountsDetailPresenter import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.AccountType import org.mifos.mobile.ui.enums.ChargeType import org.mifos.mobile.ui.enums.LoanState import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.LoanAccountsDetailView -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.CurrencyUtil -import org.mifos.mobile.utils.DateHelper -import org.mifos.mobile.utils.Network -import org.mifos.mobile.utils.QrCodeGenerator +import org.mifos.mobile.utils.* +import org.mifos.mobile.viewModels.LoanAccountsDetailViewModel import javax.inject.Inject /* @@ -35,13 +32,12 @@ import javax.inject.Inject * @author Vishwajeet * @since 19/08/16 */ -class LoanAccountsDetailFragment : BaseFragment(), LoanAccountsDetailView { +@AndroidEntryPoint +class LoanAccountsDetailFragment : BaseFragment() { private var _binding: FragmentLoanAccountDetailsBinding? = null private val binding get() = _binding!! - @JvmField - @Inject - var loanAccountDetailsPresenter: LoanAccountsDetailPresenter? = null + lateinit var viewModel: LoanAccountsDetailViewModel @JvmField @Inject @@ -63,14 +59,13 @@ class LoanAccountsDetailFragment : BaseFragment(), LoanAccountsDetailView { container: ViewGroup?, savedInstanceState: Bundle?, ): View { - (activity as BaseActivity?)?.activityComponent?.inject(this) _binding = FragmentLoanAccountDetailsBinding.inflate(inflater, container, false) val rootView = binding.root + viewModel = ViewModelProvider(this)[LoanAccountsDetailViewModel::class.java] setToolbarTitle(getString(R.string.loan_account_details)) - loanAccountDetailsPresenter?.attachView(this) sweetUIErrorHandler = SweetUIErrorHandler(activity, rootView) if (savedInstanceState == null && this.loanWithAssociations == null) { - loanAccountDetailsPresenter?.loadLoanAccountDetails(loanId) + viewModel.loadLoanAccountDetails(loanId) } else { showLoanAccountsDetail(this.loanWithAssociations) } @@ -95,7 +90,7 @@ class LoanAccountsDetailFragment : BaseFragment(), LoanAccountsDetailView { * * @param loanWithAssociations object containing details of each loan account, */ - override fun showLoanAccountsDetail(loanWithAssociations: LoanWithAssociations?) { + private fun showLoanAccountsDetail(loanWithAssociations: LoanWithAssociations?) { this.loanWithAssociations = loanWithAssociations with(binding) { llAccountDetail.visibility = View.VISIBLE @@ -171,6 +166,22 @@ class LoanAccountsDetailFragment : BaseFragment(), LoanAccountsDetailView { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.loanUiState.observe(viewLifecycleOwner) { + when (it) { + is LoanUiState.Loading -> showProgress() + is LoanUiState.ShowError -> { + hideProgress() + showErrorFetchingLoanAccountsDetail(getString(it.message)) + } + is LoanUiState.ShowLoan -> { + hideProgress() + showLoanAccountsDetail(it.loanWithAssociations) + } + else -> throw IllegalStateException("Unexpected state: $it") + } + } + with(binding) { btnMakePayment.setOnClickListener { onMakePaymentClicked() @@ -288,7 +299,7 @@ class LoanAccountsDetailFragment : BaseFragment(), LoanAccountsDetailView { * * @param message Error message that tells the user about the problem. */ - override fun showErrorFetchingLoanAccountsDetail(message: String?) { + fun showErrorFetchingLoanAccountsDetail(message: String?) { if (!Network.isConnected(activity)) { sweetUIErrorHandler?.showSweetNoInternetUI( binding.llAccountDetail, @@ -304,13 +315,13 @@ class LoanAccountsDetailFragment : BaseFragment(), LoanAccountsDetailView { } } - fun retryClicked() { + private fun retryClicked() { if (Network.isConnected(context)) { sweetUIErrorHandler?.hideSweetErrorLayoutUI( binding.llAccountDetail, binding.layoutError.root, ) - loanAccountDetailsPresenter?.loadLoanAccountDetails(loanId) + viewModel.loadLoanAccountDetails(loanId) } else { Toast.makeText( context, @@ -320,18 +331,17 @@ class LoanAccountsDetailFragment : BaseFragment(), LoanAccountsDetailView { } } - override fun showProgress() { + fun showProgress() { showProgressBar() } - override fun hideProgress() { + fun hideProgress() { hideProgressBar() } override fun onDestroyView() { super.onDestroyView() hideProgressBar() - loanAccountDetailsPresenter?.detachView() _binding = null } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanApplicationFragment.kt index 42f80e048..397ead778 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanApplicationFragment.kt @@ -6,40 +6,34 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.DialogFragment +import androidx.lifecycle.ViewModelProvider +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentAddLoanApplicationBinding import org.mifos.mobile.models.accounts.loan.LoanAccount import org.mifos.mobile.models.accounts.loan.LoanWithAssociations import org.mifos.mobile.models.payload.LoansPayload import org.mifos.mobile.models.templates.loans.LoanTemplate -import org.mifos.mobile.presenters.LoanApplicationPresenter import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.LoanState import org.mifos.mobile.ui.fragments.ReviewLoanApplicationFragment.Companion.newInstance import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.LoanApplicationMvpView -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.DateHelper -import org.mifos.mobile.utils.DatePickerConstrainType -import org.mifos.mobile.utils.Network -import org.mifos.mobile.utils.Toaster -import org.mifos.mobile.utils.getDatePickerDialog -import org.mifos.mobile.utils.getTodayFormatted +import org.mifos.mobile.utils.* +import org.mifos.mobile.viewModels.LoanApplicationViewModel import java.text.SimpleDateFormat import java.time.Instant import java.util.Locale -import javax.inject.Inject /** * Created by Rajan Maurya on 06/03/17. */ -class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { +@AndroidEntryPoint +class LoanApplicationFragment : BaseFragment() { private var _binding: FragmentAddLoanApplicationBinding? = null private val binding get() = _binding!! - @JvmField - @Inject - var loanApplicationPresenter: LoanApplicationPresenter? = null + lateinit var viewModel: LoanApplicationViewModel + private val listLoanProducts: MutableList = ArrayList() private val listLoanPurpose: MutableList = ArrayList() private var loanTemplate: LoanTemplate? = null @@ -99,7 +93,6 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as BaseActivity?)?.activityComponent?.inject(this) if (arguments != null) { loanState = arguments?.getSerializable(Constants.LOAN_STATE) as LoanState if (loanState == LoanState.CREATE) { @@ -117,7 +110,7 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { savedInstanceState: Bundle?, ): View { _binding = FragmentAddLoanApplicationBinding.inflate(inflater, container, false) - loanApplicationPresenter?.attachView(this) + viewModel = ViewModelProvider(this)[LoanApplicationViewModel::class.java] showUserInterface() if (savedInstanceState == null) { loadLoanTemplate() @@ -147,14 +140,42 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { */ private fun loadLoanTemplate() { if (loanState == LoanState.CREATE) { - loanApplicationPresenter?.loadLoanApplicationTemplate(LoanState.CREATE) + viewModel.loadLoanApplicationTemplate(LoanState.CREATE) } else { - loanApplicationPresenter?.loadLoanApplicationTemplate(LoanState.UPDATE) + viewModel.loadLoanApplicationTemplate(LoanState.UPDATE) } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.loanUiState.observe(viewLifecycleOwner) { + when (it) { + is LoanUiState.Loading -> showProgress() + is LoanUiState.ShowError -> { + hideProgress() + showError(getString(it.message)) + } + is LoanUiState.ShowLoanTemplate -> { + hideProgress() + showLoanTemplate(it.template) + } + is LoanUiState.ShowUpdateLoanTemplate -> { + hideProgress() + showUpdateLoanTemplate(it.template) + } + is LoanUiState.ShowLoanTemplateByProduct -> { + hideProgress() + showLoanTemplateByProduct(it.template) + } + is LoanUiState.ShowUpdateLoanTemplateByProduct -> { + hideProgress() + showUpdateLoanTemplateByProduct(it.template) + } + else -> throw IllegalStateException("Unexpected state: $it") + } + } + with(binding) { btnLoanReview.setOnClickListener { onReviewLoanApplication() @@ -332,7 +353,7 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { /** * Initializes the layout */ - override fun showUserInterface() { + fun showUserInterface() { with(binding) { loanProductsField.setSimpleItems(listLoanProducts.toTypedArray()) loanPurposeField.setSimpleItems(listLoanPurpose.toTypedArray()) @@ -340,7 +361,7 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { loanProductsField.setOnItemClickListener { _, _, position, _ -> println("loan_products_field clicked") productId = loanTemplate?.productOptions?.get(position)?.id - loanApplicationPresenter?.loadLoanApplicationTemplateByProduct(productId, loanState) + viewModel.loadLoanApplicationTemplateByProduct(productId, loanState) loanPurposeFieldParent.isEnabled = true } loanPurposeField.setOnItemClickListener { _, _, position, _ -> @@ -362,7 +383,7 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { * * @param loanTemplate Template for Loan Application */ - override fun showLoanTemplate(loanTemplate: LoanTemplate?) { + fun showLoanTemplate(loanTemplate: LoanTemplate?) { this.loanTemplate = loanTemplate if (loanTemplate?.productOptions != null) { for ((_, name) in loanTemplate.productOptions) { @@ -379,7 +400,7 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { * * @param loanTemplate Template for Loan Application */ - override fun showUpdateLoanTemplate(loanTemplate: LoanTemplate?) { + fun showUpdateLoanTemplate(loanTemplate: LoanTemplate?) { this.loanTemplate = loanTemplate if (loanTemplate?.productOptions != null) { for ((_, name) in loanTemplate.productOptions) { @@ -428,7 +449,7 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { * * @param loanTemplate Template for Loan Application */ - override fun showLoanTemplateByProduct(loanTemplate: LoanTemplate?) { + fun showLoanTemplateByProduct(loanTemplate: LoanTemplate?) { this.loanTemplate = loanTemplate with(binding) { tvAccountNumber.text = getString( @@ -461,7 +482,7 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { * * @param loanTemplate Template for Loan Application */ - override fun showUpdateLoanTemplateByProduct(loanTemplate: LoanTemplate?) { + fun showUpdateLoanTemplateByProduct(loanTemplate: LoanTemplate?) { this.loanTemplate = loanTemplate listLoanPurpose.clear() listLoanPurpose.add(activity?.getString(R.string.loan_purpose_not_provided)) @@ -500,7 +521,7 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { * * @param message Error message that tells the user about the problem. */ - override fun showError(message: String?) { + fun showError(message: String?) { with(binding) { if (!Network.isConnected(activity)) { llError.ivStatus.setImageResource(R.drawable.ic_error_black_24dp) @@ -513,12 +534,12 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { } } - override fun showProgress() { + fun showProgress() { binding.llAddLoan.visibility = View.GONE showProgressBar() } - override fun hideProgress() { + fun hideProgress() { binding.llAddLoan.visibility = View.VISIBLE hideProgressBar() } @@ -526,7 +547,6 @@ class LoanApplicationFragment : BaseFragment(), LoanApplicationMvpView { override fun onDestroyView() { super.onDestroyView() hideProgressBar() - loanApplicationPresenter?.detachView() _binding = null } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanRepaymentScheduleFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanRepaymentScheduleFragment.kt index 656c413cf..95ec641a5 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanRepaymentScheduleFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanRepaymentScheduleFragment.kt @@ -7,7 +7,9 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.lifecycle.ViewModelProvider import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentLoanRepaymentScheduleBinding import org.mifos.mobile.models.accounts.loan.LoanWithAssociations @@ -15,27 +17,25 @@ import org.mifos.mobile.models.accounts.loan.Periods import org.mifos.mobile.models.accounts.loan.tableview.Cell import org.mifos.mobile.models.accounts.loan.tableview.ColumnHeader import org.mifos.mobile.models.accounts.loan.tableview.RowHeader -import org.mifos.mobile.presenters.LoanRepaymentSchedulePresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.adapters.LoanRepaymentScheduleAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.LoanRepaymentScheduleMvpView import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DateHelper +import org.mifos.mobile.utils.LoanUiState import org.mifos.mobile.utils.Network +import org.mifos.mobile.viewModels.LoanRepaymentScheduleViewModel import javax.inject.Inject /** * Created by Rajan Maurya on 03/03/17. */ -class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpView { +@AndroidEntryPoint +class LoanRepaymentScheduleFragment : BaseFragment() { private var _binding: FragmentLoanRepaymentScheduleBinding? = null private val binding get() = _binding!! - @JvmField - @Inject - var loanRepaymentSchedulePresenter: LoanRepaymentSchedulePresenter? = null + lateinit var viewModel: LoanRepaymentScheduleViewModel @JvmField @Inject @@ -45,7 +45,6 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi private var loanWithAssociations: LoanWithAssociations? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as BaseActivity?)?.activityComponent?.inject(this) setToolbarTitle(getString(R.string.loan_repayment_schedule)) if (arguments != null) loanId = arguments?.getLong(Constants.LOAN_ID) } @@ -56,17 +55,37 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi savedInstanceState: Bundle?, ): View { _binding = FragmentLoanRepaymentScheduleBinding.inflate(inflater, container, false) - loanRepaymentSchedulePresenter?.attachView(this) + viewModel = ViewModelProvider(this)[LoanRepaymentScheduleViewModel::class.java] sweetUIErrorHandler = SweetUIErrorHandler(context, binding.root) showUserInterface() if (savedInstanceState == null) { - loanRepaymentSchedulePresenter?.loanLoanWithAssociations(loanId) + viewModel.loanLoanWithAssociations(loanId) } return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.loanUiState.observe(viewLifecycleOwner) { + when (it) { + is LoanUiState.Loading -> showProgress() + is LoanUiState.ShowError -> { + hideProgress() + showError(getString(it.message)) + } + is LoanUiState.ShowLoan -> { + hideProgress() + showLoanRepaymentSchedule(it.loanWithAssociations) + } + is LoanUiState.ShowEmpty -> { + hideProgress() + showEmptyRepaymentsSchedule(loanWithAssociations) + } + else -> throw IllegalStateException("Unexpected state: $it") + } + } + binding.layoutError.btnTryAgain.setOnClickListener { retryClicked() } @@ -87,7 +106,7 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi /** * Initializes the layout */ - override fun showUserInterface() { + fun showUserInterface() { val columnWidth: Double binding.tvRepaymentSchedule.setHasFixedWidth(true) val orientation = resources.configuration.orientation @@ -101,11 +120,11 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi loanRepaymentScheduleAdapter?.setColumnWidth(columnWidth) } - override fun showProgress() { + fun showProgress() { showProgressBar() } - override fun hideProgress() { + fun hideProgress() { hideProgressBar() } @@ -114,7 +133,7 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi * * @param loanWithAssociations Contains details about Repayment Schedule */ - override fun showLoanRepaymentSchedule(loanWithAssociations: LoanWithAssociations?) { + fun showLoanRepaymentSchedule(loanWithAssociations: LoanWithAssociations?) { this.loanWithAssociations = loanWithAssociations var currencyRepresentation = loanWithAssociations?.currency?.displaySymbol loanRepaymentScheduleAdapter @@ -151,7 +170,7 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi * * @param loanWithAssociations Contains details about Repayment Schedule */ - override fun showEmptyRepaymentsSchedule(loanWithAssociations: LoanWithAssociations?) { + fun showEmptyRepaymentsSchedule(loanWithAssociations: LoanWithAssociations?) { binding.tvAccountNumber.text = loanWithAssociations?.accountNo binding.tvDisbursementDate.text = DateHelper.getDateAsString(loanWithAssociations?.timeline?.expectedDisbursementDate) @@ -169,7 +188,7 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi * * @param message Error message that tells the user about the problem. */ - override fun showError(message: String?) { + fun showError(message: String?) { if (!Network.isConnected(activity)) { sweetUIErrorHandler?.showSweetNoInternetUI( binding.tvRepaymentSchedule, @@ -191,7 +210,7 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi binding.tvRepaymentSchedule, binding.layoutError.root, ) - loanRepaymentSchedulePresenter?.loanLoanWithAssociations(loanId) + viewModel.loanLoanWithAssociations(loanId) } else { Toast.makeText( context, @@ -204,7 +223,6 @@ class LoanRepaymentScheduleFragment : BaseFragment(), LoanRepaymentScheduleMvpVi override fun onDestroyView() { super.onDestroyView() hideProgressBar() - loanRepaymentSchedulePresenter?.detachView() _binding = null } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LocationsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LocationsFragment.kt index a49ef8cb2..143dd081b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LocationsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LocationsFragment.kt @@ -11,6 +11,7 @@ import com.google.android.gms.maps.MapsInitializer import com.google.android.gms.maps.OnMapReadyCallback import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.MarkerOptions +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentLocationsBinding import org.mifos.mobile.ui.fragments.base.BaseFragment @@ -21,6 +22,7 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment */ /** * Created by dilpreet on 25/2/17. */ +@AndroidEntryPoint class LocationsFragment : BaseFragment(), OnMapReadyCallback { private var _binding: FragmentLocationsBinding? = null 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..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 @@ -5,32 +5,31 @@ 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 +import dagger.hilt.android.AndroidEntryPoint 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 -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 javax.inject.Inject /** * Created by dilpreet on 13/9/17. */ -class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener { +@AndroidEntryPoint +class NotificationFragment : BaseFragment(), OnRefreshListener { private var _binding: FragmentNotificationBinding? = null private val binding get() = _binding!! - - @JvmField - @Inject - var presenter: NotificationPresenter? = null + private lateinit var viewModel : NotificationViewModel @JvmField @Inject @@ -39,7 +38,6 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setToolbarTitle(getString(R.string.notification)) - (activity as BaseActivity?)?.activityComponent?.inject(this) } override fun onCreateView( @@ -49,6 +47,7 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener ): View { _binding = FragmentNotificationBinding.inflate(inflater, container, false) val rootView = binding.root + viewModel = ViewModelProvider(this)[NotificationViewModel::class.java] sweetUIErrorHandler = SweetUIErrorHandler(activity, rootView) val layoutManager = LinearLayoutManager(activity) layoutManager.orientation = LinearLayoutManager.VERTICAL @@ -67,12 +66,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 +86,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 +104,37 @@ class NotificationFragment : BaseFragment(), NotificationView, OnRefreshListener override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + 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) + } + } + } + binding.layoutError.btnTryAgain.setOnClickListener { retryClicked() } } - fun retryClicked() { + private fun loadNotifications() { + 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 +144,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 +157,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/ui/fragments/QrCodeDisplayFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt index 36ad48c88..a8f2d966b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt @@ -9,6 +9,7 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentQrCodeDisplayBinding import org.mifos.mobile.ui.fragments.base.BaseFragment @@ -19,6 +20,7 @@ import org.mifos.mobile.utils.Utils /** * Created by dilpreet on 16/8/17. */ +@AndroidEntryPoint class QrCodeDisplayFragment : BaseFragment() { private var _binding: FragmentQrCodeDisplayBinding? = null diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt index 467517365..36cfc4d89 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt @@ -13,6 +13,7 @@ import com.google.gson.Gson import com.google.gson.JsonSyntaxException import com.google.zxing.Result import com.isseiaoki.simplecropview.CropImageView +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentQrCodeImportBinding import org.mifos.mobile.models.beneficiary.Beneficiary @@ -30,6 +31,7 @@ import javax.inject.Inject /** * Created by manishkumar on 19/05/18. */ +@AndroidEntryPoint class QrCodeImportFragment : BaseFragment(), QrCodeImportView { private var _binding: FragmentQrCodeImportBinding? = null @@ -58,7 +60,6 @@ class QrCodeImportFragment : BaseFragment(), QrCodeImportView { savedInstanceState: Bundle?, ): View { _binding = FragmentQrCodeImportBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) setToolbarTitle(getString(R.string.import_qr)) // load the uri setBitmapImage(qrUri) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeReaderFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeReaderFragment.kt index 07a1fc509..f3f1cc01d 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeReaderFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeReaderFragment.kt @@ -9,6 +9,7 @@ import android.widget.Toast import com.google.gson.Gson import com.google.gson.JsonSyntaxException import com.google.zxing.Result +import dagger.hilt.android.AndroidEntryPoint import me.dm7.barcodescanner.zxing.ZXingScannerView import me.dm7.barcodescanner.zxing.ZXingScannerView.ResultHandler import org.mifos.mobile.R @@ -21,6 +22,7 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment /** * Created by dilpreet on 6/7/17. */ +@AndroidEntryPoint class QrCodeReaderFragment : BaseFragment(), ResultHandler { private var _binding: FragmentScanQrCodeBinding? = null @@ -35,7 +37,6 @@ class QrCodeReaderFragment : BaseFragment(), ResultHandler { ): View { _binding = FragmentScanQrCodeBinding.inflate(inflater, container, false) setToolbarTitle(getString(R.string.add_beneficiary)) - (activity as BaseActivity?)?.activityComponent?.inject(this) binding.viewScanner.setAutoFocus(true) binding.btnFlash.setOnClickListener { turnOnFlash() 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 46a0dac0d..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,46 +6,43 @@ 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 import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +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 /** * @author Vishwwajeet * @since 09/08/16 */ -class RecentTransactionsFragment : BaseFragment(), RecentTransactionsView, OnRefreshListener { +@AndroidEntryPoint +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?) { super.onCreate(savedInstanceState) - (activity as BaseActivity?)?.activityComponent?.inject(this) recentTransactionList = ArrayList() } @@ -55,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() } @@ -94,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 @@ -110,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) { @@ -137,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!!) } @@ -153,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) } @@ -163,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, @@ -178,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, @@ -192,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, @@ -213,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, @@ -223,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 } @@ -239,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/ui/fragments/RegistrationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt index 4a15701b2..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 @@ -4,35 +4,34 @@ import android.graphics.PorterDuff import android.os.Bundle import android.text.Editable import android.text.TextWatcher -import android.util.Patterns import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.RadioButton import android.widget.TextView +import androidx.lifecycle.ViewModelProvider import com.hbb20.CountryCodePicker +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentRegistrationBinding -import org.mifos.mobile.models.register.RegisterPayload -import org.mifos.mobile.presenters.RegistrationPresenter import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.views.RegistrationView +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.Toaster -import javax.inject.Inject +import org.mifos.mobile.viewModels.RegistrationViewModel /** * Created by dilpreet on 31/7/17. */ -class RegistrationFragment : BaseFragment(), RegistrationView { +@AndroidEntryPoint +class RegistrationFragment : BaseFragment() { private var _binding: FragmentRegistrationBinding? = null private val binding get() = _binding!! + private lateinit var viewModel: RegistrationViewModel - @JvmField - @Inject - var presenter: RegistrationPresenter? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -40,53 +39,72 @@ class RegistrationFragment : BaseFragment(), RegistrationView { ): View { _binding = FragmentRegistrationBinding.inflate(inflater, container, false) val rootView = binding.root - (activity as BaseActivity?)?.activityComponent?.inject(this) - presenter?.attachView(this) - binding.progressBar.visibility = View.GONE - binding.passwordStrength.visibility = View.GONE - binding.etPassword.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {} - override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { - if (charSequence.isEmpty()) { - binding.progressBar.visibility = View.GONE - binding.passwordStrength.visibility = View.GONE - } else { - binding.progressBar.visibility = View.VISIBLE - binding.passwordStrength.visibility = View.VISIBLE - updatePasswordStrengthView(charSequence.toString()) + viewModel = ViewModelProvider(this)[RegistrationViewModel::class.java] + with(binding) { + etPassword.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged( + charSequence: CharSequence, i: Int, i1: Int, i2: Int + ) { + } + + override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { + if (charSequence.isEmpty()) { + progressBar.visibility = View.GONE + passwordStrength.visibility = View.GONE + } else { + progressBar.visibility = View.VISIBLE + passwordStrength.visibility = View.VISIBLE + updatePasswordStrengthView(charSequence.toString()) + } } - } - override fun afterTextChanged(editable: Editable) {} - }) + override fun afterTextChanged(editable: Editable) {} + }) + } return rootView } private fun updatePasswordStrengthView(password: String) { - if (TextView.VISIBLE != binding.passwordStrength.visibility) return - if (password.isEmpty()) { - binding.passwordStrength.text = "" - binding.progressBar.progress = 0 - return - } - val str = PasswordStrength.calculateStrength(password) - binding.passwordStrength.text = str.getText(context) - binding.passwordStrength.setTextColor(str.color) - val mode = PorterDuff.Mode.SRC_IN - binding.progressBar.progressDrawable?.setColorFilter(str.color, mode) - if (str.getText(context) == getString(R.string.password_strength_weak)) { - binding.progressBar.progress = 25 - } else if (str.getText(context) == getString(R.string.password_strength_medium)) { - binding.progressBar.progress = 50 - } else if (str.getText(context) == getString(R.string.password_strength_strong)) { - binding.progressBar.progress = 75 - } else { - binding.progressBar.progress = 100 + with(binding) { + if (TextView.VISIBLE != passwordStrength.visibility) return + if (password.isEmpty()) { + passwordStrength.text = "" + progressBar.progress = 0 + return + } + val str = PasswordStrength.calculateStrength(password) + passwordStrength.text = str.getText(context) + passwordStrength.setTextColor(str.color) + val mode = PorterDuff.Mode.SRC_IN + progressBar.progressDrawable?.setColorFilter(str.color, mode) + when (str.getText(context)) { + getString(R.string.password_strength_weak) -> progressBar.progress = 25 + getString(R.string.password_strength_medium) -> progressBar.progress = 50 + getString(R.string.password_strength_strong) -> progressBar.progress = 75 + else -> progressBar.progress = 100 + } } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.registrationUiState.observe(viewLifecycleOwner) { state -> + when (state) { + RegistrationUiState.Loading -> showProgress() + + RegistrationUiState.Success -> { + hideProgress() + showRegisteredSuccessfully() + } + + is RegistrationUiState.Error -> { + hideProgress() + showError(MFErrorParser.errorMessage(state.exception)) + } + } + } + binding.btnRegister.setOnClickListener { registerClicked() } @@ -94,120 +112,152 @@ class RegistrationFragment : BaseFragment(), RegistrationView { private fun registerClicked() { if (areFieldsValidated()) { - val radioButton = binding.rgVerificationMode.checkedRadioButtonId.let { - binding.root.findViewById(it) - } - val payload = RegisterPayload() - payload.accountNumber = binding.etAccountNumber.text.toString() - payload.authenticationMode = radioButton?.text.toString() - payload.email = binding.etEmail.text.toString() - payload.firstName = binding.etFirstName.text.toString() - payload.lastName = binding.etLastName.text.toString() - payload.mobileNumber = - binding.countryCodePicker.selectedCountryCode.toString() + binding.etPhoneNumber.text.toString() - if (binding.etPassword.text.toString() != binding.etConfirmPassword.text.toString()) { - Toaster.show(binding.root, getString(R.string.error_password_not_match)) - return - } else { - payload.password = binding.etPassword.text.toString() - } - payload.password = binding.etPassword.text.toString() - payload.username = binding.etUsername.text.toString().replace(" ", "") - if (Network.isConnected(context)) { - presenter?.registerUser(payload) - } else { - Toaster.show(binding.root, getString(R.string.no_internet_connection)) + with(binding) { + val radioButton = rgVerificationMode.checkedRadioButtonId.let { + root.findViewById(it) + } + val accountNumber = etAccountNumber.text.toString() + val authenticationMode = radioButton?.text.toString() + val email = etEmail.text.toString() + val firstName = etFirstName.text.toString() + val lastName = etLastName.text.toString() + val mobileNumber = + countryCodePicker.selectedCountryCode.toString() + etPhoneNumber.text.toString() + if (etPassword.text.toString() != etConfirmPassword.text.toString()) { + Toaster.show(root, getString(R.string.error_password_not_match)) + return + } + val password = etPassword.text.toString() + val username = etUsername.text.toString().replace(" ", "") + + if (Network.isConnected(context)) { + viewModel.registerUser( + accountNumber, + authenticationMode, + email, + firstName, + lastName, + mobileNumber, + password, + username + ) + } else { + Toaster.show(root, getString(R.string.no_internet_connection)) + } } } } private fun areFieldsValidated(): Boolean { val rootView = binding.root - if (binding.etAccountNumber.text.toString().trim { it <= ' ' }.isEmpty()) { - Toaster.show( - rootView, - getString(R.string.error_validation_blank, getString(R.string.account_number)), - ) - return false - } else if (binding.etUsername.text.toString().trim { it <= ' ' }.isEmpty()) { - Toaster.show( - rootView, - getString(R.string.error_validation_blank, getString(R.string.username)), - ) - return false - } else if (binding.etUsername.text.toString().trim { it <= ' ' }.length < 6) { - Toaster.show(rootView, getString(R.string.error_username_greater_than_six)) - return false - } else if (binding.etUsername.text.toString().trim { it <= ' ' }.contains(" ")) { - Toaster.show( - rootView, - getString( - R.string.error_validation_cannot_contain_spaces, - getString(R.string.username), - getString(R.string.not_contain_username), - ), - ) - return false - } else if (binding.etFirstName.text?.isEmpty() == true) { - Toaster.show( - rootView, - getString(R.string.error_validation_blank, getString(R.string.first_name)), - ) - return false - } else if (binding.etLastName.text.toString().trim { it <= ' ' }.isEmpty()) { - Toaster.show( - rootView, - getString(R.string.error_validation_blank, getString(R.string.last_name)), - ) - return false - } else if (binding.etEmail.text.toString().trim { it <= ' ' }.isEmpty()) { - Toaster.show( - rootView, - getString(R.string.error_validation_blank, getString(R.string.email)), - ) - return false - } else if (binding.etPassword.text.toString().trim { it <= ' ' }.isEmpty()) { - Toaster.show( - rootView, - getString(R.string.error_validation_blank, getString(R.string.password)), - ) - return false - } else if (binding.etPassword.text.toString().trim { it <= ' ' }.length - < binding.etPassword.text.toString().length - ) { - Toaster.show( - rootView, - getString( - R.string.error_validation_cannot_contain_leading_or_trailing_spaces, - getString(R.string.password), - ), - ) - return false - } else if (!Patterns.EMAIL_ADDRESS.matcher( - binding.etEmail.text.toString().trim { it <= ' ' }, - ) - .matches() - ) { - Toaster.show(rootView, getString(R.string.error_invalid_email)) - return false - } else if (binding.etPassword.text.toString().trim { it <= ' ' }.length < 6) { - Toaster.show( - rootView, - getString( - R.string.error_validation_minimum_chars, - getString(R.string.password), - resources.getInteger(R.integer.password_minimum_length), - ), - ) - return false - } else if (!isPhoneNumberValid(binding.countryCodePicker)) { - Toaster.show(rootView, getString(R.string.invalid_phn_number)) - return false + with(binding) { + return when { + viewModel.isInputFieldBlank(etAccountNumber.text.toString()) -> { + Toaster.show( + rootView, + getString( + R.string.error_validation_blank, getString(R.string.account_number) + ), + ) + false + } + + viewModel.isInputFieldBlank(etUsername.text.toString()) -> { + Toaster.show( + rootView, + getString(R.string.error_validation_blank, getString(R.string.username)), + ) + false + } + + viewModel.isInputLengthInadequate(etUsername.text.toString()) -> { + Toaster.show(rootView, getString(R.string.error_username_greater_than_six)) + false + } + + viewModel.inputHasSpaces(etUsername.text.toString()) -> { + Toaster.show( + rootView, + getString( + R.string.error_validation_cannot_contain_spaces, + getString(R.string.username), + getString(R.string.not_contain_username), + ), + ) + false + } + + viewModel.isInputFieldBlank(etFirstName.text.toString()) -> { + Toaster.show( + rootView, + getString(R.string.error_validation_blank, getString(R.string.first_name)), + ) + false + } + + viewModel.isInputFieldBlank(etLastName.text.toString()) -> { + Toaster.show( + rootView, + getString(R.string.error_validation_blank, getString(R.string.last_name)), + ) + false + } + + viewModel.isInputFieldBlank(etEmail.text.toString()) -> { + Toaster.show( + rootView, + getString(R.string.error_validation_blank, getString(R.string.email)), + ) + false + } + + viewModel.isInputFieldBlank(etPassword.text.toString()) -> { + Toaster.show( + rootView, + getString(R.string.error_validation_blank, getString(R.string.password)), + ) + false + } + + viewModel.hasLeadingTrailingSpaces(etPassword.text.toString()) -> { + Toaster.show( + rootView, + getString( + R.string.error_validation_cannot_contain_leading_or_trailing_spaces, + getString(R.string.password), + ), + ) + false + } + + viewModel.isEmailInvalid(etEmail.text.toString()) -> { + Toaster.show(rootView, getString(R.string.error_invalid_email)) + false + } + + viewModel.isInputLengthInadequate(etPassword.text.toString()) -> { + Toaster.show( + rootView, + getString( + R.string.error_validation_minimum_chars, + getString(R.string.password), + resources.getInteger(R.integer.password_minimum_length), + ), + ) + return false + } + + (!isPhoneNumberValid(countryCodePicker)) -> { + Toaster.show(rootView, getString(R.string.invalid_phn_number)) + return false + } + + else -> true + } } - return true } - override fun showRegisteredSuccessfully() { + private fun showRegisteredSuccessfully() { (activity as BaseActivity?)?.replaceFragment( RegistrationVerificationFragment.newInstance(), true, @@ -215,21 +265,20 @@ class RegistrationFragment : BaseFragment(), RegistrationView { ) } - override fun showError(msg: String?) { + fun showError(msg: String?) { Toaster.show(binding.root, msg) } - override fun showProgress() { + fun showProgress() { showMifosProgressDialog(getString(R.string.sign_up)) } - 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/ui/fragments/RegistrationVerificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt index 7962982b9..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 @@ -6,27 +6,26 @@ import android.view.LayoutInflater import android.view.View 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.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.RegistrationUiState import org.mifos.mobile.utils.Toaster -import javax.inject.Inject +import org.mifos.mobile.viewModels.RegistrationViewModel /** * Created by dilpreet on 31/7/17. */ -class RegistrationVerificationFragment : BaseFragment(), RegistrationVerificationView { +@AndroidEntryPoint +class RegistrationVerificationFragment : BaseFragment() { private var _binding: FragmentRegistrationVerificationBinding? = null private val binding get() = _binding!! + private lateinit var viewModel: RegistrationViewModel - @JvmField - @Inject - var presenter: RegistrationVerificationPresenter? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -34,46 +33,60 @@ class RegistrationVerificationFragment : BaseFragment(), RegistrationVerificatio ): View { _binding = FragmentRegistrationVerificationBinding.inflate(inflater, container, false) val rootView = binding.root - (activity as BaseActivity?)?.activityComponent?.inject(this) - presenter?.attachView(this) + viewModel = ViewModelProvider(this)[RegistrationViewModel::class.java] return rootView } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + viewModel.registrationVerificationUiState.observe(viewLifecycleOwner) { state -> + when (state) { + RegistrationUiState.Loading -> showProgress() + + RegistrationUiState.Success -> { + hideProgress() + showVerifiedSuccessfully() + } + + is RegistrationUiState.Error -> { + hideProgress() + showError(MFErrorParser.errorMessage(state.exception)) + } + } + } + binding.btnVerify.setOnClickListener { verifyClicked() } } private fun verifyClicked() { - val userVerify = UserVerify() - userVerify.authenticationToken = binding.etAuthenticationToken.text.toString() - userVerify.requestId = binding.etRequestId.text.toString() - presenter?.verifyUser(userVerify) + val authenticationToken = binding.etAuthenticationToken.text.toString() + val requestId = binding.etRequestId.text.toString() + viewModel.verifyUser(authenticationToken, requestId) } - 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/ui/fragments/ReviewLoanApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/ReviewLoanApplicationFragment.kt index d84864e51..ff079f930 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ReviewLoanApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/ReviewLoanApplicationFragment.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.lifecycle.ViewModelProviders +import dagger.hilt.android.AndroidEntryPoint import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers @@ -24,16 +25,14 @@ import kotlinx.android.synthetic.main.layout_error.tv_status import okhttp3.ResponseBody import org.mifos.mobile.R import org.mifos.mobile.models.payload.LoansPayload -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.LoanState 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.viewModels.ReviewLoanApplicationViewModel -import org.mifos.mobile.viewModels.ReviewLoanApplicationViewModelFactory -import javax.inject.Inject +@AndroidEntryPoint class ReviewLoanApplicationFragment : BaseFragment() { companion object { @@ -80,8 +79,6 @@ class ReviewLoanApplicationFragment : BaseFragment() { } } - @Inject - lateinit var viewModelFactory: ReviewLoanApplicationViewModelFactory lateinit var rootView: View @@ -93,8 +90,7 @@ class ReviewLoanApplicationFragment : BaseFragment() { savedInstanceState: Bundle?, ): View { rootView = inflater.inflate(R.layout.fragment_review_loan_application, container, false) - (activity as BaseActivity).activityComponent?.inject(this) - viewModel = ViewModelProviders.of(this, viewModelFactory) + viewModel = ViewModelProviders.of(this) .get(ReviewLoanApplicationViewModel::class.java) val loanState = arguments?.getSerializable(LOAN_STATE) as LoanState if (loanState == LoanState.CREATE) { diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsDetailFragment.kt index 81c6fdac6..9a3600b74 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsDetailFragment.kt @@ -12,6 +12,7 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.databinding.FragmentSavingAccountDetailsBinding @@ -38,6 +39,7 @@ import javax.inject.Inject * @author Vishwajeet * @since 18/8/16. */ +@AndroidEntryPoint class SavingAccountsDetailFragment : BaseFragment(), SavingAccountsDetailView { private var _binding: FragmentSavingAccountDetailsBinding? = null @@ -68,7 +70,6 @@ class SavingAccountsDetailFragment : BaseFragment(), SavingAccountsDetailView { savedInstanceState: Bundle?, ): View { _binding = FragmentSavingAccountDetailsBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) setToolbarTitle(getString(R.string.saving_account_details)) savingAccountsDetailPresenter?.attachView(this) sweetUIErrorHandler = SweetUIErrorHandler(context, binding.root) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt index 93d51dd67..d2ac45533 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt @@ -19,13 +19,13 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentSavingAccountTransactionsBinding import org.mifos.mobile.models.CheckboxStatus import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations import org.mifos.mobile.models.accounts.savings.Transactions import org.mifos.mobile.presenters.SavingAccountsTransactionPresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.adapters.CheckBoxAdapter import org.mifos.mobile.ui.adapters.SavingAccountsTransactionListAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment @@ -44,6 +44,7 @@ import javax.inject.Inject /** * Created by dilpreet on 6/3/17. */ +@AndroidEntryPoint class SavingAccountsTransactionFragment : BaseFragment(), SavingAccountsTransactionView { private var _binding: FragmentSavingAccountTransactionsBinding? = null @@ -76,7 +77,6 @@ class SavingAccountsTransactionFragment : BaseFragment(), SavingAccountsTransact override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) - (activity as BaseActivity?)?.activityComponent?.inject(this) setToolbarTitle(getString(R.string.saving_account_transactions_details)) if (arguments != null) savingsId = arguments?.getLong(Constants.SAVINGS_ID)!! } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountApplicationFragment.kt index b5b1fcd48..4301378bc 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountApplicationFragment.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.databinding.FragmentSavingsAccountApplicationBinding @@ -14,7 +15,6 @@ import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations import org.mifos.mobile.models.templates.savings.ProductOptions import org.mifos.mobile.models.templates.savings.SavingsAccountTemplate import org.mifos.mobile.presenters.SavingsAccountApplicationPresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.SavingsAccountState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.views.SavingsAccountApplicationView @@ -27,6 +27,7 @@ import javax.inject.Inject /* * Created by saksham on 30/June/2018 */ +@AndroidEntryPoint class SavingsAccountApplicationFragment : BaseFragment(), SavingsAccountApplicationView { private var _binding: FragmentSavingsAccountApplicationBinding? = null @@ -59,7 +60,6 @@ class SavingsAccountApplicationFragment : BaseFragment(), SavingsAccountApplicat savedInstanceState: Bundle?, ): View { _binding = FragmentSavingsAccountApplicationBinding.inflate(inflater) - (activity as BaseActivity?)?.activityComponent?.inject(this) presenter?.attachView(this) presenter?.loadSavingsAccountApplicationTemplate(preferencesHelper?.clientId, state) return binding.root diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountWithdrawFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountWithdrawFragment.kt index d46e5ef22..a2159d1c7 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountWithdrawFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountWithdrawFragment.kt @@ -4,12 +4,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentSavingsAccountWithdrawFragmentBinding import org.mifos.mobile.models.accounts.savings.SavingsAccountWithdrawPayload import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations import org.mifos.mobile.presenters.SavingsAccountWithdrawPresenter -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.views.SavingsAccountWithdrawView import org.mifos.mobile.utils.Constants @@ -20,6 +20,7 @@ import javax.inject.Inject /* * Created by saksham on 02/July/2018 */ +@AndroidEntryPoint class SavingsAccountWithdrawFragment : BaseFragment(), SavingsAccountWithdrawView { private var _binding: FragmentSavingsAccountWithdrawFragmentBinding? = null @@ -43,7 +44,6 @@ class SavingsAccountWithdrawFragment : BaseFragment(), SavingsAccountWithdrawVie savedInstanceState: Bundle?, ): View { _binding = FragmentSavingsAccountWithdrawFragmentBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) presenter?.attachView(this) showUserInterface() return binding.root diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsMakeTransferFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsMakeTransferFragment.kt index c7e6aebd5..1acb402f7 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsMakeTransferFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsMakeTransferFragment.kt @@ -11,6 +11,7 @@ import android.view.ViewGroup import android.widget.EditText import android.widget.Spinner import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentSavingsMakeTransferBinding import org.mifos.mobile.models.payload.TransferPayload @@ -33,6 +34,7 @@ import javax.inject.Inject /** * Created by Rajan Maurya on 10/03/17. */ +@AndroidEntryPoint class SavingsMakeTransferFragment : BaseFragment(), SavingsMakeTransferMvpView { private var _binding: FragmentSavingsMakeTransferBinding? = null @@ -72,7 +74,6 @@ class SavingsMakeTransferFragment : BaseFragment(), SavingsMakeTransferMvpView { savedInstanceState: Bundle?, ): View { _binding = FragmentSavingsMakeTransferBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) setToolbarTitle(getString(R.string.transfer)) savingsMakeTransferPresenter?.attachView(this) sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SettingsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SettingsFragment.kt index 5132f6c4b..1f34d3bf5 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SettingsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SettingsFragment.kt @@ -12,6 +12,7 @@ import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.ui.activities.PassCodeActivity @@ -24,6 +25,7 @@ import org.mifos.mobile.utils.LanguageHelper /** * Created by dilpreet on 02/10/17. */ +@AndroidEntryPoint class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListener { private val prefsHelper by lazy { PreferencesHelper(requireContext().applicationContext) } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/ThirdPartyTransferFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/ThirdPartyTransferFragment.kt index 61ff095a6..3b2ff635d 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ThirdPartyTransferFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/ThirdPartyTransferFragment.kt @@ -13,6 +13,7 @@ import android.widget.AdapterView.OnItemSelectedListener import android.widget.EditText import android.widget.Spinner import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentThirdPartyTransferBinding import org.mifos.mobile.models.beneficiary.Beneficiary @@ -39,6 +40,7 @@ import javax.inject.Inject /** * Created by dilpreet on 21/6/17. */ +@AndroidEntryPoint class ThirdPartyTransferFragment : BaseFragment(), ThirdPartyTransferView, OnItemSelectedListener { private var _binding: FragmentThirdPartyTransferBinding? = null @@ -67,7 +69,6 @@ class ThirdPartyTransferFragment : BaseFragment(), ThirdPartyTransferView, OnIte container: ViewGroup?, savedInstanceState: Bundle?, ): View { - (activity as BaseActivity?)?.activityComponent?.inject(this) _binding = FragmentThirdPartyTransferBinding.inflate(inflater, container, false) setToolbarTitle(getString(R.string.third_party_transfer)) sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt index a85aeba4e..c9fa4b825 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt @@ -5,12 +5,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentTransferProcessBinding import org.mifos.mobile.models.payload.TransferPayload import org.mifos.mobile.presenters.TransferProcessPresenter import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity -import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.TransferType import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.views.TransferProcessView @@ -23,6 +23,7 @@ import javax.inject.Inject /** * Created by dilpreet on 1/7/17. */ +@AndroidEntryPoint class TransferProcessFragment : BaseFragment(), TransferProcessView { private var _binding: FragmentTransferProcessBinding? = null @@ -47,7 +48,6 @@ class TransferProcessFragment : BaseFragment(), TransferProcessView { savedInstanceState: Bundle?, ): View { _binding = FragmentTransferProcessBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) setToolbarTitle(getString(R.string.transfer)) presenter?.attachView(this) binding.tvAmount.text = CurrencyUtil.formatCurrency(activity, payload?.transferAmount) 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 5dfd92ecb..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 @@ -8,37 +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.RegistrationUiState +import org.mifos.mobile.viewModels.UpdatePasswordViewModel /* * Created by saksham on 13/July/2018 -*/ class UpdatePasswordFragment : - BaseFragment(), - UpdatePasswordView, - TextWatcher, - OnFocusChangeListener { +*/ +@AndroidEntryPoint +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 @@ -49,8 +39,7 @@ import javax.inject.Inject ): View { _binding = FragmentUpdatePasswordBinding.inflate(inflater, container, false) setToolbarTitle(getString(R.string.change_password)) - (activity as BaseActivity?)?.activityComponent?.inject(this) - presenter?.attachView(this) + viewModel = ViewModelProvider(this)[UpdatePasswordViewModel::class.java] binding.tilNewPassword.editText?.addTextChangedListener(this) binding.tilConfirmNewPassword.editText?.addTextChangedListener(this) binding.tilNewPassword.editText?.onFocusChangeListener = this @@ -63,50 +52,115 @@ import javax.inject.Inject binding.btnUpdatePassword.setOnClickListener { updatePassword() } + + viewModel.updatePasswordUiState.observe(viewLifecycleOwner) { state -> + when (state) { + RegistrationUiState.Loading -> showProgress() + RegistrationUiState.Success -> { + hideProgress() + showPasswordUpdatedSuccessfully() + } + + is RegistrationUiState.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( @@ -123,86 +177,41 @@ import javax.inject.Inject ) } - 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/ui/fragments/UserProfileFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/UserProfileFragment.kt index ba7803189..71e613c7f 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/UserProfileFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/UserProfileFragment.kt @@ -7,6 +7,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler +import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.databinding.FragmentUserProfileBinding @@ -27,6 +28,7 @@ import javax.inject.Inject /** * Created by dilpreet on 10/7/17. */ +@AndroidEntryPoint class UserProfileFragment : BaseFragment(), UserDetailsView { private var _binding: FragmentUserProfileBinding? = null @@ -48,7 +50,6 @@ class UserProfileFragment : BaseFragment(), UserDetailsView { savedInstanceState: Bundle?, ): View { _binding = FragmentUserProfileBinding.inflate(inflater, container, false) - (activity as BaseActivity?)?.activityComponent?.inject(this) presenter?.attachView(this) (activity as BaseActivity?)?.setSupportActionBar(binding.toolbar) // check this part before pushing (activity as BaseActivity?)?.supportActionBar?.setDisplayHomeAsUpEnabled(true) diff --git a/app/src/main/java/org/mifos/mobile/ui/widgets/ChargeWidgetDataProvider.kt b/app/src/main/java/org/mifos/mobile/ui/widgets/ChargeWidgetDataProvider.kt index f69a31600..c02184d77 100644 --- a/app/src/main/java/org/mifos/mobile/ui/widgets/ChargeWidgetDataProvider.kt +++ b/app/src/main/java/org/mifos/mobile/ui/widgets/ChargeWidgetDataProvider.kt @@ -9,7 +9,7 @@ import org.mifos.mobile.api.BaseApiManager import org.mifos.mobile.api.DataManager import org.mifos.mobile.api.local.DatabaseHelper import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.injection.ApplicationContext +import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.models.Charge import org.mifos.mobile.presenters.ClientChargePresenter import org.mifos.mobile.ui.views.ClientChargeView diff --git a/app/src/main/java/org/mifos/mobile/utils/LoanUiState.kt b/app/src/main/java/org/mifos/mobile/utils/LoanUiState.kt new file mode 100644 index 000000000..76a672c71 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/LoanUiState.kt @@ -0,0 +1,16 @@ +package org.mifos.mobile.utils + +import org.mifos.mobile.models.accounts.loan.LoanWithAssociations +import org.mifos.mobile.models.templates.loans.LoanTemplate + +sealed class LoanUiState { + object Loading : LoanUiState() + object WithdrawSuccess : LoanUiState() + data class ShowError(val message: Int) : LoanUiState() + data class ShowLoan(val loanWithAssociations: LoanWithAssociations) : LoanUiState() + data class ShowEmpty(val loanWithAssociations: LoanWithAssociations) : LoanUiState() + data class ShowLoanTemplate(val template: LoanTemplate) : LoanUiState() + data class ShowUpdateLoanTemplate(val template: LoanTemplate) : LoanUiState() + data class ShowLoanTemplateByProduct(val template: LoanTemplate) : LoanUiState() + data class ShowUpdateLoanTemplateByProduct(val template: LoanTemplate) : LoanUiState() +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/utils/LoginUiState.kt b/app/src/main/java/org/mifos/mobile/utils/LoginUiState.kt new file mode 100644 index 000000000..c3404e965 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/LoginUiState.kt @@ -0,0 +1,8 @@ +package org.mifos.mobile.utils + +sealed class LoginUiState { + object LoginSuccess : LoginUiState() + object Loading : LoginUiState() + object Error : LoginUiState() + data class LoadClientSuccess(val clientName: String?) : LoginUiState() +} \ No newline at end of file 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/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/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/viewModels/LoanAccountTransactionViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/LoanAccountTransactionViewModel.kt new file mode 100644 index 000000000..9686e4157 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/LoanAccountTransactionViewModel.kt @@ -0,0 +1,61 @@ +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.accounts.loan.LoanWithAssociations +import org.mifos.mobile.repositories.LoanRepository +import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.LoanUiState +import javax.inject.Inject + +@HiltViewModel +class LoanAccountTransactionViewModel @Inject constructor(private val loanRepositoryImp: LoanRepository) : + ViewModel() { + + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + + private val _loanUiState = MutableLiveData() + val loanUiState: LiveData get() = _loanUiState + + fun loadLoanAccountDetails(loanId: Long?) { + _loanUiState.value = LoanUiState.Loading + loanRepositoryImp.getLoanWithAssociations( + Constants.TRANSACTIONS, + loanId, + )?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _loanUiState.value = + LoanUiState.ShowError(R.string.loan_account_details) + } + + override fun onNext(loanWithAssociations: LoanWithAssociations) { + if (loanWithAssociations.transactions != null && + loanWithAssociations.transactions?.isNotEmpty() == true + ) { + _loanUiState.value = LoanUiState.ShowLoan(loanWithAssociations) + } else { + _loanUiState.value = LoanUiState.ShowEmpty(loanWithAssociations) + } + } + })?.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/LoanAccountWithdrawViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/LoanAccountWithdrawViewModel.kt new file mode 100644 index 000000000..9618b2f94 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/LoanAccountWithdrawViewModel.kt @@ -0,0 +1,48 @@ +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.R +import org.mifos.mobile.models.accounts.loan.LoanWithdraw +import org.mifos.mobile.repositories.LoanRepository +import org.mifos.mobile.utils.LoanUiState +import javax.inject.Inject + +@HiltViewModel +class LoanAccountWithdrawViewModel @Inject constructor(private val loanRepositoryImp: LoanRepository) : + ViewModel() { + + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + + private val _loanUiState = MutableLiveData() + val loanUiState: LiveData get() = _loanUiState + + fun withdrawLoanAccount(loanId: Long?, loanWithdraw: LoanWithdraw?) { + _loanUiState.value = LoanUiState.Loading + loanRepositoryImp.withdrawLoanAccount(loanId, loanWithdraw) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _loanUiState.value = LoanUiState.ShowError(R.string.error_loan_account_withdraw) + } + + override fun onNext(responseBody: ResponseBody) { + _loanUiState.value = LoanUiState.WithdrawSuccess + } + })?.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/LoanAccountsDetailViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/LoanAccountsDetailViewModel.kt new file mode 100644 index 000000000..3e0dfb83d --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/LoanAccountsDetailViewModel.kt @@ -0,0 +1,55 @@ +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.accounts.loan.LoanWithAssociations +import org.mifos.mobile.repositories.LoanRepository +import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.LoanUiState +import javax.inject.Inject + +@HiltViewModel +class LoanAccountsDetailViewModel @Inject constructor(private val loanRepositoryImp: LoanRepository) : + ViewModel() { + + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + + private val _loanUiState = MutableLiveData() + val loanUiState: LiveData get() = _loanUiState + + fun loadLoanAccountDetails(loanId: Long?) { + _loanUiState.value = LoanUiState.Loading + loanRepositoryImp.getLoanWithAssociations( + Constants.REPAYMENT_SCHEDULE, + loanId, + )?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _loanUiState.value = + LoanUiState.ShowError(R.string.loan_account_details) + } + + override fun onNext(loanWithAssociations: LoanWithAssociations) { + _loanUiState.value = LoanUiState.ShowLoan(loanWithAssociations) + } + })?.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/LoanApplicationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/LoanApplicationViewModel.kt new file mode 100644 index 000000000..c9616779c --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/LoanApplicationViewModel.kt @@ -0,0 +1,79 @@ +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.templates.loans.LoanTemplate +import org.mifos.mobile.repositories.LoanRepository +import org.mifos.mobile.ui.enums.LoanState +import org.mifos.mobile.utils.LoanUiState +import javax.inject.Inject + +@HiltViewModel +class LoanApplicationViewModel @Inject constructor(private val loanRepositoryImp: LoanRepository) : + ViewModel() { + + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + + private val _loanUiState = MutableLiveData() + val loanUiState: LiveData get() = _loanUiState + + fun loadLoanApplicationTemplate(loanState: LoanState) { + _loanUiState.value = LoanUiState.Loading + loanRepositoryImp.template()?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _loanUiState.value = LoanUiState.ShowError(R.string.error_fetching_template) + } + + override fun onNext(loanTemplate: LoanTemplate) { + if (loanState === LoanState.CREATE) { + _loanUiState.value = LoanUiState.ShowLoanTemplateByProduct(loanTemplate) + } else { + _loanUiState.value = LoanUiState.ShowUpdateLoanTemplateByProduct(loanTemplate) + } + } + })?.let { + compositeDisposables.add( + it, + ) + } + } + + fun loadLoanApplicationTemplateByProduct(productId: Int?, loanState: LoanState?) { + _loanUiState.value = LoanUiState.Loading + loanRepositoryImp.getLoanTemplateByProduct(productId)?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _loanUiState.value = LoanUiState.ShowError(R.string.error_fetching_template) + } + + override fun onNext(loanTemplate: LoanTemplate) { + if (loanState === LoanState.CREATE) { + _loanUiState.value = LoanUiState.ShowLoanTemplate(loanTemplate) + } else { + _loanUiState.value = LoanUiState.ShowUpdateLoanTemplate(loanTemplate) + } + } + })?.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/LoanRepaymentScheduleViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/LoanRepaymentScheduleViewModel.kt new file mode 100644 index 000000000..cb023919e --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/LoanRepaymentScheduleViewModel.kt @@ -0,0 +1,61 @@ +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.accounts.loan.LoanWithAssociations +import org.mifos.mobile.repositories.LoanRepository +import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.LoanUiState +import javax.inject.Inject + +@HiltViewModel +class LoanRepaymentScheduleViewModel @Inject constructor(private val loanRepositoryImp: LoanRepository) : + ViewModel() { + + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + + private val _loanUiState = MutableLiveData() + val loanUiState: LiveData get() = _loanUiState + + fun loanLoanWithAssociations(loanId: Long?) { + _loanUiState.value = LoanUiState.Loading + loanRepositoryImp.getLoanWithAssociations( + Constants.REPAYMENT_SCHEDULE, + loanId, + )?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _loanUiState.value = + LoanUiState.ShowError(R.string.repayment_schedule) + } + + override fun onNext(loanWithAssociations: LoanWithAssociations) { + if (loanWithAssociations.repaymentSchedule?.periods?.isNotEmpty() == true) { + _loanUiState.value = + LoanUiState.ShowLoan(loanWithAssociations) + } else { + _loanUiState.value = + LoanUiState.ShowEmpty(loanWithAssociations) + } + } + })?.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/LoginViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/LoginViewModel.kt new file mode 100644 index 000000000..58df63636 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/LoginViewModel.kt @@ -0,0 +1,111 @@ +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.plugins.RxJavaPlugins +import io.reactivex.schedulers.Schedulers +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.User +import org.mifos.mobile.models.client.Client +import org.mifos.mobile.repositories.ClientRepository +import org.mifos.mobile.repositories.UserAuthRepository +import org.mifos.mobile.utils.LoginUiState +import javax.inject.Inject + +@HiltViewModel +class LoginViewModel @Inject constructor( + private val userAuthRepositoryImp: UserAuthRepository, + private val clientRepositoryImp: ClientRepository +) : + ViewModel() { + + private val compositeDisposable = CompositeDisposable() + private var _loginUiState = MutableLiveData() + val loginUiState: LiveData get() = _loginUiState + + fun isFieldEmpty(fieldText: String): Boolean { + return fieldText.isEmpty() + } + + fun isUsernameLengthInadequate(username: String): Boolean { + return username.length < 5 + } + + fun isPasswordLengthInadequate(password: String): Boolean { + return password.length < 6 + } + + fun usernameHasSpaces(username: String): Boolean { + return username.trim().contains(" ") + } + + /** + * This method attempts to authenticate the user from + * the server and then persist the authentication data if we successfully + * authenticate the credentials or notify about any errors. + */ + fun login(username: String, password: String) { + _loginUiState.value = LoginUiState.Loading + compositeDisposable.add( + userAuthRepositoryImp.login(username, password) + ?.observeOn(AndroidSchedulers.mainThread())?.subscribeOn(Schedulers.io())!! + .subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + try { + _loginUiState.value = LoginUiState.Error + } catch (throwable: Throwable) { + RxJavaPlugins.getErrorHandler() + } + } + + override fun onNext(user: User) { + clientRepositoryImp.saveAuthenticationTokenForSession(user) + _loginUiState.value = LoginUiState.LoginSuccess + } + }), + ) + } + + /** + * This method fetches the Client, associated with current Access Token. + */ + fun loadClient() { + clientRepositoryImp.loadClient()?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver?>() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _loginUiState.value = LoginUiState.Error + clientRepositoryImp.clearPrefHelper() + clientRepositoryImp.reInitializeService() + } + + override fun onNext(clientPage: Page) { + if (clientPage.pageItems.isNotEmpty()) { + val clientId = clientPage.pageItems[0]?.id?.toLong() + val clientName = clientPage.pageItems[0]?.displayName + clientRepositoryImp.setClientId(clientId) + clientRepositoryImp.reInitializeService() + _loginUiState.value = LoginUiState.LoadClientSuccess(clientName) + } else { + _loginUiState.value = LoginUiState.Error + } + } + })?.let { + compositeDisposable.add( + it, + ) + } + } + + override fun onCleared() { + super.onCleared() + compositeDisposable.clear() + } +} \ 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 new file mode 100644 index 000000000..365fe0a5b --- /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 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.utils.NotificationUiState +import org.mifos.mobile.models.notification.MifosNotification +import org.mifos.mobile.repositories.NotificationRepository +import javax.inject.Inject + +@HiltViewModel +class NotificationViewModel @Inject constructor(private val notificationRepositoryImp: NotificationRepository): ViewModel() { + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + + private val _notificationUiState = MutableLiveData() + val notificationUiState : LiveData get() = _notificationUiState + + fun loadNotifications() { + _notificationUiState.value = NotificationUiState.Loading + notificationRepositoryImp.loadNotifications() + .observeOn(AndroidSchedulers.mainThread()) + ?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver?>() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _notificationUiState.value = NotificationUiState.Error + } + override fun onNext(notificationModels: List) { + _notificationUiState.value = NotificationUiState.LoadNotificationsSuccessful(notificationModels) + } + })?.let { compositeDisposables.add(it) } + } + + override fun onCleared() { + super.onCleared() + compositeDisposables.clear() + } +} 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 diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt new file mode 100644 index 000000000..ecdbd4a93 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt @@ -0,0 +1,104 @@ +package org.mifos.mobile.viewModels + +import androidx.core.util.PatternsCompat +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.UserAuthRepository +import org.mifos.mobile.utils.RegistrationUiState +import javax.inject.Inject + +@HiltViewModel +class RegistrationViewModel @Inject constructor(private val userAuthRepositoryImp: UserAuthRepository) : + ViewModel() { + private val compositeDisposables: CompositeDisposable = CompositeDisposable() + + 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() + } + + fun isInputLengthInadequate(fieldText: String): Boolean { + return fieldText.trim().length < 6 + } + + fun inputHasSpaces(fieldText: String): Boolean { + return fieldText.trim().contains(" ") + } + + fun hasLeadingTrailingSpaces(fieldText: String): Boolean { + return fieldText.trim().length < fieldText.length + } + + fun isEmailInvalid(emailText: String): Boolean { + return !PatternsCompat.EMAIL_ADDRESS.matcher(emailText.trim()).matches() + } + + fun registerUser( + accountNumber: String, + authenticationMode: String, + email: String, + firstName: String, + lastName: String, + mobileNumber: String, + password: String, + username: String + ) { + _registrationUiState.value = RegistrationUiState.Loading + userAuthRepositoryImp.registerUser( + accountNumber, + authenticationMode, + email, + firstName, + lastName, + mobileNumber, + password, + username + )?.observeOn(AndroidSchedulers.mainThread())?.subscribeOn(Schedulers.io()) + ?.subscribeWith(object : DisposableObserver() { + override fun onComplete() {} + override fun onError(e: Throwable) { + _registrationUiState.value = RegistrationUiState.Error(e) + } + + override fun onNext(responseBody: ResponseBody) { + _registrationUiState.value = RegistrationUiState.Success + } + })?.let { compositeDisposables.add(it) } + } + + fun verifyUser(authenticationToken: String?, requestId: String?) { + _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 = + RegistrationUiState.Error(e) + } + + override fun onNext(responseBody: ResponseBody) { + _registrationVerificationUiState.value = + RegistrationUiState.Success + } + })?.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/ReviewLoanApplicationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/ReviewLoanApplicationViewModel.kt index 6f390e889..4cf9e8fea 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/ReviewLoanApplicationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/viewModels/ReviewLoanApplicationViewModel.kt @@ -1,6 +1,7 @@ package org.mifos.mobile.viewModels import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.Observable import okhttp3.ResponseBody import org.mifos.mobile.api.DataManager @@ -8,6 +9,7 @@ import org.mifos.mobile.models.payload.LoansPayload import org.mifos.mobile.ui.enums.LoanState import javax.inject.Inject +@HiltViewModel class ReviewLoanApplicationViewModel @Inject constructor(var dataManager: DataManager?) : ViewModel() { 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..cf9ae264b --- /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.RegistrationUiState +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 = RegistrationUiState.Loading + userAuthRepositoryImp.updateAccountPassword(newPassword, confirmPassword) + ?.subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeWith(object : DisposableObserver() { + override fun onNext(responseBody: ResponseBody) { + _updatePasswordUiState.value = RegistrationUiState.Success + clientRepositoryImp.updateAuthenticationToken(newPassword) + } + + override fun onError(e: Throwable) { + _updatePasswordUiState.value = RegistrationUiState.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/main/res/layout/fragment_registration.xml b/app/src/main/res/layout/fragment_registration.xml index 95b73b8df..feb1019c2 100644 --- a/app/src/main/res/layout/fragment_registration.xml +++ b/app/src/main/res/layout/fragment_registration.xml @@ -129,6 +129,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:visibility="gone" android:indeterminate="false" android:progress="0" /> @@ -137,6 +138,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/Mifos.DesignSystem.Spacing.marginWords" + android:visibility="gone" android:gravity="center_horizontal" android:text="@string/password_strength_weak" /> diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 33e648662..61822c86e 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -148,7 +148,7 @@ اسم المتسخدم / كلمة المرور غير صحيحة خطأ في تحميل الاستجابة من الخادم %1$s لا يمكن أن يكون فارغًا - لا يمكن أن يكون %1$s أقل من %2$s من الأحرف + لا يمكن أن يكون %1$s أقل من %2$d من الأحرف لا يمكن أن تحتوي %1$s على %2$s لا يمكن بد %1$s أو          نهاية مع مساحة فارغة @@ -443,4 +443,5 @@ أدخل المستأجر معلومات التطبيق إظهار أو إخفاء إجمالي مبلغ التوفير + فشل تسجيل الدخول يرجى المحاولة مرة أخرى في وقت لاحق. \ No newline at end of file diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index e8c26a315..47abea6ed 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -430,4 +430,5 @@ অ্যাপের তথ্য মোট সঞ্চয় পরিমাণ দেখান বা লুকান + পরে আবার চেষ্টা করুন ব্যর্থ লগইন. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 361eeebc1..6c7b6926e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -419,4 +419,5 @@ Introduce la URL principal Ir al inquilino Informacion de la applicacion + No se pudo entrar Inténtelo más tarde. \ No newline at end of file diff --git a/app/src/main/res/values-fa-rAF/strings.xml b/app/src/main/res/values-fa-rAF/strings.xml index 153b6548d..dafd90586 100644 --- a/app/src/main/res/values-fa-rAF/strings.xml +++ b/app/src/main/res/values-fa-rAF/strings.xml @@ -424,4 +424,5 @@ کار کردن بلي اطلاعات برنامه + ورود ناموفق بود، لطفاً بعداً دوباره امتحان کنید. \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index fe485ee9e..a6d805667 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -417,4 +417,5 @@ Aller au locataire Informations sur l\'application Afficher ou masquer le montant total de l\'épargne + Authentification échouée, essayez plus tard. \ No newline at end of file diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index f21034cb6..8c30105ea 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -392,6 +392,7 @@ कृपया प्रतीक्षा करें अनुप्रयोग की जानकारी + विफल प्रवेश कृपया बाद में पुन: प्रयास करें। \ No newline at end of file diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 32110188f..2ff5c0a01 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -418,4 +418,5 @@ Masukkan URL utama Pergi ke Tenant Info Aplikasi + Login Gagal, Silakan Coba Lagi Nanti. diff --git a/app/src/main/res/values-km/strings.xml b/app/src/main/res/values-km/strings.xml index e13020ec1..26f849c2d 100644 --- a/app/src/main/res/values-km/strings.xml +++ b/app/src/main/res/values-km/strings.xml @@ -418,4 +418,5 @@ បញ្ចូល URL ចម្បង ចូលទៅកាន់ភតិកៈ ព័ត៌មានកម្មវិធី + ការចូលបានបរាជ័យ សូមព្យាយាមម្តងទៀតនៅពេលក្រោយ។ diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml index 866f53f1d..f18dc2a09 100644 --- a/app/src/main/res/values-kn/strings.xml +++ b/app/src/main/res/values-kn/strings.xml @@ -418,4 +418,5 @@ ಪ್ರಾಥಮಿಕ URL ಅನ್ನು ನಮೂದಿಸಿ ಟೆನಂಟ್ಗೆ ಹೋಗಿ ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ + ಲಾಗಿನ್ ವಿಫಲವಾಗಿದೆ ದಯವಿಟ್ಟು ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ. diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index c3020c08e..9c72693d2 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -148,9 +148,9 @@ မှားနေသောအသုံးပြုသူအမည် / Password ကို server ကနေတင်ပေးမှုအမှားတုန့်ပြန် %1$s ကိုအလွတ်မဖွစျနိုငျ - %1$s ကို %2$ ဃဇာတ်ကောင်ထက်လျော့နည်းမဖွစျနိုငျ + %1$s ကို %2$d ဃဇာတ်ကောင်ထက်လျော့နည်းမဖွစျနိုငျ %1$s ကို %2$s ကိုဆံ့မခံနိုင်သည် - s ကိုစတင်မနိုင် %1$ သို့မဟုတ်ဗလာဖြင့်အဆုံး + ကိုစတင်မနိုင် %1$s သို့မဟုတ်ဗလာဖြင့်အဆုံး ပြည်တွင်းရေး server ကိုအမှား,ျေးဇူးပြု.ထပ်ကြိုးစား မှားယွင်းနေသည်တင်clientကိုစာရင်း ချေးငွေအကောင့်စာရင်းထဲတွင်တင်ပေးမှုအမှား @@ -441,5 +441,6 @@ ဥယျာဉ်စောင့် Enter အက်ပ်အချက်အလက် စုစုပေါင်းချွေတာသည့်ပမာဏကို ပြပါ သို့မဟုတ် ဝှက်ပါ။ + အကောင့်ဝင်ခြင်း မအောင်မြင်ပါ၊ ကျေးဇူးပြု၍ နောက်မှ ထပ်စမ်းကြည့်ပါ။ \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index d4fbf0f8a..d803e609f 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -419,4 +419,5 @@ Wprowadź podstawowy adres URL Wejdź do Lokatora Informacje o aplikacji + Zły login, proszę spróbować ponownie. diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 46dd622bc..78fefe25c 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -502,5 +502,6 @@ accountType.loan Erro ao carregar em detalhes de contas de empréstimo Informações do aplicativo + O login falhou por favor tente novamente mais tarde. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 6fe04625f..b4c165bba 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -419,4 +419,5 @@ Введите основной URL-адрес Перейти к Арендатору Информация о приложении + Войти не удалось, пожалуйста, повторите попытку позже. \ No newline at end of file diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index ec7d97b7b..7dca8a32f 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -418,4 +418,5 @@ Ingiza URL ya msingi Nenda kwa Mpangaji Maelezo ya Programu + Kuingia Kumeshindwa, Tafadhali Jaribu Tena Baadaye. \ No newline at end of file diff --git a/app/src/main/res/values-te/strings.xml b/app/src/main/res/values-te/strings.xml index 523d61cda..b1a669acf 100644 --- a/app/src/main/res/values-te/strings.xml +++ b/app/src/main/res/values-te/strings.xml @@ -419,4 +419,5 @@ బేస్ URL ను నమోదు చేయండి అద్దెదారు నమోదు చేయండి యాప్ సమాచారం + లాగిన్ విఫలమైంది, దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి. \ No newline at end of file diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml index c79390404..0644c048c 100644 --- a/app/src/main/res/values-ur/strings.xml +++ b/app/src/main/res/values-ur/strings.xml @@ -440,5 +440,6 @@ بیس یو آر ایل درج کریں کرایہ درج کریں ایپ کی معلومات + لاگ ان ناکام ہوگیا، براہ کرم بعد میں دوبارہ کوشش کریں۔ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1807a635c..7ce29f1a9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -645,5 +645,6 @@ Dark Theme App Info + Login Failed, Please Try Again Later. 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..b2668581b --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/repositories/ClientRepositoryImpTest.kt @@ -0,0 +1,80 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import okhttp3.Credentials +import org.mifos.mobile.api.BaseURL +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.FakeRemoteDataSource +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.api.local.PreferencesHelper +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.client.Client +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 dataManager: DataManager + + @Mock + lateinit var preferencesHelper: PreferencesHelper + + private var mockClientPage: Page? = null + private lateinit var clientRepositoryImp: ClientRepositoryImp + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + clientRepositoryImp = ClientRepositoryImp(dataManager, preferencesHelper) + mockClientPage = FakeRemoteDataSource.clients + } + + @Test + fun testLoadClient_SuccessResponseReceivedFromDataManager_ReturnsClientPageSuccessfully() { + val successResponse: Observable?> = Observable.just(mockClientPage) + Mockito.`when`( + dataManager.clients + ).thenReturn(successResponse) + + val result = clientRepositoryImp.loadClient() + + Mockito.verify(dataManager).clients + Assert.assertEquals(result, successResponse) + } + + @Test + fun testLoadClient_ErrorResponseReceivedFromDataManager_ReturnsError() { + val errorResponse: Observable?> = + Observable.error(Throwable("Load Client Failed")) + Mockito.`when`( + dataManager.clients + ).thenReturn(errorResponse) + + val result = clientRepositoryImp.loadClient() + + Mockito.verify(dataManager).clients + Assert.assertEquals(result, errorResponse) + } + + @Test + fun testUpdateAuthenticationToken() { + 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 diff --git a/app/src/test/java/org/mifos/mobile/repositories/LoanRepositoryImpTest.kt b/app/src/test/java/org/mifos/mobile/repositories/LoanRepositoryImpTest.kt new file mode 100644 index 000000000..266c2da9e --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/repositories/LoanRepositoryImpTest.kt @@ -0,0 +1,142 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import junit.framework.Assert.assertEquals +import okhttp3.ResponseBody +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.accounts.loan.LoanWithAssociations +import org.mifos.mobile.models.accounts.loan.LoanWithdraw +import org.mifos.mobile.models.templates.loans.LoanTemplate +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class LoanRepositoryImpTest { + @Mock + lateinit var dataManager: DataManager + + @Mock + lateinit var loanWithdraw: LoanWithdraw + + private lateinit var loanRepositoryImp: LoanRepositoryImp + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + loanRepositoryImp = LoanRepositoryImp(dataManager) + } + + @Test + fun testGetLoanWithAssociations_Successful() { + val success: Observable = + Observable.just(Mockito.mock(LoanWithAssociations::class.java)) + + `when`( + dataManager.getLoanWithAssociations( + Mockito.anyString(), + Mockito.anyLong() + ) + ).thenReturn(success) + + val result = loanRepositoryImp.getLoanWithAssociations( + "associationType", + 1 + ) + verify(dataManager).getLoanWithAssociations(Mockito.anyString(), Mockito.anyLong()) + assertEquals(result, success) + } + + @Test + fun testGetLoanWithAssociations_Unsuccessful() { + val error: Observable = + Observable.error(Throwable("Failed to fetch loan with associations")) + `when`( + dataManager.getLoanWithAssociations( + Mockito.anyString(), + Mockito.anyLong() + ) + ).thenReturn(error) + + val result = loanRepositoryImp.getLoanWithAssociations( + "associationType", + 1 + ) + + verify(dataManager).getLoanWithAssociations(Mockito.anyString(), Mockito.anyLong()) + assertEquals(result, error) + } + + @Test + fun testWithdrawLoanAccount_Successful() { + val success: Observable = + Observable.just(Mockito.mock(ResponseBody::class.java)) + + `when`(dataManager.withdrawLoanAccount(1, loanWithdraw)).thenReturn(success) + + val result = loanRepositoryImp.withdrawLoanAccount(1, loanWithdraw) + verify(dataManager).withdrawLoanAccount(1, loanWithdraw) + assertEquals(result, success) + } + + @Test + fun testWithdrawLoanAccount_Unsuccessful() { + val error: Observable = + Observable.error(Throwable("Failed to withdraw loan account")) + `when`(dataManager.withdrawLoanAccount(1, loanWithdraw)).thenReturn(error) + + val result = loanRepositoryImp.withdrawLoanAccount(1, loanWithdraw) + verify(dataManager).withdrawLoanAccount(1, loanWithdraw) + assertEquals(result, error) + } + + @Test + fun testTemplate_Successful() { + val success: Observable = + Observable.just(Mockito.mock(LoanTemplate::class.java)) + `when`(dataManager.loanTemplate).thenReturn(success) + + val result = loanRepositoryImp.template() + verify(dataManager).loanTemplate + assertEquals(result, success) + } + + @Test + fun testTemplate_Unsuccessful() { + val error: Observable = + Observable.error(Throwable("Failed to load template")) + `when`(dataManager.loanTemplate).thenReturn(error) + + val result = loanRepositoryImp.template() + verify(dataManager).loanTemplate + assertEquals(result, error) + } + + @Test + fun testGetLoanTemplateByProduct_Successful() { + val success: Observable = + Observable.just(Mockito.mock(LoanTemplate::class.java)) + `when`(dataManager.getLoanTemplateByProduct(1)).thenReturn(success) + + val result = loanRepositoryImp.getLoanTemplateByProduct(1) + verify(dataManager).getLoanTemplateByProduct(1) + assertEquals(result, success) + } + + @Test + fun testGetLoanTemplateByProduct_Unsuccessful() { + val error: Observable = + Observable.error(Throwable("Failed to get loan template by product")) + `when`(dataManager.getLoanTemplateByProduct(1)).thenReturn(error) + + val result = loanRepositoryImp.getLoanTemplateByProduct(1) + verify(dataManager).getLoanTemplateByProduct(1) + assertEquals(result, error) + } +} \ No newline at end of file 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/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/repositories/UserAuthRepositoryImpTest.kt b/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt new file mode 100644 index 000000000..b5e802cb2 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/repositories/UserAuthRepositoryImpTest.kt @@ -0,0 +1,163 @@ +package org.mifos.mobile.repositories + +import io.reactivex.Observable +import okhttp3.ResponseBody +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.FakeRemoteDataSource +import org.mifos.mobile.FakeRemoteDataSource.userVerify +import org.mifos.mobile.api.DataManager +import org.mifos.mobile.models.User +import org.mifos.mobile.models.payload.LoginPayload +import org.mifos.mobile.models.register.RegisterPayload +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class UserAuthRepositoryImpTest { + + @Mock + lateinit var dataManager: DataManager + + private lateinit var userAuthRepositoryImp: UserAuthRepository + private lateinit var mockUser : User + + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + userAuthRepositoryImp = UserAuthRepositoryImp(dataManager) + mockUser = FakeRemoteDataSource.user + } + + @Test + fun testRegisterUser_SuccessResponseReceivedFromDataManager_ReturnSuccessfulRegistration() { + val successResponse: Observable = + Observable.just(Mockito.mock(ResponseBody::class.java)) + val registerPayload = RegisterPayload().apply { + this.accountNumber = "accountNumber" + this.authenticationMode = "authenticationMode" + this.email = "email" + this.firstName = "firstName" + this.lastName = "lastName" + this.mobileNumber = "mobileNumber" + this.password = "password" + this.username = "username" + } + + Mockito.`when`(dataManager.registerUser(registerPayload)).thenReturn(successResponse) + + val result = userAuthRepositoryImp.registerUser( + registerPayload.accountNumber, + registerPayload.authenticationMode, + registerPayload.email, + registerPayload.firstName, + registerPayload.lastName, + registerPayload.mobileNumber, + registerPayload.password, + registerPayload.username + ) + + Mockito.verify(dataManager).registerUser(registerPayload) + Assert.assertEquals(result, successResponse) + } + + @Test + fun testRegisterUser_ErrorResponseReceivedFromDataManager_ReturnsUnsuccessfulRegistration() { + val error: Observable = Observable.error(Throwable("Registration Failed")) + val registerPayload = RegisterPayload().apply { + this.accountNumber = "accountNumber" + this.authenticationMode = "authenticationMode" + this.email = "email" + this.firstName = "firstName" + this.lastName = "lastName" + this.mobileNumber = "mobileNumber" + this.password = "password" + this.username = "username" + } + + Mockito.`when`(dataManager.registerUser(registerPayload)).thenReturn(error) + + val result = userAuthRepositoryImp.registerUser( + registerPayload.accountNumber, + registerPayload.authenticationMode, + registerPayload.email, + registerPayload.firstName, + registerPayload.lastName, + registerPayload.mobileNumber, + registerPayload.password, + registerPayload.username + ) + + Mockito.verify(dataManager).registerUser(registerPayload) + Assert.assertEquals(result, error) + } + + @Test + fun testLogin_SuccessResponseReceivedFromDataManager_ReturnsUserSuccessfully() { + val mockLoginPayload = LoginPayload().apply { + this.username = "username" + this.password = "password" + } + val successResponse : Observable = Observable.just(mockUser) + Mockito.`when`( + dataManager.login(mockLoginPayload) + ).thenReturn(successResponse) + + val result = userAuthRepositoryImp.login("username", "password") + + Mockito.verify(dataManager).login(mockLoginPayload) + Assert.assertEquals(result, successResponse) + } + + @Test + fun testLogin_ErrorResponseReceivedFromDataManager_ReturnsError() { + val mockLoginPayload = LoginPayload().apply { + this.username = "username" + this.password = "password" + } + val errorResponse : Observable = Observable.error(Throwable("Login Failed")) + Mockito.`when`( + dataManager.login(mockLoginPayload) + ).thenReturn(errorResponse) + + val result = userAuthRepositoryImp.login("username", "password") + + Mockito.verify(dataManager).login(mockLoginPayload) + Assert.assertEquals(result, errorResponse) + } + + @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.authenticationToken, userVerify.requestId) + + 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.authenticationToken, userVerify.requestId) + 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/LoanAccountTransactionViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/LoanAccountTransactionViewModelTest.kt new file mode 100644 index 000000000..7f7e49a7d --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/LoanAccountTransactionViewModelTest.kt @@ -0,0 +1,103 @@ +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.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.models.accounts.loan.LoanWithAssociations +import org.mifos.mobile.repositories.LoanRepositoryImp +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.LoanUiState +import org.mockito.Mock +import org.mifos.mobile.R +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class LoanAccountTransactionViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var loanRepositoryImp: LoanRepositoryImp + + @Mock + lateinit var loanUiStateObserver: Observer + + private lateinit var viewModel: LoanAccountTransactionViewModel + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + viewModel = LoanAccountTransactionViewModel(loanRepositoryImp) + viewModel.loanUiState.observeForever(loanUiStateObserver) + } + + @Test + fun testLoadLoanAccountDetails_Successful_WithEmptyTransaction() { + val response = mock(LoanWithAssociations::class.java) + `when`( + loanRepositoryImp.getLoanWithAssociations( + Constants.TRANSACTIONS, + 1 + ) + ).thenReturn(Observable.just(response)) + + viewModel.loadLoanAccountDetails(1) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.ShowEmpty(response)) + verifyNoMoreInteractions(loanUiStateObserver) + } + + @Test + fun testLoadLoanAccountDetails_Successful_WithNonEmptyTransaction() { + val response = mock(LoanWithAssociations::class.java) + + `when`( + loanRepositoryImp.getLoanWithAssociations( + Constants.TRANSACTIONS, + 1 + ) + ).thenReturn(Observable.just(response)) + + viewModel.loadLoanAccountDetails(1) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + if (response.transactions != null && response?.transactions?.isNotEmpty() == true) { + verify(loanUiStateObserver).onChanged(LoanUiState.ShowLoan(response)) + verifyNoMoreInteractions(loanUiStateObserver) + } + } + + @Test + fun testLoadLoanAccountDetails_Unsuccessful() { + val error = RuntimeException("Error Response") + `when`( + loanRepositoryImp.getLoanWithAssociations( + Constants.TRANSACTIONS, + 1 + ) + ).thenReturn(Observable.error(error)) + + viewModel.loadLoanAccountDetails(1) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.ShowError(R.string.loan_account_details)) + verifyNoMoreInteractions(loanUiStateObserver) + } + + @After + fun tearDown() { + viewModel.loanUiState.removeObserver(loanUiStateObserver) + } + +} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/LoanAccountWithdrawViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/LoanAccountWithdrawViewModelTest.kt new file mode 100644 index 000000000..a3c945259 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/LoanAccountWithdrawViewModelTest.kt @@ -0,0 +1,84 @@ +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.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.models.accounts.loan.LoanWithdraw +import org.mifos.mobile.repositories.LoanRepositoryImp +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.LoanUiState +import org.mockito.Mock +import org.mifos.mobile.R +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class LoanAccountWithdrawViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var loanRepositoryImp: LoanRepositoryImp + + @Mock + lateinit var loanUiStateObserver: Observer + + private lateinit var viewModel: LoanAccountWithdrawViewModel + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + viewModel = LoanAccountWithdrawViewModel(loanRepositoryImp) + viewModel.loanUiState.observeForever(loanUiStateObserver) + } + + @Test + fun testWithdrawLoanAccount_Successful() { + val response = mock(ResponseBody::class.java) + val mockLoanWithdraw = mock(LoanWithdraw::class.java) + `when`( + loanRepositoryImp.withdrawLoanAccount( + 1, + mockLoanWithdraw + ) + ).thenReturn(Observable.just(response)) + viewModel.withdrawLoanAccount(1, mockLoanWithdraw) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.WithdrawSuccess) + verifyNoMoreInteractions(loanUiStateObserver) + } + + @Test + fun testWithdrawLoanAccount_Unsuccessful() { + val error = RuntimeException("Error Response") + val mockLoanWithdraw = mock(LoanWithdraw::class.java) + `when`( + loanRepositoryImp.withdrawLoanAccount( + 1, + mockLoanWithdraw + ) + ).thenReturn(Observable.error(error)) + viewModel.withdrawLoanAccount(1, mockLoanWithdraw) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.ShowError(R.string.error_loan_account_withdraw)) + verifyNoMoreInteractions(loanUiStateObserver) + } + + @After + fun tearDown() { + viewModel.loanUiState.removeObserver(loanUiStateObserver) + } + +} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/LoanAccountsDetailViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/LoanAccountsDetailViewModelTest.kt new file mode 100644 index 000000000..f2bcf7164 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/LoanAccountsDetailViewModelTest.kt @@ -0,0 +1,85 @@ +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.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.R +import org.mifos.mobile.models.accounts.loan.LoanWithAssociations +import org.mifos.mobile.repositories.LoanRepositoryImp +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.LoanUiState +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + + +@RunWith(MockitoJUnitRunner::class) +class LoanAccountsDetailViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var loanRepositoryImp: LoanRepositoryImp + + @Mock + lateinit var loanUiStateObserver: Observer + + lateinit var viewModel: LoanAccountsDetailViewModel + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + viewModel = LoanAccountsDetailViewModel(loanRepositoryImp) + viewModel.loanUiState.observeForever(loanUiStateObserver) + } + + @Test + fun testLoadLoanAccountDetails_Successful() { + val response = mock(LoanWithAssociations::class.java) + + `when`( + loanRepositoryImp.getLoanWithAssociations( + Constants.REPAYMENT_SCHEDULE, + 1 + ) + ).thenReturn(Observable.just(response)) + + viewModel.loadLoanAccountDetails(1) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.ShowLoan(response)) + verifyNoMoreInteractions(loanUiStateObserver) + } + + @Test + fun testLoadLoanAccountDetails_Unsuccessful() { + val error = RuntimeException("Error Response") + `when`( + loanRepositoryImp.getLoanWithAssociations( + Constants.REPAYMENT_SCHEDULE, + 1 + ) + ).thenReturn(Observable.error(error)) + + viewModel.loadLoanAccountDetails(1) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.ShowError(R.string.loan_account_details)) + verifyNoMoreInteractions(loanUiStateObserver) + } + + @After + fun tearDown() { + viewModel.loanUiState.removeObserver(loanUiStateObserver) + } +} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/LoanApplicationViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/LoanApplicationViewModelTest.kt new file mode 100644 index 000000000..93984dda6 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/LoanApplicationViewModelTest.kt @@ -0,0 +1,117 @@ +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.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.R +import org.mifos.mobile.models.templates.loans.LoanTemplate +import org.mifos.mobile.repositories.LoanRepositoryImp +import org.mifos.mobile.ui.enums.LoanState +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.LoanUiState +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class LoanApplicationViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var loanRepositoryImp: LoanRepositoryImp + + @Mock + lateinit var loanUiStateObserver: Observer + + private lateinit var viewModel: LoanApplicationViewModel + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + viewModel = LoanApplicationViewModel(loanRepositoryImp) + viewModel.loanUiState.observeForever(loanUiStateObserver) + } + + @Test + fun testLoadLoanApplicationTemplate_Successful() { + val response = mock(LoanTemplate::class.java) + val mockLoanState = mock(LoanState::class.java) + `when`(loanRepositoryImp.template()).thenReturn(Observable.just(response)) + viewModel.loadLoanApplicationTemplate(mockLoanState) + + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + if (mockLoanState == LoanState.CREATE) { + verify(loanUiStateObserver).onChanged(LoanUiState.ShowLoanTemplateByProduct(response)) + verifyNoMoreInteractions(loanUiStateObserver) + } else { + verify(loanUiStateObserver).onChanged( + LoanUiState.ShowUpdateLoanTemplateByProduct( + response + ) + ) + verifyNoMoreInteractions(loanUiStateObserver) + } + } + + @Test + fun testLoadLoanApplicationTemplate_Unsuccessful() { + val error = RuntimeException("Error Response") + val loanState = mock(LoanState::class.java) + `when`(loanRepositoryImp.template()).thenReturn(Observable.error(error)) + viewModel.loadLoanApplicationTemplate(loanState) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.ShowError(R.string.error_fetching_template)) + verifyNoMoreInteractions(loanUiStateObserver) + } + + @Test + fun loadLoanApplicationTemplateByProduct_Successful() { + val response = mock(LoanTemplate::class.java) + val mockLoanState = mock(LoanState::class.java) + + `when`(loanRepositoryImp.getLoanTemplateByProduct(1)).thenReturn(Observable.just(response)) + viewModel.loadLoanApplicationTemplateByProduct(1, mockLoanState) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + if (mockLoanState == LoanState.CREATE) { + verify(loanUiStateObserver).onChanged(LoanUiState.ShowLoanTemplate(response)) + verifyNoMoreInteractions(loanUiStateObserver) + } else { + verify(loanUiStateObserver).onChanged( + LoanUiState.ShowUpdateLoanTemplate( + response + ) + ) + verifyNoMoreInteractions(loanUiStateObserver) + } + + } + + @Test + fun loadLoanApplicationTemplateByProduct_Unsuccessful() { + val error = RuntimeException("Error Response") + val mockLoanState = mock(LoanState::class.java) + `when`(loanRepositoryImp.getLoanTemplateByProduct(1)).thenReturn(Observable.error(error)) + viewModel.loadLoanApplicationTemplateByProduct(1, mockLoanState) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.ShowError(R.string.error_fetching_template)) + verifyNoMoreInteractions(loanUiStateObserver) + } + + @After + fun tearDown() { + viewModel.loanUiState.removeObserver(loanUiStateObserver) + } + +} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/LoanRepaymentScheduleViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/LoanRepaymentScheduleViewModelTest.kt new file mode 100644 index 000000000..d6fee83a5 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/LoanRepaymentScheduleViewModelTest.kt @@ -0,0 +1,90 @@ +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.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mifos.mobile.models.accounts.loan.LoanWithAssociations +import org.mifos.mobile.repositories.LoanRepositoryImp +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.LoanUiState +import org.mockito.Mock +import org.mifos.mobile.R +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class LoanRepaymentScheduleViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var loanRepositoryImp: LoanRepositoryImp + + @Mock + lateinit var loanUiStateObserver: Observer + + private lateinit var viewModel: LoanRepaymentScheduleViewModel + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + viewModel = LoanRepaymentScheduleViewModel(loanRepositoryImp) + viewModel.loanUiState.observeForever(loanUiStateObserver) + } + + @Test + fun testLoanLoanWithAssociations_Successful() { + val response = mock(LoanWithAssociations::class.java) + `when`( + loanRepositoryImp.getLoanWithAssociations( + Constants.REPAYMENT_SCHEDULE, + 1 + ) + ).thenReturn(Observable.just(response)) + + viewModel.loanLoanWithAssociations(1) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + if (response.repaymentSchedule?.periods?.isNotEmpty() == true) { + verify(loanUiStateObserver).onChanged(LoanUiState.ShowLoan(response)) + verifyNoMoreInteractions(loanUiStateObserver) + } else { + verify(loanUiStateObserver).onChanged(LoanUiState.ShowEmpty(response)) + verifyNoMoreInteractions(loanUiStateObserver) + } + } + + @Test + fun testLoanLoanWithAssociations_Unsuccessful() { + val error = RuntimeException("Error Response") + `when`( + loanRepositoryImp.getLoanWithAssociations( + Constants.REPAYMENT_SCHEDULE, + 1 + ) + ).thenReturn( + Observable.error(error) + ) + viewModel.loanLoanWithAssociations(1) + verify(loanUiStateObserver).onChanged(LoanUiState.Loading) + verify(loanUiStateObserver).onChanged(LoanUiState.ShowError(R.string.repayment_schedule)) + } + + @After + fun tearDown() { + viewModel.loanUiState.removeObserver(loanUiStateObserver) + } + + +} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/LoginViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/LoginViewModelTest.kt new file mode 100644 index 000000000..f8934bb23 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/LoginViewModelTest.kt @@ -0,0 +1,184 @@ +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.FakeRemoteDataSource +import org.mifos.mobile.models.Page +import org.mifos.mobile.models.User +import org.mifos.mobile.models.client.Client +import org.mifos.mobile.repositories.ClientRepository +import org.mifos.mobile.repositories.UserAuthRepository +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.LoginUiState +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 LoginViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var userAuthRepositoryImp : UserAuthRepository + + @Mock + lateinit var clientRepositoryImp : ClientRepository + + @Mock + lateinit var loginUiStateObserver : Observer + + private lateinit var mockUser : User + private lateinit var loginViewModel : LoginViewModel + private var emptyClientPage : Page? = null + private var clientPage : Page? = null + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + loginViewModel = LoginViewModel(userAuthRepositoryImp, clientRepositoryImp) + loginViewModel.loginUiState.observeForever(loginUiStateObserver) + mockUser = FakeRemoteDataSource.user + emptyClientPage = FakeRemoteDataSource.noClients + clientPage = FakeRemoteDataSource.clients + } + + @Test + fun testIsFieldEmpty_WithNonEmptyStringInput_ReturnsFalse() { + val result = loginViewModel.isFieldEmpty("nonEmptyTestString") + Assert.assertFalse(result) + } + + @Test + fun testIsFieldEmpty_WithEmptyStringInput_ReturnsTrue() { + val result = loginViewModel.isFieldEmpty("") + Assert.assertTrue(result) + } + + @Test + fun testIsUsernameLengthInadequate_WithAdequateLengthInput_ReturnsFalse() { + val result = loginViewModel.isUsernameLengthInadequate("username123") + Assert.assertFalse(result) + } + + @Test + fun testIsUsernameLengthInadequate_WithInadequateLengthInput_ReturnsTrue() { + val result = loginViewModel.isUsernameLengthInadequate("user") + Assert.assertTrue(result) + } + + @Test + fun testIsPasswordLengthInadequate_WithAdequateLengthInput_ReturnsFalse() { + val result = loginViewModel.isUsernameLengthInadequate("password123") + Assert.assertFalse(result) + } + + @Test + fun testIsPasswordLengthInadequate_WithInadequateLengthInput_ReturnsTrue() { + val result = loginViewModel.isUsernameLengthInadequate("pass") + Assert.assertTrue(result) + } + + @Test + fun testUsernameHasSpaces_WithSpacesInput_ReturnsTrue() { + val result = loginViewModel.usernameHasSpaces("username withSpace") + Assert.assertTrue(result) + } + + @Test + fun testUsernameHasSpaces_WithNoSpacesInput_ReturnsFalse() { + val result = loginViewModel.usernameHasSpaces("usernameNoSpaces") + Assert.assertFalse(result) + } + + @Test + fun testLogin_SuccessfulLoginReceivedFromRepository_ReturnsLoginSuccess() { + Mockito.`when`( + userAuthRepositoryImp.login(Mockito.anyString(), Mockito.anyString()) + ).thenReturn(Observable.just(mockUser)) + + loginViewModel.login("username", "password") + + Mockito.verify(loginUiStateObserver).onChanged(LoginUiState.Loading) + Mockito.verify(clientRepositoryImp).saveAuthenticationTokenForSession(mockUser) + Mockito.verify(loginUiStateObserver).onChanged(LoginUiState.LoginSuccess) + Mockito.verifyNoMoreInteractions(loginUiStateObserver) + } + + @Test + fun testLogin_UnsuccessfulLoginReceivedFromRepository_ReturnsError() { + val error = RuntimeException("Login Failed") + Mockito.`when`( + userAuthRepositoryImp.login(Mockito.anyString(), Mockito.anyString()) + ).thenReturn(Observable.error(error)) + + loginViewModel.login("username", "password") + + Mockito.verify(loginUiStateObserver).onChanged(LoginUiState.Loading) + Mockito.verify(loginUiStateObserver).onChanged(LoginUiState.Error) + Mockito.verifyNoMoreInteractions(loginUiStateObserver) + } + + @Test + fun testLoadClient_UnsuccessfulLoadClientReceivedFromRepository_ReturnsError() { + val error = RuntimeException("Load Client Failed") + Mockito.`when`( + clientRepositoryImp.loadClient() + ).thenReturn(Observable.error(error)) + + loginViewModel.loadClient() + + Mockito.verify(loginUiStateObserver).onChanged(LoginUiState.Error) + Mockito.verify(clientRepositoryImp).clearPrefHelper() + Mockito.verify(clientRepositoryImp).reInitializeService() + Mockito.verifyNoMoreInteractions(loginUiStateObserver) + } + + @Test + fun testLoadClient_EmptyClientPageReceivedFromRepository_ReturnsError() { + Mockito.`when`( + clientRepositoryImp.loadClient() + ).thenReturn(Observable.just(emptyClientPage)) + + loginViewModel.loadClient() + + Mockito.verify(loginUiStateObserver).onChanged(LoginUiState.Error) + Mockito.verifyNoMoreInteractions(loginUiStateObserver) + } + + @Test + fun testLoadClient_NonEmptyClientPageReceivedFromRepository_ReturnsLoadClientSuccess() { + val clientId = clientPage?.pageItems?.get(0)?.id?.toLong() + val clientName = clientPage?.pageItems?.get(0)?.displayName + Mockito.`when`( + clientRepositoryImp.loadClient() + ).thenReturn(Observable.just(clientPage)) + + loginViewModel.loadClient() + + Mockito.verify(clientRepositoryImp).setClientId(clientId) + Mockito.verify(clientRepositoryImp).reInitializeService() + Mockito.verify(loginUiStateObserver).onChanged(LoginUiState.LoadClientSuccess(clientName)) + Mockito.verifyNoMoreInteractions(loginUiStateObserver) + } + + @After + fun tearDown() { + loginViewModel.loginUiState.removeObserver(loginUiStateObserver) + } +} \ 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 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 diff --git a/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt new file mode 100644 index 000000000..322322961 --- /dev/null +++ b/app/src/test/java/org/mifos/mobile/viewModels/RegistrationViewModelTest.kt @@ -0,0 +1,211 @@ +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.UserAuthRepository +import org.mifos.mobile.util.RxSchedulersOverrideRule +import org.mifos.mobile.utils.RegistrationUiState +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 RegistrationViewModelTest { + + @JvmField + @Rule + val mOverrideSchedulersRule = RxSchedulersOverrideRule() + + @get:Rule + val rule = InstantTaskExecutorRule() + + @Mock + lateinit var userAuthRepositoryImp: UserAuthRepository + + @Mock + lateinit var registrationUiStateObserver: Observer + + @Mock + lateinit var registrationVerificationUiStateObserver: Observer + + private lateinit var registrationViewModel: RegistrationViewModel + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + registrationViewModel = RegistrationViewModel(userAuthRepositoryImp) + registrationViewModel.registrationUiState.observeForever(registrationUiStateObserver) + registrationViewModel.registrationVerificationUiState.observeForever( + registrationVerificationUiStateObserver + ) + } + + @Test + fun testIsInputFieldBlank_WithNonEmptyStringInput_ReturnsFalse() { + val result = registrationViewModel.isInputFieldBlank("nonEmptyTestString") + Assert.assertFalse(result) + } + + @Test + fun testIsInputFieldBlank_WithEmptyStringInput_ReturnsTrue() { + val result = registrationViewModel.isInputFieldBlank("") + Assert.assertTrue(result) + } + + @Test + fun testIsInputLengthInadequate_WithAdequateLengthInput_ReturnsFalse() { + val result = registrationViewModel.isInputLengthInadequate("Password123") + Assert.assertFalse(result) + } + + @Test + fun testIsInputLengthInadequate_WithInadequateLengthInput_ReturnsTrue() { + val result = registrationViewModel.isInputLengthInadequate("") + Assert.assertTrue(result) + } + + @Test + fun testInputHasSpaces_WithSpacesInput_ReturnsTrue() { + val result = registrationViewModel.inputHasSpaces("testUpdateAuthenticationToken string") + Assert.assertTrue(result) + } + + @Test + fun testInputHasSpaces_WithNoSpacesInput_ReturnsFalse() { + val result = registrationViewModel.inputHasSpaces("testString") + Assert.assertFalse(result) + } + + @Test + fun testHasLeadingTrailingSpaces_WithLeadingTrailingSpacesInput_ReturnsTrue() { + val result = registrationViewModel.hasLeadingTrailingSpaces(" Hello World ") + Assert.assertTrue(result) + } + + @Test + fun testHasLeadingTrailingSpaces_WithoutLeadingTrailingSpacesInput_ReturnsFalse() { + val result = registrationViewModel.hasLeadingTrailingSpaces("Hello World") + Assert.assertFalse(result) + } + + @Test + fun testIsEmailInvalid_WithValidEmailInput_ReturnsFalse() { + val result = registrationViewModel.isEmailInvalid("testUpdateAuthenticationToken@example.com") + Assert.assertFalse(result) + } + + @Test + fun testIsEmailInvalid_WithInvalidEmailInput_ReturnsTrue() { + val result = registrationViewModel.isEmailInvalid("testExample.com") + Assert.assertTrue(result) + } + + + @Test + fun testRegisterUser_SuccessfulRegistrationReceivedFromRepository_ReturnsRegistrationSuccessful() { + val responseBody = Mockito.mock(ResponseBody::class.java) + Mockito.`when`( + userAuthRepositoryImp.registerUser( + Mockito.anyString(), Mockito.anyString(), + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), + Mockito.anyString(), Mockito.anyString(), + ) + ).thenReturn(Observable.just(responseBody)) + + registrationViewModel.registerUser( + "accountNumber", + "authMode", + "email", + "firstName", + "lastName", + "mobileNumber", + "password", + "userName" + ) + + Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Loading) + Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Success) + Mockito.verifyNoMoreInteractions(registrationUiStateObserver) + } + + @Test + fun testRegisterUser_UnsuccessfulRegistrationReceivedFromRepository_ReturnsRegistrationUnsuccessful() { + val error = RuntimeException("Registration Failed") + Mockito.`when`( + userAuthRepositoryImp.registerUser( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString() + ) + ).thenReturn(Observable.error(error)) + + registrationViewModel.registerUser( + "accountNumber", + "authMode", + "email", + "firstName", + "lastName", + "mobileNumber", + "password", + "username" + ) + + Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Loading) + Mockito.verify(registrationUiStateObserver).onChanged(RegistrationUiState.Error(error)) + Mockito.verifyNoMoreInteractions(registrationUiStateObserver) + } + + @Test + fun testVerifyUser_SuccessfulRegistrationVerificationReceivedFromRepository_ReturnsRegistrationVerificationSuccessful() { + Mockito.`when`( + userAuthRepositoryImp.verifyUser(Mockito.anyString(), Mockito.anyString()) + ).thenReturn(Observable.just(Mockito.mock(ResponseBody::class.java))) + + registrationViewModel.verifyUser("authenticationToken", "requestId") + + Mockito.verify(registrationVerificationUiStateObserver) + .onChanged(RegistrationUiState.Loading) + Mockito.verify(registrationVerificationUiStateObserver) + .onChanged(RegistrationUiState.Success) + Mockito.verifyNoMoreInteractions(registrationUiStateObserver) + } + + @Test + fun testVerifyUser_UnsuccessfulRegistrationVerificationReceivedFromRepository_ReturnsRegistrationVerificationUnsuccessful() { + val error = RuntimeException("RegistrationVerification Failed") + Mockito.`when`( + userAuthRepositoryImp.verifyUser(Mockito.anyString(), Mockito.anyString()) + ).thenReturn(Observable.error(error)) + + registrationViewModel.verifyUser("authenticationToken", "requestId") + + Mockito.verify(registrationVerificationUiStateObserver) + .onChanged(RegistrationUiState.Loading) + Mockito.verify(registrationVerificationUiStateObserver) + .onChanged(RegistrationUiState.Error(error)) + Mockito.verifyNoMoreInteractions(registrationUiStateObserver) + } + + @After + fun tearDown() { + registrationViewModel.registrationUiState.removeObserver(registrationUiStateObserver) + registrationViewModel.registrationVerificationUiState.removeObserver( + registrationVerificationUiStateObserver + ) + } +} \ No newline at end of file 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..d1014b4a5 --- /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.RegistrationUiState +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(RegistrationUiState.Loading) + Mockito.verify(updatePasswordUiStateObserver).onChanged(RegistrationUiState.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(RegistrationUiState.Loading) + Mockito.verify(updatePasswordUiStateObserver).onChanged(RegistrationUiState.Error(error)) + Mockito.verifyNoMoreInteractions(updatePasswordUiStateObserver) + } + + + @After + fun tearDown() { + updatePasswordViewModel.updatePasswordUiState.removeObserver(updatePasswordUiStateObserver) + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index e616b856a..f0a0d2ae9 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,9 @@ buildscript { // in the individual module build.gradle filesa } } - +plugins { + id("com.google.dagger.hilt.android") version "2.44" apply false +} allprojects { repositories { google() @@ -68,7 +70,8 @@ ext { kotlinVersion = '1.6.10' tableViewVersion = '0.8.9.4' biometric = '1.1.0' - + archCoreVersion = '2.2.0' + coroutines = '1.6.4' jUnitVersion = '4.13.2' mockitoVersion = '5.4.0' runnerVersion = '1.6.0-alpha03'