diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 5f76c92896c..64e6801c57b 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 0.5.1 + 0.6.0 ../sormas-base 4.0.0 diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/Disease.java b/sormas-api/src/main/java/de/symeda/sormas/api/Disease.java index f435837a148..f8fcf0b05d6 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/Disease.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/Disease.java @@ -9,6 +9,7 @@ public enum Disease { MEASLES, YELLOW_FEVER, DENGUE, + MONKEYPOX, OTHER ; @@ -23,4 +24,8 @@ public String toShortString() { public String getName() { return this.name(); } + + public boolean hasContactFollowUp() { + return this == EVD || this == LASSA || this == AVIAN_INFLUENCA || this == MONKEYPOX || this == OTHER; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/I18nProperties.java b/sormas-api/src/main/java/de/symeda/sormas/api/I18nProperties.java index cd6186943ed..02d3e23c9da 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/I18nProperties.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/I18nProperties.java @@ -10,7 +10,7 @@ public class I18nProperties { private final Properties fieldCaptionProperties; private final Properties fieldDescriptionProperties; - private final Properties buttonCaptionProperties; + private final Properties fragmentProperties; private final Properties enumProperties; private static I18nProperties getInstance() { @@ -44,14 +44,32 @@ public static String getEnumCaption(Enum value, String addition) { /** * Uses key as default value */ - public static String getButtonCaption(String key) { - return getButtonCaption(key, key); + public static String getFragment(String key) { + return getFragment(key, key); } - public static String getButtonCaption(String key, String defaultValue) { - return getInstance().buttonCaptionProperties.getProperty(key, defaultValue); + public static String getFragment(String key, String defaultValue) { + return getInstance().fragmentProperties.getProperty(key, defaultValue); } + /** + * Uses key as default value + */ + public static String getPrefixFragment(String prefix, String key) { + return getPrefixFragment(prefix, key, key); + } + + public static String getPrefixFragment(String prefix, String key, String defaultValue) { + String result = null; + if (prefix != null) { + result = getInstance().fragmentProperties.getProperty(prefix+"."+key); + } + if (result == null) { + result = getFragment(key, defaultValue); + } + return result; + } + /** * Uses key as default value */ @@ -110,7 +128,7 @@ public static String getPrefixFieldDescription(String prefix, String key, String private I18nProperties() { fieldCaptionProperties = loadProperties("/fieldCaptions.properties"); fieldDescriptionProperties = loadProperties("/fieldDescriptions.properties"); - buttonCaptionProperties = loadProperties("/buttonCaptions.properties"); + fragmentProperties = loadProperties("/fragments.properties"); enumProperties = loadProperties("/enum.properties"); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java index 9d1ef2ad34b..31972833b44 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java @@ -48,6 +48,7 @@ public class CaseDataDto extends CaseReferenceDto { public static final String MEASLES_VACCINATION_INFO_SOURCE = "measlesVaccinationInfoSource"; public static final String YELLOW_FEVER_VACCINATION = "yellowFeverVaccination"; public static final String YELLOW_FEVER_VACCINATION_INFO_SOURCE = "yellowFeverVaccinationInfoSource"; + public static final String SMALLPOX_VACCINATION_SCAR = "smallpoxVaccinationScar"; public static final String EPID_NUMBER = "epidNumber"; public static final String REPORT_LAT = "reportLat"; public static final String REPORT_LON = "reportLon"; @@ -83,14 +84,18 @@ public class CaseDataDto extends CaseReferenceDto { private Vaccination yellowFeverVaccination; @Diseases({Disease.YELLOW_FEVER}) private VaccinationInfoSource yellowFeverVaccinationInfoSource; + @Diseases({Disease.MONKEYPOX}) + private YesNoUnknown smallpoxVaccinationScar; private String epidNumber; private UserReferenceDto surveillanceOfficer; private UserReferenceDto caseOfficer; - private Float reportLat; - private Float reportLon; + private Double reportLat; + private Double reportLon; + private Float reportLatLonAccuracy; + public CaseClassification getCaseClassification() { return caseClassification; @@ -284,6 +289,14 @@ public void setYellowFeverVaccinationInfoSource(VaccinationInfoSource yellowFeve this.yellowFeverVaccinationInfoSource = yellowFeverVaccinationInfoSource; } + public YesNoUnknown getSmallpoxVaccinationScar() { + return smallpoxVaccinationScar; + } + + public void setSmallpoxVaccinationScar(YesNoUnknown smallpoxVaccinationScar) { + this.smallpoxVaccinationScar = smallpoxVaccinationScar; + } + public String getEpidNumber() { return epidNumber; } @@ -292,20 +305,28 @@ public void setEpidNumber(String epidNumber) { this.epidNumber = epidNumber; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } + } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java index 826bbf6c4f9..46f83138dc2 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java @@ -9,8 +9,10 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.facility.FacilityReferenceDto; import de.symeda.sormas.api.region.CommunityReferenceDto; +import de.symeda.sormas.api.region.DistrictReferenceDto; import de.symeda.sormas.api.region.RegionReferenceDto; import de.symeda.sormas.api.user.UserReferenceDto; +import de.symeda.sormas.api.utils.EpiWeek; @Remote public interface CaseFacade { @@ -19,8 +21,8 @@ public interface CaseFacade { List getAllCasesByDisease(Disease disease, String userUuid); - List getAllCasesBetween(Date fromDate, Date toDate, Disease disease, String userUuid); - + List getAllCasesBetween(Date fromDate, Date toDate, DistrictReferenceDto districtRef, Disease disease, String userUuid); + CaseDataDto getCaseDataByUuid(String uuid); CaseDataDto saveCase(CaseDataDto dto); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactDto.java index 88076447f4b..1828e6faa47 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactDto.java @@ -37,19 +37,20 @@ public class ContactDto extends ContactReferenceDto { private Date lastContactDate; private ContactProximity contactProximity; private ContactClassification contactClassification; - @Diseases({Disease.EVD,Disease.LASSA,Disease.CHOLERA}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.CHOLERA,Disease.MONKEYPOX,Disease.OTHER}) private FollowUpStatus followUpStatus; - @Diseases({Disease.EVD,Disease.LASSA,Disease.CHOLERA}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.CHOLERA,Disease.MONKEYPOX,Disease.OTHER}) private String followUpComment; - @Diseases({Disease.EVD,Disease.LASSA,Disease.CHOLERA}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.CHOLERA,Disease.MONKEYPOX,Disease.OTHER}) private Date followUpUntil; - @Diseases({Disease.EVD,Disease.LASSA,Disease.CHOLERA}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.CHOLERA,Disease.MONKEYPOX,Disease.OTHER}) private UserReferenceDto contactOfficer; private String description; private ContactRelation relationToCase; - private Float reportLat; - private Float reportLon; - + private Double reportLat; + private Double reportLon; + private Float reportLatLonAccuracy; + public PersonReferenceDto getPerson() { return person; } @@ -123,16 +124,16 @@ public ContactRelation getRelationToCase() { public void setRelationToCase(ContactRelation relationToCase) { this.relationToCase = relationToCase; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } public String getFollowUpComment() { @@ -141,5 +142,11 @@ public String getFollowUpComment() { public void setFollowUpComment(String followUpComment) { this.followUpComment = followUpComment; } + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java index e67e772440b..e84b86497e0 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java @@ -7,14 +7,16 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.caze.CaseReferenceDto; +import de.symeda.sormas.api.region.DistrictReferenceDto; import de.symeda.sormas.api.user.UserReferenceDto; +import de.symeda.sormas.api.utils.EpiWeek; @Remote public interface ContactFacade { List getAllContactsAfter(Date date, String userUuid); - List getFollowUpBetween(Date fromDate, Date toDate, Disease disease, String userUuid); + List getFollowUpBetween(Date fromDate, Date toDate, DistrictReferenceDto districtRef, Disease disease, String userUuid); List getAllByCase(CaseReferenceDto caseRef); @@ -38,5 +40,5 @@ public interface ContactFacade { List getByUuids(List uuids); - List getMapContacts(Date fromDate, Date toDate, Disease disease, String userUuid); + List getMapContacts(Date fromDate, Date toDate, DistrictReferenceDto districtRef, Disease disease, String userUuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactMapDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactMapDto.java index a211b0d0b94..69265c5da0b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactMapDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactMapDto.java @@ -1,6 +1,6 @@ package de.symeda.sormas.api.contact; -import java.util.Date; +import de.symeda.sormas.api.visit.VisitReferenceDto; public class ContactMapDto extends ContactReferenceDto { @@ -8,33 +8,50 @@ public class ContactMapDto extends ContactReferenceDto { public static final String I18N_PREFIX = "Contact"; - public static final String LAST_VISIT_DATE_TIME = "lastVisitDateTime"; + public static final String LAST_VISIT = "lastVisit"; + public static final String CONTACT_CLASSIFICATION = "contactClassification"; public static final String REPORT_LAT = "reportLat"; public static final String REPORT_LON = "reportLon"; - private Date lastVisitDateTime; - private Float reportLat; - private Float reportLon; + private VisitReferenceDto lastVisit; + private ContactClassification contactClassification; + private Double reportLat; + private Double reportLon; + private Float reportLatLonAccuracy; - public Date getLastVisitDateTime() { - return lastVisitDateTime; + public VisitReferenceDto getLastVisit() { + return lastVisit; } - public void setLastVisitDateTime(Date lastVisitDateTime) { - this.lastVisitDateTime = lastVisitDateTime; + public void setLastVisit(VisitReferenceDto lastVisit) { + this.lastVisit = lastVisit; + } + + public ContactClassification getContactClassification() { + return contactClassification; + } + public void setContactClassification(ContactClassification contactClassification) { + this.contactClassification = contactClassification; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } + + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/epidata/AnimalCondition.java b/sormas-api/src/main/java/de/symeda/sormas/api/epidata/AnimalCondition.java new file mode 100644 index 00000000000..1aeb2fe1d7e --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/epidata/AnimalCondition.java @@ -0,0 +1,16 @@ +package de.symeda.sormas.api.epidata; + +import de.symeda.sormas.api.I18nProperties; + +public enum AnimalCondition { + + ALIVE, + DEAD, + PROCESSED, + UNKNOWN; + + public String toString() { + return I18nProperties.getEnumCaption(this); + } + +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java index d9bce3c3041..21c68c7304c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java @@ -42,6 +42,9 @@ public class EpiDataDto extends DataTransferObject { public static final String WATER_BODY = "waterBody"; public static final String WATER_BODY_DETAILS = "waterBodyDetails"; public static final String TICKBITE = "tickBite"; + public static final String DATE_OF_LAST_EXPOSURE = "dateOfLastExposure"; + public static final String PLACE_OF_LAST_EXPOSURE = "placeOfLastExposure"; + public static final String ANIMAL_CONDITION = "animalCondition"; public static final String BURIALS = "burials"; public static final String GATHERINGS = "gatherings"; public static final String TRAVELS = "travels"; @@ -50,17 +53,17 @@ public class EpiDataDto extends DataTransferObject { private YesNoUnknown burialAttended; @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) private YesNoUnknown gatheringAttended; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private YesNoUnknown traveled; - @Diseases({Disease.EVD,Disease.LASSA,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.MONKEYPOX,Disease.OTHER}) private YesNoUnknown rodents; @Diseases({Disease.EVD,Disease.LASSA,Disease.OTHER}) private YesNoUnknown bats; - @Diseases({Disease.EVD,Disease.LASSA,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.MONKEYPOX,Disease.OTHER}) private YesNoUnknown primates; @Diseases({Disease.EVD,Disease.LASSA,Disease.OTHER}) private YesNoUnknown swine; - @Diseases({Disease.EVD,Disease.LASSA,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA}) private YesNoUnknown birds; @Diseases({Disease.AVIAN_INFLUENCA,Disease.OTHER}) private YesNoUnknown poultryEat; @@ -72,23 +75,23 @@ public class EpiDataDto extends DataTransferObject { private YesNoUnknown poultrySick; @Diseases({Disease.AVIAN_INFLUENCA,Disease.OTHER}) private String poultrySickDetails; - @Diseases({Disease.AVIAN_INFLUENCA,Disease.OTHER}) + @Diseases({Disease.AVIAN_INFLUENCA}) private Date poultryDate; - @Diseases({Disease.AVIAN_INFLUENCA,Disease.OTHER}) + @Diseases({Disease.AVIAN_INFLUENCA}) private String poultryLocation; @Diseases({Disease.AVIAN_INFLUENCA,Disease.OTHER}) private YesNoUnknown wildbirds; @Diseases({Disease.AVIAN_INFLUENCA,Disease.OTHER}) private String wildbirdsDetails; - @Diseases({Disease.AVIAN_INFLUENCA,Disease.OTHER}) + @Diseases({Disease.AVIAN_INFLUENCA}) private Date wildbirdsDate; - @Diseases({Disease.AVIAN_INFLUENCA,Disease.OTHER}) + @Diseases({Disease.AVIAN_INFLUENCA}) private String wildbirdsLocation; @Diseases({Disease.EVD,Disease.LASSA,Disease.OTHER}) private YesNoUnknown cattle; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.MONKEYPOX,Disease.OTHER}) private YesNoUnknown otherAnimals; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.MONKEYPOX,Disease.OTHER}) private String otherAnimalsDetails; @Diseases({Disease.CHOLERA,Disease.OTHER}) private WaterSource waterSource; @@ -100,6 +103,12 @@ public class EpiDataDto extends DataTransferObject { private String waterBodyDetails; @Diseases({Disease.EVD,Disease.LASSA,Disease.OTHER}) private YesNoUnknown tickBite; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Date dateOfLastExposure; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private String placeOfLastExposure; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private AnimalCondition animalCondition; private List burials = new ArrayList<>(); private List gatherings = new ArrayList<>(); @@ -294,6 +303,27 @@ public void setTickBite(YesNoUnknown tickBite) { this.tickBite = tickBite; } + public Date getDateOfLastExposure() { + return dateOfLastExposure; + } + public void setDateOfLastExposure(Date dateOfLastExposure) { + this.dateOfLastExposure = dateOfLastExposure; + } + + public String getPlaceOfLastExposure() { + return placeOfLastExposure; + } + public void setPlaceOfLastExposure(String placeOfLastExposure) { + this.placeOfLastExposure = placeOfLastExposure; + } + + public AnimalCondition getAnimalCondition() { + return animalCondition; + } + public void setAnimalCondition(AnimalCondition animalCondition) { + this.animalCondition = animalCondition; + } + public List getBurials() { return burials; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventDto.java index 1170ce8c649..fdbc4538ddc 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventDto.java @@ -48,8 +48,9 @@ public class EventDto extends EventReferenceDto { private String diseaseDetails; private UserReferenceDto surveillanceOfficer; private String typeOfPlaceText; - private Float reportLat; - private Float reportLon; + private Double reportLat; + private Double reportLon; + private Float reportLatLonAccuracy; public EventType getEventType() { return eventType; @@ -177,20 +178,28 @@ public void setTypeOfPlaceText(String typeOfPlaceText) { this.typeOfPlaceText = typeOfPlaceText; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } + } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java index 87e970d6657..940b7b92482 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java @@ -6,6 +6,7 @@ import javax.ejb.Remote; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.region.DistrictReferenceDto; import de.symeda.sormas.api.user.UserReferenceDto; @Remote @@ -13,7 +14,7 @@ public interface EventFacade { List getAllEventsAfter(Date date, String userUuid); - List getAllEventsBetween(Date fromDate, Date toDate, Disease disease, String userUuid); + List getAllEventsBetween(Date fromDate, Date toDate, DistrictReferenceDto districtRef, Disease disease, String userUuid); EventDto getEventByUuid(String uuid); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/facility/FacilityDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/facility/FacilityDto.java index d25ab55283d..f9e86c2479a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/facility/FacilityDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/facility/FacilityDto.java @@ -16,14 +16,15 @@ public class FacilityDto extends FacilityReferenceDto { public static final String NONE_FACILITY_UUID = "SORMAS-CONSTID-ISNONE-FACILITY"; public static final String OTHER_FACILITY = "OTHER_FACILITY"; public static final String NO_FACILITY = "NO_FACILITY"; + public static final String NAME = "name"; private String name; private RegionReferenceDto region; private DistrictReferenceDto district; private CommunityReferenceDto community; private String city; - private Float latitude; - private Float longitude; + private Double latitude; + private Double longitude; private FacilityType type; private boolean publicOwnership; @@ -57,17 +58,17 @@ public void setCommunity(CommunityReferenceDto community) { this.community = community; } - public Float getLatitude() { + public Double getLatitude() { return latitude; } - public void setLatitude(Float latitude) { + public void setLatitude(Double latitude) { this.latitude = latitude; } - public Float getLongitude() { + public Double getLongitude() { return longitude; } - public void setLongitude(Float longitude) { + public void setLongitude(Double longitude) { this.longitude = longitude; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/location/LocationDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/location/LocationDto.java index 264958317b7..8d02304d33b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/location/LocationDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/location/LocationDto.java @@ -19,6 +19,7 @@ public class LocationDto extends DataTransferObject { public static final String COMMUNITY = "community"; public static final String LATITUDE = "latitude"; public static final String LONGITUDE = "longitude"; + public static final String LAT_LON_ACCURACY = "latLonAccuracy"; private String address; private String details; @@ -28,8 +29,9 @@ public class LocationDto extends DataTransferObject { private DistrictReferenceDto district; private CommunityReferenceDto community; - private Float latitude; - private Float longitude; + private Double latitude; + private Double longitude; + private Float latLonAccuracy; public String getAddress() { return address; @@ -70,16 +72,16 @@ public CommunityReferenceDto getCommunity() { public void setCommunity(CommunityReferenceDto community) { this.community = community; } - public Float getLatitude() { + public Double getLatitude() { return latitude; } - public void setLatitude(Float latitude) { + public void setLatitude(Double latitude) { this.latitude = latitude; } - public Float getLongitude() { + public Double getLongitude() { return longitude; } - public void setLongitude(Float longitude) { + public void setLongitude(Double longitude) { this.longitude = longitude; } @@ -96,4 +98,11 @@ public boolean isEmptyLocation() { return address == null && details == null && city == null && region == null && district == null && community == null; } + + public Float getLatLonAccuracy() { + return latLonAccuracy; + } + public void setLatLonAccuracy(Float latLonAccuracy) { + this.latLonAccuracy = latLonAccuracy; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java index 6a0a54de871..0c138f91897 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java @@ -6,6 +6,7 @@ import javax.ejb.Remote; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.region.DistrictReferenceDto; import de.symeda.sormas.api.user.UserReferenceDto; @Remote @@ -19,7 +20,7 @@ public interface PersonFacade { List getPersonReferencesAfter(Date date, UserReferenceDto userRef); - List getDeathsBetween(Date fromDate, Date toDate, Disease disease, String userUuid); + List getDeathsBetween(Date fromDate, Date toDate, DistrictReferenceDto districtRef, Disease disease, String userUuid); PersonReferenceDto getReferenceByUuid(String uuid); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/region/DistrictFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/region/DistrictFacade.java index b1c12e3f9e5..e39e8080f7c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/region/DistrictFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/region/DistrictFacade.java @@ -13,5 +13,7 @@ public interface DistrictFacade { List getAllAfter(Date date); DistrictDto getDistrictByUuid(String uuid); + + DistrictReferenceDto getDistrictReferenceByUuid(String uuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/region/RegionFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/region/RegionFacade.java index 9c4af205b60..8b002a85bcb 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/region/RegionFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/region/RegionFacade.java @@ -14,6 +14,8 @@ public interface RegionFacade { RegionDto getRegionByUuid(String uuid); + RegionReferenceDto getRegionReferenceByUuid(String uuid); + List getAllData(); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/report/WeeklyReportFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/report/WeeklyReportFacade.java index 4ba7cbfcb14..8bde0aadb70 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/report/WeeklyReportFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/report/WeeklyReportFacade.java @@ -8,6 +8,7 @@ import de.symeda.sormas.api.facility.FacilityReferenceDto; import de.symeda.sormas.api.region.DistrictReferenceDto; import de.symeda.sormas.api.region.RegionReferenceDto; +import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.utils.EpiWeek; @Remote @@ -29,6 +30,12 @@ public interface WeeklyReportFacade { List getWeeklyReportsByFacility(FacilityReferenceDto facilityRef, EpiWeek epiWeek); - List getSummariesPerDistrict(EpiWeek epiWeek); + List getSummariesPerRegion(EpiWeek epiWeek); + + List getSummariesPerDistrict(RegionReferenceDto region, EpiWeek epiWeek); + + WeeklyReportReferenceDto getByEpiWeekAndUser(EpiWeek epiWeek, UserReferenceDto userRef); + + WeeklyReportDto getByUuid(String uuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleDto.java index c050acfa770..af85f192953 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleDto.java @@ -38,8 +38,13 @@ public class SampleDto extends SampleReferenceDto { private String sampleCode; private String labSampleID; private Date sampleDateTime; + private Date reportDateTime; private UserReferenceDto reportingUser; + private Double reportLat; + private Double reportLon; + private Float reportLatLonAccuracy; + private SampleMaterial sampleMaterial; private String sampleMaterialText; private FacilityReferenceDto lab; @@ -197,5 +202,23 @@ public static SampleDto buildReferralSample(UserReferenceDto userRef, SampleDto return sample; } + public Double getReportLat() { + return reportLat; + } + public void setReportLat(Double reportLat) { + this.reportLat = reportLat; + } + public Double getReportLon() { + return reportLon; + } + public void setReportLon(Double reportLon) { + this.reportLon = reportLon; + } + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleIndexDto.java index 9ace5a03121..461f6e09d09 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleIndexDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleIndexDto.java @@ -16,6 +16,7 @@ public class SampleIndexDto extends SampleReferenceDto { public static final String ASSOCIATED_CASE = "associatedCase"; public static final String DISEASE = "disease"; + public static final String DISEASE_DETAILS = "diseaseDetails"; public static final String SAMPLE_CODE = "sampleCode"; public static final String LAB_SAMPLE_ID = "labSampleID"; public static final String LGA = "lga"; @@ -34,6 +35,7 @@ public class SampleIndexDto extends SampleReferenceDto { private CaseReferenceDto associatedCase; private Disease disease; + private String diseaseDetails; private String sampleCode; private String labSampleID; private DistrictReferenceDto lga; @@ -62,6 +64,12 @@ public Disease getDisease() { public void setDisease(Disease disease) { this.disease = disease; } + public String getDiseaseDetails() { + return diseaseDetails; + } + public void setDiseaseDetails(String diseaseDetails) { + this.diseaseDetails = diseaseDetails; + } public String getSampleCode() { return sampleCode; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java index 9ee76197134..7b484eaac6a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java @@ -11,6 +11,7 @@ public enum SampleMaterial { THROAT_SWAB, NP_SWAB, CEREBROSPINAL_FLUID, + CRUST, OTHER, ; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleTestType.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleTestType.java index 81d5b637c19..ca56d1341e5 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleTestType.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleTestType.java @@ -11,6 +11,7 @@ public enum SampleTestType { MICROSCOPY, VIRUS_ISOLATION, RAPID_TEST, + ANTIGEN_DETECTION, OTHER, ; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsContext.java b/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsContext.java new file mode 100644 index 00000000000..f7f6ce84503 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsContext.java @@ -0,0 +1,8 @@ +package de.symeda.sormas.api.symptoms; + +public enum SymptomsContext { + + CASE, + VISIT; + +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java index 0a4e0e12b7d..1c7d6256e58 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java @@ -4,7 +4,6 @@ import de.symeda.sormas.api.DataTransferObject; import de.symeda.sormas.api.Disease; -import de.symeda.sormas.api.location.LocationDto; import de.symeda.sormas.api.utils.Diseases; public class SymptomsDto extends DataTransferObject { @@ -17,16 +16,20 @@ public class SymptomsDto extends DataTransferObject { public static final String TEMPERATURE_SOURCE = "temperatureSource"; public static final String ONSET_DATE = "onsetDate"; public static final String ONSET_SYMPTOM = "onsetSymptom"; + public static final String PATIENT_ILL_LOCATION = "patientIllLocation"; public static final String ABDOMINAL_PAIN = "abdominalPain"; public static final String ALTERED_CONSCIOUSNESS = "alteredConsciousness"; public static final String ANOREXIA_APPETITE_LOSS = "anorexiaAppetiteLoss"; public static final String BACKACHE = "backache"; + public static final String BEDRIDDEN = "bedridden"; public static final String BLOOD_IN_STOOL = "bloodInStool"; public static final String CHEST_PAIN = "chestPain"; + public static final String CHILLS_SWEATS = "chillsSweats"; public static final String CONFUSED_DISORIENTED = "confusedDisoriented"; public static final String CONJUNCTIVITIS = "conjunctivitis"; public static final String COUGH = "cough"; + public static final String CUTANEOUS_ERUPTION = "cutaneousEruption"; public static final String DARK_URINE = "darkUrine"; public static final String DEHYDRATION = "dehydration"; public static final String DIARRHEA = "diarrhea"; @@ -41,9 +44,30 @@ public class SymptomsDto extends DataTransferObject { public static final String JAUNDICE = "jaundice"; public static final String JOINT_PAIN = "jointPain"; public static final String KOPLIKS_SPOTS = "kopliksSpots"; + public static final String LESIONS = "lesions"; + public static final String LESIONS_SAME_STATE = "lesionsSameState"; + public static final String LESIONS_SAME_SIZE = "lesionsSameSize"; + public static final String LESIONS_DEEP_PROFOUND = "lesionsDeepProfound"; + public static final String LESIONS_FACE = "lesionsFace"; + public static final String LESIONS_LEGS = "lesionsLegs"; + public static final String LESIONS_SOLES_FEET = "lesionsSolesFeet"; + public static final String LESIONS_PALMS_HANDS = "lesionsPalmsHands"; + public static final String LESIONS_THORAX = "lesionsThorax"; + public static final String LESIONS_ARMS = "lesionsArms"; + public static final String LESIONS_GENITALS = "lesionsGenitals"; + public static final String LESIONS_ALL_OVER_BODY = "lesionsAllOverBody"; + public static final String LESIONS_RESEMBLE_IMG1 = "lesionsResembleImg1"; + public static final String LESIONS_RESEMBLE_IMG2 = "lesionsResembleImg2"; + public static final String LESIONS_RESEMBLE_IMG3 = "lesionsResembleImg3"; + public static final String LESIONS_RESEMBLE_IMG4 = "lesionsResembleImg4"; + public static final String LESIONS_THAT_ITCH = "lesionsThatItch"; + public static final String LYMPHADENOPATHY_AXILLARY = "lymphadenopathyAxillary"; + public static final String LYMPHADENOPATHY_CERVICAL = "lymphadenopathyCervical"; + public static final String LYMPHADENOPATHY_INGUINAL = "lymphadenopathyInguinal"; public static final String MUSCLE_PAIN = "musclePain"; public static final String NAUSEA = "nausea"; public static final String NECK_STIFFNESS = "neckStiffness"; + public static final String ORAL_ULCERS = "oralUlcers"; public static final String OTITIS_MEDIA = "otitisMedia"; public static final String RAPID_BREATHING = "rapidBreathing"; public static final String REFUSAL_FEEDOR_DRINK = "refusalFeedorDrink"; @@ -58,7 +82,6 @@ public class SymptomsDto extends DataTransferObject { public static final String VOMITING = "vomiting"; public static final String OTHER_NON_HEMORRHAGIC_SYMPTOMS = "otherNonHemorrhagicSymptoms"; public static final String OTHER_NON_HEMORRHAGIC_SYMPTOMS_TEXT = "otherNonHemorrhagicSymptomsText"; - public static final String UNEXPLAINED_BLEEDING = "unexplainedBleeding"; public static final String GUMS_BLEEDING = "gumsBleeding"; public static final String INJECTION_SITE_BLEEDING = "injectionSiteBleeding"; @@ -74,40 +97,33 @@ public class SymptomsDto extends DataTransferObject { public static final String OTHER_HEMORRHAGIC_SYMPTOMS_TEXT = "otherHemorrhagicSymptomsText"; public static final String SYMPTOMS_COMMENTS = "symptomsComments"; - public static final String ILLLOCATION = "illLocation"; - public static final String ILLLOCATION_FROM = "illLocationFrom"; - public static final String ILLLOCATION_TO = "illLocationTo"; public static final String SYMPTOMATIC = "symptomatic"; private Boolean symptomatic; private Date onsetDate; private String onsetSymptom; - private LocationDto illLocation; - private Date illLocationFrom; - private Date illLocationTo; - - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private Float temperature; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private TemperatureSource temperatureSource; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState fever; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState vomiting; @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.OTHER}) private SymptomState diarrhea; @Diseases({Disease.CHOLERA,Disease.YELLOW_FEVER,Disease.OTHER}) private SymptomState bloodInStool; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState nausea; @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CHOLERA,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) private SymptomState abdominalPain; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState headache; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState musclePain; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.YELLOW_FEVER,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState fatigueWeakness; @Diseases({Disease.EVD,Disease.LASSA,Disease.OTHER}) private SymptomState unexplainedBleeding; @@ -139,9 +155,9 @@ public class SymptomsDto extends DataTransferObject { private SymptomState skinRash; @Diseases({Disease.CSM,Disease.OTHER}) private SymptomState neckStiffness; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.MEASLES,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.MEASLES,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState soreThroat; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.MEASLES,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.MEASLES,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState cough; @Diseases({Disease.AVIAN_INFLUENCA,Disease.MEASLES,Disease.OTHER}) private SymptomState runnyNose; @@ -155,9 +171,9 @@ public class SymptomsDto extends DataTransferObject { private SymptomState seizures; @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.OTHER}) private SymptomState alteredConsciousness; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.MEASLES,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.MEASLES,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState conjunctivitis; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.MEASLES,Disease.DENGUE,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.MEASLES,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState eyePainLightSensitive; @Diseases({Disease.MEASLES,Disease.OTHER}) private SymptomState kopliksSpots; @@ -193,12 +209,62 @@ public class SymptomsDto extends DataTransferObject { private SymptomState rapidBreathing; @Diseases({Disease.DENGUE,Disease.OTHER}) private SymptomState swollenGlands; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.OTHER}) + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState cutaneousEruption; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState lesions; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState lesionsSameState; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState lesionsSameSize; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState lesionsDeepProfound; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Boolean lesionsFace; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Boolean lesionsLegs; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Boolean lesionsSolesFeet; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Boolean lesionsPalmsHands; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Boolean lesionsThorax; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Boolean lesionsArms; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Boolean lesionsGenitals; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private Boolean lesionsAllOverBody; + @Diseases({Disease.MONKEYPOX}) + private SymptomState lesionsResembleImg1; + @Diseases({Disease.MONKEYPOX}) + private SymptomState lesionsResembleImg2; + @Diseases({Disease.MONKEYPOX}) + private SymptomState lesionsResembleImg3; + @Diseases({Disease.MONKEYPOX}) + private SymptomState lesionsResembleImg4; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState lymphadenopathyInguinal; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState lymphadenopathyAxillary; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState lymphadenopathyCervical; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState chillsSweats; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState lesionsThatItch; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState bedridden; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private SymptomState oralUlcers; + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private SymptomState otherNonHemorrhagicSymptoms; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private String otherNonHemorrhagicSymptomsText; - @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.OTHER}) + @Diseases({Disease.EVD,Disease.LASSA,Disease.AVIAN_INFLUENCA,Disease.CSM,Disease.CHOLERA,Disease.MEASLES,Disease.DENGUE,Disease.MONKEYPOX,Disease.OTHER}) private String symptomsComments; + @Diseases({Disease.MONKEYPOX,Disease.OTHER}) + private String patientIllLocation; public Boolean getSymptomatic() { return symptomatic; @@ -218,23 +284,11 @@ public String getOnsetSymptom() { public void setOnsetSymptom(String onsetSymptom) { this.onsetSymptom = onsetSymptom; } - public LocationDto getIllLocation() { - return illLocation; - } - public void setIllLocation(LocationDto illLocation) { - this.illLocation = illLocation; - } - public Date getIllLocationFrom() { - return illLocationFrom; - } - public void setIllLocationFrom(Date illLocationFrom) { - this.illLocationFrom = illLocationFrom; + public String getPatientIllLocation() { + return patientIllLocation; } - public Date getIllLocationTo() { - return illLocationTo; - } - public void setIllLocationTo(Date illLocationTo) { - this.illLocationTo = illLocationTo; + public void setPatientIllLocation(String patientIllLocation) { + this.patientIllLocation = patientIllLocation; } public Float getTemperature() { return temperature; @@ -554,6 +608,150 @@ public SymptomState getSwollenGlands() { public void setSwollenGlands(SymptomState swollenGlands) { this.swollenGlands = swollenGlands; } + public SymptomState getCutaneousEruption() { + return cutaneousEruption; + } + public void setCutaneousEruption(SymptomState cutaneousEruption) { + this.cutaneousEruption = cutaneousEruption; + } + public SymptomState getLesions() { + return lesions; + } + public void setLesions(SymptomState lesions) { + this.lesions = lesions; + } + public Boolean getLesionsFace() { + return lesionsFace; + } + public void setLesionsFace(Boolean lesionsFace) { + this.lesionsFace = lesionsFace; + } + public Boolean getLesionsLegs() { + return lesionsLegs; + } + public void setLesionsLegs(Boolean lesionsLegs) { + this.lesionsLegs = lesionsLegs; + } + public Boolean getLesionsSolesFeet() { + return lesionsSolesFeet; + } + public void setLesionsSolesFeet(Boolean lesionsSolesFeet) { + this.lesionsSolesFeet = lesionsSolesFeet; + } + public Boolean getLesionsPalmsHands() { + return lesionsPalmsHands; + } + public void setLesionsPalmsHands(Boolean lesionsPalmsHands) { + this.lesionsPalmsHands = lesionsPalmsHands; + } + public Boolean getLesionsThorax() { + return lesionsThorax; + } + public void setLesionsThorax(Boolean lesionsThorax) { + this.lesionsThorax = lesionsThorax; + } + public Boolean getLesionsArms() { + return lesionsArms; + } + public void setLesionsArms(Boolean lesionsArms) { + this.lesionsArms = lesionsArms; + } + public Boolean getLesionsGenitals() { + return lesionsGenitals; + } + public void setLesionsGenitals(Boolean lesionsGenitals) { + this.lesionsGenitals = lesionsGenitals; + } + public Boolean getLesionsAllOverBody() { + return lesionsAllOverBody; + } + public void setLesionsAllOverBody(Boolean lesionsAllOverBody) { + this.lesionsAllOverBody = lesionsAllOverBody; + } + public SymptomState getLesionsSameState() { + return lesionsSameState; + } + public void setLesionsSameState(SymptomState lesionsSameState) { + this.lesionsSameState = lesionsSameState; + } + public SymptomState getLesionsSameSize() { + return lesionsSameSize; + } + public void setLesionsSameSize(SymptomState lesionsSameSize) { + this.lesionsSameSize = lesionsSameSize; + } + public SymptomState getLesionsDeepProfound() { + return lesionsDeepProfound; + } + public void setLesionsDeepProfound(SymptomState lesionsDeepProfound) { + this.lesionsDeepProfound = lesionsDeepProfound; + } + public SymptomState getLesionsResembleImg1() { + return lesionsResembleImg1; + } + public void setLesionsResembleImg1(SymptomState lesionsResembleImg1) { + this.lesionsResembleImg1 = lesionsResembleImg1; + } + public SymptomState getLesionsResembleImg2() { + return lesionsResembleImg2; + } + public void setLesionsResembleImg2(SymptomState lesionsResembleImg2) { + this.lesionsResembleImg2 = lesionsResembleImg2; + } + public SymptomState getLesionsResembleImg3() { + return lesionsResembleImg3; + } + public void setLesionsResembleImg3(SymptomState lesionsResembleImg3) { + this.lesionsResembleImg3 = lesionsResembleImg3; + } + public SymptomState getLesionsResembleImg4() { + return lesionsResembleImg4; + } + public void setLesionsResembleImg4(SymptomState lesionsResembleImg4) { + this.lesionsResembleImg4 = lesionsResembleImg4; + } + public SymptomState getLymphadenopathyInguinal() { + return lymphadenopathyInguinal; + } + public void setLymphadenopathyInguinal(SymptomState lymphadenopathyInguinal) { + this.lymphadenopathyInguinal = lymphadenopathyInguinal; + } + public SymptomState getLymphadenopathyAxillary() { + return lymphadenopathyAxillary; + } + public void setLymphadenopathyAxillary(SymptomState lymphadenopathyAxillary) { + this.lymphadenopathyAxillary = lymphadenopathyAxillary; + } + public SymptomState getLymphadenopathyCervical() { + return lymphadenopathyCervical; + } + public void setLymphadenopathyCervical(SymptomState lymphadenopathyCervical) { + this.lymphadenopathyCervical = lymphadenopathyCervical; + } + public SymptomState getChillsSweats() { + return chillsSweats; + } + public void setChillsSweats(SymptomState chillsSweats) { + this.chillsSweats = chillsSweats; + } + public SymptomState getLesionsThatItch() { + return lesionsThatItch; + } + public void setLesionsThatItch(SymptomState lesionsThatItch) { + this.lesionsThatItch = lesionsThatItch; + } + public SymptomState getBedridden() { + return bedridden; + } + public void setBedridden(SymptomState bedridden) { + this.bedridden = bedridden; + } + public SymptomState getOralUlcers() { + return oralUlcers; + } + public void setOralUlcers(SymptomState oralUlcers) { + this.oralUlcers = oralUlcers; + } public SymptomState getOtherNonHemorrhagicSymptoms() { return otherNonHemorrhagicSymptoms; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsHelper.java b/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsHelper.java index f77ae6e9240..1212ec34f94 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsHelper.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsHelper.java @@ -34,7 +34,10 @@ public static void updateIsSymptomatic(SymptomsDto dto) { dto.getChestPain(), dto.getConfusedDisoriented(), dto.getSeizures(), dto.getAlteredConsciousness(), dto.getConjunctivitis(), dto.getEyePainLightSensitive(), dto.getKopliksSpots(), dto.getThrobocytopenia(), dto.getOtitisMedia(), dto.getHearingloss(), dto.getDehydration(), dto.getAnorexiaAppetiteLoss(), dto.getRefusalFeedorDrink(), dto.getJointPain(), dto.getShock(), - dto.getHiccups(), dto.getUnexplainedBleeding(), dto.getOtherNonHemorrhagicSymptoms()); + dto.getHiccups(), dto.getBackache(), dto.getEyesBleeding(), dto.getJaundice(), dto.getDarkUrine(), dto.getStomachBleeding(), + dto.getRapidBreathing(), dto.getSwollenGlands(), dto.getCutaneousEruption(), dto.getLesions(), dto.getLymphadenopathyInguinal(), + dto.getLymphadenopathyAxillary(), dto.getLymphadenopathyCervical(), dto.getChillsSweats(), dto.getBedridden(), dto.getOralUlcers(), + dto.getUnexplainedBleeding(), dto.getOtherNonHemorrhagicSymptoms()); for (SymptomState symptom : unconditionalSymptoms) { if (symptom == SymptomState.YES) { diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskDto.java index 2922446a934..bcb1cf123b2 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskDto.java @@ -52,8 +52,9 @@ public class TaskDto extends DataTransferObject { private UserReferenceDto assigneeUser; private String assigneeReply; - private Float closedLat; - private Float closedLon; + private Double closedLat; + private Double closedLon; + private Float closedLatLonAccuracy; public TaskContext getTaskContext() { return taskContext; @@ -146,16 +147,16 @@ public TaskPriority getPriority() { public void setPriority(TaskPriority priority) { this.priority = priority; } - public Float getClosedLat() { + public Double getClosedLat() { return closedLat; } - public void setClosedLat(Float closedLat) { + public void setClosedLat(Double closedLat) { this.closedLat = closedLat; } - public Float getClosedLon() { + public Double getClosedLon() { return closedLon; } - public void setClosedLon(Float closedLon) { + public void setClosedLon(Double closedLon) { this.closedLon = closedLon; } @@ -173,5 +174,11 @@ public ReferenceDto getContextReference() { throw new IndexOutOfBoundsException(taskContext.toString()); } } + public Float getClosedLatLonAccuracy() { + return closedLatLonAccuracy; + } + public void setClosedLatLonAccuracy(Float closedLatLonAccuracy) { + this.closedLatLonAccuracy = closedLatLonAccuracy; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskStatus.java b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskStatus.java index 97ff5d6c053..039cb473bb4 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskStatus.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskStatus.java @@ -12,8 +12,4 @@ public enum TaskStatus { public String toString() { return I18nProperties.getEnumCaption(this); } - - public String getChangeString() { - return I18nProperties.getButtonCaption(getClass().getSimpleName() + "." + name(), name()); - } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskType.java b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskType.java index 0d09cbd8fd6..5395e0fce90 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskType.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskType.java @@ -29,7 +29,8 @@ public enum TaskType { ANIMAL_DEPOPULATION(TaskContext.EVENT, TaskContext.CASE), OTHER(true, TaskContext.CASE, TaskContext.CONTACT, TaskContext.EVENT, TaskContext.GENERAL), DAILY_REPORT_GENERATION(TaskContext.GENERAL), - SURVEILLANCE_REPORT_GENERATION(TaskContext.GENERAL); + SURVEILLANCE_REPORT_GENERATION(TaskContext.GENERAL), + WEEKLY_REPORT_GENERATION(TaskContext.GENERAL); private final boolean creatorCommentRequired; private final TaskContext[] taskContexts; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserFacade.java index 297b28b17bf..f56f5f304fe 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserFacade.java @@ -35,4 +35,6 @@ public interface UserFacade { int getNumberOfInformantsByFacility(FacilityReferenceDto facilityRef); + List getForWeeklyReportDetails(DistrictReferenceDto districtRef); + } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java index 6eeb74242a3..1c67eab891f 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java @@ -74,6 +74,10 @@ public void addAssignableRoles(Collection collection) { collection.add(SURVEILLANCE_SUPERVISOR); collection.add(CASE_SUPERVISOR); collection.add(CONTACT_SUPERVISOR); + collection.add(CASE_OFFICER); + collection.add(CONTACT_OFFICER); + collection.add(SURVEILLANCE_OFFICER); + collection.add(LAB_USER); break; case SURVEILLANCE_SUPERVISOR: collection.add(SURVEILLANCE_OFFICER); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/DateHelper.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/DateHelper.java index 4b7a220dee3..5909e272937 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/DateHelper.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/DateHelper.java @@ -210,6 +210,7 @@ public static Calendar getEpiCalendar() { Calendar calendar = Calendar.getInstance(); calendar.setFirstDayOfWeek(Calendar.MONDAY); calendar.setMinimalDaysInFirstWeek(1); + calendar.clear(); // this is necessary, because in some old java versions there a problems updating the fields based on the date return calendar; } @@ -337,47 +338,52 @@ public static List createWeeksList(int year) { /** * Calculates the start and end dates of the report for the given epi week. * + * @param now * @param epiWeek The epi week to calculate the dates for - * @param weeklyReportDate The date of report of the report for the given epi week, or null if none is available - * @param prevWeeklyReportDate The date of report of the report for the week before the given epi week, or null if none is available - * @param nextWeeklyReportDate The date of report of the report for the week after the given epi week, or null if none is available + * @param weeklyReportDate The date of report for the given epi week, or null if none is available + * @param prevWeeklyReportDate The date of report for the week before the given epi week, or null if none is available + * @param nextWeeklyReportDate The date of report for the week after the given epi week, or null if none is available * @return An array of size 2, containing the start date at index 0 and the end date at index 1 */ - public static Date[] calculateEpiWeekReportStartAndEnd(EpiWeek epiWeek, Date weeklyReportDate, Date prevWeeklyReportDate, Date nextWeeklyReportDate) { - Date epiWeekStart = getEpiWeekStart(epiWeek); - Date epiWeekEnd = getEpiWeekEnd(epiWeek); - EpiWeek currentEpiWeek = getEpiWeek(new Date()); - Date[] dates = new Date[2]; - + public static Date[] calculateEpiWeekReportStartAndEnd(Date now, EpiWeek epiWeek, Date weeklyReportDate, Date prevWeeklyReportDate, Date nextWeeklyReportDate) { + + Date[] reportStartAndEnd = new Date[2]; + + // start date: + if (prevWeeklyReportDate != null) { + // .. is the previous report date + reportStartAndEnd[0] = prevWeeklyReportDate; + } else { + // .. or the start of this week + reportStartAndEnd[0] = getEpiWeekStart(epiWeek); + } + + // end date: if (weeklyReportDate != null) { - if (prevWeeklyReportDate != null) { - dates[0] = prevWeeklyReportDate; - dates[1] = weeklyReportDate; - } else { - dates[0] = epiWeekStart; - dates[1] = weeklyReportDate; - } + // .. is the report date + reportStartAndEnd[1] = weeklyReportDate; } else { - if (prevWeeklyReportDate != null) { - if (nextWeeklyReportDate != null) { - dates[0] = prevWeeklyReportDate; - dates[1] = nextWeeklyReportDate; + Date epiWeekEnd = getEpiWeekEnd(epiWeek); + if (now.after(epiWeekEnd)) { + if (nextWeeklyReportDate == null) { + if (now.before(DateHelper.addDays(epiWeekEnd, 7))) { + // we are in the following week -> all reports until now count + reportStartAndEnd[1] = now; + } else { + // we are somewhere in the future - go with the unmodified epi week end + reportStartAndEnd[1] = epiWeekEnd; + } } else { - dates[0] = prevWeeklyReportDate; - dates[1] = DateHelper.getPreviousEpiWeek(currentEpiWeek).equals(epiWeek) ? new Date() : epiWeekEnd; - } - } else { - if (nextWeeklyReportDate != null) { - dates[0] = epiWeekStart; - dates[1] = nextWeeklyReportDate; - } else { - dates[0] = epiWeekStart; - dates[1] = DateHelper.getPreviousEpiWeek(currentEpiWeek).equals(epiWeek) ? new Date() : epiWeekEnd; + // there is a next report - go with the unmodified epi week end + reportStartAndEnd[1] = epiWeekEnd; } + } else { + // .. or the end of this week + reportStartAndEnd[1] = epiWeekEnd; } } - return dates; + return reportStartAndEnd; } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/visit/VisitDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/visit/VisitDto.java index 9624f3528c7..77457f5eb11 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/visit/VisitDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/visit/VisitDto.java @@ -30,8 +30,10 @@ public class VisitDto extends VisitReferenceDto { private VisitStatus visitStatus; private String visitRemarks; private SymptomsDto symptoms; - private Float reportLat; - private Float reportLon; + + private Double reportLat; + private Double reportLon; + private Float reportLatLonAccuracy; public Date getVisitDateTime() { return visitDateTime; @@ -75,17 +77,23 @@ public UserReferenceDto getVisitUser() { public void setVisitUser(UserReferenceDto visitUser) { this.visitUser = visitUser; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-api/src/main/resources/buttonCaptions.properties b/sormas-api/src/main/resources/buttonCaptions.properties deleted file mode 100644 index 7bc4a64e36e..00000000000 --- a/sormas-api/src/main/resources/buttonCaptions.properties +++ /dev/null @@ -1,19 +0,0 @@ - -Person.createNew = Create a new person -Person.select = Select a matching person - -Contact.cancelFollowUp = cancel follow-up -Contact.lostToFollowUp = lost to follow-up -Contact.resumeFollowUp = resume follow-up - -CaseStatus.POSSIBLE=Needs further investigation -CaseStatus.INVESTIGATED=Case investigation done -CaseStatus.SUSPECT=Is suspected case -CaseStatus.PROBABLE=Is probable case -CaseStatus.CONFIRMED=Is confirmed case -CaseStatus.NO_CASE=Is not a case -CaseStatus.RECOVERED=Is recovered -CaseStatus.DECEASED=Is deceased - -TaskStatus.DONE=Done -TaskStatus.NOT_EXECUTABLE=Not executable diff --git a/sormas-api/src/main/resources/enum.properties b/sormas-api/src/main/resources/enum.properties index fa30356d07c..f00735bea62 100644 --- a/sormas-api/src/main/resources/enum.properties +++ b/sormas-api/src/main/resources/enum.properties @@ -1,3 +1,7 @@ +AnimalCondition.ALIVE = Alive +AnimalCondition.DEAD = Dead +AnimalCondition.PROCESSED = Processed +AnimalCondition.UNKNOWN = Unknown ApproximateAgeType.YEARS=Years ApproximateAgeType.MONTHS=Months @@ -28,6 +32,9 @@ ContactRelation.SAME_ENVIRONMENT = Work in the same environment ContactRelation.MEDICAL_CARE = Provided medical care for the case ContactRelation.OTHER = Other +DateFilterOptions.DATE = By Date +DateFilterOptions.EPI_WEEK = By Epi Week + DeathPlaceType.COMMUNITY = Community DeathPlaceType.HOSPITAL = Hospital DeathPlaceType.OTHER = Other @@ -40,6 +47,7 @@ Disease.CHOLERA = Cholera Disease.MEASLES = Measles Disease.YELLOW_FEVER = Yellow fever Disease.DENGUE = Dengue fever +Disease.MONKEYPOX = Monkeypox Disease.OTHER = Other disease Disease.Short.EVD = EVD @@ -50,6 +58,7 @@ Disease.Short.CHOLERA = Cholera Disease.Short.MEASLES = Measles Disease.Short.YELLOW_FEVER = Yellow fever Disease.Short.DENGUE = Dengue +Disease.Short.MONKEYPOX = Monkeypox Disease.Short.OTHER = Other EventStatus.POSSIBLE = Possible alert @@ -118,6 +127,7 @@ SampleMaterial.NASAL_SWAB = Nasal swab SampleMaterial.THROAT_SWAB = Throat swab SampleMaterial.NP_SWAB = Nasopharyngeal swab SampleMaterial.CEREBROSPINAL_FLUID = Cerebrospinal fluid +SampleMaterial.CRUST = Crust SampleMaterial.OTHER = Other SampleSource.HUMAN = Human @@ -131,6 +141,7 @@ SampleTestType.CULTURE = Culture SampleTestType.MICROSCOPY = Microscopy SampleTestType.VIRUS_ISOLATION = Virus isolation SampleTestType.RAPID_TEST = Rapid test +SampleTestType.ANTIGEN_DETECTION = Antigen detection test SampleTestType.OTHER = Other SampleTestResultType.INDETERMINATE = Indeterminate @@ -148,7 +159,7 @@ SpecimenCondition.NOT_ADEQUATE = Not adequate SymptomState.YES=Yes SymptomState.NO=No -SymptomState.UNKNOWN=Unk +SymptomState.UNKNOWN=Unknown Sex.MALE = Male Sex.FEMALE = Female @@ -186,6 +197,7 @@ TaskType.OTHER = other task as described in comments TaskType.DAILY_REPORT_GENERATION = generate daily report TaskType.SURVEILLANCE_REPORT_GENERATION = generate surveillance report TaskType.SAMPLE_COLLECTION = sample collection +TaskType.WEEKLY_REPORT_GENERATION = generate weekly report TemperatureSource.AXILLARY=axillary TemperatureSource.ORAL=oral @@ -245,8 +257,4 @@ WaterSource.OTHER = Other YesNoUnknown.YES = Yes YesNoUnknown.NO = No -YesNoUnknown.UNKNOWN = Unk - -YesNoUnknownHoriz.YES = Yes -YesNoUnknownHoriz.NO = No -YesNoUnknownHoriz.UNKNOWN = Unk \ No newline at end of file +YesNoUnknown.UNKNOWN = Unknown \ No newline at end of file diff --git a/sormas-api/src/main/resources/fieldCaptions.properties b/sormas-api/src/main/resources/fieldCaptions.properties index 1a1e0bd98d6..41ff7b8ae5d 100644 --- a/sormas-api/src/main/resources/fieldCaptions.properties +++ b/sormas-api/src/main/resources/fieldCaptions.properties @@ -45,6 +45,7 @@ CaseData.epiData = Epidemiological data CaseData.epidNumber = EPID number CaseData.yellowFeverVaccination = Received yellow fever vaccination CaseData.yellowFeverVaccinationInfoSource = Source of vaccination information +CaseData.smallpoxVaccinationScar = Is a Smallpox vaccination scar present? # captions for caseData-tabs CaseData.CASE_DATA=Case data @@ -126,8 +127,10 @@ Dashboard.heading =
Dashboard.subHeading =
Dashboard.queryPeriod = Query period
(%d days) Dashboard.previousPeriod = Previous period
(%d days) -Dashboard.from = Show cases from onset date -Dashboard.to = Show cases to onset date +Dashboard.fromDate = From Onset Date +Dashboard.toDate = To Onset Date +Dashboard.fromWeek = From Onset Week +Dashboard.toWeek = To Onset Week Dashboard.dateFilterForMap = Apply date filter Dashboard.hcws = Healthcare workers Dashboard.total = Total @@ -141,6 +144,7 @@ Dashboard.contacts = Contacts Dashboard.alerts = Alerts Dashboard.newCases = New cases (%s to %s) Dashboard.all = All +Dashboard.district = Local Government Area Dashboard.disease = Disease Dashboard.notYetClassified = Not yet classified Dashboard.confirmed = Confirmed @@ -148,12 +152,14 @@ Dashboard.probable = Probable Dashboard.suspect = Suspect Dashboard.epiCurve = Epidemiological Curve Dashboard.situationReport = Situation Report Summary -Dashboard.caseMap = Status Map +Dashboard.caseMap = Case Status Map Dashboard.expand = Expand Dashboard.collapse = Collapse Dashboard.apply = Apply filters Dashboard.showCases = Show cases Dashboard.showContacts = Show contacts +Dashboard.showConfirmedContacts = Show confirmed contacts +Dashboard.showUnconfirmedContacts = Show unconfirmed contacts Dashboard.noFollowUp = No follow-up Dashboard.visit24Hours = Last visit < 24h Dashboard.visit48Hours = Last visit < 48h @@ -163,7 +169,8 @@ EpiData = Epidemiological data EpiData.burialAttended = Visited a burial EpiData.gatheringAttended = Visited a social event EpiData.traveled = Traveled -EpiData.hint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +EpiData.epiDataHint = Please indicate if any of the following is relevant for the patient during the incubation period or illness. +EpiData.animalHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. EpiData.rodents = Rodents or their excreta EpiData.bats = Bats or their excreta EpiData.primates = Primates (monkeys) @@ -188,6 +195,9 @@ EpiData.waterSourceOther = Specify EpiData.waterBody = Contact with body of water EpiData.waterBodyDetails = Name and location of water EpiData.tickBite = Tick bite +EpiData.dateOfLastExposure = Date of last exposure +EpiData.placeOfLastExposure = Place of last exposure +EpiData.animalCondition = Condition of animal last exposed to EpiData.burials = Burials EpiData.gatherings = Social events EpiData.travels = Travels @@ -313,7 +323,7 @@ Hospitalization.dischargeDate = Date of discharge Hospitalization.healthFacility = Hospital name Hospitalization.isolated = Isolation # Workaround -Hospitalization.1isolationDate = Date of isolation +Hospitalization.isolationDate = Date of isolation Hospitalization.hospitalizedPreviously = Was the patient hospitalized or did he/she visit a health clinic previously for this illness? Hospitalization.previousHospitalizations = Previous hospitalizations @@ -326,6 +336,8 @@ Location.district=LGA Location.community=Ward Location.latitude=GPS latitude Location.longitude=GPS longitude +Location.latLonAccuracy=GPS accuracy in m +Location.latLon=GPS lat and lon Person = Person Person.address = @@ -337,7 +349,7 @@ Person.lastName = Last name Person.nickname = Nickname Person.mothersMaidenName = Mother's maiden name Person.presentCondition = Present condition -Person.birthdate = Date of birth (day / month / year) +Person.birthdate = Date of birth (year / month / day) Person.birthdateDD = Person.birthdateMM = Person.birthdateYYYY = @@ -494,6 +506,32 @@ Symptoms.darkUrine = Dark Urine Symptoms.stomachBleeding = Bleeding from the stomach Symptoms.rapidBreathing = Rapid breathing Symptoms.swollenGlands = Swollen glands +Symptoms.cutaneousEruption = Cutaneous eruption +Symptoms.lesions = Lesions +Symptoms.lesionsSameState = All lesions in same state of development? +Symptoms.lesionsSameSize = All lesions the same size? +Symptoms.lesionsDeepProfound = Lesions deep and profound? +Symptoms.lesionsLocation = Localisation of the lesions +Symptoms.lesionsFace = Face +Symptoms.lesionsLegs = Legs +Symptoms.lesionsSolesFeet = Soles of the feet +Symptoms.lesionsPalmsHands = Palms of the hands +Symptoms.lesionsThorax = Thorax +Symptoms.lesionsArms = Arms +Symptoms.lesionsGenitals = Genitals +Symptoms.lesionsAllOverBody = All over the body +Symptoms.lesionsResembleImg1 = Do the lesions resemble the photo below? +Symptoms.lesionsResembleImg2 = Do the lesions resemble the photo below? +Symptoms.lesionsResembleImg3 = Do the lesions resemble the photo below? +Symptoms.lesionsResembleImg4 = Do the lesions resemble the photo below? +Symptoms.lymphadenopathyInguinal = Lymphadenopathy, inguinal +Symptoms.lymphadenopathyAxillary = Lymphadenopathy, axillary +Symptoms.lymphadenopathyCervical = Lymphadenopathy, cervical +Symptoms.chillsSweats = Chills or sweats +Symptoms.lesionsThatItch = Lesions that itch +Symptoms.bedridden = Is the patient bedridden? +Symptoms.oralUlcers = Oral ulcers +Symptoms.patientIllLocation = Name of the village (and country) where the patient got ill Task = Task Task.assigneeReply = Comments on execution @@ -543,9 +581,14 @@ Visit.SYMPTOMS=Symptoms WeeklyReportSummary.region = State WeeklyReportSummary.district = LGA WeeklyReportSummary.facilities = Health facilities -WeeklyReportSummary.reports = Reports +WeeklyReportSummary.reports = Case Reports WeeklyReportSummary.reportsPercentage = % WeeklyReportSummary.zeroReports = Zero reports WeeklyReportSummary.zeroReportsPercentage = % WeeklyReportSummary.missingReports = Missing reports -WeeklyReportSummary.missingReportsPercentage = % \ No newline at end of file +WeeklyReportSummary.missingReportsPercentage = % + +WeeklyReportDetails.facilityAndInformant = Health Facility & Informant +WeeklyReportDetails.totalNumberOfCases = Number of Cases +WeeklyReportDetails.confirmed = Confirmed +WeeklyReportDetails.viewDetails = \ No newline at end of file diff --git a/sormas-api/src/main/resources/fieldDescriptions.properties b/sormas-api/src/main/resources/fieldDescriptions.properties index d1062160551..96e4b4a13e0 100644 --- a/sormas-api/src/main/resources/fieldDescriptions.properties +++ b/sormas-api/src/main/resources/fieldDescriptions.properties @@ -70,6 +70,10 @@ Event.srcEmail = Enter the source's e-mail address Hospitalization.admissionDate = Please provide the date of admission to the hospital Hospitalization.isolated = Is the person in isolation or currently being placed there? +Location.latitude=GPS latitude is the the north/south angular location in degrees +Location.longitude=GPS longitude is the the east/west angular location in degrees +Location.latLonAccuracy=If you draw a circle centered at this location's latitude and longitude, and with a radius equal to the accuracy, then there is a 68% probability that the true location is inside the circle + Person.approximateAge = Enter the age of the person # Workaround Person.approximate1Age = Enter the age of the person diff --git a/sormas-api/src/main/resources/fragments.properties b/sormas-api/src/main/resources/fragments.properties new file mode 100644 index 00000000000..63c15d0eb44 --- /dev/null +++ b/sormas-api/src/main/resources/fragments.properties @@ -0,0 +1,42 @@ + +Contact.cancelFollowUp = cancel follow-up +Contact.lostToFollowUp = lost to follow-up +Contact.resumeFollowUp = resume follow-up + +Person.createNew = Create a new person +Person.select = Select a matching person + +View.cases = Case Directory +View.cases.sub = +View.cases.data = Case Information +View.cases.person = Case Person +View.cases.hospitalization = Case Hospitalization +View.cases.symptoms = Case Symptoms +View.cases.epidata = Case Epidemiological Data +View.cases.contacts = Case Contacts + +View.contacts = Contact Directory +View.contacts.sub = +View.contacts.data = Contact Information +View.contacts.person = Contact Person +View.contacts.visits = Contact Visits + +View.dashboard = Dashboard + +View.events = Alert Directory +View.events.sub = +View.events.data = Alert Information +View.events.eventparticipants = Alert Participants + +View.reports = Weekly Reports +View.reports.sub = + +View.samples = Sample Directory +View.samples.sub = +View.samples.data = Sample Information + +View.tasks = Task Management +View.tasks.sub = + +View.users = User Management +View.users.sub = \ No newline at end of file diff --git a/sormas-api/src/test/java/de/symeda/sormas/api/utils/EpiWeekCalculationTest.java b/sormas-api/src/test/java/de/symeda/sormas/api/utils/EpiWeekCalculationTest.java new file mode 100644 index 00000000000..e0cb42a35e6 --- /dev/null +++ b/sormas-api/src/test/java/de/symeda/sormas/api/utils/EpiWeekCalculationTest.java @@ -0,0 +1,53 @@ +package de.symeda.sormas.api.utils; + +import static org.junit.Assert.*; + +import java.util.Calendar; +import java.util.Date; + +import org.junit.Test; + +public class EpiWeekCalculationTest { + + @Test + public void testCalculatePreviousEpiWeek() { + EpiWeek epiWeek = new EpiWeek(2017, 1); + EpiWeek previousEpiWeek = DateHelper.getPreviousEpiWeek(epiWeek); + assertEquals(previousEpiWeek.getYear(), 2016); + assertEquals(previousEpiWeek.getWeek(), 52); + } + + @Test + public void testCalculateNextEpiWeek() { + EpiWeek epiWeek = new EpiWeek(2017, 53); + EpiWeek nextEpiWeek = DateHelper.getNextEpiWeek(epiWeek); + assertEquals(nextEpiWeek.getYear(), 2018); + assertEquals(nextEpiWeek.getWeek(), 1); + } + + /** + * TODO this test is not stable, because calculateEpiWeekReportStartAndEnd uses the current date for comparisons. + * Add a "now" param to calculateEpiWeekReportStartAndEnd + */ + @Test + public void testCalculateEpiWeekReportStartAndEnd() { + EpiWeek epiWeek = new EpiWeek(2017, 42); + Date now = new Date(2017, 9, 11); + Calendar calendar = Calendar.getInstance(); + calendar.clear(); + calendar.set(2017, 10, 11); + Date weeklyReportDate = calendar.getTime(); + calendar.clear(); + calendar.set(2017, 10, 10); + Date previousWeeklyReportDate = calendar.getTime(); + + Date[] startAndEnd = DateHelper.calculateEpiWeekReportStartAndEnd(now, epiWeek, weeklyReportDate, previousWeeklyReportDate, null); + assertTrue(startAndEnd[0].equals(previousWeeklyReportDate)); + assertFalse(startAndEnd[1].after(weeklyReportDate)); + + startAndEnd = DateHelper.calculateEpiWeekReportStartAndEnd(now, epiWeek, null, previousWeeklyReportDate, null); + assertTrue(startAndEnd[0].equals(previousWeeklyReportDate)); + assertTrue(startAndEnd[1].equals(DateHelper.getEpiWeekEnd(epiWeek))); + } + +} diff --git a/sormas-app/app/build.gradle b/sormas-app/app/build.gradle index c7bd2fb4935..1338da38131 100644 --- a/sormas-app/app/build.gradle +++ b/sormas-app/app/build.gradle @@ -11,12 +11,12 @@ android { // storePassword 'SunkSesa' // } // } - compileSdkVersion 23 + compileSdkVersion 24 buildToolsVersion '25.0.3' defaultConfig { applicationId "de.symeda.sormas.app" minSdkVersion 19 - targetSdkVersion 23 + targetSdkVersion 24 versionCode buildVersionCode() versionName "$sormasVersion" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -59,8 +59,8 @@ configurations.all { dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') // https://mvnrepository.com/artifact/com.googlecode/openbeans - compile 'com.android.support:appcompat-v7:23.3.0' - compile 'com.android.support:design:23.3.0' + compile 'com.android.support:appcompat-v7:24.2.0' + compile 'com.android.support:design:24.2.0' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.j256.ormlite:ormlite-core:4.48' @@ -73,7 +73,7 @@ dependencies { testCompile 'org.hamcrest:hamcrest-library:1.1' testCompile 'org.robolectric:robolectric:3.0' testCompile 'org.mockito:mockito-core:1.10.19' - androidTestCompile 'com.android.support:support-annotations:23.3.0' + androidTestCompile 'com.android.support:support-annotations:24.2.0' androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:rules:0.5' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java index d72b3340844..177504947d8 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java @@ -48,7 +48,7 @@ public class CaseBackendTest { @Before public void initTest() { - TestHelper.initTestEnvironment(); + TestHelper.initTestEnvironment(false); } @Test @@ -132,14 +132,12 @@ public void shouldMergeAsExpected() throws DaoException { mergeCase.setPerson((Person) caze.getPerson().clone()); mergeCase.getPerson().setAddress((Location) caze.getPerson().getAddress().clone()); mergeCase.setSymptoms((Symptoms) caze.getSymptoms().clone()); - mergeCase.getSymptoms().setIllLocation((Location) caze.getSymptoms().getIllLocation().clone()); mergeCase.setHospitalization((Hospitalization) caze.getHospitalization().clone()); mergeCase.setEpiData((EpiData) caze.getEpiData().clone()); mergeCase.setId(null); mergeCase.getPerson().setId(null); mergeCase.getPerson().getAddress().setId(null); mergeCase.getSymptoms().setId(null); - mergeCase.getSymptoms().getIllLocation().setId(null); mergeCase.getHospitalization().setId(null); mergeCase.getEpiData().setId(null); @@ -228,14 +226,12 @@ public void shouldCreateSyncLogEntry() throws DaoException { mergeCase.setPerson((Person) caze.getPerson().clone()); mergeCase.getPerson().setAddress((Location) caze.getPerson().getAddress().clone()); mergeCase.setSymptoms((Symptoms) caze.getSymptoms().clone()); - mergeCase.getSymptoms().setIllLocation((Location) caze.getSymptoms().getIllLocation().clone()); mergeCase.setHospitalization((Hospitalization) caze.getHospitalization().clone()); mergeCase.setEpiData((EpiData) caze.getEpiData().clone()); mergeCase.setId(null); mergeCase.getPerson().setId(null); mergeCase.getPerson().getAddress().setId(null); mergeCase.getSymptoms().setId(null); - mergeCase.getSymptoms().getIllLocation().setId(null); mergeCase.getHospitalization().setId(null); mergeCase.getEpiData().setId(null); mergeCase.setEpidNumber("ServerEpidNumber"); diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/ContactBackendTest.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/ContactBackendTest.java index 69a37b18c06..59e078ae77e 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/ContactBackendTest.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/ContactBackendTest.java @@ -34,13 +34,11 @@ public class ContactBackendTest { @Before public void initTest() { - TestHelper.initTestEnvironment(); + TestHelper.initTestEnvironment(false); } @Test public void shouldCreateContact() { - TestHelper.initTestEnvironment(); - assertThat(DatabaseHelper.getContactDao().queryForAll().size(), is(0)); TestEntityCreator.createContact(); @@ -85,11 +83,9 @@ public void shouldMergeAsExpected() throws DaoException { mergeVisit.setPerson((Person) visit.getPerson().clone()); mergeVisit.getPerson().setAddress((Location) visit.getPerson().getAddress().clone()); mergeVisit.setSymptoms((Symptoms) visit.getSymptoms().clone()); - mergeVisit.getSymptoms().setIllLocation((Location) visit.getSymptoms().getIllLocation().clone()); mergeVisit.setId(null); mergeVisit.getPerson().getAddress().setId(null); mergeVisit.getSymptoms().setId(null); - mergeVisit.getSymptoms().getIllLocation().setId(null); mergeVisit.setVisitStatus(VisitStatus.COOPERATIVE); diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/EventBackendTest.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/EventBackendTest.java index 6829048e761..294ccb1faa7 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/EventBackendTest.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/EventBackendTest.java @@ -34,13 +34,11 @@ public class EventBackendTest { @Before public void initTest() { - TestHelper.initTestEnvironment(); + TestHelper.initTestEnvironment(false); } @Test public void shouldCreateEvent() { - TestHelper.initTestEnvironment(); - assertThat(DatabaseHelper.getEventDao().queryForAll().size(), is(0)); TestEntityCreator.createEvent(); diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/SampleBackendTest.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/SampleBackendTest.java index 54a6ffc2848..9eaf0f77e48 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/SampleBackendTest.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/SampleBackendTest.java @@ -36,13 +36,11 @@ public class SampleBackendTest { @Before public void initTest() { - TestHelper.initTestEnvironment(); + TestHelper.initTestEnvironment(false); } @Test public void shouldCreateSample() { - TestHelper.initTestEnvironment(); - assertThat(DatabaseHelper.getSampleDao().queryForAll().size(), is(0)); TestEntityCreator.createSample(); diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestEntityCreator.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestEntityCreator.java index 5a91a02e84b..57c88b3ed95 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestEntityCreator.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestEntityCreator.java @@ -16,6 +16,7 @@ import de.symeda.sormas.api.task.TaskType; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.EpiWeek; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.DaoException; import de.symeda.sormas.app.backend.common.DatabaseHelper; @@ -33,6 +34,7 @@ import de.symeda.sormas.app.backend.region.Community; import de.symeda.sormas.app.backend.region.District; import de.symeda.sormas.app.backend.region.Region; +import de.symeda.sormas.app.backend.report.WeeklyReport; import de.symeda.sormas.app.backend.sample.Sample; import de.symeda.sormas.app.backend.sample.SampleTest; import de.symeda.sormas.app.backend.symptoms.Symptoms; @@ -216,8 +218,6 @@ public static EpiDataTravel createEpiDataTravel(Case caze) { public static Visit createVisit(Contact contact) throws DaoException { Visit visit = DatabaseHelper.getVisitDao().build(contact.getUuid()); Symptoms symptoms = DatabaseHelper.getSymptomsDao().build(); - Location illLocation = DatabaseHelper.getLocationDao().build(); - symptoms.setIllLocation(illLocation); visit.setSymptoms(symptoms); visit.setVisitUser(ConfigProvider.getUser()); @@ -287,4 +287,16 @@ public static Task createCaseTask(Case caze, TaskStatus taskStatus, User user) { return DatabaseHelper.getTaskDao().queryForId(task.getId()); } + public static WeeklyReport createWeeklyReport(EpiWeek epiWeek) { + WeeklyReport weeklyReport; + + try { + weeklyReport = DatabaseHelper.getWeeklyReportDao().create(epiWeek); + } catch (DaoException e) { + throw new RuntimeException(e); + } + + return weeklyReport; + } + } diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestHelper.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestHelper.java index 9096780a30b..6f05f923df5 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestHelper.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestHelper.java @@ -33,8 +33,9 @@ public class TestHelper { public static final String SECOND_FACILITY_UUID = "F2F2F2-F2F2F2-F2F2F2-F2F2F2F2"; public static final String USER_UUID = "0123456789"; public static final String SECOND_USER_UUID = "0987654321"; + public static final String INFORMANT_USER_UUID = "0192837465"; - public static void initTestEnvironment() { + public static void initTestEnvironment(boolean setInformantAsActiveUser) { // Initialize a testing context to not operate on the actual database RenamingDelegatingContext context = new RenamingDelegatingContext(InstrumentationRegistry.getTargetContext(), "test_"); // Make sure that no database/user is still set from the last run @@ -45,10 +46,10 @@ public static void initTestEnvironment() { ConfigProvider.init(context); insertInfrastructureData(); - insertUsers(); + insertUsers(setInformantAsActiveUser); } - private static void insertUsers() { + private static void insertUsers(boolean setInformantAsActiveUser) { // Create user and set username and password User user = new User(); user.setUserName("SanaObas"); @@ -60,8 +61,10 @@ private static void insertUsers() { user.setChangeDate(new Date()); user.setUuid(USER_UUID); DatabaseHelper.getUserDao().create(user); - ConfigProvider.setUsernameAndPassword("SanaObas", "TestPassword"); - ConfigProvider.setServerRestUrl("http://this-is-a-test-url-that-hopefully-doesnt-exist.com"); + if (!setInformantAsActiveUser) { + ConfigProvider.setUsernameAndPassword("SanaObas", "TestPassword"); + ConfigProvider.setServerRestUrl("http://this-is-a-test-url-that-hopefully-doesnt-exist.com"); + } // Create a second user with a specific region and district User secondUser = new User(); @@ -76,6 +79,25 @@ private static void insertUsers() { secondUser.setRegion(DatabaseHelper.getRegionDao().queryUuid(REGION_UUID)); secondUser.setDistrict(DatabaseHelper.getDistrictDao().queryUuid(SECOND_DISTRICT_UUID)); DatabaseHelper.getUserDao().create(secondUser); + + // Create an informant + User informant = new User(); + informant.setUserName("InfoUser"); + informant.setAktiv(true); + informant.setFirstName("Info"); + informant.setLastName("User"); + informant.setUserRole(UserRole.INFORMANT); + informant.setCreationDate(new Date()); + informant.setChangeDate(new Date()); + informant.setUuid(INFORMANT_USER_UUID); + informant.setRegion(DatabaseHelper.getRegionDao().queryUuid(REGION_UUID)); + informant.setDistrict(DatabaseHelper.getDistrictDao().queryUuid(DISTRICT_UUID)); + informant.setHealthFacility(DatabaseHelper.getFacilityDao().queryUuid(FACILITY_UUID)); + DatabaseHelper.getUserDao().create(informant); + if (setInformantAsActiveUser) { + ConfigProvider.setUsernameAndPassword("InfoUser", "TestPassword"); + ConfigProvider.setServerRestUrl("http://this-is-a-test-url-that-hopefully-doesnt-exist.com"); + } } private static void insertInfrastructureData() { diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/WeeklyReportBackendTest.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/WeeklyReportBackendTest.java new file mode 100644 index 00000000000..65541c88383 --- /dev/null +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/WeeklyReportBackendTest.java @@ -0,0 +1,58 @@ +package de.symeda.sormas.app; + +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Date; + +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.app.backend.caze.Case; +import de.symeda.sormas.app.backend.common.DatabaseHelper; +import de.symeda.sormas.app.backend.report.WeeklyReport; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * Created by Mate Strysewske on 12.10.2017. + */ +@RunWith(AndroidJUnit4.class) +public class WeeklyReportBackendTest { + + @Rule + public final ActivityTestRule testActivityRule = new ActivityTestRule<>(TestBackendActivity.class, false, true); + + @Before + public void initTest() { + TestHelper.initTestEnvironment(true); + } + + @Test + public void shouldCreateReportWithoutCases() { + // Assure that there are no weekly reports in the app to start with + assertThat(DatabaseHelper.getWeeklyReportDao().queryForAll().size(), is(0)); + + WeeklyReport report = TestEntityCreator.createWeeklyReport(DateHelper.getPreviousEpiWeek(new Date())); + + // Assure that the weekly report has been successfully created + assertThat(DatabaseHelper.getWeeklyReportDao().queryForAll().size(), is(1)); + + // Assure that the weekly report does not have any entries + assertThat(report.getTotalNumberOfCases(), is(0)); + } + + @Test + public void shouldCreateReportWithCases() { + TestEntityCreator.createCase(); + WeeklyReport report = TestEntityCreator.createWeeklyReport(DateHelper.getEpiWeek(new Date())); + + // Assure that the weekly report has an entry + assertThat(report.getTotalNumberOfCases(), is(1)); + } + +} diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractSormasActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractSormasActivity.java index 35fc0e90a77..ee2a868833f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractSormasActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractSormasActivity.java @@ -62,6 +62,13 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } + + // Show the Enter Pin Activity if the user doesn't have access to the app + if (!ConfigProvider.isAccessGranted()) { + Intent intent = new Intent(this, EnterPinActivity.class); + startActivity(intent); + return; + } } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractTabActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractTabActivity.java index 27ab10f9a73..53d374e3aa0 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractTabActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractTabActivity.java @@ -1,33 +1,11 @@ package de.symeda.sormas.app; -import android.accounts.AuthenticatorException; -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; -import android.support.v4.app.Fragment; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.ViewPager; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.view.View; - -import com.google.android.gms.analytics.Tracker; - -import java.net.ConnectException; import de.symeda.sormas.app.backend.common.AbstractDomainObject; -import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.config.ConfigProvider; -import de.symeda.sormas.app.backend.synclog.SyncLogDao; -import de.symeda.sormas.app.caze.CaseEditTabs; -import de.symeda.sormas.app.component.SyncLogDialog; -import de.symeda.sormas.app.rest.RetroProvider; -import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.util.FormTab; import de.symeda.sormas.app.util.SlidingTabLayout; -import de.symeda.sormas.app.util.SyncCallback; public abstract class AbstractTabActivity extends AbstractSormasActivity { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/EnterPinActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/EnterPinActivity.java index 0518d5b9981..9bb28c961b4 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/EnterPinActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/EnterPinActivity.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.os.Bundle; import android.support.design.widget.Snackbar; +import android.support.v4.app.NavUtils; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.view.KeyEvent; @@ -16,9 +17,11 @@ import java.util.regex.Pattern; import de.symeda.sormas.app.backend.config.ConfigProvider; +import de.symeda.sormas.app.backend.task.Task; import de.symeda.sormas.app.caze.CasesActivity; import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.settings.SettingsActivity; +import de.symeda.sormas.app.task.TaskEditActivity; import de.symeda.sormas.app.util.SyncCallback; /** @@ -136,8 +139,9 @@ public void submit(View view) { // otherwise display an error message and restart the activity if (lastEnteredPIN.equals(enteredPIN)) { ConfigProvider.setPin(enteredPIN); + ConfigProvider.setAccessGranted(true); Snackbar.make(findViewById(R.id.base_layout), R.string.snackbar_pin_correct_loading, Snackbar.LENGTH_LONG).show(); - startMainActivity(); + finish(); } else { lastEnteredPIN = null; Snackbar.make(findViewById(R.id.base_layout), R.string.snackbar_pin_not_matching, Snackbar.LENGTH_LONG).show(); @@ -174,8 +178,9 @@ public void submit(View view) { } else { // Process the login if the PIN is correct, otherwise display an error message and restart the activity if (enteredPIN.equals(savedPIN)) { + ConfigProvider.setAccessGranted(true); Snackbar.make(findViewById(R.id.base_layout), R.string.snackbar_pin_correct_loading, Snackbar.LENGTH_LONG).show(); - startMainActivity(); + finish(); } else { Snackbar.make(findViewById(R.id.base_layout), R.string.snackbar_pin_wrong, Snackbar.LENGTH_LONG).show(); triedAgain = true; @@ -262,8 +267,7 @@ public void onClick(DialogInterface dialog, int which) { dialog.show(); } - public void enterNumber(View view) - { + public void enterNumber(View view) { enterNumber(((Button)view).getText()); } @@ -297,13 +301,6 @@ public void backToSettings(View view) { startActivity(intent); } - - - private void startMainActivity() { - Intent intent = new Intent(this, CasesActivity.class); - startActivity(intent); - } - private boolean validateNumber(String number, boolean showSnackbar) { if (number.length() != 4) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/LoginActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/LoginActivity.java index 4a73a2a4213..54b8441e957 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/LoginActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/LoginActivity.java @@ -1,14 +1,10 @@ package de.symeda.sormas.app; -import android.Manifest; import android.accounts.AuthenticatorException; -import android.app.Activity; -import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; -import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.EditText; @@ -16,6 +12,7 @@ import java.net.ConnectException; import de.symeda.sormas.app.backend.config.ConfigProvider; +import de.symeda.sormas.app.caze.CasesActivity; import de.symeda.sormas.app.rest.RetroProvider; import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.settings.SettingsActivity; @@ -42,7 +39,7 @@ protected void onCreate(Bundle savedInstanceState) { protected void onResume() { super.onResume(); - if (hasGPSTurnedOnAndPermissionGranted()) { + if (LocationService.instance().validateGpsAccessAndEnabled(this)) { processLogin(); } } @@ -80,7 +77,7 @@ public void login(View view) { public void call(boolean syncFailed, String syncFailedMessage) { // logged in? if (ConfigProvider.getUser() != null) { - Intent intent = new Intent(LoginActivity.this, EnterPinActivity.class); + Intent intent = new Intent(LoginActivity.this, CasesActivity.class); startActivity(intent); } } @@ -96,92 +93,12 @@ public void showSettingsView(View view) { @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - if (hasGPSTurnedOnAndPermissionGranted()) { + if (LocationService.instance().validateGpsAccessAndEnabled(this)) { processLogin(); } } - private boolean hasGPSTurnedOnAndPermissionGranted() { - LocationService locationService = LocationService.getLocationService(this); - if (!locationService.hasGPSAccess(this)) { - AlertDialog requestPermissionDialog = buildRequestPermissionDialog(); - requestPermissionDialog.show(); - return false; - } - - if (!locationService.hasGPSEnabled()) { - AlertDialog turnOnGPSDialog = buildTurnOnGPSDialog(); - turnOnGPSDialog.show(); - return false; - } - - return true; - } - - private AlertDialog buildRequestPermissionDialog() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setCancelable(false); - builder.setMessage(R.string.alert_gps_permission); - builder.setTitle(R.string.alert_title_gps_permission); - builder.setIcon(R.drawable.ic_perm_device_information_black_24dp); - AlertDialog dialog = builder.create(); - dialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.action_close_app), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Activity finishActivity = LoginActivity.this; - do { - finishActivity.finish(); - finishActivity = finishActivity.getParent(); - } while (finishActivity != null); - } - } - ); - dialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.action_allow_gps_access), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ActivityCompat.requestPermissions(LoginActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 9999); - } - } - ); - - return dialog; - } - - private AlertDialog buildTurnOnGPSDialog() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setCancelable(false); - builder.setMessage(R.string.alert_gps); - builder.setTitle(R.string.alert_title_gps); - builder.setIcon(R.drawable.ic_location_on_black_24dp); - AlertDialog dialog = builder.create(); - dialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.action_close_app), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Activity finishActivity = LoginActivity.this; - do { - finishActivity.finish(); - finishActivity = finishActivity.getParent(); - } while (finishActivity != null); - } - } - ); - dialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.action_turn_on_gps), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Intent gpsOptionsIntent = new Intent( - android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); - startActivity(gpsOptionsIntent); - } - } - ); - - return dialog; - } private void processLogin() { // try to connect -> validates login data @@ -207,14 +124,14 @@ private void processLogin() { @Override public void call(boolean syncFailed, String syncFailedMessage) { if (ConfigProvider.getUser() != null) { - Intent intent = new Intent(LoginActivity.this, EnterPinActivity.class); + Intent intent = new Intent(LoginActivity.this, CasesActivity.class); startActivity(intent); } } }); } else { - Intent intent = new Intent(LoginActivity.this, EnterPinActivity.class); + Intent intent = new Intent(LoginActivity.this, CasesActivity.class); startActivity(intent); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/SormasApplication.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/SormasApplication.java index c7180de79c7..e4757c266c2 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/SormasApplication.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/SormasApplication.java @@ -1,8 +1,10 @@ package de.symeda.sormas.app; +import android.app.Activity; import android.app.Application; import android.content.Context; import android.location.Location; +import android.os.Bundle; import android.util.Log; import com.google.android.gms.analytics.ExceptionReporter; @@ -18,7 +20,7 @@ /** * Created by Martin Wahnschaffe on 22.07.2016. */ -public class SormasApplication extends Application { +public class SormasApplication extends Application implements Application.ActivityLifecycleCallbacks { private static final String PROPERTY_ID = "UA-98128295-1"; @@ -32,6 +34,10 @@ synchronized public Tracker getDefaultTracker() { public void onCreate() { DatabaseHelper.init(this); ConfigProvider.init(this); + LocationService.init(this); + + // Make sure the Enter Pin Activity is shown when the app has just started + ConfigProvider.setAccessGranted(false); TaskNotificationService.startTaskNotificationAlarm(this); @@ -47,6 +53,42 @@ public void onCreate() { reporter.setExceptionParser(new UncaughtExceptionParser()); super.onCreate(); + + this.registerActivityLifecycleCallbacks(this); + } + + @Override + public void onActivityCreated(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityStarted(Activity activity) { + LocationService.instance().requestActiveLocationUpdates(activity); } + @Override + public void onActivityResumed(Activity activity) { + + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + LocationService.instance().removeActiveLocationUpdates(); + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java index 08dbeeb1ab8..cb46a4c033c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java @@ -117,6 +117,9 @@ public class Case extends AbstractDomainObject { @Enumerated(EnumType.STRING) private VaccinationInfoSource yellowFeverVaccinationInfoSource; + @Enumerated(EnumType.STRING) + private YesNoUnknown smallpoxVaccinationScar; + @Column(length=512) private String epidNumber; @@ -127,13 +130,15 @@ public class Case extends AbstractDomainObject { private EpiData epiData; @Column + @Deprecated private Long contactOfficer_id; - @Column(columnDefinition = "float8") - private Float reportLat; - - @Column(columnDefinition = "float8") - private Float reportLon; + @DatabaseField + private Double reportLat; + @DatabaseField + private Double reportLon; + @DatabaseField + private Float reportLatLonAccuracy; public Person getPerson() { return person; @@ -303,6 +308,14 @@ public void setYellowFeverVaccinationInfoSource(VaccinationInfoSource yellowFeve this.yellowFeverVaccinationInfoSource = yellowFeverVaccinationInfoSource; } + public YesNoUnknown getSmallpoxVaccinationScar() { + return smallpoxVaccinationScar; + } + + public void setSmallpoxVaccinationScar(YesNoUnknown smallpoxVaccinationScar) { + this.smallpoxVaccinationScar = smallpoxVaccinationScar; + } + public String getEpidNumber() { return epidNumber; } @@ -327,19 +340,19 @@ public void setEpiData(EpiData epiData) { this.epiData = epiData; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } @@ -365,4 +378,11 @@ public String getI18nPrefix() { return I18N_PREFIX; } + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java index 59239973cb4..9a60815e3b1 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java @@ -226,17 +226,18 @@ public int getNumberOfCasesForEpiWeekAndDisease(EpiWeek epiWeek, Disease disease WeeklyReport previousEpiWeekReport = DatabaseHelper.getWeeklyReportDao().queryForEpiWeek(DateHelper.getPreviousEpiWeek(epiWeek), informant); WeeklyReport nextEpiWeekReport = DatabaseHelper.getWeeklyReportDao().queryForEpiWeek(DateHelper.getNextEpiWeek(epiWeek), informant); - Date[] dates = DateHelper.calculateEpiWeekReportStartAndEnd(epiWeek, epiWeekReport != null ? epiWeekReport.getReportDateTime() : null, + Date[] reportStartAndEnd = DateHelper.calculateEpiWeekReportStartAndEnd(new Date(), epiWeek, + epiWeekReport != null ? epiWeekReport.getReportDateTime() : null, previousEpiWeekReport != null ? previousEpiWeekReport.getReportDateTime() : null, - nextEpiWeekReport != null ? nextEpiWeekReport.getReportDateTime() : null); + nextEpiWeekReport != null? nextEpiWeekReport.getReportDateTime() : null); try { QueryBuilder builder = queryBuilder(); Where where = builder.where(); where.and( where.eq(Case.REPORTING_USER + "_id", informant), - where.ge(Case.REPORT_DATE, dates[0]), - where.le(Case.REPORT_DATE, dates[1]) + where.ge(Case.REPORT_DATE, reportStartAndEnd[0]), + where.le(Case.REPORT_DATE, reportStartAndEnd[1]) ); if (disease != null) { @@ -294,14 +295,11 @@ public Case mergeOrCreate(Case source) throws DaoException { public Case saveAndSnapshot(final Case caze) throws DaoException { // If a new case is created, use the last available location to update its report latitude and longitude if (caze.getId() == null) { - LocationService locationService = LocationService.getLocationService(DatabaseHelper.getContext()); - Location location = locationService.getLocation(); + Location location = LocationService.instance().getLocation(); if (location != null) { - // Use the geo-coordinates of the current location object if it's not older than 15 minutes - if (new Date().getTime() <= location.getTime() + (1000 * 60 * 15)) { - caze.setReportLat((float) location.getLatitude()); - caze.setReportLon((float) location.getLongitude()); - } + caze.setReportLat(location.getLatitude()); + caze.setReportLon(location.getLongitude()); + caze.setReportLatLonAccuracy(location.getAccuracy()); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDtoHelper.java index 5beabd2b882..065010e471f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDtoHelper.java @@ -101,10 +101,12 @@ public void fillInnerFromDto(Case target, CaseDataDto source) { target.setMeaslesVaccinationInfoSource(source.getMeaslesVaccinationInfoSource()); target.setYellowFeverVaccination(source.getYellowFeverVaccination()); target.setYellowFeverVaccinationInfoSource(source.getYellowFeverVaccinationInfoSource()); + target.setSmallpoxVaccinationScar(source.getSmallpoxVaccinationScar()); target.setEpidNumber(source.getEpidNumber()); target.setReportLat(source.getReportLat()); target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } @Override @@ -195,10 +197,12 @@ public void fillInnerFromAdo(CaseDataDto target, Case source) { target.setMeaslesVaccinationInfoSource(source.getMeaslesVaccinationInfoSource()); target.setYellowFeverVaccination(source.getYellowFeverVaccination()); target.setYellowFeverVaccinationInfoSource(source.getYellowFeverVaccinationInfoSource()); + target.setSmallpoxVaccinationScar(source.getSmallpoxVaccinationScar()); target.setEpidNumber(source.getEpidNumber()); target.setReportLat(source.getReportLat()); target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } public static CaseReferenceDto toReferenceDto(Case ado) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java index a3b07923c9b..069e9eb7cd9 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java @@ -73,10 +73,10 @@ */ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { - // name of the database file for your application -- change to something appropriate for your app + // name of the database file for your application. Stored in data/data/de.symeda.sormas.app/databases private static final String DATABASE_NAME = "sormas.db"; // any time you make changes to your database objects, you may have to increase the database version - private static final int DATABASE_VERSION = 108; + private static final int DATABASE_VERSION = 110; private static DatabaseHelper instance = null; public static void init(Context context) { @@ -320,6 +320,48 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int currentVersion = 107; getDao(Case.class).executeRaw("ALTER TABLE cases ADD COLUMN diseaseDetails varchar(512);"); getDao(Event.class).executeRaw("ALTER TABLE events ADD COLUMN diseaseDetails varchar(512);"); + case 108: + currentVersion = 108; + getDao(Location.class).executeRaw("ALTER TABLE location ADD COLUMN latLonAccuracy real;"); + getDao(Case.class).executeRaw("ALTER TABLE cases ADD COLUMN reportLatLonAccuracy real;"); + getDao(Contact.class).executeRaw("ALTER TABLE contacts ADD COLUMN reportLatLonAccuracy real;"); + getDao(Event.class).executeRaw("ALTER TABLE events ADD COLUMN reportLatLonAccuracy real;"); + getDao(Visit.class).executeRaw("ALTER TABLE visits ADD COLUMN reportLatLonAccuracy real;"); + getDao(Task.class).executeRaw("ALTER TABLE tasks ADD COLUMN closedLatLonAccuracy real;"); + getDao(Sample.class).executeRaw("ALTER TABLE samples ADD COLUMN reportLat double precision;"); + getDao(Sample.class).executeRaw("ALTER TABLE samples ADD COLUMN reportLon double precision;"); + getDao(Sample.class).executeRaw("ALTER TABLE samples ADD COLUMN reportLatLonAccuracy real;"); + case 109: + currentVersion = 109; + getDao(Case.class).executeRaw("ALTER TABLE cases ADD COLUMN smallpoxVaccinationScar varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN cutaneousEruption varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesions varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsSameState varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsSameSize varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsDeepProfound varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsFace boolean;"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsLegs boolean;"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsSolesFeet boolean;"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsPalmsHands boolean;"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsThorax boolean;"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsArms boolean;"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsGenitals boolean;"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsAllOverBody boolean;"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsResembleImg1 varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsResembleImg2 varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsResembleImg3 varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsResembleImg4 varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lymphadenopathyInguinal varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lymphadenopathyAxillary varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lymphadenopathyCervical varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN chillsSweats varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN lesionsThatItch varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN bedridden varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN oralUlcers varchar(255);"); + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN patientIllLocation varchar(512);"); + getDao(EpiData.class).executeRaw("ALTER TABLE epidata ADD COLUMN dateOfLastExposure timestamp;"); + getDao(EpiData.class).executeRaw("ALTER TABLE epidata ADD COLUMN placeOfLastExposure varchar(512);"); + getDao(EpiData.class).executeRaw("ALTER TABLE epidata ADD COLUMN animalCondition varchar(255);"); // ATTENTION: break should only be done after last version break; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/config/ConfigProvider.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/config/ConfigProvider.java index 9f6d90961df..3f9d33a0a6e 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/config/ConfigProvider.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/config/ConfigProvider.java @@ -50,6 +50,7 @@ public final class ConfigProvider { private static String KEY_PASSWORD = "password"; private static String KEY_PIN = "pin"; private static String KEY_SERVER_REST_URL = "serverRestUrl"; + private static String KEY_ACCESS_GRANTED = "accessGranted"; private static String LAST_NOTIFICATION_DATE = "lastNotificationDate"; public static ConfigProvider instance = null; @@ -69,6 +70,7 @@ public static void init(Context context) { private String pin; private User user; private Date lastNotificationDate; + private Boolean accessGranted; private ConfigProvider(Context context) { this.context = context; @@ -403,4 +405,30 @@ public static void setLastNotificationDate(Date lastNotificationDate) { DatabaseHelper.getConfigDao().createOrUpdate(new Config(LAST_NOTIFICATION_DATE, String.valueOf(lastNotificationDate.getTime()))); } } + + public static Boolean isAccessGranted() { + if (instance.accessGranted == null) { + Config config = DatabaseHelper.getConfigDao().queryForId(KEY_ACCESS_GRANTED); + if (config != null) { + instance.accessGranted = Boolean.parseBoolean(config.getValue()); + } + } + return instance.accessGranted; + } + + public static void setAccessGranted(Boolean accessGranted) { + if (accessGranted == null) { + throw new NullPointerException("accessGranted"); + } + + if (accessGranted.equals(instance.accessGranted)) { + return; + } + + instance.accessGranted = accessGranted; + + DatabaseHelper.getConfigDao().createOrUpdate(new Config(KEY_ACCESS_GRANTED, String.valueOf(accessGranted))); + } + + } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/Contact.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/Contact.java index d3bcf6247e8..3a5d05c5fa7 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/Contact.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/Contact.java @@ -1,8 +1,5 @@ package de.symeda.sormas.app.backend.contact; -import android.support.annotation.Nullable; - -import com.googlecode.openbeans.PropertyDescriptor; import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @@ -86,11 +83,12 @@ public class Contact extends AbstractDomainObject { @Enumerated(EnumType.STRING) private ContactRelation relationToCase; - @Column(columnDefinition = "float8") - private Float reportLat; - - @Column(columnDefinition = "float8") - private Float reportLon; + @DatabaseField + private Double reportLat; + @DatabaseField + private Double reportLon; + @DatabaseField + private Float reportLatLonAccuracy; public Person getPerson() { return person; @@ -185,19 +183,19 @@ public void setRelationToCase(ContactRelation relationToCase) { this.relationToCase = relationToCase; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } @@ -222,4 +220,12 @@ public boolean isUnreadOrChildUnread() { public String getI18nPrefix() { return I18N_PREFIX; } + + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java index 59ff7c8e4e1..ee14ac0f000 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java @@ -76,14 +76,11 @@ public void markAsRead(Contact contact) { public Contact saveAndSnapshot(final Contact contact) throws DaoException { // If a new contact is created, use the last available location to update its report latitude and longitude if (contact.getId() == null) { - LocationService locationService = LocationService.getLocationService(DatabaseHelper.getContext()); - Location location = locationService.getLocation(); + Location location = LocationService.instance().getLocation(); if (location != null) { - // Use the geo-coordinates of the current location object if it's not older than 15 minutes - if (new Date().getTime() <= location.getTime() + (1000 * 60 * 15)) { - contact.setReportLat((float) location.getLatitude()); - contact.setReportLon((float) location.getLongitude()); - } + contact.setReportLat(location.getLatitude()); + contact.setReportLon(location.getLongitude()); + contact.setReportLatLonAccuracy(location.getAccuracy()); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDtoHelper.java index 1beab238d17..4d5011a6cbd 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDtoHelper.java @@ -72,49 +72,51 @@ public void fillInnerFromDto(Contact target, ContactDto source) { target.setReportLat(source.getReportLat()); target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } @Override - public void fillInnerFromAdo(ContactDto dto, Contact ado) { + public void fillInnerFromAdo(ContactDto target, Contact source) { - if (ado.getPerson() != null) { - Person person = DatabaseHelper.getPersonDao().queryForId(ado.getPerson().getId()); - dto.setPerson(PersonDtoHelper.toReferenceDto(person)); + if (source.getPerson() != null) { + Person person = DatabaseHelper.getPersonDao().queryForId(source.getPerson().getId()); + target.setPerson(PersonDtoHelper.toReferenceDto(person)); } else { - dto.setPerson(null); + target.setPerson(null); } - if (ado.getCaze() != null) { - Case caze = DatabaseHelper.getCaseDao().queryForId(ado.getCaze().getId()); - dto.setCaze(CaseDtoHelper.toReferenceDto(caze)); + if (source.getCaze() != null) { + Case caze = DatabaseHelper.getCaseDao().queryForId(source.getCaze().getId()); + target.setCaze(CaseDtoHelper.toReferenceDto(caze)); } else { - dto.setCaze(null); + target.setCaze(null); } - if (ado.getReportingUser() != null) { - User user = DatabaseHelper.getUserDao().queryForId(ado.getReportingUser().getId()); - dto.setReportingUser(UserDtoHelper.toReferenceDto(user)); + if (source.getReportingUser() != null) { + User user = DatabaseHelper.getUserDao().queryForId(source.getReportingUser().getId()); + target.setReportingUser(UserDtoHelper.toReferenceDto(user)); } else { - dto.setReportingUser(null); + target.setReportingUser(null); } - dto.setReportDateTime(ado.getReportDateTime()); - - dto.setLastContactDate(ado.getLastContactDate()); - dto.setContactProximity(ado.getContactProximity()); - dto.setContactClassification(ado.getContactClassification()); - dto.setRelationToCase(ado.getRelationToCase()); - dto.setFollowUpStatus(ado.getFollowUpStatus()); - dto.setFollowUpComment(ado.getFollowUpComment()); - dto.setFollowUpUntil(ado.getFollowUpUntil()); - if (ado.getContactOfficer() != null) { - User user = DatabaseHelper.getUserDao().queryForId(ado.getContactOfficer().getId()); - dto.setContactOfficer(UserDtoHelper.toReferenceDto(user)); + target.setReportDateTime(source.getReportDateTime()); + + target.setLastContactDate(source.getLastContactDate()); + target.setContactProximity(source.getContactProximity()); + target.setContactClassification(source.getContactClassification()); + target.setRelationToCase(source.getRelationToCase()); + target.setFollowUpStatus(source.getFollowUpStatus()); + target.setFollowUpComment(source.getFollowUpComment()); + target.setFollowUpUntil(source.getFollowUpUntil()); + if (source.getContactOfficer() != null) { + User user = DatabaseHelper.getUserDao().queryForId(source.getContactOfficer().getId()); + target.setContactOfficer(UserDtoHelper.toReferenceDto(user)); } else { - dto.setContactOfficer(null); + target.setContactOfficer(null); } - dto.setDescription(ado.getDescription()); + target.setDescription(source.getDescription()); - dto.setReportLat(ado.getReportLat()); - dto.setReportLon(ado.getReportLon()); + target.setReportLat(source.getReportLat()); + target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } public static ContactReferenceDto toReferenceDto(Contact ado) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/epidata/EpiData.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/epidata/EpiData.java index 00069d47e7b..51bd83ace06 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/epidata/EpiData.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/epidata/EpiData.java @@ -13,6 +13,7 @@ import javax.persistence.EnumType; import javax.persistence.Enumerated; +import de.symeda.sormas.api.epidata.AnimalCondition; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.api.epidata.WaterSource; @@ -114,6 +115,15 @@ public class EpiData extends AbstractDomainObject { @Enumerated(EnumType.STRING) private YesNoUnknown tickBite; + @DatabaseField(dataType = DataType.DATE_LONG) + private Date dateOfLastExposure; + + @Column(length=512) + private String placeOfLastExposure; + + @Enumerated(EnumType.STRING) + private AnimalCondition animalCondition; + // just for reference, not persisted in DB private List burials = new ArrayList<>(); private List gatherings = new ArrayList<>(); @@ -335,6 +345,30 @@ public void setTickBite(YesNoUnknown tickBite) { this.tickBite = tickBite; } + public Date getDateOfLastExposure() { + return dateOfLastExposure; + } + + public void setDateOfLastExposure(Date dateOfLastExposure) { + this.dateOfLastExposure = dateOfLastExposure; + } + + public String getPlaceOfLastExposure() { + return placeOfLastExposure; + } + + public void setPlaceOfLastExposure(String placeOfLastExposure) { + this.placeOfLastExposure = placeOfLastExposure; + } + + public AnimalCondition getAnimalCondition() { + return animalCondition; + } + + public void setAnimalCondition(AnimalCondition animalCondition) { + this.animalCondition = animalCondition; + } + public List getBurials() { return burials; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/epidata/EpiDataDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/epidata/EpiDataDtoHelper.java index 94e20dd6d25..235d6fa345d 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/epidata/EpiDataDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/epidata/EpiDataDtoHelper.java @@ -80,6 +80,9 @@ public void fillInnerFromDto(EpiData a, EpiDataDto b) { a.setWaterBody(b.getWaterBody()); a.setWaterBodyDetails(b.getWaterBodyDetails()); a.setTickBite(b.getTickBite()); + a.setDateOfLastExposure(b.getDateOfLastExposure()); + a.setPlaceOfLastExposure(b.getPlaceOfLastExposure()); + a.setAnimalCondition(b.getAnimalCondition()); // just recreate all of this and throw the old stuff away List burials = new ArrayList<>(); @@ -144,6 +147,9 @@ public void fillInnerFromAdo(EpiDataDto a, EpiData b) { a.setWaterBody(b.getWaterBody()); a.setWaterBodyDetails(b.getWaterBodyDetails()); a.setTickBite(b.getTickBite()); + a.setDateOfLastExposure(b.getDateOfLastExposure()); + a.setPlaceOfLastExposure(b.getPlaceOfLastExposure()); + a.setAnimalCondition(b.getAnimalCondition()); List burialDtos = new ArrayList<>(); if (!b.getBurials().isEmpty()) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/Event.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/Event.java index 069401cb5b8..d1ab55e9090 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/Event.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/Event.java @@ -98,11 +98,13 @@ public class Event extends AbstractDomainObject { @Column(length=512) private String typeOfPlaceText; - @Column(columnDefinition = "float8") - private Float reportLat; + @DatabaseField + private Double reportLat; + @DatabaseField + private Double reportLon; + @DatabaseField + private Float reportLatLonAccuracy; - @Column(columnDefinition = "float8") - private Float reportLon; public EventType getEventType() { return eventType; @@ -219,19 +221,19 @@ public void setTypeOfPlaceText(String typeOfPlaceText) { this.typeOfPlaceText = typeOfPlaceText; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } @@ -246,4 +248,12 @@ public String toString() { public String getI18nPrefix() { return I18N_PREFIX; } + + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java index ca3385ec19b..cba5b05e6b3 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java @@ -61,14 +61,11 @@ public Event build() { public Event saveAndSnapshot(final Event event) throws DaoException { // If a new event is created, use the last available location to update its report latitude and longitude if (event.getId() == null) { - LocationService locationService = LocationService.getLocationService(DatabaseHelper.getContext()); - android.location.Location location = locationService.getLocation(); + android.location.Location location = LocationService.instance().getLocation(); if (location != null) { - // Use the geo-coordinates of the current location object if it's not older than 15 minutes - if (new Date().getTime() <= location.getTime() + (1000 * 60 * 15)) { - event.setReportLat((float) location.getLatitude()); - event.setReportLon((float) location.getLongitude()); - } + event.setReportLat(location.getLatitude()); + event.setReportLon(location.getLongitude()); + event.setReportLatLonAccuracy(location.getAccuracy()); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDtoHelper.java index f690c42ba5d..99d57c4374f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDtoHelper.java @@ -70,50 +70,52 @@ public void fillInnerFromDto(Event target, EventDto source) { target.setReportLat(source.getReportLat()); target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } @Override - public void fillInnerFromAdo(EventDto dto, Event ado) { + public void fillInnerFromAdo(EventDto target, Event source) { - dto.setEventType(ado.getEventType()); - dto.setEventStatus(ado.getEventStatus()); - dto.setEventDesc(ado.getEventDesc()); - dto.setEventDate(ado.getEventDate()); - dto.setReportDateTime(ado.getReportDateTime()); + target.setEventType(source.getEventType()); + target.setEventStatus(source.getEventStatus()); + target.setEventDesc(source.getEventDesc()); + target.setEventDate(source.getEventDate()); + target.setReportDateTime(source.getReportDateTime()); - if (ado.getReportingUser() != null) { - User user = DatabaseHelper.getUserDao().queryForId(ado.getReportingUser().getId()); - dto.setReportingUser(UserDtoHelper.toReferenceDto(user)); + if (source.getReportingUser() != null) { + User user = DatabaseHelper.getUserDao().queryForId(source.getReportingUser().getId()); + target.setReportingUser(UserDtoHelper.toReferenceDto(user)); } else { - dto.setReportingUser(null); + target.setReportingUser(null); } - if (ado.getEventLocation() != null) { - Location location = DatabaseHelper.getLocationDao().queryForId(ado.getEventLocation().getId()); - dto.setEventLocation(locationHelper.adoToDto(location)); + if (source.getEventLocation() != null) { + Location location = DatabaseHelper.getLocationDao().queryForId(source.getEventLocation().getId()); + target.setEventLocation(locationHelper.adoToDto(location)); } else { - dto.setEventLocation(null); + target.setEventLocation(null); } - dto.setTypeOfPlace(ado.getTypeOfPlace()); - dto.setSrcFirstName(ado.getSrcFirstName()); - dto.setSrcLastName(ado.getSrcLastName()); - dto.setSrcTelNo(ado.getSrcTelNo()); - dto.setSrcEmail(ado.getSrcEmail()); - dto.setDisease(ado.getDisease()); - dto.setDiseaseDetails(ado.getDiseaseDetails()); - - if (ado.getSurveillanceOfficer() != null) { - User user = DatabaseHelper.getUserDao().queryForId(ado.getSurveillanceOfficer().getId()); - dto.setSurveillanceOfficer(UserDtoHelper.toReferenceDto(user)); + target.setTypeOfPlace(source.getTypeOfPlace()); + target.setSrcFirstName(source.getSrcFirstName()); + target.setSrcLastName(source.getSrcLastName()); + target.setSrcTelNo(source.getSrcTelNo()); + target.setSrcEmail(source.getSrcEmail()); + target.setDisease(source.getDisease()); + target.setDiseaseDetails(source.getDiseaseDetails()); + + if (source.getSurveillanceOfficer() != null) { + User user = DatabaseHelper.getUserDao().queryForId(source.getSurveillanceOfficer().getId()); + target.setSurveillanceOfficer(UserDtoHelper.toReferenceDto(user)); } else { - dto.setSurveillanceOfficer(null); + target.setSurveillanceOfficer(null); } - dto.setTypeOfPlaceText(ado.getTypeOfPlaceText()); + target.setTypeOfPlaceText(source.getTypeOfPlaceText()); - dto.setReportLat(ado.getReportLat()); - dto.setReportLon(ado.getReportLon()); + target.setReportLat(source.getReportLat()); + target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } public static EventReferenceDto toReferenceDto(Event ado) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/facility/Facility.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/facility/Facility.java index ffd16bea976..06cd74dae1b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/facility/Facility.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/facility/Facility.java @@ -44,10 +44,11 @@ public class Facility extends AbstractDomainObject { private Community community; @Column(length = 255) private String city; - @Column(columnDefinition = "float8") - private Float latitude; - @Column(columnDefinition = "float8") - private Float longitude; + + @DatabaseField + private Double latitude; + @DatabaseField + private Double longitude; @Enumerated(EnumType.STRING) private FacilityType type; @@ -90,17 +91,17 @@ public void setCommunity(Community community) { this.community = community; } - public Float getLatitude() { + public Double getLatitude() { return latitude; } - public void setLatitude(Float latitude) { + public void setLatitude(Double latitude) { this.latitude = latitude; } - public Float getLongitude() { + public Double getLongitude() { return longitude; } - public void setLongitude(Float longitude) { + public void setLongitude(Double longitude) { this.longitude = longitude; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/Location.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/Location.java index fa81ba87865..58e60a3d72e 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/Location.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/Location.java @@ -5,6 +5,8 @@ import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; +import java.text.NumberFormat; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.ManyToOne; @@ -41,10 +43,12 @@ public class Location extends AbstractDomainObject { @DatabaseField(foreign = true, foreignAutoRefresh = true) private Community community; - @Column(columnDefinition = "float8") - private Float latitude; - @Column(columnDefinition = "float8") - private Float longitude; + @DatabaseField + private Double latitude; + @DatabaseField + private Double longitude; + @DatabaseField + private Float latLonAccuracy; @Bindable public String getAddress() { @@ -91,22 +95,22 @@ public void setCommunity(Community community) { this.community = community; } - public Float getLatitude() { + public Double getLatitude() { return latitude; } - public void setLatitude(Float latitude) { + public void setLatitude(Double latitude) { this.latitude = latitude; } - public Float getLongitude() { + public Double getLongitude() { return longitude; } - public void setLongitude(Float longitude) { + public void setLongitude(Double longitude) { this.longitude = longitude; } - @Override - public String toString() { + public String getCompleteString() { + StringBuilder sb = new StringBuilder(); if (getAddress() != null && !getAddress().isEmpty()) { sb.append(getAddress()); @@ -134,13 +138,28 @@ public String toString() { } sb.append(getDetails()); } - if (sb.length() == 0) { - sb.append(super.toString()); + + if (getLatitude() != null && getLongitude() != null) { + if (sb.length() > 0) { + sb.append(" "); + } + sb.append("(").append(android.location.Location.convert(getLatitude(), android.location.Location.FORMAT_DEGREES)) + .append(", ").append(android.location.Location.convert(getLongitude(), android.location.Location.FORMAT_DEGREES)).append(")"); } return sb.toString(); } + @Override + public String toString() { + + String result = getCompleteString(); + if (!result.isEmpty()) { + return result; + } + return super.toString(); + } + public boolean isEmptyLocation() { return address == null && details == null && city == null && region == null && district == null && community == null; @@ -150,4 +169,12 @@ public boolean isEmptyLocation() { public String getI18nPrefix() { return I18N_PREFIX; } + + public Float getLatLonAccuracy() { + return latLonAccuracy; + } + + public void setLatLonAccuracy(Float latLonAccuracy) { + this.latLonAccuracy = latLonAccuracy; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/LocationDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/LocationDtoHelper.java index 23986075100..b8fc03b6a8e 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/LocationDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/LocationDtoHelper.java @@ -48,6 +48,7 @@ public void fillInnerFromDto(Location target, LocationDto source) { target.setDetails(source.getDetails()); target.setLatitude(source.getLatitude()); target.setLongitude(source.getLongitude()); + target.setLatLonAccuracy(source.getLatLonAccuracy()); target.setRegion(DatabaseHelper.getRegionDao().getByReferenceDto(source.getRegion())); target.setDistrict(DatabaseHelper.getDistrictDao().getByReferenceDto(source.getDistrict())); @@ -55,28 +56,29 @@ public void fillInnerFromDto(Location target, LocationDto source) { } @Override - public void fillInnerFromAdo(LocationDto dto, Location ado) { + public void fillInnerFromAdo(LocationDto target, Location source) { - dto.setAddress(ado.getAddress()); - dto.setCity(ado.getCity()); - dto.setDetails(ado.getDetails()); - dto.setLatitude(ado.getLatitude()); - dto.setLongitude(ado.getLongitude()); + target.setAddress(source.getAddress()); + target.setCity(source.getCity()); + target.setDetails(source.getDetails()); + target.setLatitude(source.getLatitude()); + target.setLongitude(source.getLongitude()); + target.setLatLonAccuracy(source.getLatLonAccuracy()); - if (ado.getCommunity() != null) { - dto.setCommunity(CommunityDtoHelper.toReferenceDto(DatabaseHelper.getCommunityDao().queryForId(ado.getCommunity().getId()))); + if (source.getCommunity() != null) { + target.setCommunity(CommunityDtoHelper.toReferenceDto(DatabaseHelper.getCommunityDao().queryForId(source.getCommunity().getId()))); } else { - dto.setCommunity(null); + target.setCommunity(null); } - if (ado.getDistrict() != null) { - dto.setDistrict(DistrictDtoHelper.toReferenceDto(DatabaseHelper.getDistrictDao().queryForId(ado.getDistrict().getId()))); + if (source.getDistrict() != null) { + target.setDistrict(DistrictDtoHelper.toReferenceDto(DatabaseHelper.getDistrictDao().queryForId(source.getDistrict().getId()))); } else { - dto.setDistrict(null); + target.setDistrict(null); } - if (ado.getRegion() != null) { - dto.setRegion(RegionDtoHelper.toReferenceDto(DatabaseHelper.getRegionDao().queryForId(ado.getRegion().getId()))); + if (source.getRegion() != null) { + target.setRegion(RegionDtoHelper.toReferenceDto(DatabaseHelper.getRegionDao().queryForId(source.getRegion().getId()))); } else { - dto.setRegion(null); + target.setRegion(null); } } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/Sample.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/Sample.java index ee5aeff9cbe..a05061e9af1 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/Sample.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/Sample.java @@ -58,6 +58,13 @@ public class Sample extends AbstractDomainObject { @DatabaseField(foreign = true, foreignAutoRefresh = true) private User reportingUser; + @DatabaseField + private Double reportLat; + @DatabaseField + private Double reportLon; + @DatabaseField + private Float reportLatLonAccuracy; + @Enumerated(EnumType.STRING) @Column(nullable = false) private SampleMaterial sampleMaterial; @@ -276,4 +283,28 @@ public String getI18nPrefix() { public String toString() { return super.toString() + DateHelper.formatShortDate(getSampleDateTime()); } + + public Double getReportLat() { + return reportLat; + } + + public void setReportLat(Double reportLat) { + this.reportLat = reportLat; + } + + public Double getReportLon() { + return reportLon; + } + + public void setReportLon(Double reportLon) { + this.reportLon = reportLon; + } + + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDtoHelper.java index 410fc86b28e..a8dc6bc8f7d 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDtoHelper.java @@ -73,54 +73,62 @@ public void fillInnerFromDto(Sample target, SampleDto source) { target.setReferredTo(DatabaseHelper.getSampleDao().getByReferenceDto(source.getReferredTo())); target.setShipped(source.isShipped()); target.setReceived(source.isReceived()); + + target.setReportLat(source.getReportLat()); + target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } @Override - public void fillInnerFromAdo(SampleDto dto, Sample ado) { - if(ado.getAssociatedCase() != null) { - Case associatedCase = DatabaseHelper.getCaseDao().queryForId(ado.getAssociatedCase().getId()); - dto.setAssociatedCase(CaseDtoHelper.toReferenceDto(associatedCase)); + public void fillInnerFromAdo(SampleDto target, Sample source) { + if(source.getAssociatedCase() != null) { + Case associatedCase = DatabaseHelper.getCaseDao().queryForId(source.getAssociatedCase().getId()); + target.setAssociatedCase(CaseDtoHelper.toReferenceDto(associatedCase)); } else { - dto.setAssociatedCase(null); + target.setAssociatedCase(null); } - if(ado.getReportingUser() != null) { - User user = DatabaseHelper.getUserDao().queryForId(ado.getReportingUser().getId()); - dto.setReportingUser(UserDtoHelper.toReferenceDto(user)); + if(source.getReportingUser() != null) { + User user = DatabaseHelper.getUserDao().queryForId(source.getReportingUser().getId()); + target.setReportingUser(UserDtoHelper.toReferenceDto(user)); } else { - dto.setReportingUser(null); + target.setReportingUser(null); } - if(ado.getLab() != null) { - Facility lab = DatabaseHelper.getFacilityDao().queryForId(ado.getLab().getId()); - dto.setLab(FacilityDtoHelper.toReferenceDto(lab)); + if(source.getLab() != null) { + Facility lab = DatabaseHelper.getFacilityDao().queryForId(source.getLab().getId()); + target.setLab(FacilityDtoHelper.toReferenceDto(lab)); } else { - dto.setLab(null); + target.setLab(null); } - if (ado.getReferredTo() != null) { - Sample referredSample = DatabaseHelper.getSampleDao().queryForId(ado.getReferredTo().getId()); - dto.setReferredTo(SampleDtoHelper.toReferenceDto(referredSample)); + if (source.getReferredTo() != null) { + Sample referredSample = DatabaseHelper.getSampleDao().queryForId(source.getReferredTo().getId()); + target.setReferredTo(SampleDtoHelper.toReferenceDto(referredSample)); } else { - dto.setReferredTo(null); + target.setReferredTo(null); } - dto.setSampleCode(ado.getSampleCode()); - dto.setLabSampleID(ado.getLabSampleID()); - dto.setSampleDateTime(ado.getSampleDateTime()); - dto.setReportDateTime(ado.getReportDateTime()); - dto.setSampleMaterial(ado.getSampleMaterial()); - dto.setSampleMaterialText(ado.getSampleMaterialText()); - dto.setShipmentDate(ado.getShipmentDate()); - dto.setShipmentDetails(ado.getShipmentDetails()); - dto.setReceivedDate(ado.getReceivedDate()); - dto.setSpecimenCondition(ado.getSpecimenCondition()); - dto.setNoTestPossibleReason(ado.getNoTestPossibleReason()); - dto.setComment(ado.getComment()); - dto.setSampleSource(ado.getSampleSource()); - dto.setSuggestedTypeOfTest(ado.getSuggestedTypeOfTest()); - dto.setShipped(ado.isShipped()); - dto.setReceived(ado.isReceived()); + target.setSampleCode(source.getSampleCode()); + target.setLabSampleID(source.getLabSampleID()); + target.setSampleDateTime(source.getSampleDateTime()); + target.setReportDateTime(source.getReportDateTime()); + target.setSampleMaterial(source.getSampleMaterial()); + target.setSampleMaterialText(source.getSampleMaterialText()); + target.setShipmentDate(source.getShipmentDate()); + target.setShipmentDetails(source.getShipmentDetails()); + target.setReceivedDate(source.getReceivedDate()); + target.setSpecimenCondition(source.getSpecimenCondition()); + target.setNoTestPossibleReason(source.getNoTestPossibleReason()); + target.setComment(source.getComment()); + target.setSampleSource(source.getSampleSource()); + target.setSuggestedTypeOfTest(source.getSuggestedTypeOfTest()); + target.setShipped(source.isShipped()); + target.setReceived(source.isReceived()); + + target.setReportLat(source.getReportLat()); + target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } public static SampleReferenceDto toReferenceDto(Sample ado) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/Symptoms.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/Symptoms.java index 233c27a50cd..7d7dde21559 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/Symptoms.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/Symptoms.java @@ -35,11 +35,16 @@ public class Symptoms extends AbstractDomainObject { private String symptomsComments; @DatabaseField private Boolean symptomatic; + @Column(length = 512) + private String patientIllLocation; - @DatabaseField(foreign = true, foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 2) - private Location illLocation; + @Deprecated + @DatabaseField(columnName = "illLocation_id") + private Long illLocationId; + @Deprecated @DatabaseField(dataType = DataType.DATE_LONG) private Date illLocationFrom; + @Deprecated @DatabaseField(dataType = DataType.DATE_LONG) private Date illLocationTo; @@ -145,7 +150,54 @@ public class Symptoms extends AbstractDomainObject { private SymptomState rapidBreathing; @Enumerated(EnumType.STRING) private SymptomState swollenGlands; - + @Enumerated(EnumType.STRING) + private SymptomState cutaneousEruption; + @Enumerated(EnumType.STRING) + private SymptomState lesions; + @Enumerated(EnumType.STRING) + private SymptomState lesionsThatItch; + @Enumerated(EnumType.STRING) + private SymptomState lesionsSameState; + @Enumerated(EnumType.STRING) + private SymptomState lesionsSameSize; + @Enumerated(EnumType.STRING) + private SymptomState lesionsDeepProfound; + @DatabaseField + private Boolean lesionsFace; + @DatabaseField + private Boolean lesionsLegs; + @DatabaseField + private Boolean lesionsSolesFeet; + @DatabaseField + private Boolean lesionsPalmsHands; + @DatabaseField + private Boolean lesionsThorax; + @DatabaseField + private Boolean lesionsArms; + @DatabaseField + private Boolean lesionsGenitals; + @DatabaseField + private Boolean lesionsAllOverBody; + @Enumerated(EnumType.STRING) + private SymptomState lesionsResembleImg1; + @Enumerated(EnumType.STRING) + private SymptomState lesionsResembleImg2; + @Enumerated(EnumType.STRING) + private SymptomState lesionsResembleImg3; + @Enumerated(EnumType.STRING) + private SymptomState lesionsResembleImg4; + @Enumerated(EnumType.STRING) + private SymptomState lymphadenopathyInguinal; + @Enumerated(EnumType.STRING) + private SymptomState lymphadenopathyAxillary; + @Enumerated(EnumType.STRING) + private SymptomState lymphadenopathyCervical; + @Enumerated(EnumType.STRING) + private SymptomState chillsSweats; + @Enumerated(EnumType.STRING) + private SymptomState bedridden; + @Enumerated(EnumType.STRING) + private SymptomState oralUlcers; @Enumerated(EnumType.STRING) private SymptomState otherHemorrhagicSymptoms; @Column(length = 255) @@ -177,30 +229,6 @@ public void setTemperatureSource(TemperatureSource temperatureSource) { this.temperatureSource = temperatureSource; } - public Location getIllLocation() { - return illLocation; - } - - public void setIllLocation(Location illLocation) { - this.illLocation = illLocation; - } - - public Date getIllLocationFrom() { - return illLocationFrom; - } - - public void setIllLocationFrom(Date illLocationFrom) { - this.illLocationFrom = illLocationFrom; - } - - public Date getIllLocationTo() { - return illLocationTo; - } - - public void setIllLocationTo(Date illLocationTo) { - this.illLocationTo = illLocationTo; - } - public SymptomState getFever() { return fever; } @@ -611,6 +639,206 @@ public void setSwollenGlands(SymptomState swollenGlands) { this.swollenGlands = swollenGlands; } + public SymptomState getCutaneousEruption() { + return cutaneousEruption; + } + + public void setCutaneousEruption(SymptomState cutaneousEruption) { + this.cutaneousEruption = cutaneousEruption; + } + + public SymptomState getLesions() { + return lesions; + } + + public void setLesions(SymptomState lesions) { + this.lesions = lesions; + } + + public SymptomState getLesionsThatItch() { + return lesionsThatItch; + } + + public void setLesionsThatItch(SymptomState lesionsThatItch) { + this.lesionsThatItch = lesionsThatItch; + } + + public SymptomState getLesionsSameState() { + return lesionsSameState; + } + + public void setLesionsSameState(SymptomState lesionsSameState) { + this.lesionsSameState = lesionsSameState; + } + + public SymptomState getLesionsSameSize() { + return lesionsSameSize; + } + + public void setLesionsSameSize(SymptomState lesionsSameSize) { + this.lesionsSameSize = lesionsSameSize; + } + + public SymptomState getLesionsDeepProfound() { + return lesionsDeepProfound; + } + + public void setLesionsDeepProfound(SymptomState lesionsDeepProfound) { + this.lesionsDeepProfound = lesionsDeepProfound; + } + + public Boolean getLesionsFace() { + return lesionsFace; + } + + public void setLesionsFace(Boolean lesionsFace) { + this.lesionsFace = lesionsFace; + } + + public Boolean getLesionsLegs() { + return lesionsLegs; + } + + public void setLesionsLegs(Boolean lesionsLegs) { + this.lesionsLegs = lesionsLegs; + } + + public Boolean getLesionsSolesFeet() { + return lesionsSolesFeet; + } + + public void setLesionsSolesFeet(Boolean lesionsSolesFeet) { + this.lesionsSolesFeet = lesionsSolesFeet; + } + + public Boolean getLesionsPalmsHands() { + return lesionsPalmsHands; + } + + public void setLesionsPalmsHands(Boolean lesionsPalmsHands) { + this.lesionsPalmsHands = lesionsPalmsHands; + } + + public Boolean getLesionsThorax() { + return lesionsThorax; + } + + public void setLesionsThorax(Boolean lesionsThorax) { + this.lesionsThorax = lesionsThorax; + } + + public Boolean getLesionsArms() { + return lesionsArms; + } + + public void setLesionsArms(Boolean lesionsArms) { + this.lesionsArms = lesionsArms; + } + + public Boolean getLesionsGenitals() { + return lesionsGenitals; + } + + public void setLesionsGenitals(Boolean lesionsGenitals) { + this.lesionsGenitals = lesionsGenitals; + } + + public Boolean getLesionsAllOverBody() { + return lesionsAllOverBody; + } + + public void setLesionsAllOverBody(Boolean lesionsAllOverBody) { + this.lesionsAllOverBody = lesionsAllOverBody; + } + + public SymptomState getLesionsResembleImg1() { + return lesionsResembleImg1; + } + + public void setLesionsResembleImg1(SymptomState lesionsResembleImg1) { + this.lesionsResembleImg1 = lesionsResembleImg1; + } + + public SymptomState getLesionsResembleImg2() { + return lesionsResembleImg2; + } + + public void setLesionsResembleImg2(SymptomState lesionsResembleImg2) { + this.lesionsResembleImg2 = lesionsResembleImg2; + } + + public SymptomState getLesionsResembleImg3() { + return lesionsResembleImg3; + } + + public void setLesionsResembleImg3(SymptomState lesionsResembleImg3) { + this.lesionsResembleImg3 = lesionsResembleImg3; + } + + public SymptomState getLesionsResembleImg4() { + return lesionsResembleImg4; + } + + public void setLesionsResembleImg4(SymptomState lesionsResembleImg4) { + this.lesionsResembleImg4 = lesionsResembleImg4; + } + + public SymptomState getLymphadenopathyInguinal() { + return lymphadenopathyInguinal; + } + + public void setLymphadenopathyInguinal(SymptomState lymphadenopathyInguinal) { + this.lymphadenopathyInguinal = lymphadenopathyInguinal; + } + + public SymptomState getLymphadenopathyAxillary() { + return lymphadenopathyAxillary; + } + + public void setLymphadenopathyAxillary(SymptomState lymphadenopathyAxillary) { + this.lymphadenopathyAxillary = lymphadenopathyAxillary; + } + + public SymptomState getLymphadenopathyCervical() { + return lymphadenopathyCervical; + } + + public void setLymphadenopathyCervical(SymptomState lymphadenopathyCervical) { + this.lymphadenopathyCervical = lymphadenopathyCervical; + } + + public SymptomState getChillsSweats() { + return chillsSweats; + } + + public void setChillsSweats(SymptomState chillsSweats) { + this.chillsSweats = chillsSweats; + } + + public SymptomState getBedridden() { + return bedridden; + } + + public void setBedridden(SymptomState bedridden) { + this.bedridden = bedridden; + } + + public SymptomState getOralUlcers() { + return oralUlcers; + } + + public void setOralUlcers(SymptomState oralUlcers) { + this.oralUlcers = oralUlcers; + } + + public String getPatientIllLocation() { + return patientIllLocation; + } + + public void setPatientIllLocation(String patientIllLocation) { + this.patientIllLocation = patientIllLocation; + } + @Override public String getI18nPrefix() { return I18N_PREFIX; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/SymptomsDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/SymptomsDtoHelper.java index f0fd2342341..7f6a6b26791 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/SymptomsDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/SymptomsDtoHelper.java @@ -96,9 +96,6 @@ public void fillInnerFromDto(Symptoms a, SymptomsDto b) { a.setThrobocytopenia(b.getThrobocytopenia()); a.setUnexplainedBleeding(b.getUnexplainedBleeding()); a.setVomiting(b.getVomiting()); - a.setIllLocation(locationHelper.fillOrCreateFromDto(a.getIllLocation(), b.getIllLocation())); - a.setIllLocationFrom(b.getIllLocationFrom()); - a.setIllLocationTo(b.getIllLocationTo()); a.setBackache(b.getBackache()); a.setEyesBleeding(b.getEyesBleeding()); a.setJaundice(b.getJaundice()); @@ -106,6 +103,31 @@ public void fillInnerFromDto(Symptoms a, SymptomsDto b) { a.setStomachBleeding(b.getStomachBleeding()); a.setRapidBreathing(b.getRapidBreathing()); a.setSwollenGlands(b.getSwollenGlands()); + a.setCutaneousEruption(b.getCutaneousEruption()); + a.setLesions(b.getLesions()); + a.setLesionsSameState(b.getLesionsSameState()); + a.setLesionsSameSize(b.getLesionsSameSize()); + a.setLesionsDeepProfound(b.getLesionsDeepProfound()); + a.setLesionsThatItch(b.getLesionsThatItch()); + a.setLesionsFace(b.getLesionsFace()); + a.setLesionsLegs(b.getLesionsLegs()); + a.setLesionsSolesFeet(b.getLesionsSolesFeet()); + a.setLesionsPalmsHands(b.getLesionsPalmsHands()); + a.setLesionsThorax(b.getLesionsThorax()); + a.setLesionsArms(b.getLesionsArms()); + a.setLesionsGenitals(b.getLesionsGenitals()); + a.setLesionsAllOverBody(b.getLesionsAllOverBody()); + a.setLesionsResembleImg1(b.getLesionsResembleImg1()); + a.setLesionsResembleImg2(b.getLesionsResembleImg2()); + a.setLesionsResembleImg3(b.getLesionsResembleImg3()); + a.setLesionsResembleImg4(b.getLesionsResembleImg4()); + a.setLymphadenopathyAxillary(b.getLymphadenopathyAxillary()); + a.setLymphadenopathyCervical(b.getLymphadenopathyCervical()); + a.setLymphadenopathyInguinal(b.getLymphadenopathyInguinal()); + a.setChillsSweats(b.getChillsSweats()); + a.setBedridden(b.getBedridden()); + a.setOralUlcers(b.getOralUlcers()); + a.setPatientIllLocation(b.getPatientIllLocation()); } @Override @@ -162,10 +184,6 @@ public void fillInnerFromAdo(SymptomsDto a, Symptoms b) { a.setThrobocytopenia(b.getThrobocytopenia()); a.setUnexplainedBleeding(b.getUnexplainedBleeding()); a.setVomiting(b.getVomiting()); - Location location = DatabaseHelper.getLocationDao().queryForId(b.getIllLocation().getId()); - a.setIllLocation(locationHelper.adoToDto(location)); - a.setIllLocationFrom(b.getIllLocationFrom()); - a.setIllLocationTo(b.getIllLocationTo()); a.setBackache(b.getBackache()); a.setEyesBleeding(b.getEyesBleeding()); a.setJaundice(b.getJaundice()); @@ -173,5 +191,30 @@ public void fillInnerFromAdo(SymptomsDto a, Symptoms b) { a.setStomachBleeding(b.getStomachBleeding()); a.setRapidBreathing(b.getRapidBreathing()); a.setSwollenGlands(b.getSwollenGlands()); + a.setCutaneousEruption(b.getCutaneousEruption()); + a.setLesions(b.getLesions()); + a.setLesionsSameState(b.getLesionsSameState()); + a.setLesionsSameSize(b.getLesionsSameSize()); + a.setLesionsDeepProfound(b.getLesionsDeepProfound()); + a.setLesionsThatItch(b.getLesionsThatItch()); + a.setLesionsFace(b.getLesionsFace()); + a.setLesionsLegs(b.getLesionsLegs()); + a.setLesionsSolesFeet(b.getLesionsSolesFeet()); + a.setLesionsPalmsHands(b.getLesionsPalmsHands()); + a.setLesionsThorax(b.getLesionsThorax()); + a.setLesionsArms(b.getLesionsArms()); + a.setLesionsGenitals(b.getLesionsGenitals()); + a.setLesionsAllOverBody(b.getLesionsAllOverBody()); + a.setLesionsResembleImg1(b.getLesionsResembleImg1()); + a.setLesionsResembleImg2(b.getLesionsResembleImg2()); + a.setLesionsResembleImg3(b.getLesionsResembleImg3()); + a.setLesionsResembleImg4(b.getLesionsResembleImg4()); + a.setLymphadenopathyAxillary(b.getLymphadenopathyAxillary()); + a.setLymphadenopathyCervical(b.getLymphadenopathyCervical()); + a.setLymphadenopathyInguinal(b.getLymphadenopathyInguinal()); + a.setChillsSweats(b.getChillsSweats()); + a.setBedridden(b.getBedridden()); + a.setOralUlcers(b.getOralUlcers()); + a.setPatientIllLocation(b.getPatientIllLocation()); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/Task.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/Task.java index 3bc45b22d77..1a2bedc414e 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/Task.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/Task.java @@ -93,11 +93,12 @@ public class Task extends AbstractDomainObject { @Column(length=512) private String assigneeReply; - @Column(columnDefinition = "float8") - private Float closedLat; - - @Column(columnDefinition = "float8") - private Float closedLon; + @DatabaseField + private Double closedLat; + @DatabaseField + private Double closedLon; + @DatabaseField + private Float closedLatLonAccuracy; public TaskContext getTaskContext() { return taskContext; @@ -220,19 +221,19 @@ public void setSuggestedStart(Date suggestedStart) { this.suggestedStart = suggestedStart; } - public Float getClosedLat() { + public Double getClosedLat() { return closedLat; } - public void setClosedLat(Float closedLat) { + public void setClosedLat(Double closedLat) { this.closedLat = closedLat; } - public Float getClosedLon() { + public Double getClosedLon() { return closedLon; } - public void setClosedLon(Float closedLon) { + public void setClosedLon(Double closedLon) { this.closedLon = closedLon; } @@ -240,4 +241,12 @@ public void setClosedLon(Float closedLon) { public String getI18nPrefix() { return I18N_PREFIX; } + + public Float getClosedLatLonAccuracy() { + return closedLatLonAccuracy; + } + + public void setClosedLatLonAccuracy(Float closedLatLonAccuracy) { + this.closedLatLonAccuracy = closedLatLonAccuracy; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/TaskDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/TaskDao.java index 9c599bbb6e3..fe1c4860522 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/TaskDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/TaskDao.java @@ -46,14 +46,11 @@ public void changeTaskStatus(Task task, TaskStatus targetStatus) throws DaoExcep task.setTaskStatus(targetStatus); task.setStatusChangeDate(new Date()); - LocationService locationService = LocationService.getLocationService(DatabaseHelper.getContext()); - Location location = locationService.getLocation(); + Location location = LocationService.instance().getLocation(); if (location != null) { - // Use the geo-coordinates of the current location object if it's not older than 15 minutes - if (new Date().getTime() <= location.getTime() + (1000 * 60 * 15)) { - task.setClosedLat((float) location.getLatitude()); - task.setClosedLon((float) location.getLongitude()); - } + task.setClosedLat(location.getLatitude()); + task.setClosedLon(location.getLongitude()); + task.setClosedLatLonAccuracy(location.getAccuracy()); } saveAndSnapshot(task); @@ -65,6 +62,7 @@ public void changeTaskStatus(Task task, TaskStatus targetStatus) throws DaoExcep * 2. due date within range * 3. localChangeDate within range, not modified (-> has been updated on server) and suggested start before end of range * Ordered by priority, then due date - oldes (most due) first + * Typically, the range is the interval between two notification polls (e.g. 2 minutes) * @return */ public List queryMyPendingForNotification(Date rangeStart, Date rangeEnd) { @@ -86,6 +84,10 @@ public List queryMyPendingForNotification(Date rangeStart, Date rangeEnd) where.and( where.between(Task.LOCAL_CHANGE_DATE, rangeStart, rangeEnd), where.eq(Task.MODIFIED, false), + where.or( + where.raw(Task.LAST_OPENED_DATE + " < " + Task.LOCAL_CHANGE_DATE), + where.isNull(Task.LAST_OPENED_DATE) + ), where.le(Task.SUGGESTED_START, rangeEnd) ) ) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/TaskDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/TaskDtoHelper.java index aed6bd64d53..41ce253ac4b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/TaskDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/task/TaskDtoHelper.java @@ -67,54 +67,56 @@ public void fillInnerFromDto(Task target, TaskDto source) { target.setClosedLat(source.getClosedLat()); target.setClosedLon(source.getClosedLon()); + target.setClosedLatLonAccuracy(source.getClosedLatLonAccuracy()); } @Override - public void fillInnerFromAdo(TaskDto dto, Task ado) { + public void fillInnerFromAdo(TaskDto target, Task source) { - dto.setTaskContext(ado.getTaskContext()); - if (ado.getCaze() != null) { - Case caze = DatabaseHelper.getCaseDao().queryForId(ado.getCaze().getId()); - dto.setCaze(CaseDtoHelper.toReferenceDto(caze)); + target.setTaskContext(source.getTaskContext()); + if (source.getCaze() != null) { + Case caze = DatabaseHelper.getCaseDao().queryForId(source.getCaze().getId()); + target.setCaze(CaseDtoHelper.toReferenceDto(caze)); } else { - dto.setCaze(null); + target.setCaze(null); } - if (ado.getContact() != null) { - Contact contact = DatabaseHelper.getContactDao().queryForId(ado.getContact().getId()); - dto.setContact(ContactDtoHelper.toReferenceDto(contact)); + if (source.getContact() != null) { + Contact contact = DatabaseHelper.getContactDao().queryForId(source.getContact().getId()); + target.setContact(ContactDtoHelper.toReferenceDto(contact)); } else { - dto.setContact(null); + target.setContact(null); } - if (ado.getEvent() != null) { - Event event = DatabaseHelper.getEventDao().queryForId(ado.getEvent().getId()); - dto.setEvent(EventDtoHelper.toReferenceDto(event)); + if (source.getEvent() != null) { + Event event = DatabaseHelper.getEventDao().queryForId(source.getEvent().getId()); + target.setEvent(EventDtoHelper.toReferenceDto(event)); } else { - dto.setEvent(null); + target.setEvent(null); } - dto.setTaskType(ado.getTaskType()); - dto.setTaskStatus(ado.getTaskStatus()); - dto.setDueDate(ado.getDueDate()); - dto.setPriority(ado.getPriority()); - dto.setSuggestedStart(ado.getSuggestedStart()); - dto.setStatusChangeDate(ado.getStatusChangeDate()); - dto.setPerceivedStart(ado.getPerceivedStart()); - - if (ado.getCreatorUser() != null) { - User user = DatabaseHelper.getUserDao().queryForId(ado.getCreatorUser().getId()); - dto.setCreatorUser(UserDtoHelper.toReferenceDto(user)); + target.setTaskType(source.getTaskType()); + target.setTaskStatus(source.getTaskStatus()); + target.setDueDate(source.getDueDate()); + target.setPriority(source.getPriority()); + target.setSuggestedStart(source.getSuggestedStart()); + target.setStatusChangeDate(source.getStatusChangeDate()); + target.setPerceivedStart(source.getPerceivedStart()); + + if (source.getCreatorUser() != null) { + User user = DatabaseHelper.getUserDao().queryForId(source.getCreatorUser().getId()); + target.setCreatorUser(UserDtoHelper.toReferenceDto(user)); } else { - dto.setCreatorUser(null); + target.setCreatorUser(null); } - dto.setCreatorComment(ado.getCreatorComment()); - if (ado.getAssigneeUser() != null) { - User user = DatabaseHelper.getUserDao().queryForId(ado.getAssigneeUser().getId()); - dto.setAssigneeUser(UserDtoHelper.toReferenceDto(user)); + target.setCreatorComment(source.getCreatorComment()); + if (source.getAssigneeUser() != null) { + User user = DatabaseHelper.getUserDao().queryForId(source.getAssigneeUser().getId()); + target.setAssigneeUser(UserDtoHelper.toReferenceDto(user)); } else { - dto.setAssigneeUser(null); + target.setAssigneeUser(null); } - dto.setAssigneeReply(ado.getAssigneeReply()); + target.setAssigneeReply(source.getAssigneeReply()); - dto.setClosedLat(ado.getClosedLat()); - dto.setClosedLon(ado.getClosedLon()); + target.setClosedLat(source.getClosedLat()); + target.setClosedLon(source.getClosedLon()); + target.setClosedLatLonAccuracy(source.getClosedLatLonAccuracy()); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/Visit.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/Visit.java index ed08d2e4cfc..0ba186abb5d 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/Visit.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/Visit.java @@ -58,11 +58,12 @@ public class Visit extends AbstractDomainObject { @DatabaseField(foreign = true, foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 3) private Symptoms symptoms; - @Column(columnDefinition = "float8") - private Float reportLat; - - @Column(columnDefinition = "float8") - private Float reportLon; + @DatabaseField + private Double reportLat; + @DatabaseField + private Double reportLon; + @DatabaseField + private Float reportLatLonAccuracy; public Person getPerson() { return person; @@ -117,19 +118,19 @@ public void setSymptoms(Symptoms symptoms) { this.symptoms = symptoms; } - public Float getReportLat() { + public Double getReportLat() { return reportLat; } - public void setReportLat(Float reportLat) { + public void setReportLat(Double reportLat) { this.reportLat = reportLat; } - public Float getReportLon() { + public Double getReportLon() { return reportLon; } - public void setReportLon(Float reportLon) { + public void setReportLon(Double reportLon) { this.reportLon = reportLon; } @@ -142,4 +143,12 @@ public String getI18nPrefix() { public String toString() { return super.toString() + " " + DateHelper.formatShortDate(getVisitDateTime()); } + + public Float getReportLatLonAccuracy() { + return reportLatLonAccuracy; + } + + public void setReportLatLonAccuracy(Float reportLatLonAccuracy) { + this.reportLatLonAccuracy = reportLatLonAccuracy; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDao.java index 43bdd188e7b..c957d1c5c86 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDao.java @@ -113,14 +113,11 @@ public Visit build(String contactUuid) { public Visit saveAndSnapshot(final Visit visit) throws DaoException { // If a new visit is created, use the last available location to update its report latitude and longitude if (visit.getId() == null) { - LocationService locationService = LocationService.getLocationService(DatabaseHelper.getContext()); - Location location = locationService.getLocation(); + Location location = LocationService.instance().getLocation(); if (location != null) { - // Use the geo-coordinates of the current location object if it's not older than 15 minutes - if (new Date().getTime() <= location.getTime() + (1000 * 60 * 15)) { - visit.setReportLat((float) location.getLatitude()); - visit.setReportLon((float) location.getLongitude()); - } + visit.setReportLat(location.getLatitude()); + visit.setReportLon(location.getLongitude()); + visit.setReportLatLonAccuracy(location.getAccuracy()); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDtoHelper.java index 644305550bc..1b96bfec30f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDtoHelper.java @@ -59,40 +59,42 @@ public void fillInnerFromDto(Visit target, VisitDto source) { target.setReportLat(source.getReportLat()); target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } @Override - public void fillInnerFromAdo(VisitDto dto, Visit ado) { + public void fillInnerFromAdo(VisitDto target, Visit source) { - dto.setDisease(ado.getDisease()); + target.setDisease(source.getDisease()); - if (ado.getPerson() != null) { - Person person = DatabaseHelper.getPersonDao().queryForId(ado.getPerson().getId()); - dto.setPerson(PersonDtoHelper.toReferenceDto(person)); + if (source.getPerson() != null) { + Person person = DatabaseHelper.getPersonDao().queryForId(source.getPerson().getId()); + target.setPerson(PersonDtoHelper.toReferenceDto(person)); } else { - dto.setPerson(null); + target.setPerson(null); } - if (ado.getSymptoms() != null) { - Symptoms symptoms = DatabaseHelper.getSymptomsDao().queryForId(ado.getSymptoms().getId()); + if (source.getSymptoms() != null) { + Symptoms symptoms = DatabaseHelper.getSymptomsDao().queryForId(source.getSymptoms().getId()); SymptomsDto symptomsDto = symptomsDtoHelper.adoToDto(symptoms); - dto.setSymptoms(symptomsDto); + target.setSymptoms(symptomsDto); } else { - dto.setSymptoms(null); + target.setSymptoms(null); } - dto.setVisitDateTime(ado.getVisitDateTime()); - dto.setVisitRemarks(ado.getVisitRemarks()); - dto.setVisitStatus(ado.getVisitStatus()); + target.setVisitDateTime(source.getVisitDateTime()); + target.setVisitRemarks(source.getVisitRemarks()); + target.setVisitStatus(source.getVisitStatus()); - if (ado.getVisitUser() != null) { - User user = DatabaseHelper.getUserDao().queryForId(ado.getVisitUser().getId()); - dto.setVisitUser(UserDtoHelper.toReferenceDto(user)); + if (source.getVisitUser() != null) { + User user = DatabaseHelper.getUserDao().queryForId(source.getVisitUser().getId()); + target.setVisitUser(UserDtoHelper.toReferenceDto(user)); } else { - dto.setVisitUser(null); + target.setVisitUser(null); } - dto.setReportLat(ado.getReportLat()); - dto.setReportLon(ado.getReportLon()); + target.setReportLat(source.getReportLat()); + target.setReportLon(source.getReportLon()); + target.setReportLatLonAccuracy(source.getReportLatLonAccuracy()); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditActivity.java index f751f9370f0..9716b987610 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditActivity.java @@ -16,8 +16,10 @@ import android.view.View; import android.widget.LinearLayout; +import java.util.Arrays; import java.util.List; +import de.symeda.sormas.app.AbstractEditTabActivity; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.caze.CaseDao; @@ -34,7 +36,6 @@ import de.symeda.sormas.app.backend.sample.Sample; import de.symeda.sormas.app.backend.sample.SampleDao; import de.symeda.sormas.app.backend.symptoms.Symptoms; -import de.symeda.sormas.app.AbstractEditTabActivity; import de.symeda.sormas.app.backend.task.Task; import de.symeda.sormas.app.backend.task.TaskDao; import de.symeda.sormas.app.component.FacilityChangeDialogBuilder; @@ -52,14 +53,12 @@ import de.symeda.sormas.app.task.TasksListFragment; import de.symeda.sormas.app.util.Consumer; import de.symeda.sormas.app.util.ErrorReportingHelper; -import de.symeda.sormas.app.validation.CaseValidator; import de.symeda.sormas.app.validation.PersonValidator; import de.symeda.sormas.app.validation.SymptomsValidator; public class CaseEditActivity extends AbstractEditTabActivity { public static final String KEY_CASE_UUID = "caseUuid"; - public static final String CASE_SUBTITLE = "caseSubtitle"; private CaseEditPagerAdapter adapter; private String caseUuid; @@ -90,11 +89,12 @@ protected void onCreate(Bundle savedInstanceState) { getSupportActionBar().setTitle(getResources().getText(R.string.headline_case) + " - " + ConfigProvider.getUser().getUserRole().toShortString()); } + Case initialEntity = null; Bundle params = getIntent().getExtras(); if (params != null) { if (params.containsKey(KEY_CASE_UUID)) { caseUuid = params.getString(KEY_CASE_UUID); - Case initialEntity = DatabaseHelper.getCaseDao().queryUuid(caseUuid); + initialEntity = DatabaseHelper.getCaseDao().queryUuid(caseUuid); // If the case has been removed from the database in the meantime, redirect the user to the cases overview // TODO add Snackbar and test if (initialEntity == null) { @@ -103,6 +103,10 @@ protected void onCreate(Bundle savedInstanceState) { finish(); } + if (toolbar != null) { + getSupportActionBar().setSubtitle(initialEntity.toString()); + } + DatabaseHelper.getCaseDao().markAsRead(initialEntity); } if (params.containsKey(TaskForm.KEY_TASK_UUID)) { @@ -111,12 +115,9 @@ protected void onCreate(Bundle savedInstanceState) { if (params.containsKey(KEY_PAGE)) { currentTab = params.getInt(KEY_PAGE); } - if (params.containsKey(CASE_SUBTITLE) && toolbar != null) { - getSupportActionBar().setSubtitle(params.getString(CASE_SUBTITLE)); - } } - setAdapter(); + setAdapter(initialEntity); } @Override @@ -134,7 +135,7 @@ protected void onResume() { if (currentEntity.isUnreadOrChildUnread()) { // Resetting the adapter will reload the form and therefore also override any unsaved changes DatabaseHelper.getCaseDao().markAsRead(currentEntity); - setAdapter(); + setAdapter(currentEntity); final Snackbar snackbar = Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_entity_overridden), getResources().getString(R.string.entity_case)), Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.snackbar_okay, new View.OnClickListener() { @@ -173,7 +174,7 @@ public boolean onCreateOptionsMenu(Menu menu) { @Override public boolean onPrepareOptionsMenu(Menu menu) { - CaseEditTabs tab = CaseEditTabs.values()[currentTab]; + CaseEditTabs tab = adapter.getTabForPosition(currentTab); switch (tab) { case CASE_DATA: updateActionBarGroups(menu, false, false, true, false, true); @@ -214,8 +215,8 @@ public boolean onPrepareOptionsMenu(Menu menu) { @Override public boolean onOptionsItemSelected(MenuItem item) { setCurrentTab(pager.getCurrentItem()); - CaseEditTabs tab = CaseEditTabs.values()[currentTab]; - Case caze = (Case) getData(CaseEditTabs.CASE_DATA.ordinal()); + CaseEditTabs tab = adapter.getTabForPosition(currentTab); + Case caze = (Case) getData(adapter.getPositionOfTab(CaseEditTabs.CASE_DATA)); CaseDao caseDao = DatabaseHelper.getCaseDao(); switch (item.getItemId()) { // Respond to the action bar's Up/Home button @@ -338,8 +339,19 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - public void setAdapter() { - adapter = new CaseEditPagerAdapter(getSupportFragmentManager(), caseUuid); + public void setAdapter(Case caze) { + List visibleTabs; + if (caze != null && !caze.getDisease().hasContactFollowUp()) { + visibleTabs = Arrays.asList(CaseEditTabs.CASE_DATA, CaseEditTabs.PATIENT, + CaseEditTabs.HOSPITALIZATION, CaseEditTabs.SYMPTOMS, CaseEditTabs.EPIDATA, + CaseEditTabs.SAMPLES, CaseEditTabs.TASKS); + } else { + visibleTabs = Arrays.asList(CaseEditTabs.CASE_DATA, CaseEditTabs.PATIENT, + CaseEditTabs.HOSPITALIZATION, CaseEditTabs.SYMPTOMS, CaseEditTabs.EPIDATA, + CaseEditTabs.CONTACTS, CaseEditTabs.SAMPLES, CaseEditTabs.TASKS); + } + + adapter = new CaseEditPagerAdapter(getSupportFragmentManager(), caseUuid, visibleTabs); createTabViews(adapter); pager.setCurrentItem(currentTab); @@ -347,7 +359,7 @@ public void setAdapter() { public void moveCase(View v) { if (saveCase()) { - final CaseDataFragmentLayoutBinding caseBinding = ((CaseEditDataForm)getTabByPosition(CaseEditTabs.CASE_DATA.ordinal())).getBinding(); + final CaseDataFragmentLayoutBinding caseBinding = ((CaseEditDataForm)getTabByPosition(adapter.getPositionOfTab(CaseEditTabs.CASE_DATA))).getBinding(); final Consumer positiveCallback = new Consumer() { @Override @@ -361,7 +373,7 @@ public void accept(Object success) { Snackbar.make(findViewById(R.id.base_layout), getResources().getString(R.string.snackbar_case_moved_error), Snackbar.LENGTH_LONG).show(); } - setAdapter(); + setAdapter(updatedCase); } }; @@ -376,28 +388,28 @@ private boolean saveCase() { // PATIENT LocationDao locLocationDao = DatabaseHelper.getLocationDao(); PersonDao personDao = DatabaseHelper.getPersonDao(); - Person person = (Person) getData(CaseEditTabs.PATIENT.ordinal()); + Person person = (Person) getData(adapter.getPositionOfTab(CaseEditTabs.PATIENT)); // SYMPTOMS - Symptoms symptoms = (Symptoms) getData(CaseEditTabs.SYMPTOMS.ordinal()); + Symptoms symptoms = (Symptoms) getData(adapter.getPositionOfTab(CaseEditTabs.SYMPTOMS)); // HOSPITALIZATION - Hospitalization hospitalization = (Hospitalization) getData(CaseEditTabs.HOSPITALIZATION.ordinal()); + Hospitalization hospitalization = (Hospitalization) getData(adapter.getPositionOfTab(CaseEditTabs.HOSPITALIZATION)); // EPI DATA - EpiData epiData = (EpiData) getData(CaseEditTabs.EPIDATA.ordinal()); + EpiData epiData = (EpiData) getData(adapter.getPositionOfTab(CaseEditTabs.EPIDATA)); // CASE_DATA - Case caze = (Case) getData(CaseEditTabs.CASE_DATA.ordinal()); + Case caze = (Case) getData(adapter.getPositionOfTab(CaseEditTabs.CASE_DATA)); // Validations have to be processed from last tab to first to make sure that the user will be re-directed // to the first tab with a validation error - PersonEditFragmentLayoutBinding personBinding = ((PersonEditForm)getTabByPosition(CaseEditTabs.PATIENT.ordinal())).getBinding(); - CaseSymptomsFragmentLayoutBinding symptomsBinding = ((SymptomsEditForm)getTabByPosition(CaseEditTabs.SYMPTOMS.ordinal())).getBinding(); + PersonEditFragmentLayoutBinding personBinding = ((PersonEditForm)getTabByPosition(adapter.getPositionOfTab(CaseEditTabs.PATIENT))).getBinding(); + CaseSymptomsFragmentLayoutBinding symptomsBinding = ((SymptomsEditForm)getTabByPosition(adapter.getPositionOfTab(CaseEditTabs.SYMPTOMS))).getBinding(); // Necessary because the entry could've been automatically set, in which case the setValue method of the // custom field has not been called - symptoms.setOnsetSymptom((String) symptomsBinding.symptomsOnsetSymptom1.getValue()); + symptoms.setOnsetSymptom((String) symptomsBinding.symptomsOnsetSymptom.getValue()); PersonValidator.clearErrors(personBinding); SymptomsValidator.clearErrorsForSymptoms(symptomsBinding); @@ -405,10 +417,10 @@ private boolean saveCase() { int validationErrorTab = -1; if (!SymptomsValidator.validateCaseSymptoms(symptoms, symptomsBinding)) { - validationErrorTab = CaseEditTabs.SYMPTOMS.ordinal(); + validationErrorTab = adapter.getPositionOfTab(CaseEditTabs.SYMPTOMS); } if (!PersonValidator.validatePersonData(person, personBinding)) { - validationErrorTab = CaseEditTabs.PATIENT.ordinal(); + validationErrorTab = adapter.getPositionOfTab(CaseEditTabs.PATIENT); } if (validationErrorTab >= 0) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditDataForm.java index ee5f91874a8..597d7c068ac 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditDataForm.java @@ -85,6 +85,9 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, boolean showYellowFeverVaccination = Diseases.DiseasesConfiguration.isDefinedOrMissing(CaseDataDto.class, binding.caseDataYellowFeverVaccination.getPropertyId(), binding.getCaze().getDisease()); binding.caseDataYellowFeverVaccination.setVisibility(showYellowFeverVaccination ? View.VISIBLE : View.GONE); + boolean showSmallpoxVaccinationScar = Diseases.DiseasesConfiguration.isDefinedOrMissing(CaseDataDto.class, binding.caseDataSmallpoxVaccinationScar.getPropertyId(), binding.getCaze().getDisease()); + binding.caseDataSmallpoxVaccinationScar.setVisibility(showSmallpoxVaccinationScar ? View.VISIBLE : View.GONE); + if (binding.getCaze().getPerson().getSex() != Sex.FEMALE) { binding.caseDataPregnant.setVisibility(View.GONE); } @@ -107,7 +110,7 @@ public void onChange(PropertyField field) { }); if (binding.caseDataPregnant.getVisibility() == View.GONE && binding.caseDataMeaslesVaccination.getVisibility() == View.GONE && - binding.caseDataYellowFeverVaccination.getVisibility() == View.GONE) { + binding.caseDataYellowFeverVaccination.getVisibility() == View.GONE && binding.caseDataSmallpoxVaccinationScar.getVisibility() == View.GONE) { binding.caseMedicalInformationHeadline.setVisibility(View.GONE); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditPagerAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditPagerAdapter.java index 721ecdabdac..87275101edd 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditPagerAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditPagerAdapter.java @@ -5,6 +5,8 @@ import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; +import java.util.List; + import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.epidata.EpiData; import de.symeda.sormas.app.backend.hospitalization.Hospitalization; @@ -28,20 +30,22 @@ public class CaseEditPagerAdapter extends FragmentStatePagerAdapter { private Bundle caseEditBundle; // this bundle contains the uuids + private List visibleTabs; // Build a Constructor and assign the passed Values to appropriate values in the class - public CaseEditPagerAdapter(FragmentManager fm, String caseUuid) { + public CaseEditPagerAdapter(FragmentManager fm, String caseUuid, List visibleTabs) { super(fm); caseEditBundle = new Bundle(); caseEditBundle.putString(Case.UUID, caseUuid); + this.visibleTabs = visibleTabs; } // This method return the fragment for the every position in the View Pager @Override public Fragment getItem(int position) { Fragment frag = null; - CaseEditTabs tab = CaseEditTabs.values()[position]; - Case caze = null; + CaseEditTabs tab = visibleTabs.get(position); + Case caze; switch (tab) { case CASE_DATA: frag = new CaseEditDataForm(); @@ -109,12 +113,21 @@ public Fragment getItem(int position) { // This method return the titles for the Tabs in the Tab Strip @Override public CharSequence getPageTitle(int position) { - return CaseEditTabs.values()[position].toString(); + return visibleTabs.get(position).toString(); } // This method return the Number of tabs for the tabs Strip @Override public int getCount() { - return CaseEditTabs.values().length; + return visibleTabs.size(); + } + + public CaseEditTabs getTabForPosition(int position) { + return visibleTabs.get(position); } + + public int getPositionOfTab(CaseEditTabs tab) { + return visibleTabs.indexOf(tab); + } + } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditTabs.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditTabs.java index 48614ff2406..c731f2d0aa6 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditTabs.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditTabs.java @@ -14,10 +14,6 @@ public enum CaseEditTabs { TASKS, ; - public static CaseEditTabs fromInt(int x) { - return CaseEditTabs.values()[x]; - } - public String toString() { return I18nProperties.getFieldCaption(CaseDataDto.I18N_PREFIX+"."+this.name()); }; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewActivity.java index 7262fa45b9b..a85de838fec 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewActivity.java @@ -42,6 +42,7 @@ import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.util.Consumer; import de.symeda.sormas.app.util.ErrorReportingHelper; +import de.symeda.sormas.app.util.LocationService; import de.symeda.sormas.app.util.SyncCallback; import de.symeda.sormas.app.validation.CaseValidator; @@ -89,6 +90,13 @@ protected void onCreate(Bundle savedInstanceState) { ft.add(R.id.fragment_frame, caseNewForm).commit(); } + @Override + protected void onResume() { + LocationService.instance().requestFreshLocation(this); + + super.onResume(); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewForm.java index 41993af9764..b20334c02d7 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewForm.java @@ -15,14 +15,17 @@ import de.symeda.sormas.api.I18nProperties; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.facility.FacilityDto; +import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.DatabaseHelper; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.facility.Facility; import de.symeda.sormas.app.backend.person.Person; import de.symeda.sormas.app.backend.region.Community; import de.symeda.sormas.app.backend.region.District; import de.symeda.sormas.app.backend.region.Region; +import de.symeda.sormas.app.backend.user.User; import de.symeda.sormas.app.component.FieldHelper; import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.component.SpinnerField; @@ -173,6 +176,19 @@ public void onChange(PropertyField field) { CaseValidator.setRequiredHintsForNewCase(binding); + binding.caseDataRegion.setEnabled(false); + binding.caseDataDistrict.setEnabled(false); + User user = ConfigProvider.getUser(); + if (user.getUserRole() == UserRole.INFORMANT + && user.getHealthFacility() != null) { + // this is ok, becuase informants are required to have a community and health facility + binding.caseDataCommunity.setEnabled(false); + binding.caseDataHealthFacility.setEnabled(false); + } else { + binding.caseDataCommunity.setEnabled(true); + binding.caseDataHealthFacility.setEnabled(true); + } + return binding.getRoot(); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListArrayAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListArrayAdapter.java index d62df1db877..13ed8a3342a 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListArrayAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListArrayAdapter.java @@ -52,12 +52,9 @@ public View getView(int position, View convertView, ViewGroup parent) { uuid.setText(DataHelper.getShortUuid(caze.getUuid())); TextView disease = (TextView) convertView.findViewById(R.id.cli_disease); - if(caze.getDisease() != null) { - String diseaseName = caze.getDisease().getName(); - disease.setText(Disease.valueOf(diseaseName).toShortString() + (caze.getDisease() == Disease.OTHER ? " (" + caze.getDiseaseDetails() + ")" : "")); - } else { - disease.setText(null); - } + disease.setText(caze.getDisease() != Disease.OTHER + ? (caze.getDisease() != null ? caze.getDisease().toShortString() : "") + : DataHelper.toStringNullable(caze.getDiseaseDetails())); TextView reportDate = (TextView) convertView.findViewById(R.id.cli_report_date); reportDate.setText(DateHelper.formatDate(caze.getReportDate())); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListFragment.java index 1fae2813bc0..5cae3715701 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListFragment.java @@ -93,7 +93,6 @@ public void onItemClick( public void showCaseEditView(Case caze) { Intent intent = new Intent(getActivity(), CaseEditActivity.class); intent.putExtra(CaseEditActivity.KEY_CASE_UUID, caze.getUuid()); - intent.putExtra(CaseEditActivity.CASE_SUBTITLE, caze.toString()); startActivity(intent); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/SymptomsEditForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/SymptomsEditForm.java index 83232797c92..3aabad9b4c8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/SymptomsEditForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/SymptomsEditForm.java @@ -3,7 +3,6 @@ import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.annotation.Nullable; -import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -13,6 +12,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import de.symeda.sormas.api.Disease; @@ -20,19 +20,16 @@ import de.symeda.sormas.api.symptoms.SymptomsDto; import de.symeda.sormas.api.symptoms.SymptomsHelper; import de.symeda.sormas.api.symptoms.TemperatureSource; -import de.symeda.sormas.api.utils.Diseases; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.location.Location; import de.symeda.sormas.app.backend.symptoms.Symptoms; +import de.symeda.sormas.app.component.CheckBoxField; import de.symeda.sormas.app.component.FieldHelper; -import de.symeda.sormas.app.component.LocationDialog; import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.component.SymptomStateField; import de.symeda.sormas.app.databinding.CaseSymptomsFragmentLayoutBinding; -import de.symeda.sormas.app.util.Consumer; import de.symeda.sormas.app.util.DataUtils; import de.symeda.sormas.app.util.FormTab; import de.symeda.sormas.app.util.Item; @@ -50,9 +47,14 @@ public class SymptomsEditForm extends FormTab { public static final String FOR_VISIT = "forVisit"; public static final String VISIT_COOPERATIVE = "visitCooperative"; + private Disease disease; + private CaseSymptomsFragmentLayoutBinding binding; private List nonConditionalSymptoms; private List conditionalBleedingSymptoms; + private List lesionsFields; + private List lesionsLocationFields; + private List monkeypoxFields; private boolean forVisit; private boolean visitCooperative; @@ -64,7 +66,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Symptoms symptoms; - final Disease disease = (Disease) getArguments().getSerializable(Case.DISEASE); + disease = (Disease) getArguments().getSerializable(Case.DISEASE); // build a new visit from contact data if(getArguments().getBoolean(NEW_SYMPTOMS)) { @@ -131,32 +133,57 @@ public void onChange(PropertyField field) { } } }); + binding.symptomsLesions.addValueChangedListener(new PropertyField.ValueChangeListener() { + @Override + public void onChange(PropertyField field) { + visibilityLesionsFields(); + if (forVisit) { + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); + } else { + SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); + } + } + }); + + lesionsFields = Arrays.asList(binding.symptomsLesionsSameState, binding.symptomsLesionsSameSize, binding.symptomsLesionsDeepProfound, binding.symptomsLesionsThatItch); + + lesionsLocationFields = Arrays.asList(binding.symptomsLesionsFace, binding.symptomsLesionsLegs, binding.symptomsLesionsSolesFeet, binding.symptomsLesionsPalmsHands, + binding.symptomsLesionsThorax, binding.symptomsLesionsArms, binding.symptomsLesionsGenitals, binding.symptomsLesionsAllOverBody); + + monkeypoxFields = Arrays.asList(binding.symptomsLesionsResembleImg1, binding.symptomsLesionsResembleImg2, binding.symptomsLesionsResembleImg3, binding.symptomsLesionsResembleImg4); // set initial UI toggleUnexplainedBleedingFields(); visibilityOtherHemorrhagicSymptoms(); visibilityOtherNonHemorrhagicSymptoms(); + visibilityLesionsFields(); setVisibilityByDisease(SymptomsDto.class, disease, (ViewGroup)binding.getRoot()); + if (forVisit) { + binding.symptomsPatientIllLocation.setVisibility(View.GONE); + } + nonConditionalSymptoms = Arrays.asList(binding.symptomsFever, binding.symptomsVomiting, - binding.symptomsDiarrhea, binding.symptomsBloodInStool1, binding.symptomsNausea, binding.symptomsAbdominalPain, + binding.symptomsDiarrhea, binding.symptomsBloodInStool, binding.symptomsNausea, binding.symptomsAbdominalPain, binding.symptomsHeadache, binding.symptomsMusclePain, binding.symptomsFatigueWeakness, binding.symptomsUnexplainedBleeding, binding.symptomsSkinRash, binding.symptomsNeckStiffness, binding.symptomsSoreThroat, binding.symptomsCough, binding.symptomsRunnyNose, binding.symptomsDifficultyBreathing, binding.symptomsChestPain, binding.symptomsConfusedDisoriented, binding.symptomsSeizures, binding.symptomsAlteredConsciousness, binding.symptomsConjunctivitis, - binding.symptomsEyePainLightSensitive, binding.symptomsKopliksSpots1, binding.symptomsThrobocytopenia, + binding.symptomsEyePainLightSensitive, binding.symptomsKopliksSpots, binding.symptomsThrobocytopenia, binding.symptomsOtitisMedia, binding.symptomsHearingloss, binding.symptomsDehydration, binding.symptomsAnorexiaAppetiteLoss, binding.symptomsRefusalFeedorDrink, binding.symptomsJointPain, binding.symptomsShock, binding.symptomsHiccups, binding.symptomsBackache, binding.symptomsEyesBleeding, binding.symptomsJaundice, binding.symptomsDarkUrine, binding.symptomsStomachBleeding, binding.symptomsRapidBreathing, binding.symptomsSwollenGlands, - binding.symptomsOtherNonHemorrhagicSymptoms); + binding.symptomsOtherNonHemorrhagicSymptoms, binding.symptomsCutaneousEruption, binding.symptomsLesions, binding.symptomsLymphadenopathyAxillary, + binding.symptomsLymphadenopathyCervical, binding.symptomsLymphadenopathyInguinal, binding.symptomsChillsSweats, binding.symptomsBedridden, + binding.symptomsOralUlcers); - conditionalBleedingSymptoms = Arrays.asList(binding.symptomsGumsBleeding1, binding.symptomsInjectionSiteBleeding, - binding.symptomsNoseBleeding1, binding.symptomsBloodyBlackStool, binding.symptomsRedBloodVomit, + conditionalBleedingSymptoms = Arrays.asList(binding.symptomsGumsBleeding, binding.symptomsInjectionSiteBleeding, + binding.symptomsNoseBleeding, binding.symptomsBloodyBlackStool, binding.symptomsRedBloodVomit, binding.symptomsDigestedBloodVomit, binding.symptomsCoughingBlood, binding.symptomsBleedingVagina, - binding.symptomsSkinBruising1, binding.symptomsBloodUrine, binding.symptomsOtherHemorrhagicSymptoms); + binding.symptomsSkinBruising, binding.symptomsBloodUrine, binding.symptomsOtherHemorrhagicSymptoms); - FieldHelper.initSpinnerField(binding.symptomsOnsetSymptom1, DataUtils.toItems(null, true)); + FieldHelper.initSpinnerField(binding.symptomsOnsetSymptom, DataUtils.toItems(null, true)); addListenerForOnsetSymptom(); Button clearAllBtn = binding.symptomsClearAll; @@ -169,7 +196,15 @@ public void onClick(View v) { for (SymptomStateField symptom : conditionalBleedingSymptoms) { symptom.setValue(null); } - + for (SymptomStateField symptom : lesionsFields) { + symptom.setValue(null); + } + for (CheckBoxField checkBox : lesionsLocationFields) { + checkBox.setValue(null); + } + for (SymptomStateField symptom : monkeypoxFields) { + symptom.setValue(null); + } if (forVisit) { SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); } else { @@ -192,6 +227,16 @@ public void onClick(View v) { symptom.setValue(SymptomState.NO); } } + for (SymptomStateField symptom : lesionsFields) { + if (symptom.getVisibility() == View.VISIBLE && symptom.getValue() == null) { + symptom.setValue(SymptomState.NO); + } + } + for (SymptomStateField symptom : monkeypoxFields) { + if (symptom.getVisibility() == View.VISIBLE && symptom.getValue() == null) { + symptom.setValue(SymptomState.NO); + } + } if (forVisit) { SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); @@ -202,23 +247,8 @@ public void onClick(View v) { }); if (!forVisit) { - binding.symptomsIllLocationLayout.setVisibility(View.VISIBLE); - // ==================== IllLocation =============== - LocationDialog.addLocationField(getActivity(), symptoms.getIllLocation(), binding.symptomsIllLocation, binding.formCpBtnAddress, new Consumer() { - @Override - public void accept(Object parameter) { - if (parameter instanceof Location) { - binding.symptomsIllLocation.setValue(parameter.toString()); - binding.getSymptoms().setIllLocation(((Location) parameter)); - } - } - }); - - binding.symptomsIllLocationFrom.initialize(this); - binding.symptomsIllLocationTo.initialize(this); SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); } else { - binding.symptomsIllLocationLayout.setVisibility(View.GONE); SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); } @@ -272,17 +302,38 @@ private void visibilityOtherNonHemorrhagicSymptoms() { } } + private void visibilityLesionsFields() { + SymptomState symptomState = binding.symptomsLesions.getValue(); + binding.symptomsLesionsLayout.setVisibility(symptomState == SymptomState.YES ? View.VISIBLE : View.GONE); + if (symptomState != SymptomState.YES) { + for (PropertyField field : lesionsFields) { + field.setValue(null); + } + for (PropertyField field : lesionsLocationFields) { + field.setValue(false); + } + } + if (disease == Disease.MONKEYPOX) { + binding.symptomsMonkeypoxLayout.setVisibility(symptomState == SymptomState.YES ? View.VISIBLE : View.GONE); + if (symptomState != SymptomState.YES) { + for (PropertyField field : monkeypoxFields) { + field.setValue(null); + } + } + } + } + private void toggleUnexplainedBleedingFields() { int[] fieldIds = { - R.id.symptoms_gumsBleeding1, + R.id.symptoms_gumsBleeding, R.id.symptoms_injectionSiteBleeding, - R.id.symptoms_noseBleeding1, + R.id.symptoms_noseBleeding, R.id.symptoms_bloodyBlackStool, R.id.symptoms_redBloodVomit, R.id.symptoms_digestedBloodVomit, R.id.symptoms_coughingBlood, R.id.symptoms_bleedingVagina, - R.id.symptoms_skinBruising1, + R.id.symptoms_skinBruising, R.id.symptoms_bloodUrine, R.id.symptoms_otherHemorrhagicSymptoms }; @@ -302,33 +353,18 @@ private void toggleUnexplainedBleedingFields() { } private void addListenerForOnsetSymptom() { - final ArrayAdapter adapter = (ArrayAdapter) binding.symptomsOnsetSymptom1.getAdapter(); - - for (SymptomStateField symptom : nonConditionalSymptoms) { - symptom.addValueChangedListener(new PropertyField.ValueChangeListener() { - @Override - public void onChange(PropertyField field) { - Item item = new Item(field.getCaption(), field.getCaption()); - int position = binding.symptomsOnsetSymptom1.getPositionOf(item); - if (field.getValue() == SymptomState.YES) { - if (position == -1) { - adapter.add(item); - } - } else { - if (position != -1) { - adapter.remove(adapter.getItem(position)); - } - } - } - }); - } + final ArrayAdapter adapter = (ArrayAdapter) binding.symptomsOnsetSymptom.getAdapter(); + List relevantSymptoms = new ArrayList<>(); + relevantSymptoms.addAll(nonConditionalSymptoms); + relevantSymptoms.addAll(conditionalBleedingSymptoms); + relevantSymptoms.add(binding.symptomsLesionsThatItch); - for (SymptomStateField symptom : conditionalBleedingSymptoms) { + for (SymptomStateField symptom : relevantSymptoms) { symptom.addValueChangedListener(new PropertyField.ValueChangeListener() { @Override public void onChange(PropertyField field) { Item item = new Item(field.getCaption(), field.getCaption()); - int position = binding.symptomsOnsetSymptom1.getPositionOf(item); + int position = binding.symptomsOnsetSymptom.getPositionOf(item); if (field.getValue() == SymptomState.YES) { if (position == -1) { adapter.add(item); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/LabelField.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/LabelField.java index d2452a1dcdc..e5bb78ef248 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/LabelField.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/LabelField.java @@ -233,12 +233,18 @@ public static void setSampleTestResult(LabelField labelField, String sampleUuid) @BindingAdapter("location") public static void setLocationForLabel(LabelField labelField, Location location) { - if(location == null || location.toString().isEmpty()) { + if (location == null ) { labelField.setValue(labelField.getContext().getString(R.string.label_enter_location)); labelField.setTextColor(Color.LTGRAY); } else { - labelField.setValue(location.toString()); - labelField.setTextColor(Color.BLACK); + String locationString = location.getCompleteString(); + if (!locationString.isEmpty()) { + labelField.setValue(locationString); + labelField.setTextColor(Color.BLACK); + } else { + labelField.setValue(labelField.getContext().getString(R.string.label_enter_location)); + labelField.setTextColor(Color.LTGRAY); + } } } @@ -262,6 +268,35 @@ public static void setFacilityForLabel(LabelField labelField, Facility facility) labelField.setValue(facility!=null?facility.toString():""); } + @BindingAdapter("number") + public static void setNumberForLabel(LabelField labelField, Number number) { + labelField.setValue(number!=null?number.toString():""); + } + + @BindingAdapter("locationLatLon") + public static void setLocationLatLonForLabel(LabelField labelField, Location location) { + setLatLonForLabel(labelField, + location != null ? location.getLatitude() : null, + location != null ? location.getLongitude() : null, + location != null ? location.getLatLonAccuracy() : null); + } + + public static void setLatLonForLabel(LabelField labelField, Double latitude, Double longitude, Float latLonAccuracy) { + if (latitude == null || longitude == null) { + labelField.setValue(labelField.getContext().getString(R.string.label_pick_gps)); + } + else { + if (latLonAccuracy != null) { + labelField.setValue(android.location.Location.convert(latitude, android.location.Location.FORMAT_DEGREES) + + ", " + android.location.Location.convert(longitude, android.location.Location.FORMAT_DEGREES) + + " +-" + Math.round(latLonAccuracy) + "m"); + } else { + labelField.setValue(android.location.Location.convert(latitude, android.location.Location.FORMAT_DEGREES) + + ", " + android.location.Location.convert(longitude, android.location.Location.FORMAT_DEGREES)); + } + } + } + @Override protected void requestFocusForContentView(View nextView) { ((LabelField) nextView).textContent.requestFocus(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/LocationDialog.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/LocationDialogBuilder.java similarity index 71% rename from sormas-app/app/src/main/java/de/symeda/sormas/app/component/LocationDialog.java rename to sormas-app/app/src/main/java/de/symeda/sormas/app/component/LocationDialogBuilder.java index 1bf12d386ec..012bcfa7ffc 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/LocationDialog.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/LocationDialogBuilder.java @@ -1,20 +1,22 @@ package de.symeda.sormas.app.component; import android.content.DialogInterface; -import android.graphics.Color; +import android.graphics.Rect; import android.support.v4.app.FragmentActivity; import android.support.v7.app.AlertDialog; import android.view.View; +import android.view.Window; import android.widget.AdapterView; +import android.widget.Button; import android.widget.ImageButton; +import android.widget.TextView; import java.util.ArrayList; +import java.util.Date; import java.util.List; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.backend.common.DaoException; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.facility.Facility; import de.symeda.sormas.app.backend.location.Location; import de.symeda.sormas.app.backend.region.Community; import de.symeda.sormas.app.backend.region.District; @@ -22,14 +24,34 @@ import de.symeda.sormas.app.util.Callback; import de.symeda.sormas.app.util.DataUtils; import de.symeda.sormas.app.util.Consumer; +import de.symeda.sormas.app.util.LocationService; -public class LocationDialog extends AlertDialog.Builder { +public class LocationDialogBuilder extends AlertDialog.Builder { - public LocationDialog(FragmentActivity activity, final Location location, final Consumer positiveCallback , final Callback negativeCallback) { + private final View dialogView; + + private Double latitude; + private Double longitude; + private Float latLonAccuracy; + + public LocationDialogBuilder(final FragmentActivity activity, final Location location, final Consumer positiveCallback , final Callback negativeCallback) { super(activity); + + LocationService.instance().requestFreshLocation(activity); + this.setTitle(activity.getResources().getString(R.string.headline_location)); - final View dialogView = activity.getLayoutInflater().inflate(R.layout.location_fragment_layout, null); + + latitude = location.getLatitude(); + longitude = location.getLongitude(); + latLonAccuracy = location.getLatLonAccuracy(); + + dialogView = activity.getLayoutInflater().inflate(R.layout.location_fragment_layout, null); this.setView(dialogView); + // retrieve display dimensions + Rect displayRectangle = new Rect(); + Window window = activity.getWindow(); + window.getDecorView().getWindowVisibleDisplayFrame(displayRectangle); + dialogView.setMinimumWidth((int)(0.9f * displayRectangle.width())); final List emptyList = new ArrayList<>(); final List districtsByRegion = DataUtils.toItems(location.getRegion() != null ? DatabaseHelper.getDistrictDao().getByRegion(location.getRegion()) : DataUtils.toItems(emptyList), true); @@ -96,6 +118,26 @@ public void onNothingSelected(AdapterView parent) { ((TextField) dialogView.findViewById(R.id.location_city)).setValue(location.getCity()); } + Button gpsButton = (Button)dialogView.findViewById(R.id.form_loc_btn_gps); + gpsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + + android.location.Location phoneLocation = LocationService.instance().getLocation(activity); + if (phoneLocation != null) { + latitude = phoneLocation.getLatitude(); + longitude = phoneLocation.getLongitude(); + latLonAccuracy = phoneLocation.getAccuracy(); + } else { + latitude = null; + longitude = null; + latLonAccuracy = null; + } + updateGpsTextView(); + } + }); + updateGpsTextView(); + this.setPositiveButton(activity.getResources().getString(R.string.action_done), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { @@ -110,6 +152,10 @@ public void onClick(DialogInterface dialog, int id) { location.setDistrict((District)((SpinnerField) dialogView.findViewById(R.id.location_district)).getValue()); location.setCommunity((Community)((SpinnerField) dialogView.findViewById(R.id.location_community)).getValue()); + location.setLatitude(latitude); + location.setLongitude(longitude); + location.setLatLonAccuracy(latLonAccuracy); + if(positiveCallback!=null) { positiveCallback.accept(location); } @@ -123,7 +169,13 @@ public void onClick(DialogInterface dialog, int id) { } } }); + } + + + private void updateGpsTextView() { + LabelField gpsLabelField = (LabelField)dialogView.findViewById(R.id.location_latLon); + LabelField.setLatLonForLabel(gpsLabelField, latitude, longitude, latLonAccuracy); } public static void addLocationField(final FragmentActivity activity, final Location location, final LabelField locationText, ImageButton btn, final Consumer positiveCallback) { @@ -140,7 +192,7 @@ public void accept(Object parameter) { btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { - final LocationDialog dialogBuilder = new LocationDialog(activity, location, wrappedPositiveCallback, null); + final LocationDialogBuilder dialogBuilder = new LocationDialogBuilder(activity, location, wrappedPositiveCallback, null); AlertDialog newPersonDialog = dialogBuilder.create(); newPersonDialog.show(); } @@ -149,7 +201,7 @@ public void onClick(View arg0) { locationText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { - final LocationDialog dialogBuilder = new LocationDialog(activity, location, wrappedPositiveCallback, null); + final LocationDialogBuilder dialogBuilder = new LocationDialogBuilder(activity, location, wrappedPositiveCallback, null); AlertDialog newPersonDialog = dialogBuilder.create(); newPersonDialog.show(); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/PropertyField.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/PropertyField.java index ae08531ef88..fdd02480b0c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/PropertyField.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/PropertyField.java @@ -127,10 +127,10 @@ protected final String getFieldIdString() { String fieldIdString = getResources().getResourceName(getId()); - // this is a workaround used in AS < 2.3 because of https://code.google.com/p/android/issues/detail?id=212492 --> - if (fieldIdString.endsWith("1")) { - fieldIdString = fieldIdString.substring(0, fieldIdString.length() - 1); - } +// // this is a workaround used in AS < 2.3 because of https://code.google.com/p/android/issues/detail?id=212492 --> +// if (fieldIdString.endsWith("1")) { +// fieldIdString = fieldIdString.substring(0, fieldIdString.length() - 1); +// } return fieldIdString; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditActivity.java index e3b10a17804..f5d23a96a77 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditActivity.java @@ -100,6 +100,10 @@ protected void onCreate(Bundle savedInstanceState) { finish(); } + if (toolbar != null) { + getSupportActionBar().setSubtitle(initialEntity.toString()); + } + DatabaseHelper.getContactDao().markAsRead(initialEntity); } if (params.containsKey(TaskForm.KEY_TASK_UUID)) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewActivity.java index e233824643b..31e4fee705b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewActivity.java @@ -37,6 +37,7 @@ import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.util.Consumer; import de.symeda.sormas.app.util.ErrorReportingHelper; +import de.symeda.sormas.app.util.LocationService; import de.symeda.sormas.app.util.SyncCallback; import de.symeda.sormas.app.validation.ContactValidator; @@ -75,6 +76,13 @@ protected void onCreate(Bundle savedInstanceState) { ft.add(R.id.fragment_frame, contactNewForm).commit(); } + @Override + protected void onResume() { + LocationService.instance().requestFreshLocation(this); + + super.onResume(); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataBurialForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataBurialForm.java index 00849348c85..a2da647cc71 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataBurialForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataBurialForm.java @@ -6,22 +6,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; - -import com.google.android.gms.analytics.Tracker; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.common.AbstractDomainObject; -import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.epidata.EpiDataBurial; import de.symeda.sormas.app.backend.location.Location; import de.symeda.sormas.app.component.AbstractFormDialogFragment; -import de.symeda.sormas.app.component.LocationDialog; +import de.symeda.sormas.app.component.LocationDialogBuilder; import de.symeda.sormas.app.databinding.EpidataBurialEditFragmentLayoutBinding; import de.symeda.sormas.app.util.Consumer; -import de.symeda.sormas.app.util.DataUtils; -import de.symeda.sormas.app.util.ErrorReportingHelper; /** * Created by Mate Strysewske on 09.03.2017. @@ -47,7 +40,7 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { binding.burialTo.initialize(this); EpiDataBurial burial = binding.getEpiDataBurial(); - LocationDialog.addLocationField(getActivity(), burial.getBurialAddress(), binding.burialAddress, binding.formCpBtnAddress, new Consumer() { + LocationDialogBuilder.addLocationField(getActivity(), burial.getBurialAddress(), binding.burialAddress, binding.formCpBtnAddress, new Consumer() { @Override public void accept(Object parameter) { if (parameter instanceof Location) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataForm.java index df05fdbd189..6413b4b23db 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataForm.java @@ -8,6 +8,7 @@ import android.view.ViewGroup; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.epidata.AnimalCondition; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.api.epidata.EpiDataDto; import de.symeda.sormas.api.epidata.WaterSource; @@ -215,8 +216,12 @@ public void onChange(PropertyField field) { @Override public void onChange(PropertyField field) { binding.epiDataPoultrySickDetails.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); - binding.epiDataPoultryDate.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); - binding.epiDataPoultryLocation.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); + if (Diseases.DiseasesConfiguration.isDefinedOrMissing(EpiDataDto.class, EpiDataDto.POULTRY_DATE, disease)) { + binding.epiDataPoultryDate.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); + } + if (Diseases.DiseasesConfiguration.isDefinedOrMissing(EpiDataDto.class, EpiDataDto.POULTRY_LOCATION, disease)) { + binding.epiDataPoultryLocation.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); + } } }); @@ -231,8 +236,12 @@ public void onChange(PropertyField field) { @Override public void onChange(PropertyField field) { binding.epiDataWildbirdsDetails.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); - binding.epiDataWildbirdsDate.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); - binding.epiDataWildbirdsLocation.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); + if (Diseases.DiseasesConfiguration.isDefinedOrMissing(EpiDataDto.class, EpiDataDto.WILDBIRDS_DATE, disease)) { + binding.epiDataWildbirdsDate.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); + } + if (Diseases.DiseasesConfiguration.isDefinedOrMissing(EpiDataDto.class, EpiDataDto.WILDBIRDS_LOCATION, disease)) { + binding.epiDataWildbirdsLocation.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); + } } }); @@ -253,10 +262,19 @@ public void onChange(PropertyField field) { setVisibilityByDisease(EpiDataDto.class, disease, (ViewGroup)binding.getRoot()); showOrHideHeadlines(); + FieldHelper.initSpinnerField(binding.epiDataAnimalCondition, AnimalCondition.class); + binding.epiDataDateOfLastExposure.initialize(this); + return view; } private void showOrHideHeadlines() { + if (!(binding.epiDataBurialAttended.getVisibility() == View.VISIBLE || binding.epiDataGatheringAttended.getVisibility() == View.VISIBLE || + binding.epiDataTraveled.getVisibility() == View.VISIBLE)) { + binding.epiDataEpiData.setVisibility(View.GONE); + binding.epiDataEpiDataInfoText.setVisibility(View.GONE); + } + if (!(binding.epiDataRodents.getVisibility() == View.VISIBLE || binding.epiDataBats.getVisibility() == View.VISIBLE || binding.epiDataPrimates.getVisibility() == View.VISIBLE || binding.epiDataSwine.getVisibility() == View.VISIBLE || binding.epiDataCattle.getVisibility() == View.VISIBLE || binding.epiDataOtherAnimals.getVisibility() == View.VISIBLE || @@ -264,6 +282,7 @@ private void showOrHideHeadlines() { binding.epiDataPoultryEat.getVisibility() == View.VISIBLE || binding.epiDataPoultry.getVisibility() == View.VISIBLE || binding.epiDataPoultrySick.getVisibility() == View.VISIBLE)) { binding.epiDataAnimalContacts.setVisibility(View.GONE); + binding.epiDataAnimalContactsInfoText.setVisibility(View.GONE); } if (!(binding.epiDataWaterSource.getVisibility() == View.VISIBLE || binding.epiDataWaterBody.getVisibility() == View.VISIBLE || diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataGatheringForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataGatheringForm.java index f46ba97d803..3e8ef9f3fc6 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataGatheringForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataGatheringForm.java @@ -6,24 +6,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; - -import com.google.android.gms.analytics.Tracker; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.common.AbstractDomainObject; -import de.symeda.sormas.app.backend.config.ConfigProvider; -import de.symeda.sormas.app.backend.epidata.EpiDataBurial; import de.symeda.sormas.app.backend.epidata.EpiDataGathering; import de.symeda.sormas.app.backend.location.Location; import de.symeda.sormas.app.component.AbstractFormDialogFragment; -import de.symeda.sormas.app.component.LocationDialog; -import de.symeda.sormas.app.databinding.EpidataBurialEditFragmentLayoutBinding; +import de.symeda.sormas.app.component.LocationDialogBuilder; import de.symeda.sormas.app.databinding.EpidataGatheringEditFragmentLayoutBinding; import de.symeda.sormas.app.util.Consumer; -import de.symeda.sormas.app.util.DataUtils; -import de.symeda.sormas.app.util.ErrorReportingHelper; /** * Created by Mate Strysewske on 09.03.2017. @@ -48,7 +39,7 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { binding.gatherDate.initialize(this); EpiDataGathering gathering = binding.getEpiDataGathering(); - LocationDialog.addLocationField(getActivity(), gathering.getGatheringAddress(), binding.gatherAddress, binding.formCpBtnAddress, new Consumer() { + LocationDialogBuilder.addLocationField(getActivity(), gathering.getGatheringAddress(), binding.gatherAddress, binding.formCpBtnAddress, new Consumer() { @Override public void accept(Object parameter) { if (parameter instanceof Location) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditDataForm.java index 645e8e63aa0..7464775fba4 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditDataForm.java @@ -17,7 +17,7 @@ import de.symeda.sormas.app.backend.event.EventDao; import de.symeda.sormas.app.backend.location.Location; import de.symeda.sormas.app.component.FieldHelper; -import de.symeda.sormas.app.component.LocationDialog; +import de.symeda.sormas.app.component.LocationDialogBuilder; import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.databinding.EventDataFragmentLayoutBinding; import de.symeda.sormas.app.util.FormTab; @@ -63,7 +63,7 @@ public void onChange(PropertyField field) { FieldHelper.initSpinnerField(binding.eventDisease, Disease.class); - LocationDialog.addLocationField(getActivity(), event.getEventLocation(), binding.eventEventLocation, binding.eventEventLocationBtn, new Consumer() { + LocationDialogBuilder.addLocationField(getActivity(), event.getEventLocation(), binding.eventEventLocation, binding.eventEventLocationBtn, new Consumer() { @Override public void accept(Object parameter) { if(parameter instanceof Location) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventNewActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventNewActivity.java index ea5c23d3aa0..6dd7f82c1c7 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventNewActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventNewActivity.java @@ -27,6 +27,7 @@ import de.symeda.sormas.app.rest.RetroProvider; import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.util.ErrorReportingHelper; +import de.symeda.sormas.app.util.LocationService; import de.symeda.sormas.app.util.SyncCallback; import de.symeda.sormas.app.validation.EventValidator; @@ -62,6 +63,9 @@ protected void onCreate(Bundle savedInstanceState) { @Override protected void onResume() { + + LocationService.instance().requestFreshLocation(this); + super.onResume(); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventsListArrayAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventsListArrayAdapter.java index 2d8daaf58e7..6a3c9e8c55f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventsListArrayAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventsListArrayAdapter.java @@ -45,14 +45,9 @@ public View getView(int position, View convertView, ViewGroup parent) { uuid.setText(DataHelper.getShortUuid(event.getUuid())); TextView disease = (TextView) convertView.findViewById(R.id.eli_disease); - if(event.getDisease() != null) { - String diseaseName = event.getDisease().getName(); - disease.setText(Disease.valueOf(diseaseName).toShortString() + (event.getDisease() == Disease.OTHER ? " (" + event.getDiseaseDetails() + ")" : "")); - } else { - disease.setText(null); - } -// TextView eventStatus = (TextView) convertView.findViewById(R.id.eli_eventStatus); -// eventStatus.setText(event.getEventStatus()!=null?event.getEventStatus().toString():null); + disease.setText(event.getDisease() != Disease.OTHER + ? (event.getDisease() != null ? event.getDisease().toShortString() : "") + : DataHelper.toStringNullable(event.getDiseaseDetails())); TextView summary = (TextView) convertView.findViewById(R.id.eli_summary); StringBuilder sb = new StringBuilder(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/hospitalization/HospitalizationForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/hospitalization/HospitalizationForm.java index 92d6542296c..7cbbf8b8d22 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/hospitalization/HospitalizationForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/hospitalization/HospitalizationForm.java @@ -98,7 +98,7 @@ public void accept(Object prevHospDialog) { binding.hospitalizationAdmissionDate.initialize(this); binding.hospitalizationDischargeDate.initialize(this); - binding.hospitalization1isolationDate.initialize(this); + binding.hospitalizationIsolationDate.initialize(this); binding.hospitalizationHospitalizedPreviously.addValueChangedListener(new PropertyField.ValueChangeListener() { @Override @@ -110,7 +110,7 @@ public void onChange(PropertyField field) { binding.hospitalizationIsolated.addValueChangedListener(new PropertyField.ValueChangeListener() { @Override public void onChange(PropertyField field) { - binding.hospitalization1isolationDate.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); + binding.hospitalizationIsolationDate.setVisibility(field.getValue() == YesNoUnknown.YES ? View.VISIBLE : View.GONE); } }); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/person/PersonEditForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/person/PersonEditForm.java index b8085ba1e3b..2346e2c12b9 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/person/PersonEditForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/person/PersonEditForm.java @@ -40,7 +40,7 @@ import de.symeda.sormas.app.backend.region.District; import de.symeda.sormas.app.backend.region.Region; import de.symeda.sormas.app.component.FieldHelper; -import de.symeda.sormas.app.component.LocationDialog; +import de.symeda.sormas.app.component.LocationDialogBuilder; import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.component.SpinnerField; import de.symeda.sormas.app.component.TextField; @@ -140,7 +140,7 @@ public void onNothingSelected(AdapterView parent) { updateApproximateAgeField(); // ================ Address ================ - LocationDialog.addLocationField(getActivity(), person.getAddress(), binding.personAddress, binding.formCpBtnAddress, new Consumer() { + LocationDialogBuilder.addLocationField(getActivity(), person.getAddress(), binding.personAddress, binding.formCpBtnAddress, new Consumer() { @Override public void accept(Object parameter) { if(parameter instanceof Location) { @@ -153,7 +153,7 @@ public void accept(Object parameter) { // ================ Occupation ================ final TextField occupationDetails = binding.personOccupationDetails; - FieldHelper.initSpinnerField(binding.personOccupationType1, OccupationType.class, new AdapterView.OnItemSelectedListener() { + FieldHelper.initSpinnerField(binding.personOccupationType, OccupationType.class, new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { Item item = (Item)parent.getItemAtPosition(position); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/reports/WeeklyReportForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/reports/WeeklyReportForm.java index 9d0df97fd3e..aed30389fb8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/reports/WeeklyReportForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/reports/WeeklyReportForm.java @@ -183,7 +183,8 @@ public void onNothingSelected(AdapterView adapterView) { binding.weeklyReportShowLastWeek.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - EpiWeek epiWeek = DateHelper.getPreviousEpiWeek(new Date()); + Date now = new Date(); + EpiWeek epiWeek = DateHelper.getPreviousEpiWeek(now); binding.weeklyReportYear.setValue(epiWeek.getYear()); binding.weeklyReportWeek.setValue(epiWeek.getWeek()); } @@ -191,7 +192,9 @@ public void onClick(View view) { binding.weeklyReportShowThisWeek.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - EpiWeek epiWeek = DateHelper.getEpiWeek(new Date()); + Calendar epiCalendar = DateHelper.getEpiCalendar(); + Date now = new Date(); + EpiWeek epiWeek = DateHelper.getEpiWeek(now); binding.weeklyReportYear.setValue(epiWeek.getYear()); binding.weeklyReportWeek.setValue(epiWeek.getWeek()); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditActivity.java index 110f5ea5b71..ac3e24afee8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditActivity.java @@ -28,6 +28,7 @@ import de.symeda.sormas.app.rest.RetroProvider; import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.util.ErrorReportingHelper; +import de.symeda.sormas.app.util.LocationService; import de.symeda.sormas.app.util.SyncCallback; import de.symeda.sormas.app.validation.SampleValidator; @@ -52,16 +53,6 @@ public boolean isEditing() { return true; } - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - Bundle extras = intent.getExtras(); - if(extras != null) { - - } - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -79,25 +70,22 @@ protected void onCreate(Bundle savedInstanceState) { } params = getIntent().getExtras(); - if (params != null) { - if (params.containsKey(NEW_SAMPLE)) { - getSupportActionBar().setTitle(getResources().getText(R.string.headline_new_sample)); - } else { - getSupportActionBar().setTitle(getResources().getText(R.string.headline_sample)); + if (params.containsKey(NEW_SAMPLE)) { + getSupportActionBar().setTitle(getResources().getText(R.string.headline_new_sample)); + } else if (params.containsKey(KEY_SAMPLE_UUID)) { + getSupportActionBar().setTitle(getResources().getText(R.string.headline_sample)); + sampleUuid = params.getString(KEY_SAMPLE_UUID); + Sample initialEntity = DatabaseHelper.getSampleDao().queryUuid(sampleUuid); + // If the sample has been removed from the database in the meantime, redirect the user to the samples overview + if (initialEntity == null) { + Intent intent = new Intent(this, SamplesActivity.class); + startActivity(intent); + finish(); } - if (params.containsKey(KEY_SAMPLE_UUID)) { - sampleUuid = params.getString(KEY_SAMPLE_UUID); - Sample initialEntity = DatabaseHelper.getSampleDao().queryUuid(sampleUuid); - // If the sample has been removed from the database in the meantime, redirect the user to the samples overview - if (initialEntity == null) { - Intent intent = new Intent(this, SamplesActivity.class); - startActivity(intent); - finish(); - } - - DatabaseHelper.getSampleDao().markAsRead(initialEntity); - } + DatabaseHelper.getSampleDao().markAsRead(initialEntity); + } else { + throw new UnsupportedOperationException("SampleEditActivity needs either sampleUuid or newSample passed"); } setAdapter(); @@ -130,6 +118,9 @@ public void onClick(View view) { snackbar.show(); } } + else { + LocationService.instance().requestFreshLocation(this); + } } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListArrayAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListArrayAdapter.java index ce2302c0385..3befcb42d60 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListArrayAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListArrayAdapter.java @@ -11,6 +11,7 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.sample.SpecimenCondition; +import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.common.DatabaseHelper; @@ -49,8 +50,9 @@ public View getView(int position, View convertView, ViewGroup parent) { dateTime.setText(DateHelper.formatDate(sample.getSampleDateTime())); TextView disease = (TextView) convertView.findViewById(R.id.sample_disease_li); - disease.setText(sample.getAssociatedCase().getDisease().toShortString() + - (sample.getAssociatedCase().getDisease() == Disease.OTHER ? " (" + sample.getAssociatedCase().getDiseaseDetails() + ")" : "")); + disease.setText(sample.getAssociatedCase().getDisease() != Disease.OTHER + ? (sample.getAssociatedCase().getDisease() != null ? sample.getAssociatedCase().getDisease().toShortString() : "") + : DataHelper.toStringNullable(sample.getAssociatedCase().getDiseaseDetails())); TextView shipmentStatus = (TextView) convertView.findViewById(R.id.sample_shipment_status_li); if (sample.getReferredTo() != null) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/settings/SettingsActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/settings/SettingsActivity.java index dcdc4e64a06..4bd6f9c0852 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/settings/SettingsActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/settings/SettingsActivity.java @@ -99,6 +99,7 @@ public void openSyncLog(View view) { public void logout(View view) { ConfigProvider.clearUsernameAndPassword(); ConfigProvider.clearPin(); + ConfigProvider.setAccessGranted(false); Intent intent = new Intent(this, LoginActivity.class); startActivity(intent); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskEditActivity.java index 8e2db022417..2ebca89b109 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskEditActivity.java @@ -30,6 +30,7 @@ import de.symeda.sormas.app.rest.RetroProvider; import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.util.ErrorReportingHelper; +import de.symeda.sormas.app.util.LocationService; import de.symeda.sormas.app.util.SyncCallback; @@ -108,6 +109,8 @@ protected void onResume() { super.onResume(); taskForm.onResume(); + LocationService.instance().requestFreshLocation(this); + Task currentEntity = DatabaseHelper.getTaskDao().queryUuid(taskUuid); // If the task has been removed from the database in the meantime, redirect the user to the tasks overview if (currentEntity == null) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskForm.java index fcdc8065a4f..57570eb75c8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskForm.java @@ -87,7 +87,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, if (possibleStatusChanges.contains(TaskStatus.NOT_EXECUTABLE)) { binding.taskNotExecutableBtn.setVisibility(View.VISIBLE); - binding.taskNotExecutableBtn.setText(TaskStatus.NOT_EXECUTABLE.getChangeString()); + binding.taskNotExecutableBtn.setText(TaskStatus.NOT_EXECUTABLE.toString()); binding.taskNotExecutableBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -118,7 +118,7 @@ public void call() { if (possibleStatusChanges.contains(TaskStatus.DONE)) { binding.taskDoneBtn.setVisibility(View.VISIBLE); - binding.taskDoneBtn.setText(TaskStatus.DONE.getChangeString()); + binding.taskDoneBtn.setText(TaskStatus.DONE.toString()); binding.taskDoneBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskNotificationService.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskNotificationService.java index 14535a82542..d3fdb72c085 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskNotificationService.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskNotificationService.java @@ -117,7 +117,7 @@ public static void doTaskNotification(Context context) { EventDao eventDAO = DatabaseHelper.getEventDao(); PersonDao personDAO = DatabaseHelper.getPersonDao(); - for (Task task:taskList) { + for (Task task : taskList) { Intent notificationIntent = new Intent(context, TaskEditActivity.class); notificationIntent.putExtra(Task.UUID, task.getUuid()); @@ -163,7 +163,7 @@ public static void doTaskNotification(Context context) { Notification notification = new NotificationCompat.Builder(context) .setTicker(r.getString(R.string.headline_task_notification)) .setSmallIcon(R.mipmap.ic_launcher) - .setContentTitle(task.getTaskType().toString() + " (" + (caze != null ? caze.getDisease().toShortString() : contact != null ? contact.getCaze().getDisease().toShortString() : "") + ")") + .setContentTitle(task.getTaskType().toString() + (caze != null ? " (" + caze.getDisease().toShortString() + ")" : contact != null ? " (" + contact.getCaze().getDisease().toShortString() + ")" : "")) .setStyle(new NotificationCompat.BigTextStyle().bigText(Html.fromHtml(content.toString()))) .setContentIntent(pi) .setAutoCancel(true) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TasksListArrayAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TasksListArrayAdapter.java index 5588496ff40..0dfa2ee04da 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TasksListArrayAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TasksListArrayAdapter.java @@ -99,6 +99,8 @@ public View getView(int position, View convertView, ViewGroup parent) { sb.append(" (" + DataHelper.getShortUuid(task.getEvent().getUuid()) + ")"); sb.append(", " + task.getEvent().getEventDesc().substring(0, 15) + (task.getEvent().getEventDesc().length() > 15 ? "..." : "")); taskInfo.setText(sb.toString()); + } else { + taskInfo.setText(""); } TextView creatorComment = (TextView) convertView.findViewById(R.id.task_creatorComment_li); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/LocationDialogFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/LocationDialogFragment.java deleted file mode 100644 index 971641eb7f6..00000000000 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/LocationDialogFragment.java +++ /dev/null @@ -1,24 +0,0 @@ -package de.symeda.sormas.app.util; - -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import de.symeda.sormas.app.R; - -/** - * Created by Stefan Szczesny on 09.08.2016. - */ -public class LocationDialogFragment extends DialogFragment { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - int style = DialogFragment.STYLE_NORMAL, theme = 0; - setStyle(style, theme); - } - -} diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/LocationService.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/LocationService.java index 46785ab3a10..0ba3726b171 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/LocationService.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/LocationService.java @@ -1,109 +1,354 @@ package de.symeda.sormas.app.util; +import android.Manifest; +import android.app.Activity; import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.os.Looper; +import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; import android.util.Log; +import de.symeda.sormas.app.R; + /** * Created by Mate Strysewske on 16.08.2017. + * + * See https://developer.android.com/guide/topics/location/strategies.html for a guide */ -public class LocationService { +public final class LocationService { - // Minimum distance between two locations to trigger a new location update - private static final long MIN_DISTANCE_CHANGE = 100; // 100 metres - // Minimum time between updates - private static final long MIN_TIME_CHANGE = 1000 * 60 * 5; // 5 minutes + private static LocationService instance; + public static LocationService instance() { + return instance; + } - private static LocationService instance = null; + private Context context; - private LocationManager locationManager; - private Location location; + private Location bestKnownLocation = null; - public static LocationService getLocationService(Context context) { - if (instance == null) { - instance = new LocationService(context); - } - return instance; + private LocationService() { } /** - * Checks whether the SORMAS app has the permission to access the phone's location + * Creates a base request for GPS and network every 10 minutes when more than 100m moved * @param context - * @return */ - public boolean hasGPSAccess(Context context) { - if (instance == null) { - return false; + public static void init(Context context) { + if (instance != null) { + throw new UnsupportedOperationException("instance already initialized"); } + instance = new LocationService(); - if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - return false; + instance.context = context; + + LocationManager locationManager = (LocationManager) context.getSystemService(context.LOCATION_SERVICE); + + if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED) { + return; } - return true; + try { + if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { + return; + } + + LocationListener gpsBaseLocationListener = new BestKnownLocationListener(); + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000*60*20, 1000, gpsBaseLocationListener, Looper.getMainLooper()); + + LocationListener networkBaseLocationListener = new BestKnownLocationListener(); + locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000*60*20, 1000, networkBaseLocationListener, Looper.getMainLooper()); + + } catch (SecurityException e) { + Log.e(LocationService.class.getName(), "Error while initializing LocationService", e); + } } + int activeRequestCount = 0; + LocationListener gpsActiveLocationListener = null; + LocationListener networkActiveLocationListener = null; + /** - * Checks whether the phone's GPS is turned on - * @return + * Request network and GPS once a minute */ - public boolean hasGPSEnabled() { - if (instance == null) { - return false; + public void requestActiveLocationUpdates(Activity callingActivity) { + + activeRequestCount++; + + if (!validateGpsAccessAndEnabled(callingActivity)) { + return; } - return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + if (!isRequestingActiveLocationUpdates()) { + + if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED) { + return; + } + + LocationManager locationManager = (LocationManager) context.getSystemService(context.LOCATION_SERVICE); + + networkActiveLocationListener = new BestKnownLocationListener(); + locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000*60, 10, networkActiveLocationListener, Looper.getMainLooper()); + gpsActiveLocationListener = new BestKnownLocationListener(); + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000*60, 10, gpsActiveLocationListener, Looper.getMainLooper()); + } + } + + public void removeActiveLocationUpdates() { + + if (activeRequestCount <= 0) { + throw new UnsupportedOperationException("removeActiveLocationUpdates was called although no active request exists"); + } + + activeRequestCount--; + + if (activeRequestCount == 0 && isRequestingActiveLocationUpdates()) { + + LocationManager locationManager = (LocationManager) context.getSystemService(context.LOCATION_SERVICE); + + locationManager.removeUpdates(networkActiveLocationListener); + networkActiveLocationListener = null; + locationManager.removeUpdates(gpsActiveLocationListener); + gpsActiveLocationListener = null; + } } - private LocationService(Context context) { - initLocationService(context); + public boolean isRequestingActiveLocationUpdates() { + return gpsActiveLocationListener != null; } - private void initLocationService(Context context) { - locationManager = (LocationManager) context.getSystemService(context.LOCATION_SERVICE); + public void requestFreshLocation(Activity callingActivity) { + + if (!validateGpsAccessAndEnabled(callingActivity)) { + return; + } + // just for compiler reasons if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED) { return; } - try { - if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { - return; + LocationManager locationManager = (LocationManager) context.getSystemService(context.LOCATION_SERVICE); + locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, new BestKnownLocationListener(), Looper.getMainLooper()); + locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, new BestKnownLocationListener(), Looper.getMainLooper()); + } + + public static final class BestKnownLocationListener implements LocationListener { + + @Override + public void onLocationChanged(Location location) { + if (isBetterLocation(location, instance.bestKnownLocation)) { + instance.bestKnownLocation = location; } + } - LocationListener locationListener = new LocationListener() { - @Override - public void onLocationChanged(Location location) { - LocationService.this.location = location; - } - @Override - public void onStatusChanged(String s, int i, Bundle bundle) { - } - @Override - public void onProviderEnabled(String s) { - } - @Override - public void onProviderDisabled(String s) { - } - }; + @Override + public void onStatusChanged(String s, int i, Bundle bundle) { - locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_CHANGE, MIN_DISTANCE_CHANGE, locationListener, Looper.getMainLooper()); + } + + @Override + public void onProviderEnabled(String s) { - // Request initial GPS location - locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, locationListener, Looper.getMainLooper()); - } catch (SecurityException e) { - Log.e(getClass().getName(), "Error while initializing LocationService", e); } + + @Override + public void onProviderDisabled(String s) { + // TODO should we do something about this? + } + } + + public Location getLocation(Activity callingActivity) { + + if (!validateGpsAccessAndEnabled(callingActivity)) { + return null; + } + + return getLocation(); } public Location getLocation() { - return location; + + // just for compiler reasons + if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED) { + return null; + } + + LocationManager locationManager = (LocationManager) context.getSystemService(context.LOCATION_SERVICE); + + Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + if (isBetterLocation(location, bestKnownLocation)) { + bestKnownLocation = location; + } else { + location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + if (isBetterLocation(location, bestKnownLocation)) { + bestKnownLocation = location; + } + } + + return bestKnownLocation; + } + + private static final int SIGNIFICANTLY_NEWER_DELTA = 1000 * 60 * 2; + + /** Determines whether one Location reading is better than the current Location fix + * @param location The new Location that you want to evaluate + * @param currentBestLocation The current Location fix, to which you want to compare the new one + */ + protected static boolean isBetterLocation(Location location, Location currentBestLocation) { + if (currentBestLocation == null) { + // A new location is always better than no location + return true; + } + if (location == null) { + return false; + } + + // Check whether the new location fix is newer or older + long timeDelta = location.getTime() - currentBestLocation.getTime(); + boolean isSignificantlyNewer = timeDelta > SIGNIFICANTLY_NEWER_DELTA; + boolean isSignificantlyOlder = timeDelta < -SIGNIFICANTLY_NEWER_DELTA; + boolean isNewer = timeDelta > 0; + + // If it's been more than two minutes since the current location, use the new location + // because the user has likely moved + if (isSignificantlyNewer) { + return true; + // If the new location is more than two minutes older, it must be worse + } else if (isSignificantlyOlder) { + return false; + } + + // Check whether the new location fix is more or less accurate + int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy()); + boolean isLessAccurate = accuracyDelta > 0; + boolean isMoreAccurate = accuracyDelta < 0; + boolean isSignificantlyLessAccurate = accuracyDelta > 200; + + // Check if the old and new location are from the same provider + boolean isFromSameProvider = isSameProvider(location.getProvider(), + currentBestLocation.getProvider()); + + // Determine location quality using a combination of timeliness and accuracy + if (isMoreAccurate) { + return true; + } else if (isNewer && !isLessAccurate) { + return true; + } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { + return true; + } + return false; + } + + /** Checks whether two providers are the same */ + private static boolean isSameProvider(String provider1, String provider2) { + if (provider1 == null) { + return provider2 == null; + } + return provider1.equals(provider2); } + /** + * Checks whether the SORMAS app has the permission to access the phone's location + */ + public boolean hasGpsAccess() { + return ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; + } + + /** + * Checks whether the phone's GPS is turned on + * @return + */ + public boolean hasGpsEnabled() { + LocationManager locationManager = (LocationManager) context.getSystemService(context.LOCATION_SERVICE); + return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + } + + public boolean validateGpsAccessAndEnabled(final Activity callingActivity) { + + if (!LocationService.instance().hasGpsAccess()) { + AlertDialog requestPermissionDialog = buildRequestGpsAccessDialog(callingActivity); + requestPermissionDialog.show(); + return false; + } + + if (!LocationService.instance().hasGpsEnabled()) { + AlertDialog turnOnGPSDialog = buildEnableGpsDialog(callingActivity); + turnOnGPSDialog.show(); + return false; + } + + return true; + } + + private AlertDialog buildRequestGpsAccessDialog(final Activity callingActivity) { + AlertDialog.Builder builder = new AlertDialog.Builder(callingActivity); + builder.setCancelable(false); + builder.setMessage(R.string.alert_gps_permission); + builder.setTitle(R.string.alert_title_gps_permission); + builder.setIcon(R.drawable.ic_perm_device_information_black_24dp); + AlertDialog dialog = builder.create(); + dialog.setButton(AlertDialog.BUTTON_POSITIVE, callingActivity.getString(R.string.action_close_app), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Activity finishActivity = callingActivity; + do { + finishActivity.finish(); + finishActivity = finishActivity.getParent(); + } while (finishActivity != null); + } + } + ); + dialog.setButton(AlertDialog.BUTTON_NEGATIVE, callingActivity.getString(R.string.action_allow_gps_access), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ActivityCompat.requestPermissions(callingActivity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 9999); + } + } + ); + + return dialog; + } + + public AlertDialog buildEnableGpsDialog(final Activity callingActivity) { + AlertDialog.Builder builder = new AlertDialog.Builder(callingActivity); + builder.setCancelable(false); + builder.setMessage(R.string.alert_gps); + builder.setTitle(R.string.alert_title_gps); + builder.setIcon(R.drawable.ic_location_on_black_24dp); + AlertDialog dialog = builder.create(); + dialog.setButton(AlertDialog.BUTTON_POSITIVE, callingActivity.getString(R.string.action_close_app), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Activity finishActivity = callingActivity; + do { + finishActivity.finish(); + finishActivity = finishActivity.getParent(); + } while (finishActivity != null); + } + } + ); + dialog.setButton(AlertDialog.BUTTON_NEGATIVE, callingActivity.getString(R.string.action_turn_on_gps), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Intent gpsOptionsIntent = new Intent( + android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); + callingActivity.startActivity(gpsOptionsIntent); + } + } + ); + + return dialog; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SymptomsValidator.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SymptomsValidator.java index 0b34bba69e5..3783b6d483a 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SymptomsValidator.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SymptomsValidator.java @@ -6,12 +6,16 @@ import java.util.Arrays; import java.util.List; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.symptoms.SymptomState; +import de.symeda.sormas.api.symptoms.SymptomsDto; +import de.symeda.sormas.api.utils.Diseases; import de.symeda.sormas.api.visit.VisitStatus; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.symptoms.Symptoms; import de.symeda.sormas.app.backend.visit.Visit; +import de.symeda.sormas.app.component.CheckBoxField; import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.component.SymptomStateField; import de.symeda.sormas.app.databinding.CaseSymptomsFragmentLayoutBinding; @@ -28,11 +32,23 @@ public static boolean validateCaseSymptoms(Symptoms symptoms, CaseSymptomsFragme List nonConditionalSymptoms = getNonConditionalSymptoms(binding); List conditionalBleedingSymptoms = getConditionalBleedingSymptoms(binding); + List lesionsFields = getLesionsFields(binding); + List monkeypoxFields = getMonkeypoxFields(binding); + + // Location where patient got ill + if (binding.symptomsPatientIllLocation.getVisibility() == View.VISIBLE) { + if (isAnySymptomSetTo(SymptomState.YES, nonConditionalSymptoms)) { + if (symptoms.getPatientIllLocation() == null || symptoms.getPatientIllLocation().trim().isEmpty()) { + binding.symptomsPatientIllLocation.setError(resources.getString(R.string.validation_symptoms_patient_ill_location)); + success = false; + } + } + } // Date of initial symptom onset & initial onset symptom if (isAnySymptomSetTo(SymptomState.YES, nonConditionalSymptoms)) { if (symptoms.getOnsetSymptom() == null) { - binding.symptomsOnsetSymptom1.setError(resources.getString(R.string.validation_symptoms_onset_symptom)); + binding.symptomsOnsetSymptom.setError(resources.getString(R.string.validation_symptoms_onset_symptom)); success = false; } if (symptoms.getOnsetDate() == null) { @@ -62,6 +78,20 @@ public static boolean validateCaseSymptoms(Symptoms symptoms, CaseSymptomsFragme } } + // Lesions fields + if (symptoms.getLesions() == SymptomState.YES) { + if (markAnySymptomSetTo(null, lesionsFields, resources)) { + success = false; + } + } + + // Monkeypox fields + if (symptoms.getLesions() == SymptomState.YES) { + if (markAnySymptomSetTo(null, monkeypoxFields, resources)) { + success = false; + } + } + return success; } @@ -72,11 +102,13 @@ public static boolean validateVisitSymptoms(Visit visit, Symptoms symptoms, Case List nonConditionalSymptoms = getNonConditionalSymptoms(binding); List conditionalBleedingSymptoms = getConditionalBleedingSymptoms(binding); + List lesionsFields = getLesionsFields(binding); + List monkeypoxFields = getMonkeypoxFields(binding); // Onset symptom & date if (isAnySymptomSetTo(SymptomState.YES, nonConditionalSymptoms)) { if (symptoms.getOnsetSymptom() == null) { - binding.symptomsOnsetSymptom1.setError(resources.getString(R.string.validation_symptoms_onset_symptom)); + binding.symptomsOnsetSymptom.setError(resources.getString(R.string.validation_symptoms_onset_symptom)); success = false; } if (symptoms.getOnsetDate() == null) { @@ -106,6 +138,20 @@ public static boolean validateVisitSymptoms(Visit visit, Symptoms symptoms, Case } } + // Lesions fields + if (symptoms.getLesions() == SymptomState.YES) { + if (markAnySymptomSetTo(null, lesionsFields, resources)) { + success = false; + } + } + + // Monkeypox fields + if (symptoms.getLesions() == SymptomState.YES) { + if (markAnySymptomSetTo(null, monkeypoxFields, resources)) { + success = false; + } + } + if (visit.getVisitStatus() == VisitStatus.COOPERATIVE) { // Non-conditional symptoms if (markAnySymptomSetTo(null, nonConditionalSymptoms, resources)) { @@ -143,6 +189,14 @@ public static void clearErrorsForSymptoms(CaseSymptomsFragmentLayoutBinding bind for (PropertyField field : getOtherSymptomsFields(binding)) { field.clearError(); } + + for (PropertyField field : getLesionsFields(binding)) { + field.clearError(); + } + + for (PropertyField field : getMonkeypoxFields(binding)) { + field.clearError(); + } } public static void setRequiredHintsForCaseSymptoms(CaseSymptomsFragmentLayoutBinding binding) { @@ -151,14 +205,21 @@ public static void setRequiredHintsForCaseSymptoms(CaseSymptomsFragmentLayoutBin // Set required hints if (isAnySymptomSetTo(SymptomState.YES, getNonConditionalSymptoms(binding))) { - binding.symptomsOnsetSymptom1.setRequiredHint(true); + binding.symptomsOnsetSymptom.setRequiredHint(true); binding.symptomsOnsetDate.setRequiredHint(true); + binding.symptomsPatientIllLocation.setRequiredHint(true); } // Always required because these fields are only visible when they are actually required for (SymptomStateField field : getConditionalBleedingSymptoms(binding)) { field.setRequiredHint(true); } + for (SymptomStateField symptom : getLesionsFields(binding)) { + symptom.setRequiredHint(true); + } + for (SymptomStateField symptom : getMonkeypoxFields(binding)) { + symptom.setRequiredHint(true); + } binding.symptomsOther1NonHemorrhagicSymptomsText.setRequiredHint(true); binding.symptomsOther1HemorrhagicSymptomsText.setRequiredHint(true); } @@ -177,7 +238,7 @@ public static void setRequiredHintsForVisitSymptoms(boolean cooperative, CaseSym } if (isAnySymptomSetTo(SymptomState.YES, getNonConditionalSymptoms(binding))) { - binding.symptomsOnsetSymptom1.setRequiredHint(true); + binding.symptomsOnsetSymptom.setRequiredHint(true); binding.symptomsOnsetDate.setRequiredHint(true); } @@ -185,6 +246,12 @@ public static void setRequiredHintsForVisitSymptoms(boolean cooperative, CaseSym for (SymptomStateField field : getConditionalBleedingSymptoms(binding)) { field.setRequiredHint(true); } + for (SymptomStateField symptom : getLesionsFields(binding)) { + symptom.setRequiredHint(true); + } + for (SymptomStateField symptom : getMonkeypoxFields(binding)) { + symptom.setRequiredHint(true); + } binding.symptomsOther1NonHemorrhagicSymptomsText.setRequiredHint(true); binding.symptomsOther1HemorrhagicSymptomsText.setRequiredHint(true); } @@ -200,30 +267,46 @@ private static void resetRequiredHints(CaseSymptomsFragmentLayoutBinding binding for (PropertyField field : getOtherSymptomsFields(binding)) { field.setRequiredHint(false); } + for (SymptomStateField field : getLesionsFields(binding)) { + field.setRequiredHint(false); + } + for (SymptomStateField field : getMonkeypoxFields(binding)) { + field.setRequiredHint(false); + } } private static List getNonConditionalSymptoms(CaseSymptomsFragmentLayoutBinding binding) { // These should be in reverse order of how they're displayed on the screen return Arrays.asList(binding.symptomsFever, binding.symptomsVomiting, - binding.symptomsDiarrhea, binding.symptomsBloodInStool1, binding.symptomsNausea, binding.symptomsAbdominalPain, + binding.symptomsDiarrhea, binding.symptomsBloodInStool, binding.symptomsNausea, binding.symptomsAbdominalPain, binding.symptomsHeadache, binding.symptomsMusclePain, binding.symptomsFatigueWeakness, binding.symptomsUnexplainedBleeding, binding.symptomsSkinRash, binding.symptomsNeckStiffness, binding.symptomsSoreThroat, binding.symptomsCough, binding.symptomsRunnyNose, binding.symptomsDifficultyBreathing, binding.symptomsChestPain, binding.symptomsConfusedDisoriented, binding.symptomsSeizures, binding.symptomsAlteredConsciousness, binding.symptomsConjunctivitis, - binding.symptomsEyePainLightSensitive, binding.symptomsKopliksSpots1, binding.symptomsThrobocytopenia, + binding.symptomsEyePainLightSensitive, binding.symptomsKopliksSpots, binding.symptomsThrobocytopenia, binding.symptomsOtitisMedia, binding.symptomsHearingloss, binding.symptomsDehydration, binding.symptomsAnorexiaAppetiteLoss, binding.symptomsRefusalFeedorDrink, binding.symptomsJointPain, binding.symptomsShock, binding.symptomsHiccups, binding.symptomsBackache, binding.symptomsEyesBleeding, binding.symptomsJaundice, binding.symptomsDarkUrine, binding.symptomsStomachBleeding, binding.symptomsRapidBreathing, binding.symptomsSwollenGlands, - binding.symptomsOtherNonHemorrhagicSymptoms); + binding.symptomsOtherNonHemorrhagicSymptoms, binding.symptomsCutaneousEruption, binding.symptomsLesions, binding.symptomsLymphadenopathyAxillary, + binding.symptomsLymphadenopathyCervical, binding.symptomsLymphadenopathyInguinal, binding.symptomsChillsSweats, binding.symptomsBedridden, + binding.symptomsOralUlcers); } private static List getConditionalBleedingSymptoms(CaseSymptomsFragmentLayoutBinding binding) { // These should be in reverse order of how they're displayed on the screen - return Arrays.asList(binding.symptomsGumsBleeding1, binding.symptomsInjectionSiteBleeding, - binding.symptomsNoseBleeding1, binding.symptomsBloodyBlackStool, binding.symptomsRedBloodVomit, + return Arrays.asList(binding.symptomsGumsBleeding, binding.symptomsInjectionSiteBleeding, + binding.symptomsNoseBleeding, binding.symptomsBloodyBlackStool, binding.symptomsRedBloodVomit, binding.symptomsDigestedBloodVomit, binding.symptomsCoughingBlood, binding.symptomsBleedingVagina, - binding.symptomsSkinBruising1, binding.symptomsBloodUrine, binding.symptomsOtherHemorrhagicSymptoms); + binding.symptomsSkinBruising, binding.symptomsBloodUrine, binding.symptomsOtherHemorrhagicSymptoms); + } + + private static List getLesionsFields(CaseSymptomsFragmentLayoutBinding binding) { + return Arrays.asList(binding.symptomsLesionsSameState, binding.symptomsLesionsSameSize, binding.symptomsLesionsDeepProfound, binding.symptomsLesionsThatItch); + } + + private static List getMonkeypoxFields(CaseSymptomsFragmentLayoutBinding binding) { + return Arrays.asList(binding.symptomsLesionsResembleImg1, binding.symptomsLesionsResembleImg2, binding.symptomsLesionsResembleImg3, binding.symptomsLesionsResembleImg4); } public static boolean isSymptomatic(CaseSymptomsFragmentLayoutBinding binding) { @@ -232,9 +315,9 @@ public static boolean isSymptomatic(CaseSymptomsFragmentLayoutBinding binding) { } private static List> getOtherSymptomsFields(CaseSymptomsFragmentLayoutBinding binding) { - return Arrays.asList(binding.symptomsOnsetDate, binding.symptomsOnsetSymptom1, + return Arrays.asList(binding.symptomsOnsetDate, binding.symptomsOnsetSymptom, binding.symptomsOther1HemorrhagicSymptomsText, binding.symptomsOther1NonHemorrhagicSymptomsText, - binding.symptomsTemperature, binding.symptomsTemperatureSource); + binding.symptomsTemperature, binding.symptomsTemperatureSource, binding.symptomsPatientIllLocation); } /** @@ -255,9 +338,9 @@ private static boolean isAnySymptomSetTo(SymptomState reqSymptomState, List conditionalBleedingSymptoms, Resources resources) { + private static boolean markAnySymptomSetTo(SymptomState reqSymptomState, List symptomsList, Resources resources) { boolean fieldMarked = false; - for(SymptomStateField field : conditionalBleedingSymptoms) { + for(SymptomStateField field : symptomsList) { if(field.getVisibility() == View.VISIBLE && field.getValue() == reqSymptomState) { field.setError(resources.getString(R.string.validation_symptoms_symptom)); fieldMarked = true; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditActivity.java index 6d68846311b..558510c3d12 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditActivity.java @@ -34,6 +34,7 @@ import de.symeda.sormas.app.rest.RetroProvider; import de.symeda.sormas.app.rest.SynchronizeDataAsync; import de.symeda.sormas.app.util.ErrorReportingHelper; +import de.symeda.sormas.app.util.LocationService; import de.symeda.sormas.app.util.SyncCallback; import de.symeda.sormas.app.validation.SymptomsValidator; import de.symeda.sormas.app.validation.VisitValidator; @@ -121,6 +122,9 @@ public void onClick(View view) { snackbar.show(); } } + else { + LocationService.instance().requestFreshLocation(this); + } } @Override @@ -196,7 +200,7 @@ public boolean onOptionsItemSelected(MenuItem item) { // Necessary because the entry could've been automatically set, in which case the setValue method of the // custom field has not been called - symptoms.setOnsetSymptom((String) symptomsBinding.symptomsOnsetSymptom1.getValue()); + symptoms.setOnsetSymptom((String) symptomsBinding.symptomsOnsetSymptom.getValue()); VisitValidator.clearErrorsForVisitData(visitDataBinding); SymptomsValidator.clearErrorsForSymptoms(symptomsBinding); diff --git a/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_1.png b/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_1.png new file mode 100644 index 00000000000..9db71d5eb62 Binary files /dev/null and b/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_1.png differ diff --git a/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_2.png b/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_2.png new file mode 100644 index 00000000000..b97ac955054 Binary files /dev/null and b/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_2.png differ diff --git a/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_3.png b/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_3.png new file mode 100644 index 00000000000..12f9efb5165 Binary files /dev/null and b/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_3.png differ diff --git a/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_4.png b/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_4.png new file mode 100644 index 00000000000..2ab8ee78eb7 Binary files /dev/null and b/sormas-app/app/src/main/res/drawable-ldpi/monkeypox_lesions_4.png differ diff --git a/sormas-app/app/src/main/res/layout/case_data_fragment_layout.xml b/sormas-app/app/src/main/res/layout/case_data_fragment_layout.xml index 45457cfb9e7..6db55852f98 100644 --- a/sormas-app/app/src/main/res/layout/case_data_fragment_layout.xml +++ b/sormas-app/app/src/main/res/layout/case_data_fragment_layout.xml @@ -271,6 +271,12 @@ android:paddingBottom="@dimen/field_padding" android:value="@={caze.yellowFeverVaccinationInfoSource}"/> + + + + + + + + + + + + @@ -146,6 +146,12 @@ android:layout_height="match_parent" android:value="@={symptoms.chestPain}"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -359,7 +573,7 @@ android:value="@={symptoms.bloodyBlackStool}"/> @@ -383,7 +597,7 @@ android:value="@={symptoms.redBloodVomit}"/> @@ -466,84 +680,20 @@ android:value="@={symptoms.onsetDate}"/> - - - - - - - - - - - - - - - - - - - + android:value="@={symptoms.patientIllLocation}"/> diff --git a/sormas-app/app/src/main/res/layout/field_yes_no_vertical.xml b/sormas-app/app/src/main/res/layout/field_yes_no_vertical.xml index 2f55515d028..30bea7bbbdb 100644 --- a/sormas-app/app/src/main/res/layout/field_yes_no_vertical.xml +++ b/sormas-app/app/src/main/res/layout/field_yes_no_vertical.xml @@ -2,6 +2,7 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:descendantFocusability="beforeDescendants"> @@ -86,45 +87,29 @@ - \ No newline at end of file diff --git a/sormas-app/app/src/main/res/layout/person_edit_fragment_layout.xml b/sormas-app/app/src/main/res/layout/person_edit_fragment_layout.xml index 2c0323b08b4..6e1cb499aeb 100644 --- a/sormas-app/app/src/main/res/layout/person_edit_fragment_layout.xml +++ b/sormas-app/app/src/main/res/layout/person_edit_fragment_layout.xml @@ -82,15 +82,16 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> + + android:value="@={person.birthdateYYYY}"/> - + android:value="@={person.birthdateDD}"/> - - + android:layout_marginBottom="12dp" + > + + - - + android:layout_marginBottom="24dp" + app:passwordToggleEnabled="true" + > + +