Skip to content

Commit

Permalink
Create Event indicators component, model, fragment and presenter
Browse files Browse the repository at this point in the history
  • Loading branch information
xurxodev committed Dec 6, 2019
1 parent 87e5019 commit a647b08
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.dhis2.usescases.eventsWithoutRegistration.eventCapture;

import org.dhis2.data.dagger.PerActivity;
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.indicators.EventIndicatorsComponent;
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.indicators.EventIndicatorsModule;

import androidx.annotation.NonNull;
import dagger.Subcomponent;

/**
Expand All @@ -10,5 +13,8 @@
@PerActivity
@Subcomponent(modules = EventCaptureModule.class)
public interface EventCaptureComponent {
@NonNull
EventIndicatorsComponent plus(EventIndicatorsModule eventIndicatorsModule);

void inject(EventCaptureActivity activity);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.dhis2.usescases.eventsWithoutRegistration.eventCapture.indicators

import dagger.Subcomponent
import org.dhis2.data.dagger.PerFragment

@PerFragment
@Subcomponent(modules = [EventIndicatorsModule::class])
interface EventIndicatorsComponent {
fun inject(eventIndicatorsDialogFragment: EventIndicatorsDialogFragment?)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.dhis2.usescases.eventsWithoutRegistration.eventCapture.indicators

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.FragmentManager
import io.reactivex.functions.Consumer
import org.dhis2.App
import org.dhis2.R
import org.dhis2.data.tuples.Trio
import org.dhis2.databinding.DialogEventIndicatorsBinding
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.EventCaptureActivity
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.EventCaptureModule
import org.dhis2.usescases.general.DialogFragmentGlobalAbstract
import org.dhis2.usescases.teiDashboard.dashboardfragments.indicators.IndicatorsAdapter
import org.hisp.dhis.android.core.program.ProgramIndicator
import javax.inject.Inject

class EventIndicatorsDialogFragment : DialogFragmentGlobalAbstract(),
EventIndicatorsContracts.View {

@Inject
lateinit var presenter: EventIndicatorsContracts.Presenter

private lateinit var binding: DialogEventIndicatorsBinding
private lateinit var adapter: IndicatorsAdapter

override fun onAttach(context: Context) {
super.onAttach(context)
val activity = context as EventCaptureActivity
if ((context.applicationContext as App).userComponent() != null) {
(context.applicationContext as App)
.userComponent()?.plus(EventCaptureModule(activity.eventUid,
activity.programUid))
?.plus(
EventIndicatorsModule(
activity.programUid,
activity.eventUid
)
)?.inject(this)
}
}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.dialog_event_indicators, container, false)
adapter = IndicatorsAdapter()
binding.indicatorsRecycler.adapter = adapter
return binding.root
}

override fun onResume() {
super.onResume()
binding.spinner.visibility = View.VISIBLE
presenter.init(this)
}

override fun onPause() {
presenter.onDettach()
super.onPause()
}

override fun onStart() {
dialog!!.window.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
super.onStart()
}

fun show(fragmentManager: FragmentManager) {
show(fragmentManager, TAG)
}

override fun swapIndicators(): Consumer<List<Trio<ProgramIndicator, String, String>>> {
return Consumer { indicators: List<Trio<ProgramIndicator, String, String>>? ->
adapter.setIndicators(indicators)

binding.spinner.visibility = View.GONE
if (indicators != null && indicators.isNotEmpty()) {
binding.emptyIndicators.visibility = View.GONE
} else {
binding.emptyIndicators.visibility = View.VISIBLE
}
}
}

companion object {
private val TAG = EventIndicatorsDialogFragment::class.java.simpleName

fun create(): EventIndicatorsDialogFragment {
return EventIndicatorsDialogFragment()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.dhis2.usescases.eventsWithoutRegistration.eventCapture.indicators

import com.squareup.sqlbrite2.BriteDatabase
import dagger.Module
import dagger.Provides
import org.dhis2.data.dagger.PerFragment
import org.dhis2.data.forms.FormRepository
import org.dhis2.data.forms.dataentry.EventsRuleEngineRepository
import org.dhis2.data.forms.dataentry.RuleEngineRepository
import org.dhis2.data.schedulers.SchedulerProvider
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.EventCaptureContract.EventCaptureRepository
import org.hisp.dhis.android.core.D2

@PerFragment
@Module
class EventIndicatorsModule(private val programUid: String, private val eventUid: String) {
@Provides
@PerFragment
fun providesPresenter(
d2: D2,
eventCaptureRepository: EventCaptureRepository,
ruleEngineRepository: RuleEngineRepository,
schedulerProvider: SchedulerProvider
): EventIndicatorsContracts.Presenter {
return EventIndicatorsPresenter(
d2,
programUid,
eventUid,
eventCaptureRepository,
ruleEngineRepository,
schedulerProvider
)
}

@Provides
@PerFragment
fun ruleEngineRepository(
briteDatabase: BriteDatabase,
formRepository: FormRepository
): RuleEngineRepository {
return EventsRuleEngineRepository(briteDatabase, formRepository, eventUid)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package org.dhis2.usescases.eventsWithoutRegistration.eventCapture.indicators

import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Consumer
import org.dhis2.data.forms.dataentry.RuleEngineRepository
import org.dhis2.data.schedulers.SchedulerProvider
import org.dhis2.data.tuples.Pair
import org.dhis2.data.tuples.Trio
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.EventCaptureContract.EventCaptureRepository
import org.dhis2.utils.Result
import org.hisp.dhis.android.core.D2
import org.hisp.dhis.android.core.program.ProgramIndicator
import org.hisp.dhis.rules.models.RuleActionDisplayKeyValuePair
import org.hisp.dhis.rules.models.RuleActionDisplayText
import org.hisp.dhis.rules.models.RuleEffect
import timber.log.Timber
import java.util.ArrayList

class EventIndicatorsPresenter internal constructor(
private val d2: D2,
private val programUid: String,
private val eventUid: String,
private val eventCaptureRepository: EventCaptureRepository,
private val ruleEngineRepository: RuleEngineRepository,
private val schedulerProvider: SchedulerProvider
) : EventIndicatorsContracts.Presenter {

private lateinit var compositeDisposable: CompositeDisposable
private lateinit var view: EventIndicatorsContracts.View

override fun init(view: EventIndicatorsContracts.View) {
this.view = view
compositeDisposable = CompositeDisposable()
compositeDisposable.add(
eventCaptureRepository.getIndicators(programUid)
.map { indicators ->
Observable.fromIterable(indicators)
.filter { indicator ->
indicator.displayInForm() != null && indicator.displayInForm()!!
}
.map { indicator ->

val indicatorValue = d2.programModule().programIndicatorEngine()
.getProgramIndicatorValue(
null, eventUid,
indicator.uid()
)

Pair.create(indicator, indicatorValue ?: "")
}
.filter { pair -> pair.val1().isNotEmpty() }
.flatMap { pair ->
eventCaptureRepository.getLegendColorForIndicator(
pair.val0(),
pair.val1()
)
}
.toList()
}
.flatMap { obj -> obj.toFlowable() }
.flatMap { indicators ->
ruleEngineRepository.updateRuleEngine()
.flatMap { ruleEngineRepository.reCalculate() }
.map { calcResult -> applyRuleEffects(calcResult) } //Restart rule engine to take into account value changes
.map { ruleIndicators ->
for (indicator in ruleIndicators) {
if (!indicators.contains(indicator)) {
indicators.add(indicator)
}
}
indicators
}
}
.subscribeOn(schedulerProvider.io())
.observeOn(schedulerProvider.ui())
.subscribe(
view.swapIndicators(),
Consumer { t -> Timber.d(t) }
)
)
}

private fun applyRuleEffects(calcResult: Result<RuleEffect>): List<Trio<ProgramIndicator, String, String>> {
val indicators: MutableList<Trio<ProgramIndicator, String, String>> =
ArrayList()
if (calcResult.error() != null) {
Timber.e(calcResult.error())
return ArrayList()
}
for (ruleEffect in calcResult.items()) {
val ruleAction = ruleEffect.ruleAction()
if (!ruleEffect.data().contains("#{")) //Avoid display unavailable variables
if (ruleAction is RuleActionDisplayKeyValuePair) {
val indicator =
Trio.create(
ProgramIndicator.builder()
.uid(ruleAction.content())
.displayName(ruleAction.content())
.build(),
ruleEffect.data(), ""
)
indicators.add(indicator)
} else if (ruleAction is RuleActionDisplayText) {
val indicator =
Trio.create<ProgramIndicator, String, String>(
null,
ruleAction.content() + ruleEffect.data(), ""
)
indicators.add(indicator)
}
}
return indicators
}

override fun onDettach() {
compositeDisposable.clear()
}

override fun displayMessage(message: String) {
view.displayMessage(message)
}
}

0 comments on commit a647b08

Please sign in to comment.