Sprint 9 - 31 August 2023 Build (#788)
* Removed async at downloadModal in auth.ts
* Removed debug.keystore file
* fix(INJI-187) : [Vijay|Alka] Fixed Purple Theme Related Bugs and Duplicate Permission popup issue.
* fix(INJI-187) : [Vijay] fix about inji documentation page redirection
* Fixes in ui-revamp-release
* fix:vcsharing and wallet binding
* Removed key names version, tuvali-version in locals of AboutInji obj.
* feat(INJI-172): display error popup to restrict vc share when audit entry is not possible
audit entry cannot be made when the device remaining storage has reached the minimumStorageRequiredForAuditEntryInMB
Issue Link https://mosip.atlassian.net/browse/INJI-172
* Reverted lst commit and removed version number in locals
* fix:vcsharing and wallet binding
* removing logger
* fix(INJI-187) : [Vijay] fix welcome screen auth issue, hide the inji tour guide option and fix the tuvali version in about inji
* fix(INJI-92): [Bhargavi] show proper error message in the UI for the deactivated UIN & VID
Issue Link https://mosip.atlassian.net/browse/INJI-92
* fix(INJI-187) : [Vijay] add missing literals in hindi
* feat[#190]:[Pooja] fix back button on incoming VC page to show QR when clicked
* refator(INJI-172): [Kiruthika] rename the config key for storage limit to minimumStorageRequiredInMB
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] rename translation path of storage limit reached error shown while adding / receiving VC
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] rename storage limit reached for making audit entry variable
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] remove unused context storeError in vcItem machine
Issue Link https://mosip.atlassian.net/browse/INJI-172
* fix:logout crash
* feat(#162): [Tilak|Pooja] Create Short UUID using npm lib and display it in about page
* [Release 03-07-2023]fix:app crash on logout and remove checkbox and kebab on vc while sharing
* feat(#162): [Tilak|Pooja] Update app id ux and use alphanum_upper of length 12 for uuid
* feat(#162): [Tilak|Pooja] Add copy button for app id
* feat(#162): [Tilak|Pooja] Update app id when settings context is present in db but not app id
* feat[#162]:[Pooja] add translations for app ID
* feat[#162]:[Pooja] add translations for copy button
* [Release 03-07-2023]add:loader while saving credential registry
* [Release 03-07-2023]fix:saving credentialRegistry
* fix(INJI-206): [Vijay] fix mmkv storage issue, environment url change persistance and literal change
* fix(INJI-206): [Vijay] add comment on the getFileName method
* Adjusted splash-screen & updated locals
* Cleared existing develop changes in PR
* Cleared comments mentioned in locals
* refator(INJI-172): [Kiruthika] modify storage limit reached error message while adding or receiving card
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] add storage limit reached error message in spanish locale
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] move storage limit reached check function to storage class
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] add missing storage limit reached error message in strings.json file
Issue Link https://mosip.atlassian.net/browse/INJI-172
* fix(INJI-206): [Vijay] remove vc from RNFS when vc metadata is removed from MMKV
* refator(INJI-172): [Kiruthika] extract service and action
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] remove MB from min storage limit property name
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] extract function for displayng storage limit reached error
Issue Link https://mosip.atlassian.net/browse/INJI-172
* fix(INJI-172): [Kiruthika] show storage limit popup on minimum storage limit reached criteria when bluetooth is off
Issue Link https://mosip.atlassian.net/browse/INJI-172
* Test check
* refator(INJI-172): [Kiruthika] rename the config key of storage limit
Issue Link https://mosip.atlassian.net/browse/INJI-172
* Calculate HMAC and store Encrypted HMAC in Database
* Revert Test Check
* fix(INJI-212): [Vijay] fix qrlogin success popup redirection to history issue and vc sharing in progress screen issue
* Change error pop up text in my vc's tab for tampered data
* Revert english json changes
* refator(INJI-172): [Kiruthika] extract service and action
Issue Link https://mosip.atlassian.net/browse/INJI-172
* refator(INJI-172): [Kiruthika] replace equality check of boolean with type conversion
Issue Link https://mosip.atlassian.net/browse/INJI-172
* Add encoding for decryption of HMAC
* [Release 03-07-2023]fix:sharing timeout message displaying always
* feat(#162): [Tilak|Pooja] remove unnecessary style from purple
* [Release 03-07-2023]fix:sharing timeout message displaying always
* [Release 03-07-2023]fix:navigation to history tab after successfully receiving VC
* [Release 03-07-2023]fix:navigation to history tab after successfully receiving VC
* [Release 03-07-2023]fix:navigation to history tab after successfully receiving VC
* refator(INJI-182): [Kiruthika] send app id as X-AppId in header in the API requests
Issue Link https://mosip.atlassian.net/browse/INJI-182
* fix(INJI-210): [Bhargavi] show the home screen after closing the success status overlay
Issue Link https://mosip.atlassian.net/browse/INJI-210
* feat(#162): [Tilak|Pooja] extract app id constants.
* refator(INJI-182): [Kiruthika] send app id in header only for the residentmobileapp API requests
Issue Link https://mosip.atlassian.net/browse/INJI-182
* feat(#INJI-178) [Adityan] calculate and store encrypted HMAC hash of vc's metadata in database
* feat(#INJI-178) [Adityan] calculate and store encrypted HMAC hash of vc's metadata in database and fix
* feat(#INJI-173) [Adityan] Added a beta release workflow when tagged
* Refactor the code and remove unused params
* Refactor the code and remove unused parameters
* feat(#162): [Tilak|Pooja] fix merge issue in hindi and format app id dictionary
* Refactor the code and remove debug logs
* feat(#162): [Tilak|Pooja] remove unused parameters in settings.ts
* feat(INJI-149): add a popup when keychain fails to get password
Reason: when keychain.getGenericPassword errors due to a false/falsy response,
the state machine goes ahead and clears the MMKV store and the VC
directory as without the key the encrypted data is not meaningful,
it may so happen that the keychain/keystore is not unlocked yet as
most modern mobile OSes can choose to lock access to it when the phone
is locked
Fix: earlier the state machine would go and clear the datastores without
user intervention, this fix will give the user a prompt if encrypted
VCs exist on app-data and allow user to try reading the keychain once
again before silently deleting everything
Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Co-authored-by: Alka <prasadalka1998@gmail.com>
* feat(INJI-149): add DualMessageOverlay component
details about the component:
- has two buttons tryAgain & cancel each occupying half the space in the
row
- kludge: uses similar styling for both themes
- TODO: override the width styles in-place instead
- this component should not be used for production as this is strictly
temporary for narrowing down in on bugs
Other changes:
- removed additional button from original MessageOverlay component
* fix(INJI-149): remove unavailable action from store.ts
* chore: add missed out Podfile.lock changes
* feat(INJI-149): remove extra button component of half width
* feat(INJI-149): make DualMessageOverlay button gradient type
Co-authored-by: <vijay@Vijays-MacBook-Pro.local>
* chore: add check for Verifiable document store init
other changes:
- add Podfile.lock
- remove debug logs
* chore: bump up the tuvali version to v0.4.2 for release 18-07-2023
* fix: remove double quotes to the margin top property in send vc screen
* feat(#162): [Tilak] fix ios logout crash by navigating on timeout
* feat(#162): [Tilak] fix ios logout crash by navigating on timeout
* fix(INJI-178): check for tampered VC without considering pinned state
Issue Link https://mosip.atlassian.net/browse/INJI-178
* refactor: [Kiruthika | Dhivya] fix type warnings
* fix(INJI-223): show the camera in scan screen while sharing the VC and click on scan icon
Issue Link https://mosip.atlassian.net/browse/INJI-223
* fix version code error for internal build workflow (#761)
* chore: update pod deps' to match development team of 1st project
* feat(inji-214): [Dhivya|Tilak] integrate the secure store
* feat[#211]:[Pooja] fix turncated passcode and confirm password button
* feat[#211]:[Pooja] fix truncated histroy title text in iOS
* feat(inji-214): [Dhivya|Tilak] conditional check added for platform
* feat(inji-214): [Dhivya] modified state machine for generating keypair
* feat[#211]:[Pooja] fix multiple error being displayed when the vc binding fails
* fix(INJI-223): disconnect the device while sharing the VC and click on tab icons except scan icon
Issue Link https://mosip.atlassian.net/browse/INJI-223
* feat[#211]:[Pooja] fix download card button styles
* feat(inji-214): [Dhivya|Tilak] add logstate for vcitem state machine
(cherry picked from commit 7001679cdd6f46dfc5a60474f30284292e69b888)
* version code for beta build in pipeline
* feat(inji-214): [Dhivya|Tilak] use Secure key store to sign jwt for auth
* feat[#211]:[Pooja] add error message when VC activation fails in kebab pop up
* chore(INJI-216): bump up tuvali version to v0.4.3
* feat[#225]:[Pooja] fix about inji url in about page
* chore(INJI-216): bump up tuvali version to v0.4.3
* chore(INJI-216): update podlock file with the correct tuvali version
* feat(inji-214): [Dhivya|Tilak] use sdk hmac method to create hmac for vc key
* feat(inji-214): [Tilak|Dhivya] refactor hmac functionality
* feat(inji-214): [Dhivya|Tilak] modify generatehmac function definition
* refactor(INJI-223): get the scan string from route config to keep it consistent
Issue Link https://mosip.atlassian.net/browse/INJI-223
* feat[mosip#211]:[Pooja] refactor onCancel
Co-authored-by: Harsh Vardhan <harsh59v@gmail.com>
* feat(inji-175): show warning message to user on android hardware keystore
* feat(inji-175): refactor the files
* feat(inji-214): [Dhivya|Tilak] use sdk to create signature
* feat:(inji-175) show warning message when device keystore not supports
* fix(inji-175): resolve conflicts
* feat(inji-175): locales changes for hardware keystore not exists warning text
* feat(INJI-222): add popup for error in decryption
* feat(INJI-222): wrap app init component & popups
* feat(INJI-222): propagate event from _store to app state machine
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
* feat(inji-175): modify arabic title locale
* chore(INJI-222): move error msg text to errors obj
* feat(inji-175): update mosip package name
* Implemented Receive Card & Received Cards options in Settings
* Fixed all the locals
* fix(inji-175): modify variable name and refactor existing code
* [INJI-69]fix:The mobile camera is not opening on the scan page when the flight mode is turned
* [INJI-69]fix:The mobile camera is not opening on the scan page when the flight mode is turned
* [INJI-69]fix:The mobile camera is not opening on the scan page when the flight mode is turned
* [Inji-248]fix:The audit for deleting the VC is not logged in the history
* fix:naming conventions, removed log and values in locals
* Update .project
* Initial commit 07-08-2023
* [INJI-249]fix:Back button from the ellipsis page not working on the mobile
* Inplemented INJI Tour Guide in settings
* Set navigation from auth to home screen
* feat(inji-214): [Dhivya|Tilak] Update encryption and decryption to call SecureKeystore sdk with biometric auth enabled
* Resolved the comments
* Updated 'Get Started' button text in hindi locals
* feat(INJI-238): handling errors when invalidate keys of biometric
* feat(INJI-238): add reset keys action
* fix(INJI-149): skip showing read-error popup on launch
* feat(inji-238): fetch enabled device biometric from sdk
* chore: disallow expansion of received cards
* feat(inji-214): [Dhivya|Tilak] fix app events RESET_KEY_INVALIDATE_ERROR_DISMISS not accessible issue
* feat(inji-214): [Dhivya|Tilak] fix generate key pair failing due to wrong count of arguments
* fix(INJI-192): add error message translations for HMAC calculation
* feat(inji-214): [Dhivya|Tilak] Update biometric popup text
* feat(inji-238): translations added for biometric text
* feat(inji-214): [Dhivya|Tilak] fix language not getting updated for auth popup
* fix(INJI-286):Show VC detailed view in the Received Vc screen
* fix(INJI-286):Show VC detailed view in the Received Vc screen
* fix(INJI-285): Added the flip camera buton in the scan screen
* fix(INJI-262):pinned VC's audit logs are missing
* fix(INJI-262):pinned VC's audit logs are missing
* fix(INJI-214): secure-keystore version changes
* fix(INJI-214): fixed Podfile.lock merge issue
* refactor(INJI-214): refactor the code
* fix(INJI-262):pinned VC's audit logs are missing
* fix(INJI-211[1]): improve isPinned evaluation of (un)pinned VCs (#102)
* fix(INJI-211[1]): Pin/unpin card not working intermittently
* fix(INJI-263):camera is not opening when vc is pinned
* fix(INJI-262):pinned VC's audit logs are missing
* fix(INJI-262):pinned VC's audit logs are missing
* [INJI-69]fix:The mobile camera is not opening on the scan page when the flight mode is turned
* feat(inji-238): handle key not found error after key invalidation
* feat(inji-238): reinit app machine on dismiss of invalidation popup
* fix(INJI-262):pinned VC's audit logs are missing
* fix(INJI-263):camera is not opening when vc is pinned
* feat(INJI-255): hash the passcode and store in mmkv
* feat(inji-238): use a dummy key to request biometric auth everytime user opens the app
* feat(inji-238): revert tamperedErrorMessageString value
* feat(inji-293): use jetify to fix react-native/location bundle issue
* feat(inji-293): fix jetify running location
* Inji 282 disable camera error (#775)
* fix(INJI-282): Correct error message will be displayed when camera is disabled
* fix(INJI-260):app not aligned properly with the smaller display screen (#778)
* Fixed tab elements which are still in english (#779)
* feat(INJI-202): hash uin/vid to store in mmkv and file storage (#780)
* feat(INJI-202): hash uin/vid to store in mmkv and file storage
* feat(INJI-202): refactor to store salt in constants
* feat(INJI-202): refactor argon2i salt and add function to get MMKV data
* feat(INJI-202): refactor to get mkkv data method
---------
Co-authored-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>
* fix(inji-253): set thumbprint on wallet binding for e-signet login
* fix(INJI-296): label mismatch in language files (#772)
* fix(INJI-262):pinned VC's audit logs are missing
* fix(INJI-286): expand received card popup on click (#783)
Revert "chore: disallow expansion of received cards"
This reverts commit 038b6e4259.
* chore(INJI-304): bump up secure keystore version to v0.1.1
* chore(INJI-304): bump up tuvali version to v0.4.4
* Inji 304 update tuvali and secure keystore version (#784)
* chore(INJI-304): bump up secure keystore version to v0.1.1
* chore(INJI-304): bump up tuvali version to v0.4.4
---------
Co-authored-by: dhivya0413 <120356578+dhivya0413@users.noreply.github.com>
* fix(INJI-304): tuvali & secure-keystore version update in package-lock
Co-authored-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>
* fix(INJI-282) Cross button of pop-up will navigate to home (#786)
* fix(INJI-282) Cross button of pop-up will navigate to home
* Icon made as pressble part
* fix(INJI-253): set thumbprint for custom secure keystore for qr login (#787)
---------
Co-authored-by: anil_majji <majjianilkumar050@gmail.com>
Co-authored-by: Monobikash Das <43202165+MonobikashDas@users.noreply.github.com>
Co-authored-by: Vijay <vijay@Vijays-MacBook-Pro.local>
Co-authored-by: Alka Prasad <Alka1703@users.noreply.github.com>
Co-authored-by: Sri Kanth Kola <srikanthsri7447@gmail.com>
Co-authored-by: vijay151096 <94220135+vijay151096@users.noreply.github.com>
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Co-authored-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>
Co-authored-by: Tilak Puli <tilakpuli15@gmail.com>
Co-authored-by: adityankannan-tw <adityan.kannan@thoughtworks.com>
Co-authored-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Co-authored-by: PoojaBabusing <115976560+PoojaBabusing@users.noreply.github.com>
Co-authored-by: Harsh Vardhan <harsh59v@gmail.com>
Co-authored-by: Alka <prasadalka1998@gmail.com>
Co-authored-by: Dhivya <dhivya.v@thoughtworks.com>
Co-authored-by: srikanth716 <97477121+srikanth716@users.noreply.github.com>
Co-authored-by: Anil kumar M <106086523+Anil-kumar-Majji@users.noreply.github.com>
Co-authored-by: Swati Goel <meet2swati@gmail.com>
Co-authored-by: dhivya0413 <120356578+dhivya0413@users.noreply.github.com>
13
.env
@@ -1,3 +1,14 @@
|
||||
MIMOTO_HOST=https://api.qa-121.mosip.net/residentmobileapp
|
||||
# after making changes to the env file, ensure to start the bundler (or the project) with a --reset-cache
|
||||
# eg . npm build android:newlogic --reset-cache
|
||||
|
||||
MIMOTO_HOST=https://api.qa-inji.mosip.net
|
||||
#MIMOTO_HOST=http://mock.mimoto.newlogic.dev
|
||||
GOOGLE_NEARBY_MESSAGES_API_KEY=
|
||||
#Application Theme can be ( orange | purple )
|
||||
APPLICATION_THEME=orange
|
||||
|
||||
#environment can be changed if it is toggled
|
||||
CREDENTIAL_REGISTRY_EDIT=true
|
||||
|
||||
#supported languages( en, fil, ar, hi, kn, ta)
|
||||
APPLICATION_LANGUAGE=en
|
||||
|
||||
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,10 +1,10 @@
|
||||
---
|
||||
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug, triage
|
||||
assignees:
|
||||
assignees:
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
@@ -20,18 +20,33 @@ Steps to reproduce the behavior:
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Actual behavior**
|
||||
A clear and concise description of what factually occurred.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Add the screenshot of the profile page with commit id**
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Wallet Device: [e.g. iPhone6]
|
||||
- Phone make/model: [e.g. :Vivo Y73]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- BLE version : [e.g. 4.2]
|
||||
|
||||
- Verifier Device: [e.g. iPhone6]
|
||||
- Phone make/model: [e.g. :Vivo Y73]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- BLE version : [e.g. 4.2]
|
||||
|
||||
- Inji app version: [e.g 0.3.0]
|
||||
- Mimoto version: [e.g 1.2.x]
|
||||
- MOSIP Version: [e.g. 1.2.1]
|
||||
- Mimoto server: [e.g. https://.....com]
|
||||
- MOSIP server: [e.g. https://...mosip.com]
|
||||
|
||||
**Where does the issue occur: Wallet/Verifier?**
|
||||
|
||||
**Logs of wallet and verifier:**
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
142
.github/workflows/android-beta-build.yml
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
name: Android Beta Build
|
||||
|
||||
env:
|
||||
backendServiceDefaultUrl: https://api.sandbox.mosip.net
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Tag to be published'
|
||||
required: true
|
||||
default: 'v1.2.3'
|
||||
type: string
|
||||
body:
|
||||
description: 'Release body message'
|
||||
required: true
|
||||
default: 'Changes in this Release'
|
||||
type: string
|
||||
pre-release:
|
||||
description: 'Pre-release? True/False'
|
||||
required: true
|
||||
default: False
|
||||
type: string
|
||||
backendServiceUrl:
|
||||
description: 'Backend service URL'
|
||||
required: true
|
||||
default: 'https://api.sandbox.mosip.net'
|
||||
type: string
|
||||
theme:
|
||||
description: 'Application Theme'
|
||||
required: true
|
||||
default: 'orange'
|
||||
type: choice
|
||||
options:
|
||||
- orange
|
||||
- purple
|
||||
buildDescription:
|
||||
description: 'What to test'
|
||||
required: true
|
||||
default: 'QA-Triple environment'
|
||||
type: string
|
||||
registry_edit:
|
||||
description: 'Edit Registry'
|
||||
required: true
|
||||
default: 'true'
|
||||
type: choice
|
||||
options:
|
||||
- false
|
||||
- true
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
with:
|
||||
tag_name: ${{ github.event.inputs.tag }}
|
||||
release_name: ${{ github.event.inputs.tag }}
|
||||
body: ${{ github.event.inputs.body }}
|
||||
draft: false
|
||||
prerelease: ${{fromJSON(github.event.inputs.pre-release)}}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Check for git tag
|
||||
run: |
|
||||
cd android/scripts
|
||||
./git-tag.sh
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: |
|
||||
npm ci
|
||||
|
||||
- name: Create .env.local file
|
||||
run: |
|
||||
echo "${{ secrets.ENV_FILE }}" > .env.local > android/local.properties
|
||||
|
||||
- name: Setup branch and env
|
||||
run: |
|
||||
# Strip git ref prefix from version
|
||||
echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV
|
||||
echo "GPG_TTY=$(tty)" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup branch and GPG public key
|
||||
run: |
|
||||
# Strip git ref prefix from version
|
||||
echo ${{ env.BRANCH_NAME }}
|
||||
echo ${{ env.GPG_TTY }}
|
||||
|
||||
sudo apt-get --yes install gnupg2
|
||||
gpg2 --import ./.github/keys/mosipgpgkey_pub.gpg
|
||||
gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg
|
||||
|
||||
- name: Setup Firebase
|
||||
run: |
|
||||
cd android
|
||||
if [ ! -z "$FIREBASE_SECRET" ] && [ -f app/google-services.json.gpg ];then rm -f app/google-services.json;gpg2 --quiet --batch --passphrase=$FIREBASE_SECRET --pinentry-mode loopback --decrypt --output app/google-services.json app/mosip-google-services.json.gpg;fi
|
||||
env:
|
||||
FIREBASE_SECRET: ${{ secrets.GPG_SECRET }}
|
||||
|
||||
- name: Generate keystore
|
||||
run: |
|
||||
echo "$ANDROID_KEYSTORE_FILE" > release.keystore.b64
|
||||
base64 -d -i release.keystore.b64 > android/app/release.keystore
|
||||
env:
|
||||
ANDROID_KEYSTORE_FILE: ${{ secrets.INJI_ANDROID_RELEASE_KEYSTORE }}
|
||||
|
||||
- name: Export variables for keystore
|
||||
run: |
|
||||
cd android/app
|
||||
export RELEASE_KEYSTORE_ALIAS=androidreleasekey
|
||||
export RELEASE_KEYSTORE_PASSWORD=$RELEASE_KEYSTORE_PASSWORD
|
||||
env:
|
||||
RELEASE_KEYSTORE_PASSWORD: '${{secrets.INJI_ANDROID_RELEASE_STOREPASS}}'
|
||||
|
||||
- name: Create Google Play Config file
|
||||
run : |
|
||||
cd android
|
||||
echo "$INJI_ANDROID_PLAY_STORE_CONFIG_JSON" > play_config.json.b64
|
||||
base64 -d -i play_config.json.b64 > play_config.json
|
||||
env:
|
||||
INJI_ANDROID_PLAY_STORE_CONFIG_JSON: ${{ secrets.INJI_ANDROID_PLAY_STORE_CONFIG_JSON }}
|
||||
|
||||
- name: Run Build
|
||||
run: |
|
||||
cd android/scripts
|
||||
./beta-build.sh
|
||||
env:
|
||||
MIMOTO_HOST: ${{ github.event.inputs.backendServiceUrl }}
|
||||
APPLICATION_THEME: ${{ github.event.inputs.theme }}
|
||||
RELEASE_KEYSTORE_ALIAS: androidreleasekey
|
||||
RELEASE_KEYSTORE_PASSWORD: '${{secrets.INJI_ANDROID_RELEASE_STOREPASS}}'
|
||||
SLACK_URL: '${{ secrets.SLACK_WEBHOOK_DEVOPS }}'
|
||||
PLAY_CONSOLE_RELEASE_DESCRIPTION: ${{ github.event.inputs.buildDescription }}
|
||||
CREDENTIAL_REGISTRY_EDIT: ${{ github.event.inputs.registry_edit }}
|
||||
@@ -1,4 +1,7 @@
|
||||
name: ID PASS - MOSIP Resident Application
|
||||
name: PR - Android build verification
|
||||
|
||||
env:
|
||||
backendServiceDefaultUrl: https://api.sandbox.mosip.net
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -7,16 +10,26 @@ on:
|
||||
- develop
|
||||
- demobranch
|
||||
- qa-develop
|
||||
- 0.9
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
types: [ opened, synchronize ]
|
||||
branches:
|
||||
- develop
|
||||
- 'release-**'
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.1.0
|
||||
|
||||
# Cache stuff for faster build
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: Cache local npm repository
|
||||
uses: actions/cache@v3.0.11
|
||||
with:
|
||||
@@ -30,7 +43,7 @@ jobs:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: |
|
||||
npm ci
|
||||
@@ -39,33 +52,63 @@ jobs:
|
||||
run: |
|
||||
echo "${{ secrets.ENV_FILE }}" > .env.local > android/local.properties
|
||||
|
||||
- name: Setup branch and env
|
||||
- name: Setup branch and env
|
||||
run: |
|
||||
# Strip git ref prefix from version
|
||||
echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV
|
||||
echo "GPG_TTY=$(tty)" >> $GITHUB_ENV
|
||||
- name: Setup branch and GPG public key
|
||||
|
||||
- name: Setup branch and GPG public key
|
||||
run: |
|
||||
# Strip git ref prefix from version
|
||||
|
||||
echo ${{ env.BRANCH_NAME }}
|
||||
|
||||
echo ${{ env.GPG_TTY }}
|
||||
|
||||
sudo apt-get --yes install gnupg2
|
||||
gpg2 --import ./.github/keys/mosipgpgkey_pub.gpg
|
||||
gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg
|
||||
gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg
|
||||
|
||||
- name: Build App Newlogic Release
|
||||
- name: Setup Firebase
|
||||
run: |
|
||||
cd android
|
||||
if [ ! -z "$FIREBASE_SECRET" ] && [ -f app/google-services.json.gpg ];then rm -f app/google-services.json;gpg2 --quiet --batch --passphrase=$FIREBASE_SECRET --pinentry-mode loopback --decrypt --output app/google-services.json app/mosip-google-services.json.gpg;fi
|
||||
./gradlew :app:assembleNewlogicRelease
|
||||
env:
|
||||
FIREBASE_SECRET: ${{ secrets.GPG_SECRET }}
|
||||
|
||||
- name: Generate keystore
|
||||
run: |
|
||||
keytool \
|
||||
-genkey -v \
|
||||
-storetype PKCS12 \
|
||||
-keyalg RSA \
|
||||
-keysize 2048 \
|
||||
-validity 10000 \
|
||||
-storepass $DEBUG_KEYSTORE_PASSWORD \
|
||||
-keypass $DEBUG_KEYSTORE_PASSWORD \
|
||||
-alias androiddebugkey \
|
||||
-keystore android/app/debug.keystore \
|
||||
-dname "CN=io.mosip.residentapp,OU=,O=,L=,S=,C=US"
|
||||
env:
|
||||
DEBUG_KEYSTORE_PASSWORD: '${{secrets.INJI_ANDROID_DEBUG_STOREPASS}}'
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3.1.1
|
||||
- name: Export variables for keystore
|
||||
run: |
|
||||
cd android/app
|
||||
export DEBUG_KEYSTORE_ALIAS=androiddebugkey
|
||||
export DEBUG_KEYSTORE_PASSWORD=$DEBUG_KEYSTORE_PASSWORD
|
||||
env:
|
||||
DEBUG_KEYSTORE_PASSWORD: '${{secrets.INJI_ANDROID_DEBUG_STOREPASS}}'
|
||||
|
||||
- name: Bump version code
|
||||
uses: chkfung/android-version-actions@v1.2.1
|
||||
with:
|
||||
name: output
|
||||
path: android/app/build/outputs/apk/newlogic/release/
|
||||
retention-days: 1
|
||||
gradlePath: android/app/build.gradle
|
||||
versionCode: ${{github.run_number}}
|
||||
|
||||
- name: Run Build using Fastlane
|
||||
run: |
|
||||
cd android/scripts
|
||||
./verify-build.sh
|
||||
env:
|
||||
DEBUG_KEYSTORE_ALIAS: androiddebugkey
|
||||
DEBUG_KEYSTORE_PASSWORD: '${{secrets.INJI_ANDROID_DEBUG_STOREPASS}}'
|
||||
74
.github/workflows/android-custom-build.yml
vendored
@@ -1,74 +0,0 @@
|
||||
name: ID PASS - MOSIP Resident Application Custom build
|
||||
|
||||
env:
|
||||
backendServiceDefaultUrl: https://api.qa-121.mosip.net/residentmobileapp
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
backendServiceUrl:
|
||||
description: 'Backend service URL'
|
||||
required: true
|
||||
default: 'https://api.qa-121.mosip.net/residentmobileapp'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.1.0
|
||||
|
||||
# Cache stuff for faster build
|
||||
- name: Cache local npm repository
|
||||
uses: actions/cache@v3.0.11
|
||||
with:
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
path: ~/.npm
|
||||
|
||||
- name: Cache local gradle repository
|
||||
uses: actions/cache@v3.0.11
|
||||
with:
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: |
|
||||
npm install
|
||||
|
||||
- name: Create .env.local file
|
||||
run: |
|
||||
echo "${{ secrets.ENV_FILE }}" > .env.local > android/local.properties
|
||||
|
||||
- name: Setup branch and env
|
||||
run: |
|
||||
# Strip git ref prefix from version
|
||||
echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV
|
||||
echo "GPG_TTY=$(tty)" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup branch and GPG public key
|
||||
run: |
|
||||
# Strip git ref prefix from version
|
||||
|
||||
echo ${{ env.BRANCH_NAME }}
|
||||
|
||||
echo ${{ env.GPG_TTY }}
|
||||
sudo apt-get --yes install gnupg2
|
||||
gpg2 --import ./.github/keys/mosipgpgkey_pub.gpg
|
||||
gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg
|
||||
|
||||
- name: Build App Newlogic Release
|
||||
run: |
|
||||
cd android
|
||||
if [ ! -z "$FIREBASE_SECRET" ] && [ -f app/google-services.json.gpg ];then rm -f app/google-services.json;gpg2 --quiet --batch --passphrase=$FIREBASE_SECRET --pinentry-mode loopback --decrypt --output app/google-services.json app/mosip-google-services.json.gpg;fi
|
||||
./gradlew :app:assembleNewlogicRelease
|
||||
env:
|
||||
MIMOTO_HOST: ${{ github.event.inputs.backendServiceUrl }}
|
||||
FIREBASE_SECRET: ${{ secrets.GPG_SECRET }}
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3.1.1
|
||||
with:
|
||||
name: apk-output
|
||||
path: android/app/build/outputs/apk/newlogic/release/
|
||||
retention-days: 10
|
||||
124
.github/workflows/android-internal-build.yml
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
name: Android Internal Build
|
||||
|
||||
env:
|
||||
backendServiceDefaultUrl: https://api.sandbox.mosip.net
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
backendServiceUrl:
|
||||
description: 'Backend service URL'
|
||||
required: true
|
||||
default: 'https://api.sandbox.mosip.net'
|
||||
type: string
|
||||
theme:
|
||||
description: 'Application Theme'
|
||||
required: true
|
||||
default: 'orange'
|
||||
type: choice
|
||||
options:
|
||||
- orange
|
||||
- purple
|
||||
buildDescription:
|
||||
description: 'What to test'
|
||||
required: true
|
||||
default: 'QA-Triple environment'
|
||||
type: string
|
||||
registry_edit:
|
||||
description: 'Edit Registry'
|
||||
required: true
|
||||
default: 'true'
|
||||
type: choice
|
||||
options:
|
||||
- false
|
||||
- true
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: Cache local npm repository
|
||||
uses: actions/cache@v3.0.11
|
||||
with:
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
path: ~/.npm
|
||||
|
||||
- name: Cache local gradle repository
|
||||
uses: actions/cache@v3.0.11
|
||||
with:
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: |
|
||||
npm ci
|
||||
|
||||
- name: Create .env.local file
|
||||
run: |
|
||||
echo "${{ secrets.ENV_FILE }}" > .env.local > android/local.properties
|
||||
|
||||
- name: Setup branch and env
|
||||
run: |
|
||||
# Strip git ref prefix from version
|
||||
echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV
|
||||
echo "GPG_TTY=$(tty)" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup branch and GPG public key
|
||||
run: |
|
||||
# Strip git ref prefix from version
|
||||
echo ${{ env.BRANCH_NAME }}
|
||||
echo ${{ env.GPG_TTY }}
|
||||
|
||||
sudo apt-get --yes install gnupg2
|
||||
gpg2 --import ./.github/keys/mosipgpgkey_pub.gpg
|
||||
gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg
|
||||
|
||||
- name: Setup Firebase
|
||||
run: |
|
||||
cd android
|
||||
if [ ! -z "$FIREBASE_SECRET" ] && [ -f app/google-services.json.gpg ];then rm -f app/google-services.json;gpg2 --quiet --batch --passphrase=$FIREBASE_SECRET --pinentry-mode loopback --decrypt --output app/google-services.json app/mosip-google-services.json.gpg;fi
|
||||
env:
|
||||
FIREBASE_SECRET: ${{ secrets.GPG_SECRET }}
|
||||
|
||||
- name: Generate keystore
|
||||
run: |
|
||||
echo "$ANDROID_KEYSTORE_FILE" > release.keystore.b64
|
||||
base64 -d -i release.keystore.b64 > android/app/release.keystore
|
||||
env:
|
||||
ANDROID_KEYSTORE_FILE: ${{ secrets.INJI_ANDROID_RELEASE_KEYSTORE }}
|
||||
|
||||
- name: Export variables for keystore
|
||||
run: |
|
||||
cd android/app
|
||||
export RELEASE_KEYSTORE_ALIAS=androidreleasekey
|
||||
export RELEASE_KEYSTORE_PASSWORD=$RELEASE_KEYSTORE_PASSWORD
|
||||
env:
|
||||
RELEASE_KEYSTORE_PASSWORD: '${{secrets.INJI_ANDROID_RELEASE_STOREPASS}}'
|
||||
|
||||
- name: Create Google Play Config file
|
||||
run : |
|
||||
cd android
|
||||
echo "$INJI_ANDROID_PLAY_STORE_CONFIG_JSON" > play_config.json.b64
|
||||
base64 -d -i play_config.json.b64 > play_config.json
|
||||
env:
|
||||
INJI_ANDROID_PLAY_STORE_CONFIG_JSON: ${{ secrets.INJI_ANDROID_PLAY_STORE_CONFIG_JSON }}
|
||||
|
||||
- name: Run Build
|
||||
run: |
|
||||
cd android/scripts
|
||||
./internal-build.sh
|
||||
env:
|
||||
MIMOTO_HOST: ${{ github.event.inputs.backendServiceUrl }}
|
||||
APPLICATION_THEME: ${{ github.event.inputs.theme }}
|
||||
RELEASE_KEYSTORE_ALIAS: androidreleasekey
|
||||
RELEASE_KEYSTORE_PASSWORD: '${{secrets.INJI_ANDROID_RELEASE_STOREPASS}}'
|
||||
SLACK_URL: '${{ secrets.SLACK_WEBHOOK_DEVOPS }}'
|
||||
PLAY_CONSOLE_RELEASE_DESCRIPTION: ${{ github.event.inputs.buildDescription }}
|
||||
CREDENTIAL_REGISTRY_EDIT: ${{ github.event.inputs.registry_edit }}
|
||||
5
.github/workflows/clear_artifacts.yml
vendored
@@ -1,4 +1,7 @@
|
||||
name: 'Delete old artifacts'
|
||||
on:
|
||||
workflow_dispatch:
|
||||
name: 'Delete old artifacts'
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -8,5 +11,5 @@ jobs:
|
||||
steps:
|
||||
- uses: kolpav/purge-artifacts-action@v1
|
||||
with:
|
||||
token: ${{ secrets. access_token }}
|
||||
token: ${{ secrets.ACTION_PAT }}
|
||||
expire-in: 2days # Setting this to 0 will delete all artifacts
|
||||
59
.github/workflows/ios-build-verify.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
name: PR - IOS build verification
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
- demobranch
|
||||
- qa-develop
|
||||
- 0.9
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
types: [ opened, synchronize ]
|
||||
branches:
|
||||
- develop
|
||||
- 'release-**'
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build_ios:
|
||||
name: Building the IPA
|
||||
runs-on: macos-13
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: |
|
||||
npm install
|
||||
|
||||
- name: Install Pod
|
||||
run: |
|
||||
cd ios
|
||||
pod install
|
||||
|
||||
- name: Building the IPA
|
||||
run: |
|
||||
cd ios
|
||||
fastlane build_verify
|
||||
env:
|
||||
APP_STORE_CONNECT_TEAM_ID: '${{ secrets.APP_STORE_CONNECT_TEAM_ID }}'
|
||||
DEVELOPER_APP_ID: '${{ secrets.IOS_INJI_DEVELOPER_APP_ID }}'
|
||||
INJI_IOS_DEVELOPER_APP_IDENTIFIER: '${{ secrets.INJI_IOS_DEVELOPER_APP_IDENTIFIER }}'
|
||||
INJI_IOS_DEVELOPER_PORTAL_TEAM_ID: '${{ secrets.INJI_IOS_DEVELOPER_PORTAL_TEAM_ID }}'
|
||||
INJI_IOS_FASTLANE_APPLE_ID: '${{ secrets.INJI_IOS_FASTLANE_APPLE_ID }}'
|
||||
INJI_IOS_FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: '${{ secrets.INJI_IOS_FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}'
|
||||
GIT_AUTHORIZATION: '${{ secrets.GIT_AUTHORIZATION }}'
|
||||
INJI_IOS_PROVISIONING_PROFILE_SPECIFIER: '${{ secrets.INJI_IOS_PROVISIONING_PROFILE_SPECIFIER }}'
|
||||
INJI_IOS_TEMP_KEYCHAIN_PASSWORD: '${{ secrets.INJI_IOS_TEMP_KEYCHAIN_PASSWORD }}'
|
||||
INJI_IOS_TEMP_KEYCHAIN_USER: '${{ secrets.INJI_IOS_TEMP_KEYCHAIN_USER }}'
|
||||
APPLE_KEY_ID: '${{ secrets.APPLE_KEY_ID }}'
|
||||
APPLE_ISSUER_ID: '${{ secrets.APPLE_ISSUER_ID }}'
|
||||
APPLE_KEY_CONTENT: '${{ secrets.APPLE_KEY_CONTENT }}'
|
||||
MATCH_PASSWORD: '${{ secrets.INJI_IOS_MATCH_PASSWORD }}'
|
||||
88
.github/workflows/ios-build.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
name: Inji iOS build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
backendServiceUrl:
|
||||
description: 'Backend service URL'
|
||||
required: true
|
||||
default: 'https://api.sandbox.mosip.net'
|
||||
type: string
|
||||
theme:
|
||||
description: 'Application Theme'
|
||||
required: true
|
||||
default: 'orange'
|
||||
type: choice
|
||||
options:
|
||||
- orange
|
||||
- purple
|
||||
registry_edit:
|
||||
description: 'Edit Registry'
|
||||
required: true
|
||||
default: 'true'
|
||||
type: choice
|
||||
options:
|
||||
- false
|
||||
- true
|
||||
internal-testers:
|
||||
description: 'Internal Testers Group'
|
||||
required: true
|
||||
default: 'QA-Triple'
|
||||
type: choice
|
||||
options:
|
||||
- Dev-testing
|
||||
- MEC
|
||||
- QA
|
||||
- MOSIP-Collab
|
||||
- MOSIP-Dev-testing
|
||||
buildDescription:
|
||||
description: 'What to test'
|
||||
required: true
|
||||
default: 'QA-Triple environment build'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build_ios:
|
||||
name: Deploying to Testflight
|
||||
runs-on: macos-13
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: |
|
||||
npm install
|
||||
|
||||
- name: Install Pod
|
||||
run: |
|
||||
cd ios
|
||||
pod install
|
||||
|
||||
- name: Deploy iOS Beta to TestFlight
|
||||
run: |
|
||||
cd ios
|
||||
fastlane beta
|
||||
env:
|
||||
APP_STORE_CONNECT_TEAM_ID: '${{ secrets.APP_STORE_CONNECT_TEAM_ID }}'
|
||||
DEVELOPER_APP_ID: '${{ secrets.IOS_INJI_DEVELOPER_APP_ID }}'
|
||||
INJI_IOS_DEVELOPER_APP_IDENTIFIER: '${{ secrets.INJI_IOS_DEVELOPER_APP_IDENTIFIER }}'
|
||||
INJI_IOS_DEVELOPER_PORTAL_TEAM_ID: '${{ secrets.INJI_IOS_DEVELOPER_PORTAL_TEAM_ID }}'
|
||||
INJI_IOS_FASTLANE_APPLE_ID: '${{ secrets.INJI_IOS_FASTLANE_APPLE_ID }}'
|
||||
INJI_IOS_FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: '${{ secrets.INJI_IOS_FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}'
|
||||
GIT_AUTHORIZATION: '${{ secrets.GIT_AUTHORIZATION }}'
|
||||
INJI_IOS_PROVISIONING_PROFILE_SPECIFIER: '${{ secrets.INJI_IOS_PROVISIONING_PROFILE_SPECIFIER }}'
|
||||
INJI_IOS_TEMP_KEYCHAIN_PASSWORD: '${{ secrets.INJI_IOS_TEMP_KEYCHAIN_PASSWORD }}'
|
||||
INJI_IOS_TEMP_KEYCHAIN_USER: '${{ secrets.INJI_IOS_TEMP_KEYCHAIN_USER }}'
|
||||
APPLE_KEY_ID: '${{ secrets.APPLE_KEY_ID }}'
|
||||
APPLE_ISSUER_ID: '${{ secrets.APPLE_ISSUER_ID }}'
|
||||
APPLE_KEY_CONTENT: '${{ secrets.APPLE_KEY_CONTENT }}'
|
||||
SLACK_URL: '${{ secrets.SLACK_WEBHOOK_DEVOPS }}'
|
||||
MATCH_PASSWORD: '${{ secrets.INJI_IOS_MATCH_PASSWORD }}'
|
||||
APPLICATION_THEME: ${{ github.event.inputs.theme }}
|
||||
CREDENTIAL_REGISTRY_EDIT: ${{ github.event.inputs.registry_edit }}
|
||||
MIMOTO_HOST: ${{ github.event.inputs.backendServiceUrl }}
|
||||
TESTFLIGHT_INTERNAL_TESTERS_GROUP: ${{ github.event.inputs.internal-testers }}
|
||||
TESTFLIGHT_BETA_APP_DESCRIPTION: ${{ github.event.inputs.buildDescription }}
|
||||
43
.github/workflows/tag.yaml
vendored
@@ -1,43 +0,0 @@
|
||||
name: Tagging of repos
|
||||
|
||||
env:
|
||||
tag: v1.2.3
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Tag to be published'
|
||||
required: true
|
||||
default: 'v1.2.3'
|
||||
type: string
|
||||
body:
|
||||
description: 'Release body message'
|
||||
required: true
|
||||
default: 'Changes in this Release'
|
||||
type: string
|
||||
pre-release:
|
||||
description: 'Pre-release? True/False'
|
||||
required: true
|
||||
default: False
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3.1.0
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
|
||||
with:
|
||||
tag_name: ${{ github.event.inputs.tag }}
|
||||
release_name: ${{ github.event.inputs.tag }}
|
||||
body: |
|
||||
${{ github.event.inputs.body }}
|
||||
draft: false
|
||||
prerelease: ${{fromJSON(github.event.inputs.pre-release)}}
|
||||
9
.gitignore
vendored
@@ -60,8 +60,6 @@ yarn-error.log
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
!debug.keystore
|
||||
|
||||
# Bundle artifacts
|
||||
*.jsbundle
|
||||
@@ -90,4 +88,9 @@ dist/
|
||||
.vscode/
|
||||
temp/
|
||||
.eslintcache
|
||||
.env.local
|
||||
.env.local
|
||||
|
||||
.yalc/
|
||||
yalc.lock
|
||||
|
||||
android/app/debug.keystore
|
||||
|
||||
95
App.tsx
@@ -1,20 +1,105 @@
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import AppLoading from 'expo-app-loading';
|
||||
import { AppLayout } from './screens/AppLayout';
|
||||
import { useFont } from './shared/hooks/useFont';
|
||||
import { GlobalContextProvider } from './components/GlobalContextProvider';
|
||||
import { GlobalContext } from './shared/GlobalContext';
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { selectIsReady } from './machines/app';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
selectIsDecryptError,
|
||||
selectIsKeyInvalidateError,
|
||||
selectIsReadError,
|
||||
selectIsReady,
|
||||
} from './machines/app';
|
||||
import { DualMessageOverlay } from './components/DualMessageOverlay';
|
||||
import { useApp } from './screens/AppController';
|
||||
import { Alert } from 'react-native';
|
||||
import { ErrorMessageOverlay } from './components/MessageOverlay';
|
||||
import SecureKeystore from 'react-native-secure-keystore';
|
||||
import { isCustomSecureKeystore } from './shared/cryptoutil/cryptoUtil';
|
||||
import i18n from './i18n';
|
||||
|
||||
import './i18n';
|
||||
// kludge: this is a bad practice but has been done temporarily to surface
|
||||
// an occurance of a bug with minimal residual code changes, this should
|
||||
// be removed once the bug cause is determined & fixed, ref: INJI-222
|
||||
const DecryptErrorAlert = (controller, t) => {
|
||||
const heading = t('errors.decryptionFailed');
|
||||
const desc = t('errors.decryptionFailed');
|
||||
const ignoreBtnTxt = t('ignore');
|
||||
Alert.alert(heading, desc, [
|
||||
{
|
||||
text: ignoreBtnTxt,
|
||||
onPress: () => controller.ignoreDecrypt(),
|
||||
style: 'cancel',
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
const AppLayoutWrapper: React.FC = () => {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const isDecryptError = useSelector(appService, selectIsDecryptError);
|
||||
const controller = useApp();
|
||||
const { t } = useTranslation('WelcomeScreen');
|
||||
if (isDecryptError) {
|
||||
DecryptErrorAlert(controller, t);
|
||||
}
|
||||
return <AppLayout />;
|
||||
};
|
||||
|
||||
const AppLoadingWrapper: React.FC = () => {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const isReadError = useSelector(appService, selectIsReadError);
|
||||
const isKeyInvalidateError = useSelector(
|
||||
appService,
|
||||
selectIsKeyInvalidateError
|
||||
);
|
||||
const controller = useApp();
|
||||
const { t } = useTranslation('WelcomeScreen');
|
||||
return (
|
||||
<>
|
||||
<AppLoading />
|
||||
|
||||
<ErrorMessageOverlay
|
||||
translationPath={'WelcomeScreen'}
|
||||
isVisible={isKeyInvalidateError}
|
||||
error={'errors.invalidateKeyError'}
|
||||
onDismiss={controller.RESET}
|
||||
/>
|
||||
|
||||
{isReadError ? (
|
||||
<DualMessageOverlay
|
||||
isVisible={isReadError}
|
||||
title={t('failedToReadKeys')}
|
||||
message={t('retryRead')}
|
||||
onTryAgain={controller.TRY_AGAIN}
|
||||
onIgnore={controller.IGNORE}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const AppInitialization: React.FC = () => {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const hasFontsLoaded = useFont();
|
||||
const isReady = useSelector(appService, selectIsReady);
|
||||
const hasFontsLoaded = useFont();
|
||||
const { t } = useTranslation('common');
|
||||
|
||||
return isReady && hasFontsLoaded ? <AppLayout /> : <AppLoading />;
|
||||
useEffect(() => {
|
||||
if (isCustomSecureKeystore()) {
|
||||
SecureKeystore.updatePopup(
|
||||
t('biometricPopup.title'),
|
||||
t('biometricPopup.description')
|
||||
);
|
||||
}
|
||||
}, [i18n.language]);
|
||||
|
||||
return isReady && hasFontsLoaded ? (
|
||||
<AppLayoutWrapper />
|
||||
) : (
|
||||
<AppLoadingWrapper />
|
||||
);
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
|
||||
1
AppMetaData.md
Normal file
@@ -0,0 +1 @@
|
||||
Inji is a mobile app that can be used as a digital wallet to store credentials. It also allows verification of identity in both offline and online modes, at any place and time.
|
||||
38
README.md
@@ -15,6 +15,7 @@ Be sure to have the following build tools installed before proceeding:
|
||||
## Generate keystore for APK signing
|
||||
|
||||
```shell
|
||||
# Generate and use Debug keystore for development and testing purposes
|
||||
keytool \
|
||||
-genkey -v \
|
||||
-storetype PKCS12 \
|
||||
@@ -23,6 +24,21 @@ keytool \
|
||||
-validity 10000 \
|
||||
-storepass 'android' \
|
||||
-keypass 'android' \
|
||||
-alias androiddebugkey \
|
||||
-keystore android/app/debug.keystore \
|
||||
-dname "CN=io.mosip.residentapp,OU=,O=,L=,S=,C=US"
|
||||
```
|
||||
|
||||
```shell
|
||||
# Generate and use Release keystore for Publishing to Play store
|
||||
keytool \
|
||||
-genkey -v \
|
||||
-storetype PKCS12 \
|
||||
-keyalg RSA \
|
||||
-keysize 2048 \
|
||||
-validity 10000 \
|
||||
-storepass '<USE-YOUR-RELEASE-PASSWORD-HERE>' \
|
||||
-keypass '<USE-YOUR-RELEASE-PASSWORD-HERE>' \
|
||||
-alias androidreleasekey \
|
||||
-keystore android/app/release.keystore \
|
||||
-dname "CN=io.mosip.residentapp,OU=,O=,L=,S=,C=US"
|
||||
@@ -93,15 +109,19 @@ You need Android SDK CLI to build APK.
|
||||
# 1. Install dependencies
|
||||
npm install
|
||||
|
||||
# Setup the environment variable for keystore
|
||||
export RELEASE_KEYSTORE=release.keystore
|
||||
# 2. Setup the environment variables for the keystore
|
||||
|
||||
# Debug keystore
|
||||
export DEBUG_KEYSTORE_ALIAS=androiddebugkey
|
||||
export DEBUG_KEYSTORE_PASSWORD=android
|
||||
|
||||
# Release keystore
|
||||
export RELEASE_KEYSTORE_ALIAS=androidreleasekey
|
||||
export RELEASE_KEYSTORE_PASSWORD=android
|
||||
export RELEASE_KEYSTORE_PASSWORD=<USE-YOUR-RELEASE-PASSWORD-HERE>
|
||||
|
||||
# https://hostname/residentmobileapp is the Mimoto service url
|
||||
export BACKEND_SERVICE_URL=https://hostname/residentmobileapp
|
||||
|
||||
# Use DEBUG_KEYSTORE, DEBUG_KEYSTORE_ALIAS, DEBUG_KEYSTORE_PASSWORD for debug build
|
||||
|
||||
# Use one of following command to build the flavor you need.
|
||||
# Build for Mosip Philippines test
|
||||
npm run build:android:ph
|
||||
@@ -143,6 +163,14 @@ More info here:
|
||||
- [React Native - Publishing to the App Store](https://reactnative.dev/docs/publishing-to-app-store)
|
||||
- [Apple Developer - Distributing Your App for Beta Testing and Releases](https://developer.apple.com/documentation/xcode/distributing-your-app-for-beta-testing-and-releases)
|
||||
|
||||
## View the complete DB :
|
||||
|
||||
1. Connect your phone to the laptop and open Android Studio.
|
||||
2. On the bottom right vertical tab you will find a `Device File Explorer` button. Click on it and select you phone.
|
||||
3. Navigate to `data -> data -> io.mosip.residentapp ->databases`. You will find a file named `RKStorage` in it. Download it.
|
||||
4. Download [DB Browser for SQLite](https://sqlitebrowser.org/dl/) .
|
||||
5. Open the file in this application. Click on `Browse Data` button and select `catalystLocalStorage` table. Now you should be able to view the entire DB of Inji.
|
||||
|
||||
## Credits
|
||||
|
||||
Credits listed [here](/Credits.md)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>MOSIP Resident App</name>
|
||||
<name>Inji</name>
|
||||
<comment>Project android created by Buildship.</comment>
|
||||
<projects>
|
||||
</projects>
|
||||
|
||||
6
android/Gemfile
Normal file
@@ -0,0 +1,6 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
eval_gemfile(plugins_path) if File.exist?(plugins_path)
|
||||
220
android/Gemfile.lock
Normal file
@@ -0,0 +1,220 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.6)
|
||||
rexml
|
||||
addressable (2.8.4)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
artifactory (3.0.15)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.765.0)
|
||||
aws-sdk-core (3.172.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.64.0)
|
||||
aws-sdk-core (~> 3, >= 3.165.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.122.0)
|
||||
aws-sdk-core (~> 3, >= 3.165.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.4)
|
||||
aws-sigv4 (1.5.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
claide (1.1.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander (4.6.0)
|
||||
highline (~> 2.0.0)
|
||||
declarative (0.0.20)
|
||||
digest-crc (0.6.4)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.8.1)
|
||||
emoji_regex (3.2.3)
|
||||
excon (0.99.0)
|
||||
faraday (1.10.3)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0)
|
||||
faraday-multipart (~> 1.0)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.0)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
faraday-retry (~> 1.0)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-httpclient (1.0.1)
|
||||
faraday-multipart (1.0.4)
|
||||
multipart-post (~> 2)
|
||||
faraday-net_http (1.0.1)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.0)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.2.6)
|
||||
fastlane (2.212.2)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander (~> 4.6)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.3)
|
||||
google-apis-playcustomapp_v1 (~> 0.1)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (~> 2.0.0)
|
||||
naturally (~> 2.2)
|
||||
optparse (~> 0.1.1)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
fastlane-plugin-increment_version_code (0.4.3)
|
||||
gh_inspector (1.1.3)
|
||||
google-apis-androidpublisher_v3 (0.42.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.0)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
httpclient (>= 2.8.1, < 3.a)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.a)
|
||||
rexml
|
||||
webrick
|
||||
google-apis-iamcredentials_v1 (0.17.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-playcustomapp_v1 (0.13.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-storage_v1 (0.19.0)
|
||||
google-apis-core (>= 0.9.0, < 2.a)
|
||||
google-cloud-core (1.6.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.3.1)
|
||||
google-cloud-storage (1.44.0)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.19.0)
|
||||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (1.5.2)
|
||||
faraday (>= 0.17.3, < 3.a)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (>= 0.16, < 2.a)
|
||||
highline (2.0.3)
|
||||
http-cookie (1.0.5)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.6.2)
|
||||
json (2.6.3)
|
||||
jwt (2.7.0)
|
||||
memoist (0.16.2)
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.2)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
optparse (0.1.1)
|
||||
os (1.1.4)
|
||||
plist (3.7.0)
|
||||
public_suffix (5.0.1)
|
||||
rake (13.0.6)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.2.5)
|
||||
rouge (2.0.7)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
security (0.1.3)
|
||||
signet (0.17.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.10)
|
||||
CFPropertyList
|
||||
naturally
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
trailblazer-option (0.1.2)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.1)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8.2)
|
||||
unicode-display_width (1.8.0)
|
||||
webrick (1.8.1)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.22.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
rexml (~> 3.2.4)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
arm64-darwin-21
|
||||
|
||||
DEPENDENCIES
|
||||
fastlane
|
||||
fastlane-plugin-increment_version_code
|
||||
|
||||
BUNDLED WITH
|
||||
2.4.10
|
||||
@@ -1,4 +1,4 @@
|
||||
plugins {
|
||||
plugins {
|
||||
id 'com.gladed.androidgitversion' version '0.4.14'
|
||||
}
|
||||
|
||||
@@ -132,7 +132,9 @@ def jscFlavor = 'org.webkit:android-jsc:+'
|
||||
def enableHermes = project.ext.react.get("enableHermes", false);
|
||||
|
||||
androidGitVersion {
|
||||
baseCode 1
|
||||
baseCode 0
|
||||
codeFormat 'MXXNXXPXX'
|
||||
format '% tag %%commit_%%branch%'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -142,7 +144,7 @@ android {
|
||||
APP_NAME_RELEASE = "@string/app_name"
|
||||
APP_NAME_PH = "@string/app_name_ph"
|
||||
APP_NAME_MOSIP = "@string/app_name_mosip"
|
||||
APP_NAME_NEWLOGIC = "@string/app_name_newlogic"
|
||||
APP_NAME_BETA = "@string/app_name_beta"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
@@ -154,11 +156,8 @@ android {
|
||||
applicationId 'io.mosip.residentapp'
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
// Update versionName and/or versionCode via git tag <XX.xx.xx>
|
||||
// More info here:
|
||||
// https://github.com/gladed/gradle-android-git-version#3-use-a-git-tag-to-specify-your-version-number-see-semantic-versioning
|
||||
versionName androidGitVersion.name()
|
||||
versionCode androidGitVersion.code()
|
||||
versionCode 1
|
||||
|
||||
Properties properties = new Properties()
|
||||
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||
@@ -178,9 +177,9 @@ android {
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
def keystore = System.getenv("RELEASE_KEYSTORE") ?: "debug.keystore"
|
||||
def keystoreAlias = System.getenv("RELEASE_KEYSTORE_ALIAS") ?: "androiddebugkey"
|
||||
def keystorePass = System.getenv("RELEASE_KEYSTORE_PASSWORD") ?: "android"
|
||||
def keystore = file('release.keystore')
|
||||
def keystoreAlias = System.getenv("RELEASE_KEYSTORE_ALIAS")
|
||||
def keystorePass = System.getenv("RELEASE_KEYSTORE_PASSWORD")
|
||||
storeFile file("$keystore")
|
||||
storePassword "$keystorePass"
|
||||
keyAlias "$keystoreAlias"
|
||||
@@ -189,9 +188,9 @@ android {
|
||||
v1SigningEnabled false
|
||||
}
|
||||
debug {
|
||||
def keystore = System.getenv("DEBUG_KEYSTORE") ?: "debug.keystore"
|
||||
def keystoreAlias = System.getenv("DEBUG_KEYSTORE_ALIAS") ?: "androiddebugkey"
|
||||
def keystorePass = System.getenv("DEBUG_KEYSTORE_PASSWORD") ?: "android"
|
||||
def keystore = file('debug.keystore')
|
||||
def keystoreAlias = System.getenv("DEBUG_KEYSTORE_ALIAS")
|
||||
def keystorePass = System.getenv("DEBUG_KEYSTORE_PASSWORD")
|
||||
storeFile file("$keystore")
|
||||
storePassword "$keystorePass"
|
||||
keyAlias "$keystoreAlias"
|
||||
@@ -205,6 +204,10 @@ android {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
release {
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
abortOnError false
|
||||
}
|
||||
// Caution! In production, you need to generate your own keystore file.
|
||||
// see https://reactnative.dev/docs/signed-apk-android.
|
||||
signingConfig signingConfigs.release
|
||||
@@ -217,16 +220,16 @@ android {
|
||||
|
||||
productFlavors {
|
||||
mosip {
|
||||
versionName defaultConfig.versionName + "-mosip"
|
||||
versionName defaultConfig.versionName
|
||||
manifestPlaceholders = [
|
||||
APP_NAME: APP_NAME_MOSIP
|
||||
]
|
||||
dimension "inji"
|
||||
}
|
||||
newlogic {
|
||||
versionName defaultConfig.versionName + "-newlogic"
|
||||
beta {
|
||||
versionName defaultConfig.versionName
|
||||
manifestPlaceholders = [
|
||||
APP_NAME: APP_NAME_NEWLOGIC
|
||||
APP_NAME: APP_NAME_BETA
|
||||
]
|
||||
dimension "inji"
|
||||
}
|
||||
@@ -252,6 +255,7 @@ dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation "com.facebook.react:react-native:+"// From node_modules
|
||||
implementation 'com.facebook.soloader:soloader:0.10.1+'
|
||||
|
||||
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
|
||||
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
|
||||
@@ -320,4 +324,4 @@ try {
|
||||
}
|
||||
} catch(Exception e) {
|
||||
logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,15 @@
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
||||
android:usesPermissionFlags="neverForLocation" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
|
||||
<!-- from Android 12, Location permission isn't required as we aren't using it to determine location -->
|
||||
|
||||
<application tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" android:usesCleartextTraffic="true" />
|
||||
</manifest>
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.mosip.residentapp">
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
|
||||
<!-- from Android 12, Location permission isn't required as we aren't using it to determine location -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
||||
android:usesPermissionFlags="neverForLocation" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||
@@ -31,7 +36,8 @@
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0" />
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@nlpaolo/mosip-resident-app" />
|
||||
<meta-data android:name="com.google.android.nearby.messages.API_KEY" android:value="${GOOGLE_NEARBY_MESSAGES_API_KEY}" />
|
||||
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustPan" android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait">
|
||||
<activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustPan" android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -45,4 +51,4 @@
|
||||
</activity>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -29,9 +29,7 @@ public class MainActivity extends ReactActivity {
|
||||
Manifest.permission.BLUETOOTH_ADMIN,
|
||||
Manifest.permission.ACCESS_WIFI_STATE,
|
||||
Manifest.permission.CHANGE_WIFI_STATE,
|
||||
Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.CHANGE_WIFI_MULTICAST_STATE
|
||||
};
|
||||
|
||||
private static final int REQUEST_CODE_REQUIRED_PERMISSIONS = 1;
|
||||
|
||||
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 140 KiB |
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<resources>
|
||||
<color name="splashscreen_background">#ffffff</color>
|
||||
<color name="splashscreen_background">#FFFFFF</color>
|
||||
<color name="iconBackground">#FFFFFF</color>
|
||||
<color name="colorPrimary">#023c69</color>
|
||||
<color name="colorPrimaryDark">#ffffff</color>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<resources>
|
||||
<string name="app_name">MOSIP Resident App</string>
|
||||
<string name="app_name">Inji</string>
|
||||
<string name="app_name_mosip">MOSIP Resident App - Mosip/Inji</string>
|
||||
<string name="app_name_newlogic">MOSIP Resident App - Newlogic</string>
|
||||
<string name="app_name_ph">MOSIP Resident App - PH</string>
|
||||
<string name="expo_splash_screen_resize_mode" translatable="false">contain</string>
|
||||
<string name="expo_splash_screen_resize_mode" translatable="false">cover</string>
|
||||
<string name="expo_splash_screen_status_bar_translucent" translatable="false">false</string>
|
||||
</resources>
|
||||
@@ -4,8 +4,8 @@ buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "29.0.3"
|
||||
minSdkVersion = 23
|
||||
compileSdkVersion = 30
|
||||
targetSdkVersion = 30
|
||||
compileSdkVersion = 31
|
||||
targetSdkVersion = 31
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
@@ -34,6 +34,11 @@ allprojects {
|
||||
// Android JSC is installed from npm
|
||||
url(new File(["node", "--print", "require.resolve('jsc-android/package.json')"].execute(null, rootDir).text.trim(), "../dist"))
|
||||
}
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
force "com.facebook.soloader:soloader:0.10.1"
|
||||
}
|
||||
}
|
||||
|
||||
google()
|
||||
gradlePluginPortal()
|
||||
|
||||
2
android/fastlane/Appfile
Normal file
@@ -0,0 +1,2 @@
|
||||
json_key_file("play_config.json")
|
||||
package_name("io.mosip.residentapp")
|
||||
86
android/fastlane/Fastfile
Normal file
@@ -0,0 +1,86 @@
|
||||
default_platform(:android)
|
||||
|
||||
MIMOTO_HOST = ENV["MIMOTO_HOST"]
|
||||
APPLICATION_THEME = ENV["APPLICATION_THEME"]
|
||||
RELEASE_KEYSTORE_ALIAS = ENV["RELEASE_KEYSTORE_ALIAS"]
|
||||
RELEASE_KEYSTORE_PASSWORD = ENV["RELEASE_KEYSTORE_PASSWORD"]
|
||||
PLAY_CONSOLE_RELEASE_DESCRIPTION = ENV["PLAY_CONSOLE_RELEASE_DESCRIPTION"]
|
||||
SLACK_URL = ENV["SLACK_URL"]
|
||||
CREDENTIAL_REGISTRY_EDIT = ENV["CREDENTIAL_REGISTRY_EDIT"]
|
||||
|
||||
desc "Verify Build for Android"
|
||||
lane :android_build_verify do
|
||||
gradle(
|
||||
task: "assembleMosipDebug",
|
||||
)
|
||||
end
|
||||
|
||||
desc "Deploy an Internal testing version to the Google Play"
|
||||
lane :android_build_internal do
|
||||
previous_build_number = google_play_track_version_codes(
|
||||
package_name: "io.mosip.residentapp",
|
||||
track: "internal",
|
||||
json_key: "play_config.json",
|
||||
)[0]
|
||||
|
||||
current_build_number = previous_build_number + 1
|
||||
|
||||
increment_version_code(
|
||||
gradle_file_path: "app/build.gradle",
|
||||
version_code: current_build_number
|
||||
)
|
||||
|
||||
git_commit = sh('git rev-parse --short HEAD').strip
|
||||
git_branch = sh('git rev-parse --abbrev-ref HEAD').strip
|
||||
|
||||
versionName = "#{git_commit}-#{git_branch}"
|
||||
|
||||
gradle(task: "clean bundleMosipRelease")
|
||||
upload_to_play_store(
|
||||
track: 'internal',
|
||||
release_status: 'completed',
|
||||
version_name: versionName,
|
||||
)
|
||||
|
||||
slack(
|
||||
message: "Inji - #{versionName} (#{current_build_number}) is uploaded to Play store. Description : #{PLAY_CONSOLE_RELEASE_DESCRIPTION}.",
|
||||
success: true,
|
||||
slack_url: "#{SLACK_URL}",
|
||||
default_payloads: [:git_branch, :last_git_commit]
|
||||
)
|
||||
end
|
||||
|
||||
desc "Deploy an Beta version to the Google Play"
|
||||
lane :android_build_beta do
|
||||
|
||||
git_tag = sh('git describe --abbrev=0 --tags --exact-match HEAD').strip
|
||||
|
||||
def convert_tag_to_code(version)
|
||||
parts = version.split('.')
|
||||
version_code = parts[0].to_i * 1000000 + parts[1].to_i * 1000 + parts[2].to_i
|
||||
return version_code
|
||||
end
|
||||
|
||||
versionCode = convert_tag_to_code(git_tag)
|
||||
|
||||
increment_version_code(
|
||||
gradle_file_path: "app/build.gradle",
|
||||
version_code: versionCode
|
||||
)
|
||||
|
||||
versionName = "Inji #{git_tag}"
|
||||
|
||||
gradle(task: "clean bundleBetaRelease")
|
||||
upload_to_play_store(
|
||||
track: 'alpha',
|
||||
release_status: 'completed',
|
||||
version_name: versionName,
|
||||
)
|
||||
|
||||
slack(
|
||||
message: "Inji [Beta]- #{versionName} is uploaded to Play store. Description : #{PLAY_CONSOLE_RELEASE_DESCRIPTION}.",
|
||||
success: true,
|
||||
slack_url: "#{SLACK_URL}",
|
||||
default_payloads: [:git_branch, :last_git_commit]
|
||||
)
|
||||
end
|
||||
5
android/fastlane/Pluginfile
Normal file
@@ -0,0 +1,5 @@
|
||||
# Autogenerated by fastlane
|
||||
#
|
||||
# Ensure this file is checked in to source control!
|
||||
|
||||
gem 'fastlane-plugin-increment_version_code'
|
||||
45
android/fastlane/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
## fastlane documentation
|
||||
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```sh
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
|
||||
|
||||
# Available Actions
|
||||
|
||||
### android_build_verify
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android_build_verify
|
||||
```
|
||||
|
||||
Verify Build for Android
|
||||
|
||||
### android_build_internal
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android_build_internal
|
||||
```
|
||||
|
||||
Deploy an Internal testing version to the Google Play
|
||||
|
||||
### android_build_beta
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android_build_beta
|
||||
```
|
||||
|
||||
Deploy an Beta version to the Google Play
|
||||
|
||||
---
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
|
||||
|
||||
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
|
||||
|
||||
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
@@ -38,4 +38,7 @@ expo.gif.enabled=true
|
||||
expo.webp.enabled=true
|
||||
# Enable animated webp support (~3.4 MB increase)
|
||||
# Disabled by default because iOS doesn't support animated webp
|
||||
expo.webp.animated=false
|
||||
expo.webp.animated=false
|
||||
|
||||
# If the AsyncStorage_db_size_in_MB is not configured, Default DB_MAX_SIZE is 6MB in Android
|
||||
AsyncStorage_db_size_in_MB=30
|
||||
|
||||
10
android/scripts/beta-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#As react-native/location npm package is old, We need to run this to map androidX source code
|
||||
(cd ../../ && npx jetify)
|
||||
|
||||
cd ..
|
||||
|
||||
yes | sudo gem install bundler
|
||||
|
||||
yes | sudo fastlane install_plugins
|
||||
|
||||
bundle exec fastlane android_build_beta
|
||||
10
android/scripts/git-tag.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
TAG=$(git describe --abbrev=0 --tags --exact-match HEAD 2>/dev/null)
|
||||
|
||||
if [[ -z "$TAG" ]]; then
|
||||
echo "No tag found for the current commit. Please provide a Tag to proceed with the Build."
|
||||
exit 1
|
||||
else
|
||||
echo "Tag for the current commit: $TAG"
|
||||
fi
|
||||
10
android/scripts/internal-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#As react-native/location npm package is old, We need to run this to map androidX source code
|
||||
(cd ../../ && npx jetify)
|
||||
|
||||
cd ..
|
||||
|
||||
yes | sudo gem install bundler
|
||||
|
||||
yes | sudo fastlane install_plugins
|
||||
|
||||
bundle exec fastlane android_build_internal
|
||||
10
android/scripts/verify-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#As react-native/location npm package is old, We need to run this to map androidX source code
|
||||
(cd ../../ && npx jetify)
|
||||
|
||||
cd ..
|
||||
|
||||
yes | sudo gem install bundler
|
||||
|
||||
yes | sudo fastlane install_plugins
|
||||
|
||||
bundle exec fastlane android_build_verify
|
||||
@@ -1,4 +1,4 @@
|
||||
rootProject.name = 'MOSIP Resident App'
|
||||
rootProject.name = 'Inji'
|
||||
|
||||
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
|
||||
useExpoModules()
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
export default {
|
||||
name: 'MOSIP Resident App',
|
||||
slug: 'mosip-resident-app',
|
||||
name: 'Inji',
|
||||
slug: 'inji',
|
||||
version: '1.0.0',
|
||||
orientation: 'portrait',
|
||||
icon: './assets/icon.png',
|
||||
splash: {
|
||||
image: './assets/splash.png',
|
||||
resizeMode: 'contain',
|
||||
resizeMode: 'cover',
|
||||
backgroundColor: '#ffffff',
|
||||
},
|
||||
updates: {
|
||||
|
||||
BIN
assets/Secure-Sharing.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
assets/Secure-Sharing2.png
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
assets/biometric-unlock-icon.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/camera-flip-icon.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/digital-identity-icon.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/features-walkaround-icon.png
Normal file
|
After Width: | Height: | Size: 603 B |
BIN
assets/help-icon.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/icon.png
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 27 KiB |
BIN
assets/inji-home-logo.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/inji-logo-white.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
assets/inji_small_logo.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
assets/intro-scanner.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
assets/intro-wallet-binding.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
assets/legal-notices-icon.png
Normal file
|
After Width: | Height: | Size: 307 B |
BIN
assets/lock-icon.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/magnifier-zoom.png
Normal file
|
After Width: | Height: | Size: 325 B |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 607 B |
BIN
assets/phone_mockup_1.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/progressing-logo.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
assets/receive-card-icon.png
Normal file
|
After Width: | Height: | Size: 674 B |
BIN
assets/received-cards-icon.png
Normal file
|
After Width: | Height: | Size: 652 B |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 22 KiB |
@@ -10,5 +10,8 @@
|
||||
"VC_RECEIVED_BUT_PRESENCE_VERIFICATION_FAILED": "received. Presence verification failed",
|
||||
"PRESENCE_VERIFIED_AND_VC_SHARED": "verified and shared",
|
||||
"PRESENCE_VERIFICATION_FAILED": "verification failed",
|
||||
"QRLOGIN_SUCCESFULL": "QRLogin sucessfull"
|
||||
"QRLOGIN_SUCCESFULL": "QRLogin successful",
|
||||
"WALLET_BINDING_SUCCESSFULL": "Activation successful",
|
||||
"WALLET_BINDING_FAILURE": "Activation failed",
|
||||
"VC_REMOVED":"Removed from wallet"
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import * as DateFnsLocale from '../lib/date-fns/locale';
|
||||
import * as DateFnsLocale from 'date-fns/locale';
|
||||
import { ActivityLog } from '../machines/activityLog';
|
||||
import { TextItem } from './ui/TextItem';
|
||||
|
||||
@@ -14,6 +14,7 @@ export const ActivityLogText: React.FC<{ activity: ActivityLog }> = (props) => {
|
||||
<TextItem
|
||||
label={getActionLabel(activity, i18n.language)}
|
||||
text={`${activity.vcLabel} ${t(activity.type)}`}
|
||||
topDivider
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -26,6 +27,6 @@ function getActionLabel(activity: ActivityLog, language: string) {
|
||||
locale: DateFnsLocale[language],
|
||||
}),
|
||||
]
|
||||
.filter((label) => label.trim() !== '')
|
||||
.filter((label) => label?.trim() !== '')
|
||||
.join(' · ');
|
||||
}
|
||||
|
||||
35
components/CopyButton.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Pressable } from 'react-native';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { Text } from './ui';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const CopyButton: React.FC<CopyButtonProps> = ({ content }) => {
|
||||
const { t } = useTranslation('common');
|
||||
const [buttonText, setButtonText] = useState(t('clipboard.copy'));
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={Theme.Styles.iconContainer}
|
||||
onPress={() => {
|
||||
setButtonText(t('clipboard.copied'));
|
||||
setTimeout(() => setButtonText(t('clipboard.copy')), 3000);
|
||||
Clipboard.setString(content);
|
||||
}}>
|
||||
<Icon
|
||||
type={'material'}
|
||||
name={'file-copy'}
|
||||
color={Theme.Colors.Icon}
|
||||
style={{ marginRight: 2 }}
|
||||
size={19}
|
||||
/>
|
||||
<Text style={Theme.TextStyles.semibold}>{buttonText}</Text>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
interface CopyButtonProps {
|
||||
content: string;
|
||||
}
|
||||
@@ -10,15 +10,15 @@ export const DeviceInfoList: React.FC<DeviceInfoProps> = (props) => {
|
||||
<TextItem
|
||||
divider
|
||||
label={props.of === 'receiver' ? t('requestedBy') : t('sentBy')}
|
||||
text={props.deviceInfo.deviceName}
|
||||
text={t(props.deviceInfo.deviceName)}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
interface DeviceInfoProps {
|
||||
of: 'sender' | 'receiver';
|
||||
deviceInfo: DeviceInfo;
|
||||
of?: string;
|
||||
}
|
||||
|
||||
export interface DeviceInfo {
|
||||
|
||||
106
components/DualMessageOverlay.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Dimensions, View } from 'react-native';
|
||||
import { Overlay } from 'react-native-elements';
|
||||
import { Column, Row, Text } from './ui';
|
||||
import { Button } from './ui/Button';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
|
||||
/**
|
||||
* DualMessageOverlay is like MessageOverlay but with two buttons
|
||||
*
|
||||
* NOTE: This has been added for surfacing bugs and needs to be refactored
|
||||
* before use.
|
||||
*/
|
||||
export const DualMessageOverlay: React.FC<DualMessageOverlayProps> = (
|
||||
props
|
||||
) => {
|
||||
const { t } = useTranslation('common');
|
||||
return (
|
||||
<Overlay
|
||||
isVisible={props.isVisible}
|
||||
overlayStyle={Theme.MessageOverlayStyles.overlay}
|
||||
onShow={props.onShow}
|
||||
onBackdropPress={props.onBackdropPress}>
|
||||
<Column
|
||||
width={Dimensions.get('screen').width * 0.8}
|
||||
style={
|
||||
!props.progress
|
||||
? Theme.MessageOverlayStyles.popupOverLay
|
||||
: { height: 230 }
|
||||
}>
|
||||
<Column padding="21" crossAlign="center">
|
||||
{props.title && (
|
||||
<Text
|
||||
align="center"
|
||||
weight="bold"
|
||||
margin="0 0 10 0"
|
||||
color={Theme.Colors.Details}>
|
||||
{props.title}
|
||||
</Text>
|
||||
)}
|
||||
{props.message && (
|
||||
<Text
|
||||
align="center"
|
||||
weight="semibold"
|
||||
size="small"
|
||||
margin="10 0 0 0"
|
||||
color={Theme.Colors.Details}>
|
||||
{props.message}
|
||||
</Text>
|
||||
)}
|
||||
{props.hint && (
|
||||
<Text
|
||||
size="smaller"
|
||||
color={Theme.Colors.textLabel}
|
||||
margin={[2, 0, 0, 0]}>
|
||||
{props.hint}
|
||||
</Text>
|
||||
)}
|
||||
{props.children}
|
||||
</Column>
|
||||
<Column style={{ marginBottom: 10 }}>
|
||||
<Row style={Theme.MessageOverlayStyles.buttonContainer}>
|
||||
{!props.children && props.onTryAgain ? (
|
||||
<Button
|
||||
title={t('tryAgain')}
|
||||
type="gradient"
|
||||
onPress={props.onTryAgain}
|
||||
styles={{
|
||||
...Theme.MessageOverlayStyles.halfButton,
|
||||
...Theme.ButtonStyles.gradient,
|
||||
width: Dimensions.get('screen').width * 0.36,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{!props.children && props.onIgnore ? (
|
||||
<Button
|
||||
type="gradient"
|
||||
title={t('ignore')}
|
||||
onPress={props.onIgnore}
|
||||
styles={{
|
||||
...Theme.MessageOverlayStyles.halfButton,
|
||||
...Theme.ButtonStyles.gradient,
|
||||
width: Dimensions.get('screen').width * 0.36,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</Row>
|
||||
</Column>
|
||||
</Column>
|
||||
</Overlay>
|
||||
);
|
||||
};
|
||||
|
||||
export interface DualMessageOverlayProps {
|
||||
isVisible: boolean;
|
||||
title?: string;
|
||||
message?: string;
|
||||
progress?: boolean | number;
|
||||
requester?: boolean;
|
||||
hint?: string;
|
||||
onIgnore?: () => void;
|
||||
onBackdropPress?: () => void;
|
||||
onShow?: () => void;
|
||||
onTryAgain?: () => void;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Dimensions, I18nManager } from 'react-native';
|
||||
import { Icon, ListItem, Overlay, Input } from 'react-native-elements';
|
||||
import { Text, Column, Row, Button } from './ui';
|
||||
@@ -9,22 +9,36 @@ export const EditableListItem: React.FC<EditableListItemProps> = (props) => {
|
||||
const { t } = useTranslation('common');
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [newValue, setNewValue] = useState(props.value);
|
||||
const [overlayOpened, setOverlayOpened] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.credentialRegistryResponse === 'success') {
|
||||
closePopup();
|
||||
}
|
||||
}, [props.credentialRegistryResponse]);
|
||||
|
||||
return (
|
||||
<ListItem bottomDivider onPress={() => setIsEditing(true)}>
|
||||
<ListItem bottomDivider topDivider onPress={() => setIsEditing(true)}>
|
||||
<Icon
|
||||
name={props.Icon}
|
||||
type="antdesign"
|
||||
size={20}
|
||||
style={Theme.Styles.profileIconBg}
|
||||
containerStyle={Theme.Styles.settingsIconBg}
|
||||
type={props.IconType}
|
||||
size={25}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text color={Theme.Colors.profileLabel}>{props.label}</Text>
|
||||
<Text weight="semibold" color={Theme.Colors.profileLabel}>
|
||||
{props.label}
|
||||
</Text>
|
||||
</ListItem.Title>
|
||||
<Text color={Theme.Colors.profileValue}>{props.value}</Text>
|
||||
</ListItem.Content>
|
||||
<Text color={Theme.Colors.profileValue}>{props.value}</Text>
|
||||
<Icon
|
||||
name="chevron-right"
|
||||
size={21}
|
||||
color={Theme.Colors.profileLanguageValue}
|
||||
/>
|
||||
<Overlay
|
||||
overlayStyle={{ padding: 24, elevation: 6 }}
|
||||
isVisible={isEditing}
|
||||
@@ -35,13 +49,25 @@ export const EditableListItem: React.FC<EditableListItemProps> = (props) => {
|
||||
autoFocus
|
||||
value={newValue}
|
||||
onChangeText={setNewValue}
|
||||
selectionColor={Theme.Colors.Cursor}
|
||||
inputStyle={{
|
||||
textAlign: I18nManager.isRTL ? 'right' : 'left',
|
||||
}}
|
||||
/>
|
||||
{props.credentialRegistryResponse === 'error' && (
|
||||
<Text style={Theme.TextStyles.error}>{props.errorMessage}</Text>
|
||||
)}
|
||||
{props.credentialRegistryResponse === 'success' &&
|
||||
overlayOpened &&
|
||||
closePopup()}
|
||||
<Row>
|
||||
<Button fill type="clear" title={t('cancel')} onPress={dismiss} />
|
||||
<Button fill title={t('save')} onPress={edit} />
|
||||
<Button
|
||||
fill
|
||||
title={t('save')}
|
||||
onPress={edit}
|
||||
loading={props.progress}
|
||||
/>
|
||||
</Row>
|
||||
</Column>
|
||||
</Overlay>
|
||||
@@ -50,12 +76,20 @@ export const EditableListItem: React.FC<EditableListItemProps> = (props) => {
|
||||
|
||||
function edit() {
|
||||
props.onEdit(newValue);
|
||||
setIsEditing(false);
|
||||
if (props.credentialRegistryResponse === undefined) {
|
||||
setIsEditing(false);
|
||||
}
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
setNewValue(props.value);
|
||||
setIsEditing(false);
|
||||
props.onCancel();
|
||||
}
|
||||
|
||||
function closePopup() {
|
||||
setIsEditing(false);
|
||||
setOverlayOpened(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -63,5 +97,11 @@ interface EditableListItemProps {
|
||||
label: string;
|
||||
value: string;
|
||||
Icon: string;
|
||||
IconType?: string;
|
||||
onEdit: (newValue: string) => void;
|
||||
display?: 'none' | 'flex';
|
||||
credentialRegistryResponse: string;
|
||||
onCancel: () => void;
|
||||
progress?: boolean;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
79
components/HelpScreen.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Pressable } from 'react-native';
|
||||
import { Modal } from './ui/Modal';
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
import { MainRouteProps } from '../routes/main';
|
||||
import { Column, Text } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
|
||||
export const HelpScreen: React.FC<HelpScreenProps & MainRouteProps> = (
|
||||
props
|
||||
) => {
|
||||
const { t } = useTranslation('HelpScreen');
|
||||
|
||||
const [showHelpPage, setShowHelpPage] = useState(false);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setShowHelpPage(!showHelpPage);
|
||||
}}>
|
||||
{props.triggerComponent}
|
||||
</Pressable>
|
||||
<Modal
|
||||
isVisible={showHelpPage}
|
||||
headerTitle={t('header')}
|
||||
headerElevation={2}
|
||||
onDismiss={() => {
|
||||
setShowHelpPage(!showHelpPage);
|
||||
}}>
|
||||
<ScrollView>
|
||||
<Column fill padding="10" align="space-between">
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('whatIsDigitalCredential?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-1')}</Text>
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('whatCanDoWithDigitalCredential?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-2')}</Text>
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('howToAddCard?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-3')}</Text>
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('howToRemoveCardFromWallet?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-4')}</Text>
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('canWeAddMultipleCards?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-5')}</Text>
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('howToShareCard?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-6')}</Text>
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('howToActivateCardForOnlineLogin?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-7')}</Text>
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('howToViewActivity?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-8')}</Text>
|
||||
<Text margin="7" style={Theme.TextStyles.header}>
|
||||
{t('whatCanDoBiometricsChanged?')}
|
||||
</Text>
|
||||
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-9')}</Text>
|
||||
</Column>
|
||||
</ScrollView>
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
interface HelpScreenProps {
|
||||
triggerComponent: React.ReactElement;
|
||||
}
|
||||
94
components/KebabPopUp.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import React from 'react';
|
||||
import { Icon, ListItem, Overlay } from 'react-native-elements';
|
||||
import { Theme } from '../components/ui/styleUtils';
|
||||
import { Column, Row, Text } from '../components/ui';
|
||||
import { WalletBinding } from '../screens/Home/MyVcs/WalletBinding';
|
||||
import { Pressable } from 'react-native';
|
||||
import { useKebabPopUp } from './KebabPopUpController';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { vcItemMachine } from '../machines/vcItem';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { HistoryTab } from '../screens/Home/MyVcs/HistoryTab';
|
||||
import { RemoveVcWarningOverlay } from '../screens/Home/MyVcs/RemoveVcWarningOverlay';
|
||||
|
||||
export const KebabPopUp: React.FC<KebabPopUpProps> = (props) => {
|
||||
const controller = useKebabPopUp(props);
|
||||
const { t } = useTranslation('HomeScreenKebabPopUp');
|
||||
return (
|
||||
<Column>
|
||||
<Icon
|
||||
name={props.iconName}
|
||||
type={props.iconType}
|
||||
color={Theme.Colors.GrayIcon}
|
||||
/>
|
||||
<Overlay
|
||||
isVisible={props.isVisible}
|
||||
onBackdropPress={props.onDismiss}
|
||||
overlayStyle={Theme.KebabPopUpStyles.kebabPopUp}>
|
||||
<Row style={Theme.KebabPopUpStyles.kebabHeaderStyle}>
|
||||
<Text weight="bold">{t('title')}</Text>
|
||||
<Icon
|
||||
name="close"
|
||||
onPress={props.onDismiss}
|
||||
color={Theme.Colors.Details}
|
||||
size={25}
|
||||
/>
|
||||
</Row>
|
||||
<Column>
|
||||
<ListItem bottomDivider>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Pressable onPress={controller.PIN_CARD}>
|
||||
<Text size="small" weight="bold">
|
||||
{props.vcKey.split(':')[4] == 'true'
|
||||
? t('unPinCard')
|
||||
: t('pinCard')}
|
||||
</Text>
|
||||
</Pressable>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
|
||||
<WalletBinding
|
||||
label={t('offlineAuthenticationDisabled!')}
|
||||
content={t('offlineAuthDisabledMessage')}
|
||||
service={props.service}
|
||||
/>
|
||||
|
||||
<HistoryTab
|
||||
service={props.service}
|
||||
label={t('viewActivityLog')}
|
||||
vcKey={props.vcKey}
|
||||
/>
|
||||
|
||||
<ListItem bottomDivider>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Pressable onPress={() => controller.REMOVE(props.vcKey)}>
|
||||
<Text size="small" weight="bold">
|
||||
{t('removeFromWallet')}
|
||||
</Text>
|
||||
</Pressable>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
|
||||
<RemoveVcWarningOverlay
|
||||
isVisible={controller.isRemoveWalletWarning}
|
||||
onConfirm={controller.CONFIRM}
|
||||
onCancel={controller.CANCEL}
|
||||
/>
|
||||
</Column>
|
||||
</Overlay>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export interface KebabPopUpProps {
|
||||
iconName: string;
|
||||
iconType?: string;
|
||||
vcKey: string;
|
||||
isVisible: boolean;
|
||||
onDismiss: () => void;
|
||||
service: ActorRefFrom<typeof vcItemMachine>;
|
||||
}
|
||||
80
components/KebabPopUpController.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import {
|
||||
selectKebabPopUpWalletBindingInProgress,
|
||||
selectKebabPopUp,
|
||||
selectKebabPopUpAcceptingBindingOtp,
|
||||
selectKebabPopUpBindingWarning,
|
||||
selectRemoveWalletWarning,
|
||||
selectEmptyWalletBindingId,
|
||||
selectIsPinned,
|
||||
selectOtpError,
|
||||
selectShowWalletBindingError,
|
||||
selectWalletBindingError,
|
||||
VcItemEvents,
|
||||
vcItemMachine,
|
||||
selectShowActivities,
|
||||
} from '../machines/vcItem';
|
||||
import { selectActivities } from '../machines/activityLog';
|
||||
import { GlobalContext } from '../shared/GlobalContext';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export function useKebabPopUp(props) {
|
||||
const service = props.service as ActorRefFrom<typeof vcItemMachine>;
|
||||
const PIN_CARD = () => service.send(VcItemEvents.PIN_CARD());
|
||||
const KEBAB_POPUP = () => service.send(VcItemEvents.KEBAB_POPUP());
|
||||
const ADD_WALLET_BINDING_ID = () =>
|
||||
service.send(VcItemEvents.ADD_WALLET_BINDING_ID());
|
||||
const CONFIRM = () => service.send(VcItemEvents.CONFIRM());
|
||||
const REMOVE = (vcKey: string) => service.send(VcItemEvents.REMOVE(vcKey));
|
||||
const DISMISS = () => service.send(VcItemEvents.DISMISS());
|
||||
const CANCEL = () => service.send(VcItemEvents.CANCEL());
|
||||
const SHOW_ACTIVITY = () => service.send(VcItemEvents.SHOW_ACTIVITY());
|
||||
const INPUT_OTP = (otp: string) => service.send(VcItemEvents.INPUT_OTP(otp));
|
||||
const isPinned = useSelector(service, selectIsPinned);
|
||||
const isBindingWarning = useSelector(service, selectKebabPopUpBindingWarning);
|
||||
const isRemoveWalletWarning = useSelector(service, selectRemoveWalletWarning);
|
||||
const isAcceptingOtpInput = useSelector(
|
||||
service,
|
||||
selectKebabPopUpAcceptingBindingOtp
|
||||
);
|
||||
const isWalletBindingError = useSelector(
|
||||
service,
|
||||
selectShowWalletBindingError
|
||||
);
|
||||
const otpError = useSelector(service, selectOtpError);
|
||||
const walletBindingError = useSelector(service, selectWalletBindingError);
|
||||
const WalletBindingInProgress = useSelector(
|
||||
service,
|
||||
selectKebabPopUpWalletBindingInProgress
|
||||
);
|
||||
const emptyWalletBindingId = useSelector(service, selectEmptyWalletBindingId);
|
||||
const isKebabPopUp = useSelector(service, selectKebabPopUp);
|
||||
const isShowActivities = useSelector(service, selectShowActivities);
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const activityLogService = appService.children.get('activityLog');
|
||||
|
||||
return {
|
||||
isPinned,
|
||||
PIN_CARD,
|
||||
KEBAB_POPUP,
|
||||
ADD_WALLET_BINDING_ID,
|
||||
CONFIRM,
|
||||
DISMISS,
|
||||
REMOVE,
|
||||
CANCEL,
|
||||
INPUT_OTP,
|
||||
SHOW_ACTIVITY,
|
||||
isBindingWarning,
|
||||
isAcceptingOtpInput,
|
||||
isWalletBindingError,
|
||||
walletBindingError,
|
||||
otpError,
|
||||
WalletBindingInProgress,
|
||||
emptyWalletBindingId,
|
||||
isKebabPopUp,
|
||||
isShowActivities,
|
||||
isRemoveWalletWarning,
|
||||
activities: useSelector(activityLogService, selectActivities),
|
||||
};
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { SUPPORTED_LANGUAGES } from '../i18n';
|
||||
import { I18nManager, View } from 'react-native';
|
||||
import { Picker } from './ui/Picker';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import Storage from '../shared/storage';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18next from 'i18next';
|
||||
import RNRestart from 'react-native-restart';
|
||||
@@ -16,7 +16,7 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = (props) => {
|
||||
const changeLanguage = async (language: string) => {
|
||||
if (language !== i18n.language) {
|
||||
await i18n.changeLanguage(language).then(async () => {
|
||||
await AsyncStorage.setItem('language', i18n.language);
|
||||
await Storage.setItem('language', i18n.language);
|
||||
const isRTL = i18next.dir(language) === 'rtl' ? true : false;
|
||||
if (isRTL !== I18nManager.isRTL) {
|
||||
try {
|
||||
|
||||
@@ -7,7 +7,7 @@ export const Logo: React.FC<LogoProps> = (props) => {
|
||||
<View>
|
||||
<Image
|
||||
style={{ resizeMode: 'contain', ...props }}
|
||||
source={Theme.MosipLogo}
|
||||
source={Theme.MosipSplashLogo}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -14,14 +14,33 @@ export const MessageOverlay: React.FC<MessageOverlayProps> = (props) => {
|
||||
overlayStyle={Theme.MessageOverlayStyles.overlay}
|
||||
onShow={props.onShow}
|
||||
onBackdropPress={props.onBackdropPress}>
|
||||
<Column width={Dimensions.get('screen').width * 0.8}>
|
||||
<Column padding="24">
|
||||
<Column
|
||||
width={Dimensions.get('screen').width * 0.8}
|
||||
style={
|
||||
!props.progress
|
||||
? Theme.MessageOverlayStyles.popupOverLay
|
||||
: { height: 100 }
|
||||
}>
|
||||
<Column padding="21" crossAlign="center">
|
||||
{props.title && (
|
||||
<Text weight="semibold" margin="0 0 12 0">
|
||||
<Text
|
||||
align="center"
|
||||
weight="bold"
|
||||
margin="0 0 10 0"
|
||||
color={Theme.Colors.Details}>
|
||||
{props.title}
|
||||
</Text>
|
||||
)}
|
||||
{props.message && <Text margin="0 0 12 0">{props.message}</Text>}
|
||||
{props.message && (
|
||||
<Text
|
||||
align="center"
|
||||
weight="semibold"
|
||||
size="small"
|
||||
margin="10 0 12 0"
|
||||
color={Theme.Colors.Details}>
|
||||
{props.message}
|
||||
</Text>
|
||||
)}
|
||||
{props.progress && <Progress progress={props.progress} />}
|
||||
{props.hint && (
|
||||
<Text
|
||||
@@ -35,6 +54,7 @@ export const MessageOverlay: React.FC<MessageOverlayProps> = (props) => {
|
||||
</Column>
|
||||
{!props.children && props.onCancel ? (
|
||||
<Button
|
||||
type="gradient"
|
||||
title={t('cancel')}
|
||||
onPress={props.onCancel}
|
||||
styles={Theme.MessageOverlayStyles.button}
|
||||
@@ -45,6 +65,31 @@ export const MessageOverlay: React.FC<MessageOverlayProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const ErrorMessageOverlay: React.FC<ErrorMessageOverlayProps> = ({
|
||||
isVisible,
|
||||
error,
|
||||
onDismiss,
|
||||
translationPath,
|
||||
}) => {
|
||||
const { t } = useTranslation(translationPath);
|
||||
|
||||
return (
|
||||
<MessageOverlay
|
||||
isVisible={isVisible}
|
||||
title={t(error + '.title')}
|
||||
message={t(error + '.message')}
|
||||
onBackdropPress={onDismiss}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export interface ErrorMessageOverlayProps {
|
||||
isVisible: boolean;
|
||||
error?: string;
|
||||
onDismiss?: () => void;
|
||||
translationPath: string;
|
||||
}
|
||||
|
||||
const Progress: React.FC<Pick<MessageOverlayProps, 'progress'>> = (props) => {
|
||||
return typeof props.progress === 'boolean' ? (
|
||||
props.progress && (
|
||||
@@ -60,6 +105,7 @@ export interface MessageOverlayProps {
|
||||
title?: string;
|
||||
message?: string;
|
||||
progress?: boolean | number;
|
||||
requester?: boolean;
|
||||
hint?: string;
|
||||
onCancel?: () => void;
|
||||
onBackdropPress?: () => void;
|
||||
|
||||
@@ -23,6 +23,7 @@ export const Passcode: React.FC<PasscodeProps> = (props) => {
|
||||
onSuccess={props.onSuccess}
|
||||
onError={props.onError}
|
||||
passcode={props.storedPasscode}
|
||||
salt={props.salt}
|
||||
/>
|
||||
</Column>
|
||||
<Column fill>
|
||||
@@ -39,6 +40,7 @@ interface PasscodeProps {
|
||||
message?: string;
|
||||
error: string;
|
||||
storedPasscode: string;
|
||||
salt: string;
|
||||
onSuccess: () => void;
|
||||
onError: (value: string) => void;
|
||||
onDismiss: () => void;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PinInput } from './PinInput';
|
||||
import { hashData } from '../shared/commonUtil';
|
||||
import { argon2iConfig } from '../shared/constants';
|
||||
|
||||
export const MAX_PIN = 6;
|
||||
|
||||
@@ -16,8 +18,9 @@ export const PasscodeVerify: React.FC<PasscodeVerifyProps> = (props) => {
|
||||
|
||||
return <PinInput length={MAX_PIN} onDone={verify} />;
|
||||
|
||||
function verify(value: string) {
|
||||
if (props.passcode === value) {
|
||||
async function verify(value: string) {
|
||||
const hashedPasscode = await hashData(value, props.salt, argon2iConfig);
|
||||
if (props.passcode === hashedPasscode) {
|
||||
setIsVerified(true);
|
||||
} else {
|
||||
props.onError(t('passcodeMismatchError'));
|
||||
@@ -29,4 +32,5 @@ interface PasscodeVerifyProps {
|
||||
passcode: string;
|
||||
onSuccess: () => void;
|
||||
onError?: (error: string) => void;
|
||||
salt: string;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ export const PinInput: React.FC<PinInputProps> = (props) => {
|
||||
selectTextOnFocus
|
||||
keyboardType="numeric"
|
||||
maxLength={1}
|
||||
secureTextEntry
|
||||
selectionColor={Theme.Colors.inputSelection}
|
||||
style={Theme.PinInputStyle.input}
|
||||
key={index}
|
||||
|
||||
75
components/ProgressingModal.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Centered, Column, Text } from './ui';
|
||||
import { Modal } from './ui/Modal';
|
||||
import { Image } from 'react-native';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import PaginationDot from 'react-native-animated-pagination-dot';
|
||||
|
||||
export const ProgressingModal: React.FC<ProgressingModalProps> = (props) => {
|
||||
const { t } = useTranslation('ScanScreen');
|
||||
|
||||
let n = 0;
|
||||
const [curPage, setCurPage] = useState(n);
|
||||
|
||||
const highLightDot = () => setCurPage(n + 1);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Modal
|
||||
isVisible={props.isVisible}
|
||||
headerLeft={t(props.title)}
|
||||
onDismiss={props.onCancel}
|
||||
headerLabel={props.label}
|
||||
headerElevation={3}
|
||||
requester={props.requester}>
|
||||
<Centered crossAlign="center" fill>
|
||||
<Column margin="24 0" align="space-around">
|
||||
<Image
|
||||
source={Theme.InjiProgressingLogo}
|
||||
height={2}
|
||||
width={2}
|
||||
style={{ marginBottom: 15, marginLeft: -6 }}
|
||||
/>
|
||||
{props.progress && (
|
||||
<PaginationDot
|
||||
activeDotColor={'black'}
|
||||
curPage={curPage}
|
||||
maxPage={3}
|
||||
/>
|
||||
)}
|
||||
</Column>
|
||||
|
||||
<Column style={{ display: props.hint ? 'flex' : 'none' }}>
|
||||
<Column style={Theme.SelectVcOverlayStyles.timeoutHintContainer}>
|
||||
<Text
|
||||
align="center"
|
||||
color={Theme.Colors.TimoutText}
|
||||
style={Theme.TextStyles.bold}>
|
||||
{props.hint}
|
||||
</Text>
|
||||
{props.onCancel && (
|
||||
<Button
|
||||
type="clear"
|
||||
title={t('common:cancel')}
|
||||
onPress={props.onCancel}
|
||||
/>
|
||||
)}
|
||||
</Column>
|
||||
</Column>
|
||||
</Centered>
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export interface ProgressingModalProps {
|
||||
isVisible: boolean;
|
||||
title?: string;
|
||||
label?: string;
|
||||
hint?: string;
|
||||
onCancel?: () => void;
|
||||
requester?: boolean;
|
||||
progress?: boolean | number;
|
||||
onBackdropPress?: () => void;
|
||||
}
|
||||
64
components/QrCodeOverlay.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Dimensions, Pressable } from 'react-native';
|
||||
import { Icon, Overlay } from 'react-native-elements';
|
||||
import { Centered, Column, Row, Text } from './ui';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { Image } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const QrCodeOverlay: React.FC<QrCodeOverlayProps> = (props) => {
|
||||
const { t } = useTranslation('VcDetails');
|
||||
|
||||
const [isQrOverlayVisible, setIsQrOverlayVisible] = useState(false);
|
||||
|
||||
const toggleQrOverlay = () => setIsQrOverlayVisible(!isQrOverlayVisible);
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Pressable onPress={toggleQrOverlay}>
|
||||
<Row margin="20 0 0 0">
|
||||
<QRCode
|
||||
size={90}
|
||||
value={props.qrCodeDetailes}
|
||||
backgroundColor={Theme.Colors.QRCodeBackgroundColor}
|
||||
/>
|
||||
</Row>
|
||||
<Row
|
||||
align="flex-end"
|
||||
margin="-30 0 0 60"
|
||||
style={Theme.QrCodeStyles.magnifierZoom}>
|
||||
<Image source={Theme.MagnifierZoom} />
|
||||
</Row>
|
||||
</Pressable>
|
||||
<Overlay
|
||||
isVisible={isQrOverlayVisible}
|
||||
onBackdropPress={toggleQrOverlay}
|
||||
overlayStyle={{ padding: 1, borderRadius: 21 }}>
|
||||
<Column style={Theme.QrCodeStyles.expandedQrCode}>
|
||||
<Row pY={20} style={Theme.QrCodeStyles.QrCodeHeader}>
|
||||
<Text align="center" style={Theme.TextStyles.header} weight="bold">
|
||||
{t('qrCodeHeader')}
|
||||
</Text>
|
||||
<Icon
|
||||
name="close"
|
||||
onPress={toggleQrOverlay}
|
||||
color={Theme.Colors.Details}
|
||||
size={32}
|
||||
/>
|
||||
</Row>
|
||||
<Centered pY={30}>
|
||||
<QRCode
|
||||
size={300}
|
||||
value={props.qrCodeDetailes}
|
||||
backgroundColor={Theme.Colors.QRCodeBackgroundColor}
|
||||
/>
|
||||
</Centered>
|
||||
</Column>
|
||||
</Overlay>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
interface QrCodeOverlayProps {
|
||||
qrCodeDetailes: string;
|
||||
}
|
||||
@@ -2,20 +2,28 @@ import React, { useContext, useEffect, useState } from 'react';
|
||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||
import { Camera } from 'expo-camera';
|
||||
import { BarCodeEvent, BarCodeScanner } from 'expo-barcode-scanner';
|
||||
import { Linking, TouchableOpacity, View } from 'react-native';
|
||||
import {
|
||||
Linking,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
Image,
|
||||
Pressable,
|
||||
} from 'react-native';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { Column, Button, Text } from './ui';
|
||||
import { Column, Button, Text, Centered, Row } from './ui';
|
||||
import { GlobalContext } from '../shared/GlobalContext';
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { selectIsActive } from '../machines/app';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useScanLayout } from '../screens/Scan/ScanLayoutController';
|
||||
|
||||
export const QrScanner: React.FC<QrScannerProps> = (props) => {
|
||||
const { t } = useTranslation('QrScanner');
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const [hasPermission, setHasPermission] = useState(null);
|
||||
const [scanned, setScanned] = useState(false);
|
||||
const [type, setType] = useState(Camera.Constants.Type.back);
|
||||
const [cameraType, setCameraType] = useState(Camera.Constants.Type.back);
|
||||
const controller = useScanLayout();
|
||||
|
||||
const isActive = useSelector(appService, selectIsActive);
|
||||
|
||||
@@ -43,24 +51,36 @@ export const QrScanner: React.FC<QrScannerProps> = (props) => {
|
||||
return <View />;
|
||||
}
|
||||
|
||||
if (hasPermission === false) {
|
||||
const CameraDisabledPopUp: React.FC = () => {
|
||||
return (
|
||||
<Column fill align="space-between">
|
||||
<Text align="center" color={Theme.Colors.errorMessage}>
|
||||
{t('missingPermissionText')}
|
||||
</Text>
|
||||
<Button title={t('allowCameraButton')} onPress={openSettings} />
|
||||
</Column>
|
||||
<View>
|
||||
<Row style={Theme.Styles.cameraDisabledPopUp}>
|
||||
<Column>
|
||||
<Text color={Theme.Colors.whiteText} weight="bold">
|
||||
{t('cameraAccessDisabled')}
|
||||
</Text>
|
||||
<Text
|
||||
color={Theme.Colors.whiteText}
|
||||
weight="semibold"
|
||||
size="smaller">
|
||||
{t('cameraPermissionGuideLabel')}
|
||||
</Text>
|
||||
</Column>
|
||||
<Pressable>
|
||||
<Icon
|
||||
name="close"
|
||||
onPress={controller.DISMISS}
|
||||
color={Theme.Colors.whiteText}
|
||||
size={19}
|
||||
/>
|
||||
</Pressable>
|
||||
</Row>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
return (
|
||||
<View>
|
||||
{props.title && (
|
||||
<Text align="center" margin="16 0" color={Theme.Colors.Details}>
|
||||
{props.title}
|
||||
</Text>
|
||||
)}
|
||||
{hasPermission == false && <CameraDisabledPopUp />}
|
||||
<View style={Theme.Styles.scannerContainer}>
|
||||
<Camera
|
||||
style={Theme.Styles.scanner}
|
||||
@@ -68,25 +88,32 @@ export const QrScanner: React.FC<QrScannerProps> = (props) => {
|
||||
barcodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
|
||||
}}
|
||||
onBarCodeScanned={scanned ? undefined : onBarcodeScanned}
|
||||
type={type}
|
||||
type={cameraType}
|
||||
/>
|
||||
</View>
|
||||
<Column margin="24 0">
|
||||
{props.title && (
|
||||
<Text
|
||||
align="center"
|
||||
weight="semibold"
|
||||
style={Theme.TextStyles.base}
|
||||
margin="20 57 0 57">
|
||||
{props.title}
|
||||
</Text>
|
||||
)}
|
||||
<Column margin="18 0" crossAlign="center">
|
||||
<TouchableOpacity
|
||||
style={Theme.Styles.flipIconButton}
|
||||
onPress={() => {
|
||||
setType(
|
||||
type === Camera.Constants.Type.back
|
||||
setCameraType(
|
||||
cameraType === Camera.Constants.Type.back
|
||||
? Camera.Constants.Type.front
|
||||
: Camera.Constants.Type.back
|
||||
);
|
||||
}}>
|
||||
<Icon
|
||||
name="flip-camera-ios"
|
||||
color={Theme.Colors.flipCameraIcon}
|
||||
size={64}
|
||||
/>
|
||||
<Image source={Theme.CameraFlipIcon} />
|
||||
</TouchableOpacity>
|
||||
<Text align="center" weight="semibold" margin="9 0">
|
||||
{t('flipCamera')}
|
||||
</Text>
|
||||
</Column>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
import React, { useContext, useRef } from 'react';
|
||||
import { useInterpret, useSelector } from '@xstate/react';
|
||||
import { Image, ImageBackground, Pressable } from 'react-native';
|
||||
import { CheckBox, Icon } from 'react-native-elements';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import {
|
||||
createVcItemMachine,
|
||||
selectVerifiableCredential,
|
||||
selectGeneratedOn,
|
||||
selectId,
|
||||
vcItemMachine,
|
||||
selectContext,
|
||||
} from '../machines/vcItem';
|
||||
import { Column, Row, Text } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { GlobalContext } from '../shared/GlobalContext';
|
||||
import { RotatingIcon } from './RotatingIcon';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const VerifiedIcon: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="check-circle"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={14}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const getDetails = (arg1, arg2, verifiableCredential) => {
|
||||
if (arg1 === 'Full Name') {
|
||||
return (
|
||||
<Column>
|
||||
<Text color={Theme.Colors.DetailsLabel} size="smaller">
|
||||
{arg1}
|
||||
</Text>
|
||||
<Text
|
||||
numLines={4}
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{!verifiableCredential ? '' : arg2}
|
||||
</Text>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
if (arg1 === 'Status') {
|
||||
return (
|
||||
<Column>
|
||||
<Text size="smaller" color={Theme.Colors.DetailsLabel}>
|
||||
{arg1}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
weight="bold"
|
||||
color={Theme.Colors.Details}
|
||||
size="smaller"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{!verifiableCredential ? '' : arg2}
|
||||
</Text>
|
||||
{!verifiableCredential ? null : <VerifiedIcon />}
|
||||
</Row>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Column>
|
||||
<Text color={Theme.Colors.DetailsLabel} size="smaller">
|
||||
{arg1}
|
||||
</Text>
|
||||
<Text
|
||||
numLines={1}
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{!verifiableCredential ? '' : arg2}
|
||||
</Text>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export const SingleVcItem: React.FC<VcItemProps> = (props) => {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const { t } = useTranslation('VcDetails');
|
||||
|
||||
const machine = useRef(
|
||||
createVcItemMachine(
|
||||
appService.getSnapshot().context.serviceRefs,
|
||||
props.vcKey
|
||||
)
|
||||
);
|
||||
|
||||
const service = useInterpret(machine.current);
|
||||
const context = useSelector(service, selectContext);
|
||||
const verifiableCredential = useSelector(service, selectVerifiableCredential);
|
||||
const uin = useSelector(service, selectId);
|
||||
const generatedOn = useSelector(service, selectGeneratedOn);
|
||||
const fullName = !verifiableCredential
|
||||
? ''
|
||||
: getLocalizedField(verifiableCredential.credentialSubject.fullName);
|
||||
|
||||
const selectableOrCheck = props.selectable ? (
|
||||
<CheckBox
|
||||
checked={props.selected}
|
||||
checkedIcon={<Icon name="radio-button-checked" />}
|
||||
uncheckedIcon={<Icon name="radio-button-unchecked" />}
|
||||
onPress={() => props.onPress(service)}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={Theme.Styles.closeCardBgContainer}
|
||||
onPress={() => props.onPress(service)}>
|
||||
<ImageBackground
|
||||
source={!verifiableCredential ? null : Theme.CloseCard}
|
||||
resizeMode="stretch"
|
||||
borderRadius={4}
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.vertloadingContainer
|
||||
: Theme.Styles.backgroundImageContainer
|
||||
}>
|
||||
<Row style={Theme.Styles.homeCloseCardDetailsHeader}>
|
||||
<Image
|
||||
source={Theme.MosipLogo}
|
||||
style={Theme.Styles.logo}
|
||||
resizeMethod="auto"
|
||||
/>
|
||||
</Row>
|
||||
<Row
|
||||
crossAlign="center"
|
||||
margin="5 0 0 0"
|
||||
style={!verifiableCredential ? Theme.Styles.loadingContainer : null}>
|
||||
<Column
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingContainer
|
||||
: Theme.Styles.closeDetails
|
||||
}>
|
||||
<Image
|
||||
source={
|
||||
!verifiableCredential
|
||||
? Theme.ProfileIcon
|
||||
: { uri: context.credential.biometrics.face }
|
||||
}
|
||||
style={Theme.Styles.closeCardImage}
|
||||
/>
|
||||
|
||||
<Column margin="0 0 0 10" style={{ alignItems: 'flex-start' }}>
|
||||
{getDetails(t('fullName'), fullName, verifiableCredential)}
|
||||
{getDetails(t('uin'), uin, verifiableCredential)}
|
||||
{getDetails(t('generatedOn'), generatedOn, verifiableCredential)}
|
||||
{getDetails(t('status'), t('valid'), verifiableCredential)}
|
||||
</Column>
|
||||
</Column>
|
||||
|
||||
{verifiableCredential ? (
|
||||
selectableOrCheck
|
||||
) : (
|
||||
<RotatingIcon name="sync" color={Theme.Colors.rotatingIcon} />
|
||||
)}
|
||||
</Row>
|
||||
</ImageBackground>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
interface VcItemProps {
|
||||
vcKey: string;
|
||||
margin?: string;
|
||||
selectable?: boolean;
|
||||
selected?: boolean;
|
||||
onPress?: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
onShow?: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
}
|
||||
|
||||
interface LocalizedField {
|
||||
language: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
function getLocalizedField(rawField: string | LocalizedField) {
|
||||
if (typeof rawField === 'string') {
|
||||
return rawField;
|
||||
}
|
||||
try {
|
||||
const locales: LocalizedField[] = JSON.parse(JSON.stringify(rawField));
|
||||
return locales[0].value;
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,13 @@ export const TextEditOverlay: React.FC<EditOverlayProps> = (props) => {
|
||||
<Text weight="semibold" margin="0 0 16 0">
|
||||
{props.label}
|
||||
</Text>
|
||||
<Input autoFocus value={value} onChangeText={setValue} />
|
||||
<Input
|
||||
autoFocus
|
||||
value={value}
|
||||
maxLength={props.maxLength}
|
||||
selectionColor={Theme.Colors.Cursor}
|
||||
onChangeText={setValue}
|
||||
/>
|
||||
<Row>
|
||||
<Button
|
||||
fill
|
||||
@@ -50,4 +56,5 @@ interface EditOverlayProps {
|
||||
value: string;
|
||||
onSave: (value: string) => void;
|
||||
onDismiss: () => void;
|
||||
maxLength?: number | undefined;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import React from 'react';
|
||||
import * as DateFnsLocale from '../lib/date-fns/locale';
|
||||
import * as DateFnsLocale from 'date-fns/locale';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Image, ImageBackground } from 'react-native';
|
||||
import { Image, ImageBackground, View } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { VC, CredentialSubject, LocalizedField } from '../types/vc';
|
||||
import { VC, CredentialSubject } from '../types/vc';
|
||||
import { Button, Column, Row, Text } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { TextItem } from './ui/TextItem';
|
||||
import { VcItemTags } from './VcItemTags';
|
||||
|
||||
const VerifiedIcon: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="check-circle"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={14}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
import VerifiedIcon from './VerifiedIcon';
|
||||
import { getLocalizedField } from '../i18n';
|
||||
import { CREDENTIAL_REGISTRY_EDIT } from 'react-native-dotenv';
|
||||
import { QrCodeOverlay } from './QrCodeOverlay';
|
||||
|
||||
export const VcDetails: React.FC<VcDetailsProps> = (props) => {
|
||||
const { t, i18n } = useTranslation('VcDetails');
|
||||
@@ -33,38 +26,29 @@ export const VcDetails: React.FC<VcDetailsProps> = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Column margin="10">
|
||||
<ImageBackground
|
||||
borderRadius={10}
|
||||
style={Theme.Styles.openCardBgContainer}
|
||||
source={Theme.OpenCard}>
|
||||
<Row style={Theme.Styles.openDetailsHeader}>
|
||||
<Column margin={'0 0 0 10'}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('idType')}
|
||||
</Text>
|
||||
<Text weight="bold" size="smaller" color={Theme.Colors.Details}>
|
||||
{t('nationalCard')}
|
||||
</Text>
|
||||
<Row align="space-between">
|
||||
<Column align="space-evenly" crossAlign="center">
|
||||
<Image
|
||||
source={
|
||||
props.vc?.credential.biometrics?.face
|
||||
? { uri: props.vc?.credential.biometrics.face }
|
||||
: Theme.ProfileIcon
|
||||
}
|
||||
style={Theme.Styles.openCardImage}
|
||||
/>
|
||||
|
||||
<QrCodeOverlay qrCodeDetailes={String(props.vc.credential)} />
|
||||
<Column margin="20 0 0 0">
|
||||
<Image source={Theme.MosipLogo} style={Theme.Styles.logo} />
|
||||
</Column>
|
||||
</Column>
|
||||
<Image source={Theme.MosipLogo} style={Theme.Styles.logo} />
|
||||
</Row>
|
||||
|
||||
<Row style={Theme.Styles.openDetailsContainer}>
|
||||
<Image
|
||||
source={
|
||||
props.vc?.credential.biometrics?.face
|
||||
? { uri: props.vc?.credential.biometrics.face }
|
||||
: Theme.ProfileIcon
|
||||
}
|
||||
style={Theme.Styles.openCardImage}
|
||||
/>
|
||||
|
||||
<Column style={Theme.Styles.labelPartContainer}>
|
||||
<Column fill>
|
||||
<Column align="space-evenly">
|
||||
<Column>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
@@ -80,173 +64,206 @@ export const VcDetails: React.FC<VcDetailsProps> = (props) => {
|
||||
)}
|
||||
</Text>
|
||||
</Column>
|
||||
<Row>
|
||||
<Column>
|
||||
<Column>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('idType')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{t('nationalCard')}
|
||||
</Text>
|
||||
</Column>
|
||||
{uin ? (
|
||||
<Column margin="20 0 0 0">
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('uin')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{uin}
|
||||
</Text>
|
||||
</Column>
|
||||
) : null}
|
||||
|
||||
{uin ? (
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('uin')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{uin}
|
||||
</Text>
|
||||
{vid ? (
|
||||
<Column margin="20 0 0 0">
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('vid')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{vid}
|
||||
</Text>
|
||||
</Column>
|
||||
) : null}
|
||||
<Column margin="20 0 0 0">
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('dateOfBirth')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{new Date(
|
||||
getLocalizedField(
|
||||
props.vc?.verifiableCredential.credentialSubject
|
||||
.dateOfBirth
|
||||
)
|
||||
).toLocaleDateString()}
|
||||
</Text>
|
||||
</Column>
|
||||
</Column>
|
||||
) : null}
|
||||
|
||||
{vid ? (
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('vid')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{vid}
|
||||
</Text>
|
||||
<Column margin="0 0 0 40">
|
||||
<Column>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('gender')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{getLocalizedField(
|
||||
props.vc?.verifiableCredential.credentialSubject.gender
|
||||
)}
|
||||
</Text>
|
||||
</Column>
|
||||
<Column margin="20 0 0 0">
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('generatedOn')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{new Date(props.vc?.generatedOn).toLocaleDateString()}
|
||||
</Text>
|
||||
</Column>
|
||||
<Column margin="20 0 0 0">
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('status')}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{t('valid')}
|
||||
</Text>
|
||||
{props.vc?.isVerified && <VerifiedIcon />}
|
||||
</Row>
|
||||
</Column>
|
||||
<Column margin="20 0 0 0">
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('phoneNumber')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{getLocalizedField(
|
||||
props.vc?.verifiableCredential.credentialSubject.phone
|
||||
)}
|
||||
</Text>
|
||||
</Column>
|
||||
</Column>
|
||||
) : null}
|
||||
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('generatedOn')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{new Date(props.vc?.generatedOn).toLocaleDateString()}
|
||||
</Text>
|
||||
</Column>
|
||||
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('status')}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{t('valid')}
|
||||
</Text>
|
||||
{props.vc?.isVerified && <VerifiedIcon />}
|
||||
</Row>
|
||||
</Column>
|
||||
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('gender')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{getLocalizedField(
|
||||
props.vc?.verifiableCredential.credentialSubject.gender
|
||||
)}
|
||||
</Text>
|
||||
</Column>
|
||||
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('dateOfBirth')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{new Date(
|
||||
getLocalizedField(
|
||||
props.vc?.verifiableCredential.credentialSubject.dateOfBirth
|
||||
)
|
||||
).toLocaleDateString()}
|
||||
</Text>
|
||||
</Column>
|
||||
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('phoneNumber')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{getLocalizedField(
|
||||
props.vc?.verifiableCredential.credentialSubject.phone
|
||||
)}
|
||||
</Text>
|
||||
</Column>
|
||||
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('email')}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
style={
|
||||
props.vc?.verifiableCredential.credentialSubject.email
|
||||
.length > 25
|
||||
? { flex: 1 }
|
||||
: { flex: 0 }
|
||||
}
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{getLocalizedField(
|
||||
props.vc?.verifiableCredential.credentialSubject.email
|
||||
)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Column>
|
||||
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('address')}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
style={{ flex: 1 }}
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{getFullAddress(
|
||||
props.vc?.verifiableCredential.credentialSubject
|
||||
)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Column>
|
||||
</Row>
|
||||
</Column>
|
||||
</Row>
|
||||
<View style={Theme.Styles.hrLine}></View>
|
||||
<Column>
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('email')}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
style={
|
||||
props.vc?.verifiableCredential.credentialSubject.email
|
||||
.length > 25
|
||||
? { flex: 1 }
|
||||
: { flex: 0 }
|
||||
}
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{getLocalizedField(
|
||||
props.vc?.verifiableCredential.credentialSubject.email
|
||||
)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Column>
|
||||
|
||||
<Column style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('address')}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
style={{ flex: 1 }}
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{getFullAddress(
|
||||
props.vc?.verifiableCredential.credentialSubject
|
||||
)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Column>
|
||||
{CREDENTIAL_REGISTRY_EDIT === 'true' && (
|
||||
<Column fill style={Theme.Styles.labelPart}>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.DetailsLabel}>
|
||||
{t('credentialRegistry')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
color={Theme.Colors.Details}>
|
||||
{props.vc?.credentialRegistry}
|
||||
</Text>
|
||||
</Column>
|
||||
)}
|
||||
</Column>
|
||||
<VcItemTags tag={props.vc?.tag} />
|
||||
</ImageBackground>
|
||||
|
||||
@@ -268,58 +285,61 @@ export const VcDetails: React.FC<VcDetailsProps> = (props) => {
|
||||
/>
|
||||
))}
|
||||
|
||||
{props.isBindingPending ? (
|
||||
<Column style={Theme.Styles.openCardBgContainer}>
|
||||
<Row margin={'0 0 5 0'}>
|
||||
<Icon
|
||||
name="shield-alert"
|
||||
color={Theme.Colors.Icon}
|
||||
size={30}
|
||||
type="material-community"
|
||||
/>
|
||||
</Row>
|
||||
|
||||
<Text
|
||||
style={{ flex: 1 }}
|
||||
weight="semibold"
|
||||
size="small"
|
||||
margin={'0 0 5 0'}
|
||||
color={Theme.Colors.Details}>
|
||||
{t('offlineAuthDisabledHeader')}
|
||||
</Text>
|
||||
<Text
|
||||
style={{ flex: 1 }}
|
||||
weight="regular"
|
||||
size="small"
|
||||
margin={'0 0 5 0'}
|
||||
color={Theme.Colors.Details}>
|
||||
{t('offlineAuthDisabledMessage')}
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
title={t('enableVerification')}
|
||||
onPress={props.onBinding}
|
||||
type="radius"
|
||||
/>
|
||||
</Column>
|
||||
) : (
|
||||
<Column style={Theme.Styles.openCardBgContainer}>
|
||||
<Row crossAlign="center">
|
||||
<Icon
|
||||
name="verified-user"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={28}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
{props.activeTab !== 1 ? (
|
||||
props.isBindingPending ? (
|
||||
<Column style={Theme.Styles.openCardBgContainer}>
|
||||
<Row margin={'0 0 5 0'} crossAlign={'center'}>
|
||||
<Icon
|
||||
name="shield-alert"
|
||||
color={Theme.Colors.Icon}
|
||||
size={30}
|
||||
type="material-community"
|
||||
/>
|
||||
<Text
|
||||
style={{ flex: 1 }}
|
||||
weight="semibold"
|
||||
size="small"
|
||||
margin={'0 0 5 0'}
|
||||
color={Theme.Colors.statusLabel}>
|
||||
{t('offlineAuthDisabledHeader')}
|
||||
</Text>
|
||||
</Row>
|
||||
<Text
|
||||
numLines={1}
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
margin="10 10 10 10"
|
||||
children={t('profileAuthenticated')}></Text>
|
||||
</Row>
|
||||
</Column>
|
||||
style={{ flex: 1 }}
|
||||
weight="regular"
|
||||
size="small"
|
||||
margin={'0 0 5 0'}
|
||||
color={Theme.Colors.statusLabel}>
|
||||
{t('offlineAuthDisabledMessage')}
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
title={t('enableVerification')}
|
||||
onPress={props.onBinding}
|
||||
type="radius"
|
||||
/>
|
||||
</Column>
|
||||
) : (
|
||||
<Column style={Theme.Styles.openCardBgContainer}>
|
||||
<Row crossAlign="center">
|
||||
<Icon
|
||||
name="verified-user"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={28}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
<Text
|
||||
numLines={1}
|
||||
color={Theme.Colors.statusLabel}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
margin="10 10 10 10"
|
||||
children={t('profileAuthenticated')}></Text>
|
||||
</Row>
|
||||
</Column>
|
||||
)
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Column>
|
||||
);
|
||||
@@ -329,6 +349,7 @@ interface VcDetailsProps {
|
||||
vc: VC;
|
||||
isBindingPending: boolean;
|
||||
onBinding?: () => void;
|
||||
activeTab?: Number;
|
||||
}
|
||||
|
||||
function getFullAddress(credential: CredentialSubject) {
|
||||
@@ -351,15 +372,3 @@ function getFullAddress(credential: CredentialSubject) {
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
function getLocalizedField(rawField: string | LocalizedField[]) {
|
||||
if (typeof rawField === 'string') {
|
||||
return rawField;
|
||||
}
|
||||
try {
|
||||
const locales: LocalizedField[] = JSON.parse(JSON.stringify(rawField));
|
||||
return locales[0].value;
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useContext, useRef } from 'react';
|
||||
import { useInterpret, useSelector } from '@xstate/react';
|
||||
import { Pressable, Image, ImageBackground, Dimensions } from 'react-native';
|
||||
import { CheckBox, Icon } from 'react-native-elements';
|
||||
import { Pressable } from 'react-native';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import {
|
||||
createVcItemMachine,
|
||||
@@ -11,113 +10,21 @@ import {
|
||||
selectContext,
|
||||
selectTag,
|
||||
selectEmptyWalletBindingId,
|
||||
selectIsSavingFailedInIdle,
|
||||
selectKebabPopUp,
|
||||
} from '../machines/vcItem';
|
||||
import { Column, Row, Text } from './ui';
|
||||
import { VcItemEvents } from '../machines/vcItem';
|
||||
import { ErrorMessageOverlay } from './MessageOverlay';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { RotatingIcon } from './RotatingIcon';
|
||||
import { GlobalContext } from '../shared/GlobalContext';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const VerifiedIcon: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="check-circle"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={14}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
import { LocalizedField } from '../types/vc';
|
||||
import { VcItemTags } from './VcItemTags';
|
||||
|
||||
const getDetails = (arg1, arg2, verifiableCredential) => {
|
||||
if (arg1 === 'Status') {
|
||||
return (
|
||||
<Column>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={
|
||||
!verifiableCredential
|
||||
? Theme.Colors.LoadingDetailsLabel
|
||||
: Theme.Colors.DetailsLabel
|
||||
}>
|
||||
{arg1}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
numLines={1}
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{!verifiableCredential ? '' : arg2}
|
||||
</Text>
|
||||
{!verifiableCredential ? null : <VerifiedIcon />}
|
||||
</Row>
|
||||
</Column>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Column>
|
||||
<Text
|
||||
color={
|
||||
!verifiableCredential
|
||||
? Theme.Colors.LoadingDetailsLabel
|
||||
: Theme.Colors.DetailsLabel
|
||||
}
|
||||
weight="bold"
|
||||
size="smaller">
|
||||
{arg1}
|
||||
</Text>
|
||||
<Text
|
||||
numLines={4}
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{!verifiableCredential ? '' : arg2}
|
||||
</Text>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const WalletVerified: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="verified-user"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={28}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const WalletUnverified: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="shield-alert"
|
||||
color={Theme.Colors.Icon}
|
||||
size={28}
|
||||
type="material-community"
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
import { VcItemContent } from './VcItemContent';
|
||||
import { VcItemActivationStatus } from './VcItemActivationStatus';
|
||||
import { Row } from './ui';
|
||||
import { KebabPopUp } from './KebabPopUp';
|
||||
import { logState } from '../machines/app';
|
||||
|
||||
export const VcItem: React.FC<VcItemProps> = (props) => {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const { t } = useTranslation('VcDetails');
|
||||
const machine = useRef(
|
||||
createVcItemMachine(
|
||||
appService.getSnapshot().context.serviceRefs,
|
||||
@@ -126,179 +33,73 @@ export const VcItem: React.FC<VcItemProps> = (props) => {
|
||||
);
|
||||
|
||||
const service = useInterpret(machine.current, { devTools: __DEV__ });
|
||||
service.subscribe(logState);
|
||||
const context = useSelector(service, selectContext);
|
||||
const verifiableCredential = useSelector(service, selectVerifiableCredential);
|
||||
const emptyWalletBindingId = useSelector(service, selectEmptyWalletBindingId);
|
||||
const isKebabPopUp = useSelector(service, selectKebabPopUp);
|
||||
const DISMISS = () => service.send(VcItemEvents.DISMISS());
|
||||
const KEBAB_POPUP = () => service.send(VcItemEvents.KEBAB_POPUP());
|
||||
const isSavingFailedInIdle = useSelector(service, selectIsSavingFailedInIdle);
|
||||
|
||||
//Assigning the UIN and VID from the VC details to display the idtype label
|
||||
const uin = verifiableCredential?.credentialSubject.UIN;
|
||||
const vid = verifiableCredential?.credentialSubject.VID;
|
||||
const storeErrorTranslationPath = 'errors.savingFailed';
|
||||
|
||||
const generatedOn = useSelector(service, selectGeneratedOn);
|
||||
const fullName = !verifiableCredential
|
||||
? ''
|
||||
: getLocalizedField(verifiableCredential.credentialSubject.fullName);
|
||||
|
||||
const selectableOrCheck = props.selectable ? (
|
||||
<CheckBox
|
||||
checked={props.selected}
|
||||
checkedIcon={<Icon name="radio-button-checked" />}
|
||||
uncheckedIcon={<Icon name="radio-button-unchecked" />}
|
||||
onPress={() => props.onPress(service)}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
const tag = useSelector(service, selectTag);
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
onPress={() => props.onPress(service)}
|
||||
disabled={!verifiableCredential}
|
||||
style={
|
||||
props.selected
|
||||
? Theme.Styles.selectedBindedVc
|
||||
: Theme.Styles.closeCardBgContainer
|
||||
}>
|
||||
<ImageBackground
|
||||
source={!verifiableCredential ? null : Theme.CloseCard}
|
||||
resizeMode="stretch"
|
||||
borderRadius={4}
|
||||
<React.Fragment>
|
||||
<Pressable
|
||||
onPress={() => props.onPress(service)}
|
||||
disabled={!verifiableCredential}
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.vertloadingContainer
|
||||
: Theme.Styles.backgroundImageContainer
|
||||
props.selected
|
||||
? Theme.Styles.selectedBindedVc
|
||||
: Theme.Styles.closeCardBgContainer
|
||||
}>
|
||||
<Row style={Theme.Styles.homeCloseCardDetailsHeader}>
|
||||
<Column>
|
||||
<Text
|
||||
color={
|
||||
!verifiableCredential
|
||||
? Theme.Colors.LoadingDetailsLabel
|
||||
: Theme.Colors.DetailsLabel
|
||||
}
|
||||
weight="bold"
|
||||
size="smaller">
|
||||
{t('idType')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="bold"
|
||||
color={Theme.Colors.Details}
|
||||
size="smaller"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{t('nationalCard')}
|
||||
</Text>
|
||||
</Column>
|
||||
<Image
|
||||
source={Theme.MosipLogo}
|
||||
style={Theme.Styles.logo}
|
||||
resizeMethod="auto"
|
||||
/>
|
||||
</Row>
|
||||
<Row
|
||||
crossAlign="center"
|
||||
margin="5 0 0 0"
|
||||
style={!verifiableCredential ? Theme.Styles.loadingContainer : null}>
|
||||
<Column
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingContainer
|
||||
: Theme.Styles.closeDetails
|
||||
}>
|
||||
<Image
|
||||
source={
|
||||
!verifiableCredential
|
||||
? Theme.ProfileIcon
|
||||
: { uri: context.credential.biometrics.face }
|
||||
}
|
||||
style={Theme.Styles.closeCardImage}
|
||||
/>
|
||||
|
||||
<Column margin="0 0 0 25" style={{ alignItems: 'flex-start' }}>
|
||||
{getDetails(t('fullName'), fullName, verifiableCredential)}
|
||||
{!verifiableCredential
|
||||
? getDetails(t('id'), uin || vid, verifiableCredential)
|
||||
: null}
|
||||
{uin ? getDetails(t('uin'), uin, verifiableCredential) : null}
|
||||
{vid ? getDetails(t('vid'), vid, verifiableCredential) : null}
|
||||
{getDetails(t('generatedOn'), generatedOn, verifiableCredential)}
|
||||
{getDetails(t('status'), t('valid'), verifiableCredential)}
|
||||
</Column>
|
||||
</Column>
|
||||
|
||||
{verifiableCredential ? (
|
||||
selectableOrCheck
|
||||
) : (
|
||||
<RotatingIcon name="sync" color={Theme.Colors.rotatingIcon} />
|
||||
)}
|
||||
</Row>
|
||||
<VcItemTags tag={tag} />
|
||||
</ImageBackground>
|
||||
<Row>
|
||||
{emptyWalletBindingId ? (
|
||||
<Row
|
||||
width={Dimensions.get('screen').width * 0.8}
|
||||
align="space-between"
|
||||
crossAlign="center">
|
||||
<Row crossAlign="center" style={{ flex: 1 }}>
|
||||
{verifiableCredential && <WalletUnverified />}
|
||||
<Text
|
||||
color={Theme.Colors.Details}
|
||||
weight="semibold"
|
||||
size="small"
|
||||
margin="10 33 10 10"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}
|
||||
children={t('offlineAuthDisabledHeader')}></Text>
|
||||
</Row>
|
||||
|
||||
<Pressable>
|
||||
<Icon
|
||||
name="dots-three-horizontal"
|
||||
type="entypo"
|
||||
color={Theme.Colors.GrayIcon}
|
||||
<VcItemContent
|
||||
context={context}
|
||||
verifiableCredential={verifiableCredential}
|
||||
generatedOn={generatedOn}
|
||||
tag={tag}
|
||||
selectable={props.selectable}
|
||||
selected={props.selected}
|
||||
service={service}
|
||||
iconName={props.iconName}
|
||||
iconType={props.iconType}
|
||||
onPress={() => props.onPress(service)}
|
||||
/>
|
||||
{props.isSharingVc ? null : (
|
||||
<Row crossAlign="center">
|
||||
{props.activeTab !== 'receivedVcsTab' &&
|
||||
props.activeTab != 'sharingVcScreen' && (
|
||||
<VcItemActivationStatus
|
||||
verifiableCredential={verifiableCredential}
|
||||
emptyWalletBindingId={emptyWalletBindingId}
|
||||
onPress={() => props.onPress(service)}
|
||||
showOnlyBindedVc={props.showOnlyBindedVc}
|
||||
/>
|
||||
)}
|
||||
<Pressable onPress={KEBAB_POPUP}>
|
||||
<KebabPopUp
|
||||
vcKey={props.vcKey}
|
||||
iconName="dots-three-horizontal"
|
||||
iconType="entypo"
|
||||
isVisible={isKebabPopUp}
|
||||
onDismiss={DISMISS}
|
||||
service={service}
|
||||
/>
|
||||
</Pressable>
|
||||
</Row>
|
||||
) : (
|
||||
<Row
|
||||
width={Dimensions.get('screen').width * 0.8}
|
||||
align="space-between"
|
||||
crossAlign="center">
|
||||
<Row crossAlign="center" style={{ flex: 1 }}>
|
||||
<WalletVerified />
|
||||
<Text
|
||||
color={Theme.Colors.Details}
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
margin="10 10 10 10"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}
|
||||
children={t('profileAuthenticated')}></Text>
|
||||
</Row>
|
||||
|
||||
{props.showOnlyBindedVc ? null : (
|
||||
<Pressable>
|
||||
<Icon
|
||||
name="dots-three-horizontal"
|
||||
type="entypo"
|
||||
color={Theme.Colors.GrayIcon}
|
||||
/>
|
||||
</Pressable>
|
||||
)}
|
||||
</Row>
|
||||
)}
|
||||
</Row>
|
||||
</Pressable>
|
||||
</Pressable>
|
||||
<ErrorMessageOverlay
|
||||
isVisible={isSavingFailedInIdle}
|
||||
error={storeErrorTranslationPath}
|
||||
onDismiss={DISMISS}
|
||||
translationPath={'VcDetails'}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -310,16 +111,8 @@ interface VcItemProps {
|
||||
showOnlyBindedVc?: boolean;
|
||||
onPress?: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
onShow?: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
}
|
||||
|
||||
function getLocalizedField(rawField: string | LocalizedField) {
|
||||
if (typeof rawField === 'string') {
|
||||
return rawField;
|
||||
}
|
||||
try {
|
||||
const locales: LocalizedField[] = JSON.parse(JSON.stringify(rawField));
|
||||
return locales[0].value;
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
activeTab?: string;
|
||||
iconName?: string;
|
||||
iconType?: string;
|
||||
isSharingVc?: boolean;
|
||||
}
|
||||
|
||||
133
components/VcItemActivationStatus.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Dimensions } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { vcItemMachine } from '../machines/vcItem';
|
||||
import { VerifiableCredential } from '../types/vc';
|
||||
import { Row, Text } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
|
||||
const WalletUnverifiedIcon: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="shield-alert"
|
||||
color={Theme.Colors.Icon}
|
||||
size={28}
|
||||
type="material-community"
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const WalletVerifiedIcon: React.FC = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="verified-user"
|
||||
color={Theme.Colors.VerifiedIcon}
|
||||
size={28}
|
||||
containerStyle={{ marginStart: 4, bottom: 1 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const WalletUnverifiedActivationDetails: React.FC<
|
||||
WalletUnVerifiedDetailsProps
|
||||
> = (props) => {
|
||||
const { t } = useTranslation('VcDetails');
|
||||
return (
|
||||
<Row
|
||||
width={Dimensions.get('screen').width * 0.8}
|
||||
align="space-between"
|
||||
crossAlign="center">
|
||||
<Row
|
||||
crossAlign="center"
|
||||
style={{
|
||||
flex: 1,
|
||||
}}>
|
||||
{props.verifiableCredential && <WalletUnverifiedIcon />}
|
||||
<Text
|
||||
color={Theme.Colors.Details}
|
||||
weight="semibold"
|
||||
size="small"
|
||||
margin="10 33 10 10"
|
||||
style={
|
||||
!props.verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.statusLabel
|
||||
}
|
||||
children={t('offlineAuthDisabledHeader')}></Text>
|
||||
</Row>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
const WalletVerifiedActivationDetails: React.FC<WalletVerifiedDetailsProps> = (
|
||||
props
|
||||
) => {
|
||||
const { t } = useTranslation('VcDetails');
|
||||
return (
|
||||
<Row
|
||||
width={Dimensions.get('screen').width * 0.8}
|
||||
align="space-between"
|
||||
crossAlign="center">
|
||||
<Row
|
||||
crossAlign="center"
|
||||
style={{
|
||||
flex: 1,
|
||||
}}>
|
||||
<WalletVerifiedIcon />
|
||||
<Text
|
||||
color={Theme.Colors.statusLabel}
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
margin="10 10 10 10"
|
||||
style={
|
||||
!props.verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}
|
||||
children={t('profileAuthenticated')}></Text>
|
||||
</Row>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export const VcItemActivationStatus: React.FC<VcItemActivationStatusProps> = (
|
||||
props
|
||||
) => {
|
||||
return (
|
||||
<Row>
|
||||
{props.emptyWalletBindingId ? (
|
||||
<WalletUnverifiedActivationDetails
|
||||
verifiableCredential={props.verifiableCredential}
|
||||
onPress={props.onPress}
|
||||
/>
|
||||
) : (
|
||||
<WalletVerifiedActivationDetails
|
||||
verifiableCredential={props.verifiableCredential}
|
||||
showOnlyBindedVc={props.showOnlyBindedVc}
|
||||
onPress={props.onPress}
|
||||
/>
|
||||
)}
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
interface VcItemActivationStatusProps {
|
||||
showOnlyBindedVc: boolean;
|
||||
onPress: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
verifiableCredential: VerifiableCredential;
|
||||
emptyWalletBindingId: boolean;
|
||||
}
|
||||
|
||||
interface WalletVerifiedDetailsProps {
|
||||
showOnlyBindedVc: boolean;
|
||||
onPress: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
verifiableCredential: VerifiableCredential;
|
||||
}
|
||||
|
||||
interface WalletUnVerifiedDetailsProps {
|
||||
onPress: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
verifiableCredential: VerifiableCredential;
|
||||
}
|
||||
205
components/VcItemContent.tsx
Normal file
@@ -0,0 +1,205 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Image, ImageBackground, View } from 'react-native';
|
||||
import { getLocalizedField } from '../i18n';
|
||||
import { VerifiableCredential } from '../types/vc';
|
||||
import { VcItemTags } from './VcItemTags';
|
||||
import VerifiedIcon from './VerifiedIcon';
|
||||
import { Column, Row, Text } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { CheckBox, Icon } from 'react-native-elements';
|
||||
|
||||
const getDetails = (arg1, arg2, verifiableCredential) => {
|
||||
if (arg1 === 'Status') {
|
||||
return (
|
||||
<Column>
|
||||
<Text
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
color={
|
||||
!verifiableCredential
|
||||
? Theme.Colors.LoadingDetailsLabel
|
||||
: Theme.Colors.DetailsLabel
|
||||
}>
|
||||
{arg1}
|
||||
</Text>
|
||||
<Row>
|
||||
<Text
|
||||
numLines={1}
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{!verifiableCredential ? '' : arg2}
|
||||
</Text>
|
||||
{!verifiableCredential ? null : <VerifiedIcon />}
|
||||
</Row>
|
||||
</Column>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Column>
|
||||
<Text
|
||||
color={
|
||||
!verifiableCredential
|
||||
? Theme.Colors.LoadingDetailsLabel
|
||||
: Theme.Colors.DetailsLabel
|
||||
}
|
||||
size="smaller"
|
||||
weight={'bold'}
|
||||
style={Theme.Styles.vcItemLabelHeader}>
|
||||
{arg1}
|
||||
</Text>
|
||||
<Text
|
||||
numLines={4}
|
||||
color={Theme.Colors.Details}
|
||||
weight="bold"
|
||||
size="smaller"
|
||||
style={
|
||||
!verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{!verifiableCredential ? '' : arg2}
|
||||
</Text>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const VcItemContent: React.FC<VcItemContentProps> = (props) => {
|
||||
//Assigning the UIN and VID from the VC details to display the idtype label
|
||||
const uin = props.verifiableCredential?.credentialSubject.UIN;
|
||||
const vid = props.verifiableCredential?.credentialSubject.VID;
|
||||
const fullName = !props.verifiableCredential
|
||||
? ''
|
||||
: getLocalizedField(props.verifiableCredential.credentialSubject.fullName);
|
||||
const { t } = useTranslation('VcDetails');
|
||||
const isvalid = !props.verifiableCredential ? '' : t('valid');
|
||||
const selectableOrCheck = props.selectable ? (
|
||||
<CheckBox
|
||||
checked={props.selected}
|
||||
checkedIcon={<Icon name="radio-button-checked" />}
|
||||
uncheckedIcon={<Icon name="radio-button-unchecked" />}
|
||||
onPress={() => props.onPress()}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<ImageBackground
|
||||
source={!props.verifiableCredential ? null : Theme.CloseCard}
|
||||
resizeMode="stretch"
|
||||
borderRadius={4}
|
||||
style={
|
||||
!props.verifiableCredential
|
||||
? Theme.Styles.vertloadingContainer
|
||||
: Theme.Styles.backgroundImageContainer
|
||||
}>
|
||||
<Column>
|
||||
<Row align="space-between">
|
||||
<Row>
|
||||
<ImageBackground
|
||||
source={
|
||||
!props.verifiableCredential
|
||||
? Theme.ProfileIcon
|
||||
: { uri: props.context.credential.biometrics.face }
|
||||
}
|
||||
style={Theme.Styles.closeCardImage}>
|
||||
{props.iconName && (
|
||||
<Icon
|
||||
name={props.iconName}
|
||||
type={props.iconType}
|
||||
color={Theme.Colors.Icon}
|
||||
style={{ marginLeft: -80 }}
|
||||
/>
|
||||
)}
|
||||
</ImageBackground>
|
||||
<Column margin="0 0 0 10">
|
||||
{getDetails(t('fullName'), fullName, props.verifiableCredential)}
|
||||
|
||||
<Column margin="10 0 0 0">
|
||||
<Text
|
||||
color={
|
||||
!props.verifiableCredential
|
||||
? Theme.Colors.LoadingDetailsLabel
|
||||
: Theme.Colors.DetailsLabel
|
||||
}
|
||||
weight="semibold"
|
||||
size="smaller"
|
||||
align="left">
|
||||
{t('idType')}
|
||||
</Text>
|
||||
<Text
|
||||
weight="semibold"
|
||||
color={Theme.Colors.Details}
|
||||
size="smaller"
|
||||
style={
|
||||
!props.verifiableCredential
|
||||
? Theme.Styles.loadingTitle
|
||||
: Theme.Styles.subtitle
|
||||
}>
|
||||
{t('nationalCard')}
|
||||
</Text>
|
||||
</Column>
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
<Column>
|
||||
{props.verifiableCredential ? selectableOrCheck : null}
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
align="space-between"
|
||||
margin="5 0 0 0"
|
||||
style={
|
||||
!props.verifiableCredential ? Theme.Styles.loadingContainer : null
|
||||
}>
|
||||
<Column>
|
||||
{uin ? getDetails(t('uin'), uin, props.verifiableCredential) : null}
|
||||
{vid ? getDetails(t('vid'), vid, props.verifiableCredential) : null}
|
||||
{!props.verifiableCredential
|
||||
? getDetails(t('id'), uin || vid, props.verifiableCredential)
|
||||
: null}
|
||||
{getDetails(
|
||||
t('generatedOn'),
|
||||
props.generatedOn,
|
||||
props.verifiableCredential
|
||||
)}
|
||||
</Column>
|
||||
<Column>
|
||||
{props.verifiableCredential
|
||||
? getDetails(t('status'), isvalid, props.verifiableCredential)
|
||||
: null}
|
||||
</Column>
|
||||
<Column
|
||||
style={{ display: props.verifiableCredential ? 'flex' : 'none' }}>
|
||||
<Image
|
||||
source={Theme.MosipLogo}
|
||||
style={Theme.Styles.logo}
|
||||
resizeMethod="auto"
|
||||
/>
|
||||
</Column>
|
||||
</Row>
|
||||
</Column>
|
||||
<VcItemTags tag={props.tag} />
|
||||
</ImageBackground>
|
||||
);
|
||||
};
|
||||
|
||||
interface VcItemContentProps {
|
||||
context: any;
|
||||
verifiableCredential: VerifiableCredential;
|
||||
generatedOn: string;
|
||||
tag: string;
|
||||
selectable: boolean;
|
||||
selected: boolean;
|
||||
iconName?: string;
|
||||
iconType?: string;
|
||||
service: any;
|
||||
onPress?: () => void;
|
||||
}
|
||||
16
components/VerifiedIcon.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
|
||||
const VerifiedIcon: React.FC = () => {
|
||||
return (
|
||||
<View style={Theme.Styles.verifiedIconContainer}>
|
||||
<View style={Theme.Styles.verifiedIconInner}>
|
||||
<Icon name="check-circle" color={Theme.Colors.VerifiedIcon} size={14} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default VerifiedIcon;
|
||||
@@ -15,7 +15,7 @@ import { Column, Row, Text } from './ui';
|
||||
import { Theme } from './ui/styleUtils';
|
||||
import { RotatingIcon } from './RotatingIcon';
|
||||
import { GlobalContext } from '../shared/GlobalContext';
|
||||
import { LocalizedField } from '../types/vc';
|
||||
import { getLocalizedField } from '../i18n';
|
||||
|
||||
export const VidItem: React.FC<VcItemProps> = (props) => {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
@@ -105,15 +105,3 @@ interface VcItemProps {
|
||||
selected?: boolean;
|
||||
onPress?: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
}
|
||||
|
||||
function getLocalizedField(rawField: string | LocalizedField) {
|
||||
if (typeof rawField === 'string') {
|
||||
return rawField;
|
||||
}
|
||||
try {
|
||||
const locales: LocalizedField[] = JSON.parse(JSON.stringify(rawField));
|
||||
return locales[0].value;
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,27 +8,30 @@ import { Text } from './Text';
|
||||
import { Theme, Spacing } from './styleUtils';
|
||||
|
||||
export const Button: React.FC<ButtonProps> = (props) => {
|
||||
const type = props.type || 'solid';
|
||||
const type = props.type || 'solid' || 'radius' || 'gradient';
|
||||
const buttonStyle: StyleProp<ViewStyle> = [
|
||||
props.fill ? Theme.ButtonStyles.fill : null,
|
||||
Theme.ButtonStyles[type],
|
||||
{ width: '100%' },
|
||||
{ width: props.width ?? '100%' },
|
||||
];
|
||||
|
||||
const containerStyle: StyleProp<ViewStyle> = [
|
||||
Theme.ButtonStyles.container,
|
||||
!(type === 'gradient') ? Theme.ButtonStyles.container : null,
|
||||
props.disabled ? Theme.ButtonStyles.disabled : null,
|
||||
props.margin ? Theme.spacing('margin', props.margin) : null,
|
||||
type === 'gradient'
|
||||
? props.isVcThere
|
||||
? Theme.ButtonStyles.float
|
||||
: Theme.ButtonStyles.gradient
|
||||
: null,
|
||||
props.styles,
|
||||
];
|
||||
|
||||
const handleOnPress = (event: GestureResponderEvent) => {
|
||||
if (!props.disabled && props.onPress) {
|
||||
props.onPress(event);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
return !(type === 'gradient') ? (
|
||||
<RNEButton
|
||||
buttonStyle={buttonStyle}
|
||||
containerStyle={[
|
||||
@@ -44,6 +47,8 @@ export const Button: React.FC<ButtonProps> = (props) => {
|
||||
color={
|
||||
type === 'solid' || type === 'addId' || type === 'radius'
|
||||
? Theme.Colors.whiteText
|
||||
: type === 'plain'
|
||||
? Theme.Colors.plainText
|
||||
: Theme.Colors.AddIdBtnTxt
|
||||
}>
|
||||
{props.title}
|
||||
@@ -54,6 +59,34 @@ export const Button: React.FC<ButtonProps> = (props) => {
|
||||
onPress={handleOnPress}
|
||||
loading={props.loading}
|
||||
/>
|
||||
) : (
|
||||
<RNEButton
|
||||
buttonStyle={buttonStyle}
|
||||
ViewComponent={require('react-native-linear-gradient').default}
|
||||
linearGradientProps={{
|
||||
colors: !props.disabled
|
||||
? Theme.Colors.GradientColors
|
||||
: Theme.Colors.DisabledColors,
|
||||
}}
|
||||
containerStyle={containerStyle}
|
||||
type={props.type}
|
||||
raised={props.raised}
|
||||
title={
|
||||
<Text
|
||||
style={Theme.TextStyles.bold}
|
||||
color={
|
||||
type === 'solid' || type === 'gradient' || type === 'radius'
|
||||
? Theme.Colors.whiteText
|
||||
: Theme.Colors.DownloadIdBtnTxt
|
||||
}>
|
||||
{props.title}
|
||||
</Text>
|
||||
}
|
||||
style={[buttonStyle]}
|
||||
icon={props.icon}
|
||||
onPress={handleOnPress}
|
||||
loading={props.loading}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -61,11 +94,14 @@ interface ButtonProps {
|
||||
title: string;
|
||||
disabled?: boolean;
|
||||
margin?: Spacing;
|
||||
type?: RNEButtonProps['type'];
|
||||
type?: RNEButtonProps['type'] | 'gradient';
|
||||
isVcThere?: boolean;
|
||||
onPress?: RNEButtonProps['onPress'];
|
||||
fill?: boolean;
|
||||
raised?: boolean;
|
||||
loading?: boolean;
|
||||
icon?: RNEButtonProps['icon'];
|
||||
styles?: StyleProp<ViewStyle>;
|
||||
colors?: (string | number)[];
|
||||
width?: number;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,12 @@ export const Column = createLayout('column');
|
||||
|
||||
export const Centered = createLayout('column', 'center', 'center');
|
||||
|
||||
export const HorizontallyCentered = createLayout(
|
||||
'column',
|
||||
'flex-start',
|
||||
'center'
|
||||
);
|
||||
|
||||
interface LayoutProps {
|
||||
fill?: boolean;
|
||||
align?: FlexStyle['justifyContent'];
|
||||
|
||||
@@ -2,9 +2,13 @@ import React from 'react';
|
||||
import { I18nManager, Modal as RNModal, View } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { Column, Row, Text } from '.';
|
||||
import { useSendVcScreen } from '../../screens/Scan/SendVcScreenController';
|
||||
import { DeviceInfoList } from '../DeviceInfoList';
|
||||
import { ElevationLevel, Theme } from './styleUtils';
|
||||
|
||||
export const Modal: React.FC<ModalProps> = (props) => {
|
||||
const controller = useSendVcScreen();
|
||||
|
||||
return (
|
||||
<RNModal
|
||||
animationType="slide"
|
||||
@@ -19,8 +23,8 @@ export const Modal: React.FC<ModalProps> = (props) => {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginHorizontal: 21,
|
||||
marginVertical: 16,
|
||||
marginHorizontal: 18,
|
||||
marginVertical: 8,
|
||||
}}>
|
||||
{props.headerRight ? (
|
||||
<Icon
|
||||
@@ -34,17 +38,45 @@ export const Modal: React.FC<ModalProps> = (props) => {
|
||||
name="arrow-left"
|
||||
type="material-community"
|
||||
onPress={props.onDismiss}
|
||||
color={Theme.Colors.Details}
|
||||
containerStyle={Theme.Styles.backArrowContainer}
|
||||
color={Theme.Colors.Icon}
|
||||
/>
|
||||
) : null}
|
||||
<Row fill align="center" margin={'5 30 0 0'}>
|
||||
<Text weight="semibold">{props.headerTitle}</Text>
|
||||
<Row
|
||||
fill
|
||||
align={props.headerLeft ? 'flex-start' : 'center'}
|
||||
margin={'16 0 0 0'}>
|
||||
<Column>
|
||||
<Text style={Theme.TextStyles.header}>
|
||||
{props.headerTitle || props.headerLeft}
|
||||
</Text>
|
||||
{!props.requester ? (
|
||||
<Text
|
||||
weight="semibold"
|
||||
style={Theme.TextStyles.small}
|
||||
color={
|
||||
props.headerLabelColor
|
||||
? props.headerLabelColor
|
||||
: Theme.Colors.profileLanguageValue
|
||||
}>
|
||||
{props.headerLabel}
|
||||
</Text>
|
||||
) : (
|
||||
<Text
|
||||
weight="semibold"
|
||||
style={Theme.TextStyles.small}
|
||||
color={Theme.Colors.IconBg}>
|
||||
<DeviceInfoList deviceInfo={controller.receiverInfo} />
|
||||
</Text>
|
||||
)}
|
||||
</Column>
|
||||
</Row>
|
||||
{props.headerRight || props.arrowLeft || (
|
||||
<Icon
|
||||
name="close"
|
||||
onPress={props.onDismiss}
|
||||
color={Theme.Colors.Icon}
|
||||
color={Theme.Colors.Details}
|
||||
size={27}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
@@ -57,10 +89,14 @@ export const Modal: React.FC<ModalProps> = (props) => {
|
||||
|
||||
export interface ModalProps {
|
||||
isVisible: boolean;
|
||||
onDismiss: () => void;
|
||||
requester?: boolean;
|
||||
onDismiss?: () => void;
|
||||
headerTitle?: string;
|
||||
headerElevation?: ElevationLevel;
|
||||
headerLabel?: string;
|
||||
headerLabelColor?: string;
|
||||
headerRight?: React.ReactElement;
|
||||
headerLeft?: React.ReactElement;
|
||||
arrowLeft?: React.ReactElement;
|
||||
onShow?: () => void;
|
||||
}
|
||||
|
||||
69
components/ui/SetupPicker.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Dimensions } from 'react-native';
|
||||
import { Icon, ListItem } from 'react-native-elements';
|
||||
import { Column } from './Layout';
|
||||
import { Text } from './Text';
|
||||
import { Theme } from './styleUtils';
|
||||
|
||||
interface Picker extends React.VFC<PickerProps<unknown>> {
|
||||
<T>(props: PickerProps<T>): ReturnType<React.FC>;
|
||||
}
|
||||
|
||||
export const SetupPicker: Picker = (props: PickerProps<unknown>) => {
|
||||
const [isContentVisible, setIsContentVisible] = useState(false);
|
||||
const [selectedIndex, setSelectedIndex] = useState(-1);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedIndex(
|
||||
props.items.findIndex(({ value }) => value === props.selectedValue)
|
||||
);
|
||||
}, [props.selectedValue]);
|
||||
|
||||
const toggleContent = () => setIsContentVisible(!isContentVisible);
|
||||
|
||||
const selectItem = (index: number) => {
|
||||
setSelectedIndex(index);
|
||||
props.onValueChange(props.items[index].value, index);
|
||||
toggleContent();
|
||||
};
|
||||
|
||||
return (
|
||||
<Column
|
||||
width={Dimensions.get('window').width * 0.8}
|
||||
backgroundColor={Theme.Colors.whiteBackgroundColor}>
|
||||
{props.items.map((item, index) => (
|
||||
<ListItem
|
||||
bottomDivider
|
||||
topDivider={index !== 0}
|
||||
onPress={() => selectItem(index)}
|
||||
key={index}>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title>
|
||||
<Text
|
||||
color={selectedIndex === index ? Theme.Colors.Icon : null}
|
||||
weight={selectedIndex === index ? 'semibold' : 'regular'}>
|
||||
{item.label}
|
||||
</Text>
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
{selectedIndex === index ? (
|
||||
<Icon name="radio-button-checked" color={Theme.Colors.Icon} />
|
||||
) : (
|
||||
<Icon name="radio-button-unchecked" color={Theme.Colors.GrayIcon} />
|
||||
)}
|
||||
</ListItem>
|
||||
))}
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
interface PickerProps<T> {
|
||||
items: PickerItem<T>[];
|
||||
selectedValue: T;
|
||||
onValueChange: (value: T, index: number) => void;
|
||||
}
|
||||
|
||||
interface PickerItem<T> {
|
||||
label: string;
|
||||
value: T;
|
||||
}
|
||||
@@ -28,7 +28,7 @@ interface TextProps {
|
||||
weight?: 'regular' | 'semibold' | 'bold';
|
||||
align?: TextStyle['textAlign'];
|
||||
margin?: Spacing;
|
||||
size?: 'small' | 'smaller' | 'regular';
|
||||
size?: 'small' | 'smaller' | 'regular' | 'large';
|
||||
lineHeight?: number;
|
||||
numLines?: number;
|
||||
style?: StyleProp<TextStyle>;
|
||||
|
||||
@@ -10,10 +10,17 @@ export const TextItem: React.FC<TextItemProps> = (props) => {
|
||||
pX={24}
|
||||
pY={props.label ? 16 : 12}
|
||||
style={{
|
||||
borderBottomColor: Theme.Colors.borderBottomColor,
|
||||
borderBottomWidth: props.divider ? 1 : 0,
|
||||
borderColor: Theme.Colors.borderBottomColor,
|
||||
borderBottomWidth: props.divider ? 2 : 0,
|
||||
borderTopWidth: props.topDivider ? 2 : 0,
|
||||
alignItems: 'flex-start',
|
||||
}}>
|
||||
<Text
|
||||
color={Theme.Colors.textValue}
|
||||
weight={props.label ? 'semibold' : 'regular'}
|
||||
style={{ textAlign: 'left' }}>
|
||||
{props.text}
|
||||
</Text>
|
||||
{props.label && (
|
||||
<Text
|
||||
size="smaller"
|
||||
@@ -23,12 +30,6 @@ export const TextItem: React.FC<TextItemProps> = (props) => {
|
||||
{props.label}
|
||||
</Text>
|
||||
)}
|
||||
<Text
|
||||
color={Theme.Colors.textValue}
|
||||
weight={props.label ? 'semibold' : 'regular'}
|
||||
style={{ textAlign: 'left' }}>
|
||||
{props.text}
|
||||
</Text>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
@@ -37,5 +38,6 @@ interface TextItemProps {
|
||||
text: string;
|
||||
label?: string;
|
||||
divider?: boolean;
|
||||
topDivider?: boolean;
|
||||
margin?: string;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { Text } from './Text';
|
||||
export { Button } from './Button';
|
||||
export { Row, Column, Centered } from './Layout';
|
||||
export { Row, Column, Centered, HorizontallyCentered } from './Layout';
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { DefaultTheme } from './themes/DefaultTheme';
|
||||
import { PurpleTheme } from './themes/PurpleTheme';
|
||||
import { APPLICATION_THEME } from 'react-native-dotenv';
|
||||
|
||||
// To change the theme, CSS theme file has to import and assign it to Theme in line no 6
|
||||
|
||||
export const Theme = DefaultTheme;
|
||||
export const Theme =
|
||||
APPLICATION_THEME.toLowerCase() === 'purple' ? PurpleTheme : DefaultTheme;
|
||||
|
||||
type SpacingXY = [number, number];
|
||||
type SpacingFull = [number, number, number, number];
|
||||
|
||||
@@ -3,21 +3,36 @@ import { Dimensions, StyleSheet, ViewStyle } from 'react-native';
|
||||
import { Spacing } from '../styleUtils';
|
||||
|
||||
const Colors = {
|
||||
Black: '#231F20',
|
||||
Grey: '#B0B0B0',
|
||||
Black: '#000000',
|
||||
Zambezi: '#5F5F5F',
|
||||
Grey: '#C7C7C7',
|
||||
Grey5: '#E0E0E0',
|
||||
Grey6: '#F2F2F2',
|
||||
Gray40: '#666666',
|
||||
Gray44: '#707070',
|
||||
Gray9: '#171717',
|
||||
DimGray: '#737373',
|
||||
Orange: '#F2811D',
|
||||
LightGrey: '#f7f5f0',
|
||||
LightGrey: '#F5F5F5',
|
||||
ShadeOfGrey: '#6F6F6F',
|
||||
White: '#FFFFFF',
|
||||
Red: '#EB5757',
|
||||
Green: '#219653',
|
||||
Red: '#D52929',
|
||||
Green: '#4B9D20',
|
||||
Transparent: 'transparent',
|
||||
Warning: '#f0ad4e',
|
||||
LightOrange: '#fce7e3',
|
||||
GrayText: '#6F6F6F',
|
||||
dorColor: '#CBCBCB',
|
||||
plainText: '#FFD6A7',
|
||||
walletbindingLabel: '#000000',
|
||||
LightOrange: '#FDF1E6',
|
||||
GradientColors: ['#F59B4B', '#E86E04'],
|
||||
DisabledColors: ['#C7C7C7', '#C7C7C7'],
|
||||
TimeoutHintBoxColor: '#FFF7E5',
|
||||
TimoutText: '#8B6105',
|
||||
resendCodeTimer: '#555555',
|
||||
};
|
||||
|
||||
export type ElevationLevel = 0 | 1 | 2 | 3 | 4 | 5;
|
||||
export type ElevationLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
||||
|
||||
export const DefaultTheme = {
|
||||
Colors: {
|
||||
@@ -27,25 +42,32 @@ export const DefaultTheme = {
|
||||
LoadingDetailsLabel: Colors.Orange,
|
||||
AddIdBtnBg: Colors.Orange,
|
||||
AddIdBtnTxt: Colors.Orange,
|
||||
ClearAddIdBtnBg: Colors.Transparent,
|
||||
DownloadIdBtnTxt: Colors.White,
|
||||
Loading: Colors.Orange,
|
||||
Cursor: Colors.Orange,
|
||||
noUinText: Colors.Orange,
|
||||
IconBg: Colors.Orange,
|
||||
popUp: Colors.Green,
|
||||
Icon: Colors.Orange,
|
||||
GrayIcon: Colors.Grey,
|
||||
helpText: Colors.Gray44,
|
||||
borderBottomColor: Colors.Grey6,
|
||||
whiteBackgroundColor: Colors.White,
|
||||
lightGreyBackgroundColor: Colors.LightGrey,
|
||||
profileLanguageValue: Colors.Grey,
|
||||
profileVersion: Colors.Grey,
|
||||
aboutVersion: Colors.Gray40,
|
||||
profileAuthFactorUnlock: Colors.Grey,
|
||||
profileLabel: Colors.Black,
|
||||
profileValue: Colors.Grey,
|
||||
switchHead: Colors.Orange,
|
||||
switchTrackTrue: Colors.LightOrange,
|
||||
switchTrackFalse: Colors.Grey,
|
||||
overlayBackgroundColor: Colors.White,
|
||||
rotatingIcon: Colors.Grey5,
|
||||
loadingLabel: Colors.Grey6,
|
||||
textLabel: Colors.Grey,
|
||||
textValue: Colors.Black,
|
||||
requesterName: Colors.Red,
|
||||
errorMessage: Colors.Red,
|
||||
QRCodeBackgroundColor: Colors.LightGrey,
|
||||
ReceiveVcModalBackgroundColor: Colors.LightGrey,
|
||||
@@ -54,12 +76,28 @@ export const DefaultTheme = {
|
||||
whiteText: Colors.White,
|
||||
flipCameraIcon: Colors.Black,
|
||||
IdInputModalBorder: Colors.Grey,
|
||||
RetrieveIdLabel: Colors.ShadeOfGrey,
|
||||
inputSelection: Colors.Orange,
|
||||
checkCircleIcon: Colors.White,
|
||||
OnboardingCircleIcon: Colors.White,
|
||||
OnboardingCloseIcon: Colors.White,
|
||||
WarningIcon: Colors.Warning,
|
||||
DefaultToggle: Colors.LightOrange,
|
||||
ProfileIconBg: Colors.LightOrange,
|
||||
GrayText: Colors.GrayText,
|
||||
gradientBtn: ['#F59B4B', '#E86E04'],
|
||||
dotColor: Colors.dorColor,
|
||||
plainText: Colors.plainText,
|
||||
IconBackground: Colors.LightOrange,
|
||||
GradientColors: Colors.GradientColors,
|
||||
DisabledColors: Colors.DisabledColors,
|
||||
getVidColor: Colors.Zambezi,
|
||||
TimeoutHintBoxColor: Colors.TimeoutHintBoxColor,
|
||||
TimoutText: Colors.TimoutText,
|
||||
walletbindingLabel: Colors.Black,
|
||||
walletbindingContent: Colors.Gray40,
|
||||
resendCodeTimer: Colors.resendCodeTimer,
|
||||
statusLabel: Colors.Black,
|
||||
},
|
||||
Styles: StyleSheet.create({
|
||||
title: {
|
||||
@@ -78,6 +116,19 @@ export const DefaultTheme = {
|
||||
backgroundColor: Colors.Grey,
|
||||
borderRadius: 4,
|
||||
},
|
||||
statusLabel: {
|
||||
color: Colors.Black,
|
||||
},
|
||||
verifiedIconContainer: {
|
||||
marginLeft: 5,
|
||||
},
|
||||
verifiedIconInner: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 10,
|
||||
},
|
||||
vcItemLabelHeader: {
|
||||
color: Colors.Orange,
|
||||
},
|
||||
closeDetails: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
@@ -89,6 +140,38 @@ export const DefaultTheme = {
|
||||
backgroundColor: Colors.Grey6,
|
||||
borderRadius: 4,
|
||||
},
|
||||
loadingCardDetailsContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.Grey6,
|
||||
borderRadius: 4,
|
||||
},
|
||||
cardDetailsContainer: {},
|
||||
bottomTabIconStyle: {
|
||||
padding: 4,
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 6,
|
||||
backgroundColor: Colors.LightOrange,
|
||||
},
|
||||
downloadingVcPopUp: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: Colors.Green,
|
||||
height: 39,
|
||||
position: 'relative',
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
homeScreenContainer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 10,
|
||||
backgroundColor: '#fff',
|
||||
shadowColor: '#000',
|
||||
shadowOpacity: 0.4,
|
||||
elevation: 5,
|
||||
padding: 10,
|
||||
},
|
||||
vertloadingContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.Grey6,
|
||||
@@ -99,10 +182,11 @@ export const DefaultTheme = {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
logoContainer: {
|
||||
closecardMosipLogo: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
alignSelf: 'flex-end',
|
||||
marginLeft: 300,
|
||||
},
|
||||
closeCardBgContainer: {
|
||||
@@ -116,6 +200,12 @@ export const DefaultTheme = {
|
||||
elevation: 4,
|
||||
},
|
||||
selectedBindedVc: {
|
||||
borderRadius: 15,
|
||||
margin: 5,
|
||||
borderWidth: 3,
|
||||
borderColor: Colors.Green,
|
||||
},
|
||||
selectedVc: {
|
||||
borderRadius: 10,
|
||||
margin: 5,
|
||||
borderWidth: 2,
|
||||
@@ -138,7 +228,7 @@ export const DefaultTheme = {
|
||||
width: 100,
|
||||
},
|
||||
bottomButtonsContainer: {
|
||||
height: 120,
|
||||
height: 'auto',
|
||||
borderTopLeftRadius: 27,
|
||||
borderTopRightRadius: 27,
|
||||
padding: 6,
|
||||
@@ -175,8 +265,6 @@ export const DefaultTheme = {
|
||||
backgroundImageContainer: {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
borderBottomColor: Colors.Grey,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
successTag: {
|
||||
backgroundColor: Colors.Green,
|
||||
@@ -198,13 +286,17 @@ export const DefaultTheme = {
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
logo: {
|
||||
height: 36,
|
||||
width: 30,
|
||||
height: 35,
|
||||
width: 90,
|
||||
},
|
||||
homeCloseCardDetailsHeader: {
|
||||
flex: 1,
|
||||
},
|
||||
cardDetailsHeader: {
|
||||
flex: 1,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
mosipLogoContainer: {},
|
||||
details: {
|
||||
width: 290,
|
||||
marginLeft: 110,
|
||||
@@ -221,6 +313,38 @@ export const DefaultTheme = {
|
||||
borderRadius: 6,
|
||||
backgroundColor: Colors.LightOrange,
|
||||
},
|
||||
IconContainer: {
|
||||
padding: 6,
|
||||
width: 36,
|
||||
marginRight: 4,
|
||||
marginLeft: 10,
|
||||
height: 36,
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.LightOrange,
|
||||
},
|
||||
settingsIconBg: {
|
||||
padding: 6,
|
||||
width: 36,
|
||||
marginRight: 4,
|
||||
height: 36,
|
||||
backgroundColor: Colors.Transparent,
|
||||
},
|
||||
backArrowContainer: {
|
||||
padding: 6,
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.LightOrange,
|
||||
},
|
||||
receiveCardsContainer: {
|
||||
height: Dimensions.get('window').height * 0.12,
|
||||
width: Dimensions.get('window').width * 0.45,
|
||||
alignItems: 'center',
|
||||
borderBottomRightRadius: 0,
|
||||
padding: 15,
|
||||
marginVertical: 18,
|
||||
elevation: 1,
|
||||
},
|
||||
domainVerifiyIcon: {
|
||||
padding: 20,
|
||||
marginLeft: 120,
|
||||
@@ -241,24 +365,46 @@ export const DefaultTheme = {
|
||||
height: 135,
|
||||
borderRadius: 5,
|
||||
},
|
||||
versionContainer: {
|
||||
backgroundColor: Colors.Grey6,
|
||||
margin: 4,
|
||||
borderRadius: 14,
|
||||
},
|
||||
primaryRow: {
|
||||
backgroundColor: Colors.LightOrange,
|
||||
paddingHorizontal: 18,
|
||||
paddingVertical: 9,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
iconContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
scannerContainer: {
|
||||
borderWidth: 4,
|
||||
borderColor: Colors.Black,
|
||||
borderRadius: 32,
|
||||
justifyContent: 'center',
|
||||
height: 300,
|
||||
width: 300,
|
||||
borderRadius: 24,
|
||||
alignSelf: 'center',
|
||||
height: 350,
|
||||
width: 320,
|
||||
overflow: 'hidden',
|
||||
marginLeft: 18,
|
||||
},
|
||||
scanner: {
|
||||
height: 400,
|
||||
width: '100%',
|
||||
margin: 'auto',
|
||||
},
|
||||
flipIconButton: {
|
||||
alignSelf: 'center',
|
||||
cameraDisabledPopUp: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: Colors.Red,
|
||||
height: 75,
|
||||
position: 'relative',
|
||||
paddingHorizontal: 15,
|
||||
marginTop: -36,
|
||||
},
|
||||
photoConsentLabel: {
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
borderWidth: 0,
|
||||
},
|
||||
tabIndicator: {
|
||||
backgroundColor: Colors.Orange,
|
||||
@@ -273,55 +419,134 @@ export const DefaultTheme = {
|
||||
detailsText: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 15,
|
||||
fontFamily: 'Poppins_700Bold',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
},
|
||||
getId: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginTop: 10,
|
||||
marginVertical: 6,
|
||||
},
|
||||
placeholder: {
|
||||
fontFamily: 'Poppins_400Regular',
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
},
|
||||
hrLine: {
|
||||
borderBottomColor: 'black',
|
||||
borderBottomWidth: 1,
|
||||
marginTop: 10,
|
||||
},
|
||||
}),
|
||||
QrCodeStyles: StyleSheet.create({
|
||||
magnifierZoom: {
|
||||
backgroundColor: Colors.White,
|
||||
width: 30,
|
||||
height: 30,
|
||||
alignItems: 'center',
|
||||
padding: 5,
|
||||
borderTopLeftRadius: 11,
|
||||
elevation: 4,
|
||||
},
|
||||
expandedQrCode: {
|
||||
backgroundColor: Colors.White,
|
||||
width: 350,
|
||||
borderRadius: 21,
|
||||
},
|
||||
QrCodeHeader: {
|
||||
backgroundColor: Colors.White,
|
||||
borderTopLeftRadius: 21,
|
||||
borderTopRightRadius: 21,
|
||||
justifyContent: 'space-between',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
paddingBottom: 10,
|
||||
paddingRight: 15,
|
||||
paddingLeft: 130,
|
||||
elevation: 2,
|
||||
},
|
||||
warningText: {
|
||||
color: Colors.Red,
|
||||
fontSize: 18,
|
||||
},
|
||||
}),
|
||||
PinInputStyle: StyleSheet.create({
|
||||
input: {
|
||||
borderBottomWidth: 1,
|
||||
borderBottomWidth: 3,
|
||||
borderColor: Colors.Grey,
|
||||
color: Colors.Black,
|
||||
flex: 1,
|
||||
fontFamily: 'Poppins_600SemiBold',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
height: 40,
|
||||
fontSize: 33,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
height: 60,
|
||||
lineHeight: 28,
|
||||
margin: 8,
|
||||
textAlign: 'center',
|
||||
},
|
||||
onEnteringPin: {
|
||||
borderBottomWidth: 3,
|
||||
borderColor: Colors.Orange,
|
||||
color: Colors.Black,
|
||||
flex: 1,
|
||||
fontFamily: 'Inter_700Bold',
|
||||
fontSize: 29,
|
||||
height: 40,
|
||||
margin: 8,
|
||||
textAlign: 'center',
|
||||
},
|
||||
}),
|
||||
TextStyles: StyleSheet.create({
|
||||
base: {
|
||||
header: {
|
||||
color: Colors.Black,
|
||||
fontFamily: 'Inter_700Bold',
|
||||
fontSize: 18,
|
||||
lineHeight: 22,
|
||||
paddingTop: 4,
|
||||
},
|
||||
retrieveIdLabel: {
|
||||
color: Colors.ShadeOfGrey,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
lineHeight: 18,
|
||||
},
|
||||
helpDetailes: {
|
||||
margin: 5,
|
||||
color: Colors.Gray44,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
},
|
||||
aboutDetailes: {
|
||||
color: Colors.Black,
|
||||
fontSize: 18,
|
||||
lineHeight: 28,
|
||||
margin: 7,
|
||||
lineHeight: 18,
|
||||
},
|
||||
error: {
|
||||
color: Colors.Red,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
fontSize: 12,
|
||||
},
|
||||
base: {
|
||||
color: Colors.Black,
|
||||
fontSize: 16,
|
||||
lineHeight: 18,
|
||||
},
|
||||
regular: {
|
||||
fontFamily: 'Poppins_400Regular',
|
||||
fontFamily: 'Inter_400Regular',
|
||||
fontSize: 14,
|
||||
},
|
||||
semibold: {
|
||||
fontFamily: 'Poppins_600SemiBold',
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
fontSize: 15,
|
||||
},
|
||||
bold: {
|
||||
fontFamily: 'Poppins_700Bold',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
},
|
||||
small: {
|
||||
fontSize: 14,
|
||||
fontSize: 13,
|
||||
lineHeight: 21,
|
||||
},
|
||||
smaller: {
|
||||
fontSize: 12,
|
||||
fontSize: 11,
|
||||
lineHeight: 18,
|
||||
},
|
||||
large: {
|
||||
fontSize: 18,
|
||||
},
|
||||
}),
|
||||
VcItemStyles: StyleSheet.create({
|
||||
title: {
|
||||
@@ -376,15 +601,29 @@ export const DefaultTheme = {
|
||||
borderColor: Colors.Orange,
|
||||
},
|
||||
container: {
|
||||
minHeight: 48,
|
||||
height: 45,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
disabled: {
|
||||
opacity: 0.5,
|
||||
backgroundColor: Colors.Grey,
|
||||
},
|
||||
addId: {
|
||||
backgroundColor: Colors.Orange,
|
||||
},
|
||||
gradient: {
|
||||
borderRadius: 9,
|
||||
width: Dimensions.get('window').width * 0.72,
|
||||
alignSelf: 'center',
|
||||
margin: 4,
|
||||
},
|
||||
float: {
|
||||
borderRadius: 9,
|
||||
alignSelf: 'center',
|
||||
fontSize: 10,
|
||||
elevation: 5,
|
||||
position: 'absolute',
|
||||
bottom: 24,
|
||||
},
|
||||
clearAddIdBtnBg: {
|
||||
backgroundColor: Colors.Transparent,
|
||||
},
|
||||
@@ -404,14 +643,35 @@ export const DefaultTheme = {
|
||||
padding: 32,
|
||||
},
|
||||
}),
|
||||
QRCodeOverlay: StyleSheet.create({
|
||||
header: {},
|
||||
}),
|
||||
SelectVcOverlayStyles: StyleSheet.create({
|
||||
overlay: {
|
||||
elevation: 5,
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
},
|
||||
consentCheckContainer: {
|
||||
backgroundColor: Colors.White,
|
||||
borderWidth: 0,
|
||||
marginTop: -15,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
padding: 0,
|
||||
},
|
||||
timeoutHintContainer: {
|
||||
backgroundColor: Colors.TimeoutHintBoxColor,
|
||||
margin: 21,
|
||||
paddingHorizontal: 14,
|
||||
paddingVertical: 12,
|
||||
borderRadius: 12,
|
||||
},
|
||||
sharedSuccessfully: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.White,
|
||||
},
|
||||
}),
|
||||
CreditsStyles: StyleSheet.create({
|
||||
AppMetaDataStyles: StyleSheet.create({
|
||||
buttonContainer: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
@@ -421,9 +681,23 @@ export const DefaultTheme = {
|
||||
flex: 1,
|
||||
width: Dimensions.get('screen').width,
|
||||
},
|
||||
markdownView: {
|
||||
contentView: {
|
||||
flex: 1,
|
||||
padding: 20,
|
||||
},
|
||||
header: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'normal',
|
||||
color: 'rgb(28,28,30)',
|
||||
},
|
||||
}),
|
||||
FooterStyles: StyleSheet.create({
|
||||
bottom: {
|
||||
justifyContent: 'flex-end',
|
||||
backgroundColor: Colors.Grey6,
|
||||
borderRadius: 15,
|
||||
padding: 10,
|
||||
},
|
||||
}),
|
||||
ModalStyles: StyleSheet.create({
|
||||
modal: {
|
||||
@@ -464,16 +738,44 @@ export const DefaultTheme = {
|
||||
height: Dimensions.get('screen').height,
|
||||
},
|
||||
}),
|
||||
KebabPopUpStyles: StyleSheet.create({
|
||||
kebabPopUp: {
|
||||
borderTopLeftRadius: 15,
|
||||
borderTopRightRadius: 15,
|
||||
width: Dimensions.get('screen').width,
|
||||
marginTop: Dimensions.get('screen').height * 0.55,
|
||||
},
|
||||
kebabHeaderStyle: {
|
||||
justifyContent: 'space-between',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
paddingRight: 15,
|
||||
paddingLeft: 130,
|
||||
paddingTop: 18,
|
||||
},
|
||||
}),
|
||||
MessageOverlayStyles: StyleSheet.create({
|
||||
overlay: {
|
||||
elevation: 5,
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
padding: 5,
|
||||
borderRadius: 10,
|
||||
},
|
||||
buttonContainer: {
|
||||
justifyContent: 'center',
|
||||
marginBottom: 75,
|
||||
},
|
||||
popupOverLay: {
|
||||
height: 150,
|
||||
backgroundColor: Colors.White,
|
||||
},
|
||||
button: {
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
},
|
||||
halfButton: {
|
||||
borderRadius: 8,
|
||||
margin: '0.5%',
|
||||
},
|
||||
}),
|
||||
BindingVcWarningOverlay: StyleSheet.create({
|
||||
overlay: {
|
||||
@@ -631,7 +933,7 @@ export const DefaultTheme = {
|
||||
sliderTitle: {
|
||||
color: Colors.White,
|
||||
marginBottom: 20,
|
||||
fontFamily: 'Poppins_700Bold',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
},
|
||||
text: {
|
||||
color: Colors.White,
|
||||
@@ -651,20 +953,43 @@ export const DefaultTheme = {
|
||||
top: 40,
|
||||
zIndex: 1,
|
||||
},
|
||||
bottomContainer: {
|
||||
padding: 20,
|
||||
borderTopLeftRadius: 30,
|
||||
borderTopRightRadius: 30,
|
||||
marginTop: -185,
|
||||
paddingBottom: 100,
|
||||
},
|
||||
}),
|
||||
claimsContainer: StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: Colors.Transparent,
|
||||
},
|
||||
}),
|
||||
OpenCard: require('../../../assets/ID-open.png'),
|
||||
CloseCard: require('../../../assets/ID-closed.png'),
|
||||
OpenCard: '',
|
||||
CloseCard: '',
|
||||
ProfileIcon: require('../../../assets/placeholder-photo.png'),
|
||||
MosipSplashLogo: require('../../../assets/icon.png'),
|
||||
MosipLogo: require('../../../assets/mosip-logo.png'),
|
||||
CameraFlipIcon: require('../../../assets/camera-flip-icon.png'),
|
||||
DomainWarningLogo: require('../../../assets/domain-warning.png'),
|
||||
WarningLogo: require('../../../assets/warningLogo.png'),
|
||||
OtpLogo: require('../../../assets/otp-mobile-logo.png'),
|
||||
SuccessLogo: require('../../../assets/success-logo.png'),
|
||||
ReceiveCardIcon: require('../../../assets/receive-card-icon.png'),
|
||||
ReceivedCardsIcon: require('../../../assets/received-cards-icon.png'),
|
||||
DigitalIdentityLogo: require('../../../assets/digital-identity-icon.png'),
|
||||
InjiLogoWhite: require('../../../assets/inji-logo-white.png'),
|
||||
InjiProgressingLogo: require('../../../assets/progressing-logo.png'),
|
||||
LockIcon: require('../../../assets/lock-icon.png'),
|
||||
InjiHomeLogo: require('../../../assets/inji-home-logo.png'),
|
||||
MagnifierZoom: require('../../../assets/magnifier-zoom.png'),
|
||||
HelpIcon: require('../../../assets/help-icon.png'),
|
||||
sharingIntro: require('../../../assets/Secure-Sharing.png'),
|
||||
walletIntro: require('../../../assets/intro-wallet-binding.png'),
|
||||
IntroScanner: require('../../../assets/intro-scanner.png'),
|
||||
injiSmallLogo: require('../../../assets/inji_small_logo.png'),
|
||||
protectPrivacy: require('../../../assets/phone_mockup_1.png'),
|
||||
|
||||
elevation(level: ElevationLevel): ViewStyle {
|
||||
// https://ethercreative.github.io/react-native-shadow-generator/
|
||||
|
||||
@@ -4,48 +4,72 @@ import { Spacing } from '../styleUtils';
|
||||
|
||||
const Colors = {
|
||||
Black: '#231F20',
|
||||
Zambezi: '#5F5F5F',
|
||||
Grey: '#B0B0B0',
|
||||
Grey5: '#E0E0E0',
|
||||
Grey6: '#F2F2F2',
|
||||
Gray40: '#666666',
|
||||
Gray44: '#707070',
|
||||
Gray9: '#171717',
|
||||
DimGray: '#737373',
|
||||
Orange: '#F2811D',
|
||||
LightOrange: '#FDF1E6',
|
||||
LightGrey: '#FAF9FF',
|
||||
ShadeOfGrey: '#6F6F6F',
|
||||
White: '#FFFFFF',
|
||||
Red: '#EB5757',
|
||||
Green: '#219653',
|
||||
Purple: '#70308C',
|
||||
Transparent: 'transparent',
|
||||
Warning: '#f0ad4e',
|
||||
GrayText: '#6F6F6F',
|
||||
dorColor: '#CBCBCB',
|
||||
plainText: '#FFD6A7',
|
||||
walletbindingLabel: '#000000',
|
||||
GradientColors: ['#373086', '#70308C'],
|
||||
DisabledColors: ['#C7C7C7', '#C7C7C7'],
|
||||
Purple: '#70308C',
|
||||
LightPurple: '#AEA7FF',
|
||||
TimeoutHintBoxColor: '#FFF7E5',
|
||||
TimoutText: '#8B6105',
|
||||
resendCodeTimer: '#555555',
|
||||
};
|
||||
|
||||
export type ElevationLevel = 0 | 1 | 2 | 3 | 4 | 5;
|
||||
export type ElevationLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
||||
|
||||
export const PurpleTheme = {
|
||||
Colors: {
|
||||
TabItemText: Colors.Purple,
|
||||
Details: Colors.White,
|
||||
DetailsLabel: Colors.White,
|
||||
LoadingDetailsLabel: Colors.Black,
|
||||
Details: Colors.Black,
|
||||
DetailsLabel: Colors.Purple,
|
||||
LoadingDetailsLabel: Colors.Purple,
|
||||
AddIdBtnBg: Colors.Purple,
|
||||
AddIdBtnTxt: Colors.Purple,
|
||||
ClearAddIdBtnBg: 'transparent',
|
||||
DownloadIdBtnTxt: Colors.White,
|
||||
Loading: Colors.Purple,
|
||||
Cursor: Colors.Purple,
|
||||
noUinText: Colors.Purple,
|
||||
IconBg: Colors.Purple,
|
||||
popUp: Colors.Green,
|
||||
Icon: Colors.Purple,
|
||||
GrayIcon: Colors.Grey,
|
||||
Loading: Colors.Purple,
|
||||
helpText: Colors.Gray44,
|
||||
borderBottomColor: Colors.Grey6,
|
||||
whiteBackgroundColor: Colors.White,
|
||||
lightGreyBackgroundColor: Colors.LightGrey,
|
||||
profileLanguageValue: Colors.Grey,
|
||||
profileVersion: Colors.Grey,
|
||||
aboutVersion: Colors.Gray40,
|
||||
profileAuthFactorUnlock: Colors.Grey,
|
||||
profileLabel: Colors.Black,
|
||||
profileValue: Colors.Grey,
|
||||
switchHead: Colors.Purple,
|
||||
switchTrackTrue: Colors.LightPurple,
|
||||
switchTrackFalse: Colors.Grey,
|
||||
overlayBackgroundColor: Colors.White,
|
||||
rotatingIcon: Colors.Grey5,
|
||||
loadingLabel: Colors.Grey6,
|
||||
textLabel: Colors.Grey,
|
||||
textValue: Colors.Black,
|
||||
requesterName: Colors.Red,
|
||||
errorMessage: Colors.Red,
|
||||
QRCodeBackgroundColor: Colors.LightGrey,
|
||||
ReceiveVcModalBackgroundColor: Colors.LightGrey,
|
||||
@@ -54,11 +78,28 @@ export const PurpleTheme = {
|
||||
whiteText: Colors.White,
|
||||
flipCameraIcon: Colors.Black,
|
||||
IdInputModalBorder: Colors.Grey,
|
||||
inputSelection: Colors.Orange,
|
||||
RetrieveIdLabel: Colors.ShadeOfGrey,
|
||||
inputSelection: Colors.Purple,
|
||||
checkCircleIcon: Colors.White,
|
||||
OnboardingCircleIcon: Colors.White,
|
||||
OnboardingCloseIcon: Colors.White,
|
||||
WarningIcon: Colors.Warning,
|
||||
DefaultToggle: Colors.LightPurple,
|
||||
ProfileIconBg: Colors.LightPurple,
|
||||
GrayText: Colors.GrayText,
|
||||
gradientBtn: Colors.GradientColors,
|
||||
dotColor: Colors.dorColor,
|
||||
plainText: Colors.plainText,
|
||||
IconBackground: Colors.LightPurple,
|
||||
GradientColors: Colors.GradientColors,
|
||||
DisabledColors: Colors.DisabledColors,
|
||||
getVidColor: Colors.Zambezi,
|
||||
TimeoutHintBoxColor: Colors.TimeoutHintBoxColor,
|
||||
TimoutText: Colors.TimoutText,
|
||||
walletbindingLabel: Colors.Black,
|
||||
walletbindingContent: Colors.Gray40,
|
||||
resendCodeTimer: Colors.resendCodeTimer,
|
||||
statusLabel: Colors.Black,
|
||||
},
|
||||
Styles: StyleSheet.create({
|
||||
title: {
|
||||
@@ -77,6 +118,19 @@ export const PurpleTheme = {
|
||||
backgroundColor: Colors.Grey,
|
||||
borderRadius: 4,
|
||||
},
|
||||
statusLabel: {
|
||||
color: Colors.Black,
|
||||
},
|
||||
verifiedIconContainer: {
|
||||
marginLeft: 5,
|
||||
},
|
||||
verifiedIconInner: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 10,
|
||||
},
|
||||
vcItemLabelHeader: {
|
||||
color: Colors.Purple,
|
||||
},
|
||||
closeDetails: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
@@ -88,6 +142,38 @@ export const PurpleTheme = {
|
||||
backgroundColor: Colors.Grey6,
|
||||
borderRadius: 4,
|
||||
},
|
||||
loadingCardDetailsContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.Grey6,
|
||||
borderRadius: 4,
|
||||
},
|
||||
cardDetailsContainer: {},
|
||||
bottomTabIconStyle: {
|
||||
padding: 4,
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 6,
|
||||
backgroundColor: Colors.LightPurple,
|
||||
},
|
||||
downloadingVcPopUp: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: Colors.Green,
|
||||
height: 39,
|
||||
position: 'relative',
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
homeScreenContainer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 10,
|
||||
backgroundColor: '#fff',
|
||||
shadowColor: '#000',
|
||||
shadowOpacity: 0.4,
|
||||
elevation: 5,
|
||||
padding: 10,
|
||||
},
|
||||
vertloadingContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.Grey6,
|
||||
@@ -98,10 +184,11 @@ export const PurpleTheme = {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
logoContainer: {
|
||||
closecardMosipLogo: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
alignSelf: 'flex-end',
|
||||
marginLeft: 300,
|
||||
},
|
||||
closeCardBgContainer: {
|
||||
@@ -114,10 +201,54 @@ export const PurpleTheme = {
|
||||
shadowRadius: 3,
|
||||
elevation: 4,
|
||||
},
|
||||
selectedBindedVc: {
|
||||
borderRadius: 15,
|
||||
margin: 5,
|
||||
borderWidth: 3,
|
||||
borderColor: Colors.Green,
|
||||
},
|
||||
selectedVc: {
|
||||
borderRadius: 10,
|
||||
margin: 5,
|
||||
borderWidth: 2,
|
||||
borderColor: Colors.Purple,
|
||||
},
|
||||
labelPartContainer: {
|
||||
marginLeft: 16,
|
||||
flex: 1,
|
||||
},
|
||||
urlContainer: {
|
||||
backgroundColor: Colors.White,
|
||||
padding: 10,
|
||||
borderRadius: 12,
|
||||
fontSize: 12,
|
||||
},
|
||||
lockDomainContainer: {
|
||||
backgroundColor: Colors.White,
|
||||
alignSelf: 'center',
|
||||
borderRadius: 15,
|
||||
width: 100,
|
||||
},
|
||||
bottomButtonsContainer: {
|
||||
height: 'auto',
|
||||
borderTopLeftRadius: 27,
|
||||
borderTopRightRadius: 27,
|
||||
padding: 6,
|
||||
backgroundColor: Colors.White,
|
||||
},
|
||||
consentPageTop: {
|
||||
backgroundColor: Colors.White,
|
||||
height: 160,
|
||||
borderRadius: 6,
|
||||
},
|
||||
consentDottedLine: {
|
||||
width: 182,
|
||||
borderWidth: 2,
|
||||
margin: 5,
|
||||
borderStyle: 'dashed',
|
||||
borderRadius: 1,
|
||||
borderColor: 'grey',
|
||||
},
|
||||
labelPart: {
|
||||
marginTop: 10,
|
||||
alignItems: 'flex-start',
|
||||
@@ -136,8 +267,6 @@ export const PurpleTheme = {
|
||||
backgroundImageContainer: {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
borderBottomColor: Colors.Grey,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
successTag: {
|
||||
backgroundColor: Colors.Green,
|
||||
@@ -159,13 +288,17 @@ export const PurpleTheme = {
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
logo: {
|
||||
height: 36,
|
||||
width: 36,
|
||||
height: 35,
|
||||
width: 90,
|
||||
},
|
||||
homeCloseCardDetailsHeader: {
|
||||
flex: 1,
|
||||
},
|
||||
cardDetailsHeader: {
|
||||
flex: 1,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
mosipLogoContainer: {},
|
||||
details: {
|
||||
width: 290,
|
||||
marginLeft: 110,
|
||||
@@ -175,6 +308,55 @@ export const PurpleTheme = {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
},
|
||||
profileIconBg: {
|
||||
padding: 8,
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 6,
|
||||
backgroundColor: Colors.LightPurple,
|
||||
},
|
||||
IconContainer: {
|
||||
padding: 6,
|
||||
width: 36,
|
||||
marginRight: 4,
|
||||
marginLeft: 10,
|
||||
height: 36,
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.LightPurple,
|
||||
},
|
||||
settingsIconBg: {
|
||||
padding: 6,
|
||||
width: 36,
|
||||
marginRight: 4,
|
||||
height: 36,
|
||||
backgroundColor: Colors.Transparent,
|
||||
},
|
||||
backArrowContainer: {
|
||||
padding: 6,
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.LightPurple,
|
||||
},
|
||||
receiveCardsContainer: {
|
||||
height: Dimensions.get('window').height * 0.12,
|
||||
width: Dimensions.get('window').width * 0.45,
|
||||
alignItems: 'center',
|
||||
borderBottomRightRadius: 0,
|
||||
padding: 15,
|
||||
marginVertical: 18,
|
||||
elevation: 1,
|
||||
},
|
||||
domainVerifiyIcon: {
|
||||
padding: 20,
|
||||
marginLeft: 120,
|
||||
width: 130,
|
||||
height: 130,
|
||||
borderRadius: 60,
|
||||
borderWidth: 10,
|
||||
borderColor: Colors.White,
|
||||
backgroundColor: Colors.LightPurple,
|
||||
},
|
||||
closeCardImage: {
|
||||
width: 105,
|
||||
height: 135,
|
||||
@@ -185,13 +367,26 @@ export const PurpleTheme = {
|
||||
height: 135,
|
||||
borderRadius: 5,
|
||||
},
|
||||
versionContainer: {
|
||||
backgroundColor: Colors.Grey6,
|
||||
margin: 4,
|
||||
borderRadius: 14,
|
||||
},
|
||||
primaryRow: {
|
||||
backgroundColor: Colors.LightPurple,
|
||||
paddingHorizontal: 18,
|
||||
paddingVertical: 9,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
iconContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
scannerContainer: {
|
||||
borderWidth: 4,
|
||||
borderColor: Colors.Black,
|
||||
borderRadius: 32,
|
||||
justifyContent: 'center',
|
||||
height: 300,
|
||||
width: 300,
|
||||
borderRadius: 24,
|
||||
alignSelf: 'center',
|
||||
height: 350,
|
||||
width: 320,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
scanner: {
|
||||
@@ -199,9 +394,19 @@ export const PurpleTheme = {
|
||||
width: '100%',
|
||||
margin: 'auto',
|
||||
},
|
||||
flipIconButton: {
|
||||
alignSelf: 'center',
|
||||
cameraDisabledPopUp: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: Colors.Red,
|
||||
height: 75,
|
||||
position: 'relative',
|
||||
paddingHorizontal: 15,
|
||||
marginTop: -36,
|
||||
},
|
||||
photoConsentLabel: {
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
borderWidth: 0,
|
||||
},
|
||||
tabIndicator: {
|
||||
backgroundColor: Colors.Purple,
|
||||
@@ -216,55 +421,134 @@ export const PurpleTheme = {
|
||||
detailsText: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 15,
|
||||
fontFamily: 'Poppins_700Bold',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
},
|
||||
getId: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginTop: 10,
|
||||
marginVertical: 6,
|
||||
},
|
||||
placeholder: {
|
||||
fontFamily: 'Poppins_400Regular',
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
},
|
||||
hrLine: {
|
||||
borderBottomColor: 'black',
|
||||
borderBottomWidth: 1,
|
||||
marginTop: 10,
|
||||
},
|
||||
}),
|
||||
QrCodeStyles: StyleSheet.create({
|
||||
magnifierZoom: {
|
||||
backgroundColor: Colors.White,
|
||||
width: 30,
|
||||
height: 30,
|
||||
alignItems: 'center',
|
||||
padding: 5,
|
||||
borderTopLeftRadius: 11,
|
||||
elevation: 4,
|
||||
},
|
||||
expandedQrCode: {
|
||||
backgroundColor: Colors.White,
|
||||
width: 350,
|
||||
borderRadius: 21,
|
||||
},
|
||||
QrCodeHeader: {
|
||||
backgroundColor: Colors.White,
|
||||
borderTopLeftRadius: 21,
|
||||
borderTopRightRadius: 21,
|
||||
justifyContent: 'space-between',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
paddingBottom: 10,
|
||||
paddingRight: 15,
|
||||
paddingLeft: 130,
|
||||
elevation: 2,
|
||||
},
|
||||
warningText: {
|
||||
color: Colors.Red,
|
||||
fontSize: 18,
|
||||
},
|
||||
}),
|
||||
PinInputStyle: StyleSheet.create({
|
||||
input: {
|
||||
borderBottomWidth: 1,
|
||||
borderBottomWidth: 3,
|
||||
borderColor: Colors.Grey,
|
||||
color: Colors.Black,
|
||||
flex: 1,
|
||||
fontFamily: 'Poppins_600SemiBold',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
fontSize: 33,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
height: 40,
|
||||
lineHeight: 28,
|
||||
margin: 8,
|
||||
textAlign: 'center',
|
||||
},
|
||||
onEnteringPin: {
|
||||
borderBottomWidth: 3,
|
||||
borderColor: Colors.Purple,
|
||||
color: Colors.Black,
|
||||
flex: 1,
|
||||
fontFamily: 'Inter_700Bold',
|
||||
fontSize: 29,
|
||||
height: 60,
|
||||
margin: 8,
|
||||
textAlign: 'center',
|
||||
},
|
||||
}),
|
||||
TextStyles: StyleSheet.create({
|
||||
base: {
|
||||
header: {
|
||||
color: Colors.Black,
|
||||
fontFamily: 'Inter_700Bold',
|
||||
fontSize: 18,
|
||||
lineHeight: 22,
|
||||
paddingTop: 4,
|
||||
},
|
||||
retrieveIdLabel: {
|
||||
color: Colors.ShadeOfGrey,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
lineHeight: 18,
|
||||
},
|
||||
helpDetailes: {
|
||||
margin: 5,
|
||||
color: Colors.Gray44,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
},
|
||||
aboutDetailes: {
|
||||
color: Colors.Black,
|
||||
fontSize: 18,
|
||||
lineHeight: 28,
|
||||
margin: 7,
|
||||
lineHeight: 18,
|
||||
},
|
||||
error: {
|
||||
color: Colors.Red,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
fontSize: 12,
|
||||
},
|
||||
base: {
|
||||
color: Colors.Black,
|
||||
fontSize: 16,
|
||||
lineHeight: 18,
|
||||
},
|
||||
regular: {
|
||||
fontFamily: 'Poppins_400Regular',
|
||||
fontFamily: 'Inter_400Regular',
|
||||
fontSize: 14,
|
||||
},
|
||||
semibold: {
|
||||
fontFamily: 'Poppins_600SemiBold',
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
fontSize: 15,
|
||||
},
|
||||
bold: {
|
||||
fontFamily: 'Poppins_700Bold',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
},
|
||||
small: {
|
||||
fontSize: 14,
|
||||
fontSize: 13,
|
||||
lineHeight: 21,
|
||||
},
|
||||
smaller: {
|
||||
fontSize: 12,
|
||||
fontSize: 11,
|
||||
lineHeight: 18,
|
||||
},
|
||||
large: {
|
||||
fontSize: 18,
|
||||
},
|
||||
}),
|
||||
VcItemStyles: StyleSheet.create({
|
||||
title: {
|
||||
@@ -294,7 +578,7 @@ export const PurpleTheme = {
|
||||
}),
|
||||
ToastItemStyles: StyleSheet.create({
|
||||
toastContainer: {
|
||||
backgroundColor: Colors.Orange,
|
||||
backgroundColor: Colors.Purple,
|
||||
position: 'absolute',
|
||||
alignSelf: 'center',
|
||||
top: 80,
|
||||
@@ -319,22 +603,35 @@ export const PurpleTheme = {
|
||||
borderColor: Colors.Purple,
|
||||
},
|
||||
container: {
|
||||
minHeight: 48,
|
||||
height: 45,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
disabled: {
|
||||
opacity: 0.5,
|
||||
backgroundColor: Colors.Grey,
|
||||
},
|
||||
addId: {
|
||||
backgroundColor: Colors.Purple,
|
||||
},
|
||||
gradient: {
|
||||
borderRadius: 9,
|
||||
width: Dimensions.get('window').width * 0.72,
|
||||
alignSelf: 'center',
|
||||
margin: 4,
|
||||
},
|
||||
float: {
|
||||
borderRadius: 9,
|
||||
alignSelf: 'center',
|
||||
fontSize: 10,
|
||||
elevation: 5,
|
||||
position: 'absolute',
|
||||
bottom: 24,
|
||||
},
|
||||
clearAddIdBtnBg: {
|
||||
backgroundColor: Colors.Transparent,
|
||||
},
|
||||
radius: {
|
||||
flex: 1,
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.Orange,
|
||||
backgroundColor: Colors.Purple,
|
||||
},
|
||||
}),
|
||||
OIDCAuthStyles: StyleSheet.create({
|
||||
@@ -348,14 +645,35 @@ export const PurpleTheme = {
|
||||
padding: 32,
|
||||
},
|
||||
}),
|
||||
QRCodeOverlay: StyleSheet.create({
|
||||
header: {},
|
||||
}),
|
||||
SelectVcOverlayStyles: StyleSheet.create({
|
||||
overlay: {
|
||||
elevation: 5,
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
},
|
||||
consentCheckContainer: {
|
||||
backgroundColor: Colors.White,
|
||||
borderWidth: 0,
|
||||
marginTop: -15,
|
||||
fontFamily: 'Inter_600SemiBold',
|
||||
padding: 0,
|
||||
},
|
||||
timeoutHintContainer: {
|
||||
backgroundColor: Colors.TimeoutHintBoxColor,
|
||||
margin: 21,
|
||||
paddingHorizontal: 14,
|
||||
paddingVertical: 12,
|
||||
borderRadius: 12,
|
||||
},
|
||||
sharedSuccessfully: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.White,
|
||||
},
|
||||
}),
|
||||
CreditsStyles: StyleSheet.create({
|
||||
AppMetaDataStyles: StyleSheet.create({
|
||||
buttonContainer: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
@@ -365,9 +683,23 @@ export const PurpleTheme = {
|
||||
flex: 1,
|
||||
width: Dimensions.get('screen').width,
|
||||
},
|
||||
markdownView: {
|
||||
contentView: {
|
||||
flex: 1,
|
||||
padding: 20,
|
||||
},
|
||||
header: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'normal',
|
||||
color: 'rgb(28,28,30)',
|
||||
},
|
||||
}),
|
||||
FooterStyles: StyleSheet.create({
|
||||
bottom: {
|
||||
justifyContent: 'flex-end',
|
||||
backgroundColor: Colors.Grey6,
|
||||
borderRadius: 15,
|
||||
padding: 10,
|
||||
},
|
||||
}),
|
||||
ModalStyles: StyleSheet.create({
|
||||
modal: {
|
||||
@@ -408,11 +740,51 @@ export const PurpleTheme = {
|
||||
height: Dimensions.get('screen').height,
|
||||
},
|
||||
}),
|
||||
KebabPopUpStyles: StyleSheet.create({
|
||||
kebabPopUp: {
|
||||
borderTopLeftRadius: 15,
|
||||
borderTopRightRadius: 15,
|
||||
width: Dimensions.get('screen').width,
|
||||
marginTop: Dimensions.get('screen').height * 0.55,
|
||||
},
|
||||
kebabHeaderStyle: {
|
||||
justifyContent: 'space-between',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
paddingRight: 15,
|
||||
paddingLeft: 130,
|
||||
paddingTop: 18,
|
||||
},
|
||||
}),
|
||||
MessageOverlayStyles: StyleSheet.create({
|
||||
overlay: {
|
||||
elevation: 5,
|
||||
backgroundColor: Colors.White,
|
||||
padding: 5,
|
||||
borderRadius: 10,
|
||||
},
|
||||
buttonContainer: {
|
||||
justifyContent: 'center',
|
||||
marginBottom: 75,
|
||||
},
|
||||
popupOverLay: {
|
||||
height: 150,
|
||||
backgroundColor: Colors.White,
|
||||
},
|
||||
button: {
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
},
|
||||
halfButton: {
|
||||
borderRadius: 8,
|
||||
margin: '0.5%',
|
||||
},
|
||||
}),
|
||||
BindingVcWarningOverlay: StyleSheet.create({
|
||||
overlay: {
|
||||
elevation: 5,
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
borderRadius: 15,
|
||||
},
|
||||
button: {
|
||||
borderTopLeftRadius: 0,
|
||||
@@ -488,7 +860,7 @@ export const PurpleTheme = {
|
||||
position: 'absolute',
|
||||
top: 32,
|
||||
right: 0,
|
||||
color: Colors.Orange,
|
||||
color: Colors.Purple,
|
||||
},
|
||||
}),
|
||||
MessageStyles: StyleSheet.create({
|
||||
@@ -545,8 +917,8 @@ export const PurpleTheme = {
|
||||
overlay: {
|
||||
padding: 24,
|
||||
bottom: 86,
|
||||
backgroundColor: Colors.Transparent,
|
||||
shadowColor: Colors.Transparent,
|
||||
backgroundColor: 'transparent',
|
||||
shadowColor: 'transparent',
|
||||
},
|
||||
slide: {
|
||||
width: '100%',
|
||||
@@ -563,7 +935,7 @@ export const PurpleTheme = {
|
||||
sliderTitle: {
|
||||
color: Colors.White,
|
||||
marginBottom: 20,
|
||||
fontFamily: 'Poppins_700Bold',
|
||||
fontFamily: 'Inter_700Bold',
|
||||
},
|
||||
text: {
|
||||
color: Colors.White,
|
||||
@@ -583,17 +955,12 @@ export const PurpleTheme = {
|
||||
top: 40,
|
||||
zIndex: 1,
|
||||
},
|
||||
}),
|
||||
BindingVcWarningOverlay: StyleSheet.create({
|
||||
overlay: {
|
||||
elevation: 5,
|
||||
backgroundColor: Colors.White,
|
||||
padding: 0,
|
||||
borderRadius: 15,
|
||||
},
|
||||
button: {
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
bottomContainer: {
|
||||
padding: 20,
|
||||
borderTopLeftRadius: 30,
|
||||
borderTopRightRadius: 30,
|
||||
marginTop: -185,
|
||||
paddingBottom: 100,
|
||||
},
|
||||
}),
|
||||
claimsContainer: StyleSheet.create({
|
||||
@@ -601,13 +968,31 @@ export const PurpleTheme = {
|
||||
backgroundColor: Colors.Transparent,
|
||||
},
|
||||
}),
|
||||
OpenCard: require('../../../purpleAassets/bg_cart_one.png'),
|
||||
CloseCard: require('../../../purpleAassets/cart_unsel.png'),
|
||||
ProfileIcon: require('../../../purpleAassets/profile_icon_unsel.png'),
|
||||
MosipLogo: require('../../../purpleAassets/logo.png'),
|
||||
OpenCard: '',
|
||||
CloseCard: '',
|
||||
ProfileIcon: require('../../../purpleAssets/profile_icon.png'),
|
||||
MosipSplashLogo: require('../../../assets/icon.png'),
|
||||
MosipLogo: require('../../../assets/mosip-logo.png'),
|
||||
CameraFlipIcon: require('../../../assets/camera-flip-icon.png'),
|
||||
DomainWarningLogo: require('../../../assets/domain-warning.png'),
|
||||
WarningLogo: require('../../../assets/warningLogo.png'),
|
||||
OtpLogo: require('../../../assets/otp-mobile-logo.png'),
|
||||
OtpLogo: require('../../../purpleAssets/otp-mobile-logo.png'),
|
||||
SuccessLogo: require('../../../assets/success-logo.png'),
|
||||
ReceiveCardIcon: require('../../../assets/receive-card-icon.png'),
|
||||
ReceivedCardsIcon: require('../../../assets/received-cards-icon.png'),
|
||||
DigitalIdentityLogo: require('../../../assets/digital-identity-icon.png'),
|
||||
InjiLogoWhite: require('../../../assets/inji-logo-white.png'),
|
||||
InjiProgressingLogo: require('../../../assets/progressing-logo.png'),
|
||||
LockIcon: require('../../../assets/lock-icon.png'),
|
||||
InjiHomeLogo: require('../../../assets/inji-home-logo.png'),
|
||||
MagnifierZoom: require('../../../assets/magnifier-zoom.png'),
|
||||
HelpIcon: require('../../../assets/help-icon.png'),
|
||||
sharingIntro: require('../../../assets/Secure-Sharing.png'),
|
||||
walletIntro: require('../../../assets/intro-wallet-binding.png'),
|
||||
IntroScanner: require('../../../assets/intro-scanner.png'),
|
||||
injiSmallLogo: require('../../../assets/inji_small_logo.png'),
|
||||
protectPrivacy: require('../../../assets/phone_mockup_1.png'),
|
||||
|
||||
elevation(level: ElevationLevel): ViewStyle {
|
||||
// https://ethercreative.github.io/react-native-shadow-generator/
|
||||
|
||||
|
||||