diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index aa604adfc6..c1da539cfb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -115,7 +115,7 @@
diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureActivity.kt b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureActivity.kt
index 57a5b20dd6..b0c1f1338a 100644
--- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureActivity.kt
+++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureActivity.kt
@@ -11,6 +11,8 @@ import android.widget.PopupMenu
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModelProvider
+import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
@@ -22,6 +24,7 @@ import org.dhis2.commons.dialogs.CustomDialog
import org.dhis2.commons.dialogs.DialogClickListener
import org.dhis2.commons.popupmenu.AppMenuHelper
import org.dhis2.commons.resources.ResourceManager
+import org.dhis2.commons.sync.OnDismissListener
import org.dhis2.commons.sync.SyncContext
import org.dhis2.databinding.ActivityEventCaptureBinding
import org.dhis2.form.model.EventMode
@@ -31,6 +34,7 @@ import org.dhis2.ui.dialogs.bottomsheet.BottomSheetDialog
import org.dhis2.ui.dialogs.bottomsheet.BottomSheetDialogUiModel
import org.dhis2.ui.dialogs.bottomsheet.DialogButtonStyle.DiscardButton
import org.dhis2.ui.dialogs.bottomsheet.DialogButtonStyle.MainButton
+import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.eventCaptureFragment.EventCaptureFormFragment
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.eventCaptureFragment.OnEditionListener
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.model.EventCompletionDialog
import org.dhis2.usescases.eventsWithoutRegistration.eventDetails.injection.EventDetailsComponent
@@ -38,7 +42,10 @@ import org.dhis2.usescases.eventsWithoutRegistration.eventDetails.injection.Even
import org.dhis2.usescases.eventsWithoutRegistration.eventDetails.injection.EventDetailsModule
import org.dhis2.usescases.eventsWithoutRegistration.eventInitial.EventInitialActivity
import org.dhis2.usescases.general.ActivityGlobalAbstract
+import org.dhis2.usescases.teiDashboard.DashboardViewModel
import org.dhis2.usescases.teiDashboard.dashboardfragments.relationships.MapButtonObservable
+import org.dhis2.usescases.teiDashboard.dashboardfragments.teidata.TEIDataActivityContract
+import org.dhis2.usescases.teiDashboard.dashboardfragments.teidata.TEIDataFragment.Companion.newInstance
import org.dhis2.utils.analytics.CLICK
import org.dhis2.utils.analytics.DELETE_EVENT
import org.dhis2.utils.analytics.SHOW_HELP
@@ -48,13 +55,16 @@ import org.dhis2.utils.customviews.navigationbar.NavigationPageConfigurator
import org.dhis2.utils.granularsync.OPEN_ERROR_LOCATION
import org.dhis2.utils.granularsync.SyncStatusDialog
import org.dhis2.utils.granularsync.shouldLaunchSyncDialog
+import org.dhis2.utils.isLandscape
+import org.dhis2.utils.isPortrait
import javax.inject.Inject
class EventCaptureActivity :
ActivityGlobalAbstract(),
EventCaptureContract.View,
MapButtonObservable,
- EventDetailsComponentProvider {
+ EventDetailsComponentProvider,
+ TEIDataActivityContract {
private lateinit var binding: ActivityEventCaptureBinding
@JvmField
@@ -78,37 +88,53 @@ class EventCaptureActivity :
var eventCaptureComponent: EventCaptureComponent? = null
var programUid: String? = null
var eventUid: String? = null
+ private var teiUid: String? = null
+ private var enrollmentUid: String? = null
private val relationshipMapButton: LiveData = MutableLiveData(false)
private var onEditionListener: OnEditionListener? = null
private var adapter: EventCapturePagerAdapter? = null
+ private var eventViewPager: ViewPager2? = null
+ private var dashboardViewModel: DashboardViewModel? = null
override fun onCreate(savedInstanceState: Bundle?) {
eventUid = intent.getStringExtra(Constants.EVENT_UID)
- eventCaptureComponent = this.app().userComponent()!!.plus(
- EventCaptureModule(
- this,
- eventUid,
- ),
- )
- eventCaptureComponent!!.inject(this)
+ programUid = intent.getStringExtra(Constants.PROGRAM_UID)
+ setUpEventCaptureComponent(eventUid)
+ teiUid = presenter!!.teiUid
+ enrollmentUid = presenter!!.enrollmentUid
themeManager!!.setProgramTheme(intent.getStringExtra(Constants.PROGRAM_UID)!!)
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_event_capture)
binding.presenter = presenter
+ eventViewPager = when {
+ this.isLandscape() -> binding.eventViewLandPager
+ else -> binding.eventViewPager
+ }
eventMode = intent.getSerializableExtra(Constants.EVENT_MODE) as EventMode?
setUpViewPagerAdapter()
setUpNavigationBar()
+ setUpEventCaptureFormLandscape(eventUid ?: "")
+ if (this.isLandscape() && areTeiUidAndEnrollmentUidNotNull()) {
+ val viewModelFactory = this.app().dashboardComponent()?.dashboardViewModelFactory()
+
+ viewModelFactory?.let {
+ dashboardViewModel =
+ ViewModelProvider(this, viewModelFactory)[DashboardViewModel::class.java]
+ supportFragmentManager.beginTransaction().replace(R.id.tei_column, newInstance(programUid, teiUid, enrollmentUid)).commit()
+ dashboardViewModel?.updateSelectedEventUid(eventUid)
+ }
+ }
showProgress()
presenter!!.initNoteCounter()
presenter!!.init()
- binding.syncButton.setOnClickListener { showSyncDialog() }
+ binding.syncButton.setOnClickListener { showSyncDialog(EVENT_SYNC) }
if (intent.shouldLaunchSyncDialog()) {
- showSyncDialog()
+ showSyncDialog(EVENT_SYNC)
}
}
private fun setUpViewPagerAdapter() {
- binding.eventViewPager.isUserInputEnabled = false
+ eventViewPager?.isUserInputEnabled = false
adapter = EventCapturePagerAdapter(
this,
intent.getStringExtra(Constants.PROGRAM_UID),
@@ -118,8 +144,8 @@ class EventCaptureActivity :
intent.getBooleanExtra(OPEN_ERROR_LOCATION, false),
eventMode,
)
- binding.eventViewPager.adapter = adapter
- binding.eventViewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
+ eventViewPager?.adapter = adapter
+ eventViewPager?.registerOnPageChangeCallback(object : OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (position == 0 && eventMode !== EventMode.NEW) {
@@ -136,12 +162,56 @@ class EventCaptureActivity :
private fun setUpNavigationBar() {
binding.navigationBar.pageConfiguration(pageConfigurator!!)
+ eventViewPager?.registerOnPageChangeCallback(
+ object : OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ super.onPageSelected(position)
+ binding.navigationBar.selectItemAt(position)
+ }
+ },
+ )
binding.navigationBar.setOnItemSelectedListener { item: MenuItem ->
- binding.eventViewPager.currentItem = adapter!!.getDynamicTabIndex(item.itemId)
+ eventViewPager?.currentItem = adapter!!.getDynamicTabIndex(item.itemId)
true
}
}
+ private fun setUpEventCaptureFormLandscape(eventUid: String) {
+ if (this.isLandscape()) {
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.event_form, EventCaptureFormFragment.newInstance(eventUid, false, eventMode))
+ .commit()
+ }
+ }
+
+ private fun setUpEventCaptureComponent(eventUid: String?) {
+ eventCaptureComponent = app().userComponent()!!.plus(
+ EventCaptureModule(
+ this,
+ eventUid,
+ this.isPortrait(),
+ ),
+ )
+ eventCaptureComponent!!.inject(this)
+ }
+
+ private fun updateLandscapeViewsOnEventChange(newEventUid: String) {
+ if (newEventUid != this.eventUid) {
+ this.eventUid = newEventUid
+ setUpEventCaptureComponent(newEventUid)
+ setUpViewPagerAdapter()
+ setUpNavigationBar()
+ setUpEventCaptureFormLandscape(newEventUid)
+ showProgress()
+ presenter!!.initNoteCounter()
+ presenter!!.init()
+ }
+ }
+
+ private fun areTeiUidAndEnrollmentUidNotNull(): Boolean {
+ return teiUid != null && enrollmentUid != null
+ }
+
fun openDetails() {
binding.navigationBar.selectItemAt(0)
}
@@ -158,6 +228,9 @@ class EventCaptureActivity :
override fun onResume() {
super.onResume()
presenter!!.refreshTabCounters()
+ with(dashboardViewModel) {
+ this?.selectedEventUid()?.observe(this@EventCaptureActivity, ::updateLandscapeViewsOnEventChange)
+ }
}
override fun onDestroy() {
@@ -210,7 +283,11 @@ class EventCaptureActivity :
}
private fun isFormScreen(): Boolean {
- return adapter?.isFormScreenShown(binding.eventViewPager.currentItem) == true
+ return if (this.isPortrait()) {
+ adapter?.isFormScreenShown(binding.eventViewPager?.currentItem) == true
+ } else {
+ true
+ }
}
override fun updatePercentage(primaryValue: Float) {
@@ -225,25 +302,28 @@ class EventCaptureActivity :
emptyMandatoryFields: Map,
eventCompletionDialog: EventCompletionDialog,
) {
- if (binding.navigationBar.selectedItemId == R.id.navigation_data_entry) {
- val dialog = BottomSheetDialog(
- bottomSheetDialogUiModel = eventCompletionDialog.bottomSheetDialogUiModel,
- onMainButtonClicked = {
- setAction(eventCompletionDialog.mainButtonAction)
- },
- onSecondaryButtonClicked = {
- eventCompletionDialog.secondaryButtonAction?.let { setAction(it) }
- },
- content = if (eventCompletionDialog.fieldsWithIssues.isNotEmpty()) {
- { bottomSheetDialog ->
- ErrorFieldList(eventCompletionDialog.fieldsWithIssues) {
- bottomSheetDialog.dismiss()
- }
+ val dialog = BottomSheetDialog(
+ bottomSheetDialogUiModel = eventCompletionDialog.bottomSheetDialogUiModel,
+ onMainButtonClicked = {
+ setAction(eventCompletionDialog.mainButtonAction)
+ },
+ onSecondaryButtonClicked = {
+ eventCompletionDialog.secondaryButtonAction?.let { setAction(it) }
+ },
+ content = if (eventCompletionDialog.fieldsWithIssues.isNotEmpty()) {
+ { bottomSheetDialog ->
+ ErrorFieldList(eventCompletionDialog.fieldsWithIssues) {
+ bottomSheetDialog.dismiss()
}
- } else {
- null
- },
- )
+ }
+ } else {
+ null
+ },
+ )
+ if (binding.navigationBar.selectedItemId == R.id.navigation_data_entry) {
+ dialog.show(supportFragmentManager, SHOW_OPTIONS)
+ }
+ if (this.isLandscape()) {
dialog.show(supportFragmentManager, SHOW_OPTIONS)
}
}
@@ -452,23 +532,66 @@ class EventCaptureActivity :
return eventCaptureComponent!!.plus(module)
}
- private fun showSyncDialog() {
- SyncStatusDialog.Builder()
- .withContext(this)
- .withSyncContext(SyncContext.Event(eventUid!!))
- .onNoConnectionListener {
- val contextView = findViewById(R.id.navigationBar)
- Snackbar.make(
- contextView,
- R.string.sync_offline_check_connection,
- Snackbar.LENGTH_SHORT,
- ).show()
- }
- .show("EVENT_SYNC")
+ private fun showSyncDialog(syncType: String) {
+ val syncContext = when (syncType) {
+ TEI_SYNC -> enrollmentUid?.let { SyncContext.Enrollment(it) }
+ EVENT_SYNC -> SyncContext.Event(eventUid!!)
+ else -> null
+ }
+
+ syncContext?.let {
+ SyncStatusDialog.Builder()
+ .withContext(this)
+ .withSyncContext(it)
+ .onDismissListener(object : OnDismissListener {
+ override fun onDismiss(hasChanged: Boolean) {
+ if (hasChanged && syncType == TEI_SYNC) {
+ dashboardViewModel?.updateDashboard()
+ }
+ }
+ })
+ .onNoConnectionListener {
+ val contextView = findViewById(R.id.navigationBar)
+ Snackbar.make(
+ contextView,
+ R.string.sync_offline_check_connection,
+ Snackbar.LENGTH_SHORT,
+ ).show()
+ }
+ .show(syncType)
+ }
+ }
+
+ override fun openSyncDialog() {
+ showSyncDialog(TEI_SYNC)
+ }
+
+ override fun finishActivity() {
+ finish()
+ }
+
+ override fun restoreAdapter(programUid: String, teiUid: String, enrollmentUid: String) {
+ // we do not restore adapter in events
+ }
+
+ override fun executeOnUIThread() {
+ activity.runOnUiThread {
+ showDescription(getString(R.string.error_applying_rule_effects))
+ }
+ }
+
+ override fun getContext(): Context {
+ return this
+ }
+
+ override fun activityTeiUid(): String? {
+ return teiUid
}
companion object {
private const val SHOW_OPTIONS = "SHOW_OPTIONS"
+ private const val TEI_SYNC = "SYNC_TEI"
+ private const val EVENT_SYNC = "EVENT_SYNC"
@JvmStatic
fun getActivityBundle(eventUid: String, programUid: String, eventMode: EventMode): Bundle {
diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureContract.java b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureContract.java
index 7581ab9fdf..0cbab10877 100644
--- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureContract.java
+++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureContract.java
@@ -102,6 +102,12 @@ void attemptFinish(boolean canComplete,
void emitAction(@NotNull EventCaptureAction onBack);
String programStage();
+
+ @Nullable
+ String getTeiUid();
+
+ @Nullable
+ String getEnrollmentUid();
}
public interface EventCaptureRepository {
@@ -149,6 +155,12 @@ public interface EventCaptureRepository {
boolean hasRelationships();
ValidationStrategy validationStrategy();
+
+ @Nullable
+ String getTeiUid();
+
+ @Nullable
+ String getEnrollmentUid();
}
}
diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureModule.java b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureModule.java
index c7b9f31d8d..cfc80799f2 100644
--- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureModule.java
+++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureModule.java
@@ -42,9 +42,12 @@ public class EventCaptureModule {
private final String eventUid;
private final EventCaptureContract.View view;
- public EventCaptureModule(EventCaptureContract.View view, String eventUid) {
+ private final boolean isPortrait;
+
+ public EventCaptureModule(EventCaptureContract.View view, String eventUid, boolean isPortrait) {
this.view = view;
this.eventUid = eventUid;
+ this.isPortrait = isPortrait;
}
@Provides
@@ -138,7 +141,7 @@ FlowableProcessor getProcessor() {
NavigationPageConfigurator pageConfigurator(
EventCaptureContract.EventCaptureRepository repository
) {
- return new EventPageConfigurator(repository);
+ return new EventPageConfigurator(repository, isPortrait);
}
@Provides
diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCapturePagerAdapter.java b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCapturePagerAdapter.java
index e8e044d83e..60841ee589 100644
--- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCapturePagerAdapter.java
+++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCapturePagerAdapter.java
@@ -26,14 +26,19 @@ public class EventCapturePagerAdapter extends FragmentStateAdapter {
private final String programUid;
private final String eventUid;
- private final List pages;
+ private final List landscapePages;
+ private final List portraitPages;
+
+ private final FragmentActivity fragmentActivity;
private final boolean shouldOpenErrorSection;
private final EventMode eventMode;
+ public static final int NO_POSITION = -1;
+
public boolean isFormScreenShown(@Nullable Integer currentItem) {
- return currentItem != null && pages.get(currentItem) == EventPageType.DATA_ENTRY;
+ return currentItem != null && portraitPages.get(currentItem) == EventPageType.DATA_ENTRY;
}
private enum EventPageType {
@@ -54,50 +59,64 @@ public EventCapturePagerAdapter(FragmentActivity fragmentActivity,
this.eventUid = eventUid;
this.shouldOpenErrorSection = openErrorSection;
this.eventMode = eventMode;
- pages = new ArrayList<>();
- pages.add(EventPageType.DATA_ENTRY);
+ this.fragmentActivity = fragmentActivity;
+ landscapePages = new ArrayList<>();
+ portraitPages = new ArrayList<>();
+
+ portraitPages.add(EventPageType.DATA_ENTRY);
if (displayAnalyticScreen) {
- pages.add(EventPageType.ANALYTICS);
+ portraitPages.add(EventPageType.ANALYTICS);
+ landscapePages.add(EventPageType.ANALYTICS);
}
if (displayRelationshipScreen) {
- pages.add(EventPageType.RELATIONSHIPS);
+ portraitPages.add(EventPageType.RELATIONSHIPS);
+ landscapePages.add(EventPageType.RELATIONSHIPS);
}
- pages.add(EventPageType.NOTES);
+ portraitPages.add(EventPageType.NOTES);
+ landscapePages.add(EventPageType.NOTES);
}
public int getDynamicTabIndex(@IntegerRes int tabClicked) {
- if (tabClicked == R.id.navigation_data_entry) {
- return pages.indexOf(EventPageType.DATA_ENTRY);
- } else if (tabClicked == R.id.navigation_analytics) {
- return pages.indexOf(EventPageType.ANALYTICS);
- } else if (tabClicked == R.id.navigation_relationships) {
- return pages.indexOf(EventPageType.RELATIONSHIPS);
- } else if (tabClicked == R.id.navigation_notes) {
- return pages.indexOf(EventPageType.NOTES);
+ EventPageType pageType = switch (tabClicked) {
+ case R.id.navigation_analytics -> EventPageType.ANALYTICS;
+ case R.id.navigation_relationships -> EventPageType.RELATIONSHIPS;
+ case R.id.navigation_notes -> EventPageType.NOTES;
+ default -> null;
+ };
+
+ if (pageType != null) {
+ if (isPortrait()) {
+ return portraitPages.indexOf(pageType);
+ } else {
+ return landscapePages.indexOf(pageType);
+ }
+ } else {
+ return NO_POSITION;
}
- return 0;
}
@NonNull
@Override
public Fragment createFragment(int position) {
- switch (pages.get(position)) {
- default:
- case DATA_ENTRY:
- return EventCaptureFormFragment.newInstance(
- eventUid,
- shouldOpenErrorSection,
- eventMode
- );
- case ANALYTICS:
+ return createFragmentForPage(
+ isPortrait() ?
+ portraitPages.get(position) :
+ landscapePages.get(position)
+ );
+ }
+
+ private Fragment createFragmentForPage(EventPageType pageType) {
+ switch (pageType) {
+ case ANALYTICS -> {
Fragment indicatorFragment = new IndicatorsFragment();
Bundle arguments = new Bundle();
arguments.putString(VISUALIZATION_TYPE, VisualizationType.EVENTS.name());
indicatorFragment.setArguments(arguments);
return indicatorFragment;
- case RELATIONSHIPS:
+ }
+ case RELATIONSHIPS -> {
Fragment relationshipFragment = new RelationshipFragment();
relationshipFragment.setArguments(
RelationshipFragment.withArguments(programUid,
@@ -107,13 +126,31 @@ public Fragment createFragment(int position) {
)
);
return relationshipFragment;
- case NOTES:
+ }
+ case NOTES -> {
return NotesFragment.newEventInstance(programUid, eventUid);
+ }
+ default -> {
+ return EventCaptureFormFragment.newInstance(
+ eventUid,
+ shouldOpenErrorSection,
+ eventMode
+ );
+ }
}
+
}
@Override
public int getItemCount() {
- return pages.size();
+ if (isPortrait()) {
+ return portraitPages.size();
+ } else {
+ return landscapePages.size();
+ }
+ }
+
+ public boolean isPortrait() {
+ return fragmentActivity.getResources().getConfiguration().orientation == 1;
}
}
diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCapturePresenterImpl.kt b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCapturePresenterImpl.kt
index 4ab039b60f..51c2072858 100644
--- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCapturePresenterImpl.kt
+++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCapturePresenterImpl.kt
@@ -280,4 +280,11 @@ class EventCapturePresenterImpl(
get() = eventCaptureRepository.eventStatus().blockingFirst()
override fun programStage(): String = eventCaptureRepository.programStage().blockingFirst()
+
+ override fun getEnrollmentUid(): String? {
+ return eventCaptureRepository.enrollmentUid
+ }
+ override fun getTeiUid(): String? {
+ return eventCaptureRepository.teiUid
+ }
}
diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureRepositoryImpl.java b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureRepositoryImpl.java
index a357042c2f..7111c4bf5f 100644
--- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureRepositoryImpl.java
+++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureRepositoryImpl.java
@@ -23,6 +23,8 @@
import java.util.List;
import java.util.Objects;
+import javax.annotation.Nullable;
+
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.Single;
@@ -231,5 +233,18 @@ public ValidationStrategy validationStrategy() {
return validationStrategy != null ? validationStrategy : ValidationStrategy.ON_COMPLETE;
}
+
+ @Override
+ @Nullable
+ public String getEnrollmentUid() {
+ return getCurrentEvent().enrollment();
+ }
+
+ @Override
+ @Nullable
+ public String getTeiUid() {
+ Enrollment enrollment = d2.enrollmentModule().enrollments().uid(getEnrollmentUid()).blockingGet();
+ return enrollment != null ? enrollment.trackedEntityInstance() : null;
+ }
}
diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventPageConfigurator.kt b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventPageConfigurator.kt
index ed3d15822f..2f4a9dcdc8 100644
--- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventPageConfigurator.kt
+++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventPageConfigurator.kt
@@ -4,13 +4,14 @@ import org.dhis2.utils.customviews.navigationbar.NavigationPageConfigurator
class EventPageConfigurator(
private val eventCaptureRepository: EventCaptureContract.EventCaptureRepository,
+ val isPortrait: Boolean,
) : NavigationPageConfigurator {
override fun displayDetails(): Boolean {
return true
}
override fun displayDataEntry(): Boolean {
- return true
+ return isPortrait
}
override fun displayAnalytics(): Boolean {
diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/eventCaptureFragment/EventCaptureFormFragment.java b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/eventCaptureFragment/EventCaptureFormFragment.java
index ce2d282d59..f3915a35b3 100644
--- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/eventCaptureFragment/EventCaptureFormFragment.java
+++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/eventCaptureFragment/EventCaptureFormFragment.java
@@ -71,7 +71,6 @@ public void onAttach(@NotNull Context context) {
this,
getArguments().getString(Constants.EVENT_UID))
).inject(this);
- setRetainInstance(true);
}
@Override
diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/DashboardViewModel.kt b/app/src/main/java/org/dhis2/usescases/teiDashboard/DashboardViewModel.kt
index 7287ae0068..4c05023cda 100644
--- a/app/src/main/java/org/dhis2/usescases/teiDashboard/DashboardViewModel.kt
+++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/DashboardViewModel.kt
@@ -27,6 +27,8 @@ class DashboardViewModel(
private val eventUid = MutableLiveData()
+ private val selectedEventUid = MutableLiveData()
+
val updateEnrollment = MutableLiveData(false)
val showStatusErrorMessages = MutableLiveData(StatusChangeResultCode.CHANGED)
@@ -169,4 +171,14 @@ class DashboardViewModel(
}
}
}
+
+ fun selectedEventUid(): LiveData {
+ return selectedEventUid
+ }
+
+ fun updateSelectedEventUid(uid: String?) {
+ if (selectedEventUid.value != uid) {
+ this.selectedEventUid.value = uid
+ }
+ }
}
diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardComponent.java b/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardComponent.java
index 50c9278d86..82a0bc0cca 100644
--- a/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardComponent.java
+++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardComponent.java
@@ -29,5 +29,7 @@ public interface TeiDashboardComponent {
@NonNull
TEIDataComponent plus(TEIDataModule teiDataModule);
+ DashboardViewModelFactory dashboardViewModelFactory();
+
void inject(TeiDashboardMobileActivity mobileActivity);
}
diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardMobileActivity.kt b/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardMobileActivity.kt
index cf3251fc02..c16f884432 100644
--- a/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardMobileActivity.kt
+++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardMobileActivity.kt
@@ -20,19 +20,27 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModelProvider
import androidx.viewpager2.widget.ViewPager2
+import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import org.dhis2.App
import org.dhis2.R
import org.dhis2.commons.Constants
import org.dhis2.commons.Constants.TEI_UID
+import org.dhis2.commons.featureconfig.data.FeatureConfigRepository
+import org.dhis2.commons.featureconfig.model.Feature
import org.dhis2.commons.filters.FilterManager
import org.dhis2.commons.filters.Filters
import org.dhis2.commons.network.NetworkUtils
import org.dhis2.commons.popupmenu.AppMenuHelper
+import org.dhis2.commons.resources.ColorUtils
import org.dhis2.commons.resources.ResourceManager
import org.dhis2.commons.sync.OnDismissListener
import org.dhis2.commons.sync.SyncContext
import org.dhis2.databinding.ActivityDashboardMobileBinding
+import org.dhis2.form.model.EnrollmentMode
+import org.dhis2.form.model.EnrollmentRecords
+import org.dhis2.form.ui.FormView
+import org.dhis2.form.ui.provider.EnrollmentResultDialogUiProvider
import org.dhis2.ui.ThemeManager
import org.dhis2.ui.dialogs.bottomsheet.DeleteBottomSheetDialog
import org.dhis2.usescases.enrollment.EnrollmentActivity
@@ -43,6 +51,7 @@ import org.dhis2.usescases.teiDashboard.adapters.DashboardPagerAdapter
import org.dhis2.usescases.teiDashboard.adapters.DashboardPagerAdapter.Companion.NO_POSITION
import org.dhis2.usescases.teiDashboard.adapters.DashboardPagerAdapter.DashboardPageType
import org.dhis2.usescases.teiDashboard.dashboardfragments.relationships.MapButtonObservable
+import org.dhis2.usescases.teiDashboard.dashboardfragments.teidata.TEIDataActivityContract
import org.dhis2.usescases.teiDashboard.dashboardfragments.teidata.TEIDataFragment.Companion.newInstance
import org.dhis2.usescases.teiDashboard.teiProgramList.TeiProgramListActivity
import org.dhis2.usescases.teiDashboard.ui.setButtonContent
@@ -63,12 +72,16 @@ import javax.inject.Inject
class TeiDashboardMobileActivity :
ActivityGlobalAbstract(),
TeiDashboardContracts.View,
- MapButtonObservable {
+ MapButtonObservable,
+ TEIDataActivityContract {
private var currentOrientation = -1
@Inject
lateinit var presenter: TeiDashboardContracts.Presenter
+ var featureConfig: FeatureConfigRepository? = null
+ @Inject set
+
@Inject
lateinit var filterManager: FilterManager
@@ -101,6 +114,8 @@ class TeiDashboardMobileActivity :
private var elevation = 0f
private var restartingActivity = false
+ private lateinit var formView: FormView
+
private val detailsLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(),
) {
@@ -189,6 +204,7 @@ class TeiDashboardMobileActivity :
if (intent.shouldLaunchSyncDialog()) {
openSyncDialog()
}
+ setFormViewForLandScape()
setNavigationBar()
setEditButton()
dashboardViewModel.showStatusErrorMessages.observe(this) {
@@ -202,6 +218,47 @@ class TeiDashboardMobileActivity :
}
}
+ private fun setFormViewForLandScape() {
+ if (isLandscape() && enrollmentUid != null) {
+ val saveButton = findViewById(R.id.saveLand) as FloatingActionButton
+ formView = FormView.Builder()
+ .locationProvider(locationProvider)
+ .onItemChangeListener {
+ // Do nothing
+ }
+ .onLoadingListener { loading ->
+ if (loading) {
+ showLoadingProgress(true)
+ } else {
+ showLoadingProgress(false)
+ }
+ }
+ .onFinishDataEntry {
+ dashboardViewModel.updateDashboard()
+ }
+ .resultDialogUiProvider(
+ EnrollmentResultDialogUiProvider(
+ ResourceManager(
+ this.context,
+ ColorUtils(),
+ ),
+ ),
+ )
+ .factory(supportFragmentManager)
+ .setRecords(EnrollmentRecords(enrollmentUid!!, EnrollmentMode.NEW))
+ .useComposeForm(
+ featureConfig?.isFeatureEnable(Feature.COMPOSE_FORMS) ?: false,
+ )
+ .build()
+
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.tei_form_view, formView)
+ .commitAllowingStateLoss()
+
+ saveButton.setOnClickListener { formView.onSaveClick() }
+ }
+ }
+
private fun setEditButton() {
binding.editButton.setButtonContent(presenter.teType) {
enrollmentUid?.let { enrollmentUid ->
@@ -272,7 +329,7 @@ class TeiDashboardMobileActivity :
super.onDestroy()
}
- fun openSyncDialog() {
+ override fun openSyncDialog() {
enrollmentUid?.let { enrollmentUid ->
SyncStatusDialog.Builder()
.withContext(this, null)
@@ -339,12 +396,12 @@ class TeiDashboardMobileActivity :
binding.relationshipMapIcon.visibility = View.GONE
}
if (pageType == DashboardPageType.TEI_DETAIL && programUid != null) {
- binding.toolbarTitle.visibility = View.GONE
- binding.editButton.visibility = View.VISIBLE
+ binding.toolbarTitle?.visibility = View.GONE
+ binding.editButton?.visibility = View.VISIBLE
binding.syncButton.visibility = View.GONE
} else {
- binding.toolbarTitle.visibility = View.VISIBLE
- binding.editButton.visibility = View.GONE
+ binding.toolbarTitle?.visibility = View.VISIBLE
+ binding.editButton?.visibility = View.GONE
binding.syncButton.visibility = View.VISIBLE
}
binding.navigationBar.selectItemAt(position)
@@ -719,6 +776,35 @@ class TeiDashboardMobileActivity :
startActivity(intent)
}
+ override fun finishActivity() {
+ finish()
+ }
+
+ override fun restoreAdapter(programUid: String, teiUid: String, enrollmentUid: String) {
+ startActivity(
+ intent(
+ this,
+ teiUid,
+ programUid,
+ enrollmentUid,
+ ),
+ )
+ }
+
+ override fun executeOnUIThread() {
+ activity.runOnUiThread {
+ showDescription(getString(R.string.error_applying_rule_effects))
+ }
+ }
+
+ override fun getContext(): Context {
+ return this
+ }
+
+ override fun activityTeiUid(): String? {
+ return teiUid
+ }
+
companion object {
private const val TEI_SYNC = "SYNC_TEI"
diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataActivityContract.kt b/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataActivityContract.kt
new file mode 100644
index 0000000000..e689ee3855
--- /dev/null
+++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataActivityContract.kt
@@ -0,0 +1,12 @@
+package org.dhis2.usescases.teiDashboard.dashboardfragments.teidata
+
+import android.content.Context
+
+interface TEIDataActivityContract {
+ fun restoreAdapter(programUid: String, teiUid: String, enrollmentUid: String)
+ fun finishActivity()
+ fun openSyncDialog()
+ fun executeOnUIThread()
+ fun getContext(): Context
+ fun activityTeiUid(): String?
+}
diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataFragment.kt b/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataFragment.kt
index 726826a4ef..7753421b8c 100644
--- a/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataFragment.kt
+++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataFragment.kt
@@ -99,7 +99,7 @@ class TEIDataFragment : FragmentGlobalAbstract(), TEIDataContracts.View {
private val followUp = ObservableBoolean(false)
private var eventCatComboOptionSelector: EventCatComboOptionSelector? = null
private val dashboardViewModel: DashboardViewModel by activityViewModels()
- private val dashboardActivity: TeiDashboardMobileActivity by lazy { context as TeiDashboardMobileActivity }
+ private val dashboardActivity: TEIDataActivityContract by lazy { context as TEIDataActivityContract }
override fun onAttach(context: Context) {
super.onAttach(context)
@@ -223,8 +223,8 @@ class TEIDataFragment : FragmentGlobalAbstract(), TEIDataContracts.View {
programsCallback = {
startActivity(
TeiDashboardMobileActivity.intent(
- dashboardActivity.context,
- dashboardActivity.teiUid,
+ dashboardActivity.getContext(),
+ dashboardActivity.activityTeiUid(),
null,
null,
),
@@ -268,6 +268,7 @@ class TEIDataFragment : FragmentGlobalAbstract(), TEIDataContracts.View {
!dashboardModel?.teiHeader.isNullOrEmpty() -> {
dashboardModel?.teiHeader
}
+
else -> {
String.format(
"%s %s",
@@ -344,6 +345,7 @@ class TEIDataFragment : FragmentGlobalAbstract(), TEIDataContracts.View {
currentProgram,
colorUtils,
cardMapper,
+ initialSelectedEventUid = dashboardViewModel.selectedEventUid().value,
)
binding.teiRecycler.adapter = eventAdapter
}
@@ -463,15 +465,8 @@ class TEIDataFragment : FragmentGlobalAbstract(), TEIDataContracts.View {
}
override fun restoreAdapter(programUid: String, teiUid: String, enrollmentUid: String) {
- dashboardActivity.startActivity(
- TeiDashboardMobileActivity.intent(
- activity,
- teiUid,
- programUid,
- enrollmentUid,
- ),
- )
- dashboardActivity.finish()
+ dashboardActivity.restoreAdapter(programUid, teiUid, enrollmentUid)
+ dashboardActivity.finishActivity()
}
override fun openEventDetails(intent: Intent, options: ActivityOptionsCompat) =
@@ -484,10 +479,17 @@ class TEIDataFragment : FragmentGlobalAbstract(), TEIDataContracts.View {
updateEnrollment(true)
}
- override fun openEventCapture(intent: Intent) =
- contractHandler.editEvent(intent).observe(this.viewLifecycleOwner) {
- updateEnrollment(true)
+ override fun openEventCapture(intent: Intent) {
+ if (dashboardActivity is TeiDashboardMobileActivity) {
+ contractHandler.editEvent(intent).observe(this.viewLifecycleOwner) {
+ updateEnrollment(true)
+ }
+ }
+ if (dashboardActivity is EventCaptureActivity) {
+ val selectedEventUid = intent.getStringExtra(Constants.EVENT_UID)
+ dashboardViewModel.updateSelectedEventUid(selectedEventUid)
}
+ }
override fun goToEventInitial(
eventCreationType: EventCreationType,
@@ -580,9 +582,7 @@ class TEIDataFragment : FragmentGlobalAbstract(), TEIDataContracts.View {
}
override fun showProgramRuleErrorMessage() {
- dashboardActivity.runOnUiThread {
- showDescription(getString(R.string.error_applying_rule_effects))
- }
+ dashboardActivity.executeOnUIThread()
}
override fun updateEnrollment(update: Boolean) {
diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataPresenter.kt b/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataPresenter.kt
index 6bd28f5b9b..7bd0464cfc 100644
--- a/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataPresenter.kt
+++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/TEIDataPresenter.kt
@@ -138,7 +138,10 @@ class TEIDataPresenter(
.subscribe(
{ events ->
_events.postValue(events)
- _totalTimeLineEvents.postValue(events.firstOrNull()?.eventCount ?: 0)
+ _totalTimeLineEvents.postValue(
+ events.firstOrNull()?.eventCount
+ ?: 0,
+ )
decrement()
},
Timber.Forest::d,
diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/teievents/EventAdapter.kt b/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/teievents/EventAdapter.kt
index 8ba78e7fdc..7e7313945b 100644
--- a/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/teievents/EventAdapter.kt
+++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/dashboardfragments/teidata/teievents/EventAdapter.kt
@@ -3,8 +3,10 @@ package org.dhis2.usescases.teiDashboard.dashboardfragments.teidata.teievents
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.LocalTextStyle
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
@@ -29,12 +31,15 @@ import org.dhis2.commons.resources.ColorUtils
import org.dhis2.databinding.ItemEventBinding
import org.dhis2.usescases.teiDashboard.dashboardfragments.teidata.TEIDataPresenter
import org.dhis2.usescases.teiDashboard.dashboardfragments.teidata.teievents.ui.mapper.TEIEventCardMapper
+import org.dhis2.utils.isLandscape
import org.hisp.dhis.android.core.event.EventStatus
import org.hisp.dhis.android.core.program.Program
import org.hisp.dhis.mobile.ui.designsystem.component.ListCard
import org.hisp.dhis.mobile.ui.designsystem.component.ListCardDescriptionModel
import org.hisp.dhis.mobile.ui.designsystem.component.ListCardTitleModel
+import org.hisp.dhis.mobile.ui.designsystem.theme.Radius
import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing
+import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor
import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor
class EventAdapter(
@@ -42,6 +47,7 @@ class EventAdapter(
val program: Program,
val colorUtils: ColorUtils,
private val cardMapper: TEIEventCardMapper,
+ private val initialSelectedEventUid: String? = null,
) : ListAdapter(
object : DiffUtil.ItemCallback() {
override fun areItemsTheSame(oldItem: EventViewModel, newItem: EventViewModel): Boolean {
@@ -66,6 +72,8 @@ class EventAdapter(
private var stageSelector: FlowableProcessor = PublishProcessor.create()
+ private var previousSelectedPosition: Int = RecyclerView.NO_POSITION
+
fun stageSelector(): Flowable {
return stageSelector
}
@@ -151,11 +159,26 @@ class EventAdapter(
event.uid(),
event.status()!!,
)
+
+ if (isLandscape()) {
+ if (previousSelectedPosition != RecyclerView.NO_POSITION) {
+ currentList[previousSelectedPosition].isClicked = false
+ notifyItemChanged(previousSelectedPosition)
+ }
+ previousSelectedPosition = position
+ getItem(position).isClicked = true
+ notifyItemChanged(position)
+ }
}
}
}
},
)
+
+ if (it.event?.uid() == initialSelectedEventUid && previousSelectedPosition == RecyclerView.NO_POSITION) {
+ it.isClicked = true
+ previousSelectedPosition = position
+ }
Box(
modifier = Modifier
.padding(
@@ -185,6 +208,13 @@ class EventAdapter(
shrinkLabelText = card.shrinkLabelText,
onCardClick = card.onCardCLick,
)
+ if (it.isClicked) {
+ Box(
+ modifier = Modifier
+ .matchParentSize()
+ .background(color = SurfaceColor.Primary.copy(alpha = 0.1f), shape = RoundedCornerShape(Radius.S)),
+ )
+ }
}
}
diff --git a/app/src/main/res/layout-land/activity_dashboard_mobile.xml b/app/src/main/res/layout-land/activity_dashboard_mobile.xml
index c86361c3fa..9e8320ffe8 100644
--- a/app/src/main/res/layout-land/activity_dashboard_mobile.xml
+++ b/app/src/main/res/layout-land/activity_dashboard_mobile.xml
@@ -5,10 +5,6 @@
-
-
@@ -38,30 +34,6 @@
app:srcCompat="@drawable/ic_arrow_back"
tools:ignore="ContentDescription" />
-
-
-
-
+ tools:ignore="ContentDescription"
+ tools:visibility="visible" />
-
-
-
-
-
-
-
+ app:layout_constraintTop_toBottomOf="@id/toolbar">
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/activity_event_capture.xml b/app/src/main/res/layout-land/activity_event_capture.xml
new file mode 100644
index 0000000000..ed0da89ffa
--- /dev/null
+++ b/app/src/main/res/layout-land/activity_event_capture.xml
@@ -0,0 +1,250 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/commons/src/main/java/org/dhis2/commons/data/EventViewModel.kt b/commons/src/main/java/org/dhis2/commons/data/EventViewModel.kt
index 10984e8923..d5d5869ac4 100644
--- a/commons/src/main/java/org/dhis2/commons/data/EventViewModel.kt
+++ b/commons/src/main/java/org/dhis2/commons/data/EventViewModel.kt
@@ -26,6 +26,7 @@ data class EventViewModel(
val nameCategoryOptionCombo: String?,
val metadataIconData: MetadataIconData,
) {
+ var isClicked: Boolean = false
fun toggleValueList() {
this.valueListIsOpen = !valueListIsOpen
}