diff --git a/openmrs-client/build.gradle b/openmrs-client/build.gradle index 76fdd02dfe..af31732554 100644 --- a/openmrs-client/build.gradle +++ b/openmrs-client/build.gradle @@ -131,7 +131,9 @@ dependencies { def room_version = "2.1.0-alpha04" def appcompat_version = "1.2.0-alpha01" def material_version = "1.2.0-alpha03" + def worker_manager_version = "2.3.3" + implementation "androidx.work:work-runtime:$worker_manager_version" implementation 'com.google.code.gson:gson:2.8.5' implementation "androidx.appcompat:appcompat:$appcompat_version" androidTestImplementation( diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/activities/addeditpatient/AddEditPatientActivity.java b/openmrs-client/src/main/java/org/openmrs/mobile/activities/addeditpatient/AddEditPatientActivity.java index 8863af9d6e..752b46e116 100644 --- a/openmrs-client/src/main/java/org/openmrs/mobile/activities/addeditpatient/AddEditPatientActivity.java +++ b/openmrs-client/src/main/java/org/openmrs/mobile/activities/addeditpatient/AddEditPatientActivity.java @@ -82,7 +82,7 @@ protected void onCreate(Bundle savedInstanceState) { PlacesClient placesClient = Places.createClient(this); // Create the mPresenter - mPresenter = new AddEditPatientPresenter(addEditPatientFragment, countries, patientID, placesClient); + mPresenter = new AddEditPatientPresenter(addEditPatientFragment, countries, patientID, placesClient, getApplicationContext()); } @Override @@ -146,4 +146,4 @@ protected void onPause() { } super.onPause(); } -} \ No newline at end of file +} diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/activities/addeditpatient/AddEditPatientPresenter.java b/openmrs-client/src/main/java/org/openmrs/mobile/activities/addeditpatient/AddEditPatientPresenter.java index 382723d6eb..f82b6295fd 100644 --- a/openmrs-client/src/main/java/org/openmrs/mobile/activities/addeditpatient/AddEditPatientPresenter.java +++ b/openmrs-client/src/main/java/org/openmrs/mobile/activities/addeditpatient/AddEditPatientPresenter.java @@ -14,6 +14,7 @@ package org.openmrs.mobile.activities.addeditpatient; +import android.content.Context; import androidx.annotation.NonNull; import com.google.android.libraries.places.api.net.PlacesClient; @@ -44,7 +45,6 @@ public class AddEditPatientPresenter extends BasePresenter implements AddEditPatientContract.Presenter { private final AddEditPatientContract.View mPatientInfoView; - private PatientRepository patientRepository; private RestApi restApi; private Patient mPatient; @@ -56,12 +56,13 @@ public class AddEditPatientPresenter extends BasePresenter implements AddEditPat public AddEditPatientPresenter(AddEditPatientContract.View mPatientInfoView, List countries, String patientToUpdateId, - PlacesClient placesClient) { + PlacesClient placesClient, + Context appContext) { this.mPatientInfoView = mPatientInfoView; this.mPatientInfoView.setPresenter(this); this.mCountries = countries; this.patientToUpdateId = patientToUpdateId; - this.patientRepository = new PatientRepository(); + this.patientRepository = new PatientRepository(appContext); this.restApi = RestServiceBuilder.createService(RestApi.class); this.placesClient = placesClient; } diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/api/repository/PatientRepository.java b/openmrs-client/src/main/java/org/openmrs/mobile/api/repository/PatientRepository.java index 4f82e9db44..a28e797142 100644 --- a/openmrs-client/src/main/java/org/openmrs/mobile/api/repository/PatientRepository.java +++ b/openmrs-client/src/main/java/org/openmrs/mobile/api/repository/PatientRepository.java @@ -14,19 +14,27 @@ package org.openmrs.mobile.api.repository; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import androidx.work.Constraints; +import androidx.work.Data; +import androidx.work.NetworkType; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; import org.jdeferred.android.AndroidDeferredManager; import org.openmrs.mobile.api.EncounterService; import org.openmrs.mobile.api.RestApi; import org.openmrs.mobile.api.RestServiceBuilder; +import org.openmrs.mobile.api.workers.UpdateWorker; import org.openmrs.mobile.api.promise.SimpleDeferredObject; import org.openmrs.mobile.api.promise.SimplePromise; import org.openmrs.mobile.application.OpenMRS; import org.openmrs.mobile.application.OpenMRSLogger; import org.openmrs.mobile.dao.PatientDAO; +import org.openmrs.mobile.databases.tables.PatientTable; import org.openmrs.mobile.listeners.retrofit.DefaultResponseCallbackListener; import org.openmrs.mobile.listeners.retrofit.DownloadPatientCallbackListener; import org.openmrs.mobile.models.Encountercreate; @@ -61,8 +69,18 @@ public class PatientRepository extends RetrofitRepository { private PatientDAO patientDao; private LocationRepository locationRepository; private RestApi restApi; + private WorkManager mWorkManager = null; - public PatientRepository(){ + //constructor specifically for update which uses a workManager Implementation + public PatientRepository(Context appContext) { + this.logger = new OpenMRSLogger(); + this.patientDao = new PatientDAO(); + this.locationRepository = new LocationRepository(); + this.restApi = RestServiceBuilder.createService(RestApi.class); + this.mWorkManager = WorkManager.getInstance(appContext); + } + + public PatientRepository() { this.logger = new OpenMRSLogger(); this.patientDao = new PatientDAO(); this.locationRepository = new LocationRepository(); @@ -116,7 +134,7 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Response call, @NonNull Response response) { logger.i(response.message()); if (!response.isSuccessful()) { - ToastUtil.error("Patient photo cannot be synced due to server error: "+ response.message()); + ToastUtil.error("Patient photo cannot be synced due to server error: " + response.message()); } } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { - ToastUtil.notify("Patient photo cannot be synced due to error: " + t.toString() ); + ToastUtil.notify("Patient photo cannot be synced due to error: " + t.toString()); } }); } @@ -232,6 +251,14 @@ public void onFailure(@NonNull Call call, @NonNull Throwable t) { } }); } else { + //add patient to the local database + patientDao.updatePatient(patient.getId(), patient); + + // enqueue the work to workManager + Data data = new Data.Builder().putString(PatientTable.Column.ID, patient.getId().toString()).build(); + Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(); + mWorkManager.enqueue(new OneTimeWorkRequest.Builder(UpdateWorker.class).setConstraints(constraints).setInputData(data).build()); + ToastUtil.notify("Sync is off. Patient Update data is saved locally " + "and will sync when online mode is restored. "); if (callbackListener != null) { @@ -258,19 +285,19 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Throwable t) { callbackListener.onErrorResponse(t.getMessage()); } }); } - - public SimplePromise downloadPatientPhotoByUuid(String uuid) { + + public SimplePromise downloadPatientPhotoByUuid(String uuid) { final SimpleDeferredObject deferredObject = new SimpleDeferredObject<>(); Call call = restApi.downloadPatientPhoto(uuid); call.enqueue(new Callback() { @@ -291,6 +318,7 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Throwable t) { deferredObject.reject(t); @@ -300,17 +328,16 @@ public void onFailure(@NonNull Call call, @NonNull Throwable t) { } private void addEncounters(Patient patient) { - String enc=patient.getEncounters(); + String enc = patient.getEncounters(); List list = new ArrayList<>(); for (String s : enc.split(",")) list.add(Long.parseLong(s)); - for(long id:list) - { + for (long id : list) { Encountercreate encountercreate = new Select() .from(Encountercreate.class) - .where("id = ?",id) + .where("id = ?", id) .executeSingle(); encountercreate.setPatient(patient.getUuid()); encountercreate.save(); @@ -350,7 +377,7 @@ private SimplePromise getPatientIdentifierTypeUuid() { public void onResponse(@NonNull Call> call, @NonNull Response> response) { Results idresList = response.body(); for (IdentifierType result : idresList.getResults()) { - if(result.getDisplay().equals("OpenMRS ID")) { + if (result.getDisplay().equals("OpenMRS ID")) { deferred.resolve(result); return; } diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/api/workers/UpdateWorker.java b/openmrs-client/src/main/java/org/openmrs/mobile/api/workers/UpdateWorker.java new file mode 100644 index 0000000000..89052a7582 --- /dev/null +++ b/openmrs-client/src/main/java/org/openmrs/mobile/api/workers/UpdateWorker.java @@ -0,0 +1,177 @@ +/* + * The contents of this file are subject to the OpenMRS Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://license.openmrs.org + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * Copyright (C) OpenMRS, LLC. All Rights Reserved. + */ + +package org.openmrs.mobile.api.workers; + +import android.content.Context; +import android.content.res.Resources; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.work.Worker; +import androidx.work.WorkerParameters; +import org.openmrs.mobile.R; +import org.openmrs.mobile.api.RestApi; +import org.openmrs.mobile.api.RestServiceBuilder; +import org.openmrs.mobile.application.OpenMRSLogger; +import org.openmrs.mobile.dao.PatientDAO; +import org.openmrs.mobile.databases.tables.PatientTable; +import org.openmrs.mobile.listeners.retrofit.DefaultResponseCallbackListener; +import org.openmrs.mobile.models.Patient; +import org.openmrs.mobile.models.PatientDto; +import org.openmrs.mobile.models.PatientPhoto; +import org.openmrs.mobile.utilities.NetworkUtils; +import org.openmrs.mobile.utilities.ToastUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class UpdateWorker extends Worker { + private static final int ON_SUCCESS = 1; + private static final int ON_FAILURE = 2; + private static final int ON_UNSUCCESSFUL_RESPONSE_PHOTO_UPDATE = 3; + private static final int ON_FAILURE_RESPONSE_PHOTO_UPDATE = 4; + + private RestApi restApi; + private OpenMRSLogger logger; + private Handler mHandler; + + public UpdateWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) { + super(appContext, workerParams); + restApi = RestServiceBuilder.createService(RestApi.class); + logger = new OpenMRSLogger(); + + mHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + String responseMessage; + switch (msg.what) { + case ON_SUCCESS: + String updateSuccessPatientName = (String) msg.obj; + ToastUtil.success(Resources.getSystem().getString(R.string.patient_update_successful, updateSuccessPatientName)); + break; + case ON_FAILURE: + String updateFailedPatientName = (String) msg.obj; + ToastUtil.error(Resources.getSystem().getString(R.string.patient_update_unsuccessful, updateFailedPatientName)); + break; + case ON_UNSUCCESSFUL_RESPONSE_PHOTO_UPDATE: + responseMessage = (String) msg.obj; + ToastUtil.error(Resources.getSystem().getString(R.string.patient_photo_update_unsuccessful, responseMessage)); + case ON_FAILURE_RESPONSE_PHOTO_UPDATE: + responseMessage = (String) msg.obj; + ToastUtil.notify(Resources.getSystem().getString(R.string.patient_photo_update_unsuccessful, responseMessage)); + } + super.handleMessage(msg); + } + }; + } + + + @NonNull + @Override + public Result doWork() { + final boolean[] result = new boolean[1]; + String patientIdTobeUpdated = getInputData().getString(PatientTable.Column.ID); + PatientDAO patientDAO = new PatientDAO(); + Patient patientTobeUpdated = patientDAO.findPatientByID(patientIdTobeUpdated); + + updatePatient(patientTobeUpdated, new DefaultResponseCallbackListener() { + @Override + public void onResponse() { + result[0] = true; + Message msg = new Message(); + msg.obj = patientTobeUpdated.getPerson().getName().getNameString(); + msg.what = ON_SUCCESS; + mHandler.sendMessage(msg); + } + + @Override + public void onErrorResponse(String errorMessage) { + result[0] = false; + Message msg = new Message(); + msg.obj = patientTobeUpdated.getPerson().getName().getNameString(); + msg.what = ON_FAILURE; + mHandler.sendMessage(msg); + } + }); + return result[0] ? Result.success() : Result.retry(); + } + + public void updatePatient(final Patient patient, @Nullable final DefaultResponseCallbackListener callbackListener) { + PatientDto patientDto = patient.getPatientDto(); + if (NetworkUtils.isOnline()) { + Call call = restApi.updatePatient(patientDto, patient.getUuid(), "full"); + call.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful()) { + PatientDto patientDto = response.body(); + patient.setBirthdate(patientDto.getPerson().getBirthdate()); + + patient.setUuid(patient.getUuid()); + if (patient.getPhoto() != null) + uploadPatientPhoto(patient); + + new PatientDAO().updatePatient(patient.getId(), patient); + + if (callbackListener != null) { + callbackListener.onResponse(); + } + } else { + if (callbackListener != null) { + callbackListener.onErrorResponse(response.message()); + } + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + if (callbackListener != null) { + callbackListener.onErrorResponse(t.getMessage()); + } + } + }); + } + } + + private void uploadPatientPhoto(final Patient patient) { + PatientPhoto patientPhoto = new PatientPhoto(); + patientPhoto.setPhoto(patient.getPhoto()); + patientPhoto.setPerson(patient); + Call personPhotoCall = restApi.uploadPatientPhoto(patient.getUuid(), patientPhoto); + personPhotoCall.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + logger.i(response.message()); + + if (!response.isSuccessful()) { + Message msg = new Message(); + msg.obj = response.message(); + msg.what = ON_UNSUCCESSFUL_RESPONSE_PHOTO_UPDATE; + mHandler.sendMessage(msg); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Message msg = new Message(); + msg.obj = t.toString(); + msg.what = ON_FAILURE_RESPONSE_PHOTO_UPDATE; + mHandler.sendMessage(msg); + } + }); + } +} + diff --git a/openmrs-client/src/main/res/values/strings.xml b/openmrs-client/src/main/res/values/strings.xml index db914969a0..d0560da92f 100644 --- a/openmrs-client/src/main/res/values/strings.xml +++ b/openmrs-client/src/main/res/values/strings.xml @@ -152,6 +152,11 @@ "Downloading…" "Starting Visit" + + Patient %1$s Updated + Patient %1$s cannot be updated due to server error will retry sync + Patient photo cannot be synced due to server error: %1$s + # %1$s Photo