diff --git a/CHANGELOG.md b/CHANGELOG.md index 62d1bb7b..f479eac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,21 +5,32 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Changed -## [2.5.8] - 2020-09-10 +## [2.6.8] - 2020-09-18 ### Changed - - Remove restriction for taking app screenshots in Android [#138](https://github.com/rokwire/safer-illinois-app/issues/138). + - Change wait time colors and labels [#167](https://github.com/rokwire/safer-illinois-app/issues/167). + - Upgrade flutter for Safer Illinois to v. 1.20.4 [#82](https://github.com/rokwire/safer-illinois-app/issues/82). -## [2.5.7] - 2020-09-09 +## [2.6.7] - 2020-09-17 ### Changed - - Integrate maps for test locations [#132](https://github.com/rokwire/safer-illinois-app/issues/132). - - Use next step HTML in exposure rules [#133](https://github.com/rokwire/safer-illinois-app/issues/133). - - Various minor fixes. + - Rework swiper and fix the VoiceOver accessibility [#158] (https://github.com/rokwire/safer-illinois-app/issues/158) + - Show wait time for each test location [#160](https://github.com/rokwire/safer-illinois-app/issues/160). -## [2.5.6] - 2020-09-08 + +## [2.6.6] - 2020-09-16 ### Changed + - Load symptoms and rules from the new Health API [#152](https://github.com/rokwire/safer-illinois-app/issues/152). + +## [2.6.3] - 2020-09-11 +### Changed + - Remove "ASAP" label in Next Steps panel [#143](https://github.com/rokwire/safer-illinois-app/issues/143). + - Remove restriction for taking screenshots in Android [#138](https://github.com/rokwire/safer-illinois-app/issues/138). - Removed SAR status entries from sample health rules. Use PCR entries instead that actually contain the same status rules. + - Integrate maps for test locations [#132](https://github.com/rokwire/safer-illinois-app/issues/132). + - Use next step HTML in exposure rules [#133](https://github.com/rokwire/safer-illinois-app/issues/133). - Fixed warnings. + - Various minor fixes. ### Added - Added 'test-user' condition [#125](https://github.com/rokwire/safer-illinois-app/issues/125). @@ -69,7 +80,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Covid19OnBoardingLoginNetIdPanel (unused) - Covid19OnBoardingLoginPhonePanel (unused) - ## [2.4.2] - 2020-08-26 ### Changed - Fixed Xcode name in README.md (#1) diff --git a/android/app/build.gradle b/android/app/build.gradle index fd9dd7ce..dae32e83 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -161,6 +161,11 @@ dependencies { implementation 'com.google.zxing:core:3.3.0' //Use zxing 3.3.0 because we have minSdk < 24 implementation ('com.journeyapps:zxing-android-embedded:4.1.0@aar') { transitive = false } + //BlinkID + implementation('com.microblink:blinkid:5.3.0@aar') { + transitive = true + } + // BLESSED - BLE library used for Exposures implementation 'com.github.weliem:blessed-android:1.19' } diff --git a/android/app/src/main/java/edu/illinois/covid/MainActivity.java b/android/app/src/main/java/edu/illinois/covid/MainActivity.java index 4e0c727e..7a0e5c68 100644 --- a/android/app/src/main/java/edu/illinois/covid/MainActivity.java +++ b/android/app/src/main/java/edu/illinois/covid/MainActivity.java @@ -17,6 +17,7 @@ package edu.illinois.covid; import android.Manifest; +import android.app.Activity; import android.app.Application; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -37,13 +38,27 @@ import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; import com.journeyapps.barcodescanner.BarcodeEncoder; +import com.microblink.MicroblinkSDK; +import com.microblink.entities.recognizers.Recognizer; +import com.microblink.entities.recognizers.RecognizerBundle; +import com.microblink.entities.recognizers.blinkid.generic.BlinkIdCombinedRecognizer; +import com.microblink.entities.recognizers.blinkid.generic.DriverLicenseDetailedInfo; +import com.microblink.entities.recognizers.blinkid.mrtd.MrzResult; +import com.microblink.entities.recognizers.blinkid.passport.PassportRecognizer; +import com.microblink.intent.IntentDataTransferMode; +import com.microblink.recognition.InvalidLicenceKeyException; +import com.microblink.results.date.Date; +import com.microblink.uisettings.ActivityRunner; +import com.microblink.uisettings.BlinkIdUISettings; import java.io.ByteArrayOutputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.UUID; @@ -76,6 +91,15 @@ public class MainActivity extends FlutterActivity implements MethodChannel.Metho private RequestLocationCallback rlCallback; + // BlinkId + private static final int BLINK_ID_REQUEST_CODE = 3; + private BlinkIdCombinedRecognizer blinkIdCombinedRecognizer; + private PassportRecognizer blinkIdPassportRecognizer; + private RecognizerBundle blinkIdRecognizerBundle; + private boolean scanning = false; + private boolean microblinkInitialized = false; + private MethodChannel.Result scanMethodChannelResult; + // Gallery Plugin private GalleryPlugin galleryPlugin; @@ -419,6 +443,236 @@ private String handleBarcode(Object params) { return barcodeImageData; } + //region BlinkId + + private void handleMicroBlinkScan(Object params) { + if (!microblinkInitialized) { + initMicroblinkSdk(); + } + if (!microblinkInitialized) { + Log.i(TAG, "Cannot start scanning! Microblink has not been initialized!"); + if (scanMethodChannelResult != null) { + scanMethodChannelResult.success(null); + } + return; + } + if (scanning) { + Log.d(TAG, "Blink Id is currently scanning!"); + if (scanMethodChannelResult != null) { + scanMethodChannelResult.success(null); + } + } else { + scanning = true; + List recognizersList = Arrays.asList("combined", "passport"); // by default + if (params instanceof HashMap) { + HashMap paramsMap = (HashMap) params; + Object recognizersObject = paramsMap.get("recognizers"); + if (recognizersObject instanceof List) { + recognizersList = (List) recognizersObject; + } + } + List recognizers = new ArrayList<>(); + for (String recognizerParam : recognizersList) { + if ("combined".equals(recognizerParam)) { + blinkIdCombinedRecognizer = new BlinkIdCombinedRecognizer(); + blinkIdCombinedRecognizer.setEncodeFaceImage(true); + recognizers.add(blinkIdCombinedRecognizer); + } else if ("passport".equals(recognizerParam)) { + blinkIdPassportRecognizer = new PassportRecognizer(); + blinkIdPassportRecognizer.setEncodeFaceImage(true); + recognizers.add(blinkIdPassportRecognizer); + } + } + blinkIdRecognizerBundle = new RecognizerBundle(recognizers); + BlinkIdUISettings uiSettings = new BlinkIdUISettings(blinkIdRecognizerBundle); + ActivityRunner.startActivityForResult(this, BLINK_ID_REQUEST_CODE, uiSettings); + } + } + + private void initMicroblinkSdk() { + String blinkIdLicenseKey = Utils.Map.getValueFromPath(keys, "microblink.blink_id.license_key", null); + if (Utils.Str.isEmpty(blinkIdLicenseKey)) { + Log.e(TAG, "Microblink BlinkId license key is missing from config keys!"); + return; + } + try { + MicroblinkSDK.setLicenseKey(blinkIdLicenseKey, this); + MicroblinkSDK.setIntentDataTransferMode(IntentDataTransferMode.PERSISTED_OPTIMISED); + microblinkInitialized = true; + } catch (InvalidLicenceKeyException | NullPointerException e) { + Log.e(TAG, "Microblink failed to initialize:"); + e.printStackTrace(); + } + } + + private void onBlinkIdScanSuccess(Intent data) { + Log.d(TAG, "onBlinkIdScanSuccess"); + if (blinkIdRecognizerBundle != null) { + blinkIdRecognizerBundle.loadFromIntent(data); + } + if ((blinkIdCombinedRecognizer != null) && (blinkIdCombinedRecognizer.getResult().getResultState() == Recognizer.Result.State.Valid)) { + onCombinedRecognizerResult(blinkIdCombinedRecognizer.getResult()); + } else if ((blinkIdPassportRecognizer != null) && (blinkIdPassportRecognizer.getResult().getResultState() == Recognizer.Result.State.Valid)) { + onPassportRecognizerResult(blinkIdPassportRecognizer.getResult()); + } + } + + private void onBlinkIdScanCanceled() { + Log.d(TAG, "onBlinkIdScanCanceled"); + unInitBlinkId(); + if (scanMethodChannelResult != null) { + scanMethodChannelResult.success(null); + } + } + + private void onCombinedRecognizerResult(BlinkIdCombinedRecognizer.Result combinedRecognizerResult) { + Log.d(TAG, "onCombinedRecognizerResult"); + HashMap scanResult = null; + if (combinedRecognizerResult != null) { + scanResult = new HashMap<>(); + + String base64FaceImage = Base64.encodeToString(combinedRecognizerResult.getEncodedFaceImage(), Base64.NO_WRAP); + + scanResult.put("firstName", Utils.Str.nullIfEmpty(combinedRecognizerResult.getFirstName())); + scanResult.put("lastName", Utils.Str.nullIfEmpty(combinedRecognizerResult.getLastName())); + scanResult.put("fullName", Utils.Str.nullIfEmpty(combinedRecognizerResult.getFullName())); + scanResult.put("sex", Utils.Str.nullIfEmpty(combinedRecognizerResult.getSex())); + scanResult.put("address", Utils.Str.nullIfEmpty(combinedRecognizerResult.getAddress())); + + scanResult.put("dateOfBirth", Utils.Str.nullIfEmpty(formatBlinkIdDate(combinedRecognizerResult.getDateOfBirth().getDate()))); + scanResult.put("dateOfExpiry", Utils.Str.nullIfEmpty(formatBlinkIdDate(combinedRecognizerResult.getDateOfExpiry().getDate()))); + scanResult.put("dateOfIssue", Utils.Str.nullIfEmpty(formatBlinkIdDate(combinedRecognizerResult.getDateOfIssue().getDate()))); + + scanResult.put("documentNumber", Utils.Str.nullIfEmpty(combinedRecognizerResult.getDocumentNumber())); + + scanResult.put("placeOfBirth", Utils.Str.nullIfEmpty(combinedRecognizerResult.getPlaceOfBirth())); + scanResult.put("nationality", Utils.Str.nullIfEmpty(combinedRecognizerResult.getNationality())); + scanResult.put("race", Utils.Str.nullIfEmpty(combinedRecognizerResult.getRace())); + scanResult.put("religion", Utils.Str.nullIfEmpty(combinedRecognizerResult.getReligion())); + scanResult.put("profession", Utils.Str.nullIfEmpty(combinedRecognizerResult.getProfession())); + scanResult.put("maritalStatus", Utils.Str.nullIfEmpty(combinedRecognizerResult.getMaritalStatus())); + scanResult.put("residentialStatus", Utils.Str.nullIfEmpty(combinedRecognizerResult.getResidentialStatus())); + scanResult.put("employer", Utils.Str.nullIfEmpty(combinedRecognizerResult.getEmployer())); + scanResult.put("personalIdNumber", Utils.Str.nullIfEmpty(combinedRecognizerResult.getPersonalIdNumber())); + scanResult.put("documentAdditionalNumber", Utils.Str.nullIfEmpty(combinedRecognizerResult.getDocumentAdditionalNumber())); + scanResult.put("issuingAuthority", Utils.Str.nullIfEmpty(combinedRecognizerResult.getIssuingAuthority())); + + scanResult.put("mrz", getScanRezultFromMrz(combinedRecognizerResult.getMrzResult())); + scanResult.put("driverLicenseDetailedInfo", getScanResultFromDriverLicenseDetailedInfo(combinedRecognizerResult.getDriverLicenseDetailedInfo())); + + scanResult.put("base64FaceImage", Utils.Str.nullIfEmpty(base64FaceImage)); + } + unInitBlinkId(); + if (scanMethodChannelResult != null) { + scanMethodChannelResult.success(scanResult); + } + } + + private void onPassportRecognizerResult(PassportRecognizer.Result passportRecognizerResult) { + Log.d(TAG, "onPassportRecognizerResult"); + HashMap scanResult = null; + if (passportRecognizerResult != null) { + scanResult = new HashMap<>(); + + String base64FaceImage = Base64.encodeToString(passportRecognizerResult.getEncodedFaceImage(), Base64.NO_WRAP); + + scanResult.put("firstName", null); + scanResult.put("lastName", null); + scanResult.put("fullName", null); + scanResult.put("sex", null); + scanResult.put("address", null); + + scanResult.put("dateOfBirth", null); + scanResult.put("dateOfExpiry", null); + scanResult.put("dateOfIssue", null); + + scanResult.put("documentNumber", null); + + scanResult.put("placeOfBirth", null); + scanResult.put("nationality", null); + scanResult.put("race", null); + scanResult.put("religion", null); + scanResult.put("profession", null); + scanResult.put("maritalStatus", null); + scanResult.put("residentialStatus", null); + scanResult.put("employer", null); + scanResult.put("personalIdNumber", null); + scanResult.put("documentAdditionalNumber", null); + scanResult.put("issuingAuthority", null); + + scanResult.put("mrz", getScanRezultFromMrz(passportRecognizerResult.getMrzResult())); + scanResult.put("driverLicenseDetailedInfo", null); + + scanResult.put("base64FaceImage", Utils.Str.nullIfEmpty(base64FaceImage)); + } + unInitBlinkId(); + if (scanMethodChannelResult != null) { + scanMethodChannelResult.success(scanResult); + } + } + + private HashMap getScanResultFromDriverLicenseDetailedInfo(DriverLicenseDetailedInfo driverLicenseDetailedInfo) { + HashMap scanResult = null; + if (driverLicenseDetailedInfo != null) { + scanResult = new HashMap<>(); + + scanResult.put("restrictions", Utils.Str.nullIfEmpty(driverLicenseDetailedInfo.getRestrictions())); + scanResult.put("endorsements", Utils.Str.nullIfEmpty(driverLicenseDetailedInfo.getEndorsements())); + scanResult.put("vehicleClass", Utils.Str.nullIfEmpty(driverLicenseDetailedInfo.getVehicleClass())); + } + return scanResult; + } + + private HashMap getScanRezultFromMrz(MrzResult mrzRezult) { + HashMap scanResult = null; + if (mrzRezult != null) { + scanResult = new HashMap<>(); + + scanResult.put("primaryID", Utils.Str.nullIfEmpty(mrzRezult.getPrimaryId())); + scanResult.put("secondaryID", Utils.Str.nullIfEmpty(mrzRezult.getSecondaryId())); + scanResult.put("issuer", Utils.Str.nullIfEmpty(mrzRezult.getIssuer())); + scanResult.put("issuerName", Utils.Str.nullIfEmpty(mrzRezult.getIssuerName())); + scanResult.put("dateOfBirth", Utils.Str.nullIfEmpty(formatBlinkIdDate(mrzRezult.getDateOfBirth().getDate()))); + scanResult.put("dateOfExpiry", Utils.Str.nullIfEmpty(formatBlinkIdDate(mrzRezult.getDateOfExpiry().getDate()))); + scanResult.put("documentNumber", Utils.Str.nullIfEmpty(mrzRezult.getDocumentNumber())); + scanResult.put("nationality", Utils.Str.nullIfEmpty(mrzRezult.getNationality())); + scanResult.put("nationalityName", Utils.Str.nullIfEmpty(mrzRezult.getNationalityName())); + scanResult.put("gender", Utils.Str.nullIfEmpty(mrzRezult.getGender())); + scanResult.put("documentCode", Utils.Str.nullIfEmpty(mrzRezult.getDocumentCode())); + scanResult.put("alienNumber", Utils.Str.nullIfEmpty(mrzRezult.getAlienNumber())); + scanResult.put("applicationReceiptNumber", Utils.Str.nullIfEmpty(mrzRezult.getApplicationReceiptNumber())); + scanResult.put("immigrantCaseNumber", Utils.Str.nullIfEmpty(mrzRezult.getImmigrantCaseNumber())); + + scanResult.put("opt1", Utils.Str.nullIfEmpty(mrzRezult.getOpt1())); + scanResult.put("opt2", Utils.Str.nullIfEmpty(mrzRezult.getOpt2())); + scanResult.put("mrzText", Utils.Str.nullIfEmpty(mrzRezult.getMrzText())); + + scanResult.put("sanitizedOpt1", Utils.Str.nullIfEmpty(mrzRezult.getSanitizedOpt1())); + scanResult.put("sanitizedOpt2", Utils.Str.nullIfEmpty(mrzRezult.getSanitizedOpt2())); + scanResult.put("sanitizedNationality", Utils.Str.nullIfEmpty(mrzRezult.getSanitizedNationality())); + scanResult.put("sanitizedIssuer", Utils.Str.nullIfEmpty(mrzRezult.getSanitizedIssuer())); + scanResult.put("sanitizedDocumentCode", Utils.Str.nullIfEmpty(mrzRezult.getSanitizedDocumentCode())); + scanResult.put("sanitizedDocumentNumber", Utils.Str.nullIfEmpty(mrzRezult.getSanitizedDocumentNumber())); + } + return scanResult; + } + + private void unInitBlinkId() { + blinkIdRecognizerBundle = null; + blinkIdCombinedRecognizer = null; + blinkIdPassportRecognizer = null; + scanning = false; + } + + private String formatBlinkIdDate(Date date) { + if (date == null) { + return null; + } + return String.format(Locale.getDefault(), "%02d/%02d/%4d", date.getMonth(), date.getDay(), date.getYear()); + } + + //endregion + private Object handleHealthRsiPrivateKey(Object params) { String userId = null; String value = null; @@ -454,6 +708,19 @@ private Object handleHealthRsiPrivateKey(Object params) { } } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == BLINK_ID_REQUEST_CODE) { + if (resultCode == Activity.RESULT_OK) { + onBlinkIdScanSuccess(data); + } else { + onBlinkIdScanCanceled(); + } + } + + super.onActivityResult(requestCode, resultCode, data); + } + /** * Overrides {@link io.flutter.plugin.common.MethodChannel.MethodCallHandler} onMethodCall() */ @@ -490,7 +757,9 @@ public void onMethodCall(MethodCall methodCall, @NonNull MethodChannel.Result re result.success(false); break; case Constants.APP_MICRO_BLINK_SCAN_KEY: - result.success(null); + scanMethodChannelResult = result; + handleMicroBlinkScan(methodCall.arguments); + // Result is called on latter step break; case Constants.APP_ENABLED_ORIENTATIONS_KEY: Object orientations = methodCall.argument("orientations"); diff --git a/android/app/src/main/java/edu/illinois/covid/exposure/ble/NotificationCreator.java b/android/app/src/main/java/edu/illinois/covid/exposure/ble/NotificationCreator.java index ec77f62f..703f7382 100644 --- a/android/app/src/main/java/edu/illinois/covid/exposure/ble/NotificationCreator.java +++ b/android/app/src/main/java/edu/illinois/covid/exposure/ble/NotificationCreator.java @@ -26,7 +26,6 @@ static Notification getNotification(Context context) { NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID) .setContentTitle(context.getString(R.string.exposure_notification_title)) - .setContentText(context.getString(R.string.exposure_notification_message)) .setSmallIcon(R.drawable.app_icon) .setContentIntent(pendingIntent) .setTicker(context.getString(R.string.exposure_notification_ticker)); diff --git a/android/app/src/main/java/edu/illinois/covid/maps/MapActivity.java b/android/app/src/main/java/edu/illinois/covid/maps/MapActivity.java index 8f7facb0..7ea5dbf4 100644 --- a/android/app/src/main/java/edu/illinois/covid/maps/MapActivity.java +++ b/android/app/src/main/java/edu/illinois/covid/maps/MapActivity.java @@ -68,7 +68,6 @@ public class MapActivity extends AppCompatActivity { protected long locationTimestamp; private boolean isRunning; - private boolean firstLocationUpdatePassed; private HashMap target; private HashMap options; @@ -196,8 +195,6 @@ private void fillMarkers(){ //endregion - //region Core Location - private void initCoreLocation() { fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); createCoreLocationCallback(); @@ -237,20 +234,20 @@ public void onLocationResult(LocationResult locationResult) { //region Common Location protected void notifyLocationUpdate(long timestamp) { - locationTimestamp = timestamp; - if (!firstLocationUpdatePassed) { - firstLocationUpdatePassed = true; - handleFirstLocationUpdate(); - } - if ((debugStatusView != null) && showDebugLocation) { - String sourceAbbr = "CL"; - int sourceColor = Color.rgb(0, 126, 0); - double lat = 0.0d; - double lng = 0.0d; - int floor = 0; - debugStatusView.setText(String.format(Locale.getDefault(), "%s [%.6f, %.6f] @ %d", sourceAbbr, lat, lng, floor)); - debugStatusView.setTextColor(sourceColor); - } + locationTimestamp = timestamp; + if (!firstLocationUpdatePassed) { + firstLocationUpdatePassed = true; + handleFirstLocationUpdate(); + } + if ((debugStatusView != null) && showDebugLocation) { + String sourceAbbr = "CL"; + int sourceColor = Color.rgb(0, 126, 0); + double lat = 0.0d; + double lng = 0.0d; + int floor = 0; + debugStatusView.setText(String.format(Locale.getDefault(), "%s [%.6f, %.6f] @ %d", sourceAbbr, lat, lng, floor)); + debugStatusView.setTextColor(sourceColor); + } } protected void notifyLocationFail() { diff --git a/android/app/src/main/java/edu/illinois/covid/maps/MapDirectionsActivity.java b/android/app/src/main/java/edu/illinois/covid/maps/MapDirectionsActivity.java index 93a4234e..aba595bf 100644 --- a/android/app/src/main/java/edu/illinois/covid/maps/MapDirectionsActivity.java +++ b/android/app/src/main/java/edu/illinois/covid/maps/MapDirectionsActivity.java @@ -118,9 +118,9 @@ protected void afterMapInitialized() { @Override protected void notifyLocationUpdate(long timestamp) { super.notifyLocationUpdate(timestamp); - if ((navStatus == NavStatus.PROGRESS) && navAutoUpdate) { - updateNavByCurrentLocation(); - } + if ((navStatus == NavStatus.PROGRESS) && navAutoUpdate) { + updateNavByCurrentLocation(); + } } @Override @@ -312,6 +312,7 @@ private void buildRoute(String travelModeValue) { } private void changeSelectedTravelMode(String newTravelMode) { + } @Override @@ -387,6 +388,7 @@ private void notifyRouteEvent(String event) { String originString = null; String destinationString = null; String locationString = null; + String analyticsParam = String.format(Locale.getDefault(), "{\"origin\":%s,\"destination\":%s,\"location\":%s}", originString, destinationString, locationString); MainActivity.invokeFlutterMethod(event, analyticsParam); } diff --git a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java index 43ccd2fc..a4b50bf0 100644 --- a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java +++ b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -12,15 +12,18 @@ import com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin; import com.whelksoft.flutter_native_timezone.FlutterNativeTimezonePlugin; import io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin; -import io.github.ponnamkarthik.toast.fluttertoast.FluttertoastPlugin; +import io.github.ponnamkarthik.toast.fluttertoast.FlutterToastPlugin; import io.flutter.plugins.imagepicker.ImagePickerPlugin; import com.lyokone.location.LocationPlugin; import io.flutter.plugins.packageinfo.PackageInfoPlugin; import io.flutter.plugins.pathprovider.PathProviderPlugin; +import flutter.plugins.screen.screen.ScreenPlugin; import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin; import com.tekartik.sqflite.SqflitePlugin; import name.avioli.unilinks.UniLinksPlugin; import io.flutter.plugins.urllauncher.UrlLauncherPlugin; +import io.flutter.plugins.videoplayer.VideoPlayerPlugin; +import creativecreatorormaybenot.wakelock.WakelockPlugin; import io.flutter.plugins.webviewflutter.WebViewFlutterPlugin; /** @@ -42,15 +45,18 @@ public static void registerWith(PluginRegistry registry) { FlutterLocalNotificationsPlugin.registerWith(registry.registrarFor("com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin")); FlutterNativeTimezonePlugin.registerWith(registry.registrarFor("com.whelksoft.flutter_native_timezone.FlutterNativeTimezonePlugin")); FlutterAndroidLifecyclePlugin.registerWith(registry.registrarFor("io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin")); - FluttertoastPlugin.registerWith(registry.registrarFor("io.github.ponnamkarthik.toast.fluttertoast.FluttertoastPlugin")); + FlutterToastPlugin.registerWith(registry.registrarFor("io.github.ponnamkarthik.toast.fluttertoast.FlutterToastPlugin")); ImagePickerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.imagepicker.ImagePickerPlugin")); LocationPlugin.registerWith(registry.registrarFor("com.lyokone.location.LocationPlugin")); PackageInfoPlugin.registerWith(registry.registrarFor("io.flutter.plugins.packageinfo.PackageInfoPlugin")); PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); + ScreenPlugin.registerWith(registry.registrarFor("flutter.plugins.screen.screen.ScreenPlugin")); SharedPreferencesPlugin.registerWith(registry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin")); SqflitePlugin.registerWith(registry.registrarFor("com.tekartik.sqflite.SqflitePlugin")); UniLinksPlugin.registerWith(registry.registrarFor("name.avioli.unilinks.UniLinksPlugin")); UrlLauncherPlugin.registerWith(registry.registrarFor("io.flutter.plugins.urllauncher.UrlLauncherPlugin")); + VideoPlayerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.videoplayer.VideoPlayerPlugin")); + WakelockPlugin.registerWith(registry.registrarFor("creativecreatorormaybenot.wakelock.WakelockPlugin")); WebViewFlutterPlugin.registerWith(registry.registrarFor("io.flutter.plugins.webviewflutter.WebViewFlutterPlugin")); } diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml index 964643cb..a0e578b1 100644 --- a/android/app/src/main/res/values-es/strings.xml +++ b/android/app/src/main/res/values-es/strings.xml @@ -53,9 +53,8 @@ Salvar - Notificación de seguimiento de contactos del edificio - Seguimiento de contactos - El seguimiento de contactos para preservar la privacidad se está ejecutando actualmente - Seguimiento de contactos - Permitir notificaciones de exposición. ¿Quieres encender el bluetooth? + Sistema de notificación de exposición + Comprobación del sistema de notificación de exposición + Comprobación del sistema de notificación de exposición + Permitir notificaciones de exposición. ¿Quieres activar Bluetooth? \ No newline at end of file diff --git a/android/app/src/main/res/values-zh/strings.xml b/android/app/src/main/res/values-zh/strings.xml index b0d49114..45658007 100644 --- a/android/app/src/main/res/values-zh/strings.xml +++ b/android/app/src/main/res/values-zh/strings.xml @@ -53,9 +53,8 @@ 保存 - 建築物聯繫人跟踪通知 - 聯繫人跟踪 - 當前正在運行保護隱私的聯繫人跟踪 - 聯繫人跟踪 - 允許曝光通知. 您要打開藍牙嗎? + 曝光通知系統 + 曝光通知系統檢查 + 曝光通知系統檢查 + 允許曝光通知. 您要開啟藍牙嗎? \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index e11bd99e..9763fec6 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -53,9 +53,8 @@ Save - Building contact tracing notification - Contact tracing - Privacy-preserving contact tracing is currently running - Contact tracing - Allow exposure notifications. Do you want to turn the bluetooth on? + Exposure Notification system + Exposure Notification system checking + Exposure Notification system checking + Allow exposure notifications. Do you want to turn on Bluetooth? \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 900f3ab5..ad5a92b4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -39,6 +39,7 @@ allprojects { flatDir { dirs '../lib' } + maven { url 'https://maven.microblink.com' } maven { url 'https://jitpack.io' } } } diff --git a/assets/strings.en.json b/assets/strings.en.json index b0376e08..2c87e4e0 100644 --- a/assets/strings.en.json +++ b/assets/strings.en.json @@ -303,6 +303,12 @@ "panel.covid19_passport.label.access.granted": "GRANTED", "panel.covid19_passport.label.access.denied": "DENIED", "panel.covid19_passport.message.missing_id_info": "No Illini ID information found. You may have an expired i-card. Please contact the ID Center.", + "panel.covid19_passport.button.show_page_1.title": "Show page 1 of 2", + "panel.covid19_passport.button.show_page_1.hint": "", + "panel.covid19_passport.button.show_page_2.title": "Show page 2 of 2", + "panel.covid19_passport.button.show_page_2.hint": "", + "panel.covid19_passport.label.page_1": "Page 1", + "panel.covid19_passport.label.page_2": "Page 2", "panel.covid19_guidelines.header.title": "County Guidelines", "panel.covid19_guidelines.description.title": "Help stop the spread of COVID-19 by following these current guidelines.", @@ -352,6 +358,8 @@ "panel.covid19_test_locations.work_time.closed_until": "Closed until", "panel.covid19_test_locations.all_providers.text": "All Providers", "panel.covid19_test_locations.call.hint": "Call", + "panel.covid19_test_locations.wait_time.label": "Wait Time", + "panel.covid19_test_locations.wait_time.unavailable": "Unavailable", "panel.covid19.header.title": "COVID-19", "panel.covid19.latest_update.title": "Latest Update", @@ -696,7 +704,6 @@ "panel.health.next_steps.button.continue.title.find_locatio": "Find location", "panel.health.next_steps.button.continue.title.care_team": "Get in Touch with Care Team", "panel.health.next_steps.label.next_steps": "NEXT STEPS", - "panel.health.next_steps.label.asap": "ASAP", "panel.health.symptoms.heading.title":"Are you experiencing any of these symptoms?", "panel.health.symptoms.label.error.loading":"Failed to load symptoms.", diff --git a/assets/strings.es.json b/assets/strings.es.json index a22aa1b9..0fbf72d7 100644 --- a/assets/strings.es.json +++ b/assets/strings.es.json @@ -303,6 +303,13 @@ "panel.covid19_passport.label.access.granted": "CONCEDIDO", "panel.covid19_passport.label.access.denied": "NEGADO", "panel.covid19_passport.message.missing_id_info": "No se encontró información de identificación de Illini. Es posible que tenga una i-card vencida. Comuníquese con el Centro de identificación.", + "panel.covid19_passport.button.show_page_1.title": "Show page 1 of 2", + "panel.covid19_passport.button.show_page_1.hint": "", + "panel.covid19_passport.button.show_page_2.title": "Show page 2 of 2", + "panel.covid19_passport.button.show_page_2.hint": "", + "panel.covid19_passport.label.page_1": "Page 1", + "panel.covid19_passport.label.page_2": "Page 2", + "panel.covid19_guidelines.header.title": "Pautas del condado", "panel.covid19_guidelines.description.title": "Ayude a detener la propagación de COVID-19 siguiendo estas pautas actuales.", @@ -352,6 +359,8 @@ "panel.covid19_test_locations.work_time.closed_until": "Cerrado hasta", "panel.covid19_test_locations.all_providers.text": "Todos los proveedores", "panel.covid19_test_locations.call.hint": "Llamada", + "panel.covid19_test_locations.wait_time.label": "Tiempo de espera", + "panel.covid19_test_locations.wait_time.unavailable": "Indisponible", "panel.covid19.header.title": "COVID-19", "panel.covid19.latest_update.title": "Última actualización", @@ -696,7 +705,6 @@ "panel.health.next_steps.button.continue.title.find_locatio": "Encontrar ubicacion", "panel.health.next_steps.button.continue.title.care_team": "Póngase en contacto con Care Team", "panel.health.next_steps.label.next_steps": "PRÓXIMOS PASOS", - "panel.health.next_steps.label.asap": "Lo antes posible", "panel.health.symptoms.heading.title":"¿Estás experimentando alguno de estos síntomas?", "panel.health.symptoms.label.error.loading":"Error al cargar los síntomas.", diff --git a/assets/strings.zh.json b/assets/strings.zh.json index 8d15ad97..66f8f691 100644 --- a/assets/strings.zh.json +++ b/assets/strings.zh.json @@ -303,6 +303,12 @@ "panel.covid19_passport.label.access.granted": "授予", "panel.covid19_passport.label.access.denied": "否认", "panel.covid19_passport.message.missing_id_info": "找不到Illini ID信息. 您的I-Card可能已过期。请与ID中心联系.", + "panel.covid19_passport.button.show_page_1.title": "Show page 1 of 2", + "panel.covid19_passport.button.show_page_1.hint": "", + "panel.covid19_passport.button.show_page_2.title": "Show page 2 of 2", + "panel.covid19_passport.button.show_page_2.hint": "", + "panel.covid19_passport.label.page_1": "Page 1", + "panel.covid19_passport.label.page_2": "Page 2", "panel.covid19_guidelines.header.title": "縣準則", "panel.covid19_guidelines.description.title": "遵循這些當前準則,有助於阻止COVID-19的傳播。", @@ -352,6 +358,8 @@ "panel.covid19_test_locations.work_time.closed_until": "关闭到", "panel.covid19_test_locations.all_providers.text": "所有提供者", "panel.covid19_test_locations.call.hint": "呼叫", + "panel.covid19_test_locations.wait_time.label": "等待時間", + "panel.covid19_test_locations.wait_time.unavailable": "不可用", "panel.covid19.header.title": "COVID-19", "panel.covid19.latest_update.title": "最近更新", @@ -696,7 +704,6 @@ "panel.health.next_steps.button.continue.title.find_locatio": "查找位置", "panel.health.next_steps.button.continue.title.care_team": "联系护理团队", "panel.health.next_steps.label.next_steps": "下一步行动", - "panel.health.next_steps.label.asap": "尽快", "panel.health.symptoms.heading.title":"你有这些症状吗?", "panel.health.symptoms.label.error.loading":"未能加载症状.", diff --git a/assets/styles.json b/assets/styles.json index bfd4217e..ad83eaa1 100644 --- a/assets/styles.json +++ b/assets/styles.json @@ -51,7 +51,12 @@ "healthStatusOrange" :"#F29835", "healthStatusRed" :"#FF4F4F", - "lightBlue" :"#42b9ea" + "lightBlue" :"#42b9ea", + + "healthLocationWaitTimeColorRed" :"#ff0000", + "healthLocationWaitTimeColorYellow" :"#ffff00", + "healthLocationWaitTimeColorGreen" :"#00ff00", + "healthLocationWaitTimeColorGrey" :"#808080" }, "font_family": { "black": "ProximaNovaBlack", diff --git a/assets/styles/styles-illinois.json b/assets/styles/styles-illinois.json index 9cbf49e0..c5b58f21 100644 --- a/assets/styles/styles-illinois.json +++ b/assets/styles/styles-illinois.json @@ -51,7 +51,12 @@ "healthStatusOrange" :"#E84A27", "healthStatusRed" :"#FF4F4F", - "lightBlue" :"#42b9ea" + "lightBlue" :"#42b9ea", + + "healthLocationWaitTimeColorRed" :"#ff0000", + "healthLocationWaitTimeColorYellow" :"#ffff00", + "healthLocationWaitTimeColorGreen" :"#00ff00", + "healthLocationWaitTimeColorGrey" :"#808080" }, "font_family": { "black": "ProximaNovaBlack", diff --git a/assets/styles/styles-purdue.json b/assets/styles/styles-purdue.json index 08906edc..a7c1f4e3 100644 --- a/assets/styles/styles-purdue.json +++ b/assets/styles/styles-purdue.json @@ -50,7 +50,12 @@ "healthStatusOrange" :"#E84A27", "healthStatusRed" :"#FF4F4F", - "lightBlue" :"#42b9ea" + "lightBlue" :"#42b9ea", + + "healthLocationWaitTimeColorRed" :"#ff0000", + "healthLocationWaitTimeColorYellow" :"#ffff00", + "healthLocationWaitTimeColorGreen" :"#00ff00", + "healthLocationWaitTimeColorGrey" :"#808080" }, "font_family": { "black": "ProximaNovaBlack", diff --git a/assets/styles/styles-uic.json b/assets/styles/styles-uic.json index 94f2dca9..58f291f3 100644 --- a/assets/styles/styles-uic.json +++ b/assets/styles/styles-uic.json @@ -51,7 +51,12 @@ "healthStatusOrange" :"#E84A27", "healthStatusRed" :"#FF4F4F", - "lightBlue" :"#42b9ea" + "lightBlue" :"#42b9ea", + + "healthLocationWaitTimeColorRed" :"#ff0000", + "healthLocationWaitTimeColorYellow" :"#ffff00", + "healthLocationWaitTimeColorGreen" :"#00ff00", + "healthLocationWaitTimeColorGrey" :"#808080" }, "font_family": { "black": "ProximaNovaBlack", diff --git a/ios/Podfile b/ios/Podfile index 79389159..b8abc9c1 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -11,90 +11,40 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + target 'Runner' do use_frameworks! use_modular_headers! - - pod 'GoogleMaps', '3.3.0' - - # Disable Microblink in Safer 2.4 - # pod 'PPBlinkID', '~> 5.3.0' - - pod 'ZXingObjC', '3.6.4' - pod 'HKDFKit', '0.0.3' - pod 'Firebase/MLVisionBarcodeModel' - - # Flutter Pod - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. + pod 'GoogleMaps', '3.3.0' + pod 'MapsIndoors', '3.8.0' + pod 'ZXingObjC', '3.6.4' + pod 'PPBlinkID', '~> 5.3.0' + pod 'HKDFKit', '0.0.3' + pod 'Firebase/MLVisionBarcodeModel' - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' - - # Plugin Pods - - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') - end + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 716c063f..276389cc 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ 2605FF54236C13A6002F71BE /* GoogleService-Info-Debug.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2605FF52236C13A6002F71BE /* GoogleService-Info-Debug.plist */; }; 2605FF55236C13A6002F71BE /* GoogleService-Info-Release.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2605FF53236C13A6002F71BE /* GoogleService-Info-Release.plist */; }; 2626D94B22DC99C800F6BC2F /* NSString+InaJson.m in Sources */ = {isa = PBXBuildFile; fileRef = 2626D94922DC99C700F6BC2F /* NSString+InaJson.m */; }; + 2626D94E22DCB80000F6BC2F /* MapMarkerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2626D94D22DCB80000F6BC2F /* MapMarkerView.m */; }; + 266FA50323E0388B00F800F5 /* MapController.m in Sources */ = {isa = PBXBuildFile; fileRef = 266FA50223E0388B00F800F5 /* MapController.m */; }; 268F30F122E5DD7900547FE1 /* travel-mode-walk@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 268F30ED22E5DD7900547FE1 /* travel-mode-walk@2x.png */; }; 268F30F222E5DD7900547FE1 /* travel-mode-transit@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 268F30EE22E5DD7900547FE1 /* travel-mode-transit@2x.png */; }; 268F30F322E5DD7900547FE1 /* travel-mode-bicycle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 268F30EF22E5DD7900547FE1 /* travel-mode-bicycle@2x.png */; }; @@ -29,6 +31,7 @@ 2696995D22C38B4000B3290E /* AppKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 2696995922C38B4000B3290E /* AppKeys.m */; }; 2696995E22C38B4000B3290E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2696995A22C38B4000B3290E /* AppDelegate.m */; }; 2696996022C38C1D00B3290E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2696995F22C38C1D00B3290E /* main.m */; }; + 2696998022C3A14A00B3290E /* MapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2696997F22C3A14A00B3290E /* MapView.m */; }; 269F83E622D73E7400CC11A4 /* maps-icon-marker-circle-10@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 269F83E222D73E7400CC11A4 /* maps-icon-marker-circle-10@2x.png */; }; 269F83E722D73E7400CC11A4 /* maps-icon-marker-circle-30@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 269F83E322D73E7400CC11A4 /* maps-icon-marker-circle-30@2x.png */; }; 269F83E822D73E7400CC11A4 /* maps-icon-marker-circle-20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 269F83E422D73E7400CC11A4 /* maps-icon-marker-circle-20@2x.png */; }; @@ -36,13 +39,10 @@ 269F83EE22D73EB400CC11A4 /* NSDate+UIUCUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 269F83EA22D73EB400CC11A4 /* NSDate+UIUCUtils.m */; }; 269F83EF22D73EB400CC11A4 /* UIColor+InaParse.m in Sources */ = {isa = PBXBuildFile; fileRef = 269F83EC22D73EB400CC11A4 /* UIColor+InaParse.m */; }; 269F83F222D744E200CC11A4 /* CGGeometry+InaUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 269F83F122D744E200CC11A4 /* CGGeometry+InaUtils.m */; }; + 269F83FC22D77E5500CC11A4 /* MapDirectionsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 269F83FB22D77E5500CC11A4 /* MapDirectionsController.m */; }; 26A170EB22DDFB6500299773 /* button-icon-nav-next.png in Resources */ = {isa = PBXBuildFile; fileRef = 26A170E822DDFB6500299773 /* button-icon-nav-next.png */; }; 26A170EC22DDFB6500299773 /* button-icon-nav-prev.png in Resources */ = {isa = PBXBuildFile; fileRef = 26A170E922DDFB6500299773 /* button-icon-nav-prev.png */; }; 26A170ED22DDFB6500299773 /* button-icon-nav-clear.png in Resources */ = {isa = PBXBuildFile; fileRef = 26A170EA22DDFB6500299773 /* button-icon-nav-clear.png */; }; - 26AA76FF2508BD3500BD9CE1 /* MapController.m in Sources */ = {isa = PBXBuildFile; fileRef = 266FA50223E0388B00F800F5 /* MapController.m */; }; - 26AA77002508BD3500BD9CE1 /* MapDirectionsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 269F83FB22D77E5500CC11A4 /* MapDirectionsController.m */; }; - 26AA77012508BD3500BD9CE1 /* MapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2696997F22C3A14A00B3290E /* MapView.m */; }; - 26AA77022508BD3500BD9CE1 /* MapMarkerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2626D94D22DCB80000F6BC2F /* MapMarkerView.m */; }; 26B3403A2331195C0031CF70 /* UILabel+InaMeasure.m in Sources */ = {isa = PBXBuildFile; fileRef = 26B340392331195C0031CF70 /* UILabel+InaMeasure.m */; }; 26C07E2E247677A600E28D43 /* ExposurePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 26C07E2D247677A600E28D43 /* ExposurePlugin.m */; }; 26C90CED2361CF480092E07F /* NSDictionary+InaPathKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 26C90CEC2361CF480092E07F /* NSDictionary+InaPathKey.m */; }; @@ -388,7 +388,7 @@ 3B06AD1E1E4923F5004D2608 /* Thin Binary */, A6EAEE2D144BCA7DA3F58188 /* [CP] Embed Pods Frameworks */, 263F851F234C9C8B00397B65 /* ShellScript */, - 60FBDE3BD228BDE60FDF5E57 /* [CP] Copy Pods Resources */, + DAC4964BD8E22D8D096DBF86 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -510,21 +510,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 60FBDE3BD228BDE60FDF5E57 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 6B05DA47C845612A0CC4C440 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -567,15 +552,112 @@ files = ( ); inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", + "${PODS_ROOT}/../Flutter/Flutter.framework", + "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework", + "${BUILT_PRODUCTS_DIR}/GoogleAPIClientForREST/GoogleAPIClientForREST.framework", + "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework", + "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", + "${BUILT_PRODUCTS_DIR}/HKDFKit/HKDFKit.framework", + "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", + "${BUILT_PRODUCTS_DIR}/Mantle/Mantle.framework", + "${PODS_ROOT}/PPBlinkID/Microblink.framework", + "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", + "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework", + "${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder/SDWebImageWebPCoder.framework", + "${BUILT_PRODUCTS_DIR}/ZXingObjC/ZXingObjC.framework", + "${BUILT_PRODUCTS_DIR}/barcode_scan/barcode_scan.framework", + "${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework", + "${BUILT_PRODUCTS_DIR}/device_info/device_info.framework", + "${BUILT_PRODUCTS_DIR}/flutter_image_compress/flutter_image_compress.framework", + "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework", + "${BUILT_PRODUCTS_DIR}/flutter_native_timezone/flutter_native_timezone.framework", + "${BUILT_PRODUCTS_DIR}/fluttertoast/fluttertoast.framework", + "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", + "${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework", + "${BUILT_PRODUCTS_DIR}/location/location.framework", + "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", + "${BUILT_PRODUCTS_DIR}/package_info/package_info.framework", + "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", + "${BUILT_PRODUCTS_DIR}/screen/screen.framework", + "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", + "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", + "${BUILT_PRODUCTS_DIR}/uni_links/uni_links.framework", + "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", + "${BUILT_PRODUCTS_DIR}/video_player/video_player.framework", + "${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework", + "${BUILT_PRODUCTS_DIR}/webview_flutter/webview_flutter.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleAPIClientForREST.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HKDFKit.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mantle.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Microblink.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZXingObjC.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/barcode_scan.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_image_compress.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_native_timezone.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fluttertoast.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/location.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/screen.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/uni_links.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/webview_flutter.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + DAC4964BD8E22D8D096DBF86 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Resources/GoogleMaps.bundle", + "${PODS_ROOT}/MapsIndoors/MapsIndoors.framework/Versions/A/Resources/MapsIndoors.bundle", + "${PODS_ROOT}/PPBlinkID/Microblink.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMaps.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MapsIndoors.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Microblink.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -587,17 +669,15 @@ B6201F5B24E2D8080050F7DC /* GalleryPlugin.m in Sources */, 268F310022E5E7BF00547FE1 /* NSUserDefaults+InaUtils.m in Sources */, 26C90CF02361D13E0092E07F /* NSDictionary+UIUCConfig.m in Sources */, - 26AA76FF2508BD3500BD9CE1 /* MapController.m in Sources */, - 26AA77012508BD3500BD9CE1 /* MapView.m in Sources */, 269F83F222D744E200CC11A4 /* CGGeometry+InaUtils.m in Sources */, B6EA372423A7EF76001D78A5 /* Bluetooth+InaUtils.m in Sources */, - 26AA77002508BD3500BD9CE1 /* MapDirectionsController.m in Sources */, + 269F83FC22D77E5500CC11A4 /* MapDirectionsController.m in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 268F647D22DF09D900A85AFD /* NSArray+InaTypedValue.m in Sources */, 2696995D22C38B4000B3290E /* AppKeys.m in Sources */, 268F647A22DF050400A85AFD /* CLLocationCoordinate2D+InaUtils.m in Sources */, + 2626D94E22DCB80000F6BC2F /* MapMarkerView.m in Sources */, 269F83EE22D73EB400CC11A4 /* NSDate+UIUCUtils.m in Sources */, - 26AA77022508BD3500BD9CE1 /* MapMarkerView.m in Sources */, B681B2B923DEFD9E00093A67 /* NSData+InaHex.m in Sources */, 26FA06BE22CCA9B5003B78E4 /* NSDictionary+InaTypedValue.m in Sources */, 2626D94B22DC99C800F6BC2F /* NSString+InaJson.m in Sources */, @@ -605,10 +685,12 @@ 26C90CED2361CF480092E07F /* NSDictionary+InaPathKey.m in Sources */, 26ECB3262487AD0900479487 /* Security+UIUCUtils.m in Sources */, 26FAB1C922EB3502008E987C /* NSDictionary+UIUCExplore.m in Sources */, + 266FA50323E0388B00F800F5 /* MapController.m in Sources */, 2696996022C38C1D00B3290E /* main.m in Sources */, 2696995E22C38B4000B3290E /* AppDelegate.m in Sources */, 26B3403A2331195C0031CF70 /* UILabel+InaMeasure.m in Sources */, 26FAB1CC22EB35C7008E987C /* NSDate+InaUtils.m in Sources */, + 2696998022C3A14A00B3290E /* MapView.m in Sources */, 26ECB3232487938C00479487 /* CommonCrypto+UIUCUtils.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -647,7 +729,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -725,7 +806,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -782,7 +862,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; diff --git a/ios/Runner/AppDelegate.m b/ios/Runner/AppDelegate.m index 06f3fd1f..d2f80d4d 100644 --- a/ios/Runner/AppDelegate.m +++ b/ios/Runner/AppDelegate.m @@ -26,8 +26,6 @@ #import "MapDirectionsController.h" #import "ExposurePlugin.h" #import "GalleryPlugin.h" -#import "FlutterCompletion.h" - #import "NSArray+InaTypedValue.h" #import "NSDictionary+InaTypedValue.h" @@ -37,12 +35,9 @@ #import "Bluetooth+InaUtils.h" #import - -// Disable Microblink in Safer 2.4 -//#import - #import #import +#import #import #import @@ -63,8 +58,7 @@ @interface LaunchScreenView : UIView UIInterfaceOrientation _interfaceOrientationFromMask(UIInterfaceOrientationMask value); UIInterfaceOrientationMask _interfaceOrientationToMask(UIInterfaceOrientation value); -@interface AppDelegate() { +@interface AppDelegate() { } // Flutter @@ -80,12 +74,11 @@ @interface AppDelegate()) -#import +#if __has_include() +#import #else @import connectivity; #endif @@ -94,8 +94,14 @@ @import path_provider; #endif -#if __has_include() -#import +#if __has_include() +#import +#else +@import screen; +#endif + +#if __has_include() +#import #else @import shared_preferences; #endif @@ -118,6 +124,18 @@ @import url_launcher; #endif +#if __has_include() +#import +#else +@import video_player; +#endif + +#if __has_include() +#import +#else +@import wakelock; +#endif + #if __has_include() #import #else @@ -142,10 +160,13 @@ + (void)registerWithRegistry:(NSObject*)registry { [LocationPlugin registerWithRegistrar:[registry registrarForPlugin:@"LocationPlugin"]]; [FLTPackageInfoPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPackageInfoPlugin"]]; [FLTPathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPathProviderPlugin"]]; + [ScreenPlugin registerWithRegistrar:[registry registrarForPlugin:@"ScreenPlugin"]]; [FLTSharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTSharedPreferencesPlugin"]]; [SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]]; [UniLinksPlugin registerWithRegistrar:[registry registrarForPlugin:@"UniLinksPlugin"]]; [FLTURLLauncherPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTURLLauncherPlugin"]]; + [FLTVideoPlayerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTVideoPlayerPlugin"]]; + [WakelockPlugin registerWithRegistrar:[registry registrarForPlugin:@"WakelockPlugin"]]; [FLTWebViewFlutterPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTWebViewFlutterPlugin"]]; } diff --git a/lib/model/Auth.dart b/lib/model/Auth.dart index 85c93147..cfa01282 100644 --- a/lib/model/Auth.dart +++ b/lib/model/Auth.dart @@ -179,6 +179,7 @@ class AuthCard { final String uin; final String fullName; final String role; + final String studentLevel; final String cardNumber; final String expirationDate; final String libraryNumber; @@ -189,13 +190,14 @@ class AuthCard { return (photoBase64 != null) ? await compute(AppBytes.decodeBase64Bytes, photoBase64) : null; } - AuthCard({this.uin, this.cardNumber, this.libraryNumber, this.expirationDate, this.fullName, this.role, this.magTrack2, this.photoBase64}); + AuthCard({this.uin, this.cardNumber, this.libraryNumber, this.expirationDate, this.fullName, this.role, this.studentLevel, this.magTrack2, this.photoBase64}); factory AuthCard.fromJson(Map json) { return AuthCard( uin: json['UIN'], fullName: json['full_name'], role: json['role'], + studentLevel: json['student_level'], cardNumber: json['card_number'], expirationDate: json['expiration_date'], libraryNumber: json['library_number'], @@ -209,6 +211,7 @@ class AuthCard { 'UIN': uin, 'full_name': fullName, 'role': role, + 'student_level': studentLevel, 'card_number': cardNumber, 'expiration_date': expirationDate, 'library_number': libraryNumber, @@ -222,6 +225,7 @@ class AuthCard { 'UIN': uin, 'full_name': fullName, 'role': role, + 'student_level': studentLevel, 'card_number': cardNumber, 'expiration_date': expirationDate, 'library_number': libraryNumber, @@ -235,6 +239,7 @@ class AuthCard { o.uin == uin && o.fullName == fullName && o.role == role && + o.studentLevel == studentLevel && o.cardNumber == cardNumber && o.expirationDate == expirationDate && o.libraryNumber == libraryNumber && @@ -245,6 +250,7 @@ class AuthCard { uin.hashCode ^ fullName.hashCode ^ role.hashCode ^ + studentLevel.hashCode ^ cardNumber.hashCode ^ expirationDate.hashCode ^ libraryNumber.hashCode ^ diff --git a/lib/model/Health.dart b/lib/model/Health.dart index 23d00c54..88d7f280 100644 --- a/lib/model/Health.dart +++ b/lib/model/Health.dart @@ -1275,9 +1275,10 @@ class HealthServiceLocation { String notes; double latitude; double longitude; + HealthLocationWaitTimeColor waitTimeColor; List availableTests; List daysOfOperation; - HealthServiceLocation({this.id, this.name, this.availableTests, this.contact, this.city, this.address1, this.address2, this.state, this.country, this.zip, this.url, this.notes, this.latitude, this.longitude, this.daysOfOperation}); + HealthServiceLocation({this.id, this.name, this.availableTests, this.contact, this.city, this.address1, this.address2, this.state, this.country, this.zip, this.url, this.notes, this.latitude, this.longitude, this.waitTimeColor, this.daysOfOperation}); factory HealthServiceLocation.fromJson(Map json) { List jsoTests = json['available_tests']; @@ -1296,6 +1297,7 @@ class HealthServiceLocation { notes: json["notes"], latitude: AppJson.doubleValue(json["latitude"]), longitude: AppJson.doubleValue(json["longitude"]), + waitTimeColor: HealthServiceLocation.waitTimeColorFromString(json['wait_time_color']), availableTests: jsoTests!=null ? List.from(jsoTests) : null, daysOfOperation: jsonDaysOfOperation!=null ? HealthLocationDayOfOperation.listFromJson(jsonDaysOfOperation) : null, ) : null; @@ -1316,6 +1318,7 @@ class HealthServiceLocation { 'notes': notes, 'latitude': latitude, 'longitude': longitude, + 'wait_time_color': HealthServiceLocation.waitTimeColorToKeyString(waitTimeColor), 'available_tests': availableTests, }; } @@ -1362,6 +1365,48 @@ class HealthServiceLocation { } return json; } + + static HealthLocationWaitTimeColor waitTimeColorFromString(String colorString) { + if (colorString == 'red') { + return HealthLocationWaitTimeColor.red; + } else if (colorString == 'yellow') { + return HealthLocationWaitTimeColor.yellow; + } else if (colorString == 'green') { + return HealthLocationWaitTimeColor.green; + } else if (colorString == 'grey') { + return HealthLocationWaitTimeColor.grey; + } else { + return null; + } + } + + static String waitTimeColorToKeyString(HealthLocationWaitTimeColor color) { + switch (color) { + case HealthLocationWaitTimeColor.red: + return 'red'; + case HealthLocationWaitTimeColor.yellow: + return 'yellow'; + case HealthLocationWaitTimeColor.green: + return 'green'; + case HealthLocationWaitTimeColor.grey: + return 'grey'; + default: + return null; + } + } + + static Color waitTimeColorHex(HealthLocationWaitTimeColor color) { + switch (color) { + case HealthLocationWaitTimeColor.red: + return Styles().colors.healthLocationWaitTimeColorRed; + case HealthLocationWaitTimeColor.yellow: + return Styles().colors.healthLocationWaitTimeColorYellow; + case HealthLocationWaitTimeColor.green: + return Styles().colors.healthLocationWaitTimeColorGreen; + default: + return Styles().colors.healthLocationWaitTimeColorGrey; + } + } } /////////////////////////////// @@ -1439,6 +1484,11 @@ class HealthLocationDayOfOperation { } } +/////////////////////////////// +// HealthLocationWaitTimeColor + +enum HealthLocationWaitTimeColor { red, yellow, green, grey } + /////////////////////////////// // HealthTestType diff --git a/lib/service/Health.dart b/lib/service/Health.dart index 29136070..92784492 100644 --- a/lib/service/Health.dart +++ b/lib/service/Health.dart @@ -485,8 +485,9 @@ class Health with Service implements NotificationsListener { return rules?.symptoms?.groups; } else { - String url = "${Config().health2Url}/symptoms/symptoms.json"; - Response response = await Network().get(url); + String url = "${Config().healthUrl}/covid19/symptoms"; + String appVersion = AppVersion.majorVersion(Config().appVersion, 2); + Response response = await Network().get(url, auth: NetworkAuth.App, headers: { Network.RokwireVersion : appVersion }); String responseBody = (response?.statusCode == 200) ? response.body : null; //TMP:String responseBody = await rootBundle.loadString('assets/sample.health.symptoms.json'); List responseJson = (responseBody != null) ? AppJson.decodeList(responseBody) : null; @@ -1390,8 +1391,9 @@ class Health with Service implements NotificationsListener { // Consolidated Rules Future _loadRules2({String countyId}) async { - String url = "${Config().health2Url}/rules/county/$countyId/rules.json"; - Response response = await Network().get(url); + String appVersion = AppVersion.majorVersion(Config().appVersion, 2); + String url = "${Config().healthUrl}/covid19/crules/county/$countyId"; + Response response = await Network().get(url, auth: NetworkAuth.App, headers: { Network.RokwireVersion : appVersion }); String responseBody = (response?.statusCode == 200) ? response.body : null; //TMP:String responseBody = await rootBundle.loadString('assets/sample.health.rules.json'); Map responseJson = (responseBody != null) ? AppJson.decodeMap(responseBody) : null; diff --git a/lib/service/LocationServices.dart b/lib/service/LocationServices.dart index d09e4fe3..d7eb5da6 100644 --- a/lib/service/LocationServices.dart +++ b/lib/service/LocationServices.dart @@ -82,7 +82,7 @@ class LocationServices with Service implements NotificationsListener { _lastStatus = LocationServicesStatus.PermissionNotDetermined; } else { - _lastStatus = await Location().hasPermission() ? LocationServicesStatus.PermissionAllowed : LocationServicesStatus.PermissionDenied; + _lastStatus = await Location().hasPermission() == PermissionStatus.granted ? LocationServicesStatus.PermissionAllowed : LocationServicesStatus.PermissionDenied; } _updateLocationMonitor(); @@ -114,7 +114,7 @@ class LocationServices with Service implements NotificationsListener { _lastStatus = LocationServicesStatus.ServiceDisabled; } else if (Storage().locationServicesPermisionRequested) { - _lastStatus = await Location().hasPermission() ? LocationServicesStatus.PermissionAllowed : LocationServicesStatus.PermissionDenied; + _lastStatus = await Location().hasPermission() == PermissionStatus.granted ? LocationServicesStatus.PermissionAllowed : LocationServicesStatus.PermissionDenied; } else { _lastStatus = _locationServicesStatusFromString(await NativeCommunicator().queryLocationServicesPermission('request')); @@ -148,7 +148,7 @@ class LocationServices with Service implements NotificationsListener { void _openLocationMonitor() { if (_locationMonitor == null) { - _locationMonitor = Location().onLocationChanged().listen((LocationData location) { + _locationMonitor = Location().onLocationChanged.listen((LocationData location) { _lastLocation = location; _notifyLocationChanged(); }); diff --git a/lib/service/Network.dart b/lib/service/Network.dart index f16b422b..0b5df491 100644 --- a/lib/service/Network.dart +++ b/lib/service/Network.dart @@ -39,7 +39,8 @@ class Network { static const String RokwireApiKey = 'ROKWIRE-API-KEY'; static const String RokwireHSApiKey = 'ROKWIRE-HS-API-KEY'; - + static const String RokwireVersion = 'V'; + static final Network _network = new Network._internal(); factory Network() { return _network; diff --git a/lib/service/Styles.dart b/lib/service/Styles.dart index 86988eb9..23bf8fe8 100644 --- a/lib/service/Styles.dart +++ b/lib/service/Styles.dart @@ -289,6 +289,11 @@ class UiColors { Color get lightBlue => _colorMap['lightBlue']; + Color get healthLocationWaitTimeColorRed => _colorMap['healthLocationWaitTimeColorRed']; + Color get healthLocationWaitTimeColorYellow => _colorMap['healthLocationWaitTimeColorYellow']; + Color get healthLocationWaitTimeColorGreen => _colorMap['healthLocationWaitTimeColorGreen']; + Color get healthLocationWaitTimeColorGrey => _colorMap['healthLocationWaitTimeColorGrey']; + Color getColor(String key){ dynamic color = _colorMap[key]; return (color is Color) ? color : null; diff --git a/lib/ui/health/Covid19AddTestResultPanel.dart b/lib/ui/health/Covid19AddTestResultPanel.dart index 9674bdfd..3c335311 100644 --- a/lib/ui/health/Covid19AddTestResultPanel.dart +++ b/lib/ui/health/Covid19AddTestResultPanel.dart @@ -238,7 +238,9 @@ class _Covid19AddTestResultPanelState extends State i enabled: _canRetrieve, backgroundColor: Styles().colors.white, borderColor: _canRetrieve? Styles().colors.fillColorSecondary : Styles().colors.surfaceAccent , - textColor: _canRetrieve? Styles().colors.fillColorSecondary : Styles().colors.surfaceAccent ,), + textColor: _canRetrieve? Styles().colors.fillColorSecondary : Styles().colors.surfaceAccent , + showExternalLink: true, + ), _retrieving ? Center(child: CircularProgressIndicator(strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Styles().colors.fillColorSecondary),)) : Container(), ], ) : Container(), diff --git a/lib/ui/health/Covid19InfoCenterPanel.dart b/lib/ui/health/Covid19InfoCenterPanel.dart index 65388b06..c265af3e 100644 --- a/lib/ui/health/Covid19InfoCenterPanel.dart +++ b/lib/ui/health/Covid19InfoCenterPanel.dart @@ -19,10 +19,12 @@ import 'dart:collection'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.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/AppDateTime.dart'; import 'package:illinois/service/Config.dart'; +import 'package:illinois/service/Connectivity.dart'; import 'package:illinois/service/Health.dart'; import 'package:illinois/service/Localization.dart'; import 'package:illinois/service/NotificationService.dart'; @@ -328,7 +330,7 @@ class _Covid19InfoCenterPanelState extends State impleme if (AppString.isStringNotEmpty(nextStepHtml)) { content.addAll([ Container(height: 12,), - Html(data: nextStepHtml, onLinkTap: (url) => _onTapLink(url), defaultTextStyle: TextStyle(fontSize: 16, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground),), + Html(data: nextStepHtml, onLinkTap: (url) => _onTapLink(url), style:{ 'body' : Style(fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground)},), ]); } @@ -593,100 +595,92 @@ class _Covid19InfoCenterPanelState extends State impleme ), ); } - - - /*Widget _buildCampusUpdatesSection() { - String title = Localization().getStringEx("panel.covid19home.label.campus_updates.title","Campus Updates"); - return Semantics(container: true, child: - InkWell(onTap: () => _onTapCampusUpdates(), child: - Container( - padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16 - ), - decoration: BoxDecoration(color: Styles().colors.surface, borderRadius: BorderRadius.all(Radius.circular(4)), boxShadow: [BoxShadow(color: Styles().colors.blackTransparent018, spreadRadius: 2.0, blurRadius: 6.0, offset: Offset(2, 2))] ), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row(children: [ - Expanded(child: - Text(title, style: TextStyle(fontFamily: Styles().fontFamilies.extraBold, fontSize: 20, color: Styles().colors.fillColorPrimary),), - ), - Image.asset('images/chevron-right.png'), - ],), - ],),),), - ); - }*/ - - /*Widget _buildAboutButton() { - return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - boxShadow: [BoxShadow(color: Color.fromRGBO(19, 41, 75, 0.3), spreadRadius: 2.0, blurRadius: 8.0, offset: Offset(0, 2))], - ), - child: RibbonButton( - label: Localization().getStringEx("panel.covid19home.button.about.title","About"), - borderRadius: BorderRadius.circular(4), - onTap: ()=>_onTapAbout(), - ), - ); - }*/ void _onTapCountryGuidelines() { - Analytics.instance.logSelect(target: "COVID-19 County Guidlines"); - Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19GuidelinesPanel(status: _status))); + if(Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "COVID-19 County Guidlines"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19GuidelinesPanel(status: _status))); + } else{ + AppAlert.showOfflineMessage(context); + } } - /*void _onTapCampusUpdates() { - Analytics.instance.logSelect(target: "COVID-19 Campus Updates"); - Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19UpdatesPanel())); - }*/ - void _onTapCareTeam() { - Analytics.instance.logSelect(target: "Your Care Team"); - Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19CareTeamPanel(status: _status,))); + if(Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Your Care Team"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19CareTeamPanel(status: _status,))); + } else{ + AppAlert.showOfflineMessage(context); + } } void _onTapReportTest(){ - Analytics.instance.logSelect(target: "COVID-19 Report Test"); - Navigator.push(context, CupertinoPageRoute(builder: (context)=>Covid19AddTestResultPanel())); + if(Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "COVID-19 Report Test"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19AddTestResultPanel())); + } else{ + AppAlert.showOfflineMessage(context); + } } void _onTapTestHistory(){ - Analytics.instance.logSelect(target: "COVID-19 Test History"); - Navigator.push(context, CupertinoPageRoute(builder: (context)=>Covid19HistoryPanel())); + if(Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "COVID-19 Test History"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19HistoryPanel())); + } else{ + AppAlert.showOfflineMessage(context); + } } void _onTapFindLocations(){ - Analytics.instance.logSelect(target: "COVID-19 Find Test Locations"); - Navigator.push(context, CupertinoPageRoute(builder: (context)=>Covid19TestLocationsPanel())); + if(Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "COVID-19 Find Test Locations"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19TestLocationsPanel())); + } else{ + AppAlert.showOfflineMessage(context); + } } void _onTapShowStatusCard(){ - Analytics.instance.logSelect(target: "Show Status Card"); - Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19StatusPanel())); + if(Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Show Status Card"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19StatusPanel())); + } else{ + AppAlert.showOfflineMessage(context); + } } void _onTapSymptomCheckIn() { - Analytics.instance.logSelect(target: "Symptom Check-in"); - Navigator.push(context, CupertinoPageRoute(builder: (context)=>Covid19SymptomsPanel())); + if(Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Symptom Check-in"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19SymptomsPanel())); + } else{ + AppAlert.showOfflineMessage(context); + } } void _onTapCovidWellnessCenter(){ - Analytics.instance.logSelect(target: "Wellness Center"); - Navigator.push(context, CupertinoPageRoute(builder: (context)=>Covid19WellnessCenter())); + if(Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Wellness Center"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19WellnessCenter())); + } else{ + AppAlert.showOfflineMessage(context); + } } void _onTapLink(String url) { - if (AppString.isStringNotEmpty(url)) { - if (AppUrl.launchInternal(url)) { - Navigator.push(context, CupertinoPageRoute(builder: (context) => WebPanel(url: url))); - } else { - launch(url); + if (Connectivity().isNotOffline) { + if (AppString.isStringNotEmpty(url)) { + if (AppUrl.launchInternal(url)) { + Navigator.push(context, CupertinoPageRoute(builder: (context) => WebPanel(url: url))); + } else { + launch(url); + } } + } else { + AppAlert.showOfflineMessage(context); } } - - /*void _onTapAbout() { - Analytics.instance.logSelect(target: "About"); - Navigator.push(context, CupertinoPageRoute(builder: (context)=>Covid19AboutPanel())); - }*/ } class _Covid19HomeHeaderBar extends AppBar { diff --git a/lib/ui/health/Covid19NewsPanel.dart b/lib/ui/health/Covid19NewsPanel.dart index 183ad288..029540f6 100644 --- a/lib/ui/health/Covid19NewsPanel.dart +++ b/lib/ui/health/Covid19NewsPanel.dart @@ -17,6 +17,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.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/Localization.dart'; @@ -104,7 +105,9 @@ class _Covid19NewsPanelState extends State implements Notifica child: Html( data: htmlContent, onLinkTap: (url) => _onLinkTap(url), - defaultTextStyle: TextStyle(fontSize: 16, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground), + style: { + "body": Style(fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground) + }, ), ), ) diff --git a/lib/ui/health/Covid19NextStepsPanel.dart b/lib/ui/health/Covid19NextStepsPanel.dart index 40273ee9..d576f7a5 100644 --- a/lib/ui/health/Covid19NextStepsPanel.dart +++ b/lib/ui/health/Covid19NextStepsPanel.dart @@ -17,6 +17,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_html/style.dart'; import 'package:illinois/model/Health.dart'; import 'package:illinois/service/Localization.dart'; import 'package:illinois/service/Styles.dart'; @@ -99,22 +100,11 @@ class _Covid19NextStepsPanelState extends State { content.addAll([ Container(height: 12,), Padding(padding: EdgeInsets.symmetric(horizontal: 32), child: - Html(data: nextStepHtml, onLinkTap: (url) => _onTapLink(url), defaultTextStyle: TextStyle(fontSize: 16, fontFamily: Styles().fontFamilies.regular, color: Colors.white),), + Html(data: nextStepHtml, onLinkTap: (url) => _onTapLink(url), style:{ "body" : Style(fontFamily: Styles().fontFamilies.regular, color: Colors.white) },), ), ]); } - content.addAll([ - Container(height: 24,), - Container(child:Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset("images/icon-calendar.png", excludeFromSemantics: true), - Container(width: 8,), - Text(Localization().getStringEx("panel.health.next_steps.label.asap","ASAP"), style: TextStyle(color: Colors.white, fontSize: 16, fontFamily: Styles().fontFamilies.regular)), - ],)), - ]); - return SingleChildScrollView( child: Column(children: content,), ); diff --git a/lib/ui/health/Covid19StatusPanel.dart b/lib/ui/health/Covid19StatusPanel.dart index eafc1d6a..a023deb6 100644 --- a/lib/ui/health/Covid19StatusPanel.dart +++ b/lib/ui/health/Covid19StatusPanel.dart @@ -59,6 +59,8 @@ class _Covid19StatusPanelState extends State implements Noti MemoryImage _photoImage; + final SwiperController _swiperController = SwiperController(); + @override void initState() { super.initState(); @@ -300,6 +302,7 @@ class _Covid19StatusPanelState extends State implements Noti containerHeight: 240, // Distance from SwiperIndicator itemHeight: 200, itemCount: 2, + controller: _swiperController, pagination:SwiperCustomPagination( builder:(BuildContext context, SwiperPluginConfig config){ return Container(padding: EdgeInsets.only(top: 200),child:_buildPageIndicator(config.activeIndex)); @@ -328,23 +331,45 @@ class _Covid19StatusPanelState extends State implements Noti child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - height: 12, - width: 12, - decoration: BoxDecoration( - color: 0==index? Styles().colors.fillColorSecondary : Styles().colors.background, - borderRadius: BorderRadius.all(Radius.circular(100)), - border: Border.all(color: Styles().colors.fillColorSecondary, width: 2), + Semantics( + label: Localization().getStringEx("panel.covid19_passport.button.show_page_1.title", "Show page 1 of 2"), + hint: Localization().getStringEx("panel.covid19_passport.button.show_page_1.hint", ""), + button: true, + selected: 0==index, + child: GestureDetector( + onTap: (){ + _swiperController.previous(); + }, + child: Container( + height: 12, + width: 12, + decoration: BoxDecoration( + color: 0==index? Styles().colors.fillColorSecondary : Styles().colors.background, + borderRadius: BorderRadius.all(Radius.circular(100)), + border: Border.all(color: Styles().colors.fillColorSecondary, width: 2), + ), + ), ), ), Container(width: 8,), - Container( - height: 12, - width: 12, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(100)), - color: 1==index? Styles().colors.fillColorSecondary : Styles().colors.background, - border: Border.all(color: Styles().colors.fillColorSecondary, width: 2), + GestureDetector( + onTap: (){ + _swiperController.next(); + }, + child: Semantics( + label: Localization().getStringEx("panel.covid19_passport.button.show_page_2.title", "Show page 2 of 2"), + hint: Localization().getStringEx("panel.covid19_passport.button.show_page_2.hint", ""), + button: true, + selected: 1==index, + child: Container( + height: 12, + width: 12, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(100)), + color: 1==index? Styles().colors.fillColorSecondary : Styles().colors.background, + border: Border.all(color: Styles().colors.fillColorSecondary, width: 2), + ), + ), ), ), ],), @@ -358,17 +383,21 @@ class _Covid19StatusPanelState extends State implements Noti case true: accessText = Localization().getStringEx("panel.covid19_passport.label.access.granted","GRANTED"); break; case false: accessText = Localization().getStringEx("panel.covid19_passport.label.access.denied","DENIED"); break; } - return SingleChildScrollView(child:Container( - child: Column(children: [ - Container(height: 15,), - Image.asset(imageAsset, excludeFromSemantics: true,), - Container(height: 7,), - Text(Localization().getStringEx("panel.covid19_passport.label.access.heading","Building Access"), - style: TextStyle(fontFamily: Styles().fontFamilies.medium, fontSize: 16, color: Styles().colors.fillColorPrimary),), - Container(height: 6,), - Text(accessText, style: TextStyle(fontFamily: Styles().fontFamilies.medium, fontSize: 28, color: Styles().colors.fillColorPrimary),), - ],), - )); + return Semantics( + label: Localization().getStringEx("panel.covid19_passport.label.page_1", "Page 1"), + explicitChildNodes: true, + child: SingleChildScrollView(child:Container( + child: Column(children: [ + Container(height: 15,), + Image.asset(imageAsset, excludeFromSemantics: true,), + Container(height: 7,), + Text(Localization().getStringEx("panel.covid19_passport.label.access.heading","Building Access"), + style: TextStyle(fontFamily: Styles().fontFamilies.medium, fontSize: 16, color: Styles().colors.fillColorPrimary),), + Container(height: 6,), + Text(accessText, style: TextStyle(fontFamily: Styles().fontFamilies.medium, fontSize: 28, color: Styles().colors.fillColorPrimary),), + ],), + )), + ); } Widget _buildQrCode(){ @@ -386,52 +415,56 @@ class _Covid19StatusPanelState extends State implements Noti Localization().getStringEx('panel.covid19_passport.label.status.empty', "No available status for this County") : Localization().getStringEx('panel.covid19_passport.label.counties.empty', "No counties available"); String qrCodeImageData = AppString.getDefaultEmptyString(value: authCardOrPhone, defaultValue: User().uuid); - return SingleChildScrollView(child:Column(children: [ - Visibility( - visible: userHasHealthStatus, - child: Container( - width: 176, - height: 176, - padding: EdgeInsets.all(13), - decoration: BoxDecoration( - color: statusColor, borderRadius: BorderRadius.circular(4)), - child: Container(decoration: BoxDecoration( - color: Styles().colors.white, borderRadius: BorderRadius.circular(4)), child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - Visibility(visible: AppString.isStringNotEmpty(qrCodeImageData), child: QrImage( - data: AppString.getDefaultEmptyString(value: qrCodeImageData), - version: QrVersions.auto, - size: MediaQuery.of(context).size.width / 4 + 10, - padding: EdgeInsets.all(5),),), - Visibility(visible: AppString.isStringNotEmpty(textAuthCardOrPhone), child: Padding(padding: EdgeInsets.only(top: 5), - child: Text( - AppString.getDefaultEmptyString(value: textAuthCardOrPhone), - style: TextStyle(color: Colors.black, fontSize: 12, fontFamily: Styles().fontFamilies.regular),),),), - ],),),),), - userHasHealthStatus ? - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: - Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded(child: - Text(statusName, style: TextStyle(fontFamily: Styles().fontFamilies.medium, fontSize: 16, color: Styles().colors.textSurface),), - ), - Container(width: 6,), - IconButton(icon: Image.asset('images/icon-info-orange.png'), onPressed: () => StatusInfoDialog.show(context, _selectedCounty?.nameDisplayText ?? ""), padding: EdgeInsets.all(10),) - ],)): - Container( - padding: EdgeInsets.only(bottom: 8), - child: Row( + return Semantics( + label: Localization().getStringEx("panel.covid19_passport.label.page_2", "Page 2"), + explicitChildNodes: true, + child: SingleChildScrollView(child:Column(children: [ + Visibility( + visible: userHasHealthStatus, + child: Container( + width: 176, + height: 176, + padding: EdgeInsets.all(13), + decoration: BoxDecoration( + color: statusColor, borderRadius: BorderRadius.circular(4)), + child: Container(decoration: BoxDecoration( + color: Styles().colors.white, borderRadius: BorderRadius.circular(4)), child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + Visibility(visible: AppString.isStringNotEmpty(qrCodeImageData), child: QrImage( + data: AppString.getDefaultEmptyString(value: qrCodeImageData), + version: QrVersions.auto, + size: MediaQuery.of(context).size.width / 4 + 10, + padding: EdgeInsets.all(5),),), + Visibility(visible: AppString.isStringNotEmpty(textAuthCardOrPhone), child: Padding(padding: EdgeInsets.only(top: 5), + child: Text( + AppString.getDefaultEmptyString(value: textAuthCardOrPhone), + style: TextStyle(color: Colors.black, fontSize: 12, fontFamily: Styles().fontFamilies.regular),),),), + ],),),),), + userHasHealthStatus ? + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: + Row( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Expanded( - child: Text(noStatusDescription, style:TextStyle(color: Colors.black, fontSize: 18, fontFamily: Styles().fontFamilies.regular)), - )]) - ), + Expanded(child: + Text(statusName, style: TextStyle(fontFamily: Styles().fontFamilies.medium, fontSize: 16, color: Styles().colors.textSurface),), + ), + Container(width: 6,), + IconButton(icon: Image.asset('images/icon-info-orange.png'), onPressed: () => StatusInfoDialog.show(context, _selectedCounty?.nameDisplayText ?? ""), padding: EdgeInsets.all(10),) + ],)): + Container( + padding: EdgeInsets.only(bottom: 8), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Text(noStatusDescription, style:TextStyle(color: Colors.black, fontSize: 18, fontFamily: Styles().fontFamilies.regular)), + )]) + ), - ],)); + ],)), + ); } Widget _buildCountyDropdown(){ @@ -479,8 +512,8 @@ class _Covid19StatusPanelState extends State implements Noti } String get _userRoleString { // Simplified - show resident for the rest of the situations - if(Auth().isShibbolethLoggedIn && AppString.isStringNotEmpty(Auth()?.authCard?.role)){ - return Auth()?.authCard?.role; + if(Auth().isShibbolethLoggedIn && AppString.isStringNotEmpty(Auth()?.authCard?.studentLevel)){ + return Auth()?.authCard?.studentLevel; // Use studentLevel instead of role Ref: issue #168 } return UserRole.toRoleString(UserRole.resident); } diff --git a/lib/ui/health/Covid19TestLocations.dart b/lib/ui/health/Covid19TestLocations.dart index ca07dc9a..3872fa65 100644 --- a/lib/ui/health/Covid19TestLocations.dart +++ b/lib/ui/health/Covid19TestLocations.dart @@ -338,6 +338,12 @@ class _TestLocation extends StatelessWidget{ String distanceSufix = Localization().getStringEx("panel.covid19_test_locations.distance.text","mi away get directions"); String distanceText = distance?.toStringAsFixed(2); + HealthLocationWaitTimeColor waitTimeColor = testLocation.waitTimeColor; + bool isWaitTimeAvailable = (waitTimeColor == HealthLocationWaitTimeColor.red) || + (waitTimeColor == HealthLocationWaitTimeColor.yellow) || + (waitTimeColor == HealthLocationWaitTimeColor.green); + String waitTimeText = Localization().getStringEx('panel.covid19_test_locations.wait_time.label', 'Wait Time') + + (isWaitTimeAvailable ? '' : (' ' + Localization().getStringEx('panel.covid19_test_locations.wait_time.unavailable', 'Unavailable'))); return Semantics(button: false, container: true, child: Container( @@ -403,7 +409,35 @@ class _TestLocation extends StatelessWidget{ ], )) )),*/ - Semantics(explicitChildNodes:true,button: false, child: + Container( + padding: EdgeInsets.only(top: 4), + child: Row( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(right: 8), + child: Container( + width: 16, + height: 16, + decoration: BoxDecoration(color: HealthServiceLocation.waitTimeColorHex(waitTimeColor), shape: BoxShape.circle), + ), + ), + Text( + waitTimeText, + style: TextStyle( + fontFamily: Styles().fontFamilies.regular, + fontSize: 16, + color: Styles().colors.textSurface, + ), + ) + ], + ) + ], + )), + Semantics(explicitChildNodes:true,button: false, child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ diff --git a/lib/ui/health/Covid19UpdatesPanel.dart b/lib/ui/health/Covid19UpdatesPanel.dart index 2d0594db..e3509337 100644 --- a/lib/ui/health/Covid19UpdatesPanel.dart +++ b/lib/ui/health/Covid19UpdatesPanel.dart @@ -17,6 +17,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.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/Assets.dart'; @@ -325,8 +326,7 @@ class _Covid19UpdatesPanelState extends State with TickerPr if(AppCollection.isCollectionNotEmpty(faqGeneralEntries)) { faqGeneralEntries.forEach((entry) { TextStyle titleStyle = TextStyle(fontSize: 16, fontFamily: Styles().fontFamilies.extraBold, color: Styles().colors.textBackground); - TextStyle descriptionStyle = TextStyle(fontSize: 16, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground); - widgets.add(_buildGeneralFaqEntry(entry, titleStyle, descriptionStyle)); + widgets.add(_buildGeneralFaqEntry(entry, titleStyle)); }); widgets.add(Container(height: 32,)); return Container( @@ -376,9 +376,8 @@ class _Covid19UpdatesPanelState extends State with TickerPr if (AppCollection.isCollectionNotEmpty(questions)) { questions.forEach((Covid19FAQEntry entry) { TextStyle titleStyle = TextStyle(fontSize: 16, fontFamily: Styles().fontFamilies.bold, color: Styles().colors.fillColorPrimary); - TextStyle descriptionStyle = TextStyle(fontSize: 16, fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground); Widget faqQuestionEntry = Container( - padding: EdgeInsets.only(top: 16, left: 16, right: 16), color: Styles().colors.white, child: _buildGeneralFaqEntry(entry, titleStyle, descriptionStyle,question: true),); + padding: EdgeInsets.only(top: 16, left: 16, right: 16), color: Styles().colors.white, child: _buildGeneralFaqEntry(entry, titleStyle, question: true),); widgets.add(faqQuestionEntry); }); } @@ -428,7 +427,7 @@ class _Covid19UpdatesPanelState extends State with TickerPr ]))); } - Widget _buildGeneralFaqEntry(Covid19FAQEntry entry, TextStyle titleStyle, TextStyle descriptionStyle,{bool question = false}) { + Widget _buildGeneralFaqEntry(Covid19FAQEntry entry, TextStyle titleStyle,{bool question = false}) { if (entry == null) { return Container(); } @@ -441,7 +440,7 @@ class _Covid19UpdatesPanelState extends State with TickerPr // Semantics(label: question? Localization().getStringEx('panel.covid19.faq.answer.label',"Answer: "): " . ", child: Padding(padding: EdgeInsets.only(top: 12), child: Html(data: AppString.getDefaultEmptyString(value: entry.description), - defaultTextStyle: descriptionStyle, + style: {"body":Style(fontFamily: Styles().fontFamilies.regular, color: Styles().colors.textBackground)}, onLinkTap: (url) => _onLinkTap(url),),) // ), ]))); diff --git a/lib/ui/settings/SettingsHomePanel.dart b/lib/ui/settings/SettingsHomePanel.dart index a14094c5..697626f2 100644 --- a/lib/ui/settings/SettingsHomePanel.dart +++ b/lib/ui/settings/SettingsHomePanel.dart @@ -301,24 +301,13 @@ class _SettingsHomePanelState extends State implements Notifi } void _onConnectNetIdClicked() { - Analytics.instance.logSelect(target: "Connect netId"); - Auth().authenticateWithShibboleth(); - } - - /*void _onPhoneVerClicked() { - Analytics.instance.logSelect(target: "Phone Verification"); if (Connectivity().isNotOffline) { - Navigator.push(context, CupertinoPageRoute(settings: RouteSettings(), builder: (context) => OnboardingLoginPhoneVerifyPanel(onFinish: _didPhoneVer,))); + Analytics.instance.logSelect(target: "Connect netId"); + Auth().authenticateWithShibboleth(); } else { - AppAlert.showOfflineMessage(context, Localization().getStringEx('panel.settings.label.offline.phone_ver', 'Verify Your Phone Number is not available while offline.')); + AppAlert.showOfflineMessage(context); } - }*/ - - /*void _didPhoneVer(_) { - Navigator.of(context)?.popUntil((Route route){ - return AppNavigation.routeRootWidget(route, context: context)?.runtimeType == widget.runtimeType; - }); - }*/ + } // Customizations @@ -347,8 +336,12 @@ class _SettingsHomePanelState extends State implements Notifi } void _onWhoAreYouClicked() { - Analytics.instance.logSelect(target: "Who are you"); - Navigator.push(context, CupertinoPageRoute(builder: (context) => SettingsRolesPanel())); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Who are you"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => SettingsRolesPanel())); + } else { + AppAlert.showOfflineMessage(context); + } } // Connected @@ -536,8 +529,12 @@ class _SettingsHomePanelState extends State implements Notifi } void _onCovid19Toggled() { - Analytics.instance.logSelect(target: "COVID-19 notifications"); - FirebaseMessaging().notifyCovid19 = !FirebaseMessaging().notifyCovid19; + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "COVID-19 notifications"); + FirebaseMessaging().notifyCovid19 = !FirebaseMessaging().notifyCovid19; + } else { + AppAlert.showOfflineMessage(context); + } } //TBD move to Health service @@ -816,124 +813,154 @@ class _SettingsHomePanelState extends State implements Notifi void _onExposureNotifications() { - Analytics.instance.logSelect(target: "Exposure Notifications"); - bool exposureNotification = _healthUser?.exposureNotification ?? false; - _updateHealthUser(exposureNotification: !exposureNotification); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Exposure Notifications"); + bool exposureNotification = _healthUser?.exposureNotification ?? false; + _updateHealthUser(exposureNotification: !exposureNotification); + } else { + AppAlert.showOfflineMessage(context); + } } void _onProviderTestResult() { - Analytics.instance.logSelect(target: "Health Provider Test Results"); - bool consent = _healthUser?.consent ?? false; - _updateHealthUser(consent: !consent); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Health Provider Test Results"); + bool consent = _healthUser?.consent ?? false; + _updateHealthUser(consent: !consent); + } else { + AppAlert.showOfflineMessage(context); + } } void _onTapCovid19Login() { - Analytics.instance.logSelect(target: "Retry"); - _loadHealthUser(); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Retry"); + _loadHealthUser(); + } else { + AppAlert.showOfflineMessage(context); + } } void _onTapCovid19ResetKeys() { - Analytics.instance.logSelect(target: "Reset"); - String message = Localization().getStringEx('panel.settings.home.covid19.alert.reset.prompt', 'Doing this will provide you a new COVID-19 Secret QRcode but your previous COVID-19 event history will be lost, continue?'); - if (_refreshingHealthUserKeys != true) { - showDialog( - context: context, - builder: (BuildContext buildContext) { - return AlertDialog( - content: Text(message, style: TextStyle(color: Styles().colors.fillColorPrimary, fontSize: 16, fontFamily: Styles().fontFamilies.bold)), - actions: [ - FlatButton( - child: Text(Localization().getStringEx("dialog.yes.title", "Yes"), style: TextStyle(color: Styles().colors.fillColorPrimary, fontSize: 16, fontFamily: Styles().fontFamilies.bold)), - onPressed: () { - Analytics.instance.logAlert(text: message, selection: "Yes"); - Navigator.pop(buildContext, true); - } - ), - FlatButton( - child: Text(Localization().getStringEx("dialog.no.title", "No"), style: TextStyle(color: Styles().colors.fillColorPrimary, fontSize: 16, fontFamily: Styles().fontFamilies.bold)), - onPressed: () { - Analytics.instance.logAlert(text: message, selection: "No"); - Navigator.pop(buildContext, false); - } - ), - ], - ); - } - ).then((result) { - if (result == true) { - _refreshHealthRSAKeys(); - } - }); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Reset"); + String message = Localization().getStringEx( + 'panel.settings.home.covid19.alert.reset.prompt', 'Doing this will provide you a new COVID-19 Secret QRcode but your previous COVID-19 event history will be lost, continue?'); + if (_refreshingHealthUserKeys != true) { + showDialog( + context: context, + builder: (BuildContext buildContext) { + return AlertDialog( + content: Text(message, style: TextStyle(color: Styles().colors.fillColorPrimary, fontSize: 16, fontFamily: Styles().fontFamilies.bold)), + actions: [ + FlatButton( + child: Text( + Localization().getStringEx("dialog.yes.title", "Yes"), style: TextStyle(color: Styles().colors.fillColorPrimary, fontSize: 16, fontFamily: Styles().fontFamilies.bold)), + onPressed: () { + Analytics.instance.logAlert(text: message, selection: "Yes"); + Navigator.pop(buildContext, true); + } + ), + FlatButton( + child: Text(Localization().getStringEx("dialog.no.title", "No"), style: TextStyle(color: Styles().colors.fillColorPrimary, fontSize: 16, fontFamily: Styles().fontFamilies.bold)), + onPressed: () { + Analytics.instance.logAlert(text: message, selection: "No"); + Navigator.pop(buildContext, false); + } + ), + ], + ); + } + ).then((result) { + if (result == true) { + _refreshHealthRSAKeys(); + } + }); + } + } else { + AppAlert.showOfflineMessage(context); } } void _onTapShowCovid19QrCode() { - Analytics.instance.logSelect(target: "Show COVID-19 Secret QRcode"); - Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19QrCodePanel())); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Show COVID-19 Secret QRcode"); + Navigator.push(context, CupertinoPageRoute(builder: (context) => Covid19QrCodePanel())); + } } void _onTapScanCovid19QrCode() { - Analytics.instance.logSelect(target: "Scan COVID-19 Secret QRcode"); - BarcodeScanner.scan().then((result) { - // barcode_scan plugin returns 8 digits when it cannot read the qr code. Prevent it from storing such values - if (AppString.isStringEmpty(result) || (result.length <= 8)) { - AppAlert.showDialogResult(context, Localization().getStringEx('panel.settings.home.covid19.alert.qr_code.scan.failed.msg', 'Failed to read QR code.')); - } - else { - _onCovid19QrCodeScanSucceeded(result); - } - }); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Scan COVID-19 Secret QRcode"); + BarcodeScanner.scan().then((result) { + // barcode_scan plugin returns 8 digits when it cannot read the qr code. Prevent it from storing such values + if (AppString.isStringEmpty(result) || (result.length <= 8)) { + AppAlert.showDialogResult(context, Localization().getStringEx('panel.settings.home.covid19.alert.qr_code.scan.failed.msg', 'Failed to read QR code.')); + } + else { + _onCovid19QrCodeScanSucceeded(result); + } + }); + } else { + AppAlert.showOfflineMessage(context); + } } void _onTapLoadCovid19QrCode() { - Analytics.instance.logSelect(target: "Load COVID-19 Secret QRcode"); - Covid19Utils.loadQRCodeImageFromPictures().then((String qrCodeString) { - _onCovid19QrCodeScanSucceeded(qrCodeString); - }); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Load COVID-19 Secret QRcode"); + Covid19Utils.loadQRCodeImageFromPictures().then((String qrCodeString) { + _onCovid19QrCodeScanSucceeded(qrCodeString); + }); + } else { + AppAlert.showOfflineMessage(context); + } } void _onCovid19QrCodeScanSucceeded(String result) { + if (Connectivity().isNotOffline) { + PointyCastle.PrivateKey privateKey; + try { + Uint8List pemCompressedData = (result != null) ? base64.decode(result) : null; + List pemData = (pemCompressedData != null) ? GZipDecoder().decodeBytes(pemCompressedData) : null; + privateKey = (pemData != null) ? RsaKeyHelper.parsePrivateKeyFromPemData(pemData) : null; + } + catch (e) { + print(e?.toString()); + } - PointyCastle.PrivateKey privateKey; - try { - Uint8List pemCompressedData = (result != null) ? base64.decode(result) : null; - List pemData = (pemCompressedData != null) ? GZipDecoder().decodeBytes(pemCompressedData) : null; - privateKey = (pemData != null) ? RsaKeyHelper.parsePrivateKeyFromPemData(pemData) : null; - } - catch (e) { - print(e?.toString()); - } - - if (privateKey != null) { - RsaKeyHelper.verifyRsaKeyPair(PointyCastle.AsymmetricKeyPair(_healthUser?.publicKey, privateKey)).then((bool result) { - if (mounted) { - if (result == true) { - Health().setUserRSAPrivateKey(privateKey).then((success) { - if (mounted) { - String resultMessage = success ? Localization().getStringEx( - 'panel.settings.home.covid19.alert.qr_code.transfer.succeeded.msg', 'COVID-19 secret transferred successfully.') : Localization() - .getStringEx('panel.settings.home.covid19.alert.qr_code.transfer.failed.msg', 'Failed to transfer COVID-19 secret.'); - AppAlert.showDialogResult(context, resultMessage).then((_){ - if (success) { - setState(() { - _healthUserPrivateKey = privateKey; - _healthUserKeysPaired = true; - }); - } - }); - } - }); - } - else { - AppAlert.showDialogResult(context, Localization().getStringEx('panel.health.covid19.alert.qr_code.not_match.msg', 'COVID-19 secret key does not match existing public RSA key.')); + if (privateKey != null) { + RsaKeyHelper.verifyRsaKeyPair(PointyCastle.AsymmetricKeyPair(_healthUser?.publicKey, privateKey)).then((bool result) { + if (mounted) { + if (result == true) { + Health().setUserRSAPrivateKey(privateKey).then((success) { + if (mounted) { + String resultMessage = success ? Localization().getStringEx( + 'panel.settings.home.covid19.alert.qr_code.transfer.succeeded.msg', 'COVID-19 secret transferred successfully.') : Localization() + .getStringEx('panel.settings.home.covid19.alert.qr_code.transfer.failed.msg', 'Failed to transfer COVID-19 secret.'); + AppAlert.showDialogResult(context, resultMessage).then((_) { + if (success) { + setState(() { + _healthUserPrivateKey = privateKey; + _healthUserKeysPaired = true; + }); + } + }); + } + }); + } + else { + AppAlert.showDialogResult(context, Localization().getStringEx('panel.health.covid19.alert.qr_code.not_match.msg', 'COVID-19 secret key does not match existing public RSA key.')); + } } - } - }); - } - else { - AppAlert.showDialogResult(context, Localization().getStringEx('panel.health.covid19.alert.qr_code.invalid.msg', 'Invalid QR code.')); + }); + } + else { + AppAlert.showDialogResult(context, Localization().getStringEx('panel.health.covid19.alert.qr_code.invalid.msg', 'Invalid QR code.')); + } + } else { + AppAlert.showOfflineMessage(context); } - } // Privacy @@ -962,9 +989,14 @@ class _SettingsHomePanelState extends State implements Notifi } void _onPrivacyStatementClicked() { - Analytics.instance.logSelect(target: "Privacy Statement"); - if (Config().privacyPolicyUrl != null) { - Navigator.push(context, CupertinoPageRoute(builder: (context) => WebPanel(url: Config().privacyPolicyUrl, title: Localization().getStringEx("panel.settings.privacy_statement.label.title", "Privacy Statement"),))); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Privacy Statement"); + if (Config().privacyPolicyUrl != null) { + Navigator.push(context, CupertinoPageRoute( + builder: (context) => WebPanel(url: Config().privacyPolicyUrl, title: Localization().getStringEx("panel.settings.privacy_statement.label.title", "Privacy Statement"),))); + } + } else { + AppAlert.showOfflineMessage(context); } } @@ -994,9 +1026,13 @@ class _SettingsHomePanelState extends State implements Notifi } void _onPersonalInfoClicked() { - Analytics.instance.logSelect(target: "Personal Info"); - if (Auth().isLoggedIn) { - Navigator.push(context, CupertinoPageRoute(builder: (context) => SettingsPersonalInfoPanel())); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Personal Info"); + if (Auth().isLoggedIn) { + Navigator.push(context, CupertinoPageRoute(builder: (context) => SettingsPersonalInfoPanel())); + } + } else { + AppAlert.showOfflineMessage(context); } } @@ -1053,21 +1089,25 @@ class _SettingsHomePanelState extends State implements Notifi } void _onFeedbackClicked() { - Analytics.instance.logSelect(target: "Provide Feedback"); - - if (Connectivity().isNotOffline && (Config().feedbackUrl != null)) { - String email = Auth().userPiiData?.email; - String name = Auth().userPiiData?.fullName; - String phone = Auth().phoneToken?.phone; - String params = _constructFeedbackParams(email, phone, name); - String feedbackUrl = Config().feedbackUrl + params; - - String panelTitle = Localization().getStringEx('panel.settings.feedback.label.title', 'PROVIDE FEEDBACK'); - Navigator.push( - context, CupertinoPageRoute(builder: (context) => WebPanel(url: feedbackUrl, title: panelTitle,))); - } - else { - AppAlert.showOfflineMessage(context, Localization().getStringEx('panel.settings.label.offline.feedback', 'Providing a Feedback is not available while offline.')); + if (Connectivity().isNotOffline) { + Analytics.instance.logSelect(target: "Provide Feedback"); + + if (Connectivity().isNotOffline && (Config().feedbackUrl != null)) { + String email = Auth().userPiiData?.email; + String name = Auth().userPiiData?.fullName; + String phone = Auth().phoneToken?.phone; + String params = _constructFeedbackParams(email, phone, name); + String feedbackUrl = Config().feedbackUrl + params; + + String panelTitle = Localization().getStringEx('panel.settings.feedback.label.title', 'PROVIDE FEEDBACK'); + Navigator.push( + context, CupertinoPageRoute(builder: (context) => WebPanel(url: feedbackUrl, title: panelTitle,))); + } + else { + AppAlert.showOfflineMessage(context, Localization().getStringEx('panel.settings.label.offline.feedback', 'Providing a Feedback is not available while offline.')); + } + } else { + AppAlert.showOfflineMessage(context); } } @@ -1083,7 +1123,7 @@ class _SettingsHomePanelState extends State implements Notifi fontSize: 16.0, textColor: Styles().colors.fillColorPrimary, borderColor: Styles().colors.fillColorSecondary, - onTap: _onDebugClicked(), + onTap: _onDebugClicked, ), ); } diff --git a/lib/ui/widgets/RoundedButton.dart b/lib/ui/widgets/RoundedButton.dart index 94c6c05b..118c6e4c 100644 --- a/lib/ui/widgets/RoundedButton.dart +++ b/lib/ui/widgets/RoundedButton.dart @@ -175,6 +175,7 @@ class ScalableRoundedButton extends StatelessWidget { final bool enabled; final bool showAdd; final bool showChevron; + final bool showExternalLink; ScalableRoundedButton( {this.label = '', @@ -191,7 +192,8 @@ class ScalableRoundedButton extends StatelessWidget { this.secondaryBorderColor, this.onTap, this.showAdd = false, - this.showChevron = false + this.showChevron = false, + this.showExternalLink = false, }); @override @@ -246,6 +248,12 @@ class ScalableRoundedButton extends StatelessWidget { child: Padding( padding: EdgeInsets.only(left: 5), child: Image.asset('images/icon-add-20x18.png'), + )), + Visibility( + visible: showExternalLink, + child: Padding( + padding: EdgeInsets.only(left: 5), + child: Image.asset('images/external-link.png'), )) ],)), ), diff --git a/lib/utils/Utils.dart b/lib/utils/Utils.dart index f0599dad..53baa140 100644 --- a/lib/utils/Utils.dart +++ b/lib/utils/Utils.dart @@ -316,7 +316,7 @@ class AppToast { msg: msg, textColor: Colors.white, toastLength: Toast.LENGTH_LONG, - timeInSecForIos: 3, + timeInSecForIosWeb: 3, gravity: ToastGravity.BOTTOM, backgroundColor: Styles().colors.blackTransparent06, ); @@ -360,13 +360,13 @@ class AppAlert { return alertDismissed; } - static Future showOfflineMessage(BuildContext context, String message) async { + static Future showOfflineMessage(BuildContext context, [String message]) async { return showDialog(context: context, builder: (context) { return AlertDialog( content: Column(mainAxisSize: MainAxisSize.min, children: [ Text(Localization().getStringEx("app.offline.message.title", "You appear to be offline"), style: TextStyle(fontSize: 18),), - Container(height:16), - Text(message, textAlign: TextAlign.center,), + Container(height: AppString.isStringNotEmpty(message) ? 16 : 0), + AppString.isStringNotEmpty(message) ? Text(message, textAlign: TextAlign.center,) : Container(), ],), actions: [ FlatButton( diff --git a/pubspec.lock b/pubspec.lock index a9b97def..81a85026 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2,7 +2,7 @@ # See https://dart.dev/tools/pub/glossary#lockfile packages: archive: - dependency: transitive + dependency: "direct main" description: name: archive url: "https://pub.dartlang.org" @@ -21,14 +21,14 @@ packages: name: asn1lib url: "https://pub.dartlang.org" source: hosted - version: "0.5.15" + version: "0.6.5" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.4.2" barcode_scan: dependency: "direct main" description: @@ -43,6 +43,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" charcode: dependency: transitive description: @@ -50,6 +57,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.3" + chewie: + dependency: transitive + description: + name: chewie + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.10" + chewie_audio: + dependency: transitive + description: + name: chewie_audio + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0+1" clock: dependency: transitive description: @@ -63,14 +84,35 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.12" + version: "1.14.13" connectivity: dependency: "direct main" description: name: connectivity url: "https://pub.dartlang.org" source: hosted - version: "0.4.5+1" + version: "0.4.9+2" + connectivity_for_web: + dependency: transitive + description: + name: connectivity_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.1+2" + connectivity_macos: + dependency: transitive + description: + name: connectivity_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0+4" + connectivity_platform_interface: + dependency: transitive + description: + name: connectivity_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.6" convert: dependency: transitive description: @@ -91,35 +133,56 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.5" + css_colors: + dependency: transitive + description: + name: css_colors + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" csslib: dependency: transitive description: name: csslib url: "https://pub.dartlang.org" source: hosted - version: "0.16.1" + version: "0.16.2" device_info: dependency: "direct main" description: name: device_info url: "https://pub.dartlang.org" source: hosted - version: "0.4.2+4" + version: "0.4.2+7" + device_info_platform_interface: + dependency: transitive + description: + name: device_info_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" dotted_border: dependency: "direct main" description: name: dotted_border url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.0.6" encrypt: dependency: "direct main" description: name: encrypt url: "https://pub.dartlang.org" source: hosted - version: "3.3.1" + version: "4.0.2" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" file: dependency: transitive description: @@ -133,21 +196,21 @@ packages: name: firebase url: "https://pub.dartlang.org" source: hosted - version: "7.2.1" + version: "7.3.0" firebase_core: dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.3+3" + version: "0.4.5" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.4" firebase_core_web: dependency: transitive description: @@ -161,21 +224,21 @@ packages: name: firebase_crashlytics url: "https://pub.dartlang.org" source: hosted - version: "0.1.2+5" + version: "0.1.4+1" firebase_messaging: dependency: "direct main" description: name: firebase_messaging url: "https://pub.dartlang.org" source: hosted - version: "6.0.9" + version: "6.0.16" firebase_ml_vision: dependency: "direct main" description: name: firebase_ml_vision url: "https://pub.dartlang.org" source: hosted - version: "0.9.4" + version: "0.9.6+2" flutter: dependency: "direct main" description: flutter @@ -187,21 +250,28 @@ packages: name: flutter_html url: "https://pub.dartlang.org" source: hosted - version: "0.11.1" + version: "1.0.2" flutter_image_compress: dependency: "direct main" description: name: flutter_image_compress url: "https://pub.dartlang.org" source: hosted - version: "0.6.8" + version: "0.7.0" flutter_local_notifications: dependency: "direct main" description: name: flutter_local_notifications url: "https://pub.dartlang.org" source: hosted - version: "0.8.4+3" + version: "1.4.4+4" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" flutter_localizations: dependency: "direct main" description: flutter @@ -228,6 +298,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.8" + flutter_svg: + dependency: transitive + description: + name: flutter_svg + url: "https://pub.dartlang.org" + source: hosted + version: "0.18.1" flutter_swiper: dependency: "direct main" description: @@ -251,7 +328,7 @@ packages: name: fluttertoast url: "https://pub.dartlang.org" source: hosted - version: "3.1.3" + version: "7.0.4" html: dependency: transitive description: @@ -272,21 +349,14 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.3" - image: - dependency: transitive - description: - name: image - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.12" + version: "3.1.4" image_picker: dependency: "direct main" description: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.6.7+4" + version: "0.6.7+7" image_picker_platform_interface: dependency: transitive description: @@ -307,28 +377,42 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.1+1" + version: "0.6.2" location: dependency: "direct main" description: name: location url: "https://pub.dartlang.org" source: hosted - version: "2.3.5" + version: "3.0.2" + location_platform_interface: + dependency: transitive + description: + name: location_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + location_web: + dependency: transitive + description: + name: location_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" logger: dependency: "direct main" description: name: logger url: "https://pub.dartlang.org" source: hosted - version: "0.7.0+2" + version: "0.9.2" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.6" + version: "0.12.8" meta: dependency: transitive description: @@ -342,28 +426,35 @@ packages: name: mime_type url: "https://pub.dartlang.org" source: hosted - version: "0.2.4" + version: "0.3.2" + open_iconic_flutter: + dependency: transitive + description: + name: open_iconic_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" package_info: dependency: "direct main" description: name: package_info url: "https://pub.dartlang.org" source: hosted - version: "0.4.1" + version: "0.4.3" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.6.4" + version: "1.7.0" path_drawing: dependency: transitive description: name: path_drawing url: "https://pub.dartlang.org" source: hosted - version: "0.4.1" + version: "0.4.1+1" path_parsing: dependency: transitive description: @@ -377,7 +468,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.11" + version: "1.6.14" path_provider_linux: dependency: transitive description: @@ -398,21 +489,21 @@ packages: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.8.0+1" + version: "1.9.0" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" + version: "3.0.4" platform: dependency: transitive description: @@ -420,6 +511,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.1" + platform_detect: + dependency: transitive + description: + name: platform_detect + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.0" plugin_platform_interface: dependency: transitive description: @@ -441,6 +539,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.13" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.4" qr: dependency: transitive description: @@ -462,13 +567,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.3" + screen: + dependency: transitive + description: + name: screen + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.5" shared_preferences: dependency: "direct main" description: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "0.5.3+5" + version: "0.5.10" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.2+2" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+10" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2+7" sky_engine: dependency: transitive description: flutter @@ -487,14 +627,14 @@ packages: name: sprintf url: "https://pub.dartlang.org" source: hosted - version: "4.0.2" + version: "4.1.0" sqflite: dependency: "direct main" description: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.3.1+1" sqflite_common: dependency: transitive description: @@ -508,7 +648,7 @@ packages: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "1.9.5" stream_channel: dependency: transitive description: @@ -529,7 +669,7 @@ packages: name: synchronized url: "https://pub.dartlang.org" source: hosted - version: "2.2.0+1" + version: "2.2.0+2" term_glyph: dependency: transitive description: @@ -543,7 +683,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.15" + version: "0.2.17" timezone: dependency: "direct main" description: @@ -564,49 +704,56 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.2.0" uni_links: dependency: "direct main" description: name: uni_links url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.4.0" url_launcher: dependency: "direct main" description: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "5.4.1" + version: "5.5.1" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "0.0.1+7" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.0.8" url_launcher_web: dependency: transitive description: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.0+2" + version: "0.1.3" uuid: dependency: "direct main" description: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.2.2" vector_math: dependency: transitive description: @@ -614,6 +761,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.8" + video_player: + dependency: transitive + description: + name: video_player + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.12+2" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + video_player_web: + dependency: transitive + description: + name: video_player_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3+2" + wakelock: + dependency: transitive + description: + name: wakelock + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4+2" webview_flutter: dependency: "direct main" description: @@ -634,7 +809,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "3.6.1" + version: "4.2.0" sdks: - dart: ">=2.8.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + dart: ">=2.9.0-14.0.dev <3.0.0" + flutter: ">=1.18.0-6.0.pre <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 559dfb91..c0068d76 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.5.8+508 +version: 2.6.8+608 environment: sdk: ">=2.2.0 <3.0.0" @@ -24,24 +24,25 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. + archive: ^2.0.13 shared_preferences: ^0.5.3+5 flutter_swiper: ^1.1.6 - mime_type: ^0.2.4 - location: ^2.3.5 - uni_links: ^0.2.0 + mime_type: ^0.3.2 + location: ^3.0.2 + uni_links: ^0.4.0 url_launcher: ^5.2.3 - fluttertoast: ^3.1.3 + fluttertoast: ^7.0.4 #Firebase - firebase_core: ^0.4.3+3 - firebase_messaging: ^6.0.9 + firebase_core: ^0.4.5 + firebase_messaging: ^6.0.16 firebase_crashlytics: ^0.1.2+5 firebase_ml_vision: ^0.9.4 # End Firebase - logger: ^0.7.0+2 - flutter_local_notifications: ^0.8.4 + logger: ^0.9.2 + flutter_local_notifications: ^1.4.4+4 sprintf: ^4.0.2 sqflite: ^1.1.7+1 - encrypt: ^3.3.1 + encrypt: ^4.0.2 package_info: ^0.4.0+9 device_info: ^0.4.0+4 connectivity: ^0.4.5+1 @@ -52,11 +53,11 @@ dependencies: flutter_native_timezone: ^1.0.4 path_provider: ^1.3.1 cookie_jar: ^1.0.0 - flutter_html: ^0.11.0 + flutter_html: ^1.0.2 qr_flutter: ^3.1.0 webview_flutter: ^0.3.19+7 dotted_border: ^1.0.5 - flutter_image_compress: ^0.6.8 + flutter_image_compress: ^0.7.0 barcode_scan: 2.0.2 # Explicitly use older version of the plugin. The latest one does not work! dev_dependencies: