├── .watchmanconfig
├── .gitattributes
├── ios
├── Stub.swift
├── ProtectScotland
│ ├── Images.xcassets
│ │ ├── Contents.json
│ │ ├── test-protect-logo
│ │ │ ├── Contents.json
│ │ │ └── test-protect-logo.imageset
│ │ │ │ ├── launch.png
│ │ │ │ ├── launch@2x.png
│ │ │ │ ├── launch@3x.png
│ │ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Protect Scotland Icon 1024.png
│ │ │ ├── Protect Scotland Icon 20@2x.png
│ │ │ ├── Protect Scotland Icon 20@3x.png
│ │ │ ├── Protect Scotland Icon 29@2x.png
│ │ │ ├── Protect Scotland Icon 29@3x.png
│ │ │ ├── Protect Scotland Icon 40@2x.png
│ │ │ ├── Protect Scotland Icon 40@3x.png
│ │ │ ├── Protect Scotland Icon 60@2x.png
│ │ │ ├── Protect Scotland Icon 60@3x.png
│ │ │ └── Contents.json
│ ├── main.m
│ ├── ProtectScotland.entitlements
│ ├── AppDelegate.h
│ ├── Base.lproj
│ │ └── LaunchScreen.xib
│ └── Info.plist
├── ProtectScotland-Bridging-Header.h
├── .env.default.sample
├── ProtectScotland.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── ProtectScotlandTests.xcscheme
│ │ └── ProtectScotland.xcscheme
├── ProtectScotland.xcworkspace
│ ├── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
│ └── contents.xcworkspacedata
└── fastlane
│ ├── Appfile
│ ├── Fastfile
│ └── README.md
├── app.json
├── app_context.png
├── android
├── fastlane
│ ├── Appfile
│ ├── Pluginfile
│ ├── README.md
│ └── Fastfile
├── app
│ ├── debug.keystore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── launch.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_notification.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── launch.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_notification.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── launch.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_notification.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── launch.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_notification.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── launch.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_notification.png
│ │ │ │ └── drawable
│ │ │ │ │ └── background_splash.xml
│ │ │ └── java
│ │ │ │ └── gov
│ │ │ │ └── scot
│ │ │ │ └── covidtracker
│ │ │ │ ├── SplashActivity.java
│ │ │ │ ├── generated
│ │ │ │ └── BasePackageList.java
│ │ │ │ ├── MainApplication.java
│ │ │ │ └── MainActivity.java
│ │ └── debug
│ │ │ └── AndroidManifest.xml
│ ├── build_defs.bzl
│ ├── proguard-rules.pro
│ └── _BUCK
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── .env.default.sample
├── settings.gradle
├── build.gradle
└── gradle.properties
├── app_server_side.png
├── components
├── views
│ ├── onboarding
│ │ ├── common.tsx
│ │ ├── privacy.tsx
│ │ ├── your-data.tsx
│ │ ├── test-result.tsx
│ │ ├── why-use.tsx
│ │ ├── upgrade-notice.tsx
│ │ └── permissions-info.tsx
│ ├── terms.tsx
│ ├── data-policy.tsx
│ ├── loading.tsx
│ ├── calculator.tsx
│ └── tests.tsx
├── molecules
│ ├── modal
│ │ ├── index.ts
│ │ └── clear-contacts.tsx
│ ├── new-version-card.tsx
│ ├── header.tsx
│ ├── onboarding-navbar.tsx
│ ├── close-contact-step.tsx
│ ├── action-card.tsx
│ ├── go-to-settings.tsx
│ └── arrow-link.tsx
├── atoms
│ ├── spacing.tsx
│ ├── heading.tsx
│ ├── divider.tsx
│ ├── media.tsx
│ ├── title.tsx
│ ├── rounded-box.tsx
│ ├── logo.tsx
│ ├── container.tsx
│ ├── illustration.tsx
│ ├── modal-close.tsx
│ ├── progress-bar.tsx
│ ├── back.tsx
│ ├── text.tsx
│ ├── symptom-checker.tsx
│ ├── note-link.tsx
│ └── message.tsx
├── organisms
│ └── modals
│ │ ├── index.ts
│ │ ├── push-notifications.tsx
│ │ ├── bluetooth-notification.tsx
│ │ └── exposure-notifications.tsx
└── templates
│ └── base.tsx
├── constants
└── urls.ts
├── .env.sample
├── assets
├── fonts
│ ├── Lato-Bold.ttf
│ ├── Roboto-Bold.ttf
│ ├── Lato-Regular.ttf
│ └── Roboto-Regular.ttf
└── images
│ ├── back
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── logo
│ ├── logo.png
│ ├── logo@2x.png
│ └── logo@3x.png
│ ├── map
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── wave
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-back
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-bt
│ ├── icon-bt.png
│ ├── icon-bt@2x.png
│ └── icon-bt@3x.png
│ ├── icon-jar
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-logo
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-menu
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-note
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-plus
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-tel
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── symptoms
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── tracing
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── grid-paused
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-arrow
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-close
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-eye
│ ├── icon-eye.png
│ ├── icon-eye@2x.png
│ └── icon-eye@3x.png
│ ├── icon-key
│ ├── icon-key.png
│ ├── icon-key@2x.png
│ └── icon-key@3x.png
│ ├── icon-paused
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── message
│ ├── ios
│ │ ├── image.png
│ │ ├── image@2x.png
│ │ └── image@3x.png
│ └── android
│ │ ├── image.png
│ │ ├── image@2x.png
│ │ └── image@3x.png
│ ├── icon-bell
│ ├── icon-bell.png
│ ├── icon-bell@2x.png
│ └── icon-bell@3x.png
│ ├── icon-comment
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-opt-out
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── restrictions
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── test-view-logo
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── tracing-active
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── warning-icon
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── wave-inverted
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-arrow-white
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-back-light
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-close-green
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-note-yellow
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-union
│ ├── icon-union.png
│ ├── icon-union@2x.png
│ └── icon-union@3x.png
│ ├── onboarding-group
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── onboarding-logo
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── tracing-contact
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── tracing-inactive
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── about-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-arrow-purple
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-external-link
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-settings-white
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── test-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-community-white
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-eye-pink
│ ├── icon-eye-pink.png
│ ├── icon-eye-pink@2x.png
│ └── icon-eye-pink@3x.png
│ ├── icon-jar-pink
│ ├── icon-jar-pink.png
│ ├── icon-jar-pink@2x.png
│ └── icon-jar-pink@3x.png
│ ├── icon-key-pink
│ ├── icon-key-pink.png
│ ├── icon-key-pink@2x.png
│ └── icon-key-pink@3x.png
│ ├── privacy-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── tracing-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── why-use-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── calculator-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── community-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── downloads-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-bell-pink
│ ├── icon-bell-pink.png
│ ├── icon-bell-pink@2x.png
│ └── icon-bell-pink@3x.png
│ ├── icon-external-link-light
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-tracing-active-big
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── permissions-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── send-notice-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── test-result-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── your-data-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-tracing-inactive-big
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── icon-comment-pink
│ ├── icon-comment-pink.png
│ ├── icon-comment-pink@2x.png
│ └── icon-comment-pink@3x.png
│ ├── notification
│ ├── ios
│ │ ├── age-group-1
│ │ │ ├── image.png
│ │ │ ├── image@2x.png
│ │ │ └── image@3x.png
│ │ └── age-group-2-3
│ │ │ ├── image.png
│ │ │ ├── image@2x.png
│ │ │ └── image@3x.png
│ └── android
│ │ ├── age-group-1
│ │ ├── image.png
│ │ ├── image@2x.png
│ │ └── image@3x.png
│ │ └── age-group-2-3
│ │ ├── image.png
│ │ ├── image@2x.png
│ │ └── image@3x.png
│ ├── your-data-modal-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── test-result-modal-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ ├── age-sorting-age-group-2-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
│ └── age-sorting-age-group-3-illustration
│ ├── image.png
│ ├── image@2x.png
│ └── image@3x.png
├── theme
├── layouts
│ ├── shared.ts
│ ├── index.ts
│ ├── onboarding-with-navbar.tsx
│ └── scrollable.tsx
├── index.ts
├── colors.ts
└── text.ts
├── .buckconfig
├── .prettierrc.js
├── index.js
├── hooks
├── index.ts
├── version.tsx
├── app-state.tsx
├── age-group-translation.tsx
├── a11y-element.tsx
└── confirmation-space.tsx
├── Gemfile
├── utils
├── web-browser.ts
└── exposure.ts
├── e2e
├── config.json
├── test.e2e.ts
└── environment.js
├── services
├── i18n
│ ├── common.tsx
│ └── index.ts
├── notifications
│ ├── hooks.tsx
│ ├── reminder.tsx
│ └── index.tsx
└── api
│ └── exposures.ts
├── .github
├── dependabot.yml
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── integration.yml
├── __tests__
└── App-test.tsx
├── .eslintrc.js
├── metro.config.js
├── babel.config.js
├── types
└── missingTypes.d.ts
├── .detoxrc.json
├── postinstall.sh
├── navigation.tsx
├── .gitignore
└── providers
└── reminder.tsx
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/ios/Stub.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | // DO NOT DELETE
3 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ProtectScotland",
3 | "displayName": "Protect Scotland"
4 | }
5 |
--------------------------------------------------------------------------------
/app_context.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/app_context.png
--------------------------------------------------------------------------------
/android/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | json_key_file(ENV["ANDROID_API_KEY_FILE"])
2 | package_name(ENV["PACKAGE_NAME"])
3 |
--------------------------------------------------------------------------------
/app_server_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/app_server_side.png
--------------------------------------------------------------------------------
/components/views/onboarding/common.tsx:
--------------------------------------------------------------------------------
1 | export interface OnboardingPageProps {
2 | handleNext(): void;
3 | }
4 |
--------------------------------------------------------------------------------
/constants/urls.ts:
--------------------------------------------------------------------------------
1 | import {API_HOST} from '@env';
2 |
3 | export const urls = {
4 | api: API_HOST
5 | };
6 |
--------------------------------------------------------------------------------
/.env.sample:
--------------------------------------------------------------------------------
1 | ENV=development
2 | API_HOST=
3 | BUILD_VERSION=0.0.1
4 | SAFETYNET_KEY=
5 | HIDE_DEBUG=n
6 | TEST_TOKEN=
7 |
--------------------------------------------------------------------------------
/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/debug.keystore
--------------------------------------------------------------------------------
/assets/fonts/Lato-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/fonts/Lato-Bold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/fonts/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/assets/images/back/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/back/image.png
--------------------------------------------------------------------------------
/assets/images/logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/logo/logo.png
--------------------------------------------------------------------------------
/assets/images/map/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/map/image.png
--------------------------------------------------------------------------------
/assets/images/wave/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/wave/image.png
--------------------------------------------------------------------------------
/assets/fonts/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/fonts/Lato-Regular.ttf
--------------------------------------------------------------------------------
/assets/images/logo/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/logo/logo@2x.png
--------------------------------------------------------------------------------
/assets/images/logo/logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/logo/logo@3x.png
--------------------------------------------------------------------------------
/assets/images/map/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/map/image@2x.png
--------------------------------------------------------------------------------
/assets/images/map/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/map/image@3x.png
--------------------------------------------------------------------------------
/components/molecules/modal/index.ts:
--------------------------------------------------------------------------------
1 | import Modal from './modal';
2 |
3 | export * from './modal';
4 |
5 | export default Modal;
6 |
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "author": "xcode",
4 | "version": 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Protect Scotland
3 |
4 |
--------------------------------------------------------------------------------
/assets/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/assets/images/back/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/back/image@2x.png
--------------------------------------------------------------------------------
/assets/images/back/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/back/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-back/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-back/image.png
--------------------------------------------------------------------------------
/assets/images/icon-bt/icon-bt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bt/icon-bt.png
--------------------------------------------------------------------------------
/assets/images/icon-jar/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-jar/image.png
--------------------------------------------------------------------------------
/assets/images/icon-logo/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-logo/image.png
--------------------------------------------------------------------------------
/assets/images/icon-menu/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-menu/image.png
--------------------------------------------------------------------------------
/assets/images/icon-note/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-note/image.png
--------------------------------------------------------------------------------
/assets/images/icon-plus/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-plus/image.png
--------------------------------------------------------------------------------
/assets/images/icon-tel/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tel/image.png
--------------------------------------------------------------------------------
/assets/images/symptoms/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/symptoms/image.png
--------------------------------------------------------------------------------
/assets/images/tracing/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing/image.png
--------------------------------------------------------------------------------
/assets/images/wave/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/wave/image@2x.png
--------------------------------------------------------------------------------
/assets/images/wave/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/wave/image@3x.png
--------------------------------------------------------------------------------
/theme/layouts/shared.ts:
--------------------------------------------------------------------------------
1 | export const SPACING_HORIZONTAL = 40;
2 | export const SPACING_TOP = 16;
3 | export const SPACING_BOTTOM = 8;
4 |
--------------------------------------------------------------------------------
/assets/images/grid-paused/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/grid-paused/image.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow/image.png
--------------------------------------------------------------------------------
/assets/images/icon-close/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-close/image.png
--------------------------------------------------------------------------------
/assets/images/icon-eye/icon-eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-eye/icon-eye.png
--------------------------------------------------------------------------------
/assets/images/icon-jar/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-jar/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-jar/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-jar/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-key/icon-key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-key/icon-key.png
--------------------------------------------------------------------------------
/assets/images/icon-paused/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-paused/image.png
--------------------------------------------------------------------------------
/assets/images/icon-tel/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tel/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-tel/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tel/image@3x.png
--------------------------------------------------------------------------------
/assets/images/message/ios/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/message/ios/image.png
--------------------------------------------------------------------------------
/assets/images/symptoms/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/symptoms/image@2x.png
--------------------------------------------------------------------------------
/assets/images/symptoms/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/symptoms/image@3x.png
--------------------------------------------------------------------------------
/assets/images/tracing/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing/image@2x.png
--------------------------------------------------------------------------------
/assets/images/tracing/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing/image@3x.png
--------------------------------------------------------------------------------
/.buckconfig:
--------------------------------------------------------------------------------
1 | [android]
2 | target = Google Inc.:Google APIs:23
3 |
4 | [maven_repositories]
5 | central = https://repo1.maven.org/maven2
6 |
--------------------------------------------------------------------------------
/assets/images/grid-paused/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/grid-paused/image@2x.png
--------------------------------------------------------------------------------
/assets/images/grid-paused/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/grid-paused/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-back/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-back/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-back/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-back/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-bell/icon-bell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bell/icon-bell.png
--------------------------------------------------------------------------------
/assets/images/icon-bt/icon-bt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bt/icon-bt@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-bt/icon-bt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bt/icon-bt@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-close/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-close/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-close/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-close/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-comment/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-comment/image.png
--------------------------------------------------------------------------------
/assets/images/icon-eye/icon-eye@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-eye/icon-eye@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-eye/icon-eye@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-eye/icon-eye@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-key/icon-key@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-key/icon-key@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-key/icon-key@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-key/icon-key@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-logo/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-logo/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-logo/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-logo/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-menu/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-menu/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-menu/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-menu/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-note/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-note/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-note/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-note/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-opt-out/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-opt-out/image.png
--------------------------------------------------------------------------------
/assets/images/icon-paused/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-paused/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-paused/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-paused/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-plus/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-plus/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-plus/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-plus/image@3x.png
--------------------------------------------------------------------------------
/assets/images/message/ios/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/message/ios/image@2x.png
--------------------------------------------------------------------------------
/assets/images/message/ios/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/message/ios/image@3x.png
--------------------------------------------------------------------------------
/assets/images/restrictions/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/restrictions/image.png
--------------------------------------------------------------------------------
/assets/images/test-view-logo/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-view-logo/image.png
--------------------------------------------------------------------------------
/assets/images/tracing-active/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-active/image.png
--------------------------------------------------------------------------------
/assets/images/warning-icon/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/warning-icon/image.png
--------------------------------------------------------------------------------
/assets/images/wave-inverted/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/wave-inverted/image.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow-white/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow-white/image.png
--------------------------------------------------------------------------------
/assets/images/icon-back-light/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-back-light/image.png
--------------------------------------------------------------------------------
/assets/images/icon-bell/icon-bell@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bell/icon-bell@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-bell/icon-bell@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bell/icon-bell@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-close-green/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-close-green/image.png
--------------------------------------------------------------------------------
/assets/images/icon-comment/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-comment/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-comment/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-comment/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-note-yellow/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-note-yellow/image.png
--------------------------------------------------------------------------------
/assets/images/icon-opt-out/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-opt-out/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-opt-out/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-opt-out/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-union/icon-union.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-union/icon-union.png
--------------------------------------------------------------------------------
/assets/images/message/android/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/message/android/image.png
--------------------------------------------------------------------------------
/assets/images/onboarding-group/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/onboarding-group/image.png
--------------------------------------------------------------------------------
/assets/images/onboarding-logo/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/onboarding-logo/image.png
--------------------------------------------------------------------------------
/assets/images/restrictions/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/restrictions/image@2x.png
--------------------------------------------------------------------------------
/assets/images/restrictions/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/restrictions/image@3x.png
--------------------------------------------------------------------------------
/assets/images/tracing-contact/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-contact/image.png
--------------------------------------------------------------------------------
/assets/images/tracing-inactive/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-inactive/image.png
--------------------------------------------------------------------------------
/assets/images/warning-icon/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/warning-icon/image@2x.png
--------------------------------------------------------------------------------
/assets/images/warning-icon/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/warning-icon/image@3x.png
--------------------------------------------------------------------------------
/assets/images/wave-inverted/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/wave-inverted/image@2x.png
--------------------------------------------------------------------------------
/assets/images/wave-inverted/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/wave-inverted/image@3x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/test-protect-logo/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "author": "xcode",
4 | "version": 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | bracketSpacing: false,
3 | jsxBracketSameLine: true,
4 | singleQuote: true,
5 | trailingComma: 'none'
6 | };
7 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/assets/images/about-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/about-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow-purple/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow-purple/image.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow-white/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow-white/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow-white/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow-white/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-back-light/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-back-light/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-back-light/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-back-light/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-close-green/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-close-green/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-close-green/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-close-green/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-external-link/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-external-link/image.png
--------------------------------------------------------------------------------
/assets/images/icon-note-yellow/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-note-yellow/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-note-yellow/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-note-yellow/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-settings-white/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-settings-white/image.png
--------------------------------------------------------------------------------
/assets/images/icon-union/icon-union@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-union/icon-union@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-union/icon-union@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-union/icon-union@3x.png
--------------------------------------------------------------------------------
/assets/images/message/android/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/message/android/image@2x.png
--------------------------------------------------------------------------------
/assets/images/message/android/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/message/android/image@3x.png
--------------------------------------------------------------------------------
/assets/images/onboarding-group/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/onboarding-group/image@2x.png
--------------------------------------------------------------------------------
/assets/images/onboarding-group/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/onboarding-group/image@3x.png
--------------------------------------------------------------------------------
/assets/images/onboarding-logo/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/onboarding-logo/image@2x.png
--------------------------------------------------------------------------------
/assets/images/onboarding-logo/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/onboarding-logo/image@3x.png
--------------------------------------------------------------------------------
/assets/images/test-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/test-view-logo/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-view-logo/image@2x.png
--------------------------------------------------------------------------------
/assets/images/test-view-logo/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-view-logo/image@3x.png
--------------------------------------------------------------------------------
/assets/images/tracing-active/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-active/image@2x.png
--------------------------------------------------------------------------------
/assets/images/tracing-active/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-active/image@3x.png
--------------------------------------------------------------------------------
/assets/images/tracing-contact/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-contact/image@2x.png
--------------------------------------------------------------------------------
/assets/images/tracing-contact/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-contact/image@3x.png
--------------------------------------------------------------------------------
/assets/images/tracing-inactive/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-inactive/image@2x.png
--------------------------------------------------------------------------------
/assets/images/tracing-inactive/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-inactive/image@3x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/assets/images/about-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/about-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/about-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/about-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow-purple/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow-purple/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-arrow-purple/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-arrow-purple/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-community-white/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-community-white/image.png
--------------------------------------------------------------------------------
/assets/images/icon-external-link/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-external-link/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-external-link/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-external-link/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-eye-pink/icon-eye-pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-eye-pink/icon-eye-pink.png
--------------------------------------------------------------------------------
/assets/images/icon-jar-pink/icon-jar-pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-jar-pink/icon-jar-pink.png
--------------------------------------------------------------------------------
/assets/images/icon-key-pink/icon-key-pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-key-pink/icon-key-pink.png
--------------------------------------------------------------------------------
/assets/images/privacy-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/privacy-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/test-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/test-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/tracing-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/why-use-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/why-use-illustration/image.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/launch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-hdpi/launch.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/launch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-mdpi/launch.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/launch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xhdpi/launch.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6B11A5
4 |
--------------------------------------------------------------------------------
/assets/images/calculator-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/calculator-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/community-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/community-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/downloads-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/downloads-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/icon-bell-pink/icon-bell-pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bell-pink/icon-bell-pink.png
--------------------------------------------------------------------------------
/assets/images/icon-community-white/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-community-white/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-community-white/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-community-white/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-external-link-light/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-external-link-light/image.png
--------------------------------------------------------------------------------
/assets/images/icon-eye-pink/icon-eye-pink@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-eye-pink/icon-eye-pink@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-eye-pink/icon-eye-pink@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-eye-pink/icon-eye-pink@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-jar-pink/icon-jar-pink@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-jar-pink/icon-jar-pink@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-jar-pink/icon-jar-pink@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-jar-pink/icon-jar-pink@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-key-pink/icon-key-pink@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-key-pink/icon-key-pink@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-key-pink/icon-key-pink@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-key-pink/icon-key-pink@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-settings-white/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-settings-white/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-settings-white/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-settings-white/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-tracing-active-big/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tracing-active-big/image.png
--------------------------------------------------------------------------------
/assets/images/permissions-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/permissions-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/privacy-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/privacy-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/privacy-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/privacy-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/send-notice-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/send-notice-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/test-result-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-result-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/tracing-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/tracing-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/tracing-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/why-use-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/why-use-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/why-use-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/why-use-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/your-data-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/your-data-illustration/image.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/launch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xxhdpi/launch.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/launch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xxxhdpi/launch.png
--------------------------------------------------------------------------------
/assets/images/calculator-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/calculator-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/calculator-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/calculator-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/community-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/community-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/community-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/community-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/downloads-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/downloads-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/downloads-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/downloads-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-bell-pink/icon-bell-pink@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bell-pink/icon-bell-pink@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-bell-pink/icon-bell-pink@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-bell-pink/icon-bell-pink@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-tracing-active-big/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tracing-active-big/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-tracing-active-big/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tracing-active-big/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-tracing-inactive-big/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tracing-inactive-big/image.png
--------------------------------------------------------------------------------
/assets/images/your-data-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/your-data-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/your-data-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/your-data-illustration/image@3x.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/fastlane/Pluginfile:
--------------------------------------------------------------------------------
1 | # Autogenerated by fastlane
2 | #
3 | # Ensure this file is checked in to source control!
4 |
5 | gem 'fastlane-plugin-increment_version_code'
6 |
--------------------------------------------------------------------------------
/assets/images/icon-comment-pink/icon-comment-pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-comment-pink/icon-comment-pink.png
--------------------------------------------------------------------------------
/assets/images/icon-external-link-light/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-external-link-light/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-external-link-light/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-external-link-light/image@3x.png
--------------------------------------------------------------------------------
/assets/images/icon-tracing-inactive-big/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tracing-inactive-big/image@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-tracing-inactive-big/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-tracing-inactive-big/image@3x.png
--------------------------------------------------------------------------------
/assets/images/notification/ios/age-group-1/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/ios/age-group-1/image.png
--------------------------------------------------------------------------------
/assets/images/permissions-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/permissions-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/permissions-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/permissions-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/send-notice-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/send-notice-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/send-notice-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/send-notice-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/test-result-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-result-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/test-result-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-result-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/your-data-modal-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/your-data-modal-illustration/image.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/assets/images/notification/ios/age-group-1/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/ios/age-group-1/image@2x.png
--------------------------------------------------------------------------------
/assets/images/notification/ios/age-group-1/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/ios/age-group-1/image@3x.png
--------------------------------------------------------------------------------
/assets/images/notification/ios/age-group-2-3/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/ios/age-group-2-3/image.png
--------------------------------------------------------------------------------
/assets/images/test-result-modal-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-result-modal-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/your-data-modal-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/your-data-modal-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/your-data-modal-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/your-data-modal-illustration/image@3x.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-hdpi/ic_notification.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-mdpi/ic_notification.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_notification.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_notification.png
--------------------------------------------------------------------------------
/assets/images/icon-comment-pink/icon-comment-pink@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-comment-pink/icon-comment-pink@2x.png
--------------------------------------------------------------------------------
/assets/images/icon-comment-pink/icon-comment-pink@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/icon-comment-pink/icon-comment-pink@3x.png
--------------------------------------------------------------------------------
/assets/images/notification/android/age-group-1/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/android/age-group-1/image.png
--------------------------------------------------------------------------------
/assets/images/notification/android/age-group-2-3/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/android/age-group-2-3/image.png
--------------------------------------------------------------------------------
/assets/images/notification/ios/age-group-2-3/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/ios/age-group-2-3/image@2x.png
--------------------------------------------------------------------------------
/assets/images/notification/ios/age-group-2-3/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/ios/age-group-2-3/image@3x.png
--------------------------------------------------------------------------------
/assets/images/test-result-modal-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-result-modal-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/test-result-modal-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/test-result-modal-illustration/image@3x.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_notification.png
--------------------------------------------------------------------------------
/assets/images/age-sorting-age-group-2-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/age-sorting-age-group-2-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/age-sorting-age-group-3-illustration/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/age-sorting-age-group-3-illustration/image.png
--------------------------------------------------------------------------------
/assets/images/notification/android/age-group-1/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/android/age-group-1/image@2x.png
--------------------------------------------------------------------------------
/assets/images/notification/android/age-group-1/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/android/age-group-1/image@3x.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import {AppRegistry} from 'react-native';
2 | import App from './App';
3 | import {name as appName} from './app.json';
4 |
5 | AppRegistry.registerComponent(appName, () => App);
6 |
--------------------------------------------------------------------------------
/assets/images/age-sorting-age-group-2-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/age-sorting-age-group-2-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/age-sorting-age-group-2-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/age-sorting-age-group-2-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/age-sorting-age-group-3-illustration/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/age-sorting-age-group-3-illustration/image@2x.png
--------------------------------------------------------------------------------
/assets/images/age-sorting-age-group-3-illustration/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/age-sorting-age-group-3-illustration/image@3x.png
--------------------------------------------------------------------------------
/assets/images/notification/android/age-group-2-3/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/android/age-group-2-3/image@2x.png
--------------------------------------------------------------------------------
/assets/images/notification/android/age-group-2-3/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/assets/images/notification/android/age-group-2-3/image@3x.png
--------------------------------------------------------------------------------
/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './a11y-element';
2 | export * from './app-state';
3 | export * from './confirmation-space';
4 | export * from './version';
5 | export * from './age-group-translation';
6 |
--------------------------------------------------------------------------------
/theme/layouts/index.ts:
--------------------------------------------------------------------------------
1 | import {Scrollable} from './scrollable';
2 | import OnboardingWithNavbar from './onboarding-with-navbar';
3 |
4 | export default {
5 | Scrollable,
6 | OnboardingWithNavbar
7 | };
8 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "fastlane"
4 |
5 |
6 | plugins_path = File.join(File.dirname(__FILE__), 'android', 'fastlane', 'Pluginfile')
7 | eval_gemfile(plugins_path) if File.exist?(plugins_path)
8 |
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 1024.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 20@2x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 20@3x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 29@2x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 29@3x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 40@2x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 40@3x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 60@2x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Protect Scotland Icon 60@3x.png
--------------------------------------------------------------------------------
/utils/web-browser.ts:
--------------------------------------------------------------------------------
1 | import * as WebBrowser from 'expo-web-browser';
2 |
3 | export const openBrowserAsync = (link: string) =>
4 | WebBrowser.openBrowserAsync(link, {
5 | enableBarCollapsing: true,
6 | showInRecents: true
7 | });
8 |
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/test-protect-logo/test-protect-logo.imageset/launch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/test-protect-logo/test-protect-logo.imageset/launch.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/test-protect-logo/test-protect-logo.imageset/launch@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/test-protect-logo/test-protect-logo.imageset/launch@2x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/test-protect-logo/test-protect-logo.imageset/launch@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NES-Digital-Service/protect-scotland/HEAD/ios/ProtectScotland/Images.xcassets/test-protect-logo/test-protect-logo.imageset/launch@3x.png
--------------------------------------------------------------------------------
/ios/ProtectScotland/main.m:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char * argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ios/.env.default.sample:
--------------------------------------------------------------------------------
1 | APPLE_ID=yourappleid@email.com
2 | APP_IDENTIFIER=gov.scot.covidtracker
3 | ITC_TEAM_ID=itunes_connect_team_id
4 | TEAM_ID=apple_dev_team_id
5 | XCODEPROJ=ProtectScotland.xcodeproj
6 | WORKSPACE=ProtectScotland.xcworkspace
7 | SCHEME=ProtectScotland
8 |
--------------------------------------------------------------------------------
/components/atoms/spacing.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {View} from 'react-native';
3 | import {scale} from '../../theme';
4 |
5 | const Spacing: React.FC<{s: number}> = ({s}) => (
6 |
7 | );
8 |
9 | export default Spacing;
10 |
--------------------------------------------------------------------------------
/e2e/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "preset": "ts-jest",
3 | "testRunner": "jest-circus/runner",
4 | "testTimeout": 120000,
5 | "testEnvironment": "./environment",
6 | "testRegex": "\\.e2e\\.ts$",
7 | "reporters": ["detox/runners/jest/streamlineReporter"],
8 | "verbose": true
9 | }
10 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Nov 26 08:35:18 GMT 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/ProtectScotland.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/services/i18n/common.tsx:
--------------------------------------------------------------------------------
1 | import en from '../../assets/lang/en.json';
2 |
3 | export const fallback = 'en';
4 | export const defaultNamespace = 'common';
5 | export const namespaces = ['common'];
6 |
7 | export const supportedLocales = {
8 | en: {
9 | name: 'English',
10 | ...en
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Enable version updates for npm
4 | - package-ecosystem: 'npm'
5 | # Look for `package.json` and `lock` files in the `root` directory
6 | directory: '/'
7 | # Check the npm registry for updates every day (weekdays)
8 | schedule:
9 | interval: 'daily'
--------------------------------------------------------------------------------
/ios/ProtectScotland.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/ProtectScotland/ProtectScotland.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.exposure-notification
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/ProtectScotland.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/ProtectScotland.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/__tests__/App-test.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import React from 'react';
3 | import App from '../App';
4 |
5 | // Note: test renderer must be required after react-native.
6 | import renderer from 'react-test-renderer';
7 |
8 | it('renders correctly', () => {
9 | renderer.create();
10 | });
11 |
--------------------------------------------------------------------------------
/e2e/test.e2e.ts:
--------------------------------------------------------------------------------
1 | import {expect, device, element, by} from 'detox';
2 |
3 | describe('E2E journey', () => {
4 | beforeAll(async () => {
5 | await device.launchApp({newInstance: true});
6 | });
7 |
8 | it('should have welcome screen', async () => {
9 | await expect(element(by.id('welcome'))).toBeVisible();
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/ios/ProtectScotland.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: ['@react-native-community', 'plugin:react-native-a11y/all'],
4 | parser: '@typescript-eslint/parser',
5 | plugins: ['@typescript-eslint', 'jest', 'detox'],
6 | env: {
7 | 'jest/globals': true,
8 | 'detox/detox': true
9 | },
10 | rules: {
11 | 'comma-dangle': 'off'
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/components/organisms/modals/index.ts:
--------------------------------------------------------------------------------
1 | import {ExposureNotificationsModal} from './exposure-notifications';
2 | import {BluetoothNotificationsModal} from './bluetooth-notification';
3 | import {PushNotificationsModal} from './push-notifications';
4 |
5 | export {
6 | ExposureNotificationsModal,
7 | BluetoothNotificationsModal,
8 | PushNotificationsModal
9 | };
10 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### What does this PR do?
2 |
3 |
4 |
5 | ### Related issue
6 |
7 |
8 |
9 | ### Additional notes & screenshots
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ios/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | app_identifier(ENV['APP_IDENTIFIER']) # The bundle identifier of your app
2 | apple_id(ENV['APPLE_ID']) # Your Apple email address
3 |
4 | itc_team_id(ENV['ITC_TEAM_ID']) # App Store Connect Team ID
5 | team_id(ENV['TEAM_ID']) # Developer Portal Team ID
6 |
7 | # For more information about the Appfile, see:
8 | # https://docs.fastlane.tools/advanced/#appfile
9 |
--------------------------------------------------------------------------------
/metro.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Metro configuration for React Native
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | */
7 |
8 | module.exports = {
9 | transformer: {
10 | getTransformOptions: async () => ({
11 | transform: {
12 | experimentalImportSupport: false,
13 | inlineRequires: false
14 | }
15 | })
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/android/.env.default.sample:
--------------------------------------------------------------------------------
1 | # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
2 | ANDROID_API_KEY_FILE="/path/to/your/play/api/android-api-key.json"
3 | ANDROID_KEYSTORE_PATH="/path/to/your/upload-keystore.jks"
4 | ANDROID_KEYSTORE_PASSWORD=yourkeystorepasswd
5 | ANDROID_KEY_ALIAS=upload
6 | ANDROID_KEY_PASSWORD=yourkeypasswd
7 | PACKAGE_NAME="gov.scot.covidtracker"
8 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | env: {
4 | production: {
5 | plugins: ['transform-remove-console']
6 | }
7 | },
8 | plugins: [
9 | [
10 | 'dotenv-import',
11 | {
12 | moduleName: '@env',
13 | path: '.env',
14 | safe: false,
15 | allowUndefined: false
16 | }
17 | ]
18 | ]
19 | };
20 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/background_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/e2e/environment.js:
--------------------------------------------------------------------------------
1 | const {
2 | DetoxCircusEnvironment,
3 | SpecReporter,
4 | WorkerAssignReporter
5 | } = require('detox/runners/jest-circus');
6 |
7 | class CustomDetoxEnvironment extends DetoxCircusEnvironment {
8 | constructor(config) {
9 | super(config);
10 |
11 | this.registerListeners({
12 | SpecReporter,
13 | WorkerAssignReporter
14 | });
15 | }
16 | }
17 |
18 | module.exports = CustomDetoxEnvironment;
19 |
--------------------------------------------------------------------------------
/components/templates/base.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {StyleSheet} from 'react-native';
3 |
4 | import Container from '../atoms/container';
5 | import {colors} from '../../theme';
6 |
7 | const Base: React.FC = ({children}) => (
8 | {children}
9 | );
10 |
11 | const styles = StyleSheet.create({
12 | container: {
13 | backgroundColor: colors.primaryPurple
14 | }
15 | });
16 |
17 | export {Base};
18 |
--------------------------------------------------------------------------------
/hooks/version.tsx:
--------------------------------------------------------------------------------
1 | import {useEffect, useState} from 'react';
2 | import {getVersion, Version} from 'react-native-exposure-notification-service';
3 |
4 | export function useVersion(): Version | undefined {
5 | const [version, setVersion] = useState();
6 | useEffect(() => {
7 | const getVer = async () => {
8 | const ver = await getVersion();
9 | setVersion(ver);
10 | };
11 | getVer();
12 | }, []);
13 |
14 | return version;
15 | }
16 |
--------------------------------------------------------------------------------
/types/missingTypes.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'react-native-easy-markdown';
2 | declare module 'react-native-ssl-pinning';
3 | declare module 'react-native-google-safetynet';
4 | declare module 'react-native-ios11-devicecheck';
5 | declare module '@env' {
6 | export const API_HOST: string;
7 | export const BUILD_VERSION: string;
8 | export const ENV: 'development' | 'production';
9 | export const SAFETYNET_KEY: string;
10 | export const HIDE_DEBUG: 'y' | 'n';
11 | export const TEST_TOKEN: string;
12 | }
13 |
--------------------------------------------------------------------------------
/android/app/src/main/java/gov/scot/covidtracker/SplashActivity.java:
--------------------------------------------------------------------------------
1 | package gov.scot.covidtracker;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import androidx.appcompat.app.AppCompatActivity;
6 |
7 | public class SplashActivity extends AppCompatActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 |
12 | Intent intent = new Intent(this, MainActivity.class);
13 | startActivity(intent);
14 | finish();
15 | }
16 | }
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/test-protect-logo/test-protect-logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "launch.png",
5 | "idiom": "universal",
6 | "scale": "1x"
7 | },
8 | {
9 | "filename": "launch@2x.png",
10 | "idiom": "universal",
11 | "scale": "2x"
12 | },
13 | {
14 | "filename": "launch@3x.png",
15 | "idiom": "universal",
16 | "scale": "3x"
17 | }
18 | ],
19 | "info": {
20 | "author": "xcode",
21 | "version": 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/theme/index.ts:
--------------------------------------------------------------------------------
1 | import {Dimensions, Platform} from 'react-native';
2 | import colors from './colors';
3 |
4 | import getTextStyles from './text';
5 |
6 | const SCREEN_HEIGHT = Dimensions.get('window').height;
7 | const PADDING_TOP = Platform.OS === 'ios' ? 65 : 30;
8 | const REF_HEIGHT = 667;
9 |
10 | const text = getTextStyles(scale);
11 |
12 | function scale(value: number): number {
13 | const ratio = value / REF_HEIGHT;
14 | return Math.min(Math.round(ratio * SCREEN_HEIGHT), value);
15 | }
16 |
17 | export {scale, text, colors, PADDING_TOP};
18 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/hooks/app-state.tsx:
--------------------------------------------------------------------------------
1 | import {useEffect, useState} from 'react';
2 | import {AppStateStatus, AppState} from 'react-native';
3 |
4 | export function useAppState(): [AppStateStatus] {
5 | const [state, setState] = useState(AppState.currentState);
6 | const handler = (nextState: AppStateStatus) => {
7 | setState(nextState);
8 | };
9 |
10 | useEffect(() => {
11 | AppState.addEventListener('change', handler);
12 | return () => {
13 | AppState.removeEventListener('change', handler);
14 | };
15 | }, []);
16 |
17 | return [state];
18 | }
19 |
--------------------------------------------------------------------------------
/ios/ProtectScotland/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 | #import
5 | #import
6 |
7 | @interface AppDelegate : UIResponder
8 |
9 | @property (nonatomic, strong) UMModuleRegistryAdapter *moduleRegistryAdapter;
10 | @property (nonatomic, strong) UIWindow *window;
11 | @property (strong, nonatomic) UIViewController *viewController;
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/services/notifications/hooks.tsx:
--------------------------------------------------------------------------------
1 | import {PushNotification as PushNotificationType} from 'react-native-push-notification';
2 | import {NavigationContainerRef} from '@react-navigation/native';
3 | export const notificationHooks: NotificationHooks = {};
4 |
5 | interface Token {
6 | os: string;
7 | token: string;
8 | }
9 |
10 | export interface NotificationHooks {
11 | handleNotification?: (notification: PushNotificationType) => void;
12 | handleRegister?: (token: Token) => void;
13 | handleAction?: (notification: PushNotificationType) => void;
14 | navigation?: NavigationContainerRef;
15 | }
16 |
--------------------------------------------------------------------------------
/.github/workflows/integration.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | pull_request:
5 | branches: [master]
6 |
7 | jobs:
8 | checks:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: actions/setup-node@v1
14 | with:
15 | node-version: 12.x
16 |
17 | - name: Cache dependencies
18 | uses: actions/cache@v2
19 | with:
20 | path: |
21 | **/node_modules
22 | key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}
23 |
24 | - run: yarn
25 |
26 | - run: yarn run lint
27 | - run: yarn run typecheck
28 |
--------------------------------------------------------------------------------
/components/atoms/heading.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Text, StyleSheet, View} from 'react-native';
3 |
4 | import Spacing from './spacing';
5 |
6 | interface HeadingProps {
7 | text: string;
8 | lineWidth?: number;
9 | }
10 |
11 | export const Heading: React.FC = ({text, lineWidth}) => (
12 | <>
13 | {text}
14 |
15 |
16 | >
17 | );
18 |
19 | const styles = StyleSheet.create({
20 | heading: {
21 | paddingBottom: 8
22 | },
23 | line: {
24 | height: 6,
25 | flexDirection: 'row'
26 | }
27 | });
28 |
--------------------------------------------------------------------------------
/components/atoms/divider.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {View, StyleSheet} from 'react-native';
3 | import {colors} from '../../theme';
4 |
5 | interface DividerProps {
6 | color?: 'lilac' | 'white';
7 | }
8 |
9 | export const Divider: FC = ({color = 'lilac'}) => (
10 |
11 |
12 |
13 | );
14 |
15 | const styles = StyleSheet.create({
16 | divider: {
17 | height: 2,
18 | width: '100%'
19 | },
20 | fill: {
21 | ...StyleSheet.absoluteFillObject,
22 | left: -10,
23 | right: -10
24 | }
25 | });
26 |
27 | export default Divider;
28 |
--------------------------------------------------------------------------------
/android/app/build_defs.bzl:
--------------------------------------------------------------------------------
1 | """Helper definitions to glob .aar and .jar targets"""
2 |
3 | def create_aar_targets(aarfiles):
4 | for aarfile in aarfiles:
5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6 | lib_deps.append(":" + name)
7 | android_prebuilt_aar(
8 | name = name,
9 | aar = aarfile,
10 | )
11 |
12 | def create_jar_targets(jarfiles):
13 | for jarfile in jarfiles:
14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15 | lib_deps.append(":" + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
--------------------------------------------------------------------------------
/components/atoms/media.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {View, StyleSheet, StyleProp, ViewStyle} from 'react-native';
3 |
4 | import Container from './container';
5 |
6 | interface MediaProps {
7 | left: React.ReactNode;
8 | leftStyle?: StyleProp;
9 | }
10 |
11 | const Media: FC = ({left, leftStyle, children}) => (
12 |
13 | {left}
14 | {children}
15 |
16 | );
17 |
18 | const styles = StyleSheet.create({
19 | row: {
20 | flexDirection: 'row'
21 | },
22 | left: {
23 | marginRight: 25
24 | }
25 | });
26 |
27 | export default Media;
28 |
--------------------------------------------------------------------------------
/components/atoms/title.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 |
5 | import Text, {TextProps} from '../atoms/text';
6 |
7 | interface TitleProps extends TextProps {
8 | title: string;
9 | }
10 |
11 | export const Title: FC = ({title, ...props}) => {
12 | const {t} = useTranslation();
13 | return (
14 |
20 | {t(title)}
21 |
22 | );
23 | };
24 |
25 | const styles = StyleSheet.create({
26 | title: {
27 | marginBottom: 30
28 | }
29 | });
30 |
--------------------------------------------------------------------------------
/.detoxrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "testRunner": "jest",
3 | "runnerConfig": "e2e/config.json",
4 | "configurations": {
5 | "ios.sim.debug": {
6 | "type": "ios.simulator",
7 | "binaryPath": "./ios/build/Build/Products/Debug-iphonesimulator/Protect-Scot.app",
8 | "build": "xcodebuild -workspace ios/ProtectScotland.xcworkspace -scheme ProtectScotland -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
9 | "device": {
10 | "type": "iPhone 11 Pro Max"
11 | }
12 | },
13 | "android.sim.debug": {
14 | "type": "android.emulator",
15 | "binaryPath": "SPECIFY_PATH_TO_YOUR_APP_BINARY",
16 | "device": {
17 | "avdName": "Pixel_2_API_29"
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/components/atoms/rounded-box.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View, ViewStyle} from 'react-native';
3 |
4 | import {colors} from '../../theme';
5 |
6 | interface RoundedBoxProps {
7 | children: React.ReactNode;
8 | style?: ViewStyle;
9 | }
10 |
11 | const RoundedBox: FC = ({children, style}) => (
12 | {children}
13 | );
14 |
15 | const styles = StyleSheet.create({
16 | container: {
17 | borderWidth: 1,
18 | borderStyle: 'solid',
19 | borderRadius: 10,
20 | flex: 1,
21 | paddingVertical: 23,
22 | paddingHorizontal: 30,
23 | width: '100%',
24 | color: colors.darkGrey,
25 | borderColor: colors.darkGrey
26 | }
27 | });
28 |
29 | export default RoundedBox;
30 |
--------------------------------------------------------------------------------
/ios/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # This file contains the fastlane.tools configuration
2 | # You can find the documentation at https://docs.fastlane.tools
3 | #
4 | # For a list of all available actions, check out
5 | #
6 | # https://docs.fastlane.tools/actions
7 | #
8 | # For a list of all available plugins, check out
9 | #
10 | # https://docs.fastlane.tools/plugins/available-plugins
11 | #
12 |
13 | # Uncomment the line if you want fastlane to automatically update itself
14 | # update_fastlane
15 |
16 | default_platform(:ios)
17 |
18 | platform :ios do
19 | desc "Push a new beta build to TestFlight"
20 | lane :beta do
21 | increment_build_number(xcodeproj: ENV['XCODEPROJ'])
22 | build_app(workspace: ENV['WORKSPACE'], scheme: ENV['SCHEME'])
23 | upload_to_testflight
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/services/notifications/reminder.tsx:
--------------------------------------------------------------------------------
1 | import {PushNotification as PushNotificationType} from 'react-native-push-notification';
2 | import {NotificationHooks} from 'services/notifications/hooks';
3 | import {ScreenNames} from '../../navigation';
4 |
5 | const MAX_ATTEMPTS = 50;
6 | const ATTEMPTS_DELAY = 200;
7 |
8 | export const reminderNotification = {
9 | id: 12345,
10 | handler: (notification: PushNotificationType, hooks: NotificationHooks) => {
11 | console.log(hooks);
12 | let attempts = 0;
13 | const handle = () => {
14 | if (hooks.navigation) {
15 | hooks.navigation.navigate(ScreenNames.tracing, {notification: true});
16 | } else if (attempts < MAX_ATTEMPTS) {
17 | attempts++;
18 | setTimeout(handle, ATTEMPTS_DELAY);
19 | }
20 | };
21 | handle();
22 | }
23 | } as const;
24 |
--------------------------------------------------------------------------------
/ios/fastlane/README.md:
--------------------------------------------------------------------------------
1 | # fastlane documentation
2 |
3 | # Installation
4 |
5 | Make sure you have the latest version of the Xcode command line tools installed:
6 |
7 | ```
8 | xcode-select --install
9 | ```
10 |
11 | Install _fastlane_ using
12 |
13 | ```
14 | [sudo] gem install fastlane -NV
15 | ```
16 |
17 | or alternatively using `brew install fastlane`
18 |
19 | # Available Actions
20 |
21 | ## iOS
22 |
23 | ### ios beta
24 |
25 | ```
26 | fastlane ios beta
27 | ```
28 |
29 | Push a new beta build to TestFlight
30 |
31 | ---
32 |
33 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
34 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
35 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
36 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'ProtectScotland'
2 | apply from: '../node_modules/react-native-unimodules/gradle.groovy'
3 | includeUnimodulesProjects()
4 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
5 | include ':app'
6 |
7 | include ':react-native-permissions'
8 | project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android')
9 |
10 | include ':react-native-push-notification'
11 | project(':react-native-push-notification').projectDir = file('../node_modules/react-native-push-notification/android')
12 |
13 | include ':react-native-google-safetynet'
14 | project(':react-native-google-safetynet').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-google-safetynet/android')
15 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | -keepattributes Signature
13 | -keep public class com.horcrux.svg.** {*;}
14 | -keep class com.google.crypto.tink.** { *; }
15 | -keep class net.sqlcipher.** { *; }
16 | -keep class net.sqlcipher.database.* { *; }
17 | -keep class * extends androidx.room.RoomDatabase
18 | -keep class * extends com.google.auto
19 | -keep class org.checkerframework.checker.nullness.qual.** { *; }
20 |
21 |
22 |
--------------------------------------------------------------------------------
/components/atoms/logo.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {Image, StyleSheet, View} from 'react-native';
3 | import {useSafeAreaInsets} from 'react-native-safe-area-context';
4 |
5 | const LogoImage = require('../../assets/images/logo/logo.png');
6 |
7 | const Logo: FC = () => {
8 | const insets = useSafeAreaInsets();
9 |
10 | return (
11 |
12 |
17 |
18 | );
19 | };
20 |
21 | const styles = StyleSheet.create({
22 | container: {
23 | width: '100%',
24 | alignItems: 'center',
25 | position: 'absolute',
26 | zIndex: 1
27 | },
28 | logo: {
29 | width: 101,
30 | height: 29,
31 | marginBottom: 12
32 | }
33 | });
34 |
35 | export default Logo;
36 |
--------------------------------------------------------------------------------
/theme/colors.ts:
--------------------------------------------------------------------------------
1 | const colors = {
2 | amber: '#F18E00',
3 | backgroundYellow: '#F1EEC7',
4 | baseGrey: '#D5D5D6',
5 | blueGrey: '#828DA9',
6 | blueGreyLight: '#C4E2F0',
7 | darkerPurple: '#200B22',
8 | darkGrey: '#3B3B3B',
9 | darkPurple: '#3C1540',
10 | errorRed: '#B20000',
11 | errorRedTint: '#F4E2DF',
12 | greenBackground: '#F6F9F2',
13 | hotPink: '#FF267E',
14 | lighterGrey: '#F8F8F8',
15 | lighterPurple: '#F0E7F1',
16 | lightGrey: '#EBEBEB',
17 | lilac: '#9658A1',
18 | lilac50: 'rgba(150, 88, 161, 0.5)',
19 | notificationYellowTint: '#FFF8EC',
20 | paleGrey: '#D5D5D6',
21 | pink: '#D2267E',
22 | primaryPurple: '#6B11A5',
23 | resultYellow: '#F4F48B',
24 | shareBlue: '#6398C9',
25 | validationGreen: '#00A606',
26 | validationGreenTint: '#EDF5EE',
27 | white: '#FFFFFF',
28 | transparent: 'transparent',
29 | lightGray: '#808B8D'
30 | };
31 |
32 | export default colors;
33 |
--------------------------------------------------------------------------------
/postinstall.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 | cp ./android/app/src/main/res/mipmap-hdpi/ic_notification.png ./node_modules/react-native-exposure-notification-service/android/src/main/res/mipmap-hdpi/ic_notification.png
4 |
5 | cp ./android/app/src/main/res/mipmap-mdpi/ic_notification.png ./node_modules/react-native-exposure-notification-service/android/src/main/res/mipmap-mdpi/ic_notification.png
6 |
7 | cp ./android/app/src/main/res/mipmap-xhdpi/ic_notification.png ./node_modules/react-native-exposure-notification-service/android/src/main/res/mipmap-xhdpi/ic_notification.png
8 |
9 | cp ./android/app/src/main/res/mipmap-xxhdpi/ic_notification.png ./node_modules/react-native-exposure-notification-service/android/src/main/res/mipmap-xxhdpi/ic_notification.png
10 |
11 | cp ./android/app/src/main/res/mipmap-xxxhdpi/ic_notification.png ./node_modules/react-native-exposure-notification-service/android/src/main/res/mipmap-xxxhdpi/ic_notification.png
--------------------------------------------------------------------------------
/services/i18n/index.ts:
--------------------------------------------------------------------------------
1 | import i18n from 'i18next';
2 | import {initReactI18next} from 'react-i18next';
3 | import * as Localization from 'expo-localization';
4 |
5 | import {
6 | fallback,
7 | defaultNamespace,
8 | namespaces,
9 | supportedLocales
10 | } from './common';
11 |
12 | const languageDetector = {
13 | type: 'languageDetector',
14 | async: true,
15 | detect: async (callback: (lang: string) => void) => {
16 | callback(Localization.locale.split('-')[0]);
17 | },
18 | init: () => {},
19 | cacheUserLanguage: () => {}
20 | };
21 |
22 | i18n
23 | // @ts-ignore
24 | .use(languageDetector)
25 | .use(initReactI18next)
26 | .init({
27 | fallbackLng: fallback,
28 | resources: supportedLocales,
29 | ns: namespaces,
30 | defaultNS: defaultNamespace,
31 | debug: false,
32 | interpolation: {
33 | escapeValue: false
34 | }
35 | });
36 |
37 | export default i18n;
38 |
--------------------------------------------------------------------------------
/hooks/age-group-translation.tsx:
--------------------------------------------------------------------------------
1 | import {useTranslation} from 'react-i18next';
2 | import {useApplication} from '../providers/context';
3 |
4 | export type GetTranslation = (namespace: string, options?: object) => string;
5 |
6 | export function useAgeGroupTranslation() {
7 | const {t} = useTranslation();
8 | const {user} = useApplication();
9 |
10 | const getTranslation: GetTranslation = (
11 | namespace: string,
12 | options: object = {}
13 | ) => {
14 | const defaultTranslation = t(`${namespace}:default`, options);
15 | if (!user?.ageGroup) {
16 | return defaultTranslation;
17 | }
18 |
19 | const notFound = namespace
20 | .split(':')
21 | .slice(1)
22 | .concat([user.ageGroup])
23 | .join('.');
24 |
25 | const translation = t(`${namespace}:${user.ageGroup}`, options);
26 | return translation === notFound ? defaultTranslation : translation;
27 | };
28 |
29 | return {getTranslation};
30 | }
31 |
--------------------------------------------------------------------------------
/android/app/src/main/java/gov/scot/covidtracker/generated/BasePackageList.java:
--------------------------------------------------------------------------------
1 | package gov.scot.covidtracker.generated;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 | import org.unimodules.core.interfaces.Package;
6 |
7 | public class BasePackageList {
8 | public List getPackageList() {
9 | return Arrays.asList(
10 | new expo.modules.constants.ConstantsPackage(),
11 | new expo.modules.crypto.CryptoPackage(),
12 | new expo.modules.filesystem.FileSystemPackage(),
13 | new expo.modules.font.FontLoaderPackage(),
14 | new expo.modules.haptics.HapticsPackage(),
15 | new expo.modules.imageloader.ImageLoaderPackage(),
16 | new expo.modules.intentlauncher.IntentLauncherPackage(),
17 | new expo.modules.localization.LocalizationPackage(),
18 | new expo.modules.permissions.PermissionsPackage(),
19 | new expo.modules.securestore.SecureStorePackage(),
20 | new expo.modules.webbrowser.WebBrowserPackage()
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/navigation.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {NavigationContainerRef} from '@react-navigation/native';
3 |
4 | export const isMountedRef = React.createRef();
5 |
6 | export const navigationRef = React.createRef();
7 |
8 | export enum ScreenNames {
9 | dashboard = 'dashboard',
10 | ageConfirmation = 'ageConfirmation',
11 | ageSorting = 'ageSorting',
12 | ageUnder = 'ageUnder',
13 | locationConfirmation = 'locationConfirmation',
14 | tracing = 'tracing',
15 | about = 'about',
16 | community = 'community',
17 | settings = 'settings',
18 | onboarding = 'onboarding',
19 | closeContact = 'closeContact',
20 | tests = 'tests',
21 | testsAdd = 'testsAdd',
22 | testsResult = 'testsResult',
23 | terms = 'terms',
24 | dataPolicy = 'dataPolicy',
25 | leave = 'leave',
26 | debug = 'debug',
27 | askPermissions = 'permissions-info',
28 | pause = 'pause',
29 | yourDataModal = 'yourDataModal',
30 | testResultModal = 'testResultModal',
31 | calculatorModal = 'calculatorModal',
32 | sendNotice = 'sendNotice'
33 | }
34 |
--------------------------------------------------------------------------------
/components/atoms/container.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {View, StyleSheet, ViewProps} from 'react-native';
3 |
4 | interface ContainerProps extends ViewProps {
5 | center?: 'horizontal' | 'vertical' | 'both';
6 | stretch?: boolean;
7 | }
8 |
9 | const Container: FC = ({
10 | center,
11 | stretch = true,
12 | children,
13 | style,
14 | ...props
15 | }) => (
16 |
29 | {children}
30 |
31 | );
32 |
33 | const styles = StyleSheet.create({
34 | base: {width: '100%'},
35 | stretch: {flex: 1},
36 | centerHorizontal: {alignItems: 'center'},
37 | centerVertical: {justifyContent: 'center'}
38 | });
39 |
40 | export default Container;
41 |
--------------------------------------------------------------------------------
/android/fastlane/README.md:
--------------------------------------------------------------------------------
1 | # fastlane documentation
2 |
3 | # Installation
4 |
5 | Make sure you have the latest version of the Xcode command line tools installed:
6 |
7 | ```
8 | xcode-select --install
9 | ```
10 |
11 | Install _fastlane_ using
12 |
13 | ```
14 | [sudo] gem install fastlane -NV
15 | ```
16 |
17 | or alternatively using `brew install fastlane`
18 |
19 | # Available Actions
20 |
21 | ## Android
22 |
23 | ### android internal
24 |
25 | ```
26 | fastlane android internal
27 | ```
28 |
29 | Deploy a new Internal Track Build to Google Play
30 |
31 | ### android build_release_apk
32 |
33 | ```
34 | fastlane android build_release_apk
35 | ```
36 |
37 | ### android build_release_bundle
38 |
39 | ```
40 | fastlane android build_release_bundle
41 | ```
42 |
43 | ---
44 |
45 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
46 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
47 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
48 |
--------------------------------------------------------------------------------
/components/atoms/illustration.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Image, ImageProps, StyleSheet, Dimensions} from 'react-native';
3 |
4 | import Container from './container';
5 |
6 | const WINDOW_WIDTH = Dimensions.get('window').width;
7 |
8 | interface IllustrationProps extends ImageProps {
9 | fullWidth?: boolean;
10 | }
11 |
12 | const Illustration: React.FC = ({
13 | fullWidth,
14 | source,
15 | ...props
16 | }) => {
17 | const {width: imgWidth, height: imgHeight} = Image.resolveAssetSource(source);
18 |
19 | return (
20 |
21 |
34 |
35 | );
36 | };
37 |
38 | const styles = StyleSheet.create({
39 | fullWidth: {width: '100%'}
40 | });
41 |
42 | export default Illustration;
43 |
--------------------------------------------------------------------------------
/android/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # This file contains the fastlane.tools configuration
2 | # You can find the documentation at https://docs.fastlane.tools
3 | #
4 | # For a list of all available actions, check out
5 | #
6 | # https://docs.fastlane.tools/actions
7 | #
8 | # For a list of all available plugins, check out
9 | #
10 | # https://docs.fastlane.tools/plugins/available-plugins
11 | #
12 |
13 | # Uncomment the line if you want fastlane to automatically update itself
14 | # update_fastlane
15 |
16 | default_platform(:android)
17 |
18 | platform :android do
19 | desc "Deploy a new Internal Track Build to Google Play"
20 | lane :internal do
21 | increment_version_code(
22 | gradle_file_path: "app/build.gradle",
23 | )
24 | gradle(task: "bundle", build_type: "Release")
25 | upload_to_play_store(
26 | track: "internal",
27 | skip_upload_apk: true,
28 | release_status: "draft"
29 | )
30 | end
31 |
32 | lane :build_release_apk do
33 | gradle(task: "clean assembleRelease")
34 | end
35 |
36 | lane :build_release_bundle do
37 | gradle(task: "clean bundle", build_type: "Release")
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | minSdkVersion = 23
6 | compileSdkVersion = 29
7 | targetSdkVersion = 29
8 | }
9 | repositories {
10 | google()
11 | jcenter()
12 | maven { url 'https://dl.bintray.com/android/android-tools/' }
13 | }
14 | dependencies {
15 | classpath('com.android.tools.build:gradle:4.1.2')
16 |
17 | // NOTE: Do not place your application dependencies here; they belong
18 | // in the individual module build.gradle files
19 | }
20 | }
21 |
22 | allprojects {
23 | repositories {
24 | mavenLocal()
25 | maven {
26 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
27 | url("$rootDir/../node_modules/react-native/android")
28 | }
29 | maven {
30 | // Android JSC is installed from npm
31 | url("$rootDir/../node_modules/jsc-android/dist")
32 | }
33 |
34 | google()
35 | jcenter()
36 | maven { url 'https://www.jitpack.io' }
37 | }
38 | }
39 |
40 | task clean(type: Delete) {
41 | delete rootProject.buildDir
42 | }
43 |
--------------------------------------------------------------------------------
/components/organisms/modals/push-notifications.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {useTranslation} from 'react-i18next';
3 | import {StyleSheet, Linking} from 'react-native';
4 |
5 | import Markdown from '../../atoms/markdown';
6 | import Modal from '../../molecules/modal';
7 | import {text, colors} from '../../../theme';
8 | import {ModalProps} from '../../molecules/modal';
9 |
10 | export const PushNotificationsModal: FC = (props) => {
11 | const {t} = useTranslation();
12 | return (
13 |
25 |
26 | {t('modals:sendNotifications:instructions', {name: t('common:name')})}
27 |
28 |
29 | );
30 | };
31 |
32 | const modalMarkdownStyles = StyleSheet.create({
33 | text: {
34 | ...text.default,
35 | color: colors.white
36 | },
37 | listItemNumber: {
38 | color: colors.white
39 | }
40 | });
41 |
--------------------------------------------------------------------------------
/components/atoms/modal-close.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {Image, TouchableWithoutFeedback} from 'react-native';
3 | import {useNavigation} from '@react-navigation/native';
4 | import {StackNavigationProp} from '@react-navigation/stack';
5 | import {useTranslation} from 'react-i18next';
6 |
7 | const CloseIcon = require('../../assets/images/icon-close/image.png');
8 |
9 | interface ModalCloseProps {
10 | onPress?: () => void;
11 | notification?: boolean;
12 | icon?: React.ReactNode;
13 | }
14 |
15 | export const ModalClose: FC = ({
16 | onPress,
17 | notification = false,
18 | icon
19 | }) => {
20 | const navigation = useNavigation>();
21 | const {t} = useTranslation();
22 |
23 | const handlePress = () => (onPress ? onPress() : navigation.pop());
24 |
25 | return (
26 |
27 |
37 |
38 | );
39 | };
40 |
--------------------------------------------------------------------------------
/components/organisms/modals/bluetooth-notification.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {useTranslation} from 'react-i18next';
3 | import {StyleSheet} from 'react-native';
4 |
5 | import Markdown from '../../atoms/markdown';
6 | import Modal from '../../molecules/modal';
7 | import {text, colors} from '../../../theme';
8 | import {ModalProps} from '../../molecules/modal';
9 | import {goToSettingsAction} from '../../molecules/go-to-settings';
10 |
11 | export const BluetoothNotificationsModal: FC = (props) => {
12 | const {t} = useTranslation();
13 | return (
14 | goToSettingsAction(true),
22 | hint: t('modals:bluetoothNotifications:btnLabel'),
23 | label: t('modals:bluetoothNotifications:btnLabel')
24 | }
25 | ]}>
26 |
27 | {t('modals:bluetoothNotifications:instructions')}
28 |
29 |
30 | );
31 | };
32 |
33 | const modalMarkdownStyles = StyleSheet.create({
34 | text: {
35 | ...text.default,
36 | color: colors.white
37 | },
38 | listItemNumber: {
39 | color: colors.white
40 | }
41 | });
42 |
--------------------------------------------------------------------------------
/components/views/terms.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, ScrollView, View, Platform, StatusBar} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 |
5 | import {useApplication} from '../../providers/context';
6 | import {Title} from '../atoms/title';
7 | import {Back} from '../atoms/back';
8 | import {ModalClose} from '../atoms/modal-close';
9 | import Markdown from '../atoms/markdown';
10 | import Spacing from '../atoms/spacing';
11 | import {SPACING_HORIZONTAL} from '../../theme/layouts/shared';
12 |
13 | export const Terms: FC = () => {
14 | const {t} = useTranslation();
15 | const {user} = useApplication();
16 |
17 | return (
18 | <>
19 |
20 |
21 | {user && }
22 | {!user && (
23 |
24 |
25 |
26 | )}
27 |
28 |
29 | {t('terms:body', {link: t('links:n')})}
30 |
31 | >
32 | );
33 | };
34 |
35 | const styles = StyleSheet.create({
36 | container: {
37 | paddingTop: Platform.OS === 'ios' ? 65 : 30,
38 | paddingHorizontal: SPACING_HORIZONTAL
39 | },
40 | modalClose: {
41 | justifyContent: 'flex-end',
42 | alignItems: 'flex-end'
43 | }
44 | });
45 |
--------------------------------------------------------------------------------
/theme/layouts/onboarding-with-navbar.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC, MutableRefObject} from 'react';
2 | import {ScrollView, ViewStyle} from 'react-native';
3 |
4 | import Container from '../../components/atoms/container';
5 | import NavBar from '../../components/molecules/onboarding-navbar';
6 | import {Scrollable} from './scrollable';
7 |
8 | interface OnboardingWithNavbarProps {
9 | goBack(): void;
10 | canGoBack: boolean;
11 | sections: number;
12 | activeSection: number;
13 | backgroundColor?: string;
14 | scrollableStyle?: ViewStyle;
15 | contentContainerStyle?: ViewStyle;
16 | scrollViewRef?: MutableRefObject;
17 | }
18 |
19 | const OnboardingWithNavbar: FC = ({
20 | canGoBack,
21 | goBack,
22 | children,
23 | sections,
24 | activeSection,
25 | backgroundColor,
26 | contentContainerStyle,
27 | scrollableStyle,
28 | scrollViewRef
29 | }) => (
30 |
31 |
37 |
42 | {children}
43 |
44 |
45 | );
46 |
47 | export default OnboardingWithNavbar;
48 |
--------------------------------------------------------------------------------
/components/views/data-policy.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, ScrollView, View, Platform, StatusBar} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 |
5 | import {useApplication} from '../../providers/context';
6 | import {Title} from '../atoms/title';
7 | import {Back} from '../atoms/back';
8 | import {ModalClose} from '../atoms/modal-close';
9 | import Markdown from '../atoms/markdown';
10 | import Spacing from '../atoms/spacing';
11 | import {SPACING_HORIZONTAL} from '../../theme/layouts/shared';
12 |
13 | export const DataPolicy: FC = () => {
14 | const {t} = useTranslation();
15 | const {user} = useApplication();
16 |
17 | return (
18 | <>
19 |
20 |
21 | {user && }
22 | {!user && (
23 |
24 |
25 |
26 | )}
27 |
28 |
29 | {t('dataPolicy:body', {link: t('links:m')})}
30 |
31 | >
32 | );
33 | };
34 |
35 | const styles = StyleSheet.create({
36 | container: {
37 | paddingTop: Platform.OS === 'ios' ? 65 : 30,
38 | paddingHorizontal: SPACING_HORIZONTAL
39 | },
40 | modalClose: {
41 | justifyContent: 'flex-end',
42 | alignItems: 'flex-end'
43 | }
44 | });
45 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 | # Automatically convert third-party libraries to use AndroidX
25 | android.enableJetifier=true
26 |
27 | # Version of flipper SDK to use with React Native
28 | FLIPPER_VERSION=0.33.1
29 | org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
30 |
--------------------------------------------------------------------------------
/components/atoms/progress-bar.tsx:
--------------------------------------------------------------------------------
1 | import React, {useRef, useEffect} from 'react';
2 | import {StyleSheet, Animated, View} from 'react-native';
3 | import {colors} from '../../theme';
4 |
5 | interface ProgressBarProps {
6 | style?: any;
7 | sections: number;
8 | activeSection: number;
9 | }
10 |
11 | const ProgressBar: React.FC = ({
12 | style,
13 | sections = 1,
14 | activeSection = 1
15 | }) => {
16 | const width = useRef(new Animated.Value((100 / sections) * activeSection))
17 | .current;
18 | useEffect(() => {
19 | const newWidth = (100 / sections) * activeSection;
20 | Animated.timing(width, {
21 | toValue: newWidth,
22 | duration: 200,
23 | useNativeDriver: false
24 | }).start();
25 | }, [activeSection, sections, width]);
26 |
27 | return (
28 |
29 |
40 |
41 | );
42 | };
43 |
44 | const styles = StyleSheet.create({
45 | container: {
46 | width: '100%',
47 | height: 4,
48 | borderRadius: 1,
49 | backgroundColor: colors.white
50 | },
51 | bar: {
52 | flex: 1,
53 | borderRadius: 1,
54 | backgroundColor: colors.primaryPurple
55 | }
56 | });
57 |
58 | export default ProgressBar;
59 |
--------------------------------------------------------------------------------
/components/molecules/new-version-card.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | StyleSheet,
4 | TouchableWithoutFeedback,
5 | View,
6 | Platform,
7 | Linking
8 | } from 'react-native';
9 | import {useTranslation} from 'react-i18next';
10 |
11 | import {colors} from '../../theme';
12 | import Spacing from '../atoms/spacing';
13 | import Text from '../atoms/text';
14 | import RoundedBox from '../atoms/rounded-box';
15 |
16 | export const NewVersionCard = () => {
17 | const {t} = useTranslation();
18 |
19 | const onUpdate = () => {
20 | Linking.openURL(
21 | Platform.OS === 'ios'
22 | ? t('newVersion:appstoreUrl')
23 | : t('newVersion:playstoreUrl')
24 | );
25 | };
26 |
27 | return (
28 |
29 |
30 |
31 |
32 | {t('newVersion:title', {
33 | storeName:
34 | Platform.OS === 'ios'
35 | ? t('newVersion:appstore')
36 | : t('newVersion:playstore')
37 | })}
38 |
39 |
40 |
41 | {t('newVersion:link')}
42 |
43 |
44 |
45 |
46 | );
47 | };
48 |
49 | const styles = StyleSheet.create({
50 | content: {
51 | borderColor: colors.primaryPurple,
52 | width: 'auto'
53 | }
54 | });
55 |
--------------------------------------------------------------------------------
/theme/text.ts:
--------------------------------------------------------------------------------
1 | import colors from './colors';
2 |
3 | export default (scale: (v: number) => number) => {
4 | const text = {
5 | h1Heading: {
6 | fontFamily: 'lato-bold',
7 | fontSize: scale(28),
8 | lineHeight: scale(36)
9 | },
10 | h2Heading: {
11 | fontFamily: 'lato-bold',
12 | fontSize: scale(26),
13 | lineHeight: scale(32)
14 | },
15 | h3Heading: {
16 | fontFamily: 'lato-bold',
17 | fontSize: scale(24),
18 | lineHeight: scale(32)
19 | },
20 | h4Heading: {
21 | fontFamily: 'lato-bold',
22 | fontSize: scale(18),
23 | lineHeight: scale(23)
24 | },
25 | leader: {
26 | fontFamily: 'lato',
27 | fontSize: scale(21),
28 | lineHeight: scale(28)
29 | },
30 | paragraph: {
31 | fontFamily: 'roboto',
32 | fontSize: scale(18),
33 | lineHeight: scale(28)
34 | },
35 | smallerParagraph: {
36 | fontFamily: 'roboto',
37 | fontSize: scale(16),
38 | lineHeight: scale(21)
39 | },
40 | fontFamily: {
41 | roboto: 'roboto',
42 | robotoBold: 'roboto-bold',
43 | lato: 'lato',
44 | latoBold: 'lato-bold'
45 | }
46 | };
47 |
48 | const defaultText = {
49 | ...text.paragraph,
50 | color: colors.darkGrey
51 | };
52 |
53 | const defaultBold = {
54 | ...defaultText,
55 | fontFamily: text.fontFamily.robotoBold
56 | };
57 |
58 | return {
59 | default: defaultText,
60 | defaultBold,
61 | ...text
62 | };
63 | };
64 |
--------------------------------------------------------------------------------
/android/app/_BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "gov.scot.covidtracker",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "gov.scot.covidtracker",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/hooks/a11y-element.tsx:
--------------------------------------------------------------------------------
1 | import React, {useRef, useCallback, useMemo} from 'react';
2 | import {
3 | AccessibilityInfo,
4 | findNodeHandle,
5 | StyleSheet,
6 | View,
7 | ViewProps,
8 | Platform
9 | } from 'react-native';
10 | import {useIsFocused} from '@react-navigation/native';
11 |
12 | import {useApplication} from '../providers/context';
13 |
14 | export const A11yView = React.forwardRef((props, ref) => (
15 |
21 | ));
22 |
23 | export function useA11yElement() {
24 | const {
25 | accessibility: {screenReaderEnabled}
26 | } = useApplication();
27 | const focusRef = useRef(null);
28 | const isFocused = useIsFocused();
29 |
30 | const focusA11yElement = useCallback(
31 | (timeout = 250) => {
32 | if (screenReaderEnabled && focusRef.current && isFocused) {
33 | const tag = findNodeHandle(focusRef.current);
34 | if (tag) {
35 | const id = setTimeout(
36 | () => AccessibilityInfo.setAccessibilityFocus(tag),
37 | timeout
38 | );
39 | return () => clearTimeout(id);
40 | }
41 | }
42 | },
43 | // eslint-disable-next-line react-hooks/exhaustive-deps
44 | [screenReaderEnabled, focusRef.current, isFocused]
45 | );
46 |
47 | const a11yProps = useMemo(
48 | () => ({
49 | ref: focusRef
50 | }),
51 | []
52 | );
53 |
54 | return {a11yProps, focusRef, focusA11yElement};
55 | }
56 |
--------------------------------------------------------------------------------
/components/views/loading.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, Image, View, StatusBar} from 'react-native';
3 | import Spinner from 'react-native-loading-spinner-overlay';
4 | import {useTranslation} from 'react-i18next';
5 | import {useSafeAreaInsets} from 'react-native-safe-area-context';
6 |
7 | import Spacing from '../atoms/spacing';
8 | import {colors} from '../../theme';
9 |
10 | export const Loading: FC = () => {
11 | const {t} = useTranslation();
12 | const insets = useSafeAreaInsets();
13 | return (
14 |
19 |
20 |
21 |
22 |
31 |
32 |
33 |
34 | );
35 | };
36 |
37 | const styles = StyleSheet.create({
38 | container: {
39 | flex: 1,
40 | backgroundColor: colors.white,
41 | justifyContent: 'flex-start'
42 | },
43 | bg: {
44 | ...StyleSheet.absoluteFillObject,
45 | flex: 1,
46 | backgroundColor: colors.primaryPurple
47 | },
48 | center: {
49 | alignSelf: 'center'
50 | }
51 | });
52 |
--------------------------------------------------------------------------------
/ios/ProtectScotland/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "Protect Scotland Icon 20@2x.png",
5 | "idiom": "iphone",
6 | "scale": "2x",
7 | "size": "20x20"
8 | },
9 | {
10 | "filename": "Protect Scotland Icon 20@3x.png",
11 | "idiom": "iphone",
12 | "scale": "3x",
13 | "size": "20x20"
14 | },
15 | {
16 | "filename": "Protect Scotland Icon 29@2x.png",
17 | "idiom": "iphone",
18 | "scale": "2x",
19 | "size": "29x29"
20 | },
21 | {
22 | "filename": "Protect Scotland Icon 29@3x.png",
23 | "idiom": "iphone",
24 | "scale": "3x",
25 | "size": "29x29"
26 | },
27 | {
28 | "filename": "Protect Scotland Icon 40@2x.png",
29 | "idiom": "iphone",
30 | "scale": "2x",
31 | "size": "40x40"
32 | },
33 | {
34 | "filename": "Protect Scotland Icon 40@3x.png",
35 | "idiom": "iphone",
36 | "scale": "3x",
37 | "size": "40x40"
38 | },
39 | {
40 | "filename": "Protect Scotland Icon 60@2x.png",
41 | "idiom": "iphone",
42 | "scale": "2x",
43 | "size": "60x60"
44 | },
45 | {
46 | "filename": "Protect Scotland Icon 60@3x.png",
47 | "idiom": "iphone",
48 | "scale": "3x",
49 | "size": "60x60"
50 | },
51 | {
52 | "filename": "Protect Scotland Icon 1024.png",
53 | "idiom": "ios-marketing",
54 | "scale": "1x",
55 | "size": "1024x1024"
56 | }
57 | ],
58 | "info": {
59 | "author": "xcode",
60 | "version": 1
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/utils/exposure.ts:
--------------------------------------------------------------------------------
1 | import {differenceInCalendarDays, addDays, format} from 'date-fns';
2 | import {CloseContact} from 'react-native-exposure-notification-service';
3 |
4 | export const getExposureDate = (contacts?: CloseContact[]) => {
5 | if (contacts && contacts.length > 0) {
6 | const {exposureDate} = contacts[0];
7 | return new Date(exposureDate);
8 | }
9 | };
10 |
11 | export const getSelfIsolationRemainingDays = (
12 | isolationDuration: number,
13 | contacts?: CloseContact[]
14 | ) => {
15 | const exposureDate = getExposureDate(contacts);
16 | const remainingDays = exposureDate
17 | ? isolationDuration - differenceInCalendarDays(Date.now(), exposureDate)
18 | : -1;
19 | return remainingDays > 0 ? remainingDays : 0;
20 | };
21 |
22 | export const DATE_FORMAT = 'd MMMM yyyy';
23 |
24 | export const getIsolationEndDate = (
25 | isolationDuration: number,
26 | contacts?: CloseContact[],
27 | fmt: string = DATE_FORMAT
28 | ) => {
29 | const exposureDate = getExposureDate(contacts);
30 |
31 | if (exposureDate) {
32 | const isolationEndDate = addDays(exposureDate, isolationDuration);
33 | return {
34 | raw: isolationEndDate,
35 | formatted: format(isolationEndDate, fmt)
36 | };
37 | }
38 | };
39 |
40 | export const hasCurrentExposure = (
41 | isolationDuration: number,
42 | contacts?: CloseContact[]
43 | ) => {
44 | if (!contacts || contacts.length === 0) {
45 | return false;
46 | }
47 |
48 | const exposureDate = getExposureDate(contacts);
49 | const daysDiff = differenceInCalendarDays(new Date(), exposureDate!);
50 | return daysDiff < isolationDuration;
51 | };
52 |
--------------------------------------------------------------------------------
/components/molecules/header.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View, Image, TouchableWithoutFeedback} from 'react-native';
3 | import {useNavigation} from '@react-navigation/native';
4 | import {useTranslation} from 'react-i18next';
5 |
6 | import {ScreenNames} from '../../navigation';
7 | import {SPACING_HORIZONTAL} from '../../theme/layouts/shared';
8 |
9 | const IconLogo = require('../../assets/images/icon-logo/image.png');
10 | const IconMenu = require('../../assets/images/icon-menu/image.png');
11 |
12 | export const Header: FC = () => {
13 | const navigation = useNavigation();
14 | const {t} = useTranslation();
15 | return (
16 |
17 |
18 | navigation.navigate(ScreenNames.settings)}>
23 |
29 |
30 |
31 | );
32 | };
33 |
34 | const styles = StyleSheet.create({
35 | container: {
36 | flexDirection: 'row',
37 | justifyContent: 'space-between',
38 | alignItems: 'center',
39 | paddingTop: 65,
40 | paddingHorizontal: SPACING_HORIZONTAL,
41 | paddingBottom: 25
42 | },
43 | settings: {
44 | width: 44,
45 | height: 44
46 | }
47 | });
48 |
--------------------------------------------------------------------------------
/services/notifications/index.tsx:
--------------------------------------------------------------------------------
1 | import PushNotification, {
2 | PushNotification as PushNotificationType
3 | } from 'react-native-push-notification';
4 | import {reminderNotification} from './reminder';
5 | import {notificationHooks} from './hooks';
6 |
7 | interface Token {
8 | os: string;
9 | token: string;
10 | }
11 |
12 | const notificationTypes = [reminderNotification];
13 |
14 | const getId = (notification: PushNotificationType): string => {
15 | // @ts-ignore
16 | return notification.id || notification.data.id;
17 | };
18 |
19 | PushNotification.configure({
20 | onNotification: (notification: PushNotificationType) => {
21 | console.log(`Responding to notification ${getId(notification)}`);
22 | const notificationType = notificationTypes.find(
23 | ({id}) => String(id) === getId(notification)
24 | );
25 |
26 | if (notificationType?.handler) {
27 | notificationType?.handler(notification, notificationHooks);
28 | } else if (notificationHooks.handleNotification) {
29 | notificationHooks.handleNotification(notification);
30 | }
31 | },
32 | onRegister: (token: Token) => {
33 | if (notificationHooks.handleRegister) {
34 | notificationHooks.handleRegister(token);
35 | }
36 | },
37 | // senderID: '1087125483031',
38 | permissions: {
39 | alert: true,
40 | badge: true,
41 | sound: true
42 | },
43 | popInitialNotification: true,
44 | requestPermissions: false
45 | });
46 |
47 | PushNotification.createChannel(
48 | {
49 | channelId: 'default',
50 | channelName: 'Default channel'
51 | },
52 | () => {}
53 | );
54 |
55 | export {notificationHooks};
56 |
--------------------------------------------------------------------------------
/components/molecules/onboarding-navbar.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 |
5 | import Container from '../atoms/container';
6 | import ProgressBar from '../atoms/progress-bar';
7 | import {Back} from '../atoms/back';
8 |
9 | interface NavBarProps {
10 | goBack(): void;
11 | sections: number;
12 | activeSection: number;
13 | canGoBack: boolean;
14 | }
15 |
16 | const NavBar: FC = ({
17 | goBack,
18 | sections,
19 | activeSection,
20 | canGoBack
21 | }) => {
22 | const {t} = useTranslation();
23 | return (
24 | <>
25 |
26 |
27 | {canGoBack && }
28 |
29 |
36 |
37 |
38 |
39 | >
40 | );
41 | };
42 |
43 | const styles = StyleSheet.create({
44 | container: {
45 | flexDirection: 'row',
46 | justifyContent: 'space-between',
47 | paddingTop: 56,
48 | paddingHorizontal: 40,
49 | paddingBottom: 20,
50 | width: '100%'
51 | },
52 | back: {
53 | width: 30,
54 | height: 30,
55 | marginRight: 24
56 | },
57 | wave: {
58 | position: 'absolute',
59 | zIndex: 10
60 | }
61 | });
62 |
63 | export default NavBar;
64 |
--------------------------------------------------------------------------------
/components/atoms/back.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {View, Image, StyleSheet, TouchableWithoutFeedback} from 'react-native';
3 | import {useNavigation} from '@react-navigation/native';
4 | import {useTranslation} from 'react-i18next';
5 | import {colors} from '../../theme';
6 |
7 | const IconBack = require('../../assets/images/icon-back-light/image.png');
8 | const IconBackDark = require('../../assets/images/icon-back/image.png');
9 | const IconBackArrowDark = require('../../assets/images/back/image.png');
10 |
11 | export interface BackProps {
12 | variant?: 'default' | 'light' | 'dark';
13 | onPress?: () => void;
14 | }
15 |
16 | const icons = {
17 | default: IconBackArrowDark,
18 | light: IconBack,
19 | dark: IconBackDark
20 | };
21 |
22 | export const Back: FC = ({
23 | variant = 'default',
24 | onPress: onPressProp
25 | }) => {
26 | const navigation = useNavigation();
27 | const {t} = useTranslation();
28 |
29 | const onPress = () => navigation.goBack();
30 |
31 | return (
32 |
38 |
39 |
43 |
44 |
45 | );
46 | };
47 |
48 | const styles = StyleSheet.create({
49 | container: {
50 | width: 30,
51 | height: 30,
52 | borderRadius: 15,
53 | backgroundColor: colors.white,
54 | alignItems: 'center',
55 | justifyContent: 'center'
56 | }
57 | });
58 |
--------------------------------------------------------------------------------
/components/views/onboarding/privacy.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {Image} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 |
5 | import Button from '../../atoms/button';
6 | import Spacing from '../../atoms/spacing';
7 | import Markdown from '../../atoms/markdown';
8 | import Container from '../../atoms/container';
9 | import {OnboardingPageProps} from './common';
10 | import Text from '../../atoms/text';
11 | import {openBrowserAsync} from '../../../utils/web-browser';
12 |
13 | const IllustrationSource = require('../../../assets/images/privacy-illustration/image.png');
14 |
15 | const PrivacyInfo: FC = ({handleNext}) => {
16 | const {t} = useTranslation();
17 |
18 | return (
19 | <>
20 |
21 |
22 |
26 |
27 |
28 |
29 | {t('onboarding:privacy:title')}
30 |
31 |
32 | {t('onboarding:privacy:text')}
33 |
34 |
35 |
41 |
42 |
45 |
46 | >
47 | );
48 | };
49 |
50 | export default PrivacyInfo;
51 |
--------------------------------------------------------------------------------
/components/views/onboarding/your-data.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {Image} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 |
5 | import Button from '../../atoms/button';
6 | import Spacing from '../../atoms/spacing';
7 | import Markdown from '../../atoms/markdown';
8 | import Container from '../../atoms/container';
9 | import {OnboardingPageProps} from './common';
10 | import Text from '../../atoms/text';
11 | import {ScreenNames} from '../../../navigation';
12 | import {useNavigation} from '@react-navigation/native';
13 |
14 | const IllustrationSource = require('../../../assets/images/your-data-illustration/image.png');
15 |
16 | const YourData: FC = ({handleNext}) => {
17 | const navigation = useNavigation();
18 | const {t} = useTranslation();
19 | return (
20 | <>
21 |
22 |
23 |
27 |
28 |
29 |
30 | {t('onboarding:yourData:title')}
31 |
32 |
33 | {t('onboarding:yourData:text')}
34 |
35 |
36 |
41 |
42 |
45 |
46 | >
47 | );
48 | };
49 |
50 | export default YourData;
51 |
--------------------------------------------------------------------------------
/components/views/onboarding/test-result.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {Image} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 |
5 | import Button from '../../atoms/button';
6 | import Spacing from '../../atoms/spacing';
7 | import Markdown from '../../atoms/markdown';
8 | import Container from '../../atoms/container';
9 | import {OnboardingPageProps} from './common';
10 | import Text from '../../atoms/text';
11 | import {ScreenNames} from '../../../navigation';
12 | import {useNavigation} from '@react-navigation/native';
13 |
14 | const IllustrationSource = require('../../../assets/images/test-result-illustration/image.png');
15 |
16 | const TestResult: FC = ({handleNext}) => {
17 | const navigation = useNavigation();
18 | const {t} = useTranslation();
19 | return (
20 | <>
21 |
22 |
23 |
27 |
28 |
29 |
30 | {t('onboarding:testResult:title')}
31 |
32 |
33 | {t('onboarding:testResult:text')}
34 |
35 |
36 |
42 |
43 |
46 |
47 | >
48 | );
49 | };
50 |
51 | export default TestResult;
52 |
--------------------------------------------------------------------------------
/components/molecules/modal/clear-contacts.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {useTranslation} from 'react-i18next';
3 | import {StyleSheet} from 'react-native';
4 | import {useExposure} from 'react-native-exposure-notification-service';
5 | import * as SecureStore from 'expo-secure-store';
6 |
7 | import Markdown from '../../atoms/markdown';
8 | import Modal, {ModalProps} from '.';
9 | import {text, colors} from '../../../theme';
10 | import Spacing from '../../atoms/spacing';
11 |
12 | export const ClearContactsModal: FC = (props) => {
13 | const {t} = useTranslation();
14 | const {deleteExposureData, getCloseContacts} = useExposure();
15 | return (
16 | {
22 | try {
23 | await deleteExposureData();
24 | await getCloseContacts();
25 | await SecureStore.deleteItemAsync('niexposuredate');
26 | } catch (e) {
27 | console.log('Error deleting exposure data', e);
28 | }
29 | },
30 | hint: t('modals:clearContacts:okBtnHint'),
31 | label: t('modals:clearContacts:okBtnLabel')
32 | },
33 | {
34 | action: () => {},
35 | hint: t('modals:clearContacts:cancelBtnHint'),
36 | label: t('modals:clearContacts:cancelBtnLabel'),
37 | type: 'secondary'
38 | }
39 | ]}>
40 |
41 | {t('modals:clearContacts:instructions')}
42 |
43 |
44 |
45 | );
46 | };
47 |
48 | const modalMarkdownStyles = StyleSheet.create({
49 | text: {
50 | ...text.leader,
51 | color: colors.darkGrey,
52 | textAlign: 'center'
53 | },
54 | block: {
55 | margin: 0
56 | }
57 | });
58 |
--------------------------------------------------------------------------------
/components/views/onboarding/why-use.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {Image} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 |
5 | import Button from '../../atoms/button';
6 | import Spacing from '../../atoms/spacing';
7 | import Markdown from '../../atoms/markdown';
8 | import Container from '../../atoms/container';
9 | import {OnboardingPageProps} from './common';
10 | import Text from '../../atoms/text';
11 | import {ArrowLink} from '../../molecules/arrow-link';
12 |
13 | const IllustrationSource = require('../../../assets/images/why-use-illustration/image.png');
14 |
15 | const WhyUse: FC = ({handleNext}) => {
16 | const {t} = useTranslation();
17 |
18 | return (
19 | <>
20 |
21 |
22 |
26 |
27 |
28 |
29 | {t('onboarding:whyUse:title')}
30 |
31 |
32 | {t('onboarding:whyUse:text')}
33 |
34 |
35 | {t('onboarding:whyUse:link1')}
36 |
37 |
38 |
39 |
40 |
41 | {t('onboarding:whyUse:link2')}
42 |
43 |
44 |
45 |
46 |
49 |
50 | >
51 | );
52 | };
53 |
54 | export default WhyUse;
55 |
--------------------------------------------------------------------------------
/hooks/confirmation-space.tsx:
--------------------------------------------------------------------------------
1 | // Provides the heights for age and location confirmation images and content
2 | // sized so they best fit the screen ratio without cutting off the graphic.
3 | import {useMemo} from 'react';
4 | import {Dimensions} from 'react-native';
5 |
6 | const {width: WINDOW_WIDTH, height: WINDOW_HEIGHT} = Dimensions.get('window');
7 |
8 | // The height / width ratio of the illustration and logo
9 | const IMAGE_RATIO = 993 / 1125;
10 | const LOGO_RATIO = 377 / 1125;
11 | // If the ratio of the window dimensions are less then this then don't trim the illustration
12 | const NO_TRIM_RATIO = 0.462;
13 | // If the ratio of the window dimensions are more then this then use the max trim
14 | const MAX_TRIM_RATIO = 0.53;
15 | // The maximum amount to trim from the top of the image
16 | const MAX_TRIM = -30;
17 | // The illustration is displayed full width. From this we can calculate the height
18 | const ILLUSTRATION_HEIGHT = IMAGE_RATIO * WINDOW_WIDTH;
19 | const LOGO_HEIGHT = LOGO_RATIO * WINDOW_WIDTH;
20 |
21 | export function useConfirmationSpace(
22 | minContentHeight: number
23 | ): {
24 | topTrim: number;
25 | contentHeight: number;
26 | ILLUSTRATION_HEIGHT: number;
27 | LOGO_HEIGHT: number;
28 | } {
29 | const contentHeight = useMemo(() => {
30 | const bottomHeight = WINDOW_HEIGHT - ILLUSTRATION_HEIGHT - LOGO_HEIGHT;
31 | return minContentHeight > bottomHeight ? minContentHeight : bottomHeight;
32 | }, [minContentHeight]);
33 |
34 | const topTrim = useMemo(() => {
35 | const screenRatio = WINDOW_WIDTH / WINDOW_HEIGHT;
36 | const trimRange = MAX_TRIM_RATIO - NO_TRIM_RATIO;
37 | const trimPercent =
38 | screenRatio < NO_TRIM_RATIO
39 | ? 0
40 | : screenRatio > MAX_TRIM_RATIO
41 | ? 1
42 | : 1 - (MAX_TRIM_RATIO - screenRatio) / trimRange;
43 | return trimPercent * MAX_TRIM;
44 | }, []);
45 |
46 | return {topTrim, contentHeight, ILLUSTRATION_HEIGHT, LOGO_HEIGHT};
47 | }
48 |
--------------------------------------------------------------------------------
/components/views/onboarding/upgrade-notice.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {Linking, Platform} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 | import {useExposure} from 'react-native-exposure-notification-service';
5 |
6 | import Button from '../../atoms/button';
7 | import Spacing from '../../atoms/spacing';
8 | import Text from '../../atoms/text';
9 | import Container from '../../atoms/container';
10 |
11 | interface UpgradeNoticeProps {}
12 |
13 | const UpgradeNotice: FC = () => {
14 | const {t} = useTranslation();
15 | const exposure = useExposure();
16 |
17 | const checkForUpgradeHandler = async () => {
18 | try {
19 | if (Platform.OS === 'ios') {
20 | Linking.openURL('App-Prefs:');
21 | } else {
22 | await exposure.triggerUpdate();
23 | await exposure.supportsExposureApi();
24 | }
25 | } catch (err) {
26 | console.log('Error handling check for upgrade', err);
27 | }
28 | };
29 |
30 | return (
31 | <>
32 |
33 |
34 |
35 | {t(`onboarding:upgradeNotice:${Platform.OS}:title`)}
36 |
37 |
38 | {t(`onboarding:upgradeNotice:${Platform.OS}:text1`)}
39 |
40 |
41 | {t('onboarding:upgradeNotice:text2')}
42 |
43 |
44 |
45 |
53 | {Platform.OS === 'android' && }
54 | >
55 | );
56 | };
57 |
58 | export default UpgradeNotice;
59 |
--------------------------------------------------------------------------------
/components/molecules/close-contact-step.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native';
3 |
4 | import Media from '../atoms/media';
5 | import Text from '../atoms/text';
6 | import Spacing from '../atoms/spacing';
7 | import {ArrowLink} from './arrow-link';
8 | import {colors, scale} from '../../theme';
9 |
10 | const Number: FC = ({children}) => (
11 |
12 |
13 | {children}
14 |
15 |
16 | );
17 |
18 | interface CloseContactStepProps {
19 | number: number;
20 | title: string;
21 | text?: string | React.ReactNode;
22 | link?: string;
23 | linkText?: string;
24 | onPress?: () => void;
25 | }
26 |
27 | const CloseContactStep: FC = ({
28 | number,
29 | title,
30 | text,
31 | link,
32 | linkText,
33 | onPress
34 | }) => (
35 |
36 |
37 | {number}} leftStyle={styles.left}>
38 |
39 | {title}
40 |
41 |
42 | {typeof text === 'string' ? {text} : text}
43 | {link && (
44 | <>
45 |
46 |
47 |
48 | {linkText}
49 |
50 |
51 | >
52 | )}
53 |
54 |
55 |
56 | );
57 |
58 | const styles = StyleSheet.create({
59 | left: {
60 | marginRight: 16
61 | },
62 | number: {
63 | width: 30,
64 | height: 30,
65 | borderRadius: 15,
66 | backgroundColor: colors.darkGrey
67 | },
68 | numberText: {
69 | fontSize: scale(17)
70 | }
71 | });
72 |
73 | export default CloseContactStep;
74 |
--------------------------------------------------------------------------------
/components/atoms/text.tsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect} from 'react';
2 | import {
3 | Text as T,
4 | StyleSheet,
5 | TextProps as TProps,
6 | TextStyle
7 | } from 'react-native';
8 |
9 | import {useA11yElement} from '../../hooks';
10 | import {text, colors} from '../../theme';
11 |
12 | export interface TextProps extends TProps {
13 | variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'leader' | 'normal' | 'small';
14 | inline?: boolean;
15 | light?: boolean;
16 | color?: keyof typeof colors;
17 | align?: TextStyle['textAlign'];
18 | bold?: boolean;
19 | }
20 |
21 | export const Text: React.FC = ({
22 | variant = 'normal',
23 | inline,
24 | accessible,
25 | light,
26 | color,
27 | style,
28 | children,
29 | align,
30 | bold,
31 | ...props
32 | }) => {
33 | const {focusRef, focusA11yElement} = useA11yElement();
34 |
35 | useEffect(() => {
36 | if (accessible) {
37 | focusA11yElement();
38 | }
39 | }, [accessible, focusA11yElement]);
40 |
41 | return (
42 |
62 | {children}
63 |
64 | );
65 | };
66 |
67 | const styles = StyleSheet.create({
68 | base: {width: '100%'},
69 | inline: {width: 'auto'},
70 | h1: {...text.h1Heading},
71 | h2: {...text.h2Heading},
72 | h3: {...text.h3Heading},
73 | h4: {...text.h4Heading},
74 | leader: {...text.leader},
75 | normal: {...text.paragraph},
76 | small: {...text.smallerParagraph},
77 | dark: {color: colors.darkerPurple},
78 | light: {color: colors.white}
79 | });
80 |
81 | export default Text;
82 |
--------------------------------------------------------------------------------
/ios/ProtectScotland.xcodeproj/xcshareddata/xcschemes/ProtectScotlandTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/components/atoms/symptom-checker.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View, Image, TouchableWithoutFeedback} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 | import * as WebBrowser from 'expo-web-browser';
5 |
6 | import RoundedBox from '../atoms/rounded-box';
7 | import {text, colors} from '../../theme';
8 | import Markdown from './markdown';
9 |
10 | const SymptomCheckerImage = require('../../assets/images/symptoms/image.png');
11 |
12 | export const SymptomCheckerMessage: FC = () => {
13 | const {t} = useTranslation();
14 | const handle = () => {
15 | WebBrowser.openBrowserAsync(t('links:b'), {
16 | enableBarCollapsing: true,
17 | showInRecents: true
18 | });
19 | };
20 |
21 | return (
22 |
23 |
24 |
25 |
32 |
33 |
34 | {t('symptomChecker:message')}
35 |
36 |
37 |
38 |
39 |
40 | );
41 | };
42 |
43 | const markdownStyles = StyleSheet.create({
44 | text: {
45 | ...text.smallerParagraph,
46 | color: colors.darkerPurple
47 | },
48 | // @ts-ignore
49 | strong: {
50 | ...text.h4Heading,
51 | color: colors.primaryPurple
52 | }
53 | });
54 |
55 | const styles = StyleSheet.create({
56 | container: {
57 | backgroundColor: colors.lighterPurple,
58 | borderColor: colors.lilac,
59 | alignItems: 'center',
60 | flexDirection: 'row',
61 | marginLeft: 45,
62 | marginRight: 45,
63 | width: 'auto',
64 | paddingHorizontal: 20,
65 | paddingVertical: 0
66 | },
67 | symptomMessage: {
68 | paddingVertical: 20,
69 | marginLeft: 15,
70 | flex: 1
71 | }
72 | });
73 |
--------------------------------------------------------------------------------
/components/atoms/note-link.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {
3 | TouchableWithoutFeedback,
4 | View,
5 | Image,
6 | Text,
7 | StyleSheet
8 | } from 'react-native';
9 | import * as WebBrowser from 'expo-web-browser';
10 | import {useTranslation} from 'react-i18next';
11 |
12 | import {text as T, colors} from '../../theme';
13 |
14 | const IconNote = require('../../assets/images/icon-note/image.png');
15 |
16 | interface NoteLink {
17 | text: string;
18 | link: string;
19 | background?: string;
20 | }
21 |
22 | export const NoteLink: FC = ({
23 | background = colors.darkGrey,
24 | link,
25 | text
26 | }) => {
27 | const {t} = useTranslation();
28 | const handle = () => {
29 | WebBrowser.openBrowserAsync(t(link), {
30 | enableBarCollapsing: true,
31 | showInRecents: true
32 | });
33 | };
34 |
35 | return (
36 |
37 |
38 |
39 |
47 |
48 |
49 |
50 | {t(text)}
51 |
52 |
53 |
54 |
55 | );
56 | };
57 |
58 | const styles = StyleSheet.create({
59 | container: {
60 | flexDirection: 'row',
61 | borderWidth: 1,
62 | borderStyle: 'solid',
63 | borderRadius: 10,
64 | overflow: 'hidden'
65 | },
66 | heading: {
67 | fontWeight: 'bold'
68 | },
69 | icon: {
70 | alignItems: 'center',
71 | justifyContent: 'center',
72 | padding: 12,
73 | width: 100
74 | },
75 | text: {
76 | ...T.smallerParagraph
77 | },
78 | textContainer: {
79 | flex: 1,
80 | padding: 13,
81 | paddingHorizontal: 25
82 | }
83 | });
84 |
--------------------------------------------------------------------------------
/android/app/src/main/java/gov/scot/covidtracker/MainApplication.java:
--------------------------------------------------------------------------------
1 | package gov.scot.covidtracker;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.util.Log;
6 |
7 | import com.facebook.react.PackageList;
8 | import com.facebook.react.ReactApplication;
9 | import com.facebook.react.ReactInstanceManager;
10 | import com.facebook.react.ReactNativeHost;
11 | import com.facebook.react.ReactPackage;
12 | import com.facebook.soloader.SoLoader;
13 | import java.lang.reflect.InvocationTargetException;
14 | import java.util.List;
15 | import java.util.Arrays;
16 |
17 | import gov.scot.covidtracker.generated.BasePackageList;
18 | import org.unimodules.adapters.react.ModuleRegistryAdapter;
19 | import org.unimodules.adapters.react.ReactModuleRegistryProvider;
20 | import org.unimodules.core.interfaces.SingletonModule;
21 |
22 | public class MainApplication extends Application implements ReactApplication {
23 | private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider(new BasePackageList().getPackageList(), Arrays.asList());
24 |
25 | private final ReactNativeHost mReactNativeHost =
26 | new ReactNativeHost(this) {
27 | @Override
28 | public boolean getUseDeveloperSupport() {
29 | return BuildConfig.DEBUG;
30 | }
31 |
32 | @Override
33 | protected List getPackages() {
34 | @SuppressWarnings("UnnecessaryLocalVariable")
35 | List packages = new PackageList(this).getPackages();
36 | List unimodules = Arrays.asList(
37 | new ModuleRegistryAdapter(mModuleRegistryProvider)
38 | );
39 | packages.addAll(unimodules);
40 | return packages;
41 | }
42 |
43 | @Override
44 | protected String getJSMainModuleName() {
45 | return "index";
46 | }
47 | };
48 |
49 | @Override
50 | public ReactNativeHost getReactNativeHost() {
51 | return mReactNativeHost;
52 | }
53 |
54 | @Override
55 | public void onCreate() {
56 | super.onCreate();
57 | SoLoader.init(this, /* native exopackage */ false);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/ios/ProtectScotland/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/theme/layouts/scrollable.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC, MutableRefObject} from 'react';
2 | import {
3 | StyleSheet,
4 | ScrollView,
5 | RefreshControl,
6 | ViewStyle,
7 | AccessibilityProps
8 | } from 'react-native';
9 | import {useSafeAreaInsets} from 'react-native-safe-area-context';
10 |
11 | import {SPACING_TOP, SPACING_BOTTOM, SPACING_HORIZONTAL} from './shared';
12 | import Container from '../../components/atoms/container';
13 | import Spacing from '../../components/atoms/spacing';
14 |
15 | interface LayoutProps {
16 | toast?: React.ReactNode;
17 | backgroundColor?: string;
18 | refresh?: {
19 | refreshing: boolean;
20 | onRefresh: () => void;
21 | };
22 | scrollViewRef?: MutableRefObject;
23 | safeArea?: boolean;
24 | children: React.ReactNode;
25 | contentContainerStyle?: ViewStyle;
26 | scrollableStyle?: ViewStyle;
27 | importantForAccessibility?: AccessibilityProps['importantForAccessibility'];
28 | }
29 |
30 | export const Scrollable: FC = ({
31 | toast,
32 | backgroundColor,
33 | refresh,
34 | scrollViewRef,
35 | safeArea = true,
36 | children,
37 | contentContainerStyle,
38 | scrollableStyle = {},
39 | importantForAccessibility = 'auto'
40 | }) => {
41 | const insets = useSafeAreaInsets();
42 | const refreshControl = refresh && ;
43 |
44 | return (
45 |
46 |
57 | {toast && (
58 | <>
59 | {toast}
60 |
61 | >
62 | )}
63 | {children}
64 |
65 |
66 | );
67 | };
68 |
69 | const styles = StyleSheet.create({
70 | scrollView: {
71 | paddingTop: SPACING_TOP,
72 | paddingHorizontal: SPACING_HORIZONTAL
73 | }
74 | });
75 |
--------------------------------------------------------------------------------
/android/app/src/main/java/gov/scot/covidtracker/MainActivity.java:
--------------------------------------------------------------------------------
1 | package gov.scot.covidtracker;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import androidx.annotation.Nullable;
7 | import com.facebook.react.ReactActivity;
8 | import com.facebook.react.ReactActivityDelegate;
9 | import com.rajivshah.safetynet.RNGoogleSafetyNetPackage;
10 |
11 | public class MainActivity extends ReactActivity {
12 |
13 | /**
14 | * Returns the name of the main component registered from JavaScript. This is used to schedule
15 | * rendering of the component.
16 | */
17 | @Override
18 | protected String getMainComponentName() {
19 | return "ProtectScotland";
20 | }
21 |
22 | public static class ActivityDelegate extends ReactActivityDelegate {
23 | private static final String NOTIFICATION = "exposureNotificationClicked";
24 | private Bundle mInitialProps = null;
25 | private final
26 | @Nullable
27 | Activity mActivity;
28 |
29 | public ActivityDelegate(Activity activity, String mainComponentName) {
30 | super(activity, mainComponentName);
31 | this.mActivity = activity;
32 | }
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | Log.i("ActivityDelegate", "onCreate");
37 |
38 | Bundle bundle = mActivity.getIntent().getExtras();
39 | if (bundle != null && bundle.containsKey(NOTIFICATION)) {
40 | Log.i("ActivityDelegate", "notification: " + bundle.getBoolean(NOTIFICATION));
41 | mInitialProps = new Bundle();
42 | mInitialProps.putBoolean(NOTIFICATION, bundle.getBoolean(NOTIFICATION));
43 | }
44 | super.onCreate(null);
45 | }
46 |
47 | @Override
48 | protected Bundle getLaunchOptions() {
49 | return mInitialProps;
50 | }
51 | }
52 |
53 | @Override
54 | protected ReactActivityDelegate createReactActivityDelegate() {
55 | return new ActivityDelegate(this, getMainComponentName());
56 | }
57 |
58 | @Override
59 | protected void onCreate(Bundle savedInstanceState) {
60 | Log.i("MainActivity", "onCreate");
61 | super.onCreate(null);
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/ios/ProtectScotland/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BGTaskSchedulerPermittedIdentifiers
6 |
7 | $(PRODUCT_BUNDLE_IDENTIFIER).exposure-notification
8 |
9 | CFBundleDevelopmentRegion
10 | en
11 | CFBundleDisplayName
12 | $(PRODUCT_NAME)
13 | CFBundleExecutable
14 | $(EXECUTABLE_NAME)
15 | CFBundleIdentifier
16 | $(PRODUCT_BUNDLE_IDENTIFIER)
17 | CFBundleInfoDictionaryVersion
18 | 6.0
19 | CFBundleName
20 | $(PRODUCT_NAME)
21 | CFBundlePackageType
22 | APPL
23 | CFBundleShortVersionString
24 | $(MARKETING_VERSION)
25 | CFBundleSignature
26 | ????
27 | CFBundleSpokenName
28 | Protect Scotland
29 | CFBundleVersion
30 | $(CURRENT_PROJECT_VERSION)
31 | ENAPIVersion
32 | 2
33 | ENDeveloperRegion
34 | GB-SCT
35 | ITSAppUsesNonExemptEncryption
36 |
37 | LSApplicationCategoryType
38 |
39 | LSRequiresIPhoneOS
40 |
41 | NSAppTransportSecurity
42 |
43 | NSAllowsArbitraryLoads
44 |
45 | NSExceptionDomains
46 |
47 | localhost
48 |
49 | NSExceptionAllowsInsecureHTTPLoads
50 |
51 |
52 |
53 |
54 | UIBackgroundModes
55 |
56 | fetch
57 | processing
58 |
59 | UILaunchStoryboardName
60 | LaunchScreen
61 | UIRequiredDeviceCapabilities
62 |
63 | telephony
64 | bluetooth-le
65 | armv7
66 |
67 | UISupportedInterfaceOrientations
68 |
69 | UIInterfaceOrientationPortrait
70 |
71 | UIViewControllerBasedStatusBarAppearance
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/components/atoms/message.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {
3 | StyleSheet,
4 | View,
5 | Image,
6 | TouchableWithoutFeedback,
7 | TouchableWithoutFeedbackProps,
8 | ImageSourcePropType
9 | } from 'react-native';
10 | import {withTranslation, WithTranslation} from 'react-i18next';
11 |
12 | import RoundedBox from './rounded-box';
13 | import Container from './container';
14 | import {text, colors} from '../../theme';
15 | import Markdown from './markdown';
16 | import {openBrowserAsync} from '../../utils/web-browser';
17 |
18 | const SymptomCheckerImage = require('../../assets/images/symptoms/image.png');
19 |
20 | interface MessageProps extends TouchableWithoutFeedbackProps, WithTranslation {
21 | image?: ImageSourcePropType;
22 | markdown?: string;
23 | link?: string;
24 | }
25 |
26 | const MessageBase: FC = ({
27 | t,
28 | image = SymptomCheckerImage,
29 | markdown = t('symptomChecker:message'),
30 | link = t('links:b'),
31 | accessibilityLabel = t('symptomChecker:a11y:label'),
32 | accessibilityHint = t('symptomChecker:a11y:hint'),
33 | ...props
34 | }) => (
35 | openBrowserAsync(link!)}
37 | accessibilityRole="link"
38 | accessibilityLabel={accessibilityLabel}
39 | accessibilityHint={accessibilityHint}
40 | {...props}>
41 |
42 |
43 |
49 |
50 | {markdown}
51 |
52 |
53 |
54 |
55 | );
56 |
57 | const markdownStyles = StyleSheet.create({
58 | text: {
59 | ...text.smallerParagraph,
60 | color: colors.darkerPurple
61 | },
62 | // @ts-ignore
63 | strong: {
64 | ...text.h4Heading,
65 | color: colors.primaryPurple
66 | },
67 | block: {
68 | margin: 0
69 | }
70 | });
71 |
72 | const styles = StyleSheet.create({
73 | container: {
74 | borderColor: colors.lighterPurple,
75 | backgroundColor: colors.lighterPurple,
76 | alignItems: 'center',
77 | flexDirection: 'row',
78 | width: 'auto',
79 | paddingHorizontal: 20,
80 | paddingVertical: 0
81 | },
82 | symptomMessage: {
83 | paddingVertical: 20,
84 | marginLeft: 15
85 | }
86 | });
87 |
88 | export const Message = withTranslation()(MessageBase);
89 |
--------------------------------------------------------------------------------
/components/molecules/action-card.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {
3 | StyleSheet,
4 | View,
5 | ViewStyle,
6 | Image,
7 | TouchableWithoutFeedback,
8 | AccessibilityProps
9 | } from 'react-native';
10 |
11 | import Text from '../atoms/text';
12 | import Container from '../atoms/container';
13 | import {text, colors} from '../../theme';
14 | import {openBrowserAsync} from '../../utils/web-browser';
15 |
16 | const IconNote = require('../../assets/images/icon-note/image.png');
17 | const IconNoteYellow = require('../../assets/images/icon-note-yellow/image.png');
18 |
19 | interface CardProps extends AccessibilityProps {
20 | style?: ViewStyle;
21 | content: string;
22 | link: string;
23 | inverted?: boolean;
24 | }
25 |
26 | const ActionCard: FC = ({
27 | style,
28 | content,
29 | link,
30 | inverted = false,
31 | ...props
32 | }) => {
33 | return (
34 | openBrowserAsync(link)}
36 | accessibilityRole="link"
37 | {...props}>
38 |
39 |
40 |
47 |
48 |
49 |
50 | {content}
51 |
52 |
53 |
54 |
55 | );
56 | };
57 |
58 | const styles = StyleSheet.create({
59 | inverted: {
60 | color: colors.darkGrey,
61 | borderColor: colors.darkGrey,
62 | fontFamily: text.fontFamily.latoBold
63 | },
64 | invertedBg: {backgroundColor: colors.darkGrey},
65 | container: {
66 | flexDirection: 'row',
67 | borderWidth: 1,
68 | borderStyle: 'solid',
69 | borderColor: colors.darkGrey,
70 | borderRadius: 10
71 | },
72 | left: {
73 | backgroundColor: colors.darkGrey,
74 | justifyContent: 'center',
75 | paddingVertical: 31,
76 | paddingLeft: 30,
77 | paddingRight: 24,
78 | borderBottomLeftRadius: 10,
79 | borderTopLeftRadius: 10
80 | },
81 | note: {
82 | alignSelf: 'center'
83 | },
84 | text: {
85 | paddingLeft: 20,
86 | paddingVertical: 20,
87 | paddingRight: 30
88 | }
89 | });
90 |
91 | export default ActionCard;
92 |
--------------------------------------------------------------------------------
/components/organisms/modals/exposure-notifications.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {useTranslation} from 'react-i18next';
3 | import {Platform, StyleSheet} from 'react-native';
4 | import {
5 | useExposure,
6 | StatusState,
7 | AuthorisedStatus
8 | } from 'react-native-exposure-notification-service';
9 |
10 | import Markdown from '../../atoms/markdown';
11 | import Modal, {ModalProps} from '../../molecules/modal';
12 | import {text, colors} from '../../../theme';
13 | import {goToSettingsAction} from '../../molecules/go-to-settings';
14 | import {ScrollView} from 'react-native-gesture-handler';
15 |
16 | export const ExposureNotificationsModal: FC = (props) => {
17 | const {t} = useTranslation();
18 | const {status, askPermissions, isAuthorised} = useExposure();
19 | const ensUnknown = status.state === StatusState.unknown;
20 | const ensDisabled = status.state === StatusState.disabled;
21 | const notAuthorised = isAuthorised === AuthorisedStatus.unknown;
22 |
23 | return (
24 | await askPermissions(),
34 | hint: t('common:turnOnBtnHint'),
35 | label: t('common:turnOnBtnLabel')
36 | }
37 | ]
38 | : [
39 | {
40 | variant: 'inverted',
41 | action: () => goToSettingsAction(false, askPermissions),
42 | hint: ensDisabled
43 | ? t('common:turnOnBtnHint')
44 | : Platform.OS === 'android'
45 | ? t('common:turnOnBtnHint')
46 | : t('common:goToSettingsHint'),
47 | label: ensDisabled
48 | ? t('common:turnOnBtnLabel')
49 | : Platform.OS === 'android'
50 | ? t('common:turnOnBtnLabel')
51 | : t('common:goToSettings')
52 | }
53 | ]
54 | }>
55 |
56 |
57 | {ensUnknown || notAuthorised
58 | ? t('modals:exposureNotifications:turnOn')
59 | : t(`modals:exposureNotifications:instructions${Platform.OS}`)}
60 |
61 |
62 |
63 | );
64 | };
65 |
66 | const modalMarkdownStyles = StyleSheet.create({
67 | text: {
68 | ...text.default,
69 | color: colors.white
70 | },
71 | listItemNumber: {
72 | color: colors.white
73 | }
74 | });
75 |
--------------------------------------------------------------------------------
/services/api/exposures.ts:
--------------------------------------------------------------------------------
1 | import {
2 | digestStringAsync,
3 | CryptoDigestAlgorithm,
4 | CryptoEncoding
5 | } from 'expo-crypto';
6 |
7 | import {verify} from '.';
8 | import {request} from './utils';
9 |
10 | import {urls} from '../../constants/urls';
11 |
12 | export enum ValidationResult {
13 | NetworkError,
14 | Error,
15 | Invalid,
16 | Expired,
17 | Valid
18 | }
19 |
20 | interface ValidateCodeResponse {
21 | token?: string;
22 | result: ValidationResult;
23 | }
24 |
25 | export const validateCode = async (
26 | code: string
27 | ): Promise => {
28 | const controlHash = await digestStringAsync(
29 | CryptoDigestAlgorithm.SHA512,
30 | code.substr(0, 3),
31 | {encoding: CryptoEncoding.HEX}
32 | );
33 | const codeHash = await digestStringAsync(CryptoDigestAlgorithm.SHA512, code, {
34 | encoding: CryptoEncoding.HEX
35 | });
36 |
37 | const hash = `${controlHash}${codeHash}`;
38 |
39 | try {
40 | const resp = await request(`${urls.api}/exposures/verify`, {
41 | authorizationHeaders: true,
42 | method: 'POST',
43 | mode: 'cors',
44 | headers: {
45 | 'Content-Type': 'application/json'
46 | },
47 | body: JSON.stringify({hash})
48 | });
49 |
50 | if (!resp) {
51 | throw new Error('Invalid response');
52 | }
53 | const responseData = await resp.json();
54 |
55 | return {
56 | result: ValidationResult.Valid,
57 | token: responseData.token
58 | };
59 | } catch (err) {
60 | console.log('Code validation error: ', err, err.message);
61 |
62 | if (err.message && err.message === 'Network Unavailable') {
63 | return {result: ValidationResult.NetworkError};
64 | }
65 |
66 | if (err.status === 410) {
67 | return {result: ValidationResult.Expired};
68 | } else if (err.status >= 400 && err.status <= 499) {
69 | return {result: ValidationResult.Invalid};
70 | }
71 |
72 | return {
73 | result: ValidationResult.Error
74 | };
75 | }
76 | };
77 |
78 | export const uploadExposureKeys = async (
79 | uploadToken: string,
80 | exposures: any[]
81 | ): Promise => {
82 | const resp = await request(`${urls.api}/exposures`, {
83 | authorizationHeaders: true,
84 | method: 'POST',
85 | mode: 'cors',
86 | headers: {
87 | 'Content-Type': 'application/json'
88 | },
89 | body: JSON.stringify({
90 | token: uploadToken,
91 | exposures,
92 | ...(await verify(uploadToken))
93 | })
94 | });
95 |
96 | if (!resp || resp.status !== 204) {
97 | throw new Error('Upload failed');
98 | }
99 | };
100 |
--------------------------------------------------------------------------------
/components/molecules/go-to-settings.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {Linking, Platform} from 'react-native';
3 | import * as IntentLauncher from 'expo-intent-launcher';
4 | import {
5 | useExposure,
6 | StatusState,
7 | StatusType,
8 | AuthorisedStatus
9 | } from 'react-native-exposure-notification-service';
10 |
11 | import Button from '../atoms/button';
12 | import {useTranslation} from 'react-i18next';
13 |
14 | export const goToSettingsAction = async (
15 | bluetoothDisabled?: boolean,
16 | askPermissions?: () => Promise
17 | ) => {
18 | try {
19 | if (Platform.OS === 'ios') {
20 | Linking.openSettings();
21 | } else {
22 | bluetoothDisabled
23 | ? await IntentLauncher.startActivityAsync(
24 | IntentLauncher.ACTION_SETTINGS
25 | )
26 | : await askPermissions!();
27 | }
28 | } catch (err) {
29 | console.log('Error handling go to settings', err);
30 | }
31 | };
32 |
33 | const GoToSettings: FC = () => {
34 | const {t} = useTranslation();
35 | const {status, askPermissions, isAuthorised} = useExposure();
36 | const platform = Platform.OS === 'ios' ? 'ios' : 'android';
37 |
38 | const bluetoothDisabled =
39 | status.state === StatusState.disabled &&
40 | status.type?.includes(StatusType.bluetooth);
41 |
42 | const ensUnknown = status.state === StatusState.unknown;
43 | const ensDisabled = status.state === StatusState.disabled;
44 | const notAuthorised = isAuthorised === AuthorisedStatus.unknown;
45 |
46 | return (
47 |
81 | );
82 | };
83 |
84 | export default GoToSettings;
85 |
--------------------------------------------------------------------------------
/components/views/calculator.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {ScrollView, StyleSheet, View, Text} from 'react-native';
3 | import {useSafeArea} from 'react-native-safe-area-context';
4 | import {useTranslation} from 'react-i18next';
5 | import {StackNavigationProp} from '@react-navigation/stack';
6 |
7 | import Spacing from '../atoms/spacing';
8 | import {ModalHeader} from '../molecules/modal-header';
9 | import {SPACING_BOTTOM} from '../../theme/layouts/shared';
10 | import Illustration from '../atoms/illustration';
11 | import Markdown from '../atoms/markdown';
12 | import {PADDING_TOP, text, colors} from '../../theme';
13 | import {useNavigation} from '@react-navigation/native';
14 |
15 | const CalculatorIllustration = require('../../assets/images/calculator-illustration/image.png');
16 |
17 | interface CalculatorModalProps {
18 | navigation: StackNavigationProp;
19 | }
20 |
21 | export const CalculatorModal: FC = () => {
22 | const {t} = useTranslation();
23 | const insets = useSafeArea();
24 | const navigation = useNavigation>();
25 |
26 | return (
27 |
34 | navigation.goBack()}
38 | />
39 |
40 |
46 |
47 | {t('calculator:body')}
48 |
49 |
50 | {t('calculator:highlight')}
51 |
52 |
53 |
54 | );
55 | };
56 |
57 | const markdownStyles = StyleSheet.create({
58 | text: {
59 | ...text.paragraph,
60 | color: colors.darkerPurple
61 | },
62 | // @ts-ignore
63 | strong: {
64 | ...text.h4Heading,
65 | color: colors.darkerPurple
66 | }
67 | });
68 |
69 | const styles = StyleSheet.create({
70 | container: {
71 | flex: 1
72 | },
73 | contentContainer: {
74 | flexGrow: 1,
75 | paddingTop: PADDING_TOP,
76 | paddingLeft: 45,
77 | paddingRight: 45
78 | },
79 | top: {flex: 1},
80 | highlight: {
81 | ...text.h3Heading,
82 | color: colors.amber
83 | }
84 | });
85 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 |
24 | # Android/IntelliJ
25 | #
26 | build/
27 | .idea
28 | .gradle
29 | local.properties
30 | *.iml
31 | android/app/release/
32 |
33 | # Visual Studio Code
34 | #
35 | .vscode/
36 |
37 | # node.js
38 | #
39 | node_modules/
40 | npm-debug.log
41 | yarn-error.log
42 |
43 | # BUCK
44 | buck-out/
45 | \.buckd/
46 | *.keystore
47 | !debug.keystore
48 |
49 | # fastlane
50 | #
51 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
52 | # screenshots whenever they are needed.
53 | # For more information about the recommended setup visit:
54 | # https://docs.fastlane.tools/best-practices/source-control/
55 |
56 | */fastlane/report.xml
57 | */fastlane/Preview.html
58 | */fastlane/screenshots
59 |
60 | # Bundle artifact
61 | *.jsbundle
62 |
63 | # CocoaPods
64 | /ios/Pods/
65 |
66 | # dotenv environment variables file
67 | .env
68 |
69 | # Lighthouse
70 | lighthouse-report.html
71 |
72 | # Mac attributes
73 | .DS_Store
74 |
75 | # NPM configuration file with personal access tokens
76 | .npmrc
77 |
78 | # Frontend build
79 | build
80 |
81 | # Editors
82 | *.sublime*
83 | .vscode
84 |
85 | # Misc
86 | *.zip
87 |
88 | # Xcode
89 | ## User settings
90 | xcuserdata/
91 |
92 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
93 | *.xcscmblueprint
94 | *.xccheckout
95 |
96 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
97 | build/
98 | DerivedData/
99 | *.moved-aside
100 | *.pbxuser
101 | !default.pbxuser
102 | *.mode1v3
103 | !default.mode1v3
104 | *.mode2v3
105 | !default.mode2v3
106 | *.perspectivev3
107 | !default.perspectivev3
108 |
109 | ## Xcode Patch
110 | *.xcodeproj/*
111 | !*.xcodeproj/project.pbxproj
112 | !*.xcodeproj/xcshareddata/
113 | !*.xcworkspace/contents.xcworkspacedata
114 | /*.gcno
115 |
116 | ## Android
117 | .idea
118 | .gradle
119 | local.properties
120 | *.iml
121 | .settings
122 | .classpath
123 | .project
124 | .github/secrets/
125 |
126 | # fastlane specific
127 | fastlane/report.xml
128 |
129 | # fastlane environment
130 | ios/.env.default
131 | android/.env.default
132 |
133 | # deliver temporary files
134 | fastlane/Preview.html
135 |
136 | # snapshot generated screenshots
137 | fastlane/screenshots
138 |
139 | # scan temporary files
140 | fastlane/test_output
141 |
142 | # misc
143 | /.eslintcache
144 |
--------------------------------------------------------------------------------
/components/views/tests.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, ScrollView, Image, Platform} from 'react-native';
3 | import {useSafeAreaInsets} from 'react-native-safe-area-context';
4 | import {useTranslation} from 'react-i18next';
5 | import {StackNavigationProp} from '@react-navigation/stack';
6 |
7 | import Text from '../atoms/text';
8 | import Button from '../atoms/button';
9 | import Spacing from '../atoms/spacing';
10 | import {ModalHeader} from '../molecules/modal-header';
11 | import {SPACING_BOTTOM, SPACING_HORIZONTAL} from '../../theme/layouts/shared';
12 | import {ScreenNames} from '../../navigation';
13 | import {ArrowLink} from '../molecules/arrow-link';
14 | import {openBrowserAsync} from '../../utils/web-browser';
15 |
16 | const JarIcon = require('../../assets/images/icon-jar/image.png');
17 | const Illustration = require('../../assets/images/test-illustration/image.png');
18 | const IconPlus = require('../../assets/images/icon-plus/image.png');
19 |
20 | interface TestsProps {
21 | navigation: StackNavigationProp;
22 | }
23 |
24 | export const Tests: FC = ({navigation}) => {
25 | const {t} = useTranslation();
26 | const insets = useSafeAreaInsets();
27 |
28 | const handleAddTestResult = () => navigation.navigate(ScreenNames.testsAdd);
29 |
30 | return (
31 |
36 |
37 |
38 |
43 |
44 |
45 | {t('tests:content')}
46 |
47 |
48 |
55 |
56 |
62 |
63 |
67 |
68 | {t('tests:view:tellMore')}
69 |
70 |
71 |
72 |
73 | );
74 | };
75 |
76 | const styles = StyleSheet.create({
77 | logo: {alignSelf: 'center'},
78 | contentContainer: {
79 | flexGrow: 1,
80 | paddingTop: Platform.OS === 'ios' ? 65 : 30,
81 | paddingHorizontal: SPACING_HORIZONTAL
82 | }
83 | });
84 |
--------------------------------------------------------------------------------
/components/views/onboarding/permissions-info.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC, useState} from 'react';
2 | import {Image, StyleSheet} from 'react-native';
3 | import {useTranslation} from 'react-i18next';
4 | import {StackNavigationProp} from '@react-navigation/stack';
5 | import {useExposure} from 'react-native-exposure-notification-service';
6 | import * as SecureStore from 'expo-secure-store';
7 |
8 | import Button from '../../atoms/button';
9 | import Spacing from '../../atoms/spacing';
10 | import Markdown from '../../atoms/markdown';
11 | import {ScreenNames} from '../../../navigation';
12 | import {useSettings} from '../../../providers/settings';
13 | import {useApplication} from '../../../providers/context';
14 | import Container from '../../atoms/container';
15 | import Text from '../../atoms/text';
16 | import {text, colors} from '../../../theme';
17 |
18 | const IllustrationSource = require('../../../assets/images/permissions-illustration/image.png');
19 |
20 | interface PermissionInfoProps {
21 | navigation: StackNavigationProp;
22 | }
23 |
24 | const PermissionsInfo: FC = ({navigation}) => {
25 | const {t} = useTranslation();
26 | const {reload} = useSettings();
27 | const [disabled, setDisabled] = useState(false);
28 | const {askPermissions} = useExposure();
29 | const application = useApplication();
30 |
31 | const handlePermissions = async () => {
32 | setDisabled(true);
33 | SecureStore.setItemAsync('analyticsConsent', String(true), {});
34 | try {
35 | await askPermissions();
36 | reload();
37 | await application.setContext({completedExposureOnboarding: true});
38 |
39 | setTimeout(
40 | () =>
41 | navigation.reset({
42 | index: 0,
43 | routes: [{name: ScreenNames.dashboard}]
44 | }),
45 | 1000
46 | );
47 | } catch (e) {
48 | setDisabled(false);
49 | console.log("Error opening app's settings", e);
50 | }
51 | };
52 |
53 | return (
54 | <>
55 |
56 |
57 |
61 |
62 |
63 |
64 | {t('onboarding:permissionsInfo:view:title')}
65 |
66 |
67 |
68 | {t('onboarding:permissionsInfo:view:text')}
69 |
70 |
71 |
72 |
78 |
79 | >
80 | );
81 | };
82 |
83 | const markdownStyles = StyleSheet.create({
84 | text: {
85 | ...text.default,
86 | color: colors.white
87 | }
88 | });
89 |
90 | export default PermissionsInfo;
91 |
--------------------------------------------------------------------------------
/providers/reminder.tsx:
--------------------------------------------------------------------------------
1 | import React, {createContext, useContext, useEffect, useState} from 'react';
2 | import AsyncStorage from '@react-native-community/async-storage';
3 | import {useTranslation} from 'react-i18next';
4 | import PushNotification from 'react-native-push-notification';
5 | import {addDays} from 'date-fns';
6 | import {
7 | StatusState, useExposure
8 | } from 'react-native-exposure-notification-service';
9 |
10 | interface State {
11 | paused: string | null;
12 | checked: boolean;
13 | }
14 |
15 | interface ReminderContextValue extends State {
16 | setReminder: (date: Date) => void;
17 | deleteReminder: () => void;
18 | cancelReminder: () => void;
19 | }
20 |
21 | const initialState = {
22 | paused: null,
23 | checked: false
24 | };
25 |
26 | export const ReminderContext = createContext(
27 | initialState as ReminderContextValue
28 | );
29 |
30 | export interface API {
31 | children: any;
32 | }
33 |
34 | const REMINDER_KEY = 'ni.reminder';
35 | const REMINDER_ID = 12345;
36 |
37 | export const Provider = ({children}: API) => {
38 | const [state, setState] = useState(initialState);
39 | const {t} = useTranslation();
40 | const exposure = useExposure();
41 |
42 | useEffect(() => {
43 | const checkRunning = async () => {
44 | AsyncStorage.getItem(REMINDER_KEY).then((paused) => {
45 | setState({
46 | paused: paused && exposure.status.state !== StatusState.active ? paused : null,
47 | checked: true
48 | })
49 | });
50 | };
51 |
52 | checkRunning();
53 | }, [exposure.status.state]);
54 |
55 | const cancelReminder = () =>
56 | PushNotification.cancelLocalNotifications({id: String(REMINDER_ID)});
57 |
58 | const deleteReminder = () => {
59 | PushNotification.cancelLocalNotifications({id: String(REMINDER_ID)});
60 | AsyncStorage.removeItem(REMINDER_KEY);
61 | setState({
62 | ...state,
63 | paused: null
64 | });
65 | };
66 |
67 | const setReminder = (date: Date) => {
68 | const currentDate = new Date();
69 | const notificationDate = date < currentDate ? addDays(date, 1) : date;
70 | const timestamp = String(notificationDate.getTime());
71 | AsyncStorage.setItem(REMINDER_KEY, timestamp);
72 |
73 | PushNotification.localNotificationSchedule({
74 | channelId: 'default',
75 | id: REMINDER_ID,
76 | title: t('reminder:title'),
77 | message: t('reminder:message'),
78 | date: notificationDate,
79 | repeatType: 'hour',
80 | // @ts-ignore
81 | allowWhileIdle: true
82 | });
83 |
84 | setState({
85 | ...state,
86 | paused: timestamp
87 | });
88 | };
89 |
90 | const value: ReminderContextValue = {
91 | ...state,
92 | setReminder,
93 | deleteReminder,
94 | cancelReminder
95 | };
96 |
97 | return (
98 |
99 | {children}
100 |
101 | );
102 | };
103 |
104 | export const ReminderProvider = Provider;
105 |
106 | export const useReminder = () => useContext(ReminderContext);
107 |
--------------------------------------------------------------------------------
/components/molecules/arrow-link.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {
3 | AccessibilityProps,
4 | Image,
5 | StyleSheet,
6 | Text,
7 | View,
8 | ViewStyle,
9 | TextStyle,
10 | TouchableWithoutFeedback,
11 | ImageSourcePropType
12 | } from 'react-native';
13 |
14 | import {openBrowserAsync} from '../../utils/web-browser';
15 | import {colors} from '../../theme';
16 | import {ScreenNames} from '../../navigation';
17 | const ArrowIcon = require('../../assets/images/icon-arrow/image.png');
18 | const ArrowIconPurple = require('../../assets/images/icon-arrow-purple/image.png');
19 | const ExternalLinkIcon = require('../../assets/images/icon-external-link/image.png');
20 | const ExternalLinkIconLight = require('../../assets/images/icon-external-link-light/image.png');
21 |
22 | interface ArrowLinkProps extends AccessibilityProps {
23 | navigation?: any;
24 | screen?: ScreenNames;
25 | externalLink?: string;
26 | containerStyle?: ViewStyle;
27 | textStyle?: TextStyle;
28 | invert?: boolean;
29 | fullWidth?: boolean;
30 | onPress?: () => void;
31 | icon?: ImageSourcePropType;
32 | }
33 |
34 | export const ArrowLink: FC = ({
35 | navigation,
36 | screen,
37 | onPress,
38 | externalLink,
39 | accessibilityLabel,
40 | accessibilityHint,
41 | containerStyle = {},
42 | textStyle = {},
43 | invert,
44 | fullWidth = !!externalLink,
45 | children,
46 | icon,
47 | ...props
48 | }) => {
49 | const handlePress = () => {
50 | if (screen && navigation) {
51 | return navigation.navigate(screen);
52 | }
53 | if (externalLink) {
54 | return openBrowserAsync(externalLink);
55 | }
56 | };
57 | return (
58 |
64 |
65 |
67 | {children || (
68 | {accessibilityLabel}
69 | )}
70 |
71 |
85 |
86 |
87 | );
88 | };
89 |
90 | const styles = StyleSheet.create({
91 | linkContainer: {
92 | flexDirection: 'row',
93 | alignItems: 'center'
94 | },
95 | inline: {maxWidth: '80%'},
96 | fullWidth: {flex: 1},
97 | text: {
98 | textAlign: 'left',
99 | justifyContent: 'flex-start',
100 | color: colors.darkGrey
101 | },
102 | icon: {marginLeft: 10}
103 | });
104 |
--------------------------------------------------------------------------------
/ios/ProtectScotland.xcodeproj/xcshareddata/xcschemes/ProtectScotland.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------