From 9da04c7c424fb35fccf2f12e7f8365d92f1f6a0e Mon Sep 17 00:00:00 2001 From: bennsimon Date: Fri, 20 Aug 2021 11:26:51 +0300 Subject: [PATCH] add multidistrict select feature --- build.gradle | 10 ++-- opensrp-eusm/build.gradle | 16 +++--- opensrp-eusm/src/main/assets/app.properties | 1 + .../eusm/application/EusmApplication.java | 3 +- .../AppTaskingLibraryConfiguration.java | 6 +- .../eusm/fragment/ProductInfoFragment.java | 1 - .../interactor/EusmTaskingMapInteractor.java | 22 ++++--- .../ProductInfoActivityInteractor.java | 53 ++++++----------- .../model/StructureRegisterFragmentModel.java | 16 +++--- .../presenter/EusmBaseDrawerPresenter.java | 22 ++++++- .../repository/AppLocationRepository.java | 25 +++++++- .../repository/AppStructureRepository.java | 34 +++++------ .../org/smartregister/eusm/util/AppUtils.java | 6 ++ .../eusm/view/EusmTreeViewDialog.java | 50 ++++++++++++++++ .../eusm/view/NavigationDrawerView.java | 57 +++++++++++++++---- .../TreeSelectionItemViewHolder.java | 19 +++++++ opensrp-eusm/src/main/res/values/strings.xml | 1 + .../eusm/application/EusmApplicationTest.java | 3 +- .../EusmTaskingMapInteractorTest.java | 6 +- .../AppStructureRepositoryTest.java | 12 +++- 20 files changed, 256 insertions(+), 107 deletions(-) create mode 100644 opensrp-eusm/src/main/java/org/smartregister/eusm/view/EusmTreeViewDialog.java create mode 100644 opensrp-eusm/src/main/java/org/smartregister/eusm/viewholder/TreeSelectionItemViewHolder.java diff --git a/build.gradle b/build.gradle index 1b43e16..6eb057b 100644 --- a/build.gradle +++ b/build.gradle @@ -19,11 +19,11 @@ subprojects { group = 'org.smartregister' - ext.androidToolsBuildGradle = '27.0.3' - ext.androidBuildToolsVersion = '27.0.3' - ext.androidMinSdkVersion = 16 - ext.androidCompileSdkVersion = 28 - ext.androidTargetSdkVersion = 27 + ext.androidToolsBuildGradle = '29.0.3' + ext.androidBuildToolsVersion = '29.0.3' + ext.androidMinSdkVersion = 18 + ext.androidCompileSdkVersion = 29 + ext.androidTargetSdkVersion = 29 ext.androidAnnotationsVersion = '3.0.1'; ext.androidAnnotationsAPIVersion = '3.0.1'; diff --git a/opensrp-eusm/build.gradle b/opensrp-eusm/build.gradle index 931f5b5..527a749 100644 --- a/opensrp-eusm/build.gradle +++ b/opensrp-eusm/build.gradle @@ -37,8 +37,8 @@ jacoco { android { - compileSdkVersion 28 - buildToolsVersion "29.0.3" + compileSdkVersion androidCompileSdkVersion + buildToolsVersion androidToolsBuildGradle compileOptions { coreLibraryDesugaringEnabled true @@ -48,10 +48,10 @@ android { defaultConfig { applicationId "org.smartregister.eusm" - minSdkVersion 18 - targetSdkVersion 28 + minSdkVersion androidMinSdkVersion + targetSdkVersion androidTargetSdkVersion versionCode 1 - versionName "0.0.9" + versionName "0.1.0" multiDexEnabled true buildConfigField "long", "MAX_SERVER_TIME_DIFFERENCE", "1800000l" buildConfigField "boolean", "TIME_CHECK", "false" @@ -201,7 +201,7 @@ dependencies { jarJar 'com.ibm.fhir:fhir-model:4.7.0' - implementation('org.smartregister:opensrp-client-core:4.3.10-SNAPSHOT@aar') { + implementation('org.smartregister:opensrp-client-core:4.3.16-SNAPSHOT@aar') { transitive = true exclude group: 'com.android.support', module: 'appcompat-v7' exclude group: 'com.github.ybq', module: 'Android-SpinKit' @@ -218,7 +218,7 @@ dependencies { exclude group: 'com.android.support', module: 'appcompat-v7' } - implementation('org.smartregister:opensrp-client-native-form:2.0.6-SNAPSHOT@aar') { + implementation('org.smartregister:opensrp-client-native-form:2.1.3-r12-SNAPSHOT@aar') { transitive = true exclude group: 'com.android.support', module: 'appcompat-v7' exclude group: 'com.android.support', module: 'cardview-v7' @@ -229,7 +229,7 @@ dependencies { } // implementation(project(':opensrp-tasking')) { - implementation('org.smartregister:opensrp-client-tasking:0.0.3-v17-EUSM-SNAPSHOT') { + implementation('org.smartregister:opensrp-client-tasking:0.0.3-v18-r5-EUSM-SNAPSHOT') { transitive = true exclude group: 'org.smartregister', module: 'opensrp-client-core' exclude group: 'com.ibm.fhir', module: 'fhir-model' diff --git a/opensrp-eusm/src/main/assets/app.properties b/opensrp-eusm/src/main/assets/app.properties index acb98b1..1664c25 100644 --- a/opensrp-eusm/src/main/assets/app.properties +++ b/opensrp-eusm/src/main/assets/app.properties @@ -5,3 +5,4 @@ SYNC_DOWNLOAD_BATCH_SIZE=100 CHOOSE_OPERATIONAL_AREA_FIRST=false select_plan_then_area=true allow.offline.login.with.invalid.token=true +ALLOW_MULTIPLE_OPERATIONAL_AREA_SELECTION=true \ No newline at end of file diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/application/EusmApplication.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/application/EusmApplication.java index 2f5b46d..9d1600e 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/application/EusmApplication.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/application/EusmApplication.java @@ -353,7 +353,8 @@ public void setUserLocation(Location userLocation) { @Override public void onUserAssignmentRevoked(UserAssignmentDTO userAssignmentDTO) { PreferencesUtil preferencesUtil = PreferencesUtil.getInstance(); - if (userAssignmentDTO.getJurisdictions().contains(preferencesUtil.getCurrentOperationalAreaId())) { + + if (userAssignmentDTO.getJurisdictions().containsAll(preferencesUtil.getCurrentOperationalAreaIds())) { preferencesUtil.setCurrentOperationalArea(null); } if (userAssignmentDTO.getPlans().contains(preferencesUtil.getCurrentPlanId())) { diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/config/AppTaskingLibraryConfiguration.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/config/AppTaskingLibraryConfiguration.java index b1cb8b5..b384f39 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/config/AppTaskingLibraryConfiguration.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/config/AppTaskingLibraryConfiguration.java @@ -18,6 +18,7 @@ import net.sqlcipher.database.SQLiteDatabase; +import org.apache.commons.lang3.StringUtils; import org.json.JSONObject; import org.smartregister.clientandeventmodel.Event; import org.smartregister.commonregistry.CommonPersonObjectClient; @@ -136,8 +137,8 @@ public boolean isMDA() { @Override public String getCurrentLocationId() { - Location currentOperationalArea = AppUtils.getOperationalAreaLocation(PreferencesUtil.getInstance().getCurrentOperationalArea()); - return currentOperationalArea == null ? null : currentOperationalArea.getId(); + Set currentOperationalAreas = AppUtils.getOperationalAreaLocations(PreferencesUtil.getInstance().getCurrentOperationalAreas()); + return !currentOperationalAreas.isEmpty() ? currentOperationalAreas.stream().filter(location -> location.getId() != null).map(location -> location.getId()).collect(Collectors.joining( PreferencesUtil.OPERATIONAL_AREA_SEPARATOR)) : null; } @Override @@ -481,6 +482,7 @@ public double getOnClickMaxZoomLevel() { @Override public void fetchPlans(String jurisdictionName, BaseDrawerContract.Presenter presenter) { + // TODO: jurisdictionName comma separated PlanDefinitionRepository planDefinitionRepository = EusmApplication.getInstance().getPlanDefinitionRepository(); Set planDefinitionSet = planDefinitionRepository.findAllPlanDefinitions(); getAppExecutors().mainThread().execute(new Runnable() { diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/fragment/ProductInfoFragment.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/fragment/ProductInfoFragment.java index 391e3e8..b5cd285 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/fragment/ProductInfoFragment.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/fragment/ProductInfoFragment.java @@ -34,7 +34,6 @@ public static ProductInfoFragment newInstance(Bundle bundle) { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); taskDetail = (TaskDetail) getArguments().getSerializable(AppConstants.IntentData.TASK_DETAIL); -// StructureDetail structureDetail = (StructureDetail) getArguments().getSerializable(AppConstants.IntentData.STRUCTURE_DETAIL); initializeAdapter(); initializePresenter(); } diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/interactor/EusmTaskingMapInteractor.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/interactor/EusmTaskingMapInteractor.java index 82ecd40..239022c 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/interactor/EusmTaskingMapInteractor.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/interactor/EusmTaskingMapInteractor.java @@ -12,10 +12,14 @@ import org.smartregister.eusm.util.GeoJsonUtils; import org.smartregister.tasking.contract.TaskingMapActivityContract; import org.smartregister.tasking.interactor.TaskingMapInteractor; +import org.smartregister.tasking.util.PreferencesUtil; import org.smartregister.tasking.util.TaskingConstants; -import org.smartregister.tasking.util.Utils; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import timber.log.Timber; @@ -35,13 +39,14 @@ public void fetchLocations(String plan, String operationalArea, String point, Bo appExecutors.diskIO().execute(new Runnable() { @Override public void run() { - Location operationalAreaLocation = getOperationalAreaLocation(operationalArea); + Set operationalAreaLocations = getOperationalAreaLocations(new HashSet<>(Arrays.asList(operationalArea.split(PreferencesUtil.OPERATIONAL_AREA_SEPARATOR)))); + JSONObject featureCollection = null; try { featureCollection = createFeatureCollection(); - if (operationalAreaLocation != null) { + if (!operationalAreaLocations.isEmpty()) { List structureDetails = appStructureRepository - .fetchStructureDetails(null, operationalAreaLocation.getId(), null, true, plan); + .fetchStructureDetails(null, operationalAreaLocations.stream().filter(location -> location.getId() != null).map(location -> location.getId()).collect(Collectors.toSet()), null, true, plan); if (structureDetails != null && !structureDetails.isEmpty()) { String features = geoJsonUtils.getGeoJsonFromStructureDetail(structureDetails); @@ -55,9 +60,8 @@ public void run() { appExecutors.mainThread().execute(new Runnable() { @Override public void run() { - if (operationalAreaLocation != null) { - operationalAreaId = operationalAreaLocation.getId(); - Feature operationalAreaFeature = Feature.fromJson(gson.toJson(operationalAreaLocation)); + if (!operationalAreaLocations.isEmpty()) { + Feature operationalAreaFeature = Feature.fromJson(gson.toJson(operationalAreaLocations.stream().findFirst().orElse(null))); if (locationComponentActive != null) { getPresenter().onStructuresFetched(finalFeatureCollection, operationalAreaFeature, null, point, locationComponentActive); } else { @@ -72,7 +76,7 @@ public void run() { }); } - protected Location getOperationalAreaLocation(String operationalArea) { - return AppUtils.getOperationalAreaLocation(operationalArea); + protected Set getOperationalAreaLocations(Set operationalAreas) { + return AppUtils.getOperationalAreaLocations(operationalAreas); } } diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/interactor/ProductInfoActivityInteractor.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/interactor/ProductInfoActivityInteractor.java index e9f006a..3416aac 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/interactor/ProductInfoActivityInteractor.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/interactor/ProductInfoActivityInteractor.java @@ -19,7 +19,6 @@ import org.smartregister.util.AppExecutors; import java.util.Collections; -import java.util.concurrent.atomic.AtomicInteger; import timber.log.Timber; @@ -39,13 +38,10 @@ public void saveFlagProblemForm(TaskDetail taskDetail, String encounterType, JSONObject jsonForm, StructureDetail structureDetail, ProductInfoActivityContract.InteractorCallback interactorCallback) { - appExecutors.diskIO().execute(new Runnable() { - @Override - public void run() { - getJsonFormUtils().saveImage(jsonForm, AppConstants.EventEntityType.PRODUCT); - saveEventAndInitiateProcessing(encounterType, jsonForm, "", interactorCallback, - AppConstants.EventEntityType.PRODUCT); - } + appExecutors.diskIO().execute(() -> { + getJsonFormUtils().saveImage(jsonForm, AppConstants.EventEntityType.PRODUCT); + saveEventAndInitiateProcessing(encounterType, jsonForm, "", interactorCallback, + AppConstants.EventEntityType.PRODUCT); }); } @@ -56,63 +52,46 @@ public void saveEventAndInitiateProcessing(String encounterType, JSONObject form try { Event event = AppUtils.createEventFromJsonForm(form, encounterType, bindType, entityId); try { - AtomicInteger count = new AtomicInteger(1); IntentFilter filter = new IntentFilter(TASK_GENERATED_EVENT); TaskGenerationReceiver taskGenerationReceiver = new TaskGenerationReceiver(task -> - appExecutors.mainThread().execute(() -> returnResponse(interactorCallback, event, true, count.getAndIncrement())), - AppConstants.EncounterType.FLAG_PROBLEM.equals(encounterType) ? 2 : 1); + appExecutors.mainThread().execute(() -> returnResponse(interactorCallback, event, true))); LocalBroadcastManager.getInstance(EusmApplication.getInstance().getApplicationContext()).registerReceiver(taskGenerationReceiver, filter); - AppUtils.initiateEventProcessing(Collections.singletonList(event.getFormSubmissionId())); } catch (Exception e) { Timber.e(e); - returnResponse(interactorCallback, event, false, 0); + returnResponse(interactorCallback, event, false); } } catch (JSONException e) { Timber.e(e); - returnResponse(interactorCallback, null, false, 0); + returnResponse(interactorCallback, null, false); } } @Override public void markProductAsGood(StructureDetail structureDetail, TaskDetail taskDetail, ProductInfoActivityContract.InteractorCallback callBack, Activity activity) { - appExecutors.diskIO().execute(new Runnable() { - @Override - public void run() { - JSONObject jsonObject = getJsonFormUtils() - .getFormObjectWithDetails(activity, AppConstants.JsonForm.LOOKS_GOOD, structureDetail, taskDetail); - saveEventAndInitiateProcessing(AppConstants.EncounterType.LOOKS_GOOD, jsonObject, - "", callBack, AppConstants.EventEntityType.PRODUCT); - } + appExecutors.diskIO().execute(() -> { + JSONObject jsonObject = getJsonFormUtils() + .getFormObjectWithDetails(activity, AppConstants.JsonForm.LOOKS_GOOD, structureDetail, taskDetail); + saveEventAndInitiateProcessing(AppConstants.EncounterType.LOOKS_GOOD, jsonObject, + "", callBack, AppConstants.EventEntityType.PRODUCT); }); } @Override public void startFlagProblemForm(StructureDetail structureDetail, TaskDetail taskDetail, String formName, Activity activity, ProductInfoActivityContract.InteractorCallback interactorCallBack) { - appExecutors.diskIO().execute(new Runnable() { - @Override - public void run() { - JSONObject form = getJsonFormUtils().getFormObjectWithDetails(activity, formName, structureDetail, taskDetail); - appExecutors.mainThread().execute(new Runnable() { - @Override - public void run() { - interactorCallBack.onFlagProblemFormFetched(form); - } - }); - } + appExecutors.diskIO().execute(() -> { + JSONObject form = getJsonFormUtils().getFormObjectWithDetails(activity, formName, structureDetail, taskDetail); + appExecutors.mainThread().execute(() -> interactorCallBack.onFlagProblemFormFetched(form)); }); } private void returnResponse(ProductInfoActivityContract.InteractorCallback interactorCallback, - Event event, boolean status, int callCount) { + Event event, boolean status) { if (event != null && event.getDetails() != null) { String encounterType = event.getEventType(); if (AppConstants.EncounterType.FLAG_PROBLEM.equals(encounterType)) { - if (status && callCount < 2) { - return; - } interactorCallback.onSavedFlagProblemTask(status, event); } else if (AppConstants.EncounterType.LOOKS_GOOD.equals(encounterType)) { interactorCallback.onProductMarkedAsGood(status, event); diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/model/StructureRegisterFragmentModel.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/model/StructureRegisterFragmentModel.java index 611336e..c276e58 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/model/StructureRegisterFragmentModel.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/model/StructureRegisterFragmentModel.java @@ -1,15 +1,13 @@ package org.smartregister.eusm.model; -import org.smartregister.domain.Location; import org.smartregister.eusm.application.EusmApplication; import org.smartregister.eusm.domain.StructureDetail; import org.smartregister.eusm.repository.AppStructureRepository; -import org.smartregister.eusm.util.AppUtils; import org.smartregister.tasking.util.PreferencesUtil; -import org.smartregister.tasking.util.Utils; import java.util.ArrayList; import java.util.List; +import java.util.Set; public class StructureRegisterFragmentModel { @@ -20,18 +18,18 @@ public StructureRegisterFragmentModel() { } public int countOfStructures(String nameFilter) { - Location location = AppUtils.getOperationalAreaLocation(PreferencesUtil.getInstance().getCurrentOperationalArea()); - if (location != null) { - return appStructureRepository.countOfStructures(nameFilter, location.getId(), PreferencesUtil.getInstance().getCurrentPlanId()); + Set locations = PreferencesUtil.getInstance().getCurrentOperationalAreaIds(); + if (!locations.isEmpty()) { + return appStructureRepository.countOfStructures(nameFilter, locations, PreferencesUtil.getInstance().getCurrentPlanId()); } else { return 0; } } public List fetchStructures(int pageNo, String nameFilter) { - Location location = AppUtils.getOperationalAreaLocation(PreferencesUtil.getInstance().getCurrentOperationalArea()); - if (location != null) { - return appStructureRepository.fetchStructureDetails(pageNo, location.getId(), nameFilter, PreferencesUtil.getInstance().getCurrentPlanId()); + Set locations = PreferencesUtil.getInstance().getCurrentOperationalAreaIds(); + if (!locations.isEmpty()) { + return appStructureRepository.fetchStructureDetails(pageNo, locations, nameFilter, PreferencesUtil.getInstance().getCurrentPlanId()); } else { return new ArrayList<>(); } diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/presenter/EusmBaseDrawerPresenter.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/presenter/EusmBaseDrawerPresenter.java index e0a6f6c..63f6f7b 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/presenter/EusmBaseDrawerPresenter.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/presenter/EusmBaseDrawerPresenter.java @@ -88,15 +88,33 @@ public String getEntireTree(List entireTree) { List jurisdictionList = planDefinitionSearches.stream().map(PlanDefinitionSearch::getJurisdictionId).collect(Collectors.toList()); LocationRepository locationRepository = drishtiApplication.getContext().getLocationRepository(); List locationList = locationRepository.getLocationsByIds(jurisdictionList); + List formLocations = filterLocations(locationList.stream().map(location -> location.getProperties().getName() ).collect(Collectors.toList()), entireTree); - + cleanUpFormLocations(formLocations); return AssetHandler.javaToJsonString(formLocations, new TypeToken>() { }.getType()); } + + private void cleanUpFormLocations(List formLocations) { + if (!formLocations.isEmpty()) { + FormLocation root = formLocations.get(0); + if (root.nodes != null && !root.nodes.isEmpty()) { + Iterator locationIterable = root.nodes.iterator(); + while (locationIterable.hasNext()) { + FormLocation formLocation = locationIterable.next(); + if (formLocation.nodes.isEmpty()) { + locationIterable.remove(); + } + } + } + } + } + + /** * Filter out district not in the plan * @@ -123,4 +141,6 @@ private List filterLocations(List filteredIn, List getLocationByNameAndGeoLevel(Set names, String level) { + Set locations = new HashSet<>(); + + if (names == null || names.isEmpty()) + return locations; + try (Cursor cursor = getReadableDatabase().rawQuery("SELECT * FROM " + getLocationTableName() + + " WHERE " + StringUtils.repeat(NAME + " =?", " OR ", names.size()) + " AND " + GEOGRAPHICAL_LEVEL + "=?", ArrayUtils.add(names.toArray(new String[0]), level))) { + if (cursor != null) { + while (cursor.moveToNext()) { + locations.add(readCursor(cursor)); + } + } + } catch (SQLException e) { + Timber.e(e); + } + return locations; + } } diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/repository/AppStructureRepository.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/repository/AppStructureRepository.java index d023e87..428aa1c 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/repository/AppStructureRepository.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/repository/AppStructureRepository.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Set; import timber.log.Timber; @@ -93,25 +94,28 @@ public void addOrUpdate(org.smartregister.domain.Location location) { getWritableDatabase().replace(getLocationTableName(), null, contentValues); } - public int countOfStructures(String nameFilter, String locationParentId, String planId) { + public int countOfStructures(String nameFilter, Set locationParentIds, String planId) { + int count = 0; + + if (locationParentIds == null || locationParentIds.isEmpty()) + return count; SQLiteDatabase sqLiteDatabase = getReadableDatabase(); String query = "SELECT count(DISTINCT structure._id) from " + STRUCTURE_TABLE; - String[] args = StringUtils.stripAll(locationParentId, planId); + String[] args = ArrayUtils.addAll(locationParentIds.toArray(new String[0]), planId); query += " join task on task.for = " + StructureRepository.STRUCTURE_TABLE + "._id "; query += " join location on location._id = " + StructureRepository.STRUCTURE_TABLE + ".parent_id "; - query += " where location.parent_id = ? AND task.plan_id = ?"; + query += " where " + "(" + StringUtils.repeat("location.parent_id = ? ", " OR ", locationParentIds.size()) + ")" + " AND task.plan_id = ?"; if (StringUtils.isNotBlank(nameFilter)) { - args = StringUtils.stripAll(locationParentId, planId, "%" + nameFilter + "%"); + args = ArrayUtils.addAll(args, "%" + nameFilter + "%"); query += " and " + STRUCTURE_TABLE + "." + NAME + " like ? "; } - int count = 0; try (Cursor cursor = sqLiteDatabase.rawQuery(query, args)) { if (cursor != null && cursor.moveToNext()) { count = cursor.getInt(0); @@ -122,13 +126,14 @@ public int countOfStructures(String nameFilter, String locationParentId, String return count; } - public List fetchStructureDetails(int pageNo, String locationParentId, String nameFilter, String planId) { - return fetchStructureDetails(pageNo, locationParentId, nameFilter, false, planId); + public List fetchStructureDetails(int pageNo, Set locationParentIds, String nameFilter, String planId) { + return fetchStructureDetails(pageNo, locationParentIds, nameFilter, false, planId); } - public List fetchStructureDetails(Integer pageNo, String locationParentId, + public List fetchStructureDetails(Integer pageNo, Set locationParentIds, String nameFilter, boolean isForMapping, String planId) { - + if (locationParentIds == null || locationParentIds.isEmpty()) + return new ArrayList<>(); Location location = EusmApplication.getInstance().getUserLocation(); List structureDetails = new ArrayList<>(); @@ -159,17 +164,12 @@ public List fetchStructureDetails(Integer pageNo, String locati + " join task on task.structure_id = " + StructureRepository.STRUCTURE_TABLE + "._id " + " join location on location._id = " + StructureRepository.STRUCTURE_TABLE + ".parent_id "; - String[] args = StringUtils.stripAll( - planId, - locationParentId); + String[] args = ArrayUtils.addAll(new String[]{planId}, locationParentIds.toArray(new String[0])); - query += " where task.plan_id = ? AND locationParentId = ? "; + query += " where task.plan_id = ? AND (" + StringUtils.repeat("locationParentId = ? ", " OR ", locationParentIds.size()) + ")"; if (StringUtils.isNotBlank(nameFilter)) { - args = StringUtils.stripAll( - planId, - locationParentId, - "%" + nameFilter + "%"); + args = ArrayUtils.addAll(args, "%" + nameFilter + "%"); query += " and structureName like ? "; } diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/util/AppUtils.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/util/AppUtils.java index 8f34fa8..3295115 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/util/AppUtils.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/util/AppUtils.java @@ -203,6 +203,12 @@ public static org.smartregister.domain.Location getOperationalAreaLocation(Strin }); } + public static Set getOperationalAreaLocations(Set operationalAreas) { + return EusmApplication.getInstance().getAppLocationRepository() + .getLocationByNameAndGeoLevel(operationalAreas, "2");//restrict to district geographic level + } + + public static Pair getLatLongFromForm(@NonNull JSONObject form) { JSONArray formFields = JsonFormUtils.getMultiStepFormFields(form); for (int i = 0; i < formFields.length(); i++) { diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/view/EusmTreeViewDialog.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/view/EusmTreeViewDialog.java new file mode 100644 index 0000000..ccddcda --- /dev/null +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/view/EusmTreeViewDialog.java @@ -0,0 +1,50 @@ +package org.smartregister.eusm.view; + +import android.content.Context; + +import com.unnamed.b.atv.model.TreeNode; +import com.vijay.jsonwizard.customviews.TreeViewDialog; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.smartregister.eusm.viewholder.TreeSelectionItemViewHolder; +import org.smartregister.tasking.util.PreferencesUtil; + +import java.util.ArrayList; +import java.util.Set; + +public class EusmTreeViewDialog extends TreeViewDialog { + + private Set operationalAreas; + + public EusmTreeViewDialog(Context context, int theme, JSONArray structure, + ArrayList defaultValue, ArrayList value, + boolean isSelectionMode) throws JSONException { + + super(context, theme, structure, defaultValue, value, isSelectionMode); + } + + @Override + public void init(JSONArray nodes, ArrayList defaultValue, ArrayList value, boolean isSelectionMode) throws JSONException { + this.operationalAreas = PreferencesUtil.getInstance().getCurrentOperationalAreas(); + super.init(nodes, defaultValue, value, isSelectionMode); + } + + @Override + public TreeNode.BaseNodeViewHolder getNodeViewHolder(Context context, JSONObject structure) { + return new TreeSelectionItemViewHolder(context, structure.optString(KEY_LEVEL, "")); + } + + @Override + public void updateTreeNode(int level, TreeNode curNode, TreeNode parentNode) { + curNode.setSelectable(level > 2); + boolean isSelected = operationalAreas.contains(curNode.getValue().toString()); + curNode.setSelected(isSelected); + } + + @Override + public boolean shouldExpandAllNodes() { + return true; + } +} diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/view/NavigationDrawerView.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/view/NavigationDrawerView.java index d599252..bc59312 100644 --- a/opensrp-eusm/src/main/java/org/smartregister/eusm/view/NavigationDrawerView.java +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/view/NavigationDrawerView.java @@ -1,16 +1,18 @@ package org.smartregister.eusm.view; -import android.content.DialogInterface; import android.content.Intent; +import android.graphics.Typeface; +import android.util.TypedValue; import android.view.Gravity; import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.appcompat.widget.PopupMenu; import androidx.core.util.Pair; -import com.vijay.jsonwizard.customviews.TreeViewDialog; - import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONException; @@ -20,15 +22,19 @@ import org.smartregister.eusm.presenter.EusmBaseDrawerPresenter; import org.smartregister.eusm.util.AppUtils; import org.smartregister.tasking.contract.BaseDrawerContract; +import org.smartregister.tasking.util.PreferencesUtil; import org.smartregister.tasking.view.DrawerMenuView; import org.smartregister.util.LangUtils; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import timber.log.Timber; @@ -142,20 +148,51 @@ public BaseDrawerContract.Presenter getPresenter() { @Override public void showOperationalAreaSelector(Pair> locationHierarchy) { try { - TreeViewDialog treeViewDialog = new TreeViewDialog(getContext(), + + EusmTreeViewDialog treeViewDialog = new EusmTreeViewDialog(getContext(), R.style.AppTheme_WideDialog, - new JSONArray(locationHierarchy.first), locationHierarchy.second, new ArrayList<>()); + new JSONArray(locationHierarchy.first), locationHierarchy.second, new ArrayList<>(), true); treeViewDialog.setCancelable(true); treeViewDialog.setCanceledOnTouchOutside(true); - treeViewDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - getPresenter().onOperationalAreaSelectorClicked(treeViewDialog.getName()); - } + treeViewDialog.setShouldDisableOnClickListener(true); + + + LinearLayout linearLayout = treeViewDialog.getCanvas(); + + LinearLayout buttonLayout = new LinearLayout(getContext()); + buttonLayout.setGravity(Gravity.CENTER); + + Button okButton = new Button(getContext()); + okButton.setText(R.string.ok_text); + okButton.setTypeface(Typeface.DEFAULT_BOLD); + okButton.setTextColor(getContext().getResources().getColor(R.color.white)); + okButton.setBackgroundResource(com.vijay.jsonwizard.R.drawable.btn_bg); + okButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, getContext().getResources() + .getDimension(com.vijay.jsonwizard.R.dimen.button_text_size)); + okButton.setHeight(getContext().getResources().getDimensionPixelSize(com.vijay.jsonwizard.R.dimen.button_height)); + + buttonLayout.addView(okButton); + linearLayout.addView(buttonLayout); + okButton.setOnClickListener(v -> { + List selectedValues = treeViewDialog.getTreeView().getSelectedValues(String.class); + getPresenter().onOperationalAreaSelectorClicked(new ArrayList<>(selectedValues)); + treeViewDialog.cancel(); }); treeViewDialog.show(); } catch (JSONException e) { Timber.e(e); } } + + @Override + public void onDrawerOpened(@NonNull View drawerView) { + super.onDrawerOpened(drawerView); + if (operationalAreaTextView != null) { + String opAreas = Optional.of(operationalAreaTextView.getText().toString()).orElse(""); + String setOpAres = PreferencesUtil.getInstance().getCurrentOperationalArea(); + if (!StringUtils.isBlank(setOpAres) && !opAreas.equals(setOpAres)) { + getPresenter().onOperationalAreaSelectorClicked(new ArrayList<>(Arrays.asList(setOpAres.split(PreferencesUtil.OPERATIONAL_AREA_SEPARATOR)))); + } + } + } } diff --git a/opensrp-eusm/src/main/java/org/smartregister/eusm/viewholder/TreeSelectionItemViewHolder.java b/opensrp-eusm/src/main/java/org/smartregister/eusm/viewholder/TreeSelectionItemViewHolder.java new file mode 100644 index 0000000..c6de7a8 --- /dev/null +++ b/opensrp-eusm/src/main/java/org/smartregister/eusm/viewholder/TreeSelectionItemViewHolder.java @@ -0,0 +1,19 @@ +package org.smartregister.eusm.viewholder; + +import android.content.Context; +import android.view.View; + +import com.vijay.jsonwizard.customviews.SelectableItemHolder; + +public class TreeSelectionItemViewHolder extends SelectableItemHolder { + + public TreeSelectionItemViewHolder(Context context, String levelLabel) { + super(context, levelLabel); + } + + @Override + public void toggleSelectionMode(boolean editModeEnabled) { + nodeSelector.setVisibility(mNode.isSelectable() && editModeEnabled ? View.VISIBLE : View.GONE); + nodeSelector.setChecked(mNode.isSelected()); + } +} diff --git a/opensrp-eusm/src/main/res/values/strings.xml b/opensrp-eusm/src/main/res/values/strings.xml index e67ffea..e4023ce 100644 --- a/opensrp-eusm/src/main/res/values/strings.xml +++ b/opensrp-eusm/src/main/res/values/strings.xml @@ -144,5 +144,6 @@ You\'ve selected a cluster point! identifier + OK diff --git a/opensrp-eusm/src/test/java/org/smartregister/eusm/application/EusmApplicationTest.java b/opensrp-eusm/src/test/java/org/smartregister/eusm/application/EusmApplicationTest.java index b37f5dc..034db9a 100644 --- a/opensrp-eusm/src/test/java/org/smartregister/eusm/application/EusmApplicationTest.java +++ b/opensrp-eusm/src/test/java/org/smartregister/eusm/application/EusmApplicationTest.java @@ -94,9 +94,8 @@ public void testOnUserAssignmentRevokedShouldNotClearOAsAndPlan() { String operationalArea = UUID.randomUUID().toString(); UserAssignmentDTO userAssignmentDTO = UserAssignmentDTO.builder().jurisdictions(Collections.singleton(operationalArea)).plans(Collections.singleton(planId)).build(); eusmApplication.onUserAssignmentRevoked(userAssignmentDTO); - verify(preferencesUtil).getCurrentOperationalAreaId(); + verify(preferencesUtil).getCurrentOperationalAreaIds(); verify(preferencesUtil).getCurrentPlanId(); - verifyZeroInteractions(preferencesUtil); Whitebox.setInternalState(PreferencesUtil.class, "instance", (PreferencesUtil) null); } diff --git a/opensrp-eusm/src/test/java/org/smartregister/eusm/interactor/EusmTaskingMapInteractorTest.java b/opensrp-eusm/src/test/java/org/smartregister/eusm/interactor/EusmTaskingMapInteractorTest.java index 5a04b9b..1ef57d8 100644 --- a/opensrp-eusm/src/test/java/org/smartregister/eusm/interactor/EusmTaskingMapInteractorTest.java +++ b/opensrp-eusm/src/test/java/org/smartregister/eusm/interactor/EusmTaskingMapInteractorTest.java @@ -19,6 +19,7 @@ import org.smartregister.tasking.contract.TaskingMapActivityContract; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static android.os.Looper.getMainLooper; @@ -90,6 +91,7 @@ public void testFetchLocationsWhenOperationalAreaAvailableShouldInvokeRequiredMe LocationProperty locationProperty = new LocationProperty(); Location location1 = new Location(); + location1.setType("Feature"); location1.setGeometry(geometry); location1.setProperties(locationProperty); StructureDetail structureDetail = new StructureDetail(); @@ -101,9 +103,9 @@ public void testFetchLocationsWhenOperationalAreaAvailableShouldInvokeRequiredMe structureDetails.add(structureDetail); doReturn(structureDetails).when(appStructureRepository) - .fetchStructureDetails(isNull(), anyString(), isNull(), eq(true), isNull()); + .fetchStructureDetails(isNull(), Collections.singleton(anyString()), isNull(), eq(true), isNull()); - doReturn(location).when(eusmTaskingMapInteractor).getOperationalAreaLocation(eq(operationalArea)); + doReturn(Collections.singleton(location1)).when(eusmTaskingMapInteractor).getOperationalAreaLocations(eq(Collections.singleton(operationalArea))); eusmTaskingMapInteractor.fetchLocations(plan, operationalArea, point, locationComponentActive); diff --git a/opensrp-eusm/src/test/java/org/smartregister/eusm/repository/AppStructureRepositoryTest.java b/opensrp-eusm/src/test/java/org/smartregister/eusm/repository/AppStructureRepositoryTest.java index 7a114f0..ff471be 100644 --- a/opensrp-eusm/src/test/java/org/smartregister/eusm/repository/AppStructureRepositoryTest.java +++ b/opensrp-eusm/src/test/java/org/smartregister/eusm/repository/AppStructureRepositoryTest.java @@ -22,7 +22,11 @@ import org.smartregister.eusm.domain.StructureDetail; import org.smartregister.view.activity.DrishtiApplication; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; import static org.junit.Assert.assertEquals; @@ -107,7 +111,9 @@ public Object answer(InvocationOnMock invocation) throws Throwable { } }).when(cursor).moveToNext(); - int result = appStructureRepository.countOfStructures("tes", UUID.randomUUID().toString(), UUID.randomUUID().toString()); + Set parentIds = new HashSet<>(); + parentIds.add(UUID.randomUUID().toString()); + int result = appStructureRepository.countOfStructures("tes", parentIds, UUID.randomUUID().toString()); assertEquals(0, result); } @@ -169,7 +175,9 @@ public Object answer(InvocationOnMock invocation) { } }).when(cursor).moveToNext(); - List structureDetails = appStructureRepository.fetchStructureDetails(0, "23-2", "tes", false, UUID.randomUUID().toString()); + Set parentIds = new HashSet<>(); + parentIds.add(UUID.randomUUID().toString()); + List structureDetails = appStructureRepository.fetchStructureDetails(0, parentIds, "tes", false, UUID.randomUUID().toString()); assertEquals(1, structureDetails.size()); }