diff --git a/CHANGELOG.md b/CHANGELOG.md index 14f37a94..9270a9be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [2.9.19] - 2021-03-12 +### Changed +- Disable Accept/Revoke buttons initially in Pending Family Members popup. +- Changed permission request buttons to "Continue" [#560](https://github.com/rokwire/safer-illinois-app/issues/560) +- Apply WWCL.Disclaimers in Safer app [#562](https://github.com/rokwire/safer-illinois-app/issues/562) +- Maine health history change [#563](https://github.com/rokwire/safer-illinois-app/issues/563) + +### Fixed +- Health rules file. [#567](https://github.com/rokwire/safer-illinois-app/issues/567) + ## [2.9.18] - 2021-03-09 ### Added - Fire Analytics events in Pending Family Members popup. diff --git a/assets/health.rules.json b/assets/health.rules.json index 014d6862..254dc203 100644 --- a/assets/health.rules.json +++ b/assets/health.rules.json @@ -14,11 +14,11 @@ }, "statuses": { - "PCR.xpositive": { - "health_status": "red", - "priority": 11, - "next_step_html": "positive.step.html" - }, + "PCR.xpositive": { + "health_status": "red", + "priority": 11, + "next_step_html": "positive.step.html" + }, "PCR.positive": { "condition": "timeout", "params": { @@ -42,7 +42,7 @@ "next_step_html": "positive.step.html" } }, - + "PCR.positive-IP": { "condition": "timeout", "params": { @@ -166,7 +166,7 @@ }, "PCR.negative": "test-monitor", - + "PCR.invalid": { "condition": "require-test", "params": { @@ -257,7 +257,7 @@ } } }, - + "force-test": { "condition": "require-test", "params": { @@ -296,7 +296,7 @@ "reason": "test.required.reason" } }, - + "symptoms-match": { "health_status": "orange", "priority": 1, @@ -330,7 +330,7 @@ "reason": "exposure.reason" } }, - + "quarantine-on": { "health_status": "orange", "priority": 10, @@ -355,7 +355,7 @@ "next_step": "test.resume.step", "next_step_interval": "UserTestMonitorInterval", "warning": "test.future.warning" - }, + }, "fail": { "health_status": "orange", "priority": -1, @@ -380,7 +380,7 @@ "next_step": "test.resume.step", "next_step_interval": "UndergraduateTestMonitorInterval", "warning": "test.future.warning" - }, + }, "fail": { "health_status": "orange", "priority": -1, @@ -408,7 +408,7 @@ } } } - }, + }, "out-of-test-compliance": { "condition": "require-test", @@ -430,12 +430,12 @@ } }, - "release": { - "health_status": "orange", - "priority": -1, - "next_step": "release.step", - "reason": "release.reason" - } + "release": { + "health_status": "orange", + "priority": -1, + "next_step": "release.step", + "reason": "release.reason" + } }, "tests" : { @@ -495,36 +495,43 @@ { "result": "POSITIVE", "category": "PCR.positive", + "disclaimer_html": null, "status": "PCR.positive" }, { "result": "POSITIVE-IP", "category": "PCR.positive", + "disclaimer_html": null, "status": "PCR.positive-IP" }, { "result": "POSITIVE-NIP", "category": "PCR.negative", + "disclaimer_html": null, "status": "PCR.positive-NIP" }, { "result": "NEGATIVE", "category": "PCR.negative", + "disclaimer_html": null, "status": "PCR.negative" }, { "result": "INVALID", "category": "PCR.invalid", + "disclaimer_html": null, "status": "PCR.invalid" }, { "result": "INCONCLUSIVE", "category": "PCR.invalid", + "disclaimer_html": null, "status": "PCR.invalid" }, { "result": "REJECTED", "category": "PCR.invalid", + "disclaimer_html": null, "status": "PCR.invalid" } ] @@ -646,7 +653,7 @@ } ] }, - + "symptoms": { "rules": [ { @@ -662,7 +669,7 @@ "status": "symptoms-match" } ], - + "groups": [ { "id": null, @@ -765,7 +772,7 @@ } ] }, - + "contact_trace": { "rules": [ { @@ -774,7 +781,7 @@ } ] }, - + "actions": { "rules": [ { @@ -823,15 +830,15 @@ "test.resume.step": "Resume testing on your assigned days", "test.future.warning": "You will turn orange/access denied if no negative test by {next_step_date}.", "test.past.reason": "Your status changed to Orange because you are past due for another test.", - "test.multiple.step.html": "

You must take two on-campus tests by Jan. 25.

See testing schedule and rules.

", + "test.multiple.step.html": "

You must take two on-campus tests by Jan. 25.

See testing schedule and rules.

", "symptoms.step": "Take a COVID-19 test now", "symptoms.reason": "Your status changed to Orange because you self-reported symptoms consistent with the virus.", "exposure.step.html": "

You have likely been exposed to a person who is infected with COVID-19.

", "exposure.reason": "Your status changed to Orange because you received an exposure notification.", "quarantine-on.step": "Stay at home and avoid contacts", "quarantine-on.reason": "Your status changed to Orange because the Public Health department placed you in Quarantine.", - "release.step": "Take a SHIELD Saliva Test", - "release.reason": "Your status changed to Orange because the Public Health department requires you to take a test.", + "release.step": "Take a SHIELD Saliva Test", + "release.reason": "Your status changed to Orange because the Public Health department requires you to take a test.", "symptoms.no-symptoms": "No symptoms", "symptoms.fever": "Fever", "symptoms.chills": "Chills", @@ -850,7 +857,12 @@ "symptoms.sore-throat": "Sore Throat", "symptoms.congestion-or-runny-nose": "Congestion or runny nose", "symptoms.nausea-or-vomiting": "Nausea or vomiting", - "symptoms.diarrhea":"Diarrhea" + "symptoms.diarrhea":"Diarrhea", + "disclaimers.covid-19_pcr.positive.html": "", + "disclaimers.covid-19_pcr.negative.html": "", + "disclaimers.covid-19_pcr.invalid.html": "", + "disclaimers.covid-19_pcr.inconclusive.html": "", + "disclaimers.covid-19_pcr.rejected.html": "" }, "es": { "default.step": "Realice una prueba de saliva SHIELD cuando regrese al campus.", @@ -870,15 +882,15 @@ "test.resume.step": "Reanudar las pruebas en los días asignados", "test.future.warning": "Se volverá naranja / acceso denegado si no hay una prueba negativa antes del {next_step_date}.", "test.past.reason": "Su estado cambió a Naranja porque está atrasado para otro examen.", - "test.multiple.step.html": "

Debes de tomar dos pruebas en el campus antes del 25 de enero.

Ver el calendario y las reglas de las pruebas.

", + "test.multiple.step.html": "

Debes de tomar dos pruebas en el campus antes del 25 de enero.

Ver el calendario y las reglas de las pruebas.

", "symptoms.step": "Realice una prueba de COVID-19 ahora", "symptoms.reason": "Su estado cambió a Naranja porque usted mismo informó de síntomas consistentes con el virus.", "exposure.step.html": "

Es probable que haya estado expuesto a una persona infectada con COVID-19.

", "exposure.reason": "Su estado cambió a Naranja porque recibió una notificación de exposición.", "quarantine-on.step": "Quédese en casa y evite los contactos", "quarantine-on.reason": "Su estado cambió a Orange porque el departamento de Salud Pública lo puso en cuarentena.", - "release.step": "Realice una prueba de saliva SHIELD", - "release.reason": "Su estado cambió a Orange porque el departamento de Salud Pública requiere que tome una prueba.", + "release.step": "Realice una prueba de saliva SHIELD", + "release.reason": "Su estado cambió a Orange porque el departamento de Salud Pública requiere que tome una prueba.", "symptoms.no-symptoms": "Sin síntomas", "symptoms.fever": "Fiebre", "symptoms.chills": "Resfriado", @@ -897,7 +909,12 @@ "symptoms.sore-throat": "Dolor de garganta", "symptoms.congestion-or-runny-nose": "Congestión o secreción nasal", "symptoms.nausea-or-vomiting": "Náuseas o vómitos", - "symptoms.diarrhea": "Diarrea" + "symptoms.diarrhea": "Diarrea", + "disclaimers.covid-19_pcr.positive.html": "", + "disclaimers.covid-19_pcr.negative.html": "", + "disclaimers.covid-19_pcr.invalid.html": "", + "disclaimers.covid-19_pcr.inconclusive.html": "", + "disclaimers.covid-19_pcr.rejected.html": "" }, "zh": { "default.step": "返回校園後,請參加SHIELD唾液測試。", @@ -944,7 +961,12 @@ "symptoms.sore-throat": "咽喉痛", "symptoms.congestion-or-runny-nose": "充血或流鼻涕", "symptoms.nausea-or-vomiting": "噁心或嘔吐", - "symptoms.diarrhea":"腹瀉" + "symptoms.diarrhea":"腹瀉", + "disclaimers.covid-19_pcr.positive.html": "", + "disclaimers.covid-19_pcr.negative.html": "", + "disclaimers.covid-19_pcr.invalid.html": "", + "disclaimers.covid-19_pcr.inconclusive.html": "", + "disclaimers.covid-19_pcr.rejected.html": "" } } } diff --git a/assets/strings.en.json b/assets/strings.en.json index 596d5126..788f9a09 100644 --- a/assets/strings.en.json +++ b/assets/strings.en.json @@ -60,7 +60,7 @@ "panel.onboarding.location.label.title": "Turn on Location Services", "panel.onboarding.location.label.title.hint": "Header 1", "panel.onboarding.location.label.description": "Background location is required for Bluetooth-based exposure notification to work on your phone", - "panel.onboarding.location.button.allow.title": "Enable Location Services", + "panel.onboarding.location.button.allow.title": "Continue", "panel.onboarding.location.button.allow.hint": "", "panel.onboarding.location.button.dont_allow.title": "Not right now", "panel.onboarding.location.button.dont_allow.hint": "Skip sharing location", @@ -70,7 +70,7 @@ "panel.onboarding.bluetooth.label.title": "Enable Bluetooth", "panel.onboarding.bluetooth.label.title.hint": "Header 1", "panel.onboarding.bluetooth.label.description": "Use Bluetooth to alert you to potential exposure to COVID-19.", - "panel.onboarding.bluetooth.button.allow.title": "Enable Bluetooth", + "panel.onboarding.bluetooth.button.allow.title": "Continue", "panel.onboarding.bluetooth.button.allow.hint": "", "panel.onboarding.bluetooth.button.dont_allow.title": "Not right now", "panel.onboarding.bluetooth.button.dont_allow.hint": "Skip enabling Bluetooth", @@ -81,7 +81,7 @@ "panel.onboarding.notifications.label.title.hint": "Header 1", "panel.onboarding.notifications.label.description1": "Get notified about COVID-19 info", "panel.onboarding.notifications.label.description2": "This is required for Exposure Notifications to work in background on your phone", - "panel.onboarding.notifications.button.allow.title": "Enable Notifications", + "panel.onboarding.notifications.button.allow.title": "Continue", "panel.onboarding.notifications.button.allow.hint": "", "panel.onboarding.notifications.button.dont_allow.title": "Not right now", "panel.onboarding.notifications.button.dont_allow.hint": "Skip receiving notifications", @@ -588,7 +588,7 @@ "panel.health.covid19.history.label.contact_trace.details": "contact trace: ", "panel.health.covid19.history.label.action.title": "Action Required", "panel.health.covid19.history.label.action.details": "action: ", - "panel.health.covid19.history.label.result.title": "Result: ", + "panel.health.covid19.history.label.result.title": "Result", "panel.health.covid19.history.label.location.title": "Test Location", "panel.health.covid19.history.label.technician_name.title": "Technician Name", "panel.health.covid19.history.label.technician_id.title": "Technician ID", diff --git a/assets/strings.es.json b/assets/strings.es.json index 48418613..03ed2fc4 100644 --- a/assets/strings.es.json +++ b/assets/strings.es.json @@ -60,7 +60,7 @@ "panel.onboarding.location.label.title": "Activar los servicios de ubicación", "panel.onboarding.location.label.hint": "Encabezado 1", "panel.onboarding.location.label.description": "Se requiere una ubicación en segundo plano para que la notificación de exposición basada en Bluetooth funcione en su teléfono ", - "panel.onboarding.location.button.allow.title": "Servicio de localización activado", + "panel.onboarding.location.button.allow.title": "Comenzar", "panel.onboarding.location.button.allow.hint": "", "panel.onboarding.location.button.dont_allow.title": "No en este momento", "panel.onboarding.location.button.dont_allow.hint": "Omitir ubicación para compartir", @@ -70,7 +70,7 @@ "panel.onboarding.bluetooth.label.title": "Habilitar Bluetooth", "panel.onboarding.bluetooth.label.title.hint": "Encabezado 1", "panel.onboarding.bluetooth.label.description": "Usar Bluetooth para alertarlo sobre la posible exposición al COVID-19.", - "panel.onboarding.bluetooth.button.allow.title": "Habilitar Bluetooth", + "panel.onboarding.bluetooth.button.allow.title": "Comenzar", "panel.onboarding.bluetooth.button.allow.hint": "", "panel.onboarding.bluetooth.button.dont_allow.title": "No en este momento", "panel.onboarding.bluetooth.button.dont_allow.hint": "Omitir habilitar Bluetooth", @@ -81,7 +81,7 @@ "panel.onboarding.notifications.label.hint": "Encabezado 1", "panel.onboarding.notifications.label.description1": "Reciba notificaciones sobre la información de COVID-19", "panel.onboarding.notifications.label.description2": "Esto es necesario para que las notificaciones de exposición funcionen en segundo plano en su teléfono", - "panel.onboarding.notifications.button.allow.title": "Permitir notificaciones", + "panel.onboarding.notifications.button.allow.title": "Comenzar", "panel.onboarding.notifications.button.allow.hint": "", "panel.onboarding.notifications.button.dont_allow.title": "No en este momento", "panel.onboarding.notifications.button.dont_allow.hint": "Omitir recibir notificaciones", @@ -587,7 +587,7 @@ "panel.health.covid19.history.label.contact_trace.details": "seguimiento de contacto: ", "panel.health.covid19.history.label.action.title": "Acción requerida", "panel.health.covid19.history.label.action.details": "acción: ", - "panel.health.covid19.history.label.result.title": "Resultado: ", + "panel.health.covid19.history.label.result.title": "Resultado", "panel.health.covid19.history.label.location.title": "Lugar de prueba", "panel.health.covid19.history.label.technician_name.title": "Nombre del técnico", "panel.health.covid19.history.label.technician_id.title": "ID del técnico", diff --git a/assets/strings.zh.json b/assets/strings.zh.json index 9be432ed..614c1bf0 100644 --- a/assets/strings.zh.json +++ b/assets/strings.zh.json @@ -60,7 +60,7 @@ "panel.onboarding.location.label.title": "打开位置服务", "panel.onboarding.location.label.title.hint": "标题1", "panel.onboarding.location.label.description": "要在手機上使用基於藍牙的曝光通知,需要背景位置", - "panel.onboarding.location.button.allow.title": "啟用位置服務", + "panel.onboarding.location.button.allow.title": "继续", "panel.onboarding.location.button.allow.hint": "", "panel.onboarding.location.button.dont_allow.title": "暂时不", "panel.onboarding.location.button.dont_allow.hint": "跳过共享位置", @@ -70,7 +70,7 @@ "panel.onboarding.bluetooth.label.title": "启用蓝牙", "panel.onboarding.bluetooth.label.title.hint": "标题1", "panel.onboarding.bluetooth.label.description": "使用藍牙提醒您可能接觸到COVID-19.", - "panel.onboarding.bluetooth.button.allow.title": "启用蓝牙", + "panel.onboarding.bluetooth.button.allow.title": "继续", "panel.onboarding.bluetooth.button.allow.hint": "", "panel.onboarding.bluetooth.button.dont_allow.title": "不是现在", "panel.onboarding.bluetooth.button.dont_allow.hint": "跳过启用蓝牙", @@ -81,7 +81,7 @@ "panel.onboarding.notifications.label.hint": "标题1", "panel.onboarding.notifications.label.description1": "您將收到COVID-19信息", "panel.onboarding.notifications.label.description2": "這是曝光通知在手機上後台運行所必需的", - "panel.onboarding.notifications.button.allow.title": "啟用通知", + "panel.onboarding.notifications.button.allow.title": "继续", "panel.onboarding.notifications.button.allow.hint": "", "panel.onboarding.notifications.button.dont_allow.title": "暂时不", "panel.onboarding.notifications.button.dont_allow.hint": "跳过接收通知", @@ -587,7 +587,7 @@ "panel.health.covid19.history.label.contact_trace.details": "接触者追踪: ", "panel.health.covid19.history.label.action.title": "需要採取的行動", "panel.health.covid19.history.label.action.details": "行動:", - "panel.health.covid19.history.label.result.title": "结果: ", + "panel.health.covid19.history.label.result.title": "结果", "panel.health.covid19.history.label.location.title": "测试位置", "panel.health.covid19.history.label.technician_name.title": "技术人员姓名", "panel.health.covid19.history.label.technician_id.title": "技术人员 ID", diff --git a/lib/model/Health.dart b/lib/model/Health.dart index cfafab47..91984355 100644 --- a/lib/model/Health.dart +++ b/lib/model/Health.dart @@ -401,15 +401,16 @@ class Covid19History { (this.blob?.provider == event?.provider) && (this.blob?.providerId == event?.providerId) && (this.blob?.testType == event?.blob?.testType) && - (this.blob?.testResult == event?.blob?.testResult); + (this.blob?.testResult == event?.blob?.testResult) && + ListEquality().equals(this.blob.extras, event.blob.extras); } else if (event.isAction) { return this.isAction && (this.dateUtc == event?.blob?.dateUtc) && (this.blob?.actionType == event?.blob?.actionType) && - ((this.blob?.actionText == event?.blob?.actionText) || - ((this.blob?.actionText is Map) && (event?.blob?.actionText is Map) && DeepCollectionEquality().equals(this.blob?.actionText, event?.blob?.actionText)) - ); + (DeepCollectionEquality().equals(this.blob?.actionTitle, event?.blob?.actionTitle)) && + (DeepCollectionEquality().equals(this.blob?.actionText, event?.blob?.actionText)) && + ListEquality().equals(this.blob.extras, event.blob.extras); } else { return false; @@ -539,13 +540,17 @@ class Covid19HistoryBlob { final String traceTEK; final String actionType; + final dynamic actionTitle; final dynamic actionText; + final List extras; + Covid19HistoryBlob({ this.provider, this.providerId, this.location, this.locationId, this.countyId, this.testType, this.testResult, this.symptoms, this.traceDuration, this.traceTEK, - this.actionType, this.actionText, + this.actionType, this.actionTitle, this.actionText, + this.extras, }); factory Covid19HistoryBlob.fromJson(Map json) { @@ -564,7 +569,10 @@ class Covid19HistoryBlob { traceTEK: json['trace_tek'], actionType: json['action_type'], + actionTitle: json['action_title'], actionText: json['action_text'], + + extras: Covid19EventExtra.listFromJson(json['extra']), ) : null; } @@ -584,7 +592,10 @@ class Covid19HistoryBlob { 'trace_tek': traceTEK, 'action_type': actionType, + 'action_title': actionTitle, 'action_text': actionText, + + 'extra': Covid19EventExtra.listToJson(extras), }; } @@ -601,7 +612,7 @@ class Covid19HistoryBlob { } bool get isAction { - return (actionType != null); + return (actionType != null) || (actionTitle != null) || (actionText != null); } Set get symptomsIds { @@ -655,12 +666,12 @@ class Covid19HistoryBlob { return null; } - String get localeActionText { - return Localization().localeString(actionText) ?? actionText; + String get localeActionTitle { + return Localization().localeString(actionTitle) ?? actionTitle; } - String get actionDisplayString { - return localeActionText ?? actionType; + String get localeActionText { + return Localization().localeString(actionText) ?? actionText; } } @@ -799,9 +810,12 @@ class Covid19EventBlob { final String testResult; final String actionType; + final dynamic actionTitle; final dynamic actionText; - Covid19EventBlob({this.dateUtc, this.testType, this.testResult, this.actionType, this.actionText}); + final List extras; + + Covid19EventBlob({this.dateUtc, this.testType, this.testResult, this.actionType, this.actionTitle, this.actionText, this.extras}); factory Covid19EventBlob.fromJson(Map json) { return (json != null) ? Covid19EventBlob( @@ -809,7 +823,9 @@ class Covid19EventBlob { testType: AppJson.stringValue(json['TestName']), testResult: AppJson.stringValue(json['Result']), actionType: AppJson.stringValue(json['ActionType']), + actionTitle: json['ActionTitle'], actionText: json['ActionText'], + extras: Covid19EventExtra.listFromJson(AppJson.listValue(json['Extra'])), ) : null; } @@ -819,18 +835,22 @@ class Covid19EventBlob { 'Date': healthDateTimeToString(dateUtc), 'TestName': testType, 'Result': testResult, + 'Extra': Covid19EventExtra.listToJson(extras), }; } - else if ((actionType != null) || (actionText != null)) { + else if ((actionType != null) || (actionTitle != null) || (actionText != null)) { return { 'Date': healthDateTimeToString(dateUtc), 'ActionType': actionType, + 'ActionTitle': actionTitle, 'ActionText': actionText, + 'Extra': Covid19EventExtra.listToJson(extras), }; } else { return { 'Date': healthDateTimeToString(dateUtc), + 'Extra': Covid19EventExtra.listToJson(extras), }; } } @@ -840,15 +860,100 @@ class Covid19EventBlob { } bool get isAction { - return AppString.isStringNotEmpty(actionType); + return AppString.isStringNotEmpty(actionType) || AppString.isStringNotEmpty(defaultLocaleActionTitle) || AppString.isStringNotEmpty(defaultLocaleActionText); } + String get defaultLocaleActionTitle { + return Localization().defaultLocaleString(actionTitle) ?? actionTitle; + } + String get defaultLocaleActionText { return Localization().defaultLocaleString(actionText) ?? actionText; } } +/////////////////////////////// +// Covid19EventExtra + +class Covid19EventExtra { + final dynamic displayName; + final dynamic displayValue; + + Covid19EventExtra({this.displayName, this.displayValue}); + + factory Covid19EventExtra.fromJson(Map json) { + return (json != null) ? Covid19EventExtra( + displayName: json['display_name'], + displayValue: json['display_value'], + ) : null; + } + + Map toJson() { + return { + 'display_name': displayName, + 'display_value': displayValue, + }; + } + + bool operator ==(o) => + (o is Covid19EventExtra) && + DeepCollectionEquality().equals(o.displayName, displayName) && + DeepCollectionEquality().equals(o.displayValue, displayValue); + + int get hashCode => + (DeepCollectionEquality().hash(displayName) ?? 0) ^ + (DeepCollectionEquality().hash(displayValue) ?? 0); + + bool get isVisible { + return (0 < (localeDisplayName?.length ?? 0)); + } + + String get localeDisplayName { + return Localization().localeString(displayName) ?? displayName; + } + + String get localeDisplayValue { + return Localization().localeString(displayValue) ?? displayValue; + } + + static List listFromJson(List json) { + List values; + if (json != null) { + values = []; + for (dynamic entry in json) { + Covid19EventExtra value; + try { value = Covid19EventExtra.fromJson((entry as Map)?.cast()); } + catch(e) { print(e?.toString()); } + values.add(value); + } + } + return values; + } + + static List listToJson(List values) { + List json; + if (values != null) { + json = []; + for (Covid19EventExtra value in values) { + json.add(value?.toJson()); + } + } + return json; + } + + static bool listHasVisible(List values) { + if (values != null) { + for (Covid19EventExtra value in values) { + if (value?.isVisible ?? false) { + return true; + } + } + } + return false; + } +} + /////////////////////////////// // Covid19OSFTest @@ -1431,7 +1536,7 @@ class HealthTestType { } /////////////////////////////// -// HealthTestRuleResult +// HealthTestTypeResult class HealthTestTypeResult { String id; @@ -2017,6 +2122,10 @@ class HealthRulesSet { return Localization().localeString(entry) ?? entry; } + + String localeDisclaimerHtml(Covid19HistoryBlob blob) { + return localeString(tests?.matchRuleResult(blob: blob, rules: this)?.disclaimerHtml); + } } /////////////////////////////// @@ -2050,7 +2159,7 @@ class HealthTestRulesSet { } HealthTestRuleResult matchRuleResult({ Covid19HistoryBlob blob, HealthRulesSet rules }) { - if ((_rules != null) && (blob != null)) { + if ((_rules != null) && (blob != null) && (blob.testType != null) && (blob.testResult != null)) { for (HealthTestRule rule in _rules) { if ((rule?.testType != null) && (rule?.testType?.toLowerCase() == blob?.testType?.toLowerCase()) && (rule.results != null)) { for (HealthTestRuleResult ruleResult in rule.results) { @@ -2103,14 +2212,16 @@ class HealthTestRule { class HealthTestRuleResult { final String testResult; final String category; + final String disclaimerHtml; final _HealthRuleStatus status; - HealthTestRuleResult({this.testResult, this.category, this.status}); + HealthTestRuleResult({this.testResult, this.category, this.status, this.disclaimerHtml}); factory HealthTestRuleResult.fromJson(Map json) { return (json != null) ? HealthTestRuleResult( testResult: json['result'], category: json['category'], + disclaimerHtml: json['disclaimer_html'], status: _HealthRuleStatus.fromJson(json['status']), ) : null; } diff --git a/lib/service/Analytics.dart b/lib/service/Analytics.dart index af5efdb9..2b90bf78 100644 --- a/lib/service/Analytics.dart +++ b/lib/service/Analytics.dart @@ -210,6 +210,7 @@ class Analytics with Service implements NotificationsListener { static const String LogHealthDurationName = "duration"; static const String LogHealthExposureTimestampName = "exposure_timestamp"; static const String LogHealthActionTypeName = "action_type"; + static const String LogHealthActionTitleName = "action_title"; static const String LogHealthActionTextName = "action_text"; static const String LogHealthActionTimestampName = "action_timestamp"; static const String LogHealthExposureScore = "exposure_score"; diff --git a/lib/service/Health.dart b/lib/service/Health.dart index 35b79c05..c46bcfc1 100644 --- a/lib/service/Health.dart +++ b/lib/service/Health.dart @@ -927,6 +927,7 @@ class Health with Service implements NotificationsListener { prevStatus: prevStatus, attributes: { Analytics.LogHealthActionTypeName: event.blob?.actionType, + Analytics.LogHealthActionTitleName: event.blob?.defaultLocaleActionTitle, Analytics.LogHealthActionTextName: event.blob?.defaultLocaleActionText, }); } @@ -1014,6 +1015,7 @@ class Health with Service implements NotificationsListener { providerId: event?.providerId, testType: event?.blob?.testType, testResult: event?.blob?.testResult, + extras: event?.blob?.extras ), publicKey: _user?.publicKey )); @@ -1024,7 +1026,9 @@ class Health with Service implements NotificationsListener { type: Covid19HistoryType.action, blob: Covid19HistoryBlob( actionType: event?.blob?.actionType, + actionTitle: event?.blob?.actionTitle, actionText: event?.blob?.actionText, + extras: event?.blob?.extras ), publicKey: _user?.publicKey )); @@ -1178,7 +1182,9 @@ class Health with Service implements NotificationsListener { "type": "health.covid19.action", "health.covid19.action.date": "2020-07-30T21:23:47Z", "health.covid19.action.type": "require-test-48", + "health.covid19.action.title": "Test Required", "health.covid19.action.text": "You must take a COVID-19 test in next 48 hours", + "health.covid19.action.extra": [...], }*/ if (action != null) { @@ -1187,15 +1193,19 @@ class Health with Service implements NotificationsListener { dateUtc = DateTime.now().toUtc(); } String actionType = AppJson.stringValue(action['health.covid19.action.type']); + dynamic actionTitle = AppJson.stringValue(action['health.covid19.action.title']); dynamic actionText = action['health.covid19.action.text']; + List extras = Covid19EventExtra.listFromJson(AppJson.listValue(action['health.covid19.action.extra'])); - if ((actionType != null) || (actionText != null)) { + if ((actionType != null) || (actionText != null) || (actionTitle != null)) { Covid19History history = await _addCovid19History(await Covid19History.encryptedFromBlob( dateUtc: dateUtc, type: Covid19HistoryType.action, blob: Covid19HistoryBlob( actionType: actionType, + actionTitle: actionTitle, actionText: actionText, + extras: extras ), publicKey: _user?.publicKey )); @@ -1216,6 +1226,7 @@ class Health with Service implements NotificationsListener { prevStatus: lastHealthStatus, attributes: { Analytics.LogHealthActionTypeName: actionType, + Analytics.LogHealthActionTitleName: actionTitle, Analytics.LogHealthActionTextName: actionText, Analytics.LogHealthActionTimestampName: dateUtc?.toIso8601String(), }); diff --git a/lib/ui/health/Covid19HistoryPanel.dart b/lib/ui/health/Covid19HistoryPanel.dart index 4d6c61ef..c5e5866a 100644 --- a/lib/ui/health/Covid19HistoryPanel.dart +++ b/lib/ui/health/Covid19HistoryPanel.dart @@ -17,6 +17,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/semantics.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_html/style.dart'; import 'package:illinois/model/Health.dart'; import 'package:illinois/service/Analytics.dart'; import 'package:illinois/service/Organizations.dart'; @@ -30,7 +32,7 @@ import 'package:illinois/service/Styles.dart'; import 'package:illinois/ui/widgets/PopupDialog.dart'; import 'package:illinois/ui/widgets/RoundedButton.dart'; import 'package:illinois/utils/Utils.dart'; -import 'package:sprintf/sprintf.dart'; +import 'package:url_launcher/url_launcher.dart'; class Covid19HistoryPanel extends StatefulWidget { @override @@ -468,7 +470,7 @@ class _Covid19HistoryEntryState extends State<_Covid19HistoryEntry> with SingleT bool _expanded = false; AnimationController _controller; - bool _isLoading = false; + bool _isLoadingLocation = false; @override void initState() { @@ -483,12 +485,26 @@ class _Covid19HistoryEntryState extends State<_Covid19HistoryEntry> with SingleT content.add(Container(height: 16,)); content.add(_buildCommonInfo(),); - if (widget.history?.isTestVerified ?? false) { - content.addAll([ - _buildMoreButton(), - _buildResult(), - _buildAdditionalInfo(), - ]); + if ((widget.history?.isTestVerified ?? false) || Covid19EventExtra.listHasVisible(widget.history?.blob?.extras)) { + content.add(_buildMoreButton()); + + if (_expanded) { + + Widget testResult = ((widget.history?.isTestVerified ?? false) && (widget.history?.blob?.testResult != null)) ? _buildTestResult() : null; + Widget additionalInfo = _buildAdditionalInfo(); + + if (testResult != null) { + content.add(testResult); + } + + if ((testResult != null) && (additionalInfo != null)) { + content.add(_buildSplitter()); + } + + if (additionalInfo != null) { + content.add(additionalInfo); + } + } } content.add(Container(height: 16,)); @@ -498,142 +514,164 @@ class _Covid19HistoryEntryState extends State<_Covid19HistoryEntry> with SingleT child: Column(children: content,), ); } + Widget _buildCommonInfo(){ String title; - Widget details; - bool isVerifiedTest = false; - bool isTest = false; - String dateFormat = kReleaseMode ? 'MMMM d, yyyy' : 'MMMM d, yyyy HH:mm:ss'; + Widget detailWidget; + String dateFormat = 'MMMM d, yyyy H:mm a'; if (widget.history != null) { if (widget.history.isTest) { - isTest = true; bool isManualTest = widget.history?.isManualTest ?? false; - isVerifiedTest = widget.history?.isTestVerified ?? false; title = widget.history?.blob?.testType ?? Localization().getStringEx("app.common.label.other", "Other"); - details = Row(children: [ - Image.asset(isManualTest? "images/u.png": "images/provider.png", excludeFromSemantics: true,), + detailWidget = Row(children: [ + Image.asset(isManualTest? "images/u.png": "images/provider.png", color: Styles().colors.fillColorSecondary, excludeFromSemantics: true,), Container(width: 11,), - Expanded(child: - Semantics(label: Localization().getStringEx("panel.health.covid19.history.label.provider.hint", "provider: "), child: - Text( isManualTest? Localization().getStringEx("panel.health.covid19.history.label.provider.self_reported", "Self reported"): - (widget.history?.blob?.provider ?? Localization().getStringEx("app.common.label.other", "Other")), - style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textSurface,)) - )) + Semantics(label: Localization().getStringEx("panel.health.covid19.history.label.provider.hint", "provider: "), child: + Text(isManualTest ? Localization().getStringEx("panel.health.covid19.history.label.provider.self_reported", "Self reported"): + (widget.history?.blob?.provider ?? Localization().getStringEx("app.common.label.other", "Other")), + style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textSurface,)) + ) ],); } else if (widget.history.isSymptoms) { title = Localization().getStringEx("panel.health.covid19.history.label.self_reported.title","Self Reported Symptoms"); - details = - Row(children: [ - Expanded(child: - Semantics(label: Localization().getStringEx("panel.health.covid19.history.label.self_reported.symptoms","symptoms: "), child: - Text(widget.history.blob?.symptomsDisplayString(rules: widget.rules) ?? '', style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground,)) - ) - ) - ],); + detailWidget = Semantics(label: Localization().getStringEx("panel.health.covid19.history.label.self_reported.symptoms","symptoms: "), child: + Text(widget.history.blob?.symptomsDisplayString(rules: widget.rules) ?? '', style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground,)) + ); } else if (widget.history.isContactTrace) { + dateFormat = 'MMMM d, yyyy'; title = Localization().getStringEx("panel.health.covid19.history.label.contact_trace.title","Contact Trace"); - details = - Row(children: [ - Expanded(child: - Semantics(label: Localization().getStringEx("panel.health.covid19.history.label.contact_trace.details","contact trace: "), child: - Text(widget.history.blob?.traceDurationDisplayString ?? '', style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground,)) - ))]); + detailWidget = Semantics(label: Localization().getStringEx("panel.health.covid19.history.label.contact_trace.details","contact trace: "), child: + Text(widget.history.blob?.traceDurationDisplayString ?? '', style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground,)) + ); } else if (widget.history.isAction) { - title = Localization().getStringEx("panel.health.covid19.history.label.action.title","Action Required"); - details = Semantics(label: Localization().getStringEx("panel.health.covid19.history.label.action.details","action: "), child: - Text(widget.history.blob?.actionDisplayString ?? '', style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground,)) - ); + title = widget.history.blob?.localeActionTitle ?? Localization().getStringEx("panel.health.covid19.history.label.action.title", "Action Required"); + detailWidget = Semantics(label: Localization().getStringEx("panel.health.covid19.history.label.action.details","action: "), child: + Text(widget.history.blob?.localeActionText ?? '', style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground,)) + ); } } - return - Semantics( - sortKey: OrdinalSortKey(1), - container: true, - child: Container(color: Styles().colors.white, - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(AppDateTime.formatDateTime(widget.history?.dateUtc?.toLocal(), format:dateFormat, locale: Localization().currentLocale?.languageCode) ?? '',style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textSurface,)), - Container(height: 4,), - Row(children: [ - Expanded(child: - Text(title ?? '', style:TextStyle(fontSize: 20, fontFamily: Styles().fontFamilies.extraBold, color: Styles().colors.fillColorPrimary,)), - )]), - Container(height: 9,), - details ?? Container(), - !isTest? Container(): - Container(height: 9,), - !isTest? Container(): - Row(children: [ - Image.asset(isVerifiedTest? "images/certified-copy.png": "images/pending.png"), - Container(width: 10,), - Expanded(child: isVerifiedTest? - Text(Localization().getStringEx("panel.health.covid19.history.label.verified","Verified"),style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textSurface,)): - Text(Localization().getStringEx("panel.health.covid19.history.label.verification_pending","Verification Pending"),style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textSurface,)), - ) - ],), - ], - ) - )); + List contentList = [ + Padding(padding: EdgeInsets.only(bottom: 4), child: Text(AppDateTime.formatDateTime(widget.history?.dateUtc?.toLocal(), format: dateFormat, locale: Localization().currentLocale?.languageCode) ?? '',style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textSurface,)),), + Padding(padding: EdgeInsets.only(), child: Text(title ?? '', style:TextStyle(fontSize: 20, fontFamily: Styles().fontFamilies.extraBold, color: Styles().colors.fillColorPrimary,))), + ]; + + if (detailWidget != null) { + contentList.add(Padding(padding: EdgeInsets.only(top: 9), child: detailWidget)); + } + + if (widget.history?.isTest ?? false) { + bool isVerifiedTest = widget.history?.isTestVerified ?? false; + contentList.add( + Padding(padding: EdgeInsets.only(top: 9), child: + Row(children: [ + Image.asset(isVerifiedTest ? "images/certified-copy.png": "images/pending.png", excludeFromSemantics: true,), + Container(width: 10,), + Expanded(child: isVerifiedTest ? + Text(Localization().getStringEx("panel.health.covid19.history.label.verified", "Verified"), style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textSurface,)): + Text(Localization().getStringEx("panel.health.covid19.history.label.verification_pending", "Verification Pending"), style:TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textSurface,)), + ) + ],), + ), + ); + } + + return Semantics(sortKey: OrdinalSortKey(1), container: true, child: + Container(color: Styles().colors.white, padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16), child: + Row(children: [ + Expanded(child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: contentList,) + ), + ]), + ), + ); } - Widget _buildResult(){ - return !_expanded || widget.history?.blob?.testResult==null? Container(): - Semantics( - sortKey: OrdinalSortKey(3), - container: true, - child: - Container(color: Styles().colors.white, - padding: EdgeInsets.symmetric(horizontal: 16), - child: - Column(children: [ - Container(height: 14,), - Row( - children: [ - Image.asset("images/selected-black.png",excludeFromSemantics: true,), - Container(width: 6,), - Text(Localization().getStringEx("panel.health.covid19.history.label.result.title","Result: "), - style: TextStyle(color: Styles().colors.textBackground,fontSize: 14, fontFamily: Styles().fontFamilies.bold,), - ), - Expanded(child:Container()), - Text(widget.history.blob?.testResult, - style: TextStyle(color: Styles().colors.textBackground,fontSize: 14, fontFamily: Styles().fontFamilies.regular,), - ) - ], - ), - Container(height: 14,), - Container(height:1, color: Styles().colors.surfaceAccent,) - ],) - ) + Widget _buildTestResult() { + bool hasDisclaimer = AppString.isStringNotEmpty(widget.rules?.localeDisclaimerHtml(widget.history?.blob)); + Widget contentData = Row(children: [ + Padding(padding: EdgeInsets.only(left: 16), child: + Image.asset("images/selected-black.png",excludeFromSemantics: true,), + ), + Container(width: 6,), + Text(Localization().getStringEx("panel.health.covid19.history.label.result.title", "Result"), + style: TextStyle(color: Styles().colors.textBackground,fontSize: 14, fontFamily: Styles().fontFamilies.bold,), + ), + Expanded(child:Container(height: 48)), + Padding(padding: EdgeInsets.only(right: hasDisclaimer ? 36: 16), child: + Text(widget.history.blob?.testResult, + style: TextStyle(color: Styles().colors.textBackground,fontSize: 14, fontFamily: Styles().fontFamilies.regular,), + ), + ), + ]); + + Widget contentLine = hasDisclaimer ? + Stack(children: [ + contentData, + Container(alignment: Alignment.topRight, child: + InkWell(onTap: _onTapDisclaimer, child: + Container(/*color: Color(0x20000000),*/ width: 48, height: 48, alignment: Alignment.center, child: + Image.asset('images/icon-info-orange.png') + ), + ), + ), + ],) : + contentData; + + return Semantics(sortKey: OrdinalSortKey(3), container: true, child: + Container(color: Styles().colors.white, child: + Column(children: [ + contentLine, + ],) + ), ); } - Widget _buildAdditionalInfo(){ - return - !_expanded ? Container(): - Semantics( - sortKey: OrdinalSortKey(4), - container: true, - child: - Container(color: Styles().colors.white, - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6), - child: Column( - children: [ - (_isLoading == true) ? Center(child: SizedBox(height: 24, width: 24, child:CircularProgressIndicator(strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Styles().colors.fillColorSecondary),))): - widget.history?.blob?.location==null? Container(): - _buildDetail(Localization().getStringEx("panel.health.covid19.history.label.location.title","Test Location"), widget.history?.blob?.location, onTapData: (widget.history?.blob?.location != null) ? (){ _onTapLocation(); } : null, onTapHint: "Double tap to show location"), + Widget _buildSplitter() { + return Container(color: Styles().colors.white, child: + Column(children: [ + Padding(padding: EdgeInsets.symmetric(horizontal: 16), child: + Container(height:1, color: Styles().colors.surfaceAccent,) + ), + ],) + ); + } - //_buildDetail(Localization().getStringEx("panel.health.covid19.history.label.technician_name.title","Technician Name"), widget.history?.technician), - //_buildDetail(Localization().getStringEx("panel.health.covid19.history.label.technician_id.title","Technician ID"), widget.history?.technicianId), - ], + Widget _buildAdditionalInfo() { + List content = []; + if (_isLoadingLocation == true) { + content.add(Center(child: SizedBox(height: 24, width: 24, child: CircularProgressIndicator(strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Styles().colors.fillColorSecondary),)))); + } + else if (widget.history?.blob?.location != null) { + content.add(_buildDetail( + Localization().getStringEx("panel.health.covid19.history.label.location.title", "Test Location"), + widget.history?.blob?.location, + onTapData: _onTapLocation, + onTapHint: "Double tap to show location")); + } + + if (AppCollection.isCollectionNotEmpty(widget.history?.blob?.extras)) { + for (Covid19EventExtra extra in widget.history?.blob?.extras) { + if (extra.isVisible) { + content.add(_buildDetail( + extra.localeDisplayName, + extra.localeDisplayValue ?? '-')); + } + } + } + + //content.add(_buildDetail(Localization().getStringEx("panel.health.covid19.history.label.technician_name.title","Technician Name"), widget.history?.technician)), + //content.add(_buildDetail(Localization().getStringEx("panel.health.covid19.history.label.technician_id.title","Technician ID"), widget.history?.technicianId)), + + return (0 < content.length) ? Semantics(sortKey: OrdinalSortKey(4), container: true, child: + Container(color: Styles().colors.white, padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6), child: + Column(children: content, ) ) - ); + ) : null; } Widget _buildMoreButton(){ @@ -668,7 +706,7 @@ class _Covid19HistoryEntryState extends State<_Covid19HistoryEntry> with SingleT Container(width: 4,), RotationTransition( turns: _iconTurns, - child: Image.asset("images/icon-down-orange.png")), + child: Image.asset("images/icon-down-orange.png", color: Styles().colors.fillColorSecondary, excludeFromSemantics: true,)), ],) ))); @@ -693,7 +731,7 @@ class _Covid19HistoryEntryState extends State<_Covid19HistoryEntry> with SingleT Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding(padding: EdgeInsets.symmetric(vertical: 4), child: - Text(sprintf("%s: ",[title],), + Text(title, style: TextStyle(fontSize: 14, fontFamily: Styles().fontFamilies.bold, color: Styles().colors.textBackground), ), ), @@ -707,9 +745,9 @@ class _Covid19HistoryEntryState extends State<_Covid19HistoryEntry> with SingleT Analytics().logSelect(target: widget.history?.blob?.locationId); String locationId = widget.history?.blob?.locationId; if(locationId!=null){ - setState(() => _isLoading = true); + setState(() => _isLoadingLocation = true); Health().loadHealthServiceLocation(locationId: locationId).then((location){ - setState(() => _isLoading = false); + setState(() => _isLoadingLocation = false); if(location!=null){ NativeCommunicator().launchMap( target: { @@ -734,4 +772,33 @@ class _Covid19HistoryEntryState extends State<_Covid19HistoryEntry> with SingleT AppToast.show("Missing location id"); } } + + void _onTapDisclaimer() { + Analytics.instance.logSelect(target: "Disclaimer"); + String disclaimerHtml = widget.rules?.localeDisclaimerHtml(widget.history?.blob); + if (AppString.isStringNotEmpty(disclaimerHtml)) { + showDialog(context: context, builder: (context) => _buildDisclaimerDialog(context, disclaimerHtml)); + } + } + + Widget _buildDisclaimerDialog(BuildContext context, String htmlContent) { + Style htmlStyle = Style(color: Styles().colors.fillColorPrimary, fontFamily: Styles().fontFamilies.bold, fontSize: FontSize(16)); + return ClipRRect(borderRadius: BorderRadius.all(Radius.circular(8)), child: + Dialog(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8),), child: + Stack(children: [ + Padding(padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16), child: + SingleChildScrollView(child: + Html(data: htmlContent, style: { 'body': htmlStyle }, onLinkTap: (url) => launch(url)), + ), + ), + Container(alignment: Alignment.topRight, height: 42, child: InkWell(onTap: _onCloseDisclaimerDialog, child: Container(width: 42, height: 42, alignment: Alignment.center, child: Image.asset('images/close-orange.png')))), + ],), + ), + ); + } + + void _onCloseDisclaimerDialog() { + Analytics.instance.logSelect(target: "Close Disclaimer"); + Navigator.of(context).pop(); + } } diff --git a/lib/ui/health/Covid19InfoCenterPanel.dart b/lib/ui/health/Covid19InfoCenterPanel.dart index ec5c99c0..c14bd631 100644 --- a/lib/ui/health/Covid19InfoCenterPanel.dart +++ b/lib/ui/health/Covid19InfoCenterPanel.dart @@ -332,8 +332,8 @@ class _Covid19InfoCenterPanelState extends State impleme info = isManualTest? Localization().getStringEx("panel.covid19home.label.provider.self_reported", "Self reported"): (blob?.provider ?? Localization().getStringEx("app.common.label.other", "Other")); } else if(blob.isAction){ - historyTitle = Localization().getStringEx("panel.covid19home.label.action_required.title", "Action Required"); - info = blob.actionDisplayString?? ""; + historyTitle = blob.localeActionTitle ?? Localization().getStringEx("panel.covid19home.label.action_required.title", "Action Required"); + info = blob.localeActionText ?? ""; } else if(blob.isContactTrace){ historyTitle = Localization().getStringEx("panel.covid19home.label.contact_trace.title", "Contact Trace"); info = blob.traceDurationDisplayString; diff --git a/lib/ui/health/Covid19StatusUpdatePanel.dart b/lib/ui/health/Covid19StatusUpdatePanel.dart index 3e137ec6..708c920e 100644 --- a/lib/ui/health/Covid19StatusUpdatePanel.dart +++ b/lib/ui/health/Covid19StatusUpdatePanel.dart @@ -258,9 +258,9 @@ class _Covid19StatusUpdatePanelState extends State { children: [ Image.asset("images/icon-selected.png",excludeFromSemantics: true,), Container(width: 7,), - Text(Localization().getStringEx("panel.health.status_update.label.reason.action.detail", "Action Required: "), style: TextStyle(color: Colors.white, fontSize: 12, fontFamily: Styles().fontFamilies.bold)), + Text(reasonHistory.localeActionTitle ?? Localization().getStringEx("panel.health.status_update.label.reason.action.detail", "Action Required: "), style: TextStyle(color: Colors.white, fontSize: 12, fontFamily: Styles().fontFamilies.bold)), ],), - Text(reasonHistory.actionDisplayString ?? "", style: TextStyle(color: Colors.white, fontSize: 12, fontFamily: Styles().fontFamilies.regular)), + Text(reasonHistory.localeActionText ?? "", style: TextStyle(color: Colors.white, fontSize: 12, fontFamily: Styles().fontFamilies.regular)), ],); diff --git a/lib/ui/health/debug/Covid19DebugCreateEventPanel.dart b/lib/ui/health/debug/Covid19DebugCreateEventPanel.dart index e4026ff4..8983c0b9 100644 --- a/lib/ui/health/debug/Covid19DebugCreateEventPanel.dart +++ b/lib/ui/health/debug/Covid19DebugCreateEventPanel.dart @@ -15,6 +15,7 @@ */ import 'dart:collection'; +import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -32,6 +33,7 @@ import 'package:illinois/ui/widgets/RoundedButton.dart'; import 'package:illinois/utils/Crypt.dart'; import 'package:illinois/utils/Utils.dart'; import 'package:illinois/service/Styles.dart'; +import 'package:intl/intl.dart'; import "package:pointycastle/export.dart" as PointyCastle; class Covid19DebugCreateEventPanel extends StatefulWidget { @@ -425,43 +427,101 @@ class _Covid19DebugCreateEventPanelState extends State[ ScalableRoundedButton( - label: Localization().getStringEx('panel.onboarding.notifications.button.allow.title', 'Enable Notifications'), + label: Localization().getStringEx('panel.onboarding.notifications.button.allow.title', 'Continue'), hint: Localization().getStringEx('panel.onboarding.notifications.button.allow.hint', ''), borderColor: Styles().colors.fillColorSecondary, backgroundColor: Styles().colors.background, diff --git a/lib/ui/settings/SettingsPendingFamilyMemberPanel.dart b/lib/ui/settings/SettingsPendingFamilyMemberPanel.dart index c8d44b4a..fad2ced9 100644 --- a/lib/ui/settings/SettingsPendingFamilyMemberPanel.dart +++ b/lib/ui/settings/SettingsPendingFamilyMemberPanel.dart @@ -24,7 +24,7 @@ class SettingsPendingFamilyMemberPanel extends StatefulWidget { class _SettingsPendingFamilyMemberPanelState extends State { bool _hasProgress = false; - bool _buttonsEnabled = true; + bool _buttonsEnabled = false; bool _termsAccepted = false; String _errorMessage; HealthRulesSet _rules; diff --git a/lib/utils/Utils.dart b/lib/utils/Utils.dart index 43107bea..74da4382 100644 --- a/lib/utils/Utils.dart +++ b/lib/utils/Utils.dart @@ -288,6 +288,22 @@ class AppJson { return null; } } + + static List listValue (dynamic value) { + if (value is List) { + try { return value.cast(); } + catch(e) { print(e?.toString()); } + } + return null; + } + + static Map mapValue (dynamic value) { + if (value is Map) { + try { return value.cast(); } + catch(e) { print(e?.toString()); } + } + return null; + } } class AppFile { diff --git a/pubspec.yaml b/pubspec.yaml index d338f866..b966855d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: Illinois client application. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.9.18+918 +version: 2.9.19+919 environment: sdk: ">=2.2.0 <3.0.0" diff --git a/scripts/build.sh b/scripts/build.sh index 130532e8..7af06938 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -83,6 +83,8 @@ if [ "$PLATFORM" = "all" ] || [ "$PLATFORM" = "android" ]; then cp $APK_BUILD_PATH $APK_OUT_PATH echo "Copy to $APK_OUT_PATH" fi + + aws s3 cp $APK_OUT_PATH s3://rokwire-ios-beta/Installs/ fi if [ "$PLATFORM" = "all" ] || [ "$PLATFORM" = "ios" ]; then @@ -104,7 +106,11 @@ if [ "$PLATFORM" = "all" ] || [ "$PLATFORM" = "ios" ]; then xcodebuild -exportArchive -archivePath ../build/_output/tmp/Runner.xcarchive -exportPath ../build/_output/tmp/ -exportOptionsPlist ../build/_output/$BRAND-$VERSION-$ENV.plist cd .. cp ./build/_output/tmp/Runner.ipa ./build/_output/$BRAND-$VERSION-$ENV.ipa - rm -rf ./build/_output/tmp/ + #rm -rf ./build/_output/tmp/ + + aws s3 cp $QR_BUILD_PATH s3://rokwire-ios-beta/Installs/ + aws s3 cp $PLIST_BUILD_PATH s3://rokwire-ios-beta/Installs/ + aws s3 cp ./build/_output/$BRAND-$VERSION-$ENV.ipa s3://rokwire-ios-beta/Installs/ fi