diff --git a/app/build.gradle b/app/build.gradle index 543aa9e..ef81286 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -76,6 +76,8 @@ dependencies { // acc implementation "android.arch.lifecycle:extensions:1.1.0" implementation "android.arch.lifecycle:viewmodel:1.1.0" + implementation "android.arch.lifecycle:livedata:1.1.0" + implementation "android.arch.lifecycle:reactivestreams:1.1.0" kapt "android.arch.lifecycle:compiler:1.1.0" // rx diff --git a/app/src/main/java/com/enixma/sample/charity/domain/UseCase.kt b/app/src/main/java/com/enixma/sample/charity/domain/UseCase.kt index 6841bb6..10b4dfb 100644 --- a/app/src/main/java/com/enixma/sample/charity/domain/UseCase.kt +++ b/app/src/main/java/com/enixma/sample/charity/domain/UseCase.kt @@ -1,10 +1,10 @@ package com.enixma.sample.charity.domain -import io.reactivex.Observable +import io.reactivex.Flowable interface UseCase { - fun execute(request: P): Observable + fun execute(request: P): Flowable interface Request diff --git a/app/src/main/java/com/enixma/sample/charity/domain/createdonation/CreateDonationUseCase.kt b/app/src/main/java/com/enixma/sample/charity/domain/createdonation/CreateDonationUseCase.kt index 6fd6550..a3ecc74 100644 --- a/app/src/main/java/com/enixma/sample/charity/domain/createdonation/CreateDonationUseCase.kt +++ b/app/src/main/java/com/enixma/sample/charity/domain/createdonation/CreateDonationUseCase.kt @@ -2,27 +2,30 @@ package com.enixma.sample.charity.domain.createdonation import com.enixma.sample.charity.data.repository.ICharityRepository import com.enixma.sample.charity.domain.UseCase -import io.reactivex.Observable +import io.reactivex.BackpressureStrategy +import io.reactivex.Flowable import javax.inject.Inject class CreateDonationUseCase @Inject constructor(private val charityRepository: ICharityRepository) : UseCase { enum class STATUS { + LOADING, SUCCESS, FAIL } - override fun execute(request: CreateDonationUseCaseRequest): Observable { - return charityRepository.createDonation(request.donationEntity) - .flatMap { - val result = it.let { - val status = if (it.statusCode == 201 && it.isSuccess) STATUS.SUCCESS else STATUS.FAIL - CreateDonationUseCaseResult(status).apply { - if (this.status == STATUS.FAIL) this.errorMessage = it.errorMessage - } - } - Observable.just(result) - } - + override fun execute(request: CreateDonationUseCaseRequest): Flowable { + return Flowable.just(CreateDonationUseCaseResult(STATUS.LOADING)).concatWith( + charityRepository.createDonation(request.donationEntity) + .toFlowable(BackpressureStrategy.LATEST) + .flatMap { + val result = it.let { + val status = if (it.statusCode == 201 && it.isSuccess) STATUS.SUCCESS else STATUS.FAIL + CreateDonationUseCaseResult(status).apply { + if (this.status == STATUS.FAIL) this.errorMessage = it.errorMessage + } + } + Flowable.just(result) + }) } } \ No newline at end of file diff --git a/app/src/main/java/com/enixma/sample/charity/domain/getcharitylist/GetCharityListUseCase.kt b/app/src/main/java/com/enixma/sample/charity/domain/getcharitylist/GetCharityListUseCase.kt index 0d605fd..fb11159 100644 --- a/app/src/main/java/com/enixma/sample/charity/domain/getcharitylist/GetCharityListUseCase.kt +++ b/app/src/main/java/com/enixma/sample/charity/domain/getcharitylist/GetCharityListUseCase.kt @@ -2,25 +2,29 @@ package com.enixma.sample.charity.domain.getcharitylist import com.enixma.sample.charity.data.repository.ICharityRepository import com.enixma.sample.charity.domain.UseCase -import io.reactivex.Observable +import io.reactivex.BackpressureStrategy +import io.reactivex.Flowable import javax.inject.Inject class GetCharityListUseCase @Inject constructor(private val charityRepository: ICharityRepository) : UseCase { enum class STATUS { + LOADING, SUCCESS, NO_DATA_FOUND } - override fun execute(request: GetCharityListUseCaseRequest): Observable { - return charityRepository.getCharityList() - .flatMap { - val result = it.let { - val status = if (it.total <= 0) STATUS.NO_DATA_FOUND else STATUS.SUCCESS - val charityList = it.data - GetCharityListUseCaseResult(status, charityList) - } - Observable.just(result) - } + override fun execute(request: GetCharityListUseCaseRequest): Flowable { + return Flowable.just(GetCharityListUseCaseResult(STATUS.LOADING, mutableListOf())).concatWith( + charityRepository.getCharityList() + .toFlowable(BackpressureStrategy.LATEST) + .flatMap { + val result = it.let { + val status = if (it.total <= 0) STATUS.NO_DATA_FOUND else STATUS.SUCCESS + val charityList = it.data + GetCharityListUseCaseResult(status, charityList) + } + Flowable.just(result) + }) } } \ No newline at end of file diff --git a/app/src/main/java/com/enixma/sample/charity/domain/validatecreditcard/ValidateCreditCardUseCase.kt b/app/src/main/java/com/enixma/sample/charity/domain/validatecreditcard/ValidateCreditCardUseCase.kt index e3492d0..6cbe9d3 100644 --- a/app/src/main/java/com/enixma/sample/charity/domain/validatecreditcard/ValidateCreditCardUseCase.kt +++ b/app/src/main/java/com/enixma/sample/charity/domain/validatecreditcard/ValidateCreditCardUseCase.kt @@ -2,6 +2,7 @@ package com.enixma.sample.charity.domain.validatecreditcard import co.omise.android.CardNumber import com.enixma.sample.charity.domain.UseCase +import io.reactivex.Flowable import io.reactivex.Observable class ValidateCreditCardUseCase : UseCase { @@ -18,7 +19,7 @@ class ValidateCreditCardUseCase : UseCase { + override fun execute(request: ValidateCreditCardUseCaseRequest): Flowable { val errorList = ArrayList() validateCard(request.cardNumber, errorList) @@ -27,7 +28,7 @@ class ValidateCreditCardUseCase : UseCase = MutableLiveData() + private var resultObserver: Observer + + init { + resultObserver = Observer { result -> + processGetCharityListResult(result) + } + } override fun getCharityList() { - if (isLoading) { + if (result.value?.status == GetCharityListUseCase.STATUS.LOADING) { return } - isLoading = true - getCharityListDisposable = getCharityListUseCase.execute(GetCharityListUseCaseRequest()) - .doOnNext { result -> processGetCharityListResult(result) } - .subscribe() + result = LiveDataReactiveStreams.fromPublisher(getCharityListUseCase.execute(GetCharityListUseCaseRequest())) + result.observe(lifecycleOwner, resultObserver) } - private fun processGetCharityListResult(result: GetCharityListUseCaseResult) { - isLoading = false - if (result.status == GetCharityListUseCase.STATUS.SUCCESS) { - view.populateList(result.charityList) - } else { - view.displayNoData() + private fun processGetCharityListResult(result: GetCharityListUseCaseResult?) { + result?.let { + when (it.status) { + GetCharityListUseCase.STATUS.LOADING -> { + // do nothing + } + GetCharityListUseCase.STATUS.SUCCESS -> { + view.populateList(it.charityList) + } + else -> { + view.displayNoData() + } + } } } - - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) - fun onPresenterDestroy() { - getCharityListDisposable?.dispose() - } } \ No newline at end of file diff --git a/app/src/main/java/com/enixma/sample/charity/presentation/charitylist/di/CharityListModule.kt b/app/src/main/java/com/enixma/sample/charity/presentation/charitylist/di/CharityListModule.kt index 370ccb7..6837a66 100644 --- a/app/src/main/java/com/enixma/sample/charity/presentation/charitylist/di/CharityListModule.kt +++ b/app/src/main/java/com/enixma/sample/charity/presentation/charitylist/di/CharityListModule.kt @@ -1,5 +1,6 @@ package com.enixma.sample.charity.presentation.charitylist.di +import android.arch.lifecycle.LifecycleOwner import com.enixma.sample.charity.domain.getcharitylist.GetCharityListUseCase import com.enixma.sample.charity.presentation.charitylist.CharityListContract import com.enixma.sample.charity.presentation.charitylist.CharityListPresenter @@ -8,10 +9,10 @@ import dagger.Provides import javax.inject.Inject @Module -class CharityListModule(private val view: CharityListContract.View) { +class CharityListModule(private val view: CharityListContract.View, private val lifecycleOwner: LifecycleOwner) { @Provides @Inject fun provideCharityListPresenter(getCharityListUseCase: GetCharityListUseCase): CharityListContract.Action { - return CharityListPresenter(view, getCharityListUseCase) + return CharityListPresenter(view, lifecycleOwner, getCharityListUseCase) } } diff --git a/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationContract.kt b/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationContract.kt index d38ff86..1525af0 100644 --- a/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationContract.kt +++ b/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationContract.kt @@ -5,7 +5,8 @@ import co.omise.android.models.Token interface DonationContract { interface View { fun displayError(errorMessage: String) - + fun displayLoading() + fun dismissLoading() fun goToSuccessScreen() } diff --git a/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationFragment.kt b/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationFragment.kt index d821f7c..5818d72 100644 --- a/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationFragment.kt +++ b/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationFragment.kt @@ -13,6 +13,7 @@ import android.view.View import android.view.ViewGroup import co.omise.android.models.Token import com.bumptech.glide.Glide +import com.enixma.sample.charity.BuildConfig import com.enixma.sample.charity.R import com.enixma.sample.charity.data.di.ServiceFactoryModule import com.enixma.sample.charity.data.di.CharityDataModule @@ -21,6 +22,7 @@ import com.enixma.sample.charity.presentation.creditcard.AddCreditCardActivity import com.enixma.sample.charity.presentation.donation.di.DaggerDonationComponent import com.enixma.sample.charity.presentation.donation.di.DonationModule import com.enixma.sample.charity.presentation.success.SuccessActivity +import org.json.JSONObject import javax.inject.Inject @@ -61,7 +63,7 @@ class DonationFragment : Fragment(), DonationContract.View { DaggerDonationComponent.builder() .serviceFactoryModule(ServiceFactoryModule(activity)) .charityDataModule(CharityDataModule(activity)) - .donationModule(DonationModule(this, viewModel)) + .donationModule(DonationModule(this, this, viewModel)) .build().inject(this) } @@ -74,7 +76,6 @@ class DonationFragment : Fragment(), DonationContract.View { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - lifecycle.addObserver(presenter as DonationPresenter) initProgressDialog() initDonationAmountSelection() populateImage() @@ -82,10 +83,24 @@ class DonationFragment : Fragment(), DonationContract.View { displayAmountSelectionDialog() } binding.buttonDonate.setOnClickListener { - displayConfirmDialog() + if(!BuildConfig.DEBUG){ + displayConfirmDialog() + } else { + // skip add credit card + presenter.donate(Token(JSONObject())) + progressDialog.show() + } } } + override fun displayLoading() { + progressDialog.show() + } + + override fun dismissLoading() { + progressDialog.dismiss() + } + private fun initProgressDialog() { progressDialog = ProgressDialog(activity) progressDialog.setMessage(getString(R.string.alert_message_submit_donation)) @@ -141,12 +156,10 @@ class DonationFragment : Fragment(), DonationContract.View { } override fun goToSuccessScreen() { - progressDialog.dismiss() startActivityForResult(SuccessActivity.getIntent(activity, viewModel.name, viewModel.amount.get()), REQUEST_FINAL) } override fun displayError(errorMessage: String) { - progressDialog.dismiss() alertDialog = AlertDialog.Builder(activity).apply { var message = if (errorMessage.isNullOrBlank()) getString(R.string.alert_message_communication_error) else errorMessage this.setTitle(R.string.alert_title_error) diff --git a/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationPresenter.kt b/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationPresenter.kt index c050574..6d6da56 100644 --- a/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationPresenter.kt +++ b/app/src/main/java/com/enixma/sample/charity/presentation/donation/DonationPresenter.kt @@ -1,50 +1,58 @@ package com.enixma.sample.charity.presentation.donation -import android.arch.lifecycle.Lifecycle -import android.arch.lifecycle.LifecycleObserver -import android.arch.lifecycle.OnLifecycleEvent +import android.arch.lifecycle.* import co.omise.android.models.Token import com.enixma.sample.charity.data.entity.DonationEntity import com.enixma.sample.charity.domain.createdonation.CreateDonationUseCase import com.enixma.sample.charity.domain.createdonation.CreateDonationUseCaseRequest import com.enixma.sample.charity.domain.createdonation.CreateDonationUseCaseResult -import io.reactivex.disposables.Disposable class DonationPresenter(private val view: DonationContract.View, + private val lifecycleOwner: LifecycleOwner, private val viewModel: DonationViewModel, - private val createDonationUseCase: CreateDonationUseCase) : DonationContract.Action, LifecycleObserver { + private val createDonationUseCase: CreateDonationUseCase) : DonationContract.Action { - private var createDonationDisposable: Disposable? = null - private var isLoading: Boolean = false + private var result: LiveData = MutableLiveData() + private var resultObserver: Observer + + init { + resultObserver = Observer { result -> + processDonationResult(result) + } + } override fun donate(token: Token) { - if (isLoading) { + + if(result.value?.status == CreateDonationUseCase.STATUS.LOADING){ return } - isLoading = true val request = DonationEntity().let { it.name = viewModel.name - it.token = token.id + it.token = token.id ?: "" it.amount = Integer.parseInt(viewModel.amount.get()) CreateDonationUseCaseRequest(it) } - createDonationDisposable = createDonationUseCase.execute(request) - .doOnNext { result -> processDonationResult(result) } - .subscribe() - } - private fun processDonationResult(result: CreateDonationUseCaseResult) { - isLoading = false - if (result.status == CreateDonationUseCase.STATUS.SUCCESS) { - view.goToSuccessScreen() - } else { - view.displayError(result.errorMessage) - } + result = LiveDataReactiveStreams.fromPublisher(createDonationUseCase.execute(request)) + result.observe(lifecycleOwner, resultObserver) } - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) - fun onPresenterDestroy() { - createDonationDisposable?.dispose() + private fun processDonationResult(result: CreateDonationUseCaseResult?) { + result?.let { + when(it.status) { + CreateDonationUseCase.STATUS.LOADING -> { + view.displayLoading() + } + CreateDonationUseCase.STATUS.SUCCESS -> { + view.dismissLoading() + view.goToSuccessScreen() + } + else -> { + view.dismissLoading() + view.displayError(it.errorMessage) + } + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/enixma/sample/charity/presentation/donation/di/DonationModule.kt b/app/src/main/java/com/enixma/sample/charity/presentation/donation/di/DonationModule.kt index 3121e7e..6c90098 100644 --- a/app/src/main/java/com/enixma/sample/charity/presentation/donation/di/DonationModule.kt +++ b/app/src/main/java/com/enixma/sample/charity/presentation/donation/di/DonationModule.kt @@ -1,5 +1,6 @@ package com.enixma.sample.charity.presentation.donation.di +import android.arch.lifecycle.LifecycleOwner import com.enixma.sample.charity.domain.createdonation.CreateDonationUseCase import com.enixma.sample.charity.presentation.donation.DonationContract import com.enixma.sample.charity.presentation.donation.DonationPresenter @@ -9,11 +10,13 @@ import dagger.Provides import javax.inject.Inject @Module -class DonationModule(private val view: DonationContract.View, private val viewModel: DonationViewModel) { +class DonationModule(private val view: DonationContract.View, + private val lifecycleOwner: LifecycleOwner, + private val viewModel: DonationViewModel) { @Provides @Inject fun provideDonationPresenter(createDonationUseCase: CreateDonationUseCase): DonationContract.Action { - return DonationPresenter(view, viewModel, createDonationUseCase) + return DonationPresenter(view, lifecycleOwner, viewModel, createDonationUseCase) } }