@smile_identity/react-native 10.3.2 → 10.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,10 +8,10 @@ buildscript {
8
8
  google()
9
9
  mavenCentral()
10
10
  gradlePluginPortal()
11
- // uncomment for development to test snapshots
12
- // maven {
13
- // url 'https://oss.sonatype.org/content/repositories/snapshots/'
14
- // }
11
+ // uncomment for development to test snapshots
12
+ // maven {
13
+ // url = 'https://central.sonatype.com/repository/maven-snapshots/'
14
+ // }
15
15
  }
16
16
 
17
17
  dependencies {
@@ -121,9 +121,10 @@ repositories {
121
121
  mavenCentral()
122
122
  google()
123
123
  gradlePluginPortal()
124
- maven {
125
- url 'https://oss.sonatype.org/content/repositories/snapshots/'
126
- }
124
+ // uncomment for development to test snapshots
125
+ // maven {
126
+ // url = 'https://central.sonatype.com/repository/maven-snapshots/'
127
+ // }
127
128
  }
128
129
 
129
130
  def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["SmileId_kotlinVersion"]
@@ -3,7 +3,5 @@ SmileId_minSdkVersion=21
3
3
  SmileId_targetSdkVersion=35
4
4
  SmileId_compileSdkVersion=35
5
5
  SmileId_ndkversion=21.4.7075529
6
- SmileId_androidVersion=10.6.0
7
- ; Uncomment for dev also uncomment snapshots repo in build.gradle
8
- ; SmileId_androidVersion=10.6.1-SNAPSHOT
6
+ SmileId_androidVersion=10.6.3
9
7
  SmileId_kotlinCompilerExtensionVersion=1.5.11
@@ -5,6 +5,7 @@ import com.facebook.react.bridge.ReadableMap
5
5
  import com.smileidentity.models.AuthenticationRequest
6
6
  import com.smileidentity.models.Config
7
7
  import com.smileidentity.models.ConsentInformation
8
+ import com.smileidentity.models.ConsentedInformation
8
9
  import com.smileidentity.models.EnhancedKycRequest
9
10
  import com.smileidentity.models.IdInfo
10
11
  import com.smileidentity.models.ImageType
@@ -153,23 +154,47 @@ fun ReadableMap.toEnhancedKycRequest(): EnhancedKycRequest {
153
154
  },
154
155
  consentInformation = getMapOrDefault("consentInformation", null)?.toConsentInfo() ?: run {
155
156
  ConsentInformation(
156
- consentGrantedDate = getCurrentIsoTimestamp(),
157
- personalDetailsConsentGranted = false,
158
- contactInfoConsentGranted = false,
159
- documentInfoConsentGranted = false
157
+ consented = ConsentedInformation(
158
+ consentGrantedDate = getCurrentIsoTimestamp(),
159
+ personalDetails = false,
160
+ contactInformation = false,
161
+ documentInformation = false
162
+ )
160
163
  )
161
164
  },
162
165
  )
163
166
  }
164
167
 
165
168
  fun ReadableMap.toConsentInfo(): ConsentInformation {
169
+ val consentGrantedDate =
170
+ getStringOrDefault("consentGrantedDate", getCurrentIsoTimestamp()) ?: getCurrentIsoTimestamp()
171
+
172
+ // Try the new property names first, fall back to old property names if new ones aren't present
173
+ val personalDetailsConsentGranted = if (hasKey("personalDetails")) {
174
+ getBoolOrDefault("personalDetails", false)
175
+ } else {
176
+ getBoolOrDefault("personalDetailsConsentGranted", false)
177
+ }
178
+
179
+ val contactInfoConsentGranted = if (hasKey("contactInformation")) {
180
+ getBoolOrDefault("contactInformation", false)
181
+ } else {
182
+ getBoolOrDefault("contactInfoConsentGranted", false)
183
+ }
184
+
185
+ val documentInfoConsentGranted = if (hasKey("documentInformation")) {
186
+ getBoolOrDefault("documentInformation", false)
187
+ } else {
188
+ getBoolOrDefault("documentInfoConsentGranted", false)
189
+ }
190
+
166
191
  return ConsentInformation(
167
- consentGrantedDate = getStringOrDefault("consentGrantedDate", null) ?: run {
168
- getCurrentIsoTimestamp()
169
- },
170
- personalDetailsConsentGranted = getBoolOrDefault("personalDetailsConsentGranted", false),
171
- contactInfoConsentGranted = getBoolOrDefault("contactInfoConsentGranted", false),
172
- documentInfoConsentGranted = getBoolOrDefault("documentInfoConsentGranted", false)
192
+ consented = ConsentedInformation(
193
+ consentGrantedDate = consentGrantedDate,
194
+ personalDetails = personalDetailsConsentGranted,
195
+ contactInformation = contactInfoConsentGranted,
196
+ documentInformation = documentInfoConsentGranted
197
+ ),
173
198
  )
174
199
  }
175
200
 
@@ -4,6 +4,7 @@ import com.facebook.react.bridge.ReactApplicationContext
4
4
  import com.facebook.react.bridge.ReadableMap
5
5
  import com.facebook.react.module.annotations.ReactModule
6
6
  import com.smileidentity.models.ConsentInformation
7
+ import com.smileidentity.models.ConsentedInformation
7
8
  import com.smileidentity.react.toConsentInfo
8
9
  import com.smileidentity.react.toIdInfo
9
10
  import com.smileidentity.react.utils.getBoolOrDefault
@@ -31,11 +32,13 @@ class SmileIDBiometricKYCViewManager(
31
32
  val idInfo = idInfoMap.toIdInfo()
32
33
  view.consentInformation = it.getMapOrDefault("consentInformation")?.toConsentInfo()
33
34
  ?: ConsentInformation(
34
- consentGrantedDate = getCurrentIsoTimestamp(),
35
- personalDetailsConsentGranted = false,
36
- contactInfoConsentGranted = false,
37
- documentInfoConsentGranted = false
38
- )
35
+ consented = ConsentedInformation(
36
+ consentGrantedDate = getCurrentIsoTimestamp(),
37
+ personalDetails = false,
38
+ contactInformation = false,
39
+ documentInformation = false
40
+ ),
41
+ )
39
42
  view.extraPartnerParams = it.getImmutableMapOrDefault("extraPartnerParams")
40
43
  view.userId = it.getStringOrDefault("userId")
41
44
  view.jobId = it.getStringOrDefault("jobId")
@@ -7,6 +7,7 @@ import com.facebook.react.module.annotations.ReactModule
7
7
  import com.facebook.react.uimanager.SimpleViewManager
8
8
  import com.facebook.react.uimanager.ThemedReactContext
9
9
  import com.smileidentity.models.ConsentInformation
10
+ import com.smileidentity.models.ConsentedInformation
10
11
  import com.smileidentity.react.toConsentInfo
11
12
  import com.smileidentity.react.toIdInfo
12
13
  import com.smileidentity.react.utils.getBoolOrDefault
@@ -37,10 +38,12 @@ class SmileIDEnhancedDocumentVerificationViewManager(
37
38
  )
38
39
  view.consentInformation = it.getMapOrDefault("consentInformation")?.toConsentInfo()
39
40
  ?: ConsentInformation(
40
- consentGrantedDate = getCurrentIsoTimestamp(),
41
- personalDetailsConsentGranted = false,
42
- contactInfoConsentGranted = false,
43
- documentInfoConsentGranted = false
41
+ consented = ConsentedInformation(
42
+ consentGrantedDate = getCurrentIsoTimestamp(),
43
+ personalDetails = false,
44
+ contactInformation = false,
45
+ documentInformation = false
46
+ ),
44
47
  )
45
48
  view.extraPartnerParams = it.getImmutableMapOrDefault("extraPartnerParams")
46
49
  view.userId = it.getStringOrDefault("userId")
@@ -1,22 +1,53 @@
1
1
  package com.smileidentity.react.views
2
2
 
3
+ import android.graphics.BitmapFactory
4
+ import androidx.compose.foundation.background
5
+ import androidx.compose.foundation.layout.Box
6
+ import androidx.compose.foundation.layout.WindowInsets
7
+ import androidx.compose.foundation.layout.consumeWindowInsets
8
+ import androidx.compose.foundation.layout.fillMaxSize
9
+ import androidx.compose.foundation.layout.statusBars
10
+ import androidx.compose.foundation.layout.windowInsetsPadding
3
11
  import androidx.compose.material3.MaterialTheme
4
12
  import androidx.compose.material3.Surface
13
+ import androidx.compose.runtime.Composable
5
14
  import androidx.compose.runtime.CompositionLocalProvider
15
+ import androidx.compose.runtime.getValue
16
+ import androidx.compose.runtime.mutableStateOf
17
+ import androidx.compose.runtime.remember
18
+ import androidx.compose.runtime.saveable.rememberSaveable
19
+ import androidx.compose.runtime.setValue
20
+ import androidx.compose.runtime.toMutableStateList
21
+ import androidx.compose.ui.Modifier
22
+ import androidx.compose.ui.graphics.Color
23
+ import androidx.compose.ui.graphics.asImageBitmap
24
+ import androidx.compose.ui.graphics.painter.BitmapPainter
25
+ import androidx.compose.ui.res.stringResource
26
+ import androidx.lifecycle.compose.collectAsStateWithLifecycle
6
27
  import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
28
+ import androidx.lifecycle.viewmodel.compose.viewModel
7
29
  import com.facebook.react.bridge.ReactApplicationContext
30
+ import com.smileidentity.R
8
31
  import com.smileidentity.SmileID
9
32
  import com.smileidentity.SmileIDOptIn
10
33
  import com.smileidentity.compose.SmartSelfieEnrollment
11
34
  import com.smileidentity.compose.SmartSelfieEnrollmentEnhanced
35
+ import com.smileidentity.compose.components.ImageCaptureConfirmationDialog
36
+ import com.smileidentity.compose.components.LocalMetadata
37
+ import com.smileidentity.compose.selfie.SelfieCaptureScreen
38
+ import com.smileidentity.compose.selfie.SmartSelfieInstructionsScreen
12
39
  import com.smileidentity.compose.theme.colorScheme
13
40
  import com.smileidentity.compose.theme.typography
41
+ import com.smileidentity.models.v2.Metadata
14
42
  import com.smileidentity.react.results.SmartSelfieCaptureResult
15
43
  import com.smileidentity.react.utils.SelfieCaptureResultAdapter
16
44
  import com.smileidentity.results.SmartSelfieResult
17
45
  import com.smileidentity.results.SmileIDResult
18
46
  import com.smileidentity.util.randomJobId
19
47
  import com.smileidentity.util.randomUserId
48
+ import com.smileidentity.viewmodel.SelfieUiState
49
+ import com.smileidentity.viewmodel.SelfieViewModel
50
+ import com.smileidentity.viewmodel.viewModelFactory
20
51
 
21
52
 
22
53
  @OptIn(SmileIDOptIn::class)
@@ -29,11 +60,10 @@ class SmileIDSmartSelfieCaptureView(context: ReactApplicationContext) : SmileIDS
29
60
  val customViewModelStoreOwner = CustomViewModelStoreOwner()
30
61
  setContent {
31
62
  CompositionLocalProvider(LocalViewModelStoreOwner provides customViewModelStoreOwner) {
32
- val userId = randomUserId()
33
- val jobId = randomJobId()
34
- MaterialTheme(colorScheme = SmileID.colorScheme, typography = SmileID.typography) {
35
- Surface(content = {
36
- if (useStrictMode) {
63
+ if (useStrictMode) {
64
+ val userId = randomUserId()
65
+ MaterialTheme(colorScheme = SmileID.colorScheme, typography = SmileID.typography) {
66
+ Surface(content = {
37
67
  SmileID.SmartSelfieEnrollmentEnhanced(
38
68
  userId = userId,
39
69
  showAttribution = showAttribution,
@@ -42,22 +72,122 @@ class SmileIDSmartSelfieCaptureView(context: ReactApplicationContext) : SmileIDS
42
72
  extraPartnerParams = extraPartnerParams,
43
73
  onResult = { res -> handleResultCallback(res) },
44
74
  )
45
- } else {
46
- SmileID.SmartSelfieEnrollment(
47
- userId = userId,
48
- jobId = jobId,
49
- allowAgentMode = allowAgentMode ?: false,
50
- showAttribution = showAttribution,
51
- showInstructions = showInstructions,
52
- skipApiSubmission = true,
53
- extraPartnerParams = extraPartnerParams,
54
- onResult = { res -> handleResultCallback(res) },
55
- )
56
- }
57
- })
75
+ })
76
+ }
77
+ } else {
78
+ RenderSmartSelfieCaptureContent()
58
79
  }
59
80
  }
60
81
  }
61
82
  }
62
83
  }
84
+
85
+ @Composable
86
+ private fun RenderSmartSelfieCaptureContent() {
87
+ val userId = randomUserId()
88
+ val jobId = randomJobId()
89
+ val metadata = Metadata.default().items.toMutableStateList()
90
+
91
+ val viewModel: SelfieViewModel = viewModel(
92
+ factory = viewModelFactory {
93
+ SelfieViewModel(
94
+ isEnroll = false,
95
+ userId = userId,
96
+ jobId = jobId,
97
+ allowNewEnroll = false,
98
+ skipApiSubmission = true,
99
+ metadata = metadata,
100
+ )
101
+ },
102
+ )
103
+
104
+ val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
105
+ var acknowledgedInstructions by rememberSaveable { mutableStateOf(false) }
106
+
107
+ CompositionLocalProvider(
108
+ LocalMetadata provides remember { metadata },
109
+ ) {
110
+ MaterialTheme(colorScheme = SmileID.colorScheme, typography = SmileID.typography) {
111
+ Surface(content = {
112
+ when {
113
+ showInstructions && !acknowledgedInstructions -> SmartSelfieInstructionsScreen(
114
+ showAttribution = showAttribution,
115
+ ) {
116
+ acknowledgedInstructions = true
117
+ }
118
+ uiState.processingState != null -> HandleProcessingState(viewModel)
119
+ uiState.selfieToConfirm != null -> HandleSelfieConfirmation(
120
+ showConfirmation,
121
+ uiState,
122
+ viewModel,
123
+ )
124
+ else -> RenderSelfieCaptureScreen(userId, jobId, allowAgentMode ?: true, viewModel)
125
+ }
126
+ })
127
+ }
128
+ }
129
+ }
130
+
131
+ @Composable
132
+ private fun RenderSelfieCaptureScreen(
133
+ userId: String,
134
+ jobId: String,
135
+ allowAgentMode: Boolean,
136
+ viewModel: SelfieViewModel,
137
+ ) {
138
+ Box(
139
+ modifier = Modifier
140
+ .background(color = Color.White)
141
+ .windowInsetsPadding(WindowInsets.statusBars)
142
+ .consumeWindowInsets(WindowInsets.statusBars)
143
+ .fillMaxSize(),
144
+ ) {
145
+ SelfieCaptureScreen(
146
+ userId = userId,
147
+ jobId = jobId,
148
+ allowAgentMode = allowAgentMode,
149
+ allowNewEnroll = false,
150
+ skipApiSubmission = true,
151
+ viewModel = viewModel,
152
+ )
153
+ }
154
+ }
155
+
156
+ @Composable
157
+ private fun HandleSelfieConfirmation(
158
+ showConfirmation: Boolean,
159
+ uiState: SelfieUiState,
160
+ viewModel: SelfieViewModel,
161
+ ) {
162
+ if (showConfirmation) {
163
+ ImageCaptureConfirmationDialog(
164
+ titleText = stringResource(R.string.si_smart_selfie_confirmation_dialog_title),
165
+ subtitleText = stringResource(R.string.si_smart_selfie_confirmation_dialog_subtitle),
166
+ painter = BitmapPainter(
167
+ BitmapFactory
168
+ .decodeFile(uiState.selfieToConfirm!!.absolutePath)
169
+ .asImageBitmap()
170
+ ),
171
+ confirmButtonText = stringResource(R.string.si_smart_selfie_confirmation_dialog_confirm_button),
172
+ onConfirm = {
173
+ viewModel.submitJob()
174
+ },
175
+ retakeButtonText = stringResource(R.string.si_smart_selfie_confirmation_dialog_retake_button),
176
+ onRetake = viewModel::onSelfieRejected,
177
+ scaleFactor = 1.25f,
178
+ )
179
+ } else {
180
+ // If confirmation is disabled, automatically confirm
181
+ viewModel.submitJob()
182
+ }
183
+ }
184
+
185
+ @Composable
186
+ private fun HandleProcessingState(viewModel: SelfieViewModel) {
187
+ try {
188
+ viewModel.onFinished { res -> handleResultCallback(res)}
189
+ } catch (e: Exception) {
190
+ emitFailure(e)
191
+ }
192
+ }
63
193
  }