From 7c32c477dab65b84bb3c01b84b4673bd204ff26d Mon Sep 17 00:00:00 2001 From: Xavier Molloy Date: Wed, 20 Nov 2024 16:17:21 +0100 Subject: [PATCH 01/11] ci: update vName --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5c12127119..2908f4b037 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ sdk = "34" minSdk = "21" vCode = "137" -vName = "3.1.0" +vName = "3.1.0.1" gradle = "8.6.1" kotlin = '2.0.20' hilt = '2.47' From abc926588898d11c2c17b48e7ad5416c3bd173d9 Mon Sep 17 00:00:00 2001 From: Xavier Molloy Date: Tue, 26 Nov 2024 15:27:58 +0100 Subject: [PATCH 02/11] fix: [ANDROAPP-6665] Clear filters when navigating back (#3895) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: [ANDROAPP-6665] Clear filters when navigating back * fix: [ANDROAPP-6665] clear filters on home Signed-off-by: Manu Muñoz * fix: [ANDROAPP-6665] test Signed-off-by: Manu Muñoz --------- Signed-off-by: Manu Muñoz Co-authored-by: Manu Muñoz --- .../main/java/org/dhis2/usescases/main/MainActivity.kt | 1 - .../main/java/org/dhis2/usescases/main/MainModule.kt | 5 ++--- .../java/org/dhis2/usescases/main/MainPresenter.kt | 10 +++------- .../java/org/dhis2/usescases/main/MainPresenterTest.kt | 8 +++++--- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/dhis2/usescases/main/MainActivity.kt b/app/src/main/java/org/dhis2/usescases/main/MainActivity.kt index c7a4d6679d..4ce0756b92 100644 --- a/app/src/main/java/org/dhis2/usescases/main/MainActivity.kt +++ b/app/src/main/java/org/dhis2/usescases/main/MainActivity.kt @@ -219,7 +219,6 @@ class MainActivity : } override fun onPause() { - presenter.setOpeningFilterToNone() presenter.onDetach() super.onPause() } diff --git a/app/src/main/java/org/dhis2/usescases/main/MainModule.kt b/app/src/main/java/org/dhis2/usescases/main/MainModule.kt index 95077a043c..62014e272b 100644 --- a/app/src/main/java/org/dhis2/usescases/main/MainModule.kt +++ b/app/src/main/java/org/dhis2/usescases/main/MainModule.kt @@ -6,7 +6,6 @@ import dhis2.org.analytics.charts.Charts import org.dhis2.commons.di.dagger.PerActivity import org.dhis2.commons.featureconfig.data.FeatureConfigRepository import org.dhis2.commons.filters.FilterManager -import org.dhis2.commons.filters.data.FilterRepository import org.dhis2.commons.matomo.MatomoAnalyticsController import org.dhis2.commons.prefs.PreferenceProvider import org.dhis2.commons.resources.ColorUtils @@ -32,7 +31,7 @@ class MainModule(val view: MainView, private val forceToNotSynced: Boolean) { schedulerProvider: SchedulerProvider, preferences: PreferenceProvider, workManagerController: WorkManagerController, - filterRepository: FilterRepository, + filterManager: FilterManager, matomoAnalyticsController: MatomoAnalyticsController, userManager: UserManager, deleteUserData: DeleteUserData, @@ -47,7 +46,7 @@ class MainModule(val view: MainView, private val forceToNotSynced: Boolean) { schedulerProvider, preferences, workManagerController, - filterRepository, + filterManager, matomoAnalyticsController, userManager, deleteUserData, diff --git a/app/src/main/java/org/dhis2/usescases/main/MainPresenter.kt b/app/src/main/java/org/dhis2/usescases/main/MainPresenter.kt index fe2bb73058..bc88aa6a72 100644 --- a/app/src/main/java/org/dhis2/usescases/main/MainPresenter.kt +++ b/app/src/main/java/org/dhis2/usescases/main/MainPresenter.kt @@ -15,7 +15,6 @@ import kotlinx.coroutines.launch import org.dhis2.BuildConfig import org.dhis2.commons.Constants import org.dhis2.commons.filters.FilterManager -import org.dhis2.commons.filters.data.FilterRepository import org.dhis2.commons.matomo.Actions.Companion.BLOCK_SESSION_PIN import org.dhis2.commons.matomo.Actions.Companion.OPEN_ANALYTICS import org.dhis2.commons.matomo.Actions.Companion.QR_SCANNER @@ -57,7 +56,7 @@ class MainPresenter( private val schedulerProvider: SchedulerProvider, private val preferences: PreferenceProvider, private val workManagerController: WorkManagerController, - private val filterRepository: FilterRepository, + private val filterManager: FilterManager, private val matomoAnalyticsController: MatomoAnalyticsController, private val userManager: UserManager, private val deleteUserData: DeleteUserData, @@ -78,6 +77,7 @@ class MainPresenter( val downloadingVersion = MutableLiveData(false) fun init() { + filterManager.clearAllFilters() preferences.removeValue(Preference.CURRENT_ORG_UNIT) disposable.add( repository.user() @@ -158,7 +158,7 @@ class MainPresenter( Completable.fromCallable { workManagerController.cancelAllWork() syncStatusController.restore() - FilterManager.getInstance().clearAllFilters() + filterManager.clearAllFilters() preferences.setValue(Preference.SESSION_LOCKED, false) preferences.setValue(Preference.PIN_ENABLED, false) userManager.d2.dataStoreModule().localDataStore().value(PIN).blockingDeleteIfExist() @@ -225,10 +225,6 @@ class MainPresenter( matomoAnalyticsController.trackEvent(HOME, SETTINGS, CLICK) } - fun setOpeningFilterToNone() { - filterRepository.collapseAllFilters() - } - fun isPinStored() = repository.isPinStored() fun launchInitialDataSync() { diff --git a/app/src/test/java/org/dhis2/usescases/main/MainPresenterTest.kt b/app/src/test/java/org/dhis2/usescases/main/MainPresenterTest.kt index ee6e872bbf..83863fac1c 100644 --- a/app/src/test/java/org/dhis2/usescases/main/MainPresenterTest.kt +++ b/app/src/test/java/org/dhis2/usescases/main/MainPresenterTest.kt @@ -8,7 +8,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.setMain -import org.dhis2.commons.filters.data.FilterRepository +import org.dhis2.commons.filters.FilterManager import org.dhis2.commons.matomo.Categories.Companion.HOME import org.dhis2.commons.matomo.MatomoAnalyticsController import org.dhis2.commons.prefs.Preference.Companion.DEFAULT_CAT_COMBO @@ -52,7 +52,7 @@ class MainPresenterTest { private val view: MainView = mock() private val preferences: PreferenceProvider = mock() private val workManagerController: WorkManagerController = mock() - private val filterRepository: FilterRepository = mock() + private val filterManager: FilterManager = mock() private val matomoAnalyticsController: MatomoAnalyticsController = mock() private val userManager: UserManager = mock() private val deleteUserData: DeleteUserData = mock() @@ -82,7 +82,7 @@ class MainPresenterTest { schedulers, preferences, workManagerController, - filterRepository, + filterManager, matomoAnalyticsController, userManager, deleteUserData, @@ -103,6 +103,7 @@ class MainPresenterTest { verify(view).renderUsername(any()) verify(preferences).setValue(DEFAULT_CAT_COMBO, "uid") verify(preferences).setValue(PREF_DEFAULT_CAT_OPTION_COMBO, "uid") + verify(filterManager).clearAllFilters() } @Test @@ -120,6 +121,7 @@ class MainPresenterTest { verify(workManagerController).cancelAllWork() verify(preferences).setValue(SESSION_LOCKED, false) verify(userManager.d2.dataStoreModule().localDataStore().value(PIN)).blockingDeleteIfExist() + verify(filterManager).clearAllFilters() verify(view).goToLogin(1, false) } From a837538f14edf1c5646246cec2039ed2846b6ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Miguel=20Rubio?= Date: Wed, 27 Nov 2024 10:01:14 +0100 Subject: [PATCH 03/11] fix: [ANDROAPP-6691] Null pointer on show dialog (#3904) Signed-off-by: andresmr --- .../usescases/datasets/dataSetTable/DataSetTableActivity.kt | 3 +-- .../programEventDetail/ProgramEventDetailActivity.kt | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/DataSetTableActivity.kt b/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/DataSetTableActivity.kt index b16f784076..07870ed8a1 100644 --- a/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/DataSetTableActivity.kt +++ b/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/DataSetTableActivity.kt @@ -184,9 +184,8 @@ class DataSetTableActivity : ActivityGlobalAbstract(), DataSetTableContract.View } }) .onNoConnectionListener { - val contextView = findViewById(R.id.navigationBar) Snackbar.make( - contextView, + binding.root, R.string.sync_offline_check_connection, Snackbar.LENGTH_SHORT, ).show() diff --git a/app/src/main/java/org/dhis2/usescases/programEventDetail/ProgramEventDetailActivity.kt b/app/src/main/java/org/dhis2/usescases/programEventDetail/ProgramEventDetailActivity.kt index 642fbe283d..3fac0ea471 100644 --- a/app/src/main/java/org/dhis2/usescases/programEventDetail/ProgramEventDetailActivity.kt +++ b/app/src/main/java/org/dhis2/usescases/programEventDetail/ProgramEventDetailActivity.kt @@ -273,9 +273,8 @@ class ProgramEventDetailActivity : } }) .onNoConnectionListener { - val contextView = findViewById(R.id.navigationBar) Snackbar.make( - contextView, + binding.root, R.string.sync_offline_check_connection, Snackbar.LENGTH_SHORT, ).show() @@ -524,9 +523,8 @@ class ProgramEventDetailActivity : } }) .onNoConnectionListener { - val contextView = findViewById(R.id.rootView) Snackbar.make( - contextView, + binding.root, R.string.sync_offline_check_connection, Snackbar.LENGTH_SHORT, ).show() From b16db7afa5e1df2a60619d57ffe1a7ce303c3c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tar=C3=AD?= Date: Fri, 29 Nov 2024 13:20:33 +0100 Subject: [PATCH 04/11] update SDK version for 3.1.0.1 hotfix (#3911) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2908f4b037..fe0f21ba6b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ kotlin = '2.0.20' hilt = '2.47' jacoco = '0.8.10' designSystem = "0.4.0" -dhis2sdk = "1.11.0" +dhis2sdk = "1.11.0.1-SNAPSHOT" ruleEngine = "3.0.0" expressionParser = "1.1.0" appcompat = "1.6.1" From 964ef103aeb6e5d520556471f061bd693c39fb3d Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 29 Nov 2024 14:07:24 +0100 Subject: [PATCH 05/11] hotfix: Handle large option sets (#3901) * fix: [ANDROAPP-6653] Large option sets freeze app * update design system version * fix period selector * fix unit tests * remove commented code * fix test and remove those deprecated * fix sonarcloud warnings * remove commented code * fix: option set not searching * fix integration test * fix code smell * fix code smell * fix code smell --- .../tablefields/spinner/SpinnerViewModel.java | 16 - .../usescases/enrollment/EnrollmentModule.kt | 5 +- .../providers/InputFieldsProvider.kt | 41 ++- .../EventInitialRepositoryImpl.java | 24 +- .../SearchRepositoryImplKt.kt | 97 +++--- .../teiDashboard/TeiDashboardModule.kt | 3 +- .../dialogs/scheduling/SchedulingDialogUi.kt | 27 +- .../utils/optionset/OptionSetPresenter.kt | 23 -- .../form/data/DataEntryBaseRepository.kt | 70 +++-- .../dhis2/form/data/DataEntryRepository.kt | 11 + .../dhis2/form/data/EnrollmentRepository.kt | 43 ++- .../org/dhis2/form/data/EventRepository.kt | 50 ++-- .../org/dhis2/form/data/FormRepository.kt | 1 + .../org/dhis2/form/data/FormRepositoryImpl.kt | 151 +++++++++- .../org/dhis2/form/data/GeometryController.kt | 1 - .../form/data/RuleUtilsProviderResult.kt | 3 + .../data/metadata/EnrollmentConfiguration.kt | 30 +- .../data/metadata/FormBaseConfiguration.kt | 36 +++ .../main/java/org/dhis2/form/di/Injector.kt | 2 +- .../java/org/dhis2/form/model/ActionType.kt | 1 + .../org/dhis2/form/model/FieldUiModelImpl.kt | 8 +- .../form/model/OptionSetConfiguration.kt | 100 ++----- .../form/model/OptionSetDialogViewModel.kt | 4 +- .../java/org/dhis2/form/model/UiEventType.kt | 12 - .../main/java/org/dhis2/form/ui/FormView.kt | 282 +----------------- .../java/org/dhis2/form/ui/FormViewModel.kt | 17 ++ .../org/dhis2/form/ui/event/DialogDelegate.kt | 92 ------ .../form/ui/event/RecyclerViewUiEvents.kt | 42 --- .../dhis2/form/ui/event/UiEventFactoryImpl.kt | 103 ------- .../org/dhis2/form/ui/intent/FormIntent.kt | 6 + .../inputfield/CategorySelectorProvider.kt | 32 +- .../provider/inputfield/CheckBoxProvider.kt | 31 +- .../provider/inputfield/DropdownProvider.kt | 38 ++- .../ui/provider/inputfield/FieldProvider.kt | 11 + .../inputfield/MatrixInputProvider.kt | 20 +- .../inputfield/MatrixSequentialUtilites.kt | 2 +- .../inputfield/MultiSelectionInputProvider.kt | 31 +- .../inputfield/PeriodSelectorProvider.kt | 15 +- .../inputfield/RadioButtonProvider.kt | 31 +- .../inputfield/SequentialInputProvider.kt | 20 +- .../form/data/EnrollmentRepositoryTest.kt | 3 + .../org/dhis2/form/data/FieldUiModelTest.kt | 92 ------ .../data/FormRepositoryIntegrationTest.kt | 3 + .../dhis2/form/data/GeometryControllerTest.kt | 35 --- .../form/integration/ProgramRulesTest.kt | 94 +++--- .../model/OptionSetDialogViewModelTest.kt | 61 ---- .../dhis2/form/ui/DataEntryIntegrationTest.kt | 58 ++-- .../form/ui/event/UiEventFactoryImplTest.kt | 74 ----- gradle/libs.versions.toml | 2 +- 49 files changed, 743 insertions(+), 1211 deletions(-) delete mode 100644 form/src/main/java/org/dhis2/form/ui/event/DialogDelegate.kt delete mode 100644 form/src/test/java/org/dhis2/form/data/FieldUiModelTest.kt delete mode 100644 form/src/test/java/org/dhis2/form/ui/event/UiEventFactoryImplTest.kt diff --git a/app/src/main/java/org/dhis2/data/forms/dataentry/tablefields/spinner/SpinnerViewModel.java b/app/src/main/java/org/dhis2/data/forms/dataentry/tablefields/spinner/SpinnerViewModel.java index f44f0b2198..6c558e725f 100644 --- a/app/src/main/java/org/dhis2/data/forms/dataentry/tablefields/spinner/SpinnerViewModel.java +++ b/app/src/main/java/org/dhis2/data/forms/dataentry/tablefields/spinner/SpinnerViewModel.java @@ -12,9 +12,6 @@ @AutoValue public abstract class SpinnerViewModel extends FieldViewModel { - private List optionsToHide; - private List optionGroupsToHide; - @NonNull public abstract String hint(); @@ -52,17 +49,4 @@ public FieldViewModel withWarning(@NonNull String warning) { public FieldViewModel withValue(String data) { return new AutoValue_SpinnerViewModel(uid(),label(),mandatory(),data,programStageSection(),allowFutureDate(),editable(),warning(),error(),description(),dataElement(), options(), optionsList(), storeBy(), row(), column(),categoryOptionCombo(), catCombo(),hint(),optionSet()); } - - public void setOptionsToHide(List optionsToHide, List optionsGroupsToHide) { - this.optionsToHide = optionsToHide; - this.optionGroupsToHide = optionsGroupsToHide; - } - - public List getOptionsToHide() { - return optionsToHide; - } - - public List getOptionGroupsToHide() { - return optionGroupsToHide; - } } diff --git a/app/src/main/java/org/dhis2/usescases/enrollment/EnrollmentModule.kt b/app/src/main/java/org/dhis2/usescases/enrollment/EnrollmentModule.kt index 16790d2b35..ca121488f0 100644 --- a/app/src/main/java/org/dhis2/usescases/enrollment/EnrollmentModule.kt +++ b/app/src/main/java/org/dhis2/usescases/enrollment/EnrollmentModule.kt @@ -84,8 +84,7 @@ class EnrollmentModule( @PerActivity fun provideEnrollmentConfiguration( d2: D2, - metadataIconProvider: MetadataIconProvider, - ) = EnrollmentConfiguration(d2, enrollmentUid, metadataIconProvider) + ) = EnrollmentConfiguration(d2, enrollmentUid) @Provides @PerActivity @@ -93,12 +92,14 @@ class EnrollmentModule( modelFactory: FieldViewModelFactory, enrollmentFormLabelsProvider: EnrollmentFormLabelsProvider, enrollmentConfiguration: EnrollmentConfiguration, + metadataIconProvider: MetadataIconProvider, ): EnrollmentRepository { return EnrollmentRepository( fieldFactory = modelFactory, conf = enrollmentConfiguration, enrollmentMode = EnrollmentMode.valueOf(enrollmentMode.name), enrollmentFormLabelsProvider = enrollmentFormLabelsProvider, + metadataIconProvider = metadataIconProvider, ) } diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventDetails/providers/InputFieldsProvider.kt b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventDetails/providers/InputFieldsProvider.kt index 73acff526a..51e2978dc9 100644 --- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventDetails/providers/InputFieldsProvider.kt +++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventDetails/providers/InputFieldsProvider.kt @@ -53,10 +53,16 @@ fun ProvideInputDate( ) { if (uiModel.showField) { Spacer(modifier = Modifier.height(16.dp)) - val textSelection = TextRange(if (uiModel.eventDate.dateValue != null) uiModel.eventDate.dateValue.length else 0) + val textSelection = + TextRange(if (uiModel.eventDate.dateValue != null) uiModel.eventDate.dateValue.length else 0) var value by remember(uiModel.eventDate.dateValue) { if (uiModel.eventDate.dateValue != null) { - mutableStateOf(TextFieldValue(formatStoredDateToUI(uiModel.eventDate.dateValue) ?: "", textSelection)) + mutableStateOf( + TextFieldValue( + formatStoredDateToUI(uiModel.eventDate.dateValue) ?: "", + textSelection, + ), + ) } else { mutableStateOf(TextFieldValue()) } @@ -66,7 +72,10 @@ fun ProvideInputDate( mutableStateOf(getInputState(uiModel.detailsEnabled)) } val yearRange = if (uiModel.selectableDates != null) { - IntRange(uiModel.selectableDates.initialDate.substring(4, 8).toInt(), uiModel.selectableDates.endDate.substring(4, 8).toInt()) + IntRange( + uiModel.selectableDates.initialDate.substring(4, 8).toInt(), + uiModel.selectableDates.endDate.substring(4, 8).toInt(), + ) } else { IntRange(1924, 2124) } @@ -90,7 +99,10 @@ fun ProvideInputDate( } }, is24hourFormat = uiModel.is24HourFormat, - selectableDates = uiModel.selectableDates ?: SelectableDates("01011924", "12312124"), + selectableDates = uiModel.selectableDates ?: SelectableDates( + "01011924", + "12312124", + ), yearRange = yearRange, ), modifier = modifier.testTag(INPUT_EVENT_INITIAL_DATE), @@ -246,15 +258,23 @@ fun ProvideCategorySelector( selectedItem = null eventCatComboUiModel.onClearCatCombo(eventCatComboUiModel.category) }, - onItemSelected = { newSelectedDropdownItem -> + onItemSelected = { _, newSelectedDropdownItem -> selectedItem = newSelectedDropdownItem.label eventCatComboUiModel.onOptionSelected(selectableOptions.firstOrNull { it.displayName() == newSelectedDropdownItem.label }) }, - dropdownItems = dropdownItems, + fetchItem = { index -> dropdownItems[index] }, + itemCount = dropdownItems.size, + onSearchOption = { /*no-op*/ }, + loadOptions = { /*no-op*/ }, + useDropDown = dropdownItems.size < 15, isRequiredField = eventCatComboUiModel.required, ) } else { - ProvideEmptyCategorySelector(modifier = modifier, name = eventCatComboUiModel.category.name, option = eventCatComboUiModel.noOptionsText) + ProvideEmptyCategorySelector( + modifier = modifier, + name = eventCatComboUiModel.category.name, + option = eventCatComboUiModel.noOptionsText, + ) } } @@ -316,10 +336,13 @@ fun ProvideEmptyCategorySelector( onResetButtonClicked = { selectedItem = "" }, - onItemSelected = { newSelectedDropdownItem -> + onItemSelected = { _, newSelectedDropdownItem -> selectedItem = newSelectedDropdownItem.label }, - dropdownItems = listOf(DropdownItem(option)), + fetchItem = { DropdownItem(option) }, + itemCount = 1, + onSearchOption = { /*no-op*/ }, + loadOptions = { /*no-op*/ }, isRequiredField = false, ) } diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventInitial/EventInitialRepositoryImpl.java b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventInitial/EventInitialRepositoryImpl.java index ab345fd56a..141d1af9ce 100644 --- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventInitial/EventInitialRepositoryImpl.java +++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventInitial/EventInitialRepositoryImpl.java @@ -45,6 +45,8 @@ import io.reactivex.Flowable; import io.reactivex.Observable; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; import timber.log.Timber; public class EventInitialRepositoryImpl implements EventInitialRepository { @@ -328,22 +330,12 @@ private FieldUiModel transform(@NonNull ProgramStageDataElement stage, DataEleme if (!dataValueOptions.isEmpty()) { dataValue = option.get(0).displayName(); } - optionSetConfig = OptionSetConfiguration.Companion.config( - d2.optionModule().options().byOptionSetUid().eq(optionSet).blockingCount(), - () -> { - List